pax_global_header00006660000000000000000000000064147454615430014527gustar00rootroot0000000000000052 comment=b7935f75511dde280325631541f4a8a24b245709 graphql-core-3.2.6/000077500000000000000000000000001474546154300141235ustar00rootroot00000000000000graphql-core-3.2.6/.bumpversion.cfg000066400000000000000000000010361474546154300172330ustar00rootroot00000000000000[bumpversion] current_version = 3.2.6 commit = False tag = False [bumpversion:file:src/graphql/version.py] search = version = "{current_version}" replace = version = "{new_version}" [bumpversion:file:docs/conf.py] search = version = release = '{current_version}' replace = version = release = '{new_version}' [bumpversion:file:README.md] search = The current version {current_version} replace = The current version {new_version} [bumpversion:file:pyproject.toml] search = version = "{current_version}" replace = version = "{new_version}" graphql-core-3.2.6/.coveragerc000066400000000000000000000010261474546154300162430ustar00rootroot00000000000000[run] branch = True source = src tests omit = */conftest.py */test_*_fuzz.py */assert_valid_name.py */cached_property.py */character_classes.py */is_iterable.py */subscription/__init__.py [report] exclude_lines = pragma: no cover except ImportError: \# Python < sys\.version_info < raise NotImplementedError raise TypeError\(f?"Unexpected assert False, \s+next\($ if MYPY: if TYPE_CHECKING: ^\s+\.\.\.$ ^\s+pass$ \: \.\.\.$ ignore_errors = True graphql-core-3.2.6/.editorconfig000066400000000000000000000004441474546154300166020ustar00rootroot00000000000000# http://editorconfig.org root = true [*] indent_style = space indent_size = 4 trim_trailing_whitespace = true insert_final_newline = true charset = utf-8 end_of_line = lf [*.bat] indent_style = tab end_of_line = crlf [LICENSE] insert_final_newline = false [Makefile] indent_style = tab graphql-core-3.2.6/.flake8000066400000000000000000000002061474546154300152740ustar00rootroot00000000000000[flake8] ignore = E203,E704,W503 exclude = .git,.mypy_cache,.pytest_cache,.tox,.venv,__pycache__,build,dist,docs max-line-length = 88 graphql-core-3.2.6/.github/000077500000000000000000000000001474546154300154635ustar00rootroot00000000000000graphql-core-3.2.6/.github/FUNDING.yml000066400000000000000000000000741474546154300173010ustar00rootroot00000000000000# These are supported funding model platforms github: cito graphql-core-3.2.6/.github/ISSUE_TEMPLATE/000077500000000000000000000000001474546154300176465ustar00rootroot00000000000000graphql-core-3.2.6/.github/ISSUE_TEMPLATE/config.yml000066400000000000000000000000341474546154300216330ustar00rootroot00000000000000blank_issues_enabled: false graphql-core-3.2.6/.github/ISSUE_TEMPLATE/open-a-graphql-core-issue.md000066400000000000000000000025231474546154300250610ustar00rootroot00000000000000--- name: Open a GraphQL-core issue about: General template for all GraphQL-core issues title: '' labels: '' assignees: '' --- # Questions regarding how to use GraphQL If you have a question on how to use GraphQL, please [post it to Stack Overflow](https://stackoverflow.com/questions/ask?tags=graphql) with the tag [#graphql](https://stackoverflow.com/questions/tagged/graphql). # Reporting issues with GraphQL-core 3 Before filing a new issue, make sure an issue for your problem doesn't already exist and that this is not an issue that should be filed against a different repository (see below). The best way to get a bug fixed is to provide a _pull request_ with a simplified failing test case (or better yet, include a fix). # Reporting issues with GraphQL-core 2 Please use the issue tracker of the [legacy repository](https://github.com/graphql-python/graphql-core-legacy) for issues with legacy versions of GraphQL-core. # Feature requests GraphQL-core is a Python port of the [GraphQL.js](https://github.com/graphql/graphql-js) reference implementation of the [GraphQL specification](https://github.com/graphql/graphql-spec). To discuss new features which are not Python specific, please open an issue against the GraphQL.js project. To discuss features that fundamentally change the way GraphQL works, open an issue against the specification. graphql-core-3.2.6/.github/PULL_REQUEST_TEMPLATE.md000066400000000000000000000015171474546154300212700ustar00rootroot00000000000000Thank you for contributing to GraphQL-core! If your pull-request is non-trivial, adds a feature or contains a non-breaking change, then please, first open an issue to discuss the proposed changes and add a link to that issue. GraphQL-core tries very hard to stay within the scope of being just a Python port of [GraphQL.js](https://github.com/graphql/graphql-js). Any additional feature or incompatible change will be only accepted in rare cases and requires a compelling reason, because they aggravate maintenance and synchronization with the developments in the upstream project. So please discuss such changes upfront in an issue before sending a PR. Maybe there are other ways to solve the problem. If possible, also add unit tests, or provide runnable example code as part of the accompanying issue, from which unit tests can be derived. graphql-core-3.2.6/.github/workflows/000077500000000000000000000000001474546154300175205ustar00rootroot00000000000000graphql-core-3.2.6/.github/workflows/lint.yml000066400000000000000000000007331474546154300212140ustar00rootroot00000000000000name: Code quality on: [push, pull_request] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Set up Python 3.12 uses: actions/setup-python@v5 with: python-version: 3.12 - name: Install dependencies run: | python -m pip install --upgrade pip pip install tox - name: Run code quality tests with tox run: tox env: TOXENV: black,flake8,mypy,docs,manifest graphql-core-3.2.6/.github/workflows/publish.yml000066400000000000000000000010641474546154300217120ustar00rootroot00000000000000name: Publish on: push: tags: - 'v*' jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Set up Python 3.12 uses: actions/setup-python@v5 with: python-version: 3.12 - name: Build wheel and source tarball run: | pip install setuptools wheel python setup.py sdist bdist_wheel - name: Publish a Python distribution to PyPI uses: pypa/gh-action-pypi-publish@release/v1 with: user: __token__ password: ${{ secrets.PYPI_TOKEN }} graphql-core-3.2.6/.github/workflows/test.yml000066400000000000000000000022141474546154300212210ustar00rootroot00000000000000name: Tests on: [push, pull_request] jobs: tests: runs-on: ubuntu-latest strategy: matrix: python-version: ['3.9', '3.10', '3.11', '3.12', '3.13', 'pypy3.9', 'pypy3.10'] steps: - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - name: Install dependencies run: | python -m pip install --upgrade pip pip install "tox>=4.24,<5" "tox-gh-actions>=3.2,<4" - name: Run unit tests with tox run: tox tests-old: runs-on: ubuntu-20.04 strategy: matrix: python-version: ['3.6', '3.7', '3.8'] steps: - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - name: Install dependencies run: | python -m pip install --upgrade pip pip install "tox>=3.28,<5" "tox-gh-actions>=2.12,<4" - name: Run unit tests with tox run: toxgraphql-core-3.2.6/.gitignore000066400000000000000000000003301474546154300161070ustar00rootroot00000000000000 .cache/ .coverage .env*/ .idea/ .mypy_cache/ .pytest_cache/ .tox/ .venv*/ .vs/ .vscode/ build/ dist/ docs/_build/ htmlcov/ pip-wheel-metadata/ wheels/ play/ __pycache__/ *.cover *.egg *.egg-info *.log *.py[cod] graphql-core-3.2.6/.mypy.ini000066400000000000000000000006601474546154300157020ustar00rootroot00000000000000[mypy] python_version = 3.9 check_untyped_defs = True no_implicit_optional = True strict_optional = True warn_redundant_casts = True warn_unused_ignores = True disallow_untyped_defs = True [mypy-graphql.pyutils.frozen_dict] disallow_untyped_defs = False [mypy-graphql.pyutils.frozen_list] disallow_untyped_defs = False [mypy-graphql.type.introspection] disallow_untyped_defs = False [mypy-tests.*] disallow_untyped_defs = False graphql-core-3.2.6/.readthedocs.yaml000066400000000000000000000005241474546154300173530ustar00rootroot00000000000000# .readthedocs.yaml # Read the Docs configuration file # See https://docs.readthedocs.io/en/stable/config-file/v2.html version: 2 build: os: ubuntu-20.04 tools: python: "3.9" sphinx: configuration: docs/conf.py formats: - epub - pdf python: install: - requirements: docs/requirements.txt - method: pip path: . graphql-core-3.2.6/CODEOWNERS000066400000000000000000000000071474546154300155130ustar00rootroot00000000000000* @Citographql-core-3.2.6/LICENSE000066400000000000000000000022341474546154300151310ustar00rootroot00000000000000MIT License Copyright (c) GraphQL Contributors (GraphQL.js) Copyright (c) Syrus Akbary (GraphQL-core 2) Copyright (c) Christoph Zwerschke (GraphQL-core 3) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. graphql-core-3.2.6/MANIFEST.in000066400000000000000000000007001474546154300156560ustar00rootroot00000000000000include MANIFEST.in include CODEOWNERS include LICENSE include README.md include SECURITY.md include .bumpversion.cfg include .coveragerc include .editorconfig include .flake8 include .mypy.ini include .readthedocs.yaml include tox.ini include poetry.lock include pyproject.toml graft src/graphql graft tests recursive-include docs *.txt *.rst conf.py Makefile make.bat *.jpg *.png *.gif prune docs/_build global-exclude *.py[co] __pycache__ graphql-core-3.2.6/README.md000066400000000000000000000227121474546154300154060ustar00rootroot00000000000000# GraphQL-core 3 GraphQL-core 3 is a Python 3.6+ port of [GraphQL.js](https://github.com/graphql/graphql-js), the JavaScript reference implementation for [GraphQL](https://graphql.org/), a query language for APIs created by Facebook. [![PyPI version](https://badge.fury.io/py/graphql-core.svg)](https://badge.fury.io/py/graphql-core) [![Documentation Status](https://readthedocs.org/projects/graphql-core-3/badge/)](https://graphql-core-3.readthedocs.io) ![Test Status](https://github.com/graphql-python/graphql-core/actions/workflows/test.yml/badge.svg) ![Lint Status](https://github.com/graphql-python/graphql-core/actions/workflows/lint.yml/badge.svg) [![Code Style](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/ambv/black) The current version 3.2.6 of GraphQL-core is up-to-date with GraphQL.js version 16.8.2. An extensive test suite with over 2500 unit tests and 100% coverage comprises a replication of the complete test suite of GraphQL.js, making sure this port is reliable and compatible with GraphQL.js. Note that for various reasons, GraphQL-core does not use SemVer like GraphQL.js. Changes in the major version of GraphQL.js are reflected in the minor version of GraphQL-core instead. This means there can be breaking changes in the API when the minor version changes, and only patch releases are fully backward compatible. Therefore, we recommend using something like `~= 3.2.0` as the version specifier when including GraphQL-core as a dependency. ## Documentation A more detailed documentation for GraphQL-core 3 can be found at [graphql-core-3.readthedocs.io](https://graphql-core-3.readthedocs.io/). The documentation for GraphQL.js can be found at [graphql.org/graphql-js/](https://graphql.org/graphql-js/). The documentation for GraphQL itself can be found at [graphql.org](https://graphql.org/). There will be also [blog articles](https://cito.github.io/tags/graphql/) with more usage examples. ## Getting started A general overview of GraphQL is available in the [README](https://github.com/graphql/graphql-spec/blob/main/README.md) for the [Specification for GraphQL](https://github.com/graphql/graphql-spec). That overview describes a simple set of GraphQL examples that exist as [tests](tests) in this repository. A good way to get started with this repository is to walk through that README and the corresponding tests in parallel. ## Installation GraphQL-core 3 can be installed from PyPI using the built-in pip command: python -m pip install graphql-core You can also use [poetry](https://github.com/python-poetry/poetry) for installation in a virtual environment: poetry install ## Usage GraphQL-core provides two important capabilities: building a type schema and serving queries against that type schema. First, build a GraphQL type schema which maps to your codebase: ```python from graphql import ( GraphQLSchema, GraphQLObjectType, GraphQLField, GraphQLString) schema = GraphQLSchema( query=GraphQLObjectType( name='RootQueryType', fields={ 'hello': GraphQLField( GraphQLString, resolve=lambda obj, info: 'world') })) ``` This defines a simple schema, with one type and one field, that resolves to a fixed value. The `resolve` function can return a value, a co-routine object or a list of these. It takes two positional arguments; the first one provides the root or the resolved parent field, the second one provides a `GraphQLResolveInfo` object which contains information about the execution state of the query, including a `context` attribute holding per-request state such as authentication information or database session. Any GraphQL arguments are passed to the `resolve` functions as individual keyword arguments. Note that the signature of the resolver functions is a bit different in GraphQL.js, where the context is passed separately and arguments are passed as a single object. Also note that GraphQL fields must be passed as a `GraphQLField` object explicitly. Similarly, GraphQL arguments must be passed as `GraphQLArgument` objects. A more complex example is included in the top-level [tests](tests) directory. Then, serve the result of a query against that type schema. ```python from graphql import graphql_sync source = '{ hello }' print(graphql_sync(schema, source)) ``` This runs a query fetching the one field defined, and then prints the result: ```python ExecutionResult(data={'hello': 'world'}, errors=None) ``` The `graphql_sync` function will first ensure the query is syntactically and semantically valid before executing it, reporting errors otherwise. ```python from graphql import graphql_sync source = '{ BoyHowdy }' print(graphql_sync(schema, source)) ``` Because we queried a non-existing field, we will get the following result: ```python ExecutionResult(data=None, errors=[GraphQLError( "Cannot query field 'BoyHowdy' on type 'RootQueryType'.", locations=[SourceLocation(line=1, column=3)])]) ``` The `graphql_sync` function assumes that all resolvers return values synchronously. By using coroutines as resolvers, you can also create results in an asynchronous fashion with the `graphql` function. ```python import asyncio from graphql import ( graphql, GraphQLSchema, GraphQLObjectType, GraphQLField, GraphQLString) async def resolve_hello(obj, info): await asyncio.sleep(3) return 'world' schema = GraphQLSchema( query=GraphQLObjectType( name='RootQueryType', fields={ 'hello': GraphQLField( GraphQLString, resolve=resolve_hello) })) async def main(): query = '{ hello }' print('Fetching the result...') result = await graphql(schema, query) print(result) asyncio.run(main()) ``` ## Goals and restrictions GraphQL-core tries to reproduce the code of the reference implementation GraphQL.js in Python as closely as possible and to stay up-to-date with the latest development of GraphQL.js. GraphQL-core 3 (formerly known as GraphQL-core-next) has been created as a modern alternative to [GraphQL-core 2](https://github.com/graphql-python/graphql-core-legacy), a prior work by Syrus Akbary, based on an older version of GraphQL.js and also targeting older Python versions. Some parts of GraphQL-core 3 have been inspired by GraphQL-core 2 or directly taken over with only slight modifications, but most of the code has been re-implemented from scratch, replicating the latest code in GraphQL.js very closely and adding type hints for Python. Design goals for the GraphQL-core 3 library were: * to be a simple, cruft-free, state-of-the-art GraphQL implementation for current Python versions * to be very close to the GraphQL.js reference implementation, while still providing a Pythonic API and code style * to make extensive use of Python type hints, similar to how GraphQL.js used Flow (and is now using TypeScript) * to use [black](https://github.com/ambv/black) to achieve a consistent code style while saving time and mental energy for more important matters * to replicate the complete Mocha-based test suite of GraphQL.js using [pytest](https://docs.pytest.org/) with [pytest-describe](https://pypi.org/project/pytest-describe/) Some restrictions (mostly in line with the design goals): * requires Python 3.6 or newer * does not support some already deprecated methods and options of GraphQL.js * supports asynchronous operations only via async.io (does not support the additional executors in GraphQL-core) Note that meanwhile we are using the amazing [ruff](https://docs.astral.sh/ruff/) tool to both format and check the code of GraphQL-core 3, in addition to using [mypy](https://mypy-lang.org/) as type checker. ## Integration with other libraries and roadmap * [Graphene](http://graphene-python.org/) is a more high-level framework for building GraphQL APIs in Python, and there is already a whole ecosystem of libraries, server integrations and tools built on top of Graphene. Most of this Graphene ecosystem has also been created by Syrus Akbary, who meanwhile has handed over the maintenance and future development to members of the GraphQL-Python community. Graphene 3 is now using Graphql-core 3 as core library for much of the heavy lifting. * [Ariadne](https://github.com/mirumee/ariadne) is a Python library for implementing GraphQL servers using schema-first approach created by Mirumee Software. Ariadne is also using GraphQL-core 3 as its GraphQL implementation. * [Strawberry](https://github.com/strawberry-graphql/strawberry), created by Patrick Arminio, is a new GraphQL library for Python 3, inspired by dataclasses, that is also using GraphQL-core 3 as underpinning. ## Changelog Changes are tracked as [GitHub releases](https://github.com/graphql-python/graphql-core/releases). ## Credits and history The GraphQL-core 3 library * has been created and is maintained by Christoph Zwerschke * uses ideas and code from GraphQL-core 2, a prior work by Syrus Akbary * is a Python port of GraphQL.js which has been developed by Lee Byron and others at Facebook, Inc. and is now maintained by the [GraphQL foundation](https://gql.foundation/join/) Please watch the recording of Lee Byron's short keynote on the [history of GraphQL](https://www.youtube.com/watch?v=VjHWkBr3tjI) at the open source leadership summit 2019 to better understand how and why GraphQL was created at Facebook and then became open sourced and ported to many different programming languages. ## License GraphQL-core 3 is [MIT-licensed](./LICENSE), just like GraphQL.js. graphql-core-3.2.6/SECURITY.md000066400000000000000000000013301474546154300157110ustar00rootroot00000000000000# Security Policy ## Supported Versions | Version | Supported | | ------- | ------------------ | | >= 3.2 | :white_check_mark: | | < 3.2 | :x: | ## Reporting a Vulnerability You should report any vulnerabilities privately to [Cito](https://github.com/Cito) as the current maintainer of this repository, but note that he is working on the project voluntary in his spare time, so please be patient with him. Please do not use the public Issue tracker of this repository to disclose security related issues. Also, please keep in mind that this repository is actually a port of the [GraphQL.js](https://github.com/graphql/graphql-js). Issues that also affect upstream should be also reported there. graphql-core-3.2.6/docs/000077500000000000000000000000001474546154300150535ustar00rootroot00000000000000graphql-core-3.2.6/docs/Makefile000066400000000000000000000011721474546154300165140ustar00rootroot00000000000000# Minimal makefile for Sphinx documentation # # You can set these variables from the command line, and also # from the environment for the first two. SPHINXOPTS ?= SPHINXBUILD ?= sphinx-build SOURCEDIR = . BUILDDIR = _build # Put it first so that "make" without argument is like "make help". help: @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) .PHONY: help Makefile # Catch-all target: route all unknown targets to Sphinx using the new # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). %: Makefile @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) graphql-core-3.2.6/docs/conf.py000066400000000000000000000352351474546154300163620ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # GraphQL-core 3 documentation build configuration file, created by # sphinx-quickstart on Thu Jun 21 16:28:30 2018. # # This file is execfile()d with the current directory set to its # containing dir. # # Note that not all possible configuration values are present in this # autogenerated file. # # All configuration values have a default; values that are commented out # serve to show the default. # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. # # import os # import sys # sys.path.insert(0, os.path.abspath('.')) # -- General configuration ------------------------------------------------ # If your documentation needs a minimal Sphinx version, state it here. # # needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ "sphinx.ext.autodoc", ] # Add any paths that contain templates here, relative to this directory. templates_path = ["_templates"] # The suffix(es) of source filenames. # You can specify multiple suffix as a list of string: # # source_suffix = ['.rst', '.md'] source_suffix = ".rst" # The encoding of source files. # # source_encoding = 'utf-8-sig' # The master toctree document. master_doc = "index" # General information about the project. project = "GraphQL-core 3" copyright = "2025, Christoph Zwerschke" author = "Christoph Zwerschke" # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. # version = '3.2' # The full version, including alpha/beta/rc tags. version = release = "3.2.6" # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. # # This is also used if you do content translation via gettext catalogs. # Usually you set "language" from the command line for these cases. language = "en" # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: # # today = '' # # Else, today_fmt is used as the format for a strftime call. # # today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This patterns also effect to html_static_path and html_extra_path exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] # AutoDoc configuration autoclass_content = "class" autodoc_default_options = { "members": True, "inherited-members": True, "undoc-members": True, "show-inheritance": True, } autosummary_generate = True autodoc_type_aliases = { "AwaitableOrValue": "graphql.pyutils.AwaitableOrValue", "FormattedSourceLocation": "graphql.language.FormattedSourceLocation", "Middleware": "graphql.execution.Middleware", "TypeMap": "graphql.schema.TypeMap", } # GraphQL-core top level modules with submodules that can be omitted. # Sometimes autodoc cannot find classes since it is looking for the # qualified form, but the documentation has the shorter form. # We need to give autodoc a little help in this cases. graphql_modules = { "error": ["graphql_error"], "execution": ["execute", "middleware"], "language": [ "ast", "directive_locations", "location", "source", "token_kind", "visitor", ], "pyutils": ["simple_pub_sub", "frozen_list", "path"], "type": ["definition", "directives", "schema"], "utilities": ["find_breaking_changes", "type_info"], "validation": ["rules", "validation_context"], } # GraphQL-core classes that autodoc sometimes cannot find # (e.g. where specified as string in type hints). # We need to give autodoc a little help in this cases, too: graphql_classes = { "GraphQLAbstractType": "type", "GraphQLObjectType": "type", "GraphQLOutputType": "type", "GraphQLTypeResolver": "type", "Node": "language", "Source": "language", "SourceLocation": "language", } # ignore the following undocumented or internal references: ignore_references = set( """ GNT GT KT T VT enum.Enum traceback types.TracebackType EnterLeaveVisitor FormattedSourceLocation GraphQLAbstractType GraphQLErrorExtensions GraphQLOutputType asyncio.events.AbstractEventLoop graphql.execution.map_async_iterator.MapAsyncIterator graphql.language.lexer.EscapeSequence graphql.language.visitor.EnterLeaveVisitor graphql.type.schema.InterfaceImplementations graphql.validation.validation_context.VariableUsage graphql.validation.rules.known_argument_names.KnownArgumentNamesOnDirectivesRule graphql.validation.rules.provided_required_arguments.ProvidedRequiredArgumentsOnDirectivesRule """.split() ) ignore_references.update(__builtins__.keys()) def on_missing_reference(app, env, node, contnode): """Fix or skip any missing references.""" if node.get("refdomain") != "py": return None target = node.get("reftarget") if not target: return None if target in ignore_references or target.endswith("Kwargs"): return contnode typ = node.get("reftype") name = target.rsplit(".", 1)[-1] if name in ("GT", "GNT", "KT", "T", "VT"): return contnode if typ == "obj": if target.startswith("typing."): if name in ("Any", "Optional", "Union"): return contnode if typ != "class": return None if "." in target: # maybe too specific base_module, target = target.split(".", 1) if base_module == "graphql": if "." not in target: return None base_module, target = target.split(".", 1) if "." not in target: return None sub_modules = graphql_modules.get(base_module) if not sub_modules: return sub_module = target.split(".", 1)[0] if sub_module not in sub_modules: return None target = "graphql." + base_module + "." + target.rsplit(".", 1)[-1] else: # maybe not specific enough base_module = graphql_classes.get(target) if not base_module: return None target = "graphql." + base_module + "." + target # replace target if contnode.__class__.__name__ == "Text": contnode = contnode.__class__(target) elif contnode.__class__.__name__ == "literal": if len(contnode.children) != 1: return None textnode = contnode.children[0] contnode.children[0] = textnode.__class__(target) else: return None node["reftarget"] = target fromdoc = node.get("refdoc") if not fromdoc: doc_module = node.get("py:module") if doc_module: if doc_module.startswith("graphql."): doc_module = doc_module.split(".", 1)[-1] if doc_module not in graphql_modules and doc_module != "graphql": doc_module = None fromdoc = "modules/" + (doc_module or base_module) # try resolving again with replaced target return env.domains["py"].resolve_xref( env, fromdoc, app.builder, typ, target, node, contnode ) def on_skip_member(_app, what, name, _obj, skip, _options): if what == "class" and name == "__init__": # we could set "special-members" to "__init__", # but this gives an error when documenting modules return False return skip def setup(app): app.connect("missing-reference", on_missing_reference) app.connect("autodoc-skip-member", on_skip_member) # be nitpicky (handle all possible problems in on_missing_reference) nitpicky = True # The reST default role (used for this markup: `text`) to use for all # documents. # # default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. # # add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). # # add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. # # show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = "sphinx" # A list of ignored prefixes for module index sorting. # modindex_common_prefix = [] # If true, keep warnings as "system message" paragraphs in the built documents. # keep_warnings = False # If true, `todo` and `todoList` produce output, else they produce nothing. todo_include_todos = False # -- Options for HTML output ---------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # html_theme = "sphinx_rtd_theme" # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. # html_theme_options = {"navigation_depth": 5} # Add any paths that contain custom themes here, relative to this directory. # html_theme_path = [] # The name for this set of Sphinx documents. # " v documentation" by default. # # html_title = 'GraphQL-core v3.1.0' # A shorter title for the navigation bar. Default is the same as html_title. # # html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. # # html_logo = None # The name of an image file (relative to this directory) to use as a favicon of # the docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. # # html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". # html_static_path = ['_static'] # Add any extra paths that contain custom files (such as robots.txt or # .htaccess) here, relative to this directory. These files are copied # directly to the root of the documentation. # # html_extra_path = [] # If not None, a 'Last updated on:' timestamp is inserted at every page # bottom, using the given strftime format. # The empty string is equivalent to '%b %d, %Y'. # # html_last_updated_fmt = None # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. # # html_use_smartypants = True # Custom sidebar templates, maps document names to template names. # # html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. # # html_additional_pages = {} # If false, no module index is generated. # # html_domain_indices = True # If false, no index is generated. # # html_use_index = True # If true, the index is split into individual pages for each letter. # # html_split_index = False # If true, links to the reST sources are added to the pages. # html_show_sourcelink = False # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. # # html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. # # html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. # # html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). # html_file_suffix = None # Language to be used for generating the HTML full-text search index. # Sphinx supports the following languages: # 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja' # 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr', 'zh' # # html_search_language = 'en' # A dictionary with options for the search language support, empty by default. # 'ja' uses this config value. # 'zh' user can custom change `jieba` dictionary path. # # html_search_options = {'type': 'default'} # The name of a javascript file (relative to the configuration directory) that # implements a search results scorer. If empty, the default will be used. # # html_search_scorer = 'scorer.js' # Output file base name for HTML help builder. htmlhelp_basename = "GraphQL-core-3-doc" # -- Options for LaTeX output --------------------------------------------- latex_elements = { # The paper size ('letterpaper' or 'a4paper'). # # 'papersize': 'letterpaper', # The font size ('10pt', '11pt' or '12pt'). # # 'pointsize': '10pt', # Additional stuff for the LaTeX preamble. # # 'preamble': '', # Latex figure (float) alignment # # 'figure_align': 'htbp', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ ( master_doc, "GraphQL-core-3.tex", "GraphQL-core 3 Documentation", "Christoph Zwerschke", "manual", ), ] # The name of an image file (relative to this directory) to place at the top of # the title page. # # latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. # # latex_use_parts = False # If true, show page references after internal links. # # latex_show_pagerefs = False # If true, show URL addresses after external links. # # latex_show_urls = False # Documents to append as an appendix to all manuals. # # latex_appendices = [] # If false, no module index is generated. # # latex_domain_indices = True # -- Options for manual page output --------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [(master_doc, "graphql-core", "GraphQL-core 3 Documentation", [author], 1)] # If true, show URL addresses after external links. # # man_show_urls = False # -- Options for Texinfo output ------------------------------------------- # Grouping the document tree into Texinfo files. List of tuples # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ ( master_doc, "GraphQL-core", "GraphQL-core 3 Documentation", author, "GraphQL-core 3", "One line description of project.", "Miscellaneous", ), ] # Documents to append as an appendix to all manuals. # # texinfo_appendices = [] # If false, no module index is generated. # # texinfo_domain_indices = True # How to display URL addresses: 'footnote', 'no', or 'inline'. # # texinfo_show_urls = 'footnote' # If true, do not generate a @detailmenu in the "Top" node's menu. # # texinfo_no_detailmenu = False graphql-core-3.2.6/docs/diffs.rst000066400000000000000000000131721474546154300167040ustar00rootroot00000000000000Differences from GraphQL.js =========================== The goal of GraphQL-core 3 is to be a faithful replication of `GraphQL.js`_, the JavaScript reference implementation for GraphQL, in Python 3, and to keep it aligned and up to date with the ongoing development of GraphQL.js. Therefore, we strive to be as compatible as possible to the original JavaScript library, sometimes at the cost of being less Pythonic than other libraries written particularly for Python. We also avoid incorporating additional features that do not exist in the JavaScript library, in order to keep the task of maintaining the Python code and keeping it in line with the JavaScript code manageable. The preferred way of getting new features into GraphQL-core is to propose and discuss them on the `GraphQL.js issue tracker`_ first, try to get them included into GraphQL.js, and from there ported to GraphQL-core. .. _GraphQL.js: https://github.com/graphql/graphql-js .. _GraphQL.js issue tracker: https://github.com/graphql/graphql-js/issues .. _Graphene: https://graphene-python.org/ .. currentmodule:: graphql Having said this, in a few places we allowed the API to be a bit more Pythonic than the direct equivalent would have been. We also added a few features that do not exist in the JavaScript library, mostly to support existing higher level libraries such as Graphene_ and the different naming conventions in Python. The most notable differences are the following: Direct attribute access in GraphQL types ---------------------------------------- You can access * the **fields** of GraphQLObjectTypes, GraphQLInterfaceTypes and GraphQLInputObjectTypes, * the **interfaces** of GraphQLObjectTypes, * the **types** of GraphQLUnionTypes, * the **values** of GraphQLEnumTypes and * the **query**, **mutation**, **subscription** and **type_map** of GraphQLSchemas directly as attributes, instead of using getters. For example, to get the fields of a GraphQLObjectType ``obj``, you write ``obj.fields`` instead of ``obj.getFields()``. Arguments, fields and values are dictionaries --------------------------------------------- * The **arguments** of GraphQLDirectives and GraphQLFields, * the **fields** of GraphQLObjectTypes, GraphQLInterfaceTypes and GraphQLInputObjectTypes, and * the **values** of GraphQLEnumTypes are always Python dictionaries in GraphQL-core, while they are returned as Arrays in GraphQL.js. Also, the values of these dictionaries do not have ``name`` attributes, since the names are already used as the keys of these dictionaries. Shorthand notation for creating GraphQL types --------------------------------------------- The following shorthand notations are possible: * Where you need to pass a GraphQLArgumentMap, i.e. a dictionary with names as keys and GraphQLArguments as values, you can also pass GraphQLInputTypes as values. The GraphQLInputTypes are then automatically wrapped into GraphQLArguments. * Where you need to pass a GraphQLFieldMap, i.e. a dictionary with names as keys and GraphQLFields as values, you can also pass GraphQLOutputTypes as values. The GraphQLOutputTypes are then automatically wrapped into GraphQLFields. * Where you need to pass a GraphQLInputFieldMap, i.e. a dictionary with names as keys and GraphQLInputFields as values, you can also pass GraphQLInputTypes as values. The GraphQLInputTypes are then automatically wrapped into GraphQLInputFields. * Where you need to pass a GraphQLEnumValueMap, i.e. a dictionary with names as keys and GraphQLEnumValues as values, you can pass any other Python objects as values. These will be automatically wrapped into GraphQLEnumValues. You can also pass a Python Enum type as GraphQLEnumValueMap. .. currentmodule:: graphql.type Custom output names of arguments and input fields ------------------------------------------------- You can pass a custom ``out_name`` argument to :class:`GraphQLArgument` and :class:`GraphQLInputField` that allows using JavaScript naming conventions (camelCase) on ingress and Python naming conventions (snake_case) on egress. This feature is used by Graphene. Custom output types of input object types ----------------------------------------- You can also pass a custom ``out_type`` argument to :class:`GraphQLInputObjectType` that allows conversion to any Python type on egress instead of conversion to a dictionary, which is the default. This is used to support the container feature of Graphene InputObjectTypes. .. currentmodule:: graphql.execution Custom middleware ----------------- The :func:`execute` function takes an additional ``middleware`` argument which must be a sequence of middleware functions or a :class:`MiddlewareManager` object. This feature is used by Graphene to affect the evaluation of fields using custom middleware. There has been a `request `_ to add this to GraphQL.js as well, but so far this feature only exists in GraphQL-core. Custom execution context ------------------------ The :func:`execute` function takes an additional ``execution_context_class`` argument which allows specifying a custom execution context class instead of the default :class:`ExecutionContext` used by GraphQL-core. .. currentmodule:: graphql Registering special types for descriptions ------------------------------------------ Normally, descriptions for GraphQL types must be strings. However, sometimes you may want to use other kinds of objects which are not strings, but are only resolved to strings at runtime. This is possible if you register the classes of such objects with :func:`pyutils.register_description`. If you notice any other important differences, please let us know so that they can be either removed or listed here. graphql-core-3.2.6/docs/index.rst000066400000000000000000000003701474546154300167140ustar00rootroot00000000000000Welcome to GraphQL-core 3 ========================= Contents -------- .. toctree:: :maxdepth: 2 intro usage/index diffs modules/graphql Indices and tables ------------------ * :ref:`genindex` * :ref:`modindex` * :ref:`search` graphql-core-3.2.6/docs/intro.rst000066400000000000000000000062661474546154300167520ustar00rootroot00000000000000Introduction ============ `GraphQL-core-3`_ is a Python port of `GraphQL.js`_, the JavaScript reference implementation for GraphQL_, a query language for APIs created by Facebook. `GraphQL`_ consists of three parts: * A type system that you define * A query language that you use to query the API * An execution and validation engine The reference implementation closely follows the `Specification for GraphQL`_ which consists of the following sections: * Language_ * `Type System`_ * Introspection_ * Validation_ * Execution_ * Response_ This division into subsections is reflected in the :ref:`sub-packages` of GraphQL-core 3. Each of these sub-packages implements the aspects specified in one of the sections of the specification. Getting started --------------- You can install GraphQL-core 3 using pip_:: pip install graphql-core You can also install GraphQL-core 3 with poetry_, if you prefer that:: poetry install Now you can start using GraphQL-core 3 by importing from the top-level :mod:`graphql` package. Nearly everything defined in the sub-packages can also be imported directly from the top-level package. .. currentmodule:: graphql For instance, using the types defined in the :mod:`graphql.type` package, you can define a GraphQL schema, like this simple one:: from graphql import ( GraphQLSchema, GraphQLObjectType, GraphQLField, GraphQLString) schema = GraphQLSchema( query=GraphQLObjectType( name='RootQueryType', fields={ 'hello': GraphQLField( GraphQLString, resolve=lambda obj, info: 'world') })) The :mod:`graphql.execution` package implements the mechanism for executing GraphQL queries. The top-level :func:`graphql` and :func:`graphql_sync` functions also parse and validate queries using the :mod:`graphql.language` and :mod:`graphql.validation` modules. So to validate and execute a query against our simple schema, you can do:: from graphql import graphql_sync query = '{ hello }' print(graphql_sync(schema, query)) This will yield the following output:: ExecutionResult(data={'hello': 'world'}, errors=None) Reporting Issues and Contributing --------------------------------- Please visit the `GitHub repository of GraphQL-core 3`_ if you're interested in the current development or want to report issues or send pull requests. .. _GraphQL: https://graphql.org/ .. _GraphQL.js: https://github.com/graphql/graphql-js .. _GraphQL-core-3: https://github.com/graphql-python/graphql-core .. _GitHub repository of GraphQL-core 3: https://github.com/graphql-python/graphql-core .. _Specification for GraphQL: https://facebook.github.io/graphql/ .. _Language: https://facebook.github.io/graphql/draft/#sec-Language .. _Type System: https://facebook.github.io/graphql/draft/#sec-Type-System .. _Introspection: https://facebook.github.io/graphql/draft/#sec-Introspection .. _Validation: https://facebook.github.io/graphql/draft/#sec-Validation .. _Execution: https://facebook.github.io/graphql/draft/#sec-Execution .. _Response: https://facebook.github.io/graphql/draft/#sec-Response .. _pip: https://pip.pypa.io/ .. _poetry: https://github.com/python-poetry/poetry graphql-core-3.2.6/docs/make.bat000066400000000000000000000013701474546154300164610ustar00rootroot00000000000000@ECHO OFF pushd %~dp0 REM Command file for Sphinx documentation if "%SPHINXBUILD%" == "" ( set SPHINXBUILD=sphinx-build ) set SOURCEDIR=. set BUILDDIR=_build if "%1" == "" goto help %SPHINXBUILD% >NUL 2>NUL if errorlevel 9009 ( echo. echo.The 'sphinx-build' command was not found. Make sure you have Sphinx echo.installed, then set the SPHINXBUILD environment variable to point echo.to the full path of the 'sphinx-build' executable. Alternatively you echo.may add the Sphinx directory to PATH. echo. echo.If you don't have Sphinx installed, grab it from echo.http://sphinx-doc.org/ exit /b 1 ) %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% goto end :help %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% :end popd graphql-core-3.2.6/docs/modules/000077500000000000000000000000001474546154300165235ustar00rootroot00000000000000graphql-core-3.2.6/docs/modules/error.rst000066400000000000000000000004601474546154300204060ustar00rootroot00000000000000Error ===== .. currentmodule:: graphql.error .. automodule:: graphql.error :no-members: :no-inherited-members: .. autoclass:: GraphQLError .. autoclass:: GraphQLSyntaxError .. autoclass:: GraphQLFormattedError :no-inherited-members: :no-special-members: .. autofunction:: located_error graphql-core-3.2.6/docs/modules/execution.rst000066400000000000000000000012211474546154300212540ustar00rootroot00000000000000Execution ========= .. currentmodule:: graphql.execution .. automodule:: graphql.execution :no-members: :no-inherited-members: .. autofunction:: execute .. autofunction:: execute_sync .. autofunction:: default_field_resolver .. autofunction:: default_type_resolver .. autoclass:: ExecutionContext .. autoclass:: ExecutionResult .. autoclass:: FormattedExecutionResult :no-inherited-members: .. autofunction:: subscribe .. autofunction:: create_source_event_stream .. autoclass:: MapAsyncIterator .. autoclass:: Middleware .. autoclass:: MiddlewareManager .. autofunction:: get_directive_values .. autofunction:: get_variable_values graphql-core-3.2.6/docs/modules/graphql.rst000066400000000000000000000006151474546154300207150ustar00rootroot00000000000000Reference ========= .. currentmodule:: graphql .. automodule:: graphql :no-members: :no-inherited-members: .. _top-level-functions: Top-Level Functions ------------------- .. autofunction:: graphql .. autofunction:: graphql_sync .. _sub-packages: Sub-Packages ------------ .. toctree:: :maxdepth: 2 error execution language pyutils type utilities validation graphql-core-3.2.6/docs/modules/language.rst000066400000000000000000000103211474546154300210350ustar00rootroot00000000000000Language ======== .. currentmodule:: graphql.language .. automodule:: graphql.language :no-members: :no-inherited-members: AST --- .. autoclass:: Location .. autoclass:: Node Each kind of AST node has its own class: .. autoclass:: ArgumentNode .. autoclass:: BooleanValueNode .. autoclass:: ConstArgumentNode .. autoclass:: ConstDirectiveNode .. autoclass:: ConstListValueNode .. autoclass:: ConstObjectFieldNode .. autoclass:: ConstObjectValueNode .. autoclass:: ConstValueNode .. autoclass:: DefinitionNode .. autoclass:: DirectiveDefinitionNode .. autoclass:: DirectiveNode .. autoclass:: DocumentNode .. autoclass:: EnumTypeDefinitionNode .. autoclass:: EnumTypeExtensionNode .. autoclass:: EnumValueDefinitionNode .. autoclass:: EnumValueNode .. autoclass:: ExecutableDefinitionNode .. autoclass:: FieldDefinitionNode .. autoclass:: FieldNode .. autoclass:: FloatValueNode .. autoclass:: FragmentDefinitionNode .. autoclass:: FragmentSpreadNode .. autoclass:: InlineFragmentNode .. autoclass:: InputObjectTypeDefinitionNode .. autoclass:: InputObjectTypeExtensionNode .. autoclass:: InputValueDefinitionNode .. autoclass:: IntValueNode .. autoclass:: InterfaceTypeDefinitionNode .. autoclass:: InterfaceTypeExtensionNode .. autoclass:: ListTypeNode .. autoclass:: ListValueNode .. autoclass:: NameNode .. autoclass:: NamedTypeNode .. autoclass:: NonNullTypeNode .. autoclass:: NullValueNode .. autoclass:: ObjectFieldNode .. autoclass:: ObjectTypeDefinitionNode .. autoclass:: ObjectTypeExtensionNode .. autoclass:: ObjectValueNode .. autoclass:: OperationDefinitionNode .. autoclass:: OperationType .. autoclass:: OperationTypeDefinitionNode .. autoclass:: ScalarTypeDefinitionNode .. autoclass:: ScalarTypeExtensionNode .. autoclass:: SchemaDefinitionNode .. autoclass:: SchemaExtensionNode .. autoclass:: SelectionNode .. autoclass:: SelectionSetNode .. autoclass:: StringValueNode .. autoclass:: TypeDefinitionNode .. autoclass:: TypeExtensionNode .. autoclass:: TypeNode .. autoclass:: TypeSystemDefinitionNode .. autoclass:: TypeSystemExtensionNode .. autoclass:: UnionTypeDefinitionNode .. autoclass:: UnionTypeExtensionNode .. autoclass:: ValueNode .. autoclass:: VariableDefinitionNode .. autoclass:: VariableNode Directive locations are specified using the following enumeration: .. autoclass:: DirectiveLocation You can also check the type of nodes with the following predicates: .. autofunction:: is_definition_node .. autofunction:: is_executable_definition_node .. autofunction:: is_selection_node .. autofunction:: is_value_node .. autofunction:: is_const_value_node .. autofunction:: is_type_node .. autofunction:: is_type_system_definition_node .. autofunction:: is_type_definition_node .. autofunction:: is_type_system_extension_node .. autofunction:: is_type_extension_node Lexer ----- .. autoclass:: Lexer .. autoclass:: TokenKind .. autoclass:: Token Location -------- .. autofunction:: get_location .. autoclass:: SourceLocation .. autofunction:: print_location .. autoclass:: FormattedSourceLocation :no-inherited-members: Parser ------ .. autofunction:: parse .. autofunction:: parse_type .. autofunction:: parse_value .. autofunction:: parse_const_value Printer ------- .. autofunction:: print_ast Source ------ .. autoclass:: Source .. autofunction:: print_source_location Visitor ------- .. autofunction:: visit .. autoclass:: Visitor .. autoclass:: ParallelVisitor The module also exports the following enumeration that can be used as the return type for :class:`Visitor` methods: .. currentmodule:: graphql.language.visitor .. autoclass:: VisitorActionEnum .. currentmodule:: graphql.language The module also exports the values of this enumeration directly. These can be used as return values of :class:`Visitor` methods to signal particular actions: .. data:: BREAK :annotation: (same as ``True``) This return value signals that no further nodes shall be visited. .. data:: SKIP :annotation: (same as ``False``) This return value signals that the current node shall be skipped. .. data:: REMOVE :annotation: (same as``Ellipsis``) This return value signals that the current node shall be deleted. .. data:: IDLE :annotation: = None This return value signals that no additional action shall take place. graphql-core-3.2.6/docs/modules/pyutils.rst000066400000000000000000000015001474546154300207620ustar00rootroot00000000000000PyUtils ======= .. currentmodule:: graphql.pyutils .. automodule:: graphql.pyutils :no-members: :no-inherited-members: .. autofunction:: camel_to_snake .. autofunction:: snake_to_camel .. autofunction:: cached_property .. autofunction:: register_description .. autofunction:: unregister_description .. autofunction:: did_you_mean .. autofunction:: identity_func .. autofunction:: inspect .. autofunction:: is_awaitable .. autofunction:: is_collection .. autofunction:: is_iterable .. autofunction:: natural_comparison_key .. autoclass:: AwaitableOrValue .. autofunction:: suggestion_list .. autoclass:: FrozenError :no-members: :no-inherited-members: :no-special-members: .. autoclass:: Path .. autofunction:: print_path_list .. autoclass:: SimplePubSub .. autoclass:: SimplePubSubIterator .. autodata:: Undefined graphql-core-3.2.6/docs/modules/type.rst000066400000000000000000000104261474546154300202410ustar00rootroot00000000000000Type ==== .. currentmodule:: graphql.type .. automodule:: graphql.type :no-members: :no-inherited-members: Definition ---------- Predicates ^^^^^^^^^^ .. autofunction:: is_composite_type .. autofunction:: is_enum_type .. autofunction:: is_input_object_type .. autofunction:: is_input_type .. autofunction:: is_interface_type .. autofunction:: is_leaf_type .. autofunction:: is_list_type .. autofunction:: is_named_type .. autofunction:: is_non_null_type .. autofunction:: is_nullable_type .. autofunction:: is_object_type .. autofunction:: is_output_type .. autofunction:: is_scalar_type .. autofunction:: is_type .. autofunction:: is_union_type .. autofunction:: is_wrapping_type Assertions ^^^^^^^^^^ .. autofunction:: assert_abstract_type .. autofunction:: assert_composite_type .. autofunction:: assert_enum_type .. autofunction:: assert_input_object_type .. autofunction:: assert_input_type .. autofunction:: assert_interface_type .. autofunction:: assert_leaf_type .. autofunction:: assert_list_type .. autofunction:: assert_named_type .. autofunction:: assert_non_null_type .. autofunction:: assert_nullable_type .. autofunction:: assert_object_type .. autofunction:: assert_output_type .. autofunction:: assert_scalar_type .. autofunction:: assert_type .. autofunction:: assert_union_type .. autofunction:: assert_wrapping_type Un-modifiers ^^^^^^^^^^^^ .. autofunction:: get_nullable_type .. autofunction:: get_named_type Definitions ^^^^^^^^^^^ .. autoclass:: GraphQLEnumType .. autoclass:: GraphQLInputObjectType .. autoclass:: GraphQLInterfaceType .. autoclass:: GraphQLObjectType .. autoclass:: GraphQLScalarType .. autoclass:: GraphQLUnionType Type Wrappers ^^^^^^^^^^^^^ .. autoclass:: GraphQLList .. autoclass:: GraphQLNonNull Types ^^^^^ .. autoclass:: GraphQLAbstractType .. autoclass:: GraphQLArgument .. autoclass:: GraphQLArgumentMap .. autoclass:: GraphQLCompositeType .. autoclass:: GraphQLEnumValue .. autoclass:: GraphQLEnumValueMap .. autoclass:: GraphQLField .. autoclass:: GraphQLFieldMap .. autoclass:: GraphQLInputField .. autoclass:: GraphQLInputFieldMap .. autoclass:: GraphQLInputType .. autoclass:: GraphQLLeafType .. autoclass:: GraphQLNamedType .. autoclass:: GraphQLNullableType .. autoclass:: GraphQLOutputType .. autoclass:: GraphQLType .. autoclass:: GraphQLWrappingType .. autoclass:: Thunk .. autoclass:: ThunkCollection .. autoclass:: ThunkMapping Resolvers ^^^^^^^^^ .. autoclass:: GraphQLFieldResolver .. autoclass:: GraphQLIsTypeOfFn .. autoclass:: GraphQLResolveInfo .. autoclass:: GraphQLTypeResolver Directives ---------- Predicates ^^^^^^^^^^ .. autofunction:: is_directive .. autofunction:: is_specified_directive Definitions ^^^^^^^^^^^ .. autoclass:: GraphQLDirective .. autoclass:: GraphQLIncludeDirective .. autoclass:: GraphQLSkipDirective .. autoclass:: GraphQLDeprecatedDirective .. data:: specified_directives A tuple with all directives from the GraphQL specification .. data:: DEFAULT_DEPRECATION_REASON :annotation: = 'No longer supported' String constant that can be used as the default value for ``deprecation_reason``. Introspection ------------- Predicates ^^^^^^^^^^ .. autofunction:: is_introspection_type Definitions ^^^^^^^^^^^ .. autoclass:: TypeKind .. autoclass:: TypeMetaFieldDef .. autoclass:: TypeNameMetaFieldDef .. autoclass:: SchemaMetaFieldDef .. data:: introspection_types This is a mapping containing all introspection types with their names as keys Scalars ------- Predicates ^^^^^^^^^^ .. autofunction:: is_specified_scalar_type Definitions ^^^^^^^^^^^ .. autoclass:: GraphQLBoolean .. autoclass:: GraphQLFloat .. autoclass:: GraphQLID .. autoclass:: GraphQLInt .. autoclass:: GraphQLString .. data:: GRAPHQL_MAX_INT Maximum possible Int value as per GraphQL Spec (32-bit signed integer) .. data:: GRAPHQL_MIN_INT Minimum possible Int value as per GraphQL Spec (32-bit signed integer) Schema ------ Predicates ^^^^^^^^^^ .. autofunction:: is_schema Definitions ^^^^^^^^^^^ .. autoclass:: GraphQLSchema Validate -------- Functions ^^^^^^^^^ .. autofunction:: validate_schema Assertions ^^^^^^^^^^ .. autofunction:: assert_valid_schema Other ----- Thunk Handling ^^^^^^^^^^^^^^ .. autofunction:: resolve_thunk Assertions ^^^^^^^^^^ .. autofunction:: assert_name .. autofunction:: assert_enum_value_name graphql-core-3.2.6/docs/modules/utilities.rst000066400000000000000000000051061474546154300212720ustar00rootroot00000000000000Utilities ========= .. currentmodule:: graphql.utilities .. automodule:: graphql.utilities :no-members: :no-inherited-members: The GraphQL query recommended for a full schema introspection: .. autofunction:: get_introspection_query .. autoclass:: IntrospectionQuery :no-inherited-members: Get the target Operation from a Document: .. autofunction:: get_operation_ast Get the Type for the target Operation AST: .. autofunction:: get_operation_root_type Convert a GraphQLSchema to an IntrospectionQuery: .. autofunction:: introspection_from_schema Build a GraphQLSchema from an introspection result: .. autofunction:: build_client_schema Build a GraphQLSchema from GraphQL Schema language: .. autofunction:: build_ast_schema .. autofunction:: build_schema Extend an existing GraphQLSchema from a parsed GraphQL Schema language AST: .. autofunction:: extend_schema Sort a GraphQLSchema: .. autofunction:: lexicographic_sort_schema Print a GraphQLSchema to GraphQL Schema language: .. autofunction:: print_introspection_schema .. autofunction:: print_schema .. autofunction:: print_type Create a GraphQLType from a GraphQL language AST: .. autofunction:: type_from_ast Convert a language AST to a dictionary: .. autofunction:: ast_to_dict Create a Python value from a GraphQL language AST with a type: .. autofunction:: value_from_ast Create a Python value from a GraphQL language AST without a type: .. autofunction:: value_from_ast_untyped Create a GraphQL language AST from a Python value: .. autofunction:: ast_from_value A helper to use within recursive-descent visitors which need to be aware of the GraphQL type system: .. autoclass:: TypeInfo .. autoclass:: TypeInfoVisitor Coerce a Python value to a GraphQL type, or produce errors: .. autofunction:: coerce_input_value Concatenate multiple ASTs together: .. autofunction:: concat_ast Separate an AST into an AST per Operation: .. autofunction:: separate_operations Strip characters that are not significant to the validity or execution of a GraphQL document: .. autofunction:: strip_ignored_characters Comparators for types: .. autofunction:: is_equal_type .. autofunction:: is_type_sub_type_of .. autofunction:: do_types_overlap Assert that a string is a valid GraphQL name: .. autofunction:: assert_valid_name .. autofunction:: is_valid_name_error Compare two GraphQLSchemas and detect breaking changes: .. autofunction:: find_breaking_changes .. autofunction:: find_dangerous_changes .. autoclass:: BreakingChange .. autoclass:: BreakingChangeType .. autoclass:: DangerousChange .. autoclass:: DangerousChangeType graphql-core-3.2.6/docs/modules/validation.rst000066400000000000000000000062671474546154300214220ustar00rootroot00000000000000Validation ========== .. currentmodule:: graphql.validation .. automodule:: graphql.validation :no-members: :no-inherited-members: .. autofunction:: validate .. autoclass:: ASTValidationContext .. autoclass:: ASTValidationRule .. autoclass:: SDLValidationContext .. autoclass:: SDLValidationRule .. autoclass:: ValidationContext .. autoclass:: ValidationRule Rules ----- .. module:: graphql.validation.rules .. currentmodule:: graphql.validation .. data:: specified_rules A tuple with all validation rules defined by the GraphQL specification **Spec Section: "Executable Definitions"** .. autoclass:: ExecutableDefinitionsRule **Spec Section: "Field Selections on Objects, Interfaces, and Unions Types"** .. autoclass:: FieldsOnCorrectTypeRule **Spec Section: "Fragments on Composite Types"** .. autoclass:: FragmentsOnCompositeTypesRule **Spec Section: "Argument Names"** .. autoclass:: KnownArgumentNamesRule **Spec Section: "Directives Are Defined"** .. autoclass:: KnownDirectivesRule **Spec Section: "Fragment spread target defined"** .. autoclass:: KnownFragmentNamesRule **Spec Section: "Fragment Spread Type Existence"** .. autoclass:: KnownTypeNamesRule **Spec Section: "Lone Anonymous Operation"** .. autoclass:: LoneAnonymousOperationRule **Spec Section: "Fragments must not form cycles"** .. autoclass:: NoFragmentCyclesRule **Spec Section: "All Variable Used Defined"** .. autoclass:: NoUndefinedVariablesRule **Spec Section: "Fragments must be used"** .. autoclass:: NoUnusedFragmentsRule **Spec Section: "All Variables Used"** .. autoclass:: NoUnusedVariablesRule **Spec Section: "Field Selection Merging"** .. autoclass:: OverlappingFieldsCanBeMergedRule **Spec Section: "Fragment spread is possible"** .. autoclass:: PossibleFragmentSpreadsRule **Spec Section: "Argument Optionality"** .. autoclass:: ProvidedRequiredArgumentsRule **Spec Section: "Leaf Field Selections"** .. autoclass:: ScalarLeafsRule **Spec Section: "Subscriptions with Single Root Field"** .. autoclass:: SingleFieldSubscriptionsRule **Spec Section: "Argument Uniqueness"** .. autoclass:: UniqueArgumentNamesRule **Spec Section: "Directives Are Unique Per Location"** .. autoclass:: UniqueDirectivesPerLocationRule **Spec Section: "Fragment Name Uniqueness"** .. autoclass:: UniqueFragmentNamesRule **Spec Section: "Input Object Field Uniqueness"** .. autoclass:: UniqueInputFieldNamesRule **Spec Section: "Operation Name Uniqueness"** .. autoclass:: UniqueOperationNamesRule **Spec Section: "Variable Uniqueness"** .. autoclass:: UniqueVariableNamesRule **Spec Section: "Value Type Correctness"** .. autoclass:: ValuesOfCorrectTypeRule **Spec Section: "Variables are Input Types"** .. autoclass:: VariablesAreInputTypesRule **Spec Section: "All Variable Usages Are Allowed"** .. autoclass:: VariablesInAllowedPositionRule **SDL-specific validation rules** .. autoclass:: LoneSchemaDefinitionRule .. autoclass:: UniqueOperationTypesRule .. autoclass:: UniqueTypeNamesRule .. autoclass:: UniqueEnumValueNamesRule .. autoclass:: UniqueFieldDefinitionNamesRule .. autoclass:: UniqueArgumentDefinitionNamesRule .. autoclass:: UniqueDirectiveNamesRule .. autoclass:: PossibleTypeExtensionsRule graphql-core-3.2.6/docs/requirements.txt000066400000000000000000000000441474546154300203350ustar00rootroot00000000000000sphinx>=7,<8 sphinx_rtd_theme>=2,<3 graphql-core-3.2.6/docs/usage/000077500000000000000000000000001474546154300161575ustar00rootroot00000000000000graphql-core-3.2.6/docs/usage/extension.rst000066400000000000000000000026261474546154300207330ustar00rootroot00000000000000Extending a Schema ------------------ .. currentmodule:: graphql.utilities With GraphQL-core 3 you can also extend a given schema using type extensions. For example, we might want to add a ``lastName`` property to our ``Human`` data type to retrieve only the last name of the person. This can be achieved with the :func:`extend_schema` function as follows:: from graphql import extend_schema, parse schema = extend_schema(schema, parse(""" extend type Human { lastName: String } """)) Note that this function expects the extensions as an AST, which we can get using the :func:`~graphql.language.parse` function. Also note that the :func:`extend_schema` function does not alter the original schema, but returns a new schema object. We also need to attach a resolver function to the new field:: def get_last_name(human, info): return human['name'].rsplit(None, 1)[-1] schema.get_type('Human').fields['lastName'].resolve = get_last_name Now we can query only the last name of a human:: from graphql import graphql_sync result = graphql_sync(schema, """ { human(id: "1000") { lastName homePlanet } } """) print(result) This query will give the following result:: ExecutionResult( data={'human': {'lastName': 'Skywalker', 'homePlanet': 'Tatooine'}}, errors=None) graphql-core-3.2.6/docs/usage/index.rst000066400000000000000000000004261474546154300200220ustar00rootroot00000000000000Usage ===== GraphQL-core provides two important capabilities: building a type schema, and serving queries against that type schema. .. toctree:: :maxdepth: 2 schema resolvers queries sdl methods introspection parser extension validator other graphql-core-3.2.6/docs/usage/introspection.rst000066400000000000000000000045161474546154300216170ustar00rootroot00000000000000Using an Introspection Query ---------------------------- .. currentmodule:: graphql.utilities A third way of building a schema is using an introspection query on an existing server. This is what GraphiQL uses to get information about the schema on the remote server. You can create an introspection query using GraphQL-core 3 with the :func:`get_introspection_query` function:: from graphql import get_introspection_query query = get_introspection_query(descriptions=True) This will also yield the descriptions of the introspected schema fields. You can also create a query that omits the descriptions with:: query = get_introspection_query(descriptions=False) In practice you would run this query against a remote server, but we can also run it against the schema we have just built above:: from graphql import graphql_sync introspection_query_result = graphql_sync(schema, query) The ``data`` attribute of the introspection query result now gives us a dictionary, which constitutes a third way of describing a GraphQL schema:: {'__schema': { 'queryType': {'name': 'Query'}, 'mutationType': None, 'subscriptionType': None, 'types': [ {'kind': 'OBJECT', 'name': 'Query', 'description': None, 'fields': [{ 'name': 'hero', 'description': None, 'args': [{'name': 'episode', 'description': ... }], ... }, ... ], ... }, ... ], ... } } This result contains all the information that is available in the SDL description of the schema, i.e. it does not contain the resolve functions and information on the server-side values of the enum types. You can convert the introspection result into ``GraphQLSchema`` with GraphQL-core 3 by using the :func:`build_client_schema` function:: from graphql import build_client_schema client_schema = build_client_schema(introspection_query_result.data) It is also possible to convert the result to SDL with GraphQL-core 3 by using the :func:`print_schema` function:: from graphql import print_schema sdl = print_schema(client_schema) print(sdl) This prints the SDL representation of the schema that we started with. As you see, it is easy to convert between the three forms of representing a GraphQL schema in GraphQL-core 3 using the :mod:`graphql.utilities` module. graphql-core-3.2.6/docs/usage/methods.rst000066400000000000000000000040421474546154300203540ustar00rootroot00000000000000Using resolver methods ---------------------- .. currentmodule:: graphql Above we have attached resolver functions to the schema only. However, it is also possible to define resolver methods on the resolved objects, starting with the ``root_value`` object that you can pass to the :func:`graphql` function when executing a query. In our case, we could create a ``Root`` class with three methods as root resolvers, like so:: class Root: """The root resolvers""" def hero(self, info, episode): return luke if episode == 5 else artoo def human(self, info, id): return human_data.get(id) def droid(self, info, id): return droid_data.get(id) Since we have defined synchronous methods only, we will use the :func:`graphql_sync` function to execute a query, passing a ``Root()`` object as the ``root_value``:: from graphql import graphql_sync result = graphql_sync(schema, """ { droid(id: "2001") { name primaryFunction } } """, Root()) print(result) Even if we haven't attached a resolver to the ``hero`` field as we did above, this would now still resolve and give the following output:: ExecutionResult( data={'droid': {'name': 'R2-D2', 'primaryFunction': 'Astromech'}}, errors=None) Of course you can also define asynchronous methods as resolvers, and execute queries asynchronously with :func:`graphql`. In a similar vein, you can also attach resolvers as methods to the resolved objects on deeper levels than the root of the query. In that case, instead of resolving to dictionaries with keys for all the fields, as we did above, you would resolve to objects with attributes for all the fields. For instance, you would define a class ``Human`` with a method ``friends()`` for resolving the friends of a human. You can also make use of inheritance in this case. The ``Human`` class and a ``Droid`` class could inherit from a ``Character`` class and use its methods as resolvers for common fields. graphql-core-3.2.6/docs/usage/other.rst000066400000000000000000000023521474546154300200340ustar00rootroot00000000000000Subscriptions ------------- .. currentmodule:: graphql.execution Sometimes you need to not only query data from a server, but you also want to push data from the server to the client. GraphQL-core 3 has you also covered here, because it implements the "Subscribe" algorithm described in the GraphQL spec. To execute a GraphQL subscription, you must use the :func:`subscribe` method from the :mod:`graphql.execution` package. Instead of a single :class:`~graphql.execution.ExecutionResult`, this function returns an asynchronous iterator yielding a stream of those, unless there was an immediate error. Of course you will then also need to maintain a persistent channel to the client (often realized via WebSockets) to push these results back. Other Usages ------------ .. currentmodule:: graphql.utilities GraphQL-core 3 provides many more low-level functions that can be used to work with GraphQL schemas and queries. We encourage you to explore the contents of the various :ref:`sub-packages`, particularly :mod:`graphql.utilities`, and to look into the source code and tests of `GraphQL-core 3`_ in order to find all the functionality that is provided and understand it in detail. .. _GraphQL-core 3: https://github.com/graphql-python/graphql-core graphql-core-3.2.6/docs/usage/parser.rst000066400000000000000000000052221474546154300202060ustar00rootroot00000000000000Parsing GraphQL Queries and Schema Notation ------------------------------------------- .. currentmodule:: graphql.language When executing GraphQL queries, the first step that happens under the hood is parsing the query. But GraphQL-core 3 also exposes the parser for direct usage via the :func:`parse` function. When you pass this function a GraphQL source code, it will be parsed and returned as a Document, i.e. an abstract syntax tree (AST) of :class:`Node` objects. The root node will be a :class:`DocumentNode`, with child nodes of different kinds corresponding to the GraphQL source. The nodes also carry information on the location in the source code that they correspond to. Here is an example:: from graphql import parse document = parse(""" type Query { me: User } type User { id: ID name: String } """) You can also leave out the information on the location in the source code when creating the AST document:: document = parse(..., no_location=True) This will give the same result as manually creating the AST document:: from graphql.language.ast import * document = DocumentNode(definitions=[ ObjectTypeDefinitionNode( name=NameNode(value='Query'), fields=[ FieldDefinitionNode( name=NameNode(value='me'), type=NamedTypeNode(name=NameNode(value='User')), arguments=[], directives=[]) ], directives=[], interfaces=[]), ObjectTypeDefinitionNode( name=NameNode(value='User'), fields=[ FieldDefinitionNode( name=NameNode(value='id'), type=NamedTypeNode( name=NameNode(value='ID')), arguments=[], directives=[]), FieldDefinitionNode( name=NameNode(value='name'), type=NamedTypeNode( name=NameNode(value='String')), arguments=[], directives=[]), ], directives=[], interfaces=[]), ]) When parsing with ``no_location=False`` (the default), the AST nodes will also have a ``loc`` attribute carrying the information on the source code location corresponding to the AST nodes. When there is a syntax error in the GraphQL source code, then the :func:`parse` function will raise a :exc:`~graphql.error.GraphQLSyntaxError`. The parser can not only be used to parse GraphQL queries, but also to parse the GraphQL schema definition language. This will result in another way of representing a GraphQL schema, as an AST document. graphql-core-3.2.6/docs/usage/queries.rst000066400000000000000000000075201474546154300203720ustar00rootroot00000000000000Executing Queries ----------------- .. currentmodule:: graphql.execution Now that we have defined the schema and breathed life into it with our resolver functions, we can execute arbitrary query against the schema. The :mod:`graphql` package provides the :func:`graphql.graphql` function to execute queries. This is the main feature of GraphQL-core. Note however that this function is actually a coroutine intended to be used in asynchronous code running in an event loop. Here is one way to use it:: import asyncio from graphql import graphql async def query_artoo(): result = await graphql(schema, """ { droid(id: "2001") { name primaryFunction } } """) print(result) asyncio.run(query_artoo()) In our query, we asked for the droid with the id 2001, which is R2-D2, and its primary function, Astromech. When everything has been implemented correctly as shown above, you should get the expected result:: ExecutionResult( data={'droid': {'name': 'R2-D2', 'primaryFunction': 'Astromech'}}, errors=None) The :class:`ExecutionResult` has a ``data`` attribute with the actual result, and an ``errors`` attribute with a list of errors if there were any. If all your resolvers work synchronously, as in our case, you can also use the :func:`graphql.graphql_sync` function to query the result in ordinary synchronous code:: from graphql import graphql_sync result = graphql_sync(schema, """ query FetchHuman($id: String!) { human(id: $id) { name homePlanet } } """, variable_values={'id': '1000'}) print(result) Here we asked for the human with the id 1000, Luke Skywalker, and his home planet, Tatooine. So the output of the code above is:: ExecutionResult( data={'human': {'name': 'Luke Skywalker', 'homePlanet': 'Tatooine'}}, errors=None) Let's see what happens when we make a mistake in the query, by querying a non-existing ``homeTown`` field:: result = graphql_sync(schema, """ { human(id: "1000") { name homePlace } } """) print(result) You will get the following result as output:: ExecutionResult(data=None, errors=[GraphQLError( "Cannot query field 'homePlace' on type 'Human'. Did you mean 'homePlanet'?", locations=[SourceLocation(line=5, column=9)])]) This is very helpful. Not only do we get the exact location of the mistake in the query, but also a suggestion for correcting the bad field name. GraphQL also allows to request the meta field ``__typename``. We can use this to verify that the hero of "The Empire Strikes Back" episode is Luke Skywalker and that he is in fact a human:: result = graphql_sync(schema, """ { hero(episode: EMPIRE) { __typename name } } """) print(result) This gives the following output:: ExecutionResult( data={'hero': {'__typename': 'Human', 'name': 'Luke Skywalker'}}, errors=None) Finally, let's see what happens when we try to access the secret backstory of our hero:: result = graphql_sync(schema, """ { hero(episode: EMPIRE) { name secretBackstory } } """) print(result) While we get the name of the hero, the secret backstory fields remains empty, since its resolver function raises an error. However, we get the error that has been raised by the resolver in the ``errors`` attribute of the result:: ExecutionResult( data={'hero': {'name': 'Luke Skywalker', 'secretBackstory': None}}, errors=[GraphQLError('secretBackstory is secret.', locations=[SourceLocation(line=5, column=9)], path=['hero', 'secretBackstory'])]) graphql-core-3.2.6/docs/usage/resolvers.rst000066400000000000000000000074731474546154300207500ustar00rootroot00000000000000Implementing the Resolver Functions ----------------------------------- .. currentmodule:: graphql.type Before we can execute queries against our schema, we also need to define the data (the humans and droids appearing in the Star Wars trilogy) and implement resolver functions that fetch the data (at the beginning of our schema module, because we are referencing them later):: luke = dict( id='1000', name='Luke Skywalker', homePlanet='Tatooine', friends=['1002', '1003', '2000', '2001'], appearsIn=[4, 5, 6]) vader = dict( id='1001', name='Darth Vader', homePlanet='Tatooine', friends=['1004'], appearsIn=[4, 5, 6]) han = dict( id='1002', name='Han Solo', homePlanet=None, friends=['1000', '1003', '2001'], appearsIn=[4, 5, 6]) leia = dict( id='1003', name='Leia Organa', homePlanet='Alderaan', friends=['1000', '1002', '2000', '2001'], appearsIn=[4, 5, 6]) tarkin = dict( id='1004', name='Wilhuff Tarkin', homePlanet=None, friends=['1001'], appearsIn=[4]) human_data = { '1000': luke, '1001': vader, '1002': han, '1003': leia, '1004': tarkin} threepio = dict( id='2000', name='C-3PO', primaryFunction='Protocol', friends=['1000', '1002', '1003', '2001'], appearsIn=[4, 5, 6]) artoo = dict( id='2001', name='R2-D2', primaryFunction='Astromech', friends=['1000', '1002', '1003'], appearsIn=[4, 5, 6]) droid_data = { '2000': threepio, '2001': artoo} def get_character_type(character, _info, _type): return 'Droid' if character['id'] in droid_data else 'Human' def get_character(id): """Helper function to get a character by ID.""" return human_data.get(id) or droid_data.get(id) def get_friends(character, _info): """Allows us to query for a character's friends.""" return map(get_character, character.friends) def get_hero(root, _info, episode): """Allows us to fetch the undisputed hero of the trilogy, R2-D2.""" if episode == 5: return luke # Luke is the hero of Episode V return artoo # Artoo is the hero otherwise def get_human(root, _info, id): """Allows us to query for the human with the given id.""" return human_data.get(id) def get_droid(root, _info, id): """Allows us to query for the droid with the given id.""" return droid_data.get(id) def get_secret_backstory(_character, _info): """Raise an error when attempting to get the secret backstory.""" raise RuntimeError('secretBackstory is secret.') Note that the resolver functions get the current object as first argument. For a field on the root Query type this is often not used, but a root object can also be defined when executing the query. As the second argument, they get an object containing execution information, as defined in the :class:`~GraphQLResolveInfo` class. This object also has a ``context`` attribute that can be used to provide every resolver with contextual information like the currently logged in user, or a database session. In our simple example we don't authenticate users and use static data instead of a database, so we don't make use of it here. In addition to these two arguments, resolver functions optionally get the defined for the field in the schema, using the same names (the names are not translated from GraphQL naming conventions to Python naming conventions). Also note that you don't need to provide resolvers for simple attribute access or for fetching items from Python dictionaries. Finally, note that our data uses the internal values of the ``Episode`` enum that we have defined above, not the descriptive enum names that are used externally. For example, ``NEWHOPE`` ("A New Hope") has internally the actual episode number 4 as value. graphql-core-3.2.6/docs/usage/schema.rst000066400000000000000000000166421474546154300201620ustar00rootroot00000000000000Building a Type Schema ---------------------- .. currentmodule:: graphql.type Using the classes in the :mod:`graphql.type` sub-package as building blocks, you can build a complete GraphQL type schema. Let's take the following schema as an example, which will allow us to query our favorite heroes from the Star Wars trilogy:: enum Episode { NEWHOPE, EMPIRE, JEDI } interface Character { id: String! name: String friends: [Character] appearsIn: [Episode] } type Human implements Character { id: String! name: String friends: [Character] appearsIn: [Episode] homePlanet: String } type Droid implements Character { id: String! name: String friends: [Character] appearsIn: [Episode] primaryFunction: String } type Query { hero(episode: Episode): Character human(id: String!): Human droid(id: String!): Droid } We have been using the so called GraphQL schema definition language (SDL) here to describe the schema. While it is also possible to build a schema directly from this notation using GraphQL-core 3, let's first create that schema manually by assembling the types defined here using Python classes, adding resolver functions written in Python for querying the data. First, we need to import all the building blocks from the :mod:`graphql.type` sub-package. Note that you don't need to import from the sub-packages, since nearly everything is also available directly in the top :mod:`graphql` package:: from graphql import ( GraphQLArgument, GraphQLEnumType, GraphQLEnumValue, GraphQLField, GraphQLInterfaceType, GraphQLList, GraphQLNonNull, GraphQLObjectType, GraphQLSchema, GraphQLString) Next, we need to build the enum type ``Episode``:: episode_enum = GraphQLEnumType('Episode', { 'NEWHOPE': GraphQLEnumValue(4, description='Released in 1977.'), 'EMPIRE': GraphQLEnumValue(5, description='Released in 1980.'), 'JEDI': GraphQLEnumValue(6, description='Released in 1983.') }, description='One of the films in the Star Wars Trilogy') If you don't need the descriptions for the enum values, you can also define the enum type like this using an underlying Python ``Enum`` type:: from enum import Enum class EpisodeEnum(Enum): NEWHOPE = 4 EMPIRE = 5 JEDI = 6 episode_enum = GraphQLEnumType( 'Episode', EpisodeEnum, description='One of the films in the Star Wars Trilogy') You can also use a Python dictionary instead of a Python ``Enum`` type to define the GraphQL enum type:: episode_enum = GraphQLEnumType( 'Episode', {'NEWHOPE': 4, 'EMPIRE': 5, 'JEDI': 6}, description='One of the films in the Star Wars Trilogy') Our schema also contains a ``Character`` interface. Here is how we build it:: character_interface = GraphQLInterfaceType('Character', lambda: { 'id': GraphQLField( GraphQLNonNull(GraphQLString), description='The id of the character.'), 'name': GraphQLField( GraphQLString, description='The name of the character.'), 'friends': GraphQLField( GraphQLList(character_interface), description='The friends of the character,' ' or an empty list if they have none.'), 'appearsIn': GraphQLField( GraphQLList(episode_enum), description='Which movies they appear in.'), 'secretBackstory': GraphQLField( GraphQLString, description='All secrets about their past.')}, resolve_type=get_character_type, description='A character in the Star Wars Trilogy') Note that we did not pass the dictionary of fields to the ``GraphQLInterfaceType`` directly, but using a lambda function (a so-called "thunk"). This is necessary because the fields are referring back to the character interface that we are just defining. Whenever you have such recursive definitions in GraphQL-core, you need to use thunks. Otherwise, you can pass everything directly. Characters in the Star Wars trilogy are either humans or droids. So we define a ``Human`` and a ``Droid`` type, which both implement the ``Character`` interface:: human_type = GraphQLObjectType('Human', lambda: { 'id': GraphQLField( GraphQLNonNull(GraphQLString), description='The id of the human.'), 'name': GraphQLField( GraphQLString, description='The name of the human.'), 'friends': GraphQLField( GraphQLList(character_interface), description='The friends of the human,' ' or an empty list if they have none.', resolve=get_friends), 'appearsIn': GraphQLField( GraphQLList(episode_enum), description='Which movies they appear in.'), 'homePlanet': GraphQLField( GraphQLString, description='The home planet of the human, or null if unknown.'), 'secretBackstory': GraphQLField( GraphQLString, resolve=get_secret_backstory, description='Where are they from' ' and how they came to be who they are.')}, interfaces=[character_interface], description='A humanoid creature in the Star Wars universe.') droid_type = GraphQLObjectType('Droid', lambda: { 'id': GraphQLField( GraphQLNonNull(GraphQLString), description='The id of the droid.'), 'name': GraphQLField( GraphQLString, description='The name of the droid.'), 'friends': GraphQLField( GraphQLList(character_interface), description='The friends of the droid,' ' or an empty list if they have none.', resolve=get_friends, ), 'appearsIn': GraphQLField( GraphQLList(episode_enum), description='Which movies they appear in.'), 'secretBackstory': GraphQLField( GraphQLString, resolve=get_secret_backstory, description='Construction date and the name of the designer.'), 'primaryFunction': GraphQLField( GraphQLString, description='The primary function of the droid.') }, interfaces=[character_interface], description='A mechanical creature in the Star Wars universe.') Now that we have defined all used result types, we can construct the ``Query`` type for our schema:: query_type = GraphQLObjectType('Query', lambda: { 'hero': GraphQLField(character_interface, args={ 'episode': GraphQLArgument(episode_enum, description=( 'If omitted, returns the hero of the whole saga.' ' If provided, returns the hero of that particular episode.'))}, resolve=get_hero), 'human': GraphQLField(human_type, args={ 'id': GraphQLArgument( GraphQLNonNull(GraphQLString), description='id of the human')}, resolve=get_human), 'droid': GraphQLField(droid_type, args={ 'id': GraphQLArgument( GraphQLNonNull(GraphQLString), description='id of the droid')}, resolve=get_droid)}) Using our query type we can define our schema:: schema = GraphQLSchema(query_type) Note that you can also pass a mutation type and a subscription type as additional arguments to the :class:`GraphQLSchema`. graphql-core-3.2.6/docs/usage/sdl.rst000066400000000000000000000051101474546154300174700ustar00rootroot00000000000000Using the Schema Definition Language ------------------------------------ .. currentmodule:: graphql.type Above we defined the GraphQL schema as Python code, using the :class:`GraphQLSchema` class and other classes representing the various GraphQL types. GraphQL-core 3 also provides a language-agnostic way of defining a GraphQL schema using the GraphQL schema definition language (SDL) which is also part of the GraphQL specification. To do this, we simply feed the SDL as a string to the :func:`~graphql.utilities.build_schema` function in :mod:`graphql.utilities`:: from graphql import build_schema schema = build_schema(""" enum Episode { NEWHOPE, EMPIRE, JEDI } interface Character { id: String! name: String friends: [Character] appearsIn: [Episode] } type Human implements Character { id: String! name: String friends: [Character] appearsIn: [Episode] homePlanet: String } type Droid implements Character { id: String! name: String friends: [Character] appearsIn: [Episode] primaryFunction: String } type Query { hero(episode: Episode): Character human(id: String!): Human droid(id: String!): Droid } """) The result is a :class:`GraphQLSchema` object just like the one we defined above, except for the resolver functions which cannot be defined in the SDL. We would need to manually attach these functions to the schema, like so:: schema.query_type.fields['hero'].resolve = get_hero schema.get_type('Character').resolve_type = get_character_type Another problem is that the SDL does not define the server side values of the ``Episode`` enum type which are returned by the resolver functions and which are different from the names used for the episode. So we would also need to manually define these values, like so:: for name, value in schema.get_type('Episode').values.items(): value.value = EpisodeEnum[name].value This would allow us to query the schema built from SDL just like the manually assembled schema:: from graphql import graphql_sync result = graphql_sync(schema, """ { hero(episode: EMPIRE) { name appearsIn } } """) print(result) And we would get the expected result:: ExecutionResult( data={'hero': {'name': 'Luke Skywalker', 'appearsIn': ['NEWHOPE', 'EMPIRE', 'JEDI']}}, errors=None) graphql-core-3.2.6/docs/usage/validator.rst000066400000000000000000000032671474546154300207060ustar00rootroot00000000000000Validating GraphQL Queries -------------------------- .. currentmodule:: graphql.validation When executing GraphQL queries, the second step that happens under the hood after parsing the source code is a validation against the given schema using the rules of the GraphQL specification. You can also run the validation step manually by calling the :func:`validate` function, passing the schema and the AST document:: from graphql import parse, validate errors = validate(schema, parse(""" { human(id: NEWHOPE) { name homePlace friends } } """)) As a result, you will get a complete list of all errors that the validators has found. In this case, we will get the following three validation errors:: [GraphQLError( 'String cannot represent a non string value: NEWHOPE', locations=[SourceLocation(line=3, column=17)]), GraphQLError( "Cannot query field 'homePlace' on type 'Human'." " Did you mean 'homePlanet'?", locations=[SourceLocation(line=5, column=9)]), GraphQLError( "Field 'friends' of type '[Character]' must have a selection of subfields." " Did you mean 'friends { ... }'?", locations=[SourceLocation(line=6, column=9)])] These rules are available in the :data:`specified_rules` list and implemented in the :mod:`graphql.validation.rules` subpackage. Instead of the default rules, you can also use a subset or create custom rules. The rules are based on the :class:`ValidationRule` class which is based on the :class:`~graphql.language.Visitor` class which provides a way of walking through an AST document using the visitor pattern. graphql-core-3.2.6/poetry.lock000066400000000000000000000012531474546154300163200ustar00rootroot00000000000000# This file is automatically @generated by Poetry 1.8.5 and should not be changed by hand. [[package]] name = "typing-extensions" version = "4.1.1" description = "Backported and Experimental Type Hints for Python 3.6+" optional = false python-versions = ">=3.6" files = [ {file = "typing_extensions-4.1.1-py3-none-any.whl", hash = "sha256:21c85e0fe4b9a155d0799430b0ad741cdce7e359660ccbd8b530613e8df88ce2"}, {file = "typing_extensions-4.1.1.tar.gz", hash = "sha256:1a9462dcc3347a79b1f1c0271fbe79e844580bb598bafa1ed208b94da3cdcd42"}, ] [metadata] lock-version = "2.0" python-versions = "^3.6" content-hash = "101c4a8c58c012e2a35491927fc7f20dd2ec86a7d7297998be0bf6c4b12204af" graphql-core-3.2.6/pyproject.toml000066400000000000000000000052131474546154300170400ustar00rootroot00000000000000[tool.poetry] name = "graphql-core" version = "3.2.6" description = """ GraphQL-core is a Python port of GraphQL.js,\ the JavaScript reference implementation for GraphQL.""" license = "MIT" authors = [ "Christoph Zwerschke " ] readme = "README.md" homepage = "https://github.com/graphql-python/graphql-core" repository = "https://github.com/graphql-python/graphql-core" documentation = "https://graphql-core-3.readthedocs.io/" keywords = ["graphql"] classifiers = [ "Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13" ] packages = [ { include = "graphql", from = "src" }, { include = "tests", format = "sdist" }, { include = "docs", format = "sdist" }, { include = '.bumpversion.cfg', format = "sdist" }, { include = '.coveragerc', format = "sdist" }, { include = '.editorconfig', format = "sdist" }, { include = '.flake8', format = "sdist" }, { include = '.mypy.ini', format = "sdist" }, { include = '.readthedocs.yaml', format = "sdist" }, { include = 'poetry.lock', format = "sdist" }, { include = 'tox.ini', format = "sdist" }, { include = 'setup.cfg', format = "sdist" }, { include = 'setup.py', format = "sdist" }, { include = 'CODEOWNERS', format = "sdist" }, { include = 'MANIFEST.in', format = "sdist" }, { include = 'SECURITY.md', format = "sdist" } ] [tool.poetry.dependencies] python = "^3.6" typing-extensions = [ { version = ">=4.1,<5", python = "<3.10" } ] [tool.black] target-version = ['py36', 'py37', 'py38', 'py39', 'py310', 'py311', 'py312', 'py313'] [tool.pyright] reportIncompatibleVariableOverride = false reportMissingTypeArgument = false reportUnknownArgumentType = false reportUnknownMemberType = false reportUnknownParameterType = false reportUnnecessaryIsInstance = false reportUnknownVariableType = false ignore = ["**/test_*"] # test functions [tool.pylint.basic] max-module-lines = 2000 [tool.pylint.messages_control] disable = [ "method-hidden", "missing-module-docstring", # test modules "redefined-outer-name", "unused-variable", # test functions ] [build-system] requires = ["poetry_core>=1,<3", "setuptools>=59,<76"] build-backend = "poetry.core.masonry.api" graphql-core-3.2.6/setup.cfg000066400000000000000000000012341474546154300157440ustar00rootroot00000000000000[bdist_wheel] python-tag = py3 [aliases] test = pytest [tool:pytest] # Only run benchmarks as tests. # To actually run the benchmarks, use --benchmark-enable on the command line. # To run the slow tests (fuzzing), add --run-slow on the command line. addopts = --benchmark-disable # Deactivate default name pattern for test classes (we use pytest_describe). python_classes = PyTest* # Handle all async fixtures and tests automatically by asyncio asyncio_mode = auto # Set a timeout in seconds for aborting tests that run too long. timeout = 100 # Ignore config options not (yet) available in older Python versions. filterwarnings = ignore::pytest.PytestConfigWarning graphql-core-3.2.6/setup.py000066400000000000000000000033611474546154300156400ustar00rootroot00000000000000from re import search from setuptools import find_packages, setup with open("src/graphql/version.py") as version_file: version = search('version = "(.*)"', version_file.read()).group(1) with open("README.md") as readme_file: readme = readme_file.read() setup( name="graphql-core", version=version, description="GraphQL implementation for Python, a port of GraphQL.js," " the JavaScript reference implementation for GraphQL.", long_description=readme, long_description_content_type="text/markdown", keywords="graphql", url="https://github.com/graphql-python/graphql-core", author="Christoph Zwerschke", author_email="cito@online.de", license="MIT license", classifiers=[ "Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "Topic :: Software Development :: Libraries", "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", ], install_requires=[ "typing-extensions>=4,<5; python_version < '3.10'", ], python_requires=">=3.6,<4", packages=find_packages("src"), package_dir={"": "src"}, # PEP-561: https://www.python.org/dev/peps/pep-0561/ package_data={"graphql": ["py.typed"]}, include_package_data=True, zip_safe=False, ) graphql-core-3.2.6/src/000077500000000000000000000000001474546154300147125ustar00rootroot00000000000000graphql-core-3.2.6/src/graphql/000077500000000000000000000000001474546154300163505ustar00rootroot00000000000000graphql-core-3.2.6/src/graphql/__init__.py000066400000000000000000000502101474546154300204570ustar00rootroot00000000000000"""GraphQL-core The primary :mod:`graphql` package includes everything you need to define a GraphQL schema and fulfill GraphQL requests. GraphQL-core provides a reference implementation for the GraphQL specification but is also a useful utility for operating on GraphQL files and building sophisticated tools. This top-level package exports a general purpose function for fulfilling all steps of the GraphQL specification in a single operation, but also includes utilities for every part of the GraphQL specification: - Parsing the GraphQL language. - Building a GraphQL type schema. - Validating a GraphQL request against a type schema. - Executing a GraphQL request against a type schema. This also includes utility functions for operating on GraphQL types and GraphQL documents to facilitate building tools. You may also import from each sub-package directly. For example, the following two import statements are equivalent:: from graphql import parse from graphql.language import parse The sub-packages of GraphQL-core 3 are: - :mod:`graphql.language`: Parse and operate on the GraphQL language. - :mod:`graphql.type`: Define GraphQL types and schema. - :mod:`graphql.validation`: The Validation phase of fulfilling a GraphQL result. - :mod:`graphql.execution`: The Execution phase of fulfilling a GraphQL request. - :mod:`graphql.error`: Creating and formatting GraphQL errors. - :mod:`graphql.utilities`: Common useful computations upon the GraphQL language and type objects. """ # The GraphQL-core 3 and GraphQL.js version info. from .version import version, version_info, version_js, version_info_js # Utilities for compatibility with the Python language. from .pyutils import Undefined, UndefinedType # Create, format, and print GraphQL errors. from .error import ( GraphQLError, GraphQLErrorExtensions, GraphQLFormattedError, GraphQLSyntaxError, located_error, ) # Parse and operate on GraphQL language source files. from .language import ( Source, get_location, # Print source location print_location, print_source_location, # Lex Lexer, TokenKind, # Parse parse, parse_value, parse_const_value, parse_type, # Print print_ast, # Visit visit, ParallelVisitor, Visitor, VisitorAction, VisitorKeyMap, BREAK, SKIP, REMOVE, IDLE, DirectiveLocation, # Predicates is_definition_node, is_executable_definition_node, is_selection_node, is_value_node, is_const_value_node, is_type_node, is_type_system_definition_node, is_type_definition_node, is_type_system_extension_node, is_type_extension_node, # Types SourceLocation, Location, Token, # AST nodes Node, # Each kind of AST node NameNode, DocumentNode, DefinitionNode, ExecutableDefinitionNode, OperationDefinitionNode, OperationType, VariableDefinitionNode, VariableNode, SelectionSetNode, SelectionNode, FieldNode, ArgumentNode, ConstArgumentNode, FragmentSpreadNode, InlineFragmentNode, FragmentDefinitionNode, ValueNode, ConstValueNode, IntValueNode, FloatValueNode, StringValueNode, BooleanValueNode, NullValueNode, EnumValueNode, ListValueNode, ConstListValueNode, ObjectValueNode, ConstObjectValueNode, ObjectFieldNode, ConstObjectFieldNode, DirectiveNode, ConstDirectiveNode, TypeNode, NamedTypeNode, ListTypeNode, NonNullTypeNode, TypeSystemDefinitionNode, SchemaDefinitionNode, OperationTypeDefinitionNode, TypeDefinitionNode, ScalarTypeDefinitionNode, ObjectTypeDefinitionNode, FieldDefinitionNode, InputValueDefinitionNode, InterfaceTypeDefinitionNode, UnionTypeDefinitionNode, EnumTypeDefinitionNode, EnumValueDefinitionNode, InputObjectTypeDefinitionNode, DirectiveDefinitionNode, TypeSystemExtensionNode, SchemaExtensionNode, TypeExtensionNode, ScalarTypeExtensionNode, ObjectTypeExtensionNode, InterfaceTypeExtensionNode, UnionTypeExtensionNode, EnumTypeExtensionNode, InputObjectTypeExtensionNode, ) # Utilities for operating on GraphQL type schema and parsed sources. from .utilities import ( # Produce the GraphQL query recommended for a full schema introspection. # Accepts optional IntrospectionOptions. get_introspection_query, IntrospectionQuery, # Get the target Operation from a Document. get_operation_ast, # Get the Type for the target Operation AST. get_operation_root_type, # Convert a GraphQLSchema to an IntrospectionQuery. introspection_from_schema, # Build a GraphQLSchema from an introspection result. build_client_schema, # Build a GraphQLSchema from a parsed GraphQL Schema language AST. build_ast_schema, # Build a GraphQLSchema from a GraphQL schema language document. build_schema, # Extend an existing GraphQLSchema from a parsed GraphQL Schema language AST. extend_schema, # Sort a GraphQLSchema. lexicographic_sort_schema, # Print a GraphQLSchema to GraphQL Schema language. print_schema, # Print a GraphQLType to GraphQL Schema language. print_type, # Prints the built-in introspection schema in the Schema Language format. print_introspection_schema, # Create a GraphQLType from a GraphQL language AST. type_from_ast, # Convert a language AST to a dictionary. ast_to_dict, # Create a Python value from a GraphQL language AST with a Type. value_from_ast, # Create a Python value from a GraphQL language AST without a Type. value_from_ast_untyped, # Create a GraphQL language AST from a Python value. ast_from_value, # A helper to use within recursive-descent visitors which need to be aware of the # GraphQL type system. TypeInfo, TypeInfoVisitor, # Coerce a Python value to a GraphQL type, or produce errors. coerce_input_value, # Concatenates multiple ASTs together. concat_ast, # Separate an AST into an AST per Operation. separate_operations, # Strip characters that are not significant to the validity or execution # of a GraphQL document. strip_ignored_characters, # Comparators for types is_equal_type, is_type_sub_type_of, do_types_overlap, # Assert a string is a valid GraphQL name. assert_valid_name, # Determine if a string is a valid GraphQL name. is_valid_name_error, # Compare two GraphQLSchemas and detect breaking changes. BreakingChange, BreakingChangeType, DangerousChange, DangerousChangeType, find_breaking_changes, find_dangerous_changes, ) # Create and operate on GraphQL type definitions and schema. from .type import ( # Definitions GraphQLSchema, GraphQLDirective, GraphQLScalarType, GraphQLObjectType, GraphQLInterfaceType, GraphQLUnionType, GraphQLEnumType, GraphQLInputObjectType, GraphQLList, GraphQLNonNull, # Standard GraphQL Scalars specified_scalar_types, GraphQLInt, GraphQLFloat, GraphQLString, GraphQLBoolean, GraphQLID, # Int boundaries constants GRAPHQL_MAX_INT, GRAPHQL_MIN_INT, # Built-in Directives defined by the Spec specified_directives, GraphQLIncludeDirective, GraphQLSkipDirective, GraphQLDeprecatedDirective, GraphQLSpecifiedByDirective, # "Enum" of Type Kinds TypeKind, # Constant Deprecation Reason DEFAULT_DEPRECATION_REASON, # GraphQL Types for introspection. introspection_types, # Meta-field definitions. SchemaMetaFieldDef, TypeMetaFieldDef, TypeNameMetaFieldDef, # Predicates is_schema, is_directive, is_type, is_scalar_type, is_object_type, is_interface_type, is_union_type, is_enum_type, is_input_object_type, is_list_type, is_non_null_type, is_input_type, is_output_type, is_leaf_type, is_composite_type, is_abstract_type, is_wrapping_type, is_nullable_type, is_named_type, is_required_argument, is_required_input_field, is_specified_scalar_type, is_introspection_type, is_specified_directive, # Assertions assert_schema, assert_directive, assert_type, assert_scalar_type, assert_object_type, assert_interface_type, assert_union_type, assert_enum_type, assert_input_object_type, assert_list_type, assert_non_null_type, assert_input_type, assert_output_type, assert_leaf_type, assert_composite_type, assert_abstract_type, assert_wrapping_type, assert_nullable_type, assert_named_type, # Un-modifiers get_nullable_type, get_named_type, # Thunk handling resolve_thunk, # Validate GraphQL schema. validate_schema, assert_valid_schema, # Uphold the spec rules about naming assert_name, assert_enum_value_name, # Types GraphQLType, GraphQLInputType, GraphQLOutputType, GraphQLLeafType, GraphQLCompositeType, GraphQLAbstractType, GraphQLWrappingType, GraphQLNullableType, GraphQLNamedType, GraphQLNamedInputType, GraphQLNamedOutputType, Thunk, ThunkCollection, ThunkMapping, GraphQLArgument, GraphQLArgumentMap, GraphQLEnumValue, GraphQLEnumValueMap, GraphQLField, GraphQLFieldMap, GraphQLFieldResolver, GraphQLInputField, GraphQLInputFieldMap, GraphQLScalarSerializer, GraphQLScalarValueParser, GraphQLScalarLiteralParser, GraphQLIsTypeOfFn, GraphQLResolveInfo, ResponsePath, GraphQLTypeResolver, # Keyword args GraphQLArgumentKwargs, GraphQLDirectiveKwargs, GraphQLEnumTypeKwargs, GraphQLEnumValueKwargs, GraphQLFieldKwargs, GraphQLInputFieldKwargs, GraphQLInputObjectTypeKwargs, GraphQLInterfaceTypeKwargs, GraphQLNamedTypeKwargs, GraphQLObjectTypeKwargs, GraphQLScalarTypeKwargs, GraphQLSchemaKwargs, GraphQLUnionTypeKwargs, ) # Validate GraphQL queries. from .validation import ( validate, ValidationContext, ValidationRule, ASTValidationRule, SDLValidationRule, # All validation rules in the GraphQL Specification. specified_rules, # Individual validation rules. ExecutableDefinitionsRule, FieldsOnCorrectTypeRule, FragmentsOnCompositeTypesRule, KnownArgumentNamesRule, KnownDirectivesRule, KnownFragmentNamesRule, KnownTypeNamesRule, LoneAnonymousOperationRule, NoFragmentCyclesRule, NoUndefinedVariablesRule, NoUnusedFragmentsRule, NoUnusedVariablesRule, OverlappingFieldsCanBeMergedRule, PossibleFragmentSpreadsRule, ProvidedRequiredArgumentsRule, ScalarLeafsRule, SingleFieldSubscriptionsRule, UniqueArgumentNamesRule, UniqueDirectivesPerLocationRule, UniqueFragmentNamesRule, UniqueInputFieldNamesRule, UniqueOperationNamesRule, UniqueVariableNamesRule, ValuesOfCorrectTypeRule, VariablesAreInputTypesRule, VariablesInAllowedPositionRule, # SDL-specific validation rules LoneSchemaDefinitionRule, UniqueOperationTypesRule, UniqueTypeNamesRule, UniqueEnumValueNamesRule, UniqueFieldDefinitionNamesRule, UniqueArgumentDefinitionNamesRule, UniqueDirectiveNamesRule, PossibleTypeExtensionsRule, # Custom validation rules NoDeprecatedCustomRule, NoSchemaIntrospectionCustomRule, ) # Execute GraphQL documents. from .execution import ( execute, execute_sync, default_field_resolver, default_type_resolver, get_argument_values, get_directive_values, get_variable_values, # Types ExecutionContext, ExecutionResult, FormattedExecutionResult, # Subscription subscribe, create_source_event_stream, MapAsyncIterator, # Middleware Middleware, MiddlewareManager, ) # The primary entry point into fulfilling a GraphQL request. from .graphql import graphql, graphql_sync INVALID = Undefined # deprecated alias # The GraphQL-core version info. __version__ = version __version_info__ = version_info # The GraphQL.js version info. __version_js__ = version_js __version_info_js__ = version_info_js __all__ = [ "version", "version_info", "version_js", "version_info_js", "graphql", "graphql_sync", "GraphQLSchema", "GraphQLDirective", "GraphQLScalarType", "GraphQLObjectType", "GraphQLInterfaceType", "GraphQLUnionType", "GraphQLEnumType", "GraphQLInputObjectType", "GraphQLList", "GraphQLNonNull", "specified_scalar_types", "GraphQLInt", "GraphQLFloat", "GraphQLString", "GraphQLBoolean", "GraphQLID", "GRAPHQL_MAX_INT", "GRAPHQL_MIN_INT", "specified_directives", "GraphQLIncludeDirective", "GraphQLSkipDirective", "GraphQLDeprecatedDirective", "GraphQLSpecifiedByDirective", "TypeKind", "DEFAULT_DEPRECATION_REASON", "introspection_types", "SchemaMetaFieldDef", "TypeMetaFieldDef", "TypeNameMetaFieldDef", "is_schema", "is_directive", "is_type", "is_scalar_type", "is_object_type", "is_interface_type", "is_union_type", "is_enum_type", "is_input_object_type", "is_list_type", "is_non_null_type", "is_input_type", "is_output_type", "is_leaf_type", "is_composite_type", "is_abstract_type", "is_wrapping_type", "is_nullable_type", "is_named_type", "is_required_argument", "is_required_input_field", "is_specified_scalar_type", "is_introspection_type", "is_specified_directive", "assert_schema", "assert_directive", "assert_type", "assert_scalar_type", "assert_object_type", "assert_interface_type", "assert_union_type", "assert_enum_type", "assert_input_object_type", "assert_list_type", "assert_non_null_type", "assert_input_type", "assert_output_type", "assert_leaf_type", "assert_composite_type", "assert_abstract_type", "assert_wrapping_type", "assert_nullable_type", "assert_named_type", "get_nullable_type", "get_named_type", "resolve_thunk", "validate_schema", "assert_valid_schema", "assert_name", "assert_enum_value_name", "GraphQLType", "GraphQLInputType", "GraphQLOutputType", "GraphQLLeafType", "GraphQLCompositeType", "GraphQLAbstractType", "GraphQLWrappingType", "GraphQLNullableType", "GraphQLNamedType", "GraphQLNamedInputType", "GraphQLNamedOutputType", "Thunk", "ThunkCollection", "ThunkMapping", "GraphQLArgument", "GraphQLArgumentMap", "GraphQLEnumValue", "GraphQLEnumValueMap", "GraphQLField", "GraphQLFieldMap", "GraphQLFieldResolver", "GraphQLInputField", "GraphQLInputFieldMap", "GraphQLScalarSerializer", "GraphQLScalarValueParser", "GraphQLScalarLiteralParser", "GraphQLIsTypeOfFn", "GraphQLResolveInfo", "ResponsePath", "GraphQLTypeResolver", "GraphQLArgumentKwargs", "GraphQLDirectiveKwargs", "GraphQLEnumTypeKwargs", "GraphQLEnumValueKwargs", "GraphQLFieldKwargs", "GraphQLInputFieldKwargs", "GraphQLInputObjectTypeKwargs", "GraphQLInterfaceTypeKwargs", "GraphQLNamedTypeKwargs", "GraphQLObjectTypeKwargs", "GraphQLScalarTypeKwargs", "GraphQLSchemaKwargs", "GraphQLUnionTypeKwargs", "Source", "get_location", "print_location", "print_source_location", "Lexer", "TokenKind", "parse", "parse_value", "parse_const_value", "parse_type", "print_ast", "visit", "ParallelVisitor", "TypeInfoVisitor", "Visitor", "VisitorAction", "VisitorKeyMap", "BREAK", "SKIP", "REMOVE", "IDLE", "DirectiveLocation", "is_definition_node", "is_executable_definition_node", "is_selection_node", "is_value_node", "is_const_value_node", "is_type_node", "is_type_system_definition_node", "is_type_definition_node", "is_type_system_extension_node", "is_type_extension_node", "SourceLocation", "Location", "Token", "Node", "NameNode", "DocumentNode", "DefinitionNode", "ExecutableDefinitionNode", "OperationDefinitionNode", "OperationType", "VariableDefinitionNode", "VariableNode", "SelectionSetNode", "SelectionNode", "FieldNode", "ArgumentNode", "ConstArgumentNode", "FragmentSpreadNode", "InlineFragmentNode", "FragmentDefinitionNode", "ValueNode", "ConstValueNode", "IntValueNode", "FloatValueNode", "StringValueNode", "BooleanValueNode", "NullValueNode", "EnumValueNode", "ListValueNode", "ConstListValueNode", "ObjectValueNode", "ConstObjectValueNode", "ObjectFieldNode", "ConstObjectFieldNode", "DirectiveNode", "ConstDirectiveNode", "TypeNode", "NamedTypeNode", "ListTypeNode", "NonNullTypeNode", "TypeSystemDefinitionNode", "SchemaDefinitionNode", "OperationTypeDefinitionNode", "TypeDefinitionNode", "ScalarTypeDefinitionNode", "ObjectTypeDefinitionNode", "FieldDefinitionNode", "InputValueDefinitionNode", "InterfaceTypeDefinitionNode", "UnionTypeDefinitionNode", "EnumTypeDefinitionNode", "EnumValueDefinitionNode", "InputObjectTypeDefinitionNode", "DirectiveDefinitionNode", "TypeSystemExtensionNode", "SchemaExtensionNode", "TypeExtensionNode", "ScalarTypeExtensionNode", "ObjectTypeExtensionNode", "InterfaceTypeExtensionNode", "UnionTypeExtensionNode", "EnumTypeExtensionNode", "InputObjectTypeExtensionNode", "execute", "execute_sync", "default_field_resolver", "default_type_resolver", "get_argument_values", "get_directive_values", "get_variable_values", "ExecutionContext", "ExecutionResult", "FormattedExecutionResult", "Middleware", "MiddlewareManager", "subscribe", "create_source_event_stream", "MapAsyncIterator", "validate", "ValidationContext", "ValidationRule", "ASTValidationRule", "SDLValidationRule", "specified_rules", "ExecutableDefinitionsRule", "FieldsOnCorrectTypeRule", "FragmentsOnCompositeTypesRule", "KnownArgumentNamesRule", "KnownDirectivesRule", "KnownFragmentNamesRule", "KnownTypeNamesRule", "LoneAnonymousOperationRule", "NoFragmentCyclesRule", "NoUndefinedVariablesRule", "NoUnusedFragmentsRule", "NoUnusedVariablesRule", "OverlappingFieldsCanBeMergedRule", "PossibleFragmentSpreadsRule", "ProvidedRequiredArgumentsRule", "ScalarLeafsRule", "SingleFieldSubscriptionsRule", "UniqueArgumentNamesRule", "UniqueDirectivesPerLocationRule", "UniqueFragmentNamesRule", "UniqueInputFieldNamesRule", "UniqueOperationNamesRule", "UniqueVariableNamesRule", "ValuesOfCorrectTypeRule", "VariablesAreInputTypesRule", "VariablesInAllowedPositionRule", "LoneSchemaDefinitionRule", "UniqueOperationTypesRule", "UniqueTypeNamesRule", "UniqueEnumValueNamesRule", "UniqueFieldDefinitionNamesRule", "UniqueArgumentDefinitionNamesRule", "UniqueDirectiveNamesRule", "PossibleTypeExtensionsRule", "NoDeprecatedCustomRule", "NoSchemaIntrospectionCustomRule", "GraphQLError", "GraphQLErrorExtensions", "GraphQLFormattedError", "GraphQLSyntaxError", "located_error", "get_introspection_query", "IntrospectionQuery", "get_operation_ast", "get_operation_root_type", "introspection_from_schema", "build_client_schema", "build_ast_schema", "build_schema", "extend_schema", "lexicographic_sort_schema", "print_schema", "print_type", "print_introspection_schema", "type_from_ast", "value_from_ast", "value_from_ast_untyped", "ast_from_value", "ast_to_dict", "TypeInfo", "coerce_input_value", "concat_ast", "separate_operations", "strip_ignored_characters", "is_equal_type", "is_type_sub_type_of", "do_types_overlap", "assert_valid_name", "is_valid_name_error", "find_breaking_changes", "find_dangerous_changes", "BreakingChange", "BreakingChangeType", "DangerousChange", "DangerousChangeType", "Undefined", "UndefinedType", ] graphql-core-3.2.6/src/graphql/error/000077500000000000000000000000001474546154300175015ustar00rootroot00000000000000graphql-core-3.2.6/src/graphql/error/__init__.py000066400000000000000000000006601474546154300216140ustar00rootroot00000000000000"""GraphQL Errors The :mod:`graphql.error` package is responsible for creating and formatting GraphQL errors. """ from .graphql_error import GraphQLError, GraphQLErrorExtensions, GraphQLFormattedError from .syntax_error import GraphQLSyntaxError from .located_error import located_error __all__ = [ "GraphQLError", "GraphQLErrorExtensions", "GraphQLFormattedError", "GraphQLSyntaxError", "located_error", ] graphql-core-3.2.6/src/graphql/error/graphql_error.py000066400000000000000000000224631474546154300227310ustar00rootroot00000000000000from sys import exc_info from typing import Any, Collection, Dict, List, Optional, Union, TYPE_CHECKING try: from typing import TypedDict except ImportError: # Python < 3.8 from typing_extensions import TypedDict if TYPE_CHECKING: from ..language.ast import Node # noqa: F401 from ..language.location import ( SourceLocation, FormattedSourceLocation, ) # noqa: F401 from ..language.source import Source # noqa: F401 __all__ = ["GraphQLError", "GraphQLErrorExtensions", "GraphQLFormattedError"] # Custom extensions GraphQLErrorExtensions = Dict[str, Any] # Use a unique identifier name for your extension, for example the name of # your library or project. Do not use a shortened identifier as this increases # the risk of conflicts. We recommend you add at most one extension key, # a dictionary which can contain all the values you need. class GraphQLFormattedError(TypedDict, total=False): """Formatted GraphQL error""" # A short, human-readable summary of the problem that **SHOULD NOT** change # from occurrence to occurrence of the problem, except for purposes of localization. message: str # If an error can be associated to a particular point in the requested # GraphQL document, it should contain a list of locations. locations: List["FormattedSourceLocation"] # If an error can be associated to a particular field in the GraphQL result, # it _must_ contain an entry with the key `path` that details the path of # the response field which experienced the error. This allows clients to # identify whether a null result is intentional or caused by a runtime error. path: List[Union[str, int]] # Reserved for implementors to extend the protocol however they see fit, # and hence there are no additional restrictions on its contents. extensions: GraphQLErrorExtensions class GraphQLError(Exception): """GraphQL Error A GraphQLError describes an Error found during the parse, validate, or execute phases of performing a GraphQL operation. In addition to a message, it also includes information about the locations in a GraphQL document and/or execution result that correspond to the Error. """ message: str """A message describing the Error for debugging purposes""" locations: Optional[List["SourceLocation"]] """Source locations A list of (line, column) locations within the source GraphQL document which correspond to this error. Errors during validation often contain multiple locations, for example to point out two things with the same name. Errors during execution include a single location, the field which produced the error. """ path: Optional[List[Union[str, int]]] """ A list of field names and array indexes describing the JSON-path into the execution response which corresponds to this error. Only included for errors during execution. """ nodes: Optional[List["Node"]] """A list of GraphQL AST Nodes corresponding to this error""" source: Optional["Source"] """The source GraphQL document for the first location of this error Note that if this Error represents more than one node, the source may not represent nodes after the first node. """ positions: Optional[Collection[int]] """Error positions A list of character offsets within the source GraphQL document which correspond to this error. """ original_error: Optional[Exception] """The original error thrown from a field resolver during execution""" extensions: Optional[GraphQLErrorExtensions] """Extension fields to add to the formatted error""" __slots__ = ( "message", "nodes", "source", "positions", "locations", "path", "original_error", "extensions", ) __hash__ = Exception.__hash__ def __init__( self, message: str, nodes: Union[Collection["Node"], "Node", None] = None, source: Optional["Source"] = None, positions: Optional[Collection[int]] = None, path: Optional[Collection[Union[str, int]]] = None, original_error: Optional[Exception] = None, extensions: Optional[GraphQLErrorExtensions] = None, ) -> None: super().__init__(message) self.message = message if path and not isinstance(path, list): path = list(path) self.path = path or None # type: ignore self.original_error = original_error # Compute list of blame nodes. if nodes and not isinstance(nodes, list): nodes = [nodes] # type: ignore self.nodes = nodes or None # type: ignore node_locations = ( [node.loc for node in nodes if node.loc] if nodes else [] # type: ignore ) # Compute locations in the source for the given nodes/positions. self.source = source if not source and node_locations: loc = node_locations[0] if loc.source: # pragma: no cover else self.source = loc.source if not positions and node_locations: positions = [loc.start for loc in node_locations] self.positions = positions or None if positions and source: locations: Optional[List["SourceLocation"]] = [ source.get_location(pos) for pos in positions ] else: locations = [loc.source.get_location(loc.start) for loc in node_locations] self.locations = locations or None if original_error: self.__traceback__ = original_error.__traceback__ if original_error.__cause__: self.__cause__ = original_error.__cause__ elif original_error.__context__: self.__context__ = original_error.__context__ if extensions is None: original_extensions = getattr(original_error, "extensions", None) if isinstance(original_extensions, dict): extensions = original_extensions self.extensions = extensions or {} if not self.__traceback__: self.__traceback__ = exc_info()[2] def __str__(self) -> str: # Lazy import to avoid a cyclic dependency between error and language from ..language.print_location import print_location, print_source_location output = [self.message] if self.nodes: for node in self.nodes: if node.loc: output.append(print_location(node.loc)) elif self.source and self.locations: source = self.source for location in self.locations: output.append(print_source_location(source, location)) return "\n\n".join(output) def __repr__(self) -> str: args = [repr(self.message)] if self.locations: args.append(f"locations={self.locations!r}") if self.path: args.append(f"path={self.path!r}") if self.extensions: args.append(f"extensions={self.extensions!r}") return f"{self.__class__.__name__}({', '.join(args)})" def __eq__(self, other: Any) -> bool: return ( isinstance(other, GraphQLError) and self.__class__ == other.__class__ and all( getattr(self, slot) == getattr(other, slot) for slot in self.__slots__ if slot != "original_error" ) ) or ( isinstance(other, dict) and "message" in other and all( slot in self.__slots__ and getattr(self, slot) == other.get(slot) for slot in other if slot != "original_error" ) ) def __ne__(self, other: Any) -> bool: return not self == other @property def formatted(self) -> GraphQLFormattedError: """Get error formatted according to the specification. Given a GraphQLError, format it according to the rules described by the "Response Format, Errors" section of the GraphQL Specification. """ formatted: GraphQLFormattedError = { "message": self.message or "An unknown error occurred.", } if self.locations is not None: formatted["locations"] = [location.formatted for location in self.locations] if self.path is not None: formatted["path"] = self.path if self.extensions: formatted["extensions"] = self.extensions return formatted def print_error(error: GraphQLError) -> str: """Print a GraphQLError to a string. Represents useful location information about the error's position in the source. .. deprecated:: 3.2 Please use ``str(error)`` instead. Will be removed in v3.3. """ if not isinstance(error, GraphQLError): raise TypeError("Expected a GraphQLError.") return str(error) def format_error(error: GraphQLError) -> GraphQLFormattedError: """Format a GraphQL error. Given a GraphQLError, format it according to the rules described by the "Response Format, Errors" section of the GraphQL Specification. .. deprecated:: 3.2 Please use ``error.formatted`` instead. Will be removed in v3.3. """ if not isinstance(error, GraphQLError): raise TypeError("Expected a GraphQLError.") return error.formatted graphql-core-3.2.6/src/graphql/error/located_error.py000066400000000000000000000035041474546154300227010ustar00rootroot00000000000000from typing import TYPE_CHECKING, Collection, Optional, Union from ..pyutils import inspect from .graphql_error import GraphQLError if TYPE_CHECKING: from ..language.ast import Node # noqa: F401 __all__ = ["located_error"] def located_error( original_error: Exception, nodes: Optional[Union["None", Collection["Node"]]] = None, path: Optional[Collection[Union[str, int]]] = None, ) -> GraphQLError: """Located GraphQL Error Given an arbitrary Exception, presumably thrown while attempting to execute a GraphQL operation, produce a new GraphQLError aware of the location in the document responsible for the original Exception. """ # Sometimes a non-error is thrown, wrap it as a TypeError to ensure consistency. if not isinstance(original_error, Exception): original_error = TypeError(f"Unexpected error value: {inspect(original_error)}") # Note: this uses a brand-check to support GraphQL errors originating from # other contexts. if isinstance(original_error, GraphQLError) and original_error.path is not None: return original_error try: # noinspection PyUnresolvedReferences message = str(original_error.message) # type: ignore except AttributeError: message = str(original_error) try: # noinspection PyUnresolvedReferences source = original_error.source # type: ignore except AttributeError: source = None try: # noinspection PyUnresolvedReferences positions = original_error.positions # type: ignore except AttributeError: positions = None try: # noinspection PyUnresolvedReferences nodes = original_error.nodes or nodes # type: ignore except AttributeError: pass return GraphQLError(message, nodes, source, positions, path, original_error) graphql-core-3.2.6/src/graphql/error/syntax_error.py000066400000000000000000000010051474546154300226060ustar00rootroot00000000000000from typing import TYPE_CHECKING from .graphql_error import GraphQLError if TYPE_CHECKING: from ..language.source import Source # noqa: F401 __all__ = ["GraphQLSyntaxError"] class GraphQLSyntaxError(GraphQLError): """A GraphQLError representing a syntax error.""" def __init__(self, source: "Source", position: int, description: str) -> None: super().__init__( f"Syntax Error: {description}", source=source, positions=[position] ) self.description = description graphql-core-3.2.6/src/graphql/execution/000077500000000000000000000000001474546154300203535ustar00rootroot00000000000000graphql-core-3.2.6/src/graphql/execution/__init__.py000066400000000000000000000016771474546154300224770ustar00rootroot00000000000000"""GraphQL Execution The :mod:`graphql.execution` package is responsible for the execution phase of fulfilling a GraphQL request. """ from .execute import ( execute, execute_sync, default_field_resolver, default_type_resolver, ExecutionContext, ExecutionResult, FormattedExecutionResult, Middleware, ) from .map_async_iterator import MapAsyncIterator from .subscribe import subscribe, create_source_event_stream from .middleware import MiddlewareManager from .values import get_argument_values, get_directive_values, get_variable_values __all__ = [ "create_source_event_stream", "execute", "execute_sync", "default_field_resolver", "default_type_resolver", "subscribe", "ExecutionContext", "ExecutionResult", "FormattedExecutionResult", "MapAsyncIterator", "Middleware", "MiddlewareManager", "get_argument_values", "get_directive_values", "get_variable_values", ] graphql-core-3.2.6/src/graphql/execution/collect_fields.py000066400000000000000000000131231474546154300237000ustar00rootroot00000000000000from typing import Any, Dict, List, Set, Union, cast from ..language import ( FieldNode, FragmentDefinitionNode, FragmentSpreadNode, InlineFragmentNode, SelectionSetNode, ) from ..type import ( GraphQLAbstractType, GraphQLIncludeDirective, GraphQLObjectType, GraphQLSchema, GraphQLSkipDirective, is_abstract_type, ) from ..utilities.type_from_ast import type_from_ast from .values import get_directive_values __all__ = ["collect_fields", "collect_sub_fields"] def collect_fields( schema: GraphQLSchema, fragments: Dict[str, FragmentDefinitionNode], variable_values: Dict[str, Any], runtime_type: GraphQLObjectType, selection_set: SelectionSetNode, ) -> Dict[str, List[FieldNode]]: """Collect fields. Given a selection_set, collects all the fields and returns them. collect_fields requires the "runtime type" of an object. For a field that returns an Interface or Union type, the "runtime type" will be the actual object type returned by that field. For internal use only. """ fields: Dict[str, List[FieldNode]] = {} collect_fields_impl( schema, fragments, variable_values, runtime_type, selection_set, fields, set() ) return fields def collect_sub_fields( schema: GraphQLSchema, fragments: Dict[str, FragmentDefinitionNode], variable_values: Dict[str, Any], return_type: GraphQLObjectType, field_nodes: List[FieldNode], ) -> Dict[str, List[FieldNode]]: """Collect sub fields. Given a list of field nodes, collects all the subfields of the passed in fields, and returns them at the end. collect_sub_fields requires the "return type" of an object. For a field that returns an Interface or Union type, the "return type" will be the actual object type returned by that field. For internal use only. """ sub_field_nodes: Dict[str, List[FieldNode]] = {} visited_fragment_names: Set[str] = set() for node in field_nodes: if node.selection_set: collect_fields_impl( schema, fragments, variable_values, return_type, node.selection_set, sub_field_nodes, visited_fragment_names, ) return sub_field_nodes def collect_fields_impl( schema: GraphQLSchema, fragments: Dict[str, FragmentDefinitionNode], variable_values: Dict[str, Any], runtime_type: GraphQLObjectType, selection_set: SelectionSetNode, fields: Dict[str, List[FieldNode]], visited_fragment_names: Set[str], ) -> None: """Collect fields (internal implementation).""" for selection in selection_set.selections: if isinstance(selection, FieldNode): if not should_include_node(variable_values, selection): continue name = get_field_entry_key(selection) fields.setdefault(name, []).append(selection) elif isinstance(selection, InlineFragmentNode): if not should_include_node( variable_values, selection ) or not does_fragment_condition_match(schema, selection, runtime_type): continue collect_fields_impl( schema, fragments, variable_values, runtime_type, selection.selection_set, fields, visited_fragment_names, ) elif isinstance(selection, FragmentSpreadNode): # pragma: no cover else frag_name = selection.name.value if frag_name in visited_fragment_names or not should_include_node( variable_values, selection ): continue visited_fragment_names.add(frag_name) fragment = fragments.get(frag_name) if not fragment or not does_fragment_condition_match( schema, fragment, runtime_type ): continue collect_fields_impl( schema, fragments, variable_values, runtime_type, fragment.selection_set, fields, visited_fragment_names, ) def should_include_node( variable_values: Dict[str, Any], node: Union[FragmentSpreadNode, FieldNode, InlineFragmentNode], ) -> bool: """Check if node should be included Determines if a field should be included based on the @include and @skip directives, where @skip has higher precedence than @include. """ skip = get_directive_values(GraphQLSkipDirective, node, variable_values) if skip and skip["if"]: return False include = get_directive_values(GraphQLIncludeDirective, node, variable_values) if include and not include["if"]: return False return True def does_fragment_condition_match( schema: GraphQLSchema, fragment: Union[FragmentDefinitionNode, InlineFragmentNode], type_: GraphQLObjectType, ) -> bool: """Determine if a fragment is applicable to the given type.""" type_condition_node = fragment.type_condition if not type_condition_node: return True conditional_type = type_from_ast(schema, type_condition_node) if conditional_type is type_: return True if is_abstract_type(conditional_type): return schema.is_sub_type(cast(GraphQLAbstractType, conditional_type), type_) return False def get_field_entry_key(node: FieldNode) -> str: """Implements the logic to compute the key of a given field's entry""" return node.alias.value if node.alias else node.name.value graphql-core-3.2.6/src/graphql/execution/execute.py000066400000000000000000001326011474546154300223720ustar00rootroot00000000000000from asyncio import ensure_future, gather from collections.abc import Mapping from inspect import isawaitable from typing import ( Any, AsyncIterable, Awaitable, Callable, Dict, Iterable, List, Optional, Tuple, Type, Union, cast, ) try: from typing import TypedDict except ImportError: # Python < 3.8 from typing_extensions import TypedDict from ..error import GraphQLError, GraphQLFormattedError, located_error from ..language import ( DocumentNode, FieldNode, FragmentDefinitionNode, OperationDefinitionNode, OperationType, ) from ..pyutils import ( AwaitableOrValue, Path, Undefined, inspect, is_iterable, ) from ..pyutils import ( is_awaitable as default_is_awaitable, ) from ..type import ( GraphQLAbstractType, GraphQLField, GraphQLFieldResolver, GraphQLLeafType, GraphQLList, GraphQLNonNull, GraphQLObjectType, GraphQLOutputType, GraphQLResolveInfo, GraphQLSchema, GraphQLTypeResolver, SchemaMetaFieldDef, TypeMetaFieldDef, TypeNameMetaFieldDef, assert_valid_schema, is_abstract_type, is_leaf_type, is_list_type, is_non_null_type, is_object_type, ) from .collect_fields import collect_fields, collect_sub_fields from .middleware import MiddlewareManager from .values import get_argument_values, get_variable_values __all__ = [ "assert_valid_execution_arguments", "default_field_resolver", "default_type_resolver", "execute", "execute_sync", "get_field_def", "ExecutionResult", "ExecutionContext", "FormattedExecutionResult", "Middleware", ] # Terminology # # "Definitions" are the generic name for top-level statements in the document. # Examples of this include: # 1) Operations (such as a query) # 2) Fragments # # "Operations" are a generic name for requests in the document. # Examples of this include: # 1) query, # 2) mutation # # "Selections" are the definitions that can appear legally and at # single level of the query. These include: # 1) field references e.g "a" # 2) fragment "spreads" e.g. "...c" # 3) inline fragment "spreads" e.g. "...on Type { a }" class FormattedExecutionResult(TypedDict, total=False): """Formatted execution result""" errors: List[GraphQLFormattedError] data: Optional[Dict[str, Any]] extensions: Dict[str, Any] class ExecutionResult: """The result of GraphQL execution. - ``data`` is the result of a successful execution of the query. - ``errors`` is included when any errors occurred as a non-empty list. - ``extensions`` is reserved for adding non-standard properties. """ __slots__ = "data", "errors", "extensions" data: Optional[Dict[str, Any]] errors: Optional[List[GraphQLError]] extensions: Optional[Dict[str, Any]] def __init__( self, data: Optional[Dict[str, Any]] = None, errors: Optional[List[GraphQLError]] = None, extensions: Optional[Dict[str, Any]] = None, ): self.data = data self.errors = errors self.extensions = extensions def __repr__(self) -> str: name = self.__class__.__name__ ext = "" if self.extensions is None else f", extensions={self.extensions}" return f"{name}(data={self.data!r}, errors={self.errors!r}{ext})" def __iter__(self) -> Iterable[Any]: return iter((self.data, self.errors)) @property def formatted(self) -> FormattedExecutionResult: """Get execution result formatted according to the specification.""" formatted: FormattedExecutionResult = {"data": self.data} if self.errors is not None: formatted["errors"] = [error.formatted for error in self.errors] if self.extensions is not None: formatted["extensions"] = self.extensions return formatted def __eq__(self, other: Any) -> bool: if isinstance(other, dict): if "extensions" not in other: return other == dict(data=self.data, errors=self.errors) return other == dict( data=self.data, errors=self.errors, extensions=self.extensions ) if isinstance(other, tuple): if len(other) == 2: return other == (self.data, self.errors) return other == (self.data, self.errors, self.extensions) return ( isinstance(other, self.__class__) and other.data == self.data and other.errors == self.errors and other.extensions == self.extensions ) def __ne__(self, other: Any) -> bool: return not self == other Middleware = Optional[Union[Tuple, List, MiddlewareManager]] class ExecutionContext: """Data that must be available at all points during query execution. Namely, schema of the type system that is currently executing, and the fragments defined in the query document. """ schema: GraphQLSchema fragments: Dict[str, FragmentDefinitionNode] root_value: Any context_value: Any operation: OperationDefinitionNode variable_values: Dict[str, Any] field_resolver: GraphQLFieldResolver type_resolver: GraphQLTypeResolver subscribe_field_resolver: GraphQLFieldResolver errors: List[GraphQLError] middleware_manager: Optional[MiddlewareManager] is_awaitable = staticmethod(default_is_awaitable) def __init__( self, schema: GraphQLSchema, fragments: Dict[str, FragmentDefinitionNode], root_value: Any, context_value: Any, operation: OperationDefinitionNode, variable_values: Dict[str, Any], field_resolver: GraphQLFieldResolver, type_resolver: GraphQLTypeResolver, subscribe_field_resolver: GraphQLFieldResolver, errors: List[GraphQLError], middleware_manager: Optional[MiddlewareManager], is_awaitable: Optional[Callable[[Any], bool]], ) -> None: self.schema = schema self.fragments = fragments self.root_value = root_value self.context_value = context_value self.operation = operation self.variable_values = variable_values self.field_resolver = field_resolver self.type_resolver = type_resolver self.subscribe_field_resolver = subscribe_field_resolver self.errors = errors self.middleware_manager = middleware_manager if is_awaitable: self.is_awaitable = is_awaitable # type: ignore self._subfields_cache: Dict[Tuple, Dict[str, List[FieldNode]]] = {} @classmethod def build( cls, schema: GraphQLSchema, document: DocumentNode, root_value: Any = None, context_value: Any = None, raw_variable_values: Optional[Dict[str, Any]] = None, operation_name: Optional[str] = None, field_resolver: Optional[GraphQLFieldResolver] = None, type_resolver: Optional[GraphQLTypeResolver] = None, subscribe_field_resolver: Optional[GraphQLFieldResolver] = None, middleware: Optional[Middleware] = None, is_awaitable: Optional[Callable[[Any], bool]] = None, ) -> Union[List[GraphQLError], "ExecutionContext"]: """Build an execution context Constructs a ExecutionContext object from the arguments passed to execute, which we will pass throughout the other execution methods. Throws a GraphQLError if a valid execution context cannot be created. For internal use only. """ operation: Optional[OperationDefinitionNode] = None fragments: Dict[str, FragmentDefinitionNode] = {} middleware_manager: Optional[MiddlewareManager] = None if middleware is not None: if isinstance(middleware, (list, tuple)): middleware_manager = MiddlewareManager(*middleware) elif isinstance(middleware, MiddlewareManager): middleware_manager = middleware else: raise TypeError( "Middleware must be passed as a list or tuple of functions" " or objects, or as a single MiddlewareManager object." f" Got {inspect(middleware)} instead." ) for definition in document.definitions: if isinstance(definition, OperationDefinitionNode): if operation_name is None: if operation: return [ GraphQLError( "Must provide operation name" " if query contains multiple operations." ) ] operation = definition elif definition.name and definition.name.value == operation_name: operation = definition elif isinstance(definition, FragmentDefinitionNode): fragments[definition.name.value] = definition if not operation: if operation_name is not None: return [GraphQLError(f"Unknown operation named '{operation_name}'.")] return [GraphQLError("Must provide an operation.")] coerced_variable_values = get_variable_values( schema, operation.variable_definitions or (), raw_variable_values or {}, max_errors=50, ) if isinstance(coerced_variable_values, list): return coerced_variable_values # errors return cls( schema, fragments, root_value, context_value, operation, coerced_variable_values, # coerced values field_resolver or default_field_resolver, type_resolver or default_type_resolver, subscribe_field_resolver or default_field_resolver, [], middleware_manager, is_awaitable, ) @staticmethod def build_response( data: Optional[Dict[str, Any]], errors: List[GraphQLError] ) -> ExecutionResult: """Build response. Given a completed execution context and data, build the (data, errors) response defined by the "Response" section of the GraphQL spec. """ if not errors: return ExecutionResult(data, None) # Sort the error list in order to make it deterministic, since we might have # been using parallel execution. errors.sort( key=lambda error: (error.locations or [], error.path or [], error.message) ) return ExecutionResult(data, errors) def execute_operation( self, operation: OperationDefinitionNode, root_value: Any ) -> Optional[AwaitableOrValue[Any]]: """Execute an operation. Implements the "Executing operations" section of the spec. """ root_type = self.schema.get_root_type(operation.operation) if root_type is None: raise GraphQLError( "Schema is not configured to execute" f" {operation.operation.value} operation.", operation, ) root_fields = collect_fields( self.schema, self.fragments, self.variable_values, root_type, operation.selection_set, ) path = None return ( self.execute_fields_serially if operation.operation == OperationType.MUTATION else self.execute_fields )(root_type, root_value, path, root_fields) def execute_fields_serially( self, parent_type: GraphQLObjectType, source_value: Any, path: Optional[Path], fields: Dict[str, List[FieldNode]], ) -> AwaitableOrValue[Dict[str, Any]]: """Execute the given fields serially. Implements the "Executing selection sets" section of the spec for fields that must be executed serially. """ results: AwaitableOrValue[Dict[str, Any]] = {} is_awaitable = self.is_awaitable for response_name, field_nodes in fields.items(): field_path = Path(path, response_name, parent_type.name) result = self.execute_field( parent_type, source_value, field_nodes, field_path ) if result is Undefined: continue if is_awaitable(results): # noinspection PyShadowingNames async def await_and_set_result( results: Awaitable[Dict[str, Any]], response_name: str, result: AwaitableOrValue[Any], ) -> Dict[str, Any]: awaited_results = await results awaited_results[response_name] = ( await result if is_awaitable(result) else result ) return awaited_results results = await_and_set_result( cast(Awaitable, results), response_name, result ) elif is_awaitable(result): # noinspection PyShadowingNames async def set_result( results: Dict[str, Any], response_name: str, result: Awaitable, ) -> Dict[str, Any]: results[response_name] = await result return results results = set_result( cast(Dict[str, Any], results), response_name, result ) else: cast(Dict[str, Any], results)[response_name] = result return results def execute_fields( self, parent_type: GraphQLObjectType, source_value: Any, path: Optional[Path], fields: Dict[str, List[FieldNode]], ) -> AwaitableOrValue[Dict[str, Any]]: """Execute the given fields concurrently. Implements the "Executing selection sets" section of the spec for fields that may be executed in parallel. """ results = {} is_awaitable = self.is_awaitable awaitable_fields: List[str] = [] append_awaitable = awaitable_fields.append for response_name, field_nodes in fields.items(): field_path = Path(path, response_name, parent_type.name) result = self.execute_field( parent_type, source_value, field_nodes, field_path ) if result is not Undefined: results[response_name] = result if is_awaitable(result): append_awaitable(response_name) # If there are no coroutines, we can just return the object if not awaitable_fields: return results # Otherwise, results is a map from field name to the result of resolving that # field, which is possibly a coroutine object. Return a coroutine object that # will yield this same map, but with any coroutines awaited in parallel and # replaced with the values they yielded. async def get_results() -> Dict[str, Any]: results.update( zip( awaitable_fields, await gather(*(results[field] for field in awaitable_fields)), ) ) return results return get_results() def build_resolve_info( self, field_def: GraphQLField, field_nodes: List[FieldNode], parent_type: GraphQLObjectType, path: Path, ) -> GraphQLResolveInfo: """Build the GraphQLResolveInfo object. For internal use only.""" # The resolve function's first argument is a collection of information about # the current execution state. return GraphQLResolveInfo( field_nodes[0].name.value, field_nodes, field_def.type, parent_type, path, self.schema, self.fragments, self.root_value, self.operation, self.variable_values, self.context_value, self.is_awaitable, ) def execute_field( self, parent_type: GraphQLObjectType, source: Any, field_nodes: List[FieldNode], path: Path, ) -> AwaitableOrValue[Any]: """Resolve the field on the given source object. Implements the "Executing fields" section of the spec. In particular, this method figures out the value that the field returns by calling its resolve function, then calls complete_value to await coroutine objects, serialize scalars, or execute the sub-selection-set for objects. """ field_def = get_field_def(self.schema, parent_type, field_nodes[0]) if not field_def: return Undefined return_type = field_def.type resolve_fn = field_def.resolve or self.field_resolver if self.middleware_manager: resolve_fn = self.middleware_manager.get_field_resolver(resolve_fn) info = self.build_resolve_info(field_def, field_nodes, parent_type, path) # Get the resolve function, regardless of if its result is normal or abrupt # (error). try: # Build a dictionary of arguments from the field.arguments AST, using the # variables scope to fulfill any variable references. args = get_argument_values(field_def, field_nodes[0], self.variable_values) # Note that contrary to the JavaScript implementation, we pass the context # value as part of the resolve info. result = resolve_fn(source, info, **args) if self.is_awaitable(result): # noinspection PyShadowingNames async def await_result() -> Any: try: completed = self.complete_value( return_type, field_nodes, info, path, await result ) if self.is_awaitable(completed): return await completed return completed except Exception as raw_error: error = located_error(raw_error, field_nodes, path.as_list()) self.handle_field_error(error, return_type) return None return await_result() completed = self.complete_value( return_type, field_nodes, info, path, result ) if self.is_awaitable(completed): # noinspection PyShadowingNames async def await_completed() -> Any: try: return await completed except Exception as raw_error: error = located_error(raw_error, field_nodes, path.as_list()) self.handle_field_error(error, return_type) return None return await_completed() return completed except Exception as raw_error: error = located_error(raw_error, field_nodes, path.as_list()) self.handle_field_error(error, return_type) return None def handle_field_error( self, error: GraphQLError, return_type: GraphQLOutputType, ) -> None: # If the field type is non-nullable, then it is resolved without any protection # from errors, however it still properly locates the error. if is_non_null_type(return_type): raise error # Otherwise, error protection is applied, logging the error and resolving a # null value for this field if one is encountered. self.errors.append(error) return None def complete_value( self, return_type: GraphQLOutputType, field_nodes: List[FieldNode], info: GraphQLResolveInfo, path: Path, result: Any, ) -> AwaitableOrValue[Any]: """Complete a value. Implements the instructions for completeValue as defined in the "Value completion" section of the spec. If the field type is Non-Null, then this recursively completes the value for the inner type. It throws a field error if that completion returns null, as per the "Nullability" section of the spec. If the field type is a List, then this recursively completes the value for the inner type on each item in the list. If the field type is a Scalar or Enum, ensures the completed value is a legal value of the type by calling the ``serialize`` method of GraphQL type definition. If the field is an abstract type, determine the runtime type of the value and then complete based on that type. Otherwise, the field type expects a sub-selection set, and will complete the value by evaluating all sub-selections. """ # If result is an Exception, throw a located error. if isinstance(result, Exception): raise result # If field type is NonNull, complete for inner type, and throw field error if # result is null. if is_non_null_type(return_type): completed = self.complete_value( cast(GraphQLNonNull, return_type).of_type, field_nodes, info, path, result, ) if completed is None: raise TypeError( "Cannot return null for non-nullable field" f" {info.parent_type.name}.{info.field_name}." ) return completed # If result value is null or undefined then return null. if result is None or result is Undefined: return None # If field type is List, complete each item in the list with inner type if is_list_type(return_type): return self.complete_list_value( cast(GraphQLList, return_type), field_nodes, info, path, result ) # If field type is a leaf type, Scalar or Enum, serialize to a valid value, # returning null if serialization is not possible. if is_leaf_type(return_type): return self.complete_leaf_value(cast(GraphQLLeafType, return_type), result) # If field type is an abstract type, Interface or Union, determine the runtime # Object type and complete for that type. if is_abstract_type(return_type): return self.complete_abstract_value( cast(GraphQLAbstractType, return_type), field_nodes, info, path, result ) # If field type is Object, execute and complete all sub-selections. if is_object_type(return_type): return self.complete_object_value( cast(GraphQLObjectType, return_type), field_nodes, info, path, result ) # Not reachable. All possible output types have been considered. raise TypeError( # pragma: no cover "Cannot complete value of unexpected output type:" f" '{inspect(return_type)}'." ) def complete_list_value( self, return_type: GraphQLList[GraphQLOutputType], field_nodes: List[FieldNode], info: GraphQLResolveInfo, path: Path, result: Union[AsyncIterable[Any], Iterable[Any]], ) -> AwaitableOrValue[List[Any]]: """Complete a list value. Complete a list value by completing each item in the list with the inner type. """ if not is_iterable(result): # experimental: allow async iterables if isinstance(result, AsyncIterable): # noinspection PyShadowingNames async def async_iterable_to_list( async_result: AsyncIterable[Any], ) -> Any: sync_result = [item async for item in async_result] return self.complete_list_value( return_type, field_nodes, info, path, sync_result ) return async_iterable_to_list(result) raise GraphQLError( "Expected Iterable, but did not find one for field" f" '{info.parent_type.name}.{info.field_name}'." ) result = cast(Iterable[Any], result) # This is specified as a simple map, however we're optimizing the path where # the list contains no coroutine objects by avoiding creating another coroutine # object. item_type = return_type.of_type is_awaitable = self.is_awaitable awaitable_indices: List[int] = [] append_awaitable = awaitable_indices.append completed_results: List[Any] = [] append_result = completed_results.append for index, item in enumerate(result): # No need to modify the info object containing the path, since from here on # it is not ever accessed by resolver functions. item_path = path.add_key(index, None) completed_item: AwaitableOrValue[Any] if is_awaitable(item): # noinspection PyShadowingNames async def await_completed(item: Any, item_path: Path) -> Any: try: completed = self.complete_value( item_type, field_nodes, info, item_path, await item ) if is_awaitable(completed): return await completed return completed except Exception as raw_error: error = located_error( raw_error, field_nodes, item_path.as_list() ) self.handle_field_error(error, item_type) return None completed_item = await_completed(item, item_path) else: try: completed_item = self.complete_value( item_type, field_nodes, info, item_path, item ) if is_awaitable(completed_item): # noinspection PyShadowingNames async def await_completed(item: Any, item_path: Path) -> Any: try: return await item except Exception as raw_error: error = located_error( raw_error, field_nodes, item_path.as_list() ) self.handle_field_error(error, item_type) return None completed_item = await_completed(completed_item, item_path) except Exception as raw_error: error = located_error(raw_error, field_nodes, item_path.as_list()) self.handle_field_error(error, item_type) completed_item = None if is_awaitable(completed_item): append_awaitable(index) append_result(completed_item) if not awaitable_indices: return completed_results # noinspection PyShadowingNames async def get_completed_results() -> List[Any]: for index, result in zip( awaitable_indices, await gather( *(completed_results[index] for index in awaitable_indices) ), ): completed_results[index] = result return completed_results return get_completed_results() @staticmethod def complete_leaf_value(return_type: GraphQLLeafType, result: Any) -> Any: """Complete a leaf value. Complete a Scalar or Enum by serializing to a valid value, returning null if serialization is not possible. """ serialized_result = return_type.serialize(result) if serialized_result is Undefined or serialized_result is None: raise TypeError( f"Expected `{inspect(return_type)}.serialize({inspect(result)})`" f" to return non-nullable value, returned: {inspect(serialized_result)}" ) return serialized_result def complete_abstract_value( self, return_type: GraphQLAbstractType, field_nodes: List[FieldNode], info: GraphQLResolveInfo, path: Path, result: Any, ) -> AwaitableOrValue[Any]: """Complete an abstract value. Complete a value of an abstract type by determining the runtime object type of that value, then complete the value for that type. """ resolve_type_fn = return_type.resolve_type or self.type_resolver runtime_type = resolve_type_fn(result, info, return_type) if self.is_awaitable(runtime_type): runtime_type = cast(Awaitable, runtime_type) async def await_complete_object_value() -> Any: value = self.complete_object_value( self.ensure_valid_runtime_type( await runtime_type, # type: ignore return_type, field_nodes, info, result, ), field_nodes, info, path, result, ) if self.is_awaitable(value): return await value # type: ignore return value # pragma: no cover return await_complete_object_value() runtime_type = cast(Optional[str], runtime_type) return self.complete_object_value( self.ensure_valid_runtime_type( runtime_type, return_type, field_nodes, info, result ), field_nodes, info, path, result, ) def ensure_valid_runtime_type( self, runtime_type_name: Any, return_type: GraphQLAbstractType, field_nodes: List[FieldNode], info: GraphQLResolveInfo, result: Any, ) -> GraphQLObjectType: if runtime_type_name is None: raise GraphQLError( f"Abstract type '{return_type.name}' must resolve" " to an Object type at runtime" f" for field '{info.parent_type.name}.{info.field_name}'." f" Either the '{return_type.name}' type should provide" " a 'resolve_type' function or each possible type should provide" " an 'is_type_of' function.", field_nodes, ) if is_object_type(runtime_type_name): # pragma: no cover raise GraphQLError( "Support for returning GraphQLObjectType from resolve_type was" " removed in GraphQL-core 3.2, please return type name instead." ) if not isinstance(runtime_type_name, str): raise GraphQLError( f"Abstract type '{return_type.name}' must resolve" " to an Object type at runtime" f" for field '{info.parent_type.name}.{info.field_name}' with value" f" {inspect(result)}, received '{inspect(runtime_type_name)}'.", field_nodes, ) runtime_type = self.schema.get_type(runtime_type_name) if runtime_type is None: raise GraphQLError( f"Abstract type '{return_type.name}' was resolved to a type" f" '{runtime_type_name}' that does not exist inside the schema.", field_nodes, ) if not is_object_type(runtime_type): raise GraphQLError( f"Abstract type '{return_type.name}' was resolved" f" to a non-object type '{runtime_type_name}'.", field_nodes, ) runtime_type = cast(GraphQLObjectType, runtime_type) if not self.schema.is_sub_type(return_type, runtime_type): raise GraphQLError( f"Runtime Object type '{runtime_type.name}' is not a possible" f" type for '{return_type.name}'.", field_nodes, ) return runtime_type def complete_object_value( self, return_type: GraphQLObjectType, field_nodes: List[FieldNode], info: GraphQLResolveInfo, path: Path, result: Any, ) -> AwaitableOrValue[Dict[str, Any]]: """Complete an Object value by executing all sub-selections.""" # Collect sub-fields to execute to complete this value. sub_field_nodes = self.collect_subfields(return_type, field_nodes) # If there is an `is_type_of()` predicate function, call it with the current # result. If `is_type_of()` returns False, then raise an error rather than # continuing execution. if return_type.is_type_of: is_type_of = return_type.is_type_of(result, info) if self.is_awaitable(is_type_of): async def execute_subfields_async() -> Dict[str, Any]: if not await is_type_of: # type: ignore raise invalid_return_type_error( return_type, result, field_nodes ) return self.execute_fields( return_type, result, path, sub_field_nodes ) # type: ignore return execute_subfields_async() if not is_type_of: raise invalid_return_type_error(return_type, result, field_nodes) return self.execute_fields(return_type, result, path, sub_field_nodes) def collect_subfields( self, return_type: GraphQLObjectType, field_nodes: List[FieldNode] ) -> Dict[str, List[FieldNode]]: """Collect subfields. A cached collection of relevant subfields with regard to the return type is kept in the execution context as ``_subfields_cache``. This ensures the subfields are not repeatedly calculated, which saves overhead when resolving lists of values. """ cache = self._subfields_cache # We cannot use the field_nodes themselves as key for the cache, since they # are not hashable as a list. We also do not want to use the field_nodes # themselves (converted to a tuple) as keys, since hashing them is slow. # Therefore we use the ids of the field_nodes as keys. Note that we do not # use the id of the list, since we want to hit the cache for all lists of # the same nodes, not only for the same list of nodes. Also, the list id may # even be reused, in which case we would get wrong results from the cache. key = ( (return_type, id(field_nodes[0])) if len(field_nodes) == 1 # optimize most frequent case else tuple((return_type, *map(id, field_nodes))) ) sub_field_nodes = cache.get(key) if sub_field_nodes is None: sub_field_nodes = collect_sub_fields( self.schema, self.fragments, self.variable_values, return_type, field_nodes, ) cache[key] = sub_field_nodes return sub_field_nodes def execute( schema: GraphQLSchema, document: DocumentNode, root_value: Any = None, context_value: Any = None, variable_values: Optional[Dict[str, Any]] = None, operation_name: Optional[str] = None, field_resolver: Optional[GraphQLFieldResolver] = None, type_resolver: Optional[GraphQLTypeResolver] = None, subscribe_field_resolver: Optional[GraphQLFieldResolver] = None, middleware: Optional[Middleware] = None, execution_context_class: Optional[Type["ExecutionContext"]] = None, is_awaitable: Optional[Callable[[Any], bool]] = None, ) -> AwaitableOrValue[ExecutionResult]: """Execute a GraphQL operation. Implements the "Executing requests" section of the GraphQL specification. Returns an ExecutionResult (if all encountered resolvers are synchronous), or a coroutine object eventually yielding an ExecutionResult. If the arguments to this function do not result in a legal execution context, a GraphQLError will be thrown immediately explaining the invalid input. """ # If arguments are missing or incorrect, throw an error. assert_valid_execution_arguments(schema, document, variable_values) if execution_context_class is None: execution_context_class = ExecutionContext # If a valid execution context cannot be created due to incorrect arguments, # a "Response" with only errors is returned. exe_context = execution_context_class.build( schema, document, root_value, context_value, variable_values, operation_name, field_resolver, type_resolver, subscribe_field_resolver, middleware, is_awaitable, ) # Return early errors if execution context failed. if isinstance(exe_context, list): return ExecutionResult(data=None, errors=exe_context) # Return a possible coroutine object that will eventually yield the data described # by the "Response" section of the GraphQL specification. # # If errors are encountered while executing a GraphQL field, only that field and # its descendants will be omitted, and sibling fields will still be executed. An # execution which encounters errors will still result in a coroutine object that # can be executed without errors. # # Errors from sub-fields of a NonNull type may propagate to the top level, # at which point we still log the error and null the parent field, which # in this case is the entire response. errors = exe_context.errors build_response = exe_context.build_response try: operation = exe_context.operation result = exe_context.execute_operation(operation, root_value) if exe_context.is_awaitable(result): # noinspection PyShadowingNames async def await_result() -> Any: try: return build_response(await result, errors) # type: ignore except GraphQLError as error: errors.append(error) return build_response(None, errors) return await_result() except GraphQLError as error: errors.append(error) return build_response(None, errors) else: return build_response(result, errors) # type: ignore def assume_not_awaitable(_value: Any) -> bool: """Replacement for isawaitable if everything is assumed to be synchronous.""" return False def execute_sync( schema: GraphQLSchema, document: DocumentNode, root_value: Any = None, context_value: Any = None, variable_values: Optional[Dict[str, Any]] = None, operation_name: Optional[str] = None, field_resolver: Optional[GraphQLFieldResolver] = None, type_resolver: Optional[GraphQLTypeResolver] = None, middleware: Optional[Middleware] = None, execution_context_class: Optional[Type["ExecutionContext"]] = None, check_sync: bool = False, ) -> ExecutionResult: """Execute a GraphQL operation synchronously. Also implements the "Executing requests" section of the GraphQL specification. However, it guarantees to complete synchronously (or throw an error) assuming that all field resolvers are also synchronous. Set check_sync to True to still run checks that no awaitable values are returned. """ is_awaitable = ( check_sync if callable(check_sync) else (None if check_sync else assume_not_awaitable) ) result = execute( schema, document, root_value, context_value, variable_values, operation_name, field_resolver, type_resolver, None, middleware, execution_context_class, is_awaitable, ) # Assert that the execution was synchronous. if isawaitable(result): ensure_future(result).cancel() raise RuntimeError("GraphQL execution failed to complete synchronously.") return result def assert_valid_execution_arguments( schema: GraphQLSchema, document: DocumentNode, raw_variable_values: Optional[Dict[str, Any]] = None, ) -> None: """Check that the arguments are acceptable. Essential assertions before executing to provide developer feedback for improper use of the GraphQL library. For internal use only. """ if not document: raise TypeError("Must provide document.") # If the schema used for execution is invalid, throw an error. assert_valid_schema(schema) # Variables, if provided, must be a dictionary. if not (raw_variable_values is None or isinstance(raw_variable_values, dict)): raise TypeError( "Variable values must be provided as a dictionary" " with variable names as keys. Perhaps look to see" " if an unparsed JSON string was provided." ) def get_field_def( schema: GraphQLSchema, parent_type: GraphQLObjectType, field_node: FieldNode ) -> GraphQLField: """Get field definition. This method looks up the field on the given type definition. It has special casing for the three introspection fields, ``__schema``, ``__type`, and ``__typename``. ``__typename`` is special because it can always be queried as a field, even in situations where no other fields are allowed, like on a Union. ``__schema`` and ``__type`` could get automatically added to the query type, but that would require mutating type definitions, which would cause issues. For internal use only. """ field_name = field_node.name.value if field_name == "__schema" and schema.query_type == parent_type: return SchemaMetaFieldDef elif field_name == "__type" and schema.query_type == parent_type: return TypeMetaFieldDef elif field_name == "__typename": return TypeNameMetaFieldDef return parent_type.fields.get(field_name) def invalid_return_type_error( return_type: GraphQLObjectType, result: Any, field_nodes: List[FieldNode] ) -> GraphQLError: """Create a GraphQLError for an invalid return type.""" return GraphQLError( f"Expected value of type '{return_type.name}' but got: {inspect(result)}.", field_nodes, ) def get_typename(value: Any) -> Optional[str]: """Get the ``__typename`` property of the given value.""" if isinstance(value, Mapping): return value.get("__typename") # need to de-mangle the attribute assumed to be "private" in Python for cls in value.__class__.__mro__: __typename = getattr(value, f"_{cls.__name__}__typename", None) if __typename: return __typename return None def default_type_resolver( value: Any, info: GraphQLResolveInfo, abstract_type: GraphQLAbstractType ) -> AwaitableOrValue[Optional[str]]: """Default type resolver function. If a resolve_type function is not given, then a default resolve behavior is used which attempts two strategies: First, See if the provided value has a ``__typename`` field defined, if so, use that value as name of the resolved type. Otherwise, test each possible type for the abstract type by calling :meth:`~graphql.type.GraphQLObjectType.is_type_of` for the object being coerced, returning the first type that matches. """ # First, look for `__typename`. type_name = get_typename(value) if isinstance(type_name, str): return type_name # Otherwise, test each possible type. possible_types = info.schema.get_possible_types(abstract_type) is_awaitable = info.is_awaitable awaitable_is_type_of_results: List[Awaitable] = [] append_awaitable_results = awaitable_is_type_of_results.append awaitable_types: List[GraphQLObjectType] = [] append_awaitable_types = awaitable_types.append for type_ in possible_types: if type_.is_type_of: is_type_of_result = type_.is_type_of(value, info) if is_awaitable(is_type_of_result): append_awaitable_results(cast(Awaitable, is_type_of_result)) append_awaitable_types(type_) elif is_type_of_result: return type_.name if awaitable_is_type_of_results: # noinspection PyShadowingNames async def get_type() -> Optional[str]: is_type_of_results = await gather(*awaitable_is_type_of_results) for is_type_of_result, type_ in zip(is_type_of_results, awaitable_types): if is_type_of_result: return type_.name return None return get_type() return None def default_field_resolver(source: Any, info: GraphQLResolveInfo, **args: Any) -> Any: """Default field resolver. If a resolve function is not given, then a default resolve behavior is used which takes the property of the source object of the same name as the field and returns it as the result, or if it's a function, returns the result of calling that function while passing along args and context. For dictionaries, the field names are used as keys, for all other objects they are used as attribute names. """ # Ensure source is a value for which property access is acceptable. field_name = info.field_name value = ( source.get(field_name) if isinstance(source, Mapping) else getattr(source, field_name, None) ) if callable(value): return value(info, **args) return value graphql-core-3.2.6/src/graphql/execution/map_async_iterator.py000066400000000000000000000073051474546154300246150ustar00rootroot00000000000000from asyncio import CancelledError, Event, Task, ensure_future, wait from concurrent.futures import FIRST_COMPLETED from inspect import isasyncgen, isawaitable from types import TracebackType from typing import Any, AsyncIterable, Callable, Optional, Set, Type, Union __all__ = ["MapAsyncIterator"] # noinspection PyAttributeOutsideInit class MapAsyncIterator: """Map an AsyncIterable over a callback function. Given an AsyncIterable and a callback function, return an AsyncIterator which produces values mapped via calling the callback function. When the resulting AsyncIterator is closed, the underlying AsyncIterable will also be closed. """ def __init__(self, iterable: AsyncIterable, callback: Callable) -> None: self.iterator = iterable.__aiter__() self.callback = callback self._close_event = Event() def __aiter__(self) -> "MapAsyncIterator": """Get the iterator object.""" return self async def __anext__(self) -> Any: """Get the next value of the iterator.""" if self.is_closed: if not isasyncgen(self.iterator): raise StopAsyncIteration value = await self.iterator.__anext__() else: aclose = ensure_future(self._close_event.wait()) anext = ensure_future(self.iterator.__anext__()) try: pending: Set[Task] = ( await wait([aclose, anext], return_when=FIRST_COMPLETED) )[1] except CancelledError: # cancel underlying tasks and close aclose.cancel() anext.cancel() await self.aclose() raise # re-raise the cancellation for task in pending: task.cancel() if aclose.done(): raise StopAsyncIteration error = anext.exception() if error: raise error value = anext.result() result = self.callback(value) return await result if isawaitable(result) else result async def athrow( self, type_: Union[BaseException, Type[BaseException]], value: Optional[BaseException] = None, traceback: Optional[TracebackType] = None, ) -> None: """Throw an exception into the asynchronous iterator.""" if self.is_closed: return if isinstance(type_, BaseException): value = type_ type_ = type(value) traceback = value.__traceback__ athrow = getattr(self.iterator, "athrow", None) if athrow: await athrow(type_ if value is None else value) else: await self.aclose() if value is None: if traceback is None: raise type_ # pragma: no cover value = type_ if isinstance(value, BaseException) else type_() if traceback is not None: value = value.with_traceback(traceback) raise value async def aclose(self) -> None: """Close the iterator.""" if not self.is_closed: aclose = getattr(self.iterator, "aclose", None) if aclose: try: await aclose() except RuntimeError: pass self.is_closed = True @property def is_closed(self) -> bool: """Check whether the iterator is closed.""" return self._close_event.is_set() @is_closed.setter def is_closed(self, value: bool) -> None: """Mark the iterator as closed.""" if value: self._close_event.set() else: self._close_event.clear() graphql-core-3.2.6/src/graphql/execution/middleware.py000066400000000000000000000046431474546154300230510ustar00rootroot00000000000000from functools import partial, reduce from inspect import isfunction from typing import Callable, Iterator, Dict, List, Tuple, Any, Optional __all__ = ["MiddlewareManager"] GraphQLFieldResolver = Callable[..., Any] class MiddlewareManager: """Manager for the middleware chain. This class helps to wrap resolver functions with the provided middleware functions and/or objects. The functions take the next middleware function as first argument. If middleware is provided as an object, it must provide a method ``resolve`` that is used as the middleware function. Note that since resolvers return "AwaitableOrValue"s, all middleware functions must be aware of this and check whether values are awaitable before awaiting them. """ # allow custom attributes (not used internally) __slots__ = "__dict__", "middlewares", "_middleware_resolvers", "_cached_resolvers" _cached_resolvers: Dict[GraphQLFieldResolver, GraphQLFieldResolver] _middleware_resolvers: Optional[List[Callable]] def __init__(self, *middlewares: Any): self.middlewares = middlewares self._middleware_resolvers = ( list(get_middleware_resolvers(middlewares)) if middlewares else None ) self._cached_resolvers = {} def get_field_resolver( self, field_resolver: GraphQLFieldResolver ) -> GraphQLFieldResolver: """Wrap the provided resolver with the middleware. Returns a function that chains the middleware functions with the provided resolver function. """ if self._middleware_resolvers is None: return field_resolver if field_resolver not in self._cached_resolvers: self._cached_resolvers[field_resolver] = reduce( lambda chained_fns, next_fn: partial(next_fn, chained_fns), self._middleware_resolvers, field_resolver, ) return self._cached_resolvers[field_resolver] def get_middleware_resolvers(middlewares: Tuple[Any, ...]) -> Iterator[Callable]: """Get a list of resolver functions from a list of classes or functions.""" for middleware in middlewares: if isfunction(middleware): yield middleware else: # middleware provided as object with 'resolve' method resolver_func = getattr(middleware, "resolve", None) if resolver_func is not None: yield resolver_func graphql-core-3.2.6/src/graphql/execution/subscribe.py000066400000000000000000000174361474546154300227210ustar00rootroot00000000000000from inspect import isawaitable from typing import ( Any, AsyncIterable, AsyncIterator, Dict, Optional, Union, ) from ..error import GraphQLError, located_error from ..execution.collect_fields import collect_fields from ..execution.execute import ( assert_valid_execution_arguments, execute, get_field_def, ExecutionContext, ExecutionResult, ) from ..execution.values import get_argument_values from ..language import DocumentNode from ..pyutils import Path, inspect from ..type import GraphQLFieldResolver, GraphQLSchema from .map_async_iterator import MapAsyncIterator __all__ = ["subscribe", "create_source_event_stream"] async def subscribe( schema: GraphQLSchema, document: DocumentNode, root_value: Any = None, context_value: Any = None, variable_values: Optional[Dict[str, Any]] = None, operation_name: Optional[str] = None, field_resolver: Optional[GraphQLFieldResolver] = None, subscribe_field_resolver: Optional[GraphQLFieldResolver] = None, ) -> Union[AsyncIterator[ExecutionResult], ExecutionResult]: """Create a GraphQL subscription. Implements the "Subscribe" algorithm described in the GraphQL spec. Returns a coroutine object which yields either an AsyncIterator (if successful) or an ExecutionResult (client error). The coroutine will raise an exception if a server error occurs. If the client-provided arguments to this function do not result in a compliant subscription, a GraphQL Response (ExecutionResult) with descriptive errors and no data will be returned. If the source stream could not be created due to faulty subscription resolver logic or underlying systems, the coroutine object will yield a single ExecutionResult containing ``errors`` and no ``data``. If the operation succeeded, the coroutine will yield an AsyncIterator, which yields a stream of ExecutionResults representing the response stream. """ result_or_stream = await create_source_event_stream( schema, document, root_value, context_value, variable_values, operation_name, subscribe_field_resolver, ) if isinstance(result_or_stream, ExecutionResult): return result_or_stream async def map_source_to_response(payload: Any) -> ExecutionResult: """Map source to response. For each payload yielded from a subscription, map it over the normal GraphQL :func:`~graphql.execute` function, with ``payload`` as the ``root_value``. This implements the "MapSourceToResponseEvent" algorithm described in the GraphQL specification. The :func:`~graphql.execute` function provides the "ExecuteSubscriptionEvent" algorithm, as it is nearly identical to the "ExecuteQuery" algorithm, for which :func:`~graphql.execute` is also used. """ result = execute( schema, document, payload, context_value, variable_values, operation_name, field_resolver, ) return await result if isawaitable(result) else result # Map every source value to a ExecutionResult value as described above. return MapAsyncIterator(result_or_stream, map_source_to_response) async def create_source_event_stream( schema: GraphQLSchema, document: DocumentNode, root_value: Any = None, context_value: Any = None, variable_values: Optional[Dict[str, Any]] = None, operation_name: Optional[str] = None, subscribe_field_resolver: Optional[GraphQLFieldResolver] = None, ) -> Union[AsyncIterable[Any], ExecutionResult]: """Create source event stream Implements the "CreateSourceEventStream" algorithm described in the GraphQL specification, resolving the subscription source event stream. Returns a coroutine that yields an AsyncIterable. If the client-provided arguments to this function do not result in a compliant subscription, a GraphQL Response (ExecutionResult) with descriptive errors and no data will be returned. If the source stream could not be created due to faulty subscription resolver logic or underlying systems, the coroutine object will yield a single ExecutionResult containing ``errors`` and no ``data``. A source event stream represents a sequence of events, each of which triggers a GraphQL execution for that event. This may be useful when hosting the stateful subscription service in a different process or machine than the stateless GraphQL execution engine, or otherwise separating these two steps. For more on this, see the "Supporting Subscriptions at Scale" information in the GraphQL spec. """ # If arguments are missing or incorrectly typed, this is an internal developer # mistake which should throw an early error. assert_valid_execution_arguments(schema, document, variable_values) # If a valid context cannot be created due to incorrect arguments, # a "Response" with only errors is returned. context = ExecutionContext.build( schema, document, root_value, context_value, variable_values, operation_name, subscribe_field_resolver=subscribe_field_resolver, ) # Return early errors if execution context failed. if isinstance(context, list): return ExecutionResult(data=None, errors=context) try: event_stream = await execute_subscription(context) # Assert field returned an event stream, otherwise yield an error. if not isinstance(event_stream, AsyncIterable): raise TypeError( "Subscription field must return AsyncIterable." f" Received: {inspect(event_stream)}." ) return event_stream except GraphQLError as error: # Report it as an ExecutionResult, containing only errors and no data. return ExecutionResult(data=None, errors=[error]) async def execute_subscription(context: ExecutionContext) -> AsyncIterable[Any]: schema = context.schema root_type = schema.subscription_type if root_type is None: raise GraphQLError( "Schema is not configured to execute subscription operation.", context.operation, ) root_fields = collect_fields( schema, context.fragments, context.variable_values, root_type, context.operation.selection_set, ) response_name, field_nodes = next(iter(root_fields.items())) field_def = get_field_def(schema, root_type, field_nodes[0]) if not field_def: field_name = field_nodes[0].name.value raise GraphQLError( f"The subscription field '{field_name}' is not defined.", field_nodes ) path = Path(None, response_name, root_type.name) info = context.build_resolve_info(field_def, field_nodes, root_type, path) # Implements the "ResolveFieldEventStream" algorithm from GraphQL specification. # It differs from "ResolveFieldValue" due to providing a different `resolveFn`. try: # Build a dictionary of arguments from the field.arguments AST, using the # variables scope to fulfill any variable references. args = get_argument_values(field_def, field_nodes[0], context.variable_values) # Call the `subscribe()` resolver or the default resolver to produce an # AsyncIterable yielding raw payloads. resolve_fn = field_def.subscribe or context.subscribe_field_resolver event_stream = resolve_fn(context.root_value, info, **args) if context.is_awaitable(event_stream): event_stream = await event_stream if isinstance(event_stream, Exception): raise event_stream return event_stream except Exception as error: raise located_error(error, field_nodes, path.as_list()) graphql-core-3.2.6/src/graphql/execution/values.py000066400000000000000000000215111474546154300222240ustar00rootroot00000000000000from typing import Any, Callable, Collection, Dict, List, Optional, Union, cast from ..error import GraphQLError from ..language import ( DirectiveNode, EnumValueDefinitionNode, ExecutableDefinitionNode, FieldDefinitionNode, FieldNode, InputValueDefinitionNode, NullValueNode, SchemaDefinitionNode, SelectionNode, TypeDefinitionNode, TypeExtensionNode, VariableDefinitionNode, VariableNode, print_ast, ) from ..pyutils import Undefined, inspect, print_path_list from ..type import ( GraphQLDirective, GraphQLField, GraphQLInputType, GraphQLSchema, is_input_object_type, is_input_type, is_non_null_type, ) from ..utilities.coerce_input_value import coerce_input_value from ..utilities.type_from_ast import type_from_ast from ..utilities.value_from_ast import value_from_ast __all__ = ["get_argument_values", "get_directive_values", "get_variable_values"] CoercedVariableValues = Union[List[GraphQLError], Dict[str, Any]] def get_variable_values( schema: GraphQLSchema, var_def_nodes: Collection[VariableDefinitionNode], inputs: Dict[str, Any], max_errors: Optional[int] = None, ) -> CoercedVariableValues: """Get coerced variable values based on provided definitions. Prepares a dict of variable values of the correct type based on the provided variable definitions and arbitrary input. If the input cannot be parsed to match the variable definitions, a GraphQLError will be raised. """ errors: List[GraphQLError] = [] def on_error(error: GraphQLError) -> None: if max_errors is not None and len(errors) >= max_errors: raise GraphQLError( "Too many errors processing variables," " error limit reached. Execution aborted." ) errors.append(error) try: coerced = coerce_variable_values(schema, var_def_nodes, inputs, on_error) if not errors: return coerced except GraphQLError as e: errors.append(e) return errors def coerce_variable_values( schema: GraphQLSchema, var_def_nodes: Collection[VariableDefinitionNode], inputs: Dict[str, Any], on_error: Callable[[GraphQLError], None], ) -> Dict[str, Any]: coerced_values: Dict[str, Any] = {} for var_def_node in var_def_nodes: var_name = var_def_node.variable.name.value var_type = type_from_ast(schema, var_def_node.type) if not is_input_type(var_type): # Must use input types for variables. This should be caught during # validation, however is checked again here for safety. var_type_str = print_ast(var_def_node.type) on_error( GraphQLError( f"Variable '${var_name}' expected value of type '{var_type_str}'" " which cannot be used as an input type.", var_def_node.type, ) ) continue var_type = cast(GraphQLInputType, var_type) if var_name not in inputs: if var_def_node.default_value: coerced_values[var_name] = value_from_ast( var_def_node.default_value, var_type ) elif is_non_null_type(var_type): # pragma: no cover else var_type_str = inspect(var_type) on_error( GraphQLError( f"Variable '${var_name}' of required type '{var_type_str}'" " was not provided.", var_def_node, ) ) continue value = inputs[var_name] if value is None and is_non_null_type(var_type): var_type_str = inspect(var_type) on_error( GraphQLError( f"Variable '${var_name}' of non-null type '{var_type_str}'" " must not be null.", var_def_node, ) ) continue def on_input_value_error( path: List[Union[str, int]], invalid_value: Any, error: GraphQLError ) -> None: invalid_str = inspect(invalid_value) prefix = f"Variable '${var_name}' got invalid value {invalid_str}" if path: prefix += f" at '{var_name}{print_path_list(path)}'" on_error( GraphQLError( prefix + "; " + error.message, var_def_node, original_error=error, ) ) coerced_values[var_name] = coerce_input_value( value, var_type, on_input_value_error ) return coerced_values def get_argument_values( type_def: Union[GraphQLField, GraphQLDirective], node: Union[FieldNode, DirectiveNode], variable_values: Optional[Dict[str, Any]] = None, ) -> Dict[str, Any]: """Get coerced argument values based on provided definitions and nodes. Prepares a dict of argument values given a list of argument definitions and list of argument AST nodes. """ coerced_values: Dict[str, Any] = {} arg_node_map = {arg.name.value: arg for arg in node.arguments or []} for name, arg_def in type_def.args.items(): arg_type = arg_def.type argument_node = arg_node_map.get(name) if argument_node is None: value = arg_def.default_value if value is not Undefined: if is_input_object_type(arg_def.type): # coerce input value so that out_names are used value = coerce_input_value(value, arg_def.type) coerced_values[arg_def.out_name or name] = value elif is_non_null_type(arg_type): # pragma: no cover else raise GraphQLError( f"Argument '{name}' of required type '{arg_type}'" " was not provided.", node, ) continue # pragma: no cover value_node = argument_node.value is_null = isinstance(argument_node.value, NullValueNode) if isinstance(value_node, VariableNode): variable_name = value_node.name.value if variable_values is None or variable_name not in variable_values: value = arg_def.default_value if value is not Undefined: if is_input_object_type(arg_def.type): # coerce input value so that out_names are used value = coerce_input_value(value, arg_def.type) coerced_values[arg_def.out_name or name] = value elif is_non_null_type(arg_type): # pragma: no cover else raise GraphQLError( f"Argument '{name}' of required type '{arg_type}'" f" was provided the variable '${variable_name}'" " which was not provided a runtime value.", value_node, ) continue # pragma: no cover is_null = variable_values[variable_name] is None if is_null and is_non_null_type(arg_type): raise GraphQLError( f"Argument '{name}' of non-null type '{arg_type}' must not be null.", value_node, ) coerced_value = value_from_ast(value_node, arg_type, variable_values) if coerced_value is Undefined: # Note: `values_of_correct_type` validation should catch this before # execution. This is a runtime check to ensure execution does not # continue with an invalid argument value. raise GraphQLError( f"Argument '{name}' has invalid value {print_ast(value_node)}.", value_node, ) coerced_values[arg_def.out_name or name] = coerced_value return coerced_values NodeWithDirective = Union[ EnumValueDefinitionNode, ExecutableDefinitionNode, FieldDefinitionNode, InputValueDefinitionNode, SelectionNode, SchemaDefinitionNode, TypeDefinitionNode, TypeExtensionNode, ] def get_directive_values( directive_def: GraphQLDirective, node: NodeWithDirective, variable_values: Optional[Dict[str, Any]] = None, ) -> Optional[Dict[str, Any]]: """Get coerced argument values based on provided nodes. Prepares a dict of argument values given a directive definition and an AST node which may contain directives. Optionally also accepts a dict of variable values. If the directive does not exist on the node, returns None. """ directives = node.directives if directives: directive_name = directive_def.name for directive in directives: if directive.name.value == directive_name: return get_argument_values(directive_def, directive, variable_values) return None graphql-core-3.2.6/src/graphql/graphql.py000066400000000000000000000152421474546154300203640ustar00rootroot00000000000000from asyncio import ensure_future from inspect import isawaitable from typing import Any, Callable, Dict, Optional, Type, Union from .error import GraphQLError from .execution import ExecutionContext, ExecutionResult, Middleware, execute from .language import Source, parse from .pyutils import AwaitableOrValue from .type import ( GraphQLFieldResolver, GraphQLSchema, GraphQLTypeResolver, validate_schema, ) __all__ = ["graphql", "graphql_sync"] async def graphql( schema: GraphQLSchema, source: Union[str, Source], root_value: Any = None, context_value: Any = None, variable_values: Optional[Dict[str, Any]] = None, operation_name: Optional[str] = None, field_resolver: Optional[GraphQLFieldResolver] = None, type_resolver: Optional[GraphQLTypeResolver] = None, middleware: Optional[Middleware] = None, execution_context_class: Optional[Type[ExecutionContext]] = None, is_awaitable: Optional[Callable[[Any], bool]] = None, ) -> ExecutionResult: """Execute a GraphQL operation asynchronously. This is the primary entry point function for fulfilling GraphQL operations by parsing, validating, and executing a GraphQL document along side a GraphQL schema. More sophisticated GraphQL servers, such as those which persist queries, may wish to separate the validation and execution phases to a static time tooling step, and a server runtime step. Accepts the following arguments: :arg schema: The GraphQL type system to use when validating and executing a query. :arg source: A GraphQL language formatted string representing the requested operation. :arg root_value: The value provided as the first argument to resolver functions on the top level type (e.g. the query object type). :arg context_value: The context value is provided as an attribute of the second argument (the resolve info) to resolver functions. It is used to pass shared information useful at any point during query execution, for example the currently logged in user and connections to databases or other services. :arg variable_values: A mapping of variable name to runtime value to use for all variables defined in the request string. :arg operation_name: The name of the operation to use if request string contains multiple possible operations. Can be omitted if request string contains only one operation. :arg field_resolver: A resolver function to use when one is not provided by the schema. If not provided, the default field resolver is used (which looks for a value or method on the source value with the field's name). :arg type_resolver: A type resolver function to use when none is provided by the schema. If not provided, the default type resolver is used (which looks for a ``__typename`` field or alternatively calls the :meth:`~graphql.type.GraphQLObjectType.is_type_of` method). :arg middleware: The middleware to wrap the resolvers with :arg execution_context_class: The execution context class to use to build the context :arg is_awaitable: The predicate to be used for checking whether values are awaitable """ # Always return asynchronously for a consistent API. result = graphql_impl( schema, source, root_value, context_value, variable_values, operation_name, field_resolver, type_resolver, middleware, execution_context_class, is_awaitable, ) if isawaitable(result): return await result return result def assume_not_awaitable(_value: Any) -> bool: """Replacement for isawaitable if everything is assumed to be synchronous.""" return False def graphql_sync( schema: GraphQLSchema, source: Union[str, Source], root_value: Any = None, context_value: Any = None, variable_values: Optional[Dict[str, Any]] = None, operation_name: Optional[str] = None, field_resolver: Optional[GraphQLFieldResolver] = None, type_resolver: Optional[GraphQLTypeResolver] = None, middleware: Optional[Middleware] = None, execution_context_class: Optional[Type[ExecutionContext]] = None, check_sync: bool = False, ) -> ExecutionResult: """Execute a GraphQL operation synchronously. The graphql_sync function also fulfills GraphQL operations by parsing, validating, and executing a GraphQL document along side a GraphQL schema. However, it guarantees to complete synchronously (or throw an error) assuming that all field resolvers are also synchronous. Set check_sync to True to still run checks that no awaitable values are returned. """ is_awaitable = ( check_sync if callable(check_sync) else (None if check_sync else assume_not_awaitable) ) result = graphql_impl( schema, source, root_value, context_value, variable_values, operation_name, field_resolver, type_resolver, middleware, execution_context_class, is_awaitable, ) # Assert that the execution was synchronous. if isawaitable(result): ensure_future(result).cancel() raise RuntimeError("GraphQL execution failed to complete synchronously.") return result def graphql_impl( schema: GraphQLSchema, source: Union[str, Source], root_value: Any, context_value: Any, variable_values: Optional[Dict[str, Any]], operation_name: Optional[str], field_resolver: Optional[GraphQLFieldResolver], type_resolver: Optional[GraphQLTypeResolver], middleware: Optional[Middleware], execution_context_class: Optional[Type[ExecutionContext]], is_awaitable: Optional[Callable[[Any], bool]], ) -> AwaitableOrValue[ExecutionResult]: """Execute a query, return asynchronously only if necessary.""" # Validate Schema schema_validation_errors = validate_schema(schema) if schema_validation_errors: return ExecutionResult(data=None, errors=schema_validation_errors) # Parse try: document = parse(source) except GraphQLError as error: return ExecutionResult(data=None, errors=[error]) # Validate from .validation import validate validation_errors = validate(schema, document) if validation_errors: return ExecutionResult(data=None, errors=validation_errors) # Execute return execute( schema, document, root_value, context_value, variable_values, operation_name, field_resolver, type_resolver, None, middleware, execution_context_class, is_awaitable, ) graphql-core-3.2.6/src/graphql/language/000077500000000000000000000000001474546154300201335ustar00rootroot00000000000000graphql-core-3.2.6/src/graphql/language/__init__.py000066400000000000000000000112661474546154300222520ustar00rootroot00000000000000"""GraphQL Language The :mod:`graphql.language` package is responsible for parsing and operating on the GraphQL language. """ from .source import Source from .location import get_location, SourceLocation, FormattedSourceLocation from .print_location import print_location, print_source_location from .token_kind import TokenKind from .lexer import Lexer from .parser import parse, parse_type, parse_value, parse_const_value from .printer import print_ast from .visitor import ( visit, Visitor, ParallelVisitor, VisitorAction, VisitorKeyMap, BREAK, SKIP, REMOVE, IDLE, ) from .ast import ( Location, Token, Node, # Each kind of AST node NameNode, DocumentNode, DefinitionNode, ExecutableDefinitionNode, OperationDefinitionNode, OperationType, VariableDefinitionNode, VariableNode, SelectionSetNode, SelectionNode, FieldNode, ArgumentNode, ConstArgumentNode, FragmentSpreadNode, InlineFragmentNode, FragmentDefinitionNode, ValueNode, ConstValueNode, IntValueNode, FloatValueNode, StringValueNode, BooleanValueNode, NullValueNode, EnumValueNode, ListValueNode, ConstListValueNode, ObjectValueNode, ConstObjectValueNode, ObjectFieldNode, ConstObjectFieldNode, DirectiveNode, ConstDirectiveNode, TypeNode, NamedTypeNode, ListTypeNode, NonNullTypeNode, TypeSystemDefinitionNode, SchemaDefinitionNode, OperationTypeDefinitionNode, TypeDefinitionNode, ScalarTypeDefinitionNode, ObjectTypeDefinitionNode, FieldDefinitionNode, InputValueDefinitionNode, InterfaceTypeDefinitionNode, UnionTypeDefinitionNode, EnumTypeDefinitionNode, EnumValueDefinitionNode, InputObjectTypeDefinitionNode, DirectiveDefinitionNode, TypeSystemExtensionNode, SchemaExtensionNode, TypeExtensionNode, ScalarTypeExtensionNode, ObjectTypeExtensionNode, InterfaceTypeExtensionNode, UnionTypeExtensionNode, EnumTypeExtensionNode, InputObjectTypeExtensionNode, ) from .predicates import ( is_definition_node, is_executable_definition_node, is_selection_node, is_value_node, is_const_value_node, is_type_node, is_type_system_definition_node, is_type_definition_node, is_type_system_extension_node, is_type_extension_node, ) from .directive_locations import DirectiveLocation __all__ = [ "get_location", "SourceLocation", "FormattedSourceLocation", "print_location", "print_source_location", "TokenKind", "Lexer", "parse", "parse_value", "parse_const_value", "parse_type", "print_ast", "Source", "visit", "Visitor", "ParallelVisitor", "VisitorAction", "VisitorKeyMap", "BREAK", "SKIP", "REMOVE", "IDLE", "Location", "Token", "DirectiveLocation", "Node", "NameNode", "DocumentNode", "DefinitionNode", "ExecutableDefinitionNode", "OperationDefinitionNode", "OperationType", "VariableDefinitionNode", "VariableNode", "SelectionSetNode", "SelectionNode", "FieldNode", "ArgumentNode", "ConstArgumentNode", "FragmentSpreadNode", "InlineFragmentNode", "FragmentDefinitionNode", "ValueNode", "ConstValueNode", "IntValueNode", "FloatValueNode", "StringValueNode", "BooleanValueNode", "NullValueNode", "EnumValueNode", "ListValueNode", "ConstListValueNode", "ObjectValueNode", "ConstObjectValueNode", "ObjectFieldNode", "ConstObjectFieldNode", "DirectiveNode", "ConstDirectiveNode", "TypeNode", "NamedTypeNode", "ListTypeNode", "NonNullTypeNode", "TypeSystemDefinitionNode", "SchemaDefinitionNode", "OperationTypeDefinitionNode", "TypeDefinitionNode", "ScalarTypeDefinitionNode", "ObjectTypeDefinitionNode", "FieldDefinitionNode", "InputValueDefinitionNode", "InterfaceTypeDefinitionNode", "UnionTypeDefinitionNode", "EnumTypeDefinitionNode", "EnumValueDefinitionNode", "InputObjectTypeDefinitionNode", "DirectiveDefinitionNode", "TypeSystemExtensionNode", "SchemaExtensionNode", "TypeExtensionNode", "ScalarTypeExtensionNode", "ObjectTypeExtensionNode", "InterfaceTypeExtensionNode", "UnionTypeExtensionNode", "EnumTypeExtensionNode", "InputObjectTypeExtensionNode", "is_definition_node", "is_executable_definition_node", "is_selection_node", "is_value_node", "is_const_value_node", "is_type_node", "is_type_system_definition_node", "is_type_definition_node", "is_type_system_extension_node", "is_type_extension_node", ] graphql-core-3.2.6/src/graphql/language/ast.py000066400000000000000000000505071474546154300213030ustar00rootroot00000000000000from copy import copy, deepcopy from enum import Enum from typing import Any, Dict, List, Tuple, Optional, Union from .source import Source from .token_kind import TokenKind from ..pyutils import camel_to_snake __all__ = [ "Location", "Token", "Node", "NameNode", "DocumentNode", "DefinitionNode", "ExecutableDefinitionNode", "OperationDefinitionNode", "VariableDefinitionNode", "SelectionSetNode", "SelectionNode", "FieldNode", "ArgumentNode", "ConstArgumentNode", "FragmentSpreadNode", "InlineFragmentNode", "FragmentDefinitionNode", "ValueNode", "ConstValueNode", "VariableNode", "IntValueNode", "FloatValueNode", "StringValueNode", "BooleanValueNode", "NullValueNode", "EnumValueNode", "ListValueNode", "ConstListValueNode", "ObjectValueNode", "ConstObjectValueNode", "ObjectFieldNode", "ConstObjectFieldNode", "DirectiveNode", "ConstDirectiveNode", "TypeNode", "NamedTypeNode", "ListTypeNode", "NonNullTypeNode", "TypeSystemDefinitionNode", "SchemaDefinitionNode", "OperationType", "OperationTypeDefinitionNode", "TypeDefinitionNode", "ScalarTypeDefinitionNode", "ObjectTypeDefinitionNode", "FieldDefinitionNode", "InputValueDefinitionNode", "InterfaceTypeDefinitionNode", "UnionTypeDefinitionNode", "EnumTypeDefinitionNode", "EnumValueDefinitionNode", "InputObjectTypeDefinitionNode", "DirectiveDefinitionNode", "SchemaExtensionNode", "TypeExtensionNode", "TypeSystemExtensionNode", "ScalarTypeExtensionNode", "ObjectTypeExtensionNode", "InterfaceTypeExtensionNode", "UnionTypeExtensionNode", "EnumTypeExtensionNode", "InputObjectTypeExtensionNode", "QUERY_DOCUMENT_KEYS", ] class Token: """AST Token Represents a range of characters represented by a lexical token within a Source. """ __slots__ = "kind", "start", "end", "line", "column", "prev", "next", "value" kind: TokenKind # the kind of token start: int # the character offset at which this Node begins end: int # the character offset at which this Node ends line: int # the 1-indexed line number on which this Token appears column: int # the 1-indexed column number at which this Token begins # for non-punctuation tokens, represents the interpreted value of the token: value: Optional[str] # Tokens exist as nodes in a double-linked-list amongst all tokens including # ignored tokens. is always the first node and the last. prev: Optional["Token"] next: Optional["Token"] def __init__( self, kind: TokenKind, start: int, end: int, line: int, column: int, value: Optional[str] = None, ) -> None: self.kind = kind self.start, self.end = start, end self.line, self.column = line, column self.value = value self.prev = self.next = None def __str__(self) -> str: return self.desc def __repr__(self) -> str: """Print a simplified form when appearing in repr() or inspect().""" return f"" def __inspect__(self) -> str: return repr(self) def __eq__(self, other: Any) -> bool: if isinstance(other, Token): return ( self.kind == other.kind and self.start == other.start and self.end == other.end and self.line == other.line and self.column == other.column and self.value == other.value ) elif isinstance(other, str): return other == self.desc return False def __hash__(self) -> int: return hash( (self.kind, self.start, self.end, self.line, self.column, self.value) ) def __copy__(self) -> "Token": """Create a shallow copy of the token""" token = self.__class__( self.kind, self.start, self.end, self.line, self.column, self.value, ) token.prev = self.prev return token def __deepcopy__(self, memo: Dict) -> "Token": """Allow only shallow copies to avoid recursion.""" return copy(self) def __getstate__(self) -> Dict[str, Any]: """Remove the links when pickling. Keeping the links would make pickling a schema too expensive. """ return { key: getattr(self, key) for key in self.__slots__ if key not in {"prev", "next"} } def __setstate__(self, state: Dict[str, Any]) -> None: """Reset the links when un-pickling.""" for key, value in state.items(): setattr(self, key, value) self.prev = self.next = None @property def desc(self) -> str: """A helper property to describe a token as a string for debugging""" kind, value = self.kind.value, self.value return f"{kind} {value!r}" if value else kind class Location: """AST Location Contains a range of UTF-8 character offsets and token references that identify the region of the source from which the AST derived. """ __slots__ = ( "start", "end", "start_token", "end_token", "source", ) start: int # character offset at which this Node begins end: int # character offset at which this Node ends start_token: Token # Token at which this Node begins end_token: Token # Token at which this Node ends. source: Source # Source document the AST represents def __init__(self, start_token: Token, end_token: Token, source: Source) -> None: self.start = start_token.start self.end = end_token.end self.start_token = start_token self.end_token = end_token self.source = source def __str__(self) -> str: return f"{self.start}:{self.end}" def __repr__(self) -> str: """Print a simplified form when appearing in repr() or inspect().""" return f"" def __inspect__(self) -> str: return repr(self) def __eq__(self, other: Any) -> bool: if isinstance(other, Location): return self.start == other.start and self.end == other.end elif isinstance(other, (list, tuple)) and len(other) == 2: return self.start == other[0] and self.end == other[1] return False def __ne__(self, other: Any) -> bool: return not self == other def __hash__(self) -> int: return hash((self.start, self.end)) class OperationType(Enum): QUERY = "query" MUTATION = "mutation" SUBSCRIPTION = "subscription" # Default map from node kinds to their node attributes (internal) QUERY_DOCUMENT_KEYS: Dict[str, Tuple[str, ...]] = { "name": (), "document": ("definitions",), "operation_definition": ( "name", "variable_definitions", "directives", "selection_set", ), "variable_definition": ("variable", "type", "default_value", "directives"), "variable": ("name",), "selection_set": ("selections",), "field": ("alias", "name", "arguments", "directives", "selection_set"), "argument": ("name", "value"), "fragment_spread": ("name", "directives"), "inline_fragment": ("type_condition", "directives", "selection_set"), "fragment_definition": ( # Note: fragment variable definitions are deprecated and will be removed in v3.3 "name", "variable_definitions", "type_condition", "directives", "selection_set", ), "list_value": ("values",), "object_value": ("fields",), "object_field": ("name", "value"), "directive": ("name", "arguments"), "named_type": ("name",), "list_type": ("type",), "non_null_type": ("type",), "schema_definition": ("description", "directives", "operation_types"), "operation_type_definition": ("type",), "scalar_type_definition": ("description", "name", "directives"), "object_type_definition": ( "description", "name", "interfaces", "directives", "fields", ), "field_definition": ("description", "name", "arguments", "type", "directives"), "input_value_definition": ( "description", "name", "type", "default_value", "directives", ), "interface_type_definition": ( "description", "name", "interfaces", "directives", "fields", ), "union_type_definition": ("description", "name", "directives", "types"), "enum_type_definition": ("description", "name", "directives", "values"), "enum_value_definition": ("description", "name", "directives"), "input_object_type_definition": ("description", "name", "directives", "fields"), "directive_definition": ("description", "name", "arguments", "locations"), "schema_extension": ("directives", "operation_types"), "scalar_type_extension": ("name", "directives"), "object_type_extension": ("name", "interfaces", "directives", "fields"), "interface_type_extension": ("name", "interfaces", "directives", "fields"), "union_type_extension": ("name", "directives", "types"), "enum_type_extension": ("name", "directives", "values"), "input_object_type_extension": ("name", "directives", "fields"), } # Base AST Node class Node: """AST nodes""" # allow custom attributes and weak references (not used internally) __slots__ = "__dict__", "__weakref__", "loc", "_hash" loc: Optional[Location] kind: str = "ast" # the kind of the node as a snake_case string keys: Tuple[str, ...] = ("loc",) # the names of the attributes of this node def __init__(self, **kwargs: Any) -> None: """Initialize the node with the given keyword arguments.""" for key in self.keys: value = kwargs.get(key) if isinstance(value, list): value = tuple(value) setattr(self, key, value) def __repr__(self) -> str: """Get a simple representation of the node.""" name, loc = self.__class__.__name__, getattr(self, "loc", None) return f"{name} at {loc}" if loc else name def __eq__(self, other: Any) -> bool: """Test whether two nodes are equal (recursively).""" return ( isinstance(other, Node) and self.__class__ == other.__class__ and all(getattr(self, key) == getattr(other, key) for key in self.keys) ) def __hash__(self) -> int: """Get a cached hash value for the node.""" # Caching the hash values improves the performance of AST validators hashed = getattr(self, "_hash", None) if hashed is None: self._hash = id(self) # avoid recursion hashed = hash(tuple(getattr(self, key) for key in self.keys)) self._hash = hashed return hashed def __setattr__(self, key: str, value: Any) -> None: # reset cashed hash value if attributes are changed if hasattr(self, "_hash") and key in self.keys: del self._hash super().__setattr__(key, value) def __copy__(self) -> "Node": """Create a shallow copy of the node.""" return self.__class__(**{key: getattr(self, key) for key in self.keys}) def __deepcopy__(self, memo: Dict) -> "Node": """Create a deep copy of the node""" # noinspection PyArgumentList return self.__class__( **{key: deepcopy(getattr(self, key), memo) for key in self.keys} ) def __init_subclass__(cls) -> None: super().__init_subclass__() name = cls.__name__ try: name = name.removeprefix("Const").removesuffix("Node") except AttributeError: # pragma: no cover (Python < 3.9) if name.startswith("Const"): name = name[5:] if name.endswith("Node"): name = name[:-4] cls.kind = camel_to_snake(name) keys: List[str] = [] for base in cls.__bases__: # noinspection PyUnresolvedReferences keys.extend(base.keys) # type: ignore keys.extend(cls.__slots__) cls.keys = tuple(keys) def to_dict(self, locations: bool = False) -> Dict: from ..utilities import ast_to_dict return ast_to_dict(self, locations) # Name class NameNode(Node): __slots__ = ("value",) value: str # Document class DocumentNode(Node): __slots__ = ("definitions",) definitions: Tuple["DefinitionNode", ...] class DefinitionNode(Node): __slots__ = () class ExecutableDefinitionNode(DefinitionNode): __slots__ = "name", "directives", "variable_definitions", "selection_set" name: Optional[NameNode] directives: Tuple["DirectiveNode", ...] variable_definitions: Tuple["VariableDefinitionNode", ...] selection_set: "SelectionSetNode" class OperationDefinitionNode(ExecutableDefinitionNode): __slots__ = ("operation",) operation: OperationType class VariableDefinitionNode(Node): __slots__ = "variable", "type", "default_value", "directives" variable: "VariableNode" type: "TypeNode" default_value: Optional["ConstValueNode"] directives: Tuple["ConstDirectiveNode", ...] class SelectionSetNode(Node): __slots__ = ("selections",) selections: Tuple["SelectionNode", ...] class SelectionNode(Node): __slots__ = ("directives",) directives: Tuple["DirectiveNode", ...] class FieldNode(SelectionNode): __slots__ = "alias", "name", "arguments", "selection_set" alias: Optional[NameNode] name: NameNode arguments: Tuple["ArgumentNode", ...] selection_set: Optional[SelectionSetNode] class ArgumentNode(Node): __slots__ = "name", "value" name: NameNode value: "ValueNode" class ConstArgumentNode(ArgumentNode): value: "ConstValueNode" # Fragments class FragmentSpreadNode(SelectionNode): __slots__ = ("name",) name: NameNode class InlineFragmentNode(SelectionNode): __slots__ = "type_condition", "selection_set" type_condition: "NamedTypeNode" selection_set: SelectionSetNode class FragmentDefinitionNode(ExecutableDefinitionNode): __slots__ = ("type_condition",) name: NameNode type_condition: "NamedTypeNode" # Values class ValueNode(Node): __slots__ = () class VariableNode(ValueNode): __slots__ = ("name",) name: NameNode class IntValueNode(ValueNode): __slots__ = ("value",) value: str class FloatValueNode(ValueNode): __slots__ = ("value",) value: str class StringValueNode(ValueNode): __slots__ = "value", "block" value: str block: Optional[bool] class BooleanValueNode(ValueNode): __slots__ = ("value",) value: bool class NullValueNode(ValueNode): __slots__ = () class EnumValueNode(ValueNode): __slots__ = ("value",) value: str class ListValueNode(ValueNode): __slots__ = ("values",) values: Tuple[ValueNode, ...] class ConstListValueNode(ListValueNode): values: Tuple["ConstValueNode", ...] class ObjectValueNode(ValueNode): __slots__ = ("fields",) fields: Tuple["ObjectFieldNode", ...] class ConstObjectValueNode(ObjectValueNode): fields: Tuple["ConstObjectFieldNode", ...] class ObjectFieldNode(Node): __slots__ = "name", "value" name: NameNode value: ValueNode class ConstObjectFieldNode(ObjectFieldNode): value: "ConstValueNode" ConstValueNode = Union[ IntValueNode, FloatValueNode, StringValueNode, BooleanValueNode, NullValueNode, EnumValueNode, ConstListValueNode, ConstObjectValueNode, ] # Directives class DirectiveNode(Node): __slots__ = "name", "arguments" name: NameNode arguments: Tuple[ArgumentNode, ...] class ConstDirectiveNode(DirectiveNode): arguments: Tuple[ConstArgumentNode, ...] # Type Reference class TypeNode(Node): __slots__ = () class NamedTypeNode(TypeNode): __slots__ = ("name",) name: NameNode class ListTypeNode(TypeNode): __slots__ = ("type",) type: TypeNode class NonNullTypeNode(TypeNode): __slots__ = ("type",) type: Union[NamedTypeNode, ListTypeNode] # Type System Definition class TypeSystemDefinitionNode(DefinitionNode): __slots__ = () class SchemaDefinitionNode(TypeSystemDefinitionNode): __slots__ = "description", "directives", "operation_types" description: Optional[StringValueNode] directives: Tuple[ConstDirectiveNode, ...] operation_types: Tuple["OperationTypeDefinitionNode", ...] class OperationTypeDefinitionNode(Node): __slots__ = "operation", "type" operation: OperationType type: NamedTypeNode # Type Definition class TypeDefinitionNode(TypeSystemDefinitionNode): __slots__ = "description", "name", "directives" description: Optional[StringValueNode] name: NameNode directives: Tuple[DirectiveNode, ...] class ScalarTypeDefinitionNode(TypeDefinitionNode): __slots__ = () directives: Tuple[ConstDirectiveNode, ...] class ObjectTypeDefinitionNode(TypeDefinitionNode): __slots__ = "interfaces", "fields" interfaces: Tuple[NamedTypeNode, ...] directives: Tuple[ConstDirectiveNode, ...] fields: Tuple["FieldDefinitionNode", ...] class FieldDefinitionNode(DefinitionNode): __slots__ = "description", "name", "directives", "arguments", "type" description: Optional[StringValueNode] name: NameNode directives: Tuple[ConstDirectiveNode, ...] arguments: Tuple["InputValueDefinitionNode", ...] type: TypeNode class InputValueDefinitionNode(DefinitionNode): __slots__ = "description", "name", "directives", "type", "default_value" description: Optional[StringValueNode] name: NameNode directives: Tuple[ConstDirectiveNode, ...] type: TypeNode default_value: Optional[ConstValueNode] class InterfaceTypeDefinitionNode(TypeDefinitionNode): __slots__ = "fields", "interfaces" fields: Tuple["FieldDefinitionNode", ...] directives: Tuple[ConstDirectiveNode, ...] interfaces: Tuple[NamedTypeNode, ...] class UnionTypeDefinitionNode(TypeDefinitionNode): __slots__ = ("types",) directives: Tuple[ConstDirectiveNode, ...] types: Tuple[NamedTypeNode, ...] class EnumTypeDefinitionNode(TypeDefinitionNode): __slots__ = ("values",) directives: Tuple[ConstDirectiveNode, ...] values: Tuple["EnumValueDefinitionNode", ...] class EnumValueDefinitionNode(DefinitionNode): __slots__ = "description", "name", "directives" description: Optional[StringValueNode] name: NameNode directives: Tuple[ConstDirectiveNode, ...] class InputObjectTypeDefinitionNode(TypeDefinitionNode): __slots__ = ("fields",) directives: Tuple[ConstDirectiveNode, ...] fields: Tuple[InputValueDefinitionNode, ...] # Directive Definitions class DirectiveDefinitionNode(TypeSystemDefinitionNode): __slots__ = "description", "name", "arguments", "repeatable", "locations" description: Optional[StringValueNode] name: NameNode arguments: Tuple[InputValueDefinitionNode, ...] repeatable: bool locations: Tuple[NameNode, ...] # Type System Extensions class SchemaExtensionNode(Node): __slots__ = "directives", "operation_types" directives: Tuple[ConstDirectiveNode, ...] operation_types: Tuple[OperationTypeDefinitionNode, ...] # Type Extensions class TypeExtensionNode(TypeSystemDefinitionNode): __slots__ = "name", "directives" name: NameNode directives: Tuple[ConstDirectiveNode, ...] TypeSystemExtensionNode = Union[SchemaExtensionNode, TypeExtensionNode] class ScalarTypeExtensionNode(TypeExtensionNode): __slots__ = () class ObjectTypeExtensionNode(TypeExtensionNode): __slots__ = "interfaces", "fields" interfaces: Tuple[NamedTypeNode, ...] fields: Tuple[FieldDefinitionNode, ...] class InterfaceTypeExtensionNode(TypeExtensionNode): __slots__ = "interfaces", "fields" interfaces: Tuple[NamedTypeNode, ...] fields: Tuple[FieldDefinitionNode, ...] class UnionTypeExtensionNode(TypeExtensionNode): __slots__ = ("types",) types: Tuple[NamedTypeNode, ...] class EnumTypeExtensionNode(TypeExtensionNode): __slots__ = ("values",) values: Tuple[EnumValueDefinitionNode, ...] class InputObjectTypeExtensionNode(TypeExtensionNode): __slots__ = ("fields",) fields: Tuple[InputValueDefinitionNode, ...] graphql-core-3.2.6/src/graphql/language/block_string.py000066400000000000000000000115241474546154300231700ustar00rootroot00000000000000from typing import Collection, List from sys import maxsize __all__ = [ "dedent_block_string_lines", "is_printable_as_block_string", "print_block_string", ] def dedent_block_string_lines(lines: Collection[str]) -> List[str]: """Produce the value of a block string from its parsed raw value. This function works similar to CoffeeScript's block string, Python's docstring trim or Ruby's strip_heredoc. It implements the GraphQL spec's BlockStringValue() static algorithm. Note that this is very similar to Python's inspect.cleandoc() function. The difference is that the latter also expands tabs to spaces and removes whitespace at the beginning of the first line. Python also has textwrap.dedent() which uses a completely different algorithm. For internal use only. """ common_indent = maxsize first_non_empty_line = None last_non_empty_line = -1 for i, line in enumerate(lines): indent = leading_white_space(line) if indent == len(line): continue # skip empty lines if first_non_empty_line is None: first_non_empty_line = i last_non_empty_line = i if i and indent < common_indent: common_indent = indent if first_non_empty_line is None: first_non_empty_line = 0 return [ # Remove common indentation from all lines but first. line[common_indent:] if i else line for i, line in enumerate(lines) ][ # Remove leading and trailing blank lines. first_non_empty_line : last_non_empty_line + 1 ] def leading_white_space(s: str) -> int: i = 0 for c in s: if c not in " \t": return i i += 1 return i def is_printable_as_block_string(value: str) -> bool: """Check whether the given string is printable as a block string. For internal use only. """ if not isinstance(value, str): value = str(value) # resolve lazy string proxy object if not value: return True # emtpy string is printable is_empty_line = True has_indent = False has_common_indent = True seen_non_empty_line = False for c in value: if c == "\n": if is_empty_line and not seen_non_empty_line: return False # has leading new line seen_non_empty_line = True is_empty_line = True has_indent = False elif c in " \t": has_indent = has_indent or is_empty_line elif c <= "\x0f": return False else: has_common_indent = has_common_indent and has_indent is_empty_line = False if is_empty_line: return False # has trailing empty lines if has_common_indent and seen_non_empty_line: return False # has internal indent return True def print_block_string(value: str, minimize: bool = False) -> str: """Print a block string in the indented block form. Prints a block string in the indented block form by adding a leading and trailing blank line. However, if a block string starts with whitespace and is a single-line, adding a leading blank line would strip that whitespace. For internal use only. """ if not isinstance(value, str): value = str(value) # resolve lazy string proxy object escaped_value = value.replace('"""', '\\"""') # Expand a block string's raw value into independent lines. lines = escaped_value.splitlines() or [""] num_lines = len(lines) is_single_line = num_lines == 1 # If common indentation is found, # we can fix some of those cases by adding a leading new line. force_leading_new_line = num_lines > 1 and all( not line or line[0] in " \t" for line in lines[1:] ) # Trailing triple quotes just looks confusing but doesn't force trailing new line. has_trailing_triple_quotes = escaped_value.endswith('\\"""') # Trailing quote (single or double) or slash forces trailing new line has_trailing_quote = value.endswith('"') and not has_trailing_triple_quotes has_trailing_slash = value.endswith("\\") force_trailing_new_line = has_trailing_quote or has_trailing_slash print_as_multiple_lines = not minimize and ( # add leading and trailing new lines only if it improves readability not is_single_line or len(value) > 70 or force_trailing_new_line or force_leading_new_line or has_trailing_triple_quotes ) # Format a multi-line block quote to account for leading space. skip_leading_new_line = is_single_line and value and value[0] in " \t" before = ( "\n" if print_as_multiple_lines and not skip_leading_new_line or force_leading_new_line else "" ) after = "\n" if print_as_multiple_lines or force_trailing_new_line else "" return f'"""{before}{escaped_value}{after}"""' graphql-core-3.2.6/src/graphql/language/character_classes.py000066400000000000000000000036741474546154300241700ustar00rootroot00000000000000__all__ = ["is_digit", "is_letter", "is_name_start", "is_name_continue"] try: "string".isascii() except AttributeError: # Python < 3.7 def is_digit(char: str) -> bool: """Check whether char is a digit For internal use by the lexer only. """ return "0" <= char <= "9" def is_letter(char: str) -> bool: """Check whether char is a plain ASCII letter For internal use by the lexer only. """ return "a" <= char <= "z" or "A" <= char <= "Z" def is_name_start(char: str) -> bool: """Check whether char is allowed at the beginning of a GraphQL name For internal use by the lexer only. """ return "a" <= char <= "z" or "A" <= char <= "Z" or char == "_" def is_name_continue(char: str) -> bool: """Check whether char is allowed in the continuation of a GraphQL name For internal use by the lexer only. """ return ( "a" <= char <= "z" or "A" <= char <= "Z" or "0" <= char <= "9" or char == "_" ) else: def is_digit(char: str) -> bool: """Check whether char is a digit For internal use by the lexer only. """ return char.isascii() and char.isdigit() def is_letter(char: str) -> bool: """Check whether char is a plain ASCII letter For internal use by the lexer only. """ return char.isascii() and char.isalpha() def is_name_start(char: str) -> bool: """Check whether char is allowed at the beginning of a GraphQL name For internal use by the lexer only. """ return char.isascii() and (char.isalpha() or char == "_") def is_name_continue(char: str) -> bool: """Check whether char is allowed in the continuation of a GraphQL name For internal use by the lexer only. """ return char.isascii() and (char.isalnum() or char == "_") graphql-core-3.2.6/src/graphql/language/directive_locations.py000066400000000000000000000014761474546154300245460ustar00rootroot00000000000000from enum import Enum __all__ = ["DirectiveLocation"] class DirectiveLocation(Enum): """The enum type representing the directive location values.""" # Request Definitions QUERY = "query" MUTATION = "mutation" SUBSCRIPTION = "subscription" FIELD = "field" FRAGMENT_DEFINITION = "fragment definition" FRAGMENT_SPREAD = "fragment spread" VARIABLE_DEFINITION = "variable definition" INLINE_FRAGMENT = "inline fragment" # Type System Definitions SCHEMA = "schema" SCALAR = "scalar" OBJECT = "object" FIELD_DEFINITION = "field definition" ARGUMENT_DEFINITION = "argument definition" INTERFACE = "interface" UNION = "union" ENUM = "enum" ENUM_VALUE = "enum value" INPUT_OBJECT = "input object" INPUT_FIELD_DEFINITION = "input field definition" graphql-core-3.2.6/src/graphql/language/lexer.py000066400000000000000000000456631474546154300216420ustar00rootroot00000000000000from typing import List, NamedTuple, Optional from ..error import GraphQLSyntaxError from .ast import Token from .block_string import dedent_block_string_lines from .character_classes import is_digit, is_name_start, is_name_continue from .source import Source from .token_kind import TokenKind __all__ = ["Lexer", "is_punctuator_token_kind"] class EscapeSequence(NamedTuple): """The string value and lexed size of an escape sequence.""" value: str size: int class Lexer: """GraphQL Lexer A Lexer is a stateful stream generator in that every time it is advanced, it returns the next token in the Source. Assuming the source lexes, the final Token emitted by the lexer will be of kind EOF, after which the lexer will repeatedly return the same EOF token whenever called. """ def __init__(self, source: Source): """Given a Source object, initialize a Lexer for that source.""" self.source = source self.token = self.last_token = Token(TokenKind.SOF, 0, 0, 0, 0) self.line, self.line_start = 1, 0 def advance(self) -> Token: """Advance the token stream to the next non-ignored token.""" self.last_token = self.token token = self.token = self.lookahead() return token def lookahead(self) -> Token: """Look ahead and return the next non-ignored token, but do not change state.""" token = self.token if token.kind != TokenKind.EOF: while True: if token.next: token = token.next else: # Read the next token and form a link in the token linked-list. next_token = self.read_next_token(token.end) token.next = next_token next_token.prev = token token = next_token if token.kind != TokenKind.COMMENT: break return token def print_code_point_at(self, location: int) -> str: """Print the code point at the given location. Prints the code point (or end of file reference) at a given location in a source for use in error messages. Printable ASCII is printed quoted, while other points are printed in Unicode code point form (ie. U+1234). """ body = self.source.body if location >= len(body): return TokenKind.EOF.value char = body[location] # Printable ASCII if "\x20" <= char <= "\x7E": return "'\"'" if char == '"' else f"'{char}'" # Unicode code point point = ord( body[location : location + 2] .encode("utf-16", "surrogatepass") .decode("utf-16") if is_supplementary_code_point(body, location) else char ) return f"U+{point:04X}" def create_token( self, kind: TokenKind, start: int, end: int, value: Optional[str] = None ) -> Token: """Create a token with line and column location information.""" line = self.line col = 1 + start - self.line_start return Token(kind, start, end, line, col, value) def read_next_token(self, start: int) -> Token: """Get the next token from the source starting at the given position. This skips over whitespace until it finds the next lexable token, then lexes punctuators immediately or calls the appropriate helper function for more complicated tokens. """ body = self.source.body body_length = len(body) position = start while position < body_length: char = body[position] # SourceCharacter if char in " \t,\ufeff": position += 1 continue elif char == "\n": position += 1 self.line += 1 self.line_start = position continue elif char == "\r": if body[position + 1 : position + 2] == "\n": position += 2 else: position += 1 self.line += 1 self.line_start = position continue if char == "#": return self.read_comment(position) if char == '"': if body[position + 1 : position + 3] == '""': return self.read_block_string(position) return self.read_string(position) kind = _KIND_FOR_PUNCT.get(char) if kind: return self.create_token(kind, position, position + 1) if is_digit(char) or char == "-": return self.read_number(position, char) if is_name_start(char): return self.read_name(position) if char == ".": if body[position + 1 : position + 3] == "..": return self.create_token(TokenKind.SPREAD, position, position + 3) message = ( "Unexpected single quote character (')," ' did you mean to use a double quote (")?' if char == "'" else ( f"Unexpected character: {self.print_code_point_at(position)}." if is_unicode_scalar_value(char) or is_supplementary_code_point(body, position) else f"Invalid character: {self.print_code_point_at(position)}." ) ) raise GraphQLSyntaxError(self.source, position, message) return self.create_token(TokenKind.EOF, body_length, body_length) def read_comment(self, start: int) -> Token: """Read a comment token from the source file.""" body = self.source.body body_length = len(body) position = start + 1 while position < body_length: char = body[position] if char in "\r\n": break if is_unicode_scalar_value(char): position += 1 elif is_supplementary_code_point(body, position): position += 2 else: break # pragma: no cover return self.create_token( TokenKind.COMMENT, start, position, body[start + 1 : position], ) def read_number(self, start: int, first_char: str) -> Token: """Reads a number token from the source file. This can be either a FloatValue or an IntValue, depending on whether a FractionalPart or ExponentPart is encountered. """ body = self.source.body position = start char = first_char is_float = False if char == "-": position += 1 char = body[position : position + 1] if char == "0": position += 1 char = body[position : position + 1] if is_digit(char): raise GraphQLSyntaxError( self.source, position, "Invalid number, unexpected digit after 0:" f" {self.print_code_point_at(position)}.", ) else: position = self.read_digits(position, char) char = body[position : position + 1] if char == ".": is_float = True position += 1 char = body[position : position + 1] position = self.read_digits(position, char) char = body[position : position + 1] if char and char in "Ee": is_float = True position += 1 char = body[position : position + 1] if char and char in "+-": position += 1 char = body[position : position + 1] position = self.read_digits(position, char) char = body[position : position + 1] # Numbers cannot be followed by . or NameStart if char and (char == "." or is_name_start(char)): raise GraphQLSyntaxError( self.source, position, "Invalid number, expected digit but got:" f" {self.print_code_point_at(position)}.", ) return self.create_token( TokenKind.FLOAT if is_float else TokenKind.INT, start, position, body[start:position], ) def read_digits(self, start: int, first_char: str) -> int: """Return the new position in the source after reading one or more digits.""" if not is_digit(first_char): raise GraphQLSyntaxError( self.source, start, "Invalid number, expected digit but got:" f" {self.print_code_point_at(start)}.", ) body = self.source.body body_length = len(body) position = start + 1 while position < body_length and is_digit(body[position]): position += 1 return position def read_string(self, start: int) -> Token: """Read a single-quote string token from the source file.""" body = self.source.body body_length = len(body) position = start + 1 chunk_start = position value: List[str] = [] append = value.append while position < body_length: char = body[position] if char == '"': append(body[chunk_start:position]) return self.create_token( TokenKind.STRING, start, position + 1, "".join(value), ) if char == "\\": append(body[chunk_start:position]) escape = ( ( self.read_escaped_unicode_variable_width(position) if body[position + 2 : position + 3] == "{" else self.read_escaped_unicode_fixed_width(position) ) if body[position + 1 : position + 2] == "u" else self.read_escaped_character(position) ) append(escape.value) position += escape.size chunk_start = position continue if char in "\r\n": break if is_unicode_scalar_value(char): position += 1 elif is_supplementary_code_point(body, position): position += 2 else: raise GraphQLSyntaxError( self.source, position, "Invalid character within String:" f" {self.print_code_point_at(position)}.", ) raise GraphQLSyntaxError(self.source, position, "Unterminated string.") def read_escaped_unicode_variable_width(self, position: int) -> EscapeSequence: body = self.source.body point = 0 size = 3 max_size = min(12, len(body) - position) # Cannot be larger than 12 chars (\u{00000000}). while size < max_size: char = body[position + size] size += 1 if char == "}": # Must be at least 5 chars (\u{0}) and encode a Unicode scalar value. if size < 5 or not ( 0 <= point <= 0xD7FF or 0xE000 <= point <= 0x10FFFF ): break return EscapeSequence(chr(point), size) # Append this hex digit to the code point. point = (point << 4) | read_hex_digit(char) if point < 0: break raise GraphQLSyntaxError( self.source, position, f"Invalid Unicode escape sequence: '{body[position: position + size]}'.", ) def read_escaped_unicode_fixed_width(self, position: int) -> EscapeSequence: body = self.source.body code = read_16_bit_hex_code(body, position + 2) if 0 <= code <= 0xD7FF or 0xE000 <= code <= 0x10FFFF: return EscapeSequence(chr(code), 6) # GraphQL allows JSON-style surrogate pair escape sequences, but only when # a valid pair is formed. if 0xD800 <= code <= 0xDBFF: if body[position + 6 : position + 8] == "\\u": trailing_code = read_16_bit_hex_code(body, position + 8) if 0xDC00 <= trailing_code <= 0xDFFF: return EscapeSequence( (chr(code) + chr(trailing_code)) .encode("utf-16", "surrogatepass") .decode("utf-16"), 12, ) raise GraphQLSyntaxError( self.source, position, f"Invalid Unicode escape sequence: '{body[position: position + 6]}'.", ) def read_escaped_character(self, position: int) -> EscapeSequence: body = self.source.body value = _ESCAPED_CHARS.get(body[position + 1]) if value: return EscapeSequence(value, 2) raise GraphQLSyntaxError( self.source, position, f"Invalid character escape sequence: '{body[position: position + 2]}'.", ) def read_block_string(self, start: int) -> Token: """Read a block string token from the source file.""" body = self.source.body body_length = len(body) line_start = self.line_start position = start + 3 chunk_start = position current_line = "" block_lines = [] while position < body_length: char = body[position] if char == '"' and body[position + 1 : position + 3] == '""': current_line += body[chunk_start:position] block_lines.append(current_line) token = self.create_token( TokenKind.BLOCK_STRING, start, position + 3, # return a string of the lines joined with new lines "\n".join(dedent_block_string_lines(block_lines)), ) self.line += len(block_lines) - 1 self.line_start = line_start return token if char == "\\" and body[position + 1 : position + 4] == '"""': current_line += body[chunk_start:position] chunk_start = position + 1 # skip only slash position += 4 continue if char in "\r\n": current_line += body[chunk_start:position] block_lines.append(current_line) if char == "\r" and body[position + 1 : position + 2] == "\n": position += 2 else: position += 1 current_line = "" chunk_start = line_start = position continue if is_unicode_scalar_value(char): position += 1 elif is_supplementary_code_point(body, position): position += 2 else: raise GraphQLSyntaxError( self.source, position, "Invalid character within String:" f" {self.print_code_point_at(position)}.", ) raise GraphQLSyntaxError(self.source, position, "Unterminated string.") def read_name(self, start: int) -> Token: """Read an alphanumeric + underscore name from the source.""" body = self.source.body body_length = len(body) position = start + 1 while position < body_length: char = body[position] if not is_name_continue(char): break position += 1 return self.create_token(TokenKind.NAME, start, position, body[start:position]) _punctuator_token_kinds = frozenset( [ TokenKind.BANG, TokenKind.DOLLAR, TokenKind.AMP, TokenKind.PAREN_L, TokenKind.PAREN_R, TokenKind.SPREAD, TokenKind.COLON, TokenKind.EQUALS, TokenKind.AT, TokenKind.BRACKET_L, TokenKind.BRACKET_R, TokenKind.BRACE_L, TokenKind.PIPE, TokenKind.BRACE_R, ] ) def is_punctuator_token_kind(kind: TokenKind) -> bool: """Check whether the given token kind corresponds to a punctuator. For internal use only. """ return kind in _punctuator_token_kinds _KIND_FOR_PUNCT = { "!": TokenKind.BANG, "$": TokenKind.DOLLAR, "&": TokenKind.AMP, "(": TokenKind.PAREN_L, ")": TokenKind.PAREN_R, ":": TokenKind.COLON, "=": TokenKind.EQUALS, "@": TokenKind.AT, "[": TokenKind.BRACKET_L, "]": TokenKind.BRACKET_R, "{": TokenKind.BRACE_L, "}": TokenKind.BRACE_R, "|": TokenKind.PIPE, } _ESCAPED_CHARS = { '"': '"', "/": "/", "\\": "\\", "b": "\b", "f": "\f", "n": "\n", "r": "\r", "t": "\t", } def read_16_bit_hex_code(body: str, position: int) -> int: """Read a 16bit hexadecimal string and return its positive integer value (0-65535). Reads four hexadecimal characters and returns the positive integer that 16bit hexadecimal string represents. For example, "000f" will return 15, and "dead" will return 57005. Returns a negative number if any char was not a valid hexadecimal digit. """ # read_hex_digit() returns -1 on error. ORing a negative value with any other # value always produces a negative value. return ( read_hex_digit(body[position]) << 12 | read_hex_digit(body[position + 1]) << 8 | read_hex_digit(body[position + 2]) << 4 | read_hex_digit(body[position + 3]) ) def read_hex_digit(char: str) -> int: """Read a hexadecimal character and returns its positive integer value (0-15). '0' becomes 0, '9' becomes 9 'A' becomes 10, 'F' becomes 15 'a' becomes 10, 'f' becomes 15 Returns -1 if the provided character code was not a valid hexadecimal digit. """ if "0" <= char <= "9": return ord(char) - 48 elif "A" <= char <= "F": return ord(char) - 55 elif "a" <= char <= "f": return ord(char) - 87 return -1 def is_unicode_scalar_value(char: str) -> bool: """Check whether this is a Unicode scalar value. A Unicode scalar value is any Unicode code point except surrogate code points. In other words, the inclusive ranges of values 0x0000 to 0xD7FF and 0xE000 to 0x10FFFF. """ return "\x00" <= char <= "\ud7ff" or "\ue000" <= char <= "\U0010ffff" def is_supplementary_code_point(body: str, location: int) -> bool: """ Check whether the current location is a supplementary code point. The GraphQL specification defines source text as a sequence of unicode scalar values (which Unicode defines to exclude surrogate code points). """ try: return ( "\ud800" <= body[location] <= "\udbff" and "\udc00" <= body[location + 1] <= "\udfff" ) except IndexError: return False graphql-core-3.2.6/src/graphql/language/location.py000066400000000000000000000022561474546154300223220ustar00rootroot00000000000000from typing import Any, NamedTuple, TYPE_CHECKING try: from typing import TypedDict except ImportError: # Python < 3.8 from typing_extensions import TypedDict if TYPE_CHECKING: from .source import Source # noqa: F401 __all__ = ["get_location", "SourceLocation", "FormattedSourceLocation"] class FormattedSourceLocation(TypedDict): """Formatted source location""" line: int column: int class SourceLocation(NamedTuple): """Represents a location in a Source.""" line: int column: int @property def formatted(self) -> FormattedSourceLocation: return dict(line=self.line, column=self.column) def __eq__(self, other: Any) -> bool: if isinstance(other, dict): return self.formatted == other return tuple(self) == other def __ne__(self, other: Any) -> bool: return not self == other def get_location(source: "Source", position: int) -> SourceLocation: """Get the line and column for a character position in the source. Takes a Source and a UTF-8 character offset, and returns the corresponding line and column as a SourceLocation. """ return source.get_location(position) graphql-core-3.2.6/src/graphql/language/parser.py000066400000000000000000001270451474546154300220120ustar00rootroot00000000000000from functools import partial from typing import Callable, Dict, List, Optional, TypeVar, Union, cast from ..error import GraphQLError, GraphQLSyntaxError from .ast import ( ArgumentNode, BooleanValueNode, ConstArgumentNode, ConstDirectiveNode, ConstValueNode, DefinitionNode, DirectiveDefinitionNode, DirectiveNode, DocumentNode, EnumTypeDefinitionNode, EnumTypeExtensionNode, EnumValueDefinitionNode, EnumValueNode, FieldDefinitionNode, FieldNode, FloatValueNode, FragmentDefinitionNode, FragmentSpreadNode, InlineFragmentNode, InputObjectTypeDefinitionNode, InputObjectTypeExtensionNode, InputValueDefinitionNode, InterfaceTypeDefinitionNode, InterfaceTypeExtensionNode, IntValueNode, ListTypeNode, ListValueNode, Location, NamedTypeNode, NameNode, NonNullTypeNode, NullValueNode, ObjectFieldNode, ObjectTypeDefinitionNode, ObjectTypeExtensionNode, ObjectValueNode, OperationDefinitionNode, OperationType, OperationTypeDefinitionNode, ScalarTypeDefinitionNode, ScalarTypeExtensionNode, SchemaDefinitionNode, SchemaExtensionNode, SelectionNode, SelectionSetNode, StringValueNode, Token, TypeNode, TypeSystemExtensionNode, UnionTypeDefinitionNode, UnionTypeExtensionNode, ValueNode, VariableDefinitionNode, VariableNode, ) from .directive_locations import DirectiveLocation from .lexer import Lexer, is_punctuator_token_kind from .source import Source, is_source from .token_kind import TokenKind __all__ = ["parse", "parse_type", "parse_value", "parse_const_value"] T = TypeVar("T") SourceType = Union[Source, str] def parse( source: SourceType, no_location: bool = False, max_tokens: Optional[int] = None, allow_legacy_fragment_variables: bool = False, ) -> DocumentNode: """Given a GraphQL source, parse it into a Document. Throws GraphQLError if a syntax error is encountered. By default, the parser creates AST nodes that know the location in the source that they correspond to. Setting the ``no_location`` parameter to False disables that behavior for performance or testing. Parser CPU and memory usage is linear to the number of tokens in a document, however in extreme cases it becomes quadratic due to memory exhaustion. Parsing happens before validation, so even invalid queries can burn lots of CPU time and memory. To prevent this, you can set a maximum number of tokens allowed within a document using the ``max_tokens`` parameter. Legacy feature (will be removed in v3.3): If ``allow_legacy_fragment_variables`` is set to ``True``, the parser will understand and parse variable definitions contained in a fragment definition. They'll be represented in the :attr:`~graphql.language.FragmentDefinitionNode.variable_definitions` field of the :class:`~graphql.language.FragmentDefinitionNode`. The syntax is identical to normal, query-defined variables. For example:: fragment A($var: Boolean = false) on T { ... } """ parser = Parser( source, no_location=no_location, max_tokens=max_tokens, allow_legacy_fragment_variables=allow_legacy_fragment_variables, ) return parser.parse_document() def parse_value( source: SourceType, no_location: bool = False, max_tokens: Optional[int] = None, allow_legacy_fragment_variables: bool = False, ) -> ValueNode: """Parse the AST for a given string containing a GraphQL value. Throws GraphQLError if a syntax error is encountered. This is useful within tools that operate upon GraphQL Values directly and in isolation of complete GraphQL documents. Consider providing the results to the utility function: :func:`~graphql.utilities.value_from_ast`. """ parser = Parser( source, no_location=no_location, max_tokens=max_tokens, allow_legacy_fragment_variables=allow_legacy_fragment_variables, ) parser.expect_token(TokenKind.SOF) value = parser.parse_value_literal(False) parser.expect_token(TokenKind.EOF) return value def parse_const_value( source: SourceType, no_location: bool = False, max_tokens: Optional[int] = None, allow_legacy_fragment_variables: bool = False, ) -> ConstValueNode: """Parse the AST for a given string containing a GraphQL constant value. Similar to parse_value, but raises a arse error if it encounters a variable. The return type will be a constant value. """ parser = Parser( source, no_location=no_location, max_tokens=max_tokens, allow_legacy_fragment_variables=allow_legacy_fragment_variables, ) parser.expect_token(TokenKind.SOF) value = parser.parse_const_value_literal() parser.expect_token(TokenKind.EOF) return value def parse_type( source: SourceType, no_location: bool = False, max_tokens: Optional[int] = None, allow_legacy_fragment_variables: bool = False, ) -> TypeNode: """Parse the AST for a given string containing a GraphQL Type. Throws GraphQLError if a syntax error is encountered. This is useful within tools that operate upon GraphQL Types directly and in isolation of complete GraphQL documents. Consider providing the results to the utility function: :func:`~graphql.utilities.value_from_ast`. """ parser = Parser( source, no_location=no_location, max_tokens=max_tokens, allow_legacy_fragment_variables=allow_legacy_fragment_variables, ) parser.expect_token(TokenKind.SOF) type_ = parser.parse_type_reference() parser.expect_token(TokenKind.EOF) return type_ class Parser: """GraphQL AST parser. This class is exported only to assist people in implementing their own parsers without duplicating too much code and should be used only as last resort for cases such as experimental syntax or if certain features couldn't be contributed upstream. It's still part of the internal API and is versioned, so any changes to it are never considered breaking changes. If you still need to support multiple versions of the library, please use the `__version_info__` variable for version detection. """ _lexer: Lexer _no_location: bool _max_tokens: Optional[int] _allow_legacy_fragment_variables: bool _token_counter: int def __init__( self, source: SourceType, no_location: bool = False, max_tokens: Optional[int] = None, allow_legacy_fragment_variables: bool = False, ): source = ( cast(Source, source) if is_source(source) else Source(cast(str, source)) ) self._lexer = Lexer(source) self._no_location = no_location self._max_tokens = max_tokens self._allow_legacy_fragment_variables = allow_legacy_fragment_variables self._token_counter = 0 def parse_name(self) -> NameNode: """Convert a name lex token into a name parse node.""" token = self.expect_token(TokenKind.NAME) return NameNode(value=token.value, loc=self.loc(token)) # Implement the parsing rules in the Document section. def parse_document(self) -> DocumentNode: """Document: Definition+""" start = self._lexer.token return DocumentNode( definitions=self.many(TokenKind.SOF, self.parse_definition, TokenKind.EOF), loc=self.loc(start), ) _parse_type_system_definition_method_names: Dict[str, str] = { "schema": "schema_definition", "scalar": "scalar_type_definition", "type": "object_type_definition", "interface": "interface_type_definition", "union": "union_type_definition", "enum": "enum_type_definition", "input": "input_object_type_definition", "directive": "directive_definition", } _parse_other_definition_method_names: Dict[str, str] = { **dict.fromkeys(("query", "mutation", "subscription"), "operation_definition"), "fragment": "fragment_definition", "extend": "type_system_extension", } def parse_definition(self) -> DefinitionNode: """Definition: ExecutableDefinition or TypeSystemDefinition/Extension ExecutableDefinition: OperationDefinition or FragmentDefinition TypeSystemDefinition: SchemaDefinition, TypeDefinition or DirectiveDefinition TypeDefinition: ScalarTypeDefinition, ObjectTypeDefinition, InterfaceTypeDefinition, UnionTypeDefinition, EnumTypeDefinition or InputObjectTypeDefinition """ if self.peek(TokenKind.BRACE_L): return self.parse_operation_definition() # Many definitions begin with a description and require a lookahead. has_description = self.peek_description() keyword_token = ( self._lexer.lookahead() if has_description else self._lexer.token ) if keyword_token.kind is TokenKind.NAME: token_name = cast(str, keyword_token.value) method_name = self._parse_type_system_definition_method_names.get( token_name ) if method_name: return getattr(self, f"parse_{method_name}")() if has_description: raise GraphQLSyntaxError( self._lexer.source, self._lexer.token.start, "Unexpected description," " descriptions are supported only on type definitions.", ) method_name = self._parse_other_definition_method_names.get(token_name) if method_name: return getattr(self, f"parse_{method_name}")() raise self.unexpected(keyword_token) # Implement the parsing rules in the Operations section. def parse_operation_definition(self) -> OperationDefinitionNode: """OperationDefinition""" start = self._lexer.token if self.peek(TokenKind.BRACE_L): return OperationDefinitionNode( operation=OperationType.QUERY, name=None, variable_definitions=[], directives=[], selection_set=self.parse_selection_set(), loc=self.loc(start), ) operation = self.parse_operation_type() name = self.parse_name() if self.peek(TokenKind.NAME) else None return OperationDefinitionNode( operation=operation, name=name, variable_definitions=self.parse_variable_definitions(), directives=self.parse_directives(False), selection_set=self.parse_selection_set(), loc=self.loc(start), ) def parse_operation_type(self) -> OperationType: """OperationType: one of query mutation subscription""" operation_token = self.expect_token(TokenKind.NAME) try: return OperationType(operation_token.value) except ValueError: raise self.unexpected(operation_token) def parse_variable_definitions(self) -> List[VariableDefinitionNode]: """VariableDefinitions: (VariableDefinition+)""" return self.optional_many( TokenKind.PAREN_L, self.parse_variable_definition, TokenKind.PAREN_R ) def parse_variable_definition(self) -> VariableDefinitionNode: """VariableDefinition: Variable: Type DefaultValue? Directives[Const]?""" start = self._lexer.token return VariableDefinitionNode( variable=self.parse_variable(), type=self.expect_token(TokenKind.COLON) and self.parse_type_reference(), default_value=( self.parse_const_value_literal() if self.expect_optional_token(TokenKind.EQUALS) else None ), directives=self.parse_const_directives(), loc=self.loc(start), ) def parse_variable(self) -> VariableNode: """Variable: $Name""" start = self._lexer.token self.expect_token(TokenKind.DOLLAR) return VariableNode(name=self.parse_name(), loc=self.loc(start)) def parse_selection_set(self) -> SelectionSetNode: """SelectionSet: {Selection+}""" start = self._lexer.token return SelectionSetNode( selections=self.many( TokenKind.BRACE_L, self.parse_selection, TokenKind.BRACE_R ), loc=self.loc(start), ) def parse_selection(self) -> SelectionNode: """Selection: Field or FragmentSpread or InlineFragment""" return ( self.parse_fragment if self.peek(TokenKind.SPREAD) else self.parse_field )() def parse_field(self) -> FieldNode: """Field: Alias? Name Arguments? Directives? SelectionSet?""" start = self._lexer.token name_or_alias = self.parse_name() if self.expect_optional_token(TokenKind.COLON): alias: Optional[NameNode] = name_or_alias name = self.parse_name() else: alias = None name = name_or_alias return FieldNode( alias=alias, name=name, arguments=self.parse_arguments(False), directives=self.parse_directives(False), selection_set=( self.parse_selection_set() if self.peek(TokenKind.BRACE_L) else None ), loc=self.loc(start), ) def parse_arguments(self, is_const: bool) -> List[ArgumentNode]: """Arguments[Const]: (Argument[?Const]+)""" item = self.parse_const_argument if is_const else self.parse_argument return self.optional_many( TokenKind.PAREN_L, cast(Callable[[], ArgumentNode], item), TokenKind.PAREN_R ) def parse_argument(self, is_const: bool = False) -> ArgumentNode: """Argument[Const]: Name : Value[?Const]""" start = self._lexer.token name = self.parse_name() self.expect_token(TokenKind.COLON) return ArgumentNode( name=name, value=self.parse_value_literal(is_const), loc=self.loc(start) ) def parse_const_argument(self) -> ConstArgumentNode: """Argument[Const]: Name : Value[Const]""" return cast(ConstArgumentNode, self.parse_argument(True)) # Implement the parsing rules in the Fragments section. def parse_fragment(self) -> Union[FragmentSpreadNode, InlineFragmentNode]: """Corresponds to both FragmentSpread and InlineFragment in the spec. FragmentSpread: ... FragmentName Directives? InlineFragment: ... TypeCondition? Directives? SelectionSet """ start = self._lexer.token self.expect_token(TokenKind.SPREAD) has_type_condition = self.expect_optional_keyword("on") if not has_type_condition and self.peek(TokenKind.NAME): return FragmentSpreadNode( name=self.parse_fragment_name(), directives=self.parse_directives(False), loc=self.loc(start), ) return InlineFragmentNode( type_condition=self.parse_named_type() if has_type_condition else None, directives=self.parse_directives(False), selection_set=self.parse_selection_set(), loc=self.loc(start), ) def parse_fragment_definition(self) -> FragmentDefinitionNode: """FragmentDefinition""" start = self._lexer.token self.expect_keyword("fragment") # Legacy support for defining variables within fragments changes # the grammar of FragmentDefinition if self._allow_legacy_fragment_variables: return FragmentDefinitionNode( name=self.parse_fragment_name(), variable_definitions=self.parse_variable_definitions(), type_condition=self.parse_type_condition(), directives=self.parse_directives(False), selection_set=self.parse_selection_set(), loc=self.loc(start), ) return FragmentDefinitionNode( name=self.parse_fragment_name(), type_condition=self.parse_type_condition(), directives=self.parse_directives(False), selection_set=self.parse_selection_set(), loc=self.loc(start), ) def parse_fragment_name(self) -> NameNode: """FragmentName: Name but not ``on``""" if self._lexer.token.value == "on": raise self.unexpected() return self.parse_name() def parse_type_condition(self) -> NamedTypeNode: """TypeCondition: NamedType""" self.expect_keyword("on") return self.parse_named_type() # Implement the parsing rules in the Values section. _parse_value_literal_method_names: Dict[TokenKind, str] = { TokenKind.BRACKET_L: "list", TokenKind.BRACE_L: "object", TokenKind.INT: "int", TokenKind.FLOAT: "float", TokenKind.STRING: "string_literal", TokenKind.BLOCK_STRING: "string_literal", TokenKind.NAME: "named_values", TokenKind.DOLLAR: "variable_value", } def parse_value_literal(self, is_const: bool) -> ValueNode: method_name = self._parse_value_literal_method_names.get(self._lexer.token.kind) if method_name: # pragma: no cover return getattr(self, f"parse_{method_name}")(is_const) raise self.unexpected() # pragma: no cover def parse_string_literal(self, _is_const: bool = False) -> StringValueNode: token = self._lexer.token self.advance_lexer() return StringValueNode( value=token.value, block=token.kind == TokenKind.BLOCK_STRING, loc=self.loc(token), ) def parse_list(self, is_const: bool) -> ListValueNode: """ListValue[Const]""" start = self._lexer.token item = partial(self.parse_value_literal, is_const) # noinspection PyTypeChecker return ListValueNode( values=self.any(TokenKind.BRACKET_L, item, TokenKind.BRACKET_R), loc=self.loc(start), ) def parse_object_field(self, is_const: bool) -> ObjectFieldNode: start = self._lexer.token name = self.parse_name() self.expect_token(TokenKind.COLON) return ObjectFieldNode( name=name, value=self.parse_value_literal(is_const), loc=self.loc(start) ) def parse_object(self, is_const: bool) -> ObjectValueNode: """ObjectValue[Const]""" start = self._lexer.token item = partial(self.parse_object_field, is_const) return ObjectValueNode( fields=self.any(TokenKind.BRACE_L, item, TokenKind.BRACE_R), loc=self.loc(start), ) def parse_int(self, _is_const: bool = False) -> IntValueNode: token = self._lexer.token self.advance_lexer() return IntValueNode(value=token.value, loc=self.loc(token)) def parse_float(self, _is_const: bool = False) -> FloatValueNode: token = self._lexer.token self.advance_lexer() return FloatValueNode(value=token.value, loc=self.loc(token)) def parse_named_values(self, _is_const: bool = False) -> ValueNode: token = self._lexer.token value = token.value self.advance_lexer() if value == "true": return BooleanValueNode(value=True, loc=self.loc(token)) if value == "false": return BooleanValueNode(value=False, loc=self.loc(token)) if value == "null": return NullValueNode(loc=self.loc(token)) return EnumValueNode(value=value, loc=self.loc(token)) def parse_variable_value(self, is_const: bool) -> VariableNode: if is_const: variable_token = self.expect_token(TokenKind.DOLLAR) token = self._lexer.token if token.kind is TokenKind.NAME: var_name = token.value raise GraphQLSyntaxError( self._lexer.source, variable_token.start, f"Unexpected variable '${var_name}' in constant value.", ) raise self.unexpected(variable_token) return self.parse_variable() def parse_const_value_literal(self) -> ConstValueNode: return cast(ConstValueNode, self.parse_value_literal(True)) # Implement the parsing rules in the Directives section. def parse_directives(self, is_const: bool) -> List[DirectiveNode]: """Directives[Const]: Directive[?Const]+""" directives: List[DirectiveNode] = [] append = directives.append while self.peek(TokenKind.AT): append(self.parse_directive(is_const)) return directives def parse_const_directives(self) -> List[ConstDirectiveNode]: return cast(List[ConstDirectiveNode], self.parse_directives(True)) def parse_directive(self, is_const: bool) -> DirectiveNode: """Directive[Const]: @ Name Arguments[?Const]?""" start = self._lexer.token self.expect_token(TokenKind.AT) return DirectiveNode( name=self.parse_name(), arguments=self.parse_arguments(is_const), loc=self.loc(start), ) # Implement the parsing rules in the Types section. def parse_type_reference(self) -> TypeNode: """Type: NamedType or ListType or NonNullType""" start = self._lexer.token type_: TypeNode if self.expect_optional_token(TokenKind.BRACKET_L): inner_type = self.parse_type_reference() self.expect_token(TokenKind.BRACKET_R) type_ = ListTypeNode(type=inner_type, loc=self.loc(start)) else: type_ = self.parse_named_type() if self.expect_optional_token(TokenKind.BANG): return NonNullTypeNode(type=type_, loc=self.loc(start)) return type_ def parse_named_type(self) -> NamedTypeNode: """NamedType: Name""" start = self._lexer.token return NamedTypeNode(name=self.parse_name(), loc=self.loc(start)) # Implement the parsing rules in the Type Definition section. _parse_type_extension_method_names: Dict[str, str] = { "schema": "schema_extension", "scalar": "scalar_type_extension", "type": "object_type_extension", "interface": "interface_type_extension", "union": "union_type_extension", "enum": "enum_type_extension", "input": "input_object_type_extension", } def parse_type_system_extension(self) -> TypeSystemExtensionNode: """TypeSystemExtension""" keyword_token = self._lexer.lookahead() if keyword_token.kind == TokenKind.NAME: method_name = self._parse_type_extension_method_names.get( cast(str, keyword_token.value) ) if method_name: # pragma: no cover return getattr(self, f"parse_{method_name}")() raise self.unexpected(keyword_token) def peek_description(self) -> bool: return self.peek(TokenKind.STRING) or self.peek(TokenKind.BLOCK_STRING) def parse_description(self) -> Optional[StringValueNode]: """Description: StringValue""" if self.peek_description(): return self.parse_string_literal() return None def parse_schema_definition(self) -> SchemaDefinitionNode: """SchemaDefinition""" start = self._lexer.token description = self.parse_description() self.expect_keyword("schema") directives = self.parse_const_directives() operation_types = self.many( TokenKind.BRACE_L, self.parse_operation_type_definition, TokenKind.BRACE_R ) return SchemaDefinitionNode( description=description, directives=directives, operation_types=operation_types, loc=self.loc(start), ) def parse_operation_type_definition(self) -> OperationTypeDefinitionNode: """OperationTypeDefinition: OperationType : NamedType""" start = self._lexer.token operation = self.parse_operation_type() self.expect_token(TokenKind.COLON) type_ = self.parse_named_type() return OperationTypeDefinitionNode( operation=operation, type=type_, loc=self.loc(start) ) def parse_scalar_type_definition(self) -> ScalarTypeDefinitionNode: """ScalarTypeDefinition: Description? scalar Name Directives[Const]?""" start = self._lexer.token description = self.parse_description() self.expect_keyword("scalar") name = self.parse_name() directives = self.parse_const_directives() return ScalarTypeDefinitionNode( description=description, name=name, directives=directives, loc=self.loc(start), ) def parse_object_type_definition(self) -> ObjectTypeDefinitionNode: """ObjectTypeDefinition""" start = self._lexer.token description = self.parse_description() self.expect_keyword("type") name = self.parse_name() interfaces = self.parse_implements_interfaces() directives = self.parse_const_directives() fields = self.parse_fields_definition() return ObjectTypeDefinitionNode( description=description, name=name, interfaces=interfaces, directives=directives, fields=fields, loc=self.loc(start), ) def parse_implements_interfaces(self) -> List[NamedTypeNode]: """ImplementsInterfaces""" return ( self.delimited_many(TokenKind.AMP, self.parse_named_type) if self.expect_optional_keyword("implements") else [] ) def parse_fields_definition(self) -> List[FieldDefinitionNode]: """FieldsDefinition: {FieldDefinition+}""" return self.optional_many( TokenKind.BRACE_L, self.parse_field_definition, TokenKind.BRACE_R ) def parse_field_definition(self) -> FieldDefinitionNode: """FieldDefinition""" start = self._lexer.token description = self.parse_description() name = self.parse_name() args = self.parse_argument_defs() self.expect_token(TokenKind.COLON) type_ = self.parse_type_reference() directives = self.parse_const_directives() return FieldDefinitionNode( description=description, name=name, arguments=args, type=type_, directives=directives, loc=self.loc(start), ) def parse_argument_defs(self) -> List[InputValueDefinitionNode]: """ArgumentsDefinition: (InputValueDefinition+)""" return self.optional_many( TokenKind.PAREN_L, self.parse_input_value_def, TokenKind.PAREN_R ) def parse_input_value_def(self) -> InputValueDefinitionNode: """InputValueDefinition""" start = self._lexer.token description = self.parse_description() name = self.parse_name() self.expect_token(TokenKind.COLON) type_ = self.parse_type_reference() default_value = ( self.parse_const_value_literal() if self.expect_optional_token(TokenKind.EQUALS) else None ) directives = self.parse_const_directives() return InputValueDefinitionNode( description=description, name=name, type=type_, default_value=default_value, directives=directives, loc=self.loc(start), ) def parse_interface_type_definition(self) -> InterfaceTypeDefinitionNode: """InterfaceTypeDefinition""" start = self._lexer.token description = self.parse_description() self.expect_keyword("interface") name = self.parse_name() interfaces = self.parse_implements_interfaces() directives = self.parse_const_directives() fields = self.parse_fields_definition() return InterfaceTypeDefinitionNode( description=description, name=name, interfaces=interfaces, directives=directives, fields=fields, loc=self.loc(start), ) def parse_union_type_definition(self) -> UnionTypeDefinitionNode: """UnionTypeDefinition""" start = self._lexer.token description = self.parse_description() self.expect_keyword("union") name = self.parse_name() directives = self.parse_const_directives() types = self.parse_union_member_types() return UnionTypeDefinitionNode( description=description, name=name, directives=directives, types=types, loc=self.loc(start), ) def parse_union_member_types(self) -> List[NamedTypeNode]: """UnionMemberTypes""" return ( self.delimited_many(TokenKind.PIPE, self.parse_named_type) if self.expect_optional_token(TokenKind.EQUALS) else [] ) def parse_enum_type_definition(self) -> EnumTypeDefinitionNode: """UnionTypeDefinition""" start = self._lexer.token description = self.parse_description() self.expect_keyword("enum") name = self.parse_name() directives = self.parse_const_directives() values = self.parse_enum_values_definition() return EnumTypeDefinitionNode( description=description, name=name, directives=directives, values=values, loc=self.loc(start), ) def parse_enum_values_definition(self) -> List[EnumValueDefinitionNode]: """EnumValuesDefinition: {EnumValueDefinition+}""" return self.optional_many( TokenKind.BRACE_L, self.parse_enum_value_definition, TokenKind.BRACE_R ) def parse_enum_value_definition(self) -> EnumValueDefinitionNode: """EnumValueDefinition: Description? EnumValue Directives[Const]?""" start = self._lexer.token description = self.parse_description() name = self.parse_enum_value_name() directives = self.parse_const_directives() return EnumValueDefinitionNode( description=description, name=name, directives=directives, loc=self.loc(start), ) def parse_enum_value_name(self) -> NameNode: """EnumValue: Name but not ``true``, ``false`` or ``null``""" if self._lexer.token.value in ("true", "false", "null"): raise GraphQLSyntaxError( self._lexer.source, self._lexer.token.start, f"{get_token_desc(self._lexer.token)} is reserved" " and cannot be used for an enum value.", ) return self.parse_name() def parse_input_object_type_definition(self) -> InputObjectTypeDefinitionNode: """InputObjectTypeDefinition""" start = self._lexer.token description = self.parse_description() self.expect_keyword("input") name = self.parse_name() directives = self.parse_const_directives() fields = self.parse_input_fields_definition() return InputObjectTypeDefinitionNode( description=description, name=name, directives=directives, fields=fields, loc=self.loc(start), ) def parse_input_fields_definition(self) -> List[InputValueDefinitionNode]: """InputFieldsDefinition: {InputValueDefinition+}""" return self.optional_many( TokenKind.BRACE_L, self.parse_input_value_def, TokenKind.BRACE_R ) def parse_schema_extension(self) -> SchemaExtensionNode: """SchemaExtension""" start = self._lexer.token self.expect_keyword("extend") self.expect_keyword("schema") directives = self.parse_const_directives() operation_types = self.optional_many( TokenKind.BRACE_L, self.parse_operation_type_definition, TokenKind.BRACE_R ) if not directives and not operation_types: raise self.unexpected() return SchemaExtensionNode( directives=directives, operation_types=operation_types, loc=self.loc(start) ) def parse_scalar_type_extension(self) -> ScalarTypeExtensionNode: """ScalarTypeExtension""" start = self._lexer.token self.expect_keyword("extend") self.expect_keyword("scalar") name = self.parse_name() directives = self.parse_const_directives() if not directives: raise self.unexpected() return ScalarTypeExtensionNode( name=name, directives=directives, loc=self.loc(start) ) def parse_object_type_extension(self) -> ObjectTypeExtensionNode: """ObjectTypeExtension""" start = self._lexer.token self.expect_keyword("extend") self.expect_keyword("type") name = self.parse_name() interfaces = self.parse_implements_interfaces() directives = self.parse_const_directives() fields = self.parse_fields_definition() if not (interfaces or directives or fields): raise self.unexpected() return ObjectTypeExtensionNode( name=name, interfaces=interfaces, directives=directives, fields=fields, loc=self.loc(start), ) def parse_interface_type_extension(self) -> InterfaceTypeExtensionNode: """InterfaceTypeExtension""" start = self._lexer.token self.expect_keyword("extend") self.expect_keyword("interface") name = self.parse_name() interfaces = self.parse_implements_interfaces() directives = self.parse_const_directives() fields = self.parse_fields_definition() if not (interfaces or directives or fields): raise self.unexpected() return InterfaceTypeExtensionNode( name=name, interfaces=interfaces, directives=directives, fields=fields, loc=self.loc(start), ) def parse_union_type_extension(self) -> UnionTypeExtensionNode: """UnionTypeExtension""" start = self._lexer.token self.expect_keyword("extend") self.expect_keyword("union") name = self.parse_name() directives = self.parse_const_directives() types = self.parse_union_member_types() if not (directives or types): raise self.unexpected() return UnionTypeExtensionNode( name=name, directives=directives, types=types, loc=self.loc(start) ) def parse_enum_type_extension(self) -> EnumTypeExtensionNode: """EnumTypeExtension""" start = self._lexer.token self.expect_keyword("extend") self.expect_keyword("enum") name = self.parse_name() directives = self.parse_const_directives() values = self.parse_enum_values_definition() if not (directives or values): raise self.unexpected() return EnumTypeExtensionNode( name=name, directives=directives, values=values, loc=self.loc(start) ) def parse_input_object_type_extension(self) -> InputObjectTypeExtensionNode: """InputObjectTypeExtension""" start = self._lexer.token self.expect_keyword("extend") self.expect_keyword("input") name = self.parse_name() directives = self.parse_const_directives() fields = self.parse_input_fields_definition() if not (directives or fields): raise self.unexpected() return InputObjectTypeExtensionNode( name=name, directives=directives, fields=fields, loc=self.loc(start) ) def parse_directive_definition(self) -> DirectiveDefinitionNode: """DirectiveDefinition""" start = self._lexer.token description = self.parse_description() self.expect_keyword("directive") self.expect_token(TokenKind.AT) name = self.parse_name() args = self.parse_argument_defs() repeatable = self.expect_optional_keyword("repeatable") self.expect_keyword("on") locations = self.parse_directive_locations() return DirectiveDefinitionNode( description=description, name=name, arguments=args, repeatable=repeatable, locations=locations, loc=self.loc(start), ) def parse_directive_locations(self) -> List[NameNode]: """DirectiveLocations""" return self.delimited_many(TokenKind.PIPE, self.parse_directive_location) def parse_directive_location(self) -> NameNode: """DirectiveLocation""" start = self._lexer.token name = self.parse_name() if name.value in DirectiveLocation.__members__: return name raise self.unexpected(start) # Core parsing utility functions def loc(self, start_token: Token) -> Optional[Location]: """Return a location object. Used to identify the place in the source that created a given parsed object. """ if not self._no_location: end_token = self._lexer.last_token source = self._lexer.source return Location(start_token, end_token, source) return None def peek(self, kind: TokenKind) -> bool: """Determine if the next token is of a given kind""" return self._lexer.token.kind == kind def expect_token(self, kind: TokenKind) -> Token: """Expect the next token to be of the given kind. If the next token is of the given kind, return that token after advancing the lexer. Otherwise, do not change the parser state and throw an error. """ token = self._lexer.token if token.kind == kind: self.advance_lexer() return token raise GraphQLSyntaxError( self._lexer.source, token.start, f"Expected {get_token_kind_desc(kind)}, found {get_token_desc(token)}.", ) def expect_optional_token(self, kind: TokenKind) -> bool: """Expect the next token optionally to be of the given kind. If the next token is of the given kind, return True after advancing the lexer. Otherwise, do not change the parser state and return False. """ token = self._lexer.token if token.kind == kind: self.advance_lexer() return True return False def expect_keyword(self, value: str) -> None: """Expect the next token to be a given keyword. If the next token is a given keyword, advance the lexer. Otherwise, do not change the parser state and throw an error. """ token = self._lexer.token if token.kind == TokenKind.NAME and token.value == value: self.advance_lexer() else: raise GraphQLSyntaxError( self._lexer.source, token.start, f"Expected '{value}', found {get_token_desc(token)}.", ) def expect_optional_keyword(self, value: str) -> bool: """Expect the next token optionally to be a given keyword. If the next token is a given keyword, return True after advancing the lexer. Otherwise, do not change the parser state and return False. """ token = self._lexer.token if token.kind == TokenKind.NAME and token.value == value: self.advance_lexer() return True return False def unexpected(self, at_token: Optional[Token] = None) -> GraphQLError: """Create an error when an unexpected lexed token is encountered.""" token = at_token or self._lexer.token return GraphQLSyntaxError( self._lexer.source, token.start, f"Unexpected {get_token_desc(token)}." ) def any( self, open_kind: TokenKind, parse_fn: Callable[[], T], close_kind: TokenKind ) -> List[T]: """Fetch any matching nodes, possibly none. Returns a possibly empty list of parse nodes, determined by the ``parse_fn``. This list begins with a lex token of ``open_kind`` and ends with a lex token of ``close_kind``. Advances the parser to the next lex token after the closing token. """ self.expect_token(open_kind) nodes: List[T] = [] append = nodes.append expect_optional_token = partial(self.expect_optional_token, close_kind) while not expect_optional_token(): append(parse_fn()) return nodes def optional_many( self, open_kind: TokenKind, parse_fn: Callable[[], T], close_kind: TokenKind ) -> List[T]: """Fetch matching nodes, maybe none. Returns a list of parse nodes, determined by the ``parse_fn``. It can be empty only if the open token is missing, otherwise it will always return a non-empty list that begins with a lex token of ``open_kind`` and ends with a lex token of ``close_kind``. Advances the parser to the next lex token after the closing token. """ if self.expect_optional_token(open_kind): nodes = [parse_fn()] append = nodes.append expect_optional_token = partial(self.expect_optional_token, close_kind) while not expect_optional_token(): append(parse_fn()) return nodes return [] def many( self, open_kind: TokenKind, parse_fn: Callable[[], T], close_kind: TokenKind ) -> List[T]: """Fetch matching nodes, at least one. Returns a non-empty list of parse nodes, determined by the ``parse_fn``. This list begins with a lex token of ``open_kind`` and ends with a lex token of ``close_kind``. Advances the parser to the next lex token after the closing token. """ self.expect_token(open_kind) nodes = [parse_fn()] append = nodes.append expect_optional_token = partial(self.expect_optional_token, close_kind) while not expect_optional_token(): append(parse_fn()) return nodes def delimited_many( self, delimiter_kind: TokenKind, parse_fn: Callable[[], T] ) -> List[T]: """Fetch many delimited nodes. Returns a non-empty list of parse nodes, determined by the ``parse_fn``. This list may begin with a lex token of ``delimiter_kind`` followed by items separated by lex tokens of ``delimiter_kind``. Advances the parser to the next lex token after the last item in the list. """ expect_optional_token = partial(self.expect_optional_token, delimiter_kind) expect_optional_token() nodes: List[T] = [] append = nodes.append while True: append(parse_fn()) if not expect_optional_token(): break return nodes def advance_lexer(self) -> None: max_tokens = self._max_tokens token = self._lexer.advance() if max_tokens is not None and token.kind != TokenKind.EOF: self._token_counter += 1 if self._token_counter > max_tokens: raise GraphQLSyntaxError( self._lexer.source, token.start, f"Document contains more than {max_tokens} tokens." " Parsing aborted.", ) def get_token_desc(token: Token) -> str: """Describe a token as a string for debugging.""" value = token.value return get_token_kind_desc(token.kind) + ( f" '{value}'" if value is not None else "" ) def get_token_kind_desc(kind: TokenKind) -> str: """Describe a token kind as a string for debugging.""" return f"'{kind.value}'" if is_punctuator_token_kind(kind) else kind.value graphql-core-3.2.6/src/graphql/language/predicates.py000066400000000000000000000047711474546154300226410ustar00rootroot00000000000000from .ast import ( Node, DefinitionNode, ExecutableDefinitionNode, ListValueNode, ObjectValueNode, SchemaExtensionNode, SelectionNode, TypeDefinitionNode, TypeExtensionNode, TypeNode, TypeSystemDefinitionNode, ValueNode, VariableNode, ) __all__ = [ "is_definition_node", "is_executable_definition_node", "is_selection_node", "is_value_node", "is_const_value_node", "is_type_node", "is_type_system_definition_node", "is_type_definition_node", "is_type_system_extension_node", "is_type_extension_node", ] def is_definition_node(node: Node) -> bool: """Check whether the given node represents a definition.""" return isinstance(node, DefinitionNode) def is_executable_definition_node(node: Node) -> bool: """Check whether the given node represents an executable definition.""" return isinstance(node, ExecutableDefinitionNode) def is_selection_node(node: Node) -> bool: """Check whether the given node represents a selection.""" return isinstance(node, SelectionNode) def is_value_node(node: Node) -> bool: """Check whether the given node represents a value.""" return isinstance(node, ValueNode) def is_const_value_node(node: Node) -> bool: """Check whether the given node represents a constant value.""" return is_value_node(node) and ( any(is_const_value_node(value) for value in node.values) if isinstance(node, ListValueNode) else ( any(is_const_value_node(field.value) for field in node.fields) if isinstance(node, ObjectValueNode) else not isinstance(node, VariableNode) ) ) def is_type_node(node: Node) -> bool: """Check whether the given node represents a type.""" return isinstance(node, TypeNode) def is_type_system_definition_node(node: Node) -> bool: """Check whether the given node represents a type system definition.""" return isinstance(node, TypeSystemDefinitionNode) def is_type_definition_node(node: Node) -> bool: """Check whether the given node represents a type definition.""" return isinstance(node, TypeDefinitionNode) def is_type_system_extension_node(node: Node) -> bool: """Check whether the given node represents a type system extension.""" return isinstance(node, (SchemaExtensionNode, TypeExtensionNode)) def is_type_extension_node(node: Node) -> bool: """Check whether the given node represents a type extension.""" return isinstance(node, TypeExtensionNode) graphql-core-3.2.6/src/graphql/language/print_location.py000066400000000000000000000053121474546154300235320ustar00rootroot00000000000000import re from typing import Optional, Tuple, cast from .ast import Location from .location import SourceLocation, get_location from .source import Source __all__ = ["print_location", "print_source_location"] def print_location(location: Location) -> str: """Render a helpful description of the location in the GraphQL Source document.""" return print_source_location( location.source, get_location(location.source, location.start) ) _re_newline = re.compile(r"\r\n|[\n\r]") def print_source_location(source: Source, source_location: SourceLocation) -> str: """Render a helpful description of the location in the GraphQL Source document.""" first_line_column_offset = source.location_offset.column - 1 body = "".rjust(first_line_column_offset) + source.body line_index = source_location.line - 1 line_offset = source.location_offset.line - 1 line_num = source_location.line + line_offset column_offset = first_line_column_offset if source_location.line == 1 else 0 column_num = source_location.column + column_offset location_str = f"{source.name}:{line_num}:{column_num}\n" lines = _re_newline.split(body) # works a bit different from splitlines() location_line = lines[line_index] # Special case for minified documents if len(location_line) > 120: sub_line_index, sub_line_column_num = divmod(column_num, 80) sub_lines = [ location_line[i : i + 80] for i in range(0, len(location_line), 80) ] return location_str + print_prefixed_lines( (f"{line_num} |", sub_lines[0]), *[("|", sub_line) for sub_line in sub_lines[1 : sub_line_index + 1]], ("|", "^".rjust(sub_line_column_num)), ( "|", ( sub_lines[sub_line_index + 1] if sub_line_index < len(sub_lines) - 1 else None ), ), ) return location_str + print_prefixed_lines( (f"{line_num - 1} |", lines[line_index - 1] if line_index > 0 else None), (f"{line_num} |", location_line), ("|", "^".rjust(column_num)), ( f"{line_num + 1} |", lines[line_index + 1] if line_index < len(lines) - 1 else None, ), ) def print_prefixed_lines(*lines: Tuple[str, Optional[str]]) -> str: """Print lines specified like this: ("prefix", "string")""" existing_lines = [ cast(Tuple[str, str], line) for line in lines if line[1] is not None ] pad_len = max(len(line[0]) for line in existing_lines) return "\n".join( prefix.rjust(pad_len) + (" " + line if line else "") for prefix, line in existing_lines ) graphql-core-3.2.6/src/graphql/language/print_string.py000066400000000000000000000033121474546154300232260ustar00rootroot00000000000000__all__ = ["print_string"] def print_string(s: str) -> str: """Print a string as a GraphQL StringValue literal. Replaces control characters and excluded characters (" U+0022 and \\ U+005C) with escape sequences. """ if not isinstance(s, str): s = str(s) return f'"{s.translate(escape_sequences)}"' escape_sequences = { 0x00: "\\u0000", 0x01: "\\u0001", 0x02: "\\u0002", 0x03: "\\u0003", 0x04: "\\u0004", 0x05: "\\u0005", 0x06: "\\u0006", 0x07: "\\u0007", 0x08: "\\b", 0x09: "\\t", 0x0A: "\\n", 0x0B: "\\u000B", 0x0C: "\\f", 0x0D: "\\r", 0x0E: "\\u000E", 0x0F: "\\u000F", 0x10: "\\u0010", 0x11: "\\u0011", 0x12: "\\u0012", 0x13: "\\u0013", 0x14: "\\u0014", 0x15: "\\u0015", 0x16: "\\u0016", 0x17: "\\u0017", 0x18: "\\u0018", 0x19: "\\u0019", 0x1A: "\\u001A", 0x1B: "\\u001B", 0x1C: "\\u001C", 0x1D: "\\u001D", 0x1E: "\\u001E", 0x1F: "\\u001F", 0x22: '\\"', 0x5C: "\\\\", 0x7F: "\\u007F", 0x80: "\\u0080", 0x81: "\\u0081", 0x82: "\\u0082", 0x83: "\\u0083", 0x84: "\\u0084", 0x85: "\\u0085", 0x86: "\\u0086", 0x87: "\\u0087", 0x88: "\\u0088", 0x89: "\\u0089", 0x8A: "\\u008A", 0x8B: "\\u008B", 0x8C: "\\u008C", 0x8D: "\\u008D", 0x8E: "\\u008E", 0x8F: "\\u008F", 0x90: "\\u0090", 0x91: "\\u0091", 0x92: "\\u0092", 0x93: "\\u0093", 0x94: "\\u0094", 0x95: "\\u0095", 0x96: "\\u0096", 0x97: "\\u0097", 0x98: "\\u0098", 0x99: "\\u0099", 0x9A: "\\u009A", 0x9B: "\\u009B", 0x9C: "\\u009C", 0x9D: "\\u009D", 0x9E: "\\u009E", 0x9F: "\\u009F", } graphql-core-3.2.6/src/graphql/language/printer.py000066400000000000000000000315431474546154300221760ustar00rootroot00000000000000from typing import Any, Collection, Optional from ..language.ast import Node, OperationType from .block_string import print_block_string from .print_string import print_string from .visitor import visit, Visitor __all__ = ["print_ast"] MAX_LINE_LENGTH = 80 Strings = Collection[str] class PrintedNode: """A union type for all nodes that have been processed by the printer.""" alias: str arguments: Strings block: bool default_value: str definitions: Strings description: str directives: str fields: Strings interfaces: Strings locations: Strings name: str operation: OperationType operation_types: Strings repeatable: bool selection_set: str selections: Strings type: str type_condition: str types: Strings value: str values: Strings variable: str variable_definitions: Strings def print_ast(ast: Node) -> str: """Convert an AST into a string. The conversion is done using a set of reasonable formatting rules. """ return visit(ast, PrintAstVisitor()) class PrintAstVisitor(Visitor): @staticmethod def leave_name(node: PrintedNode, *_args: Any) -> str: return node.value @staticmethod def leave_variable(node: PrintedNode, *_args: Any) -> str: return f"${node.name}" # Document @staticmethod def leave_document(node: PrintedNode, *_args: Any) -> str: return join(node.definitions, "\n\n") @staticmethod def leave_operation_definition(node: PrintedNode, *_args: Any) -> str: var_defs = wrap("(", join(node.variable_definitions, ", "), ")") prefix = join( ( node.operation.value, join((node.name, var_defs)), join(node.directives, " "), ), " ", ) # Anonymous queries with no directives or variable definitions can use the # query short form. return ("" if prefix == "query" else prefix + " ") + node.selection_set @staticmethod def leave_variable_definition(node: PrintedNode, *_args: Any) -> str: return ( f"{node.variable}: {node.type}" f"{wrap(' = ', node.default_value)}" f"{wrap(' ', join(node.directives, ' '))}" ) @staticmethod def leave_selection_set(node: PrintedNode, *_args: Any) -> str: return block(node.selections) @staticmethod def leave_field(node: PrintedNode, *_args: Any) -> str: prefix = wrap("", node.alias, ": ") + node.name args_line = prefix + wrap("(", join(node.arguments, ", "), ")") if len(args_line) > MAX_LINE_LENGTH: args_line = prefix + wrap("(\n", indent(join(node.arguments, "\n")), "\n)") return join((args_line, join(node.directives, " "), node.selection_set), " ") @staticmethod def leave_argument(node: PrintedNode, *_args: Any) -> str: return f"{node.name}: {node.value}" # Fragments @staticmethod def leave_fragment_spread(node: PrintedNode, *_args: Any) -> str: return f"...{node.name}{wrap(' ', join(node.directives, ' '))}" @staticmethod def leave_inline_fragment(node: PrintedNode, *_args: Any) -> str: return join( ( "...", wrap("on ", node.type_condition), join(node.directives, " "), node.selection_set, ), " ", ) @staticmethod def leave_fragment_definition(node: PrintedNode, *_args: Any) -> str: # Note: fragment variable definitions are deprecated and will be removed in v3.3 return ( f"fragment {node.name}" f"{wrap('(', join(node.variable_definitions, ', '), ')')}" f" on {node.type_condition}" f" {wrap('', join(node.directives, ' '), ' ')}" f"{node.selection_set}" ) # Value @staticmethod def leave_int_value(node: PrintedNode, *_args: Any) -> str: return node.value @staticmethod def leave_float_value(node: PrintedNode, *_args: Any) -> str: return node.value @staticmethod def leave_string_value(node: PrintedNode, *_args: Any) -> str: if node.block: return print_block_string(node.value) return print_string(node.value) @staticmethod def leave_boolean_value(node: PrintedNode, *_args: Any) -> str: return "true" if node.value else "false" @staticmethod def leave_null_value(_node: PrintedNode, *_args: Any) -> str: return "null" @staticmethod def leave_enum_value(node: PrintedNode, *_args: Any) -> str: return node.value @staticmethod def leave_list_value(node: PrintedNode, *_args: Any) -> str: return f"[{join(node.values, ', ')}]" @staticmethod def leave_object_value(node: PrintedNode, *_args: Any) -> str: return f"{{{join(node.fields, ', ')}}}" @staticmethod def leave_object_field(node: PrintedNode, *_args: Any) -> str: return f"{node.name}: {node.value}" # Directive @staticmethod def leave_directive(node: PrintedNode, *_args: Any) -> str: return f"@{node.name}{wrap('(', join(node.arguments, ', '), ')')}" # Type @staticmethod def leave_named_type(node: PrintedNode, *_args: Any) -> str: return node.name @staticmethod def leave_list_type(node: PrintedNode, *_args: Any) -> str: return f"[{node.type}]" @staticmethod def leave_non_null_type(node: PrintedNode, *_args: Any) -> str: return f"{node.type}!" # Type System Definitions @staticmethod def leave_schema_definition(node: PrintedNode, *_args: Any) -> str: return wrap("", node.description, "\n") + join( ( "schema", join(node.directives, " "), block(node.operation_types), ), " ", ) @staticmethod def leave_operation_type_definition(node: PrintedNode, *_args: Any) -> str: return f"{node.operation.value}: {node.type}" @staticmethod def leave_scalar_type_definition(node: PrintedNode, *_args: Any) -> str: return wrap("", node.description, "\n") + join( ( "scalar", node.name, join(node.directives, " "), ), " ", ) @staticmethod def leave_object_type_definition(node: PrintedNode, *_args: Any) -> str: return wrap("", node.description, "\n") + join( ( "type", node.name, wrap("implements ", join(node.interfaces, " & ")), join(node.directives, " "), block(node.fields), ), " ", ) @staticmethod def leave_field_definition(node: PrintedNode, *_args: Any) -> str: args = node.arguments args = ( wrap("(\n", indent(join(args, "\n")), "\n)") if has_multiline_items(args) else wrap("(", join(args, ", "), ")") ) directives = wrap(" ", join(node.directives, " ")) return ( wrap("", node.description, "\n") + f"{node.name}{args}: {node.type}{directives}" ) @staticmethod def leave_input_value_definition(node: PrintedNode, *_args: Any) -> str: return wrap("", node.description, "\n") + join( ( f"{node.name}: {node.type}", wrap("= ", node.default_value), join(node.directives, " "), ), " ", ) @staticmethod def leave_interface_type_definition(node: PrintedNode, *_args: Any) -> str: return wrap("", node.description, "\n") + join( ( "interface", node.name, wrap("implements ", join(node.interfaces, " & ")), join(node.directives, " "), block(node.fields), ), " ", ) @staticmethod def leave_union_type_definition(node: PrintedNode, *_args: Any) -> str: return wrap("", node.description, "\n") + join( ( "union", node.name, join(node.directives, " "), wrap("= ", join(node.types, " | ")), ), " ", ) @staticmethod def leave_enum_type_definition(node: PrintedNode, *_args: Any) -> str: return wrap("", node.description, "\n") + join( ("enum", node.name, join(node.directives, " "), block(node.values)), " " ) @staticmethod def leave_enum_value_definition(node: PrintedNode, *_args: Any) -> str: return wrap("", node.description, "\n") + join( (node.name, join(node.directives, " ")), " " ) @staticmethod def leave_input_object_type_definition(node: PrintedNode, *_args: Any) -> str: return wrap("", node.description, "\n") + join( ("input", node.name, join(node.directives, " "), block(node.fields)), " " ) @staticmethod def leave_directive_definition(node: PrintedNode, *_args: Any) -> str: args = node.arguments args = ( wrap("(\n", indent(join(args, "\n")), "\n)") if has_multiline_items(args) else wrap("(", join(args, ", "), ")") ) repeatable = " repeatable" if node.repeatable else "" locations = join(node.locations, " | ") return ( wrap("", node.description, "\n") + f"directive @{node.name}{args}{repeatable} on {locations}" ) @staticmethod def leave_schema_extension(node: PrintedNode, *_args: Any) -> str: return join( ("extend schema", join(node.directives, " "), block(node.operation_types)), " ", ) @staticmethod def leave_scalar_type_extension(node: PrintedNode, *_args: Any) -> str: return join(("extend scalar", node.name, join(node.directives, " ")), " ") @staticmethod def leave_object_type_extension(node: PrintedNode, *_args: Any) -> str: return join( ( "extend type", node.name, wrap("implements ", join(node.interfaces, " & ")), join(node.directives, " "), block(node.fields), ), " ", ) @staticmethod def leave_interface_type_extension(node: PrintedNode, *_args: Any) -> str: return join( ( "extend interface", node.name, wrap("implements ", join(node.interfaces, " & ")), join(node.directives, " "), block(node.fields), ), " ", ) @staticmethod def leave_union_type_extension(node: PrintedNode, *_args: Any) -> str: return join( ( "extend union", node.name, join(node.directives, " "), wrap("= ", join(node.types, " | ")), ), " ", ) @staticmethod def leave_enum_type_extension(node: PrintedNode, *_args: Any) -> str: return join( ("extend enum", node.name, join(node.directives, " "), block(node.values)), " ", ) @staticmethod def leave_input_object_type_extension(node: PrintedNode, *_args: Any) -> str: return join( ("extend input", node.name, join(node.directives, " "), block(node.fields)), " ", ) def join(strings: Optional[Strings], separator: str = "") -> str: """Join strings in a given collection. Return an empty string if it is None or empty, otherwise join all items together separated by separator if provided. """ return separator.join(s for s in strings if s) if strings else "" def block(strings: Optional[Strings]) -> str: """Return strings inside a block. Given a collection of strings, return a string with each item on its own line, wrapped in an indented "{ }" block. """ return wrap("{\n", indent(join(strings, "\n")), "\n}") def wrap(start: str, string: Optional[str], end: str = "") -> str: """Wrap string inside other strings at start and end. If the string is not None or empty, then wrap with start and end, otherwise return an empty string. """ return f"{start}{string}{end}" if string else "" def indent(string: str) -> str: """Indent string with two spaces. If the string is not None or empty, add two spaces at the beginning of every line inside the string. """ return wrap(" ", string.replace("\n", "\n ")) def is_multiline(string: str) -> bool: """Check whether a string consists of multiple lines.""" return "\n" in string def has_multiline_items(strings: Optional[Strings]) -> bool: """Check whether one of the items in the list has multiple lines.""" return any(is_multiline(item) for item in strings) if strings else False graphql-core-3.2.6/src/graphql/language/source.py000066400000000000000000000044421474546154300220110ustar00rootroot00000000000000from typing import Any from .location import SourceLocation __all__ = ["Source", "is_source"] class Source: """A representation of source input to GraphQL.""" # allow custom attributes and weak references (not used internally) __slots__ = "__weakref__", "__dict__", "body", "name", "location_offset" def __init__( self, body: str, name: str = "GraphQL request", location_offset: SourceLocation = SourceLocation(1, 1), ) -> None: """Initialize source input. The ``name`` and ``location_offset`` parameters are optional, but they are useful for clients who store GraphQL documents in source files. For example, if the GraphQL input starts at line 40 in a file named ``Foo.graphql``, it might be useful for ``name`` to be ``"Foo.graphql"`` and location to be ``(40, 0)``. The ``line`` and ``column`` attributes in ``location_offset`` are 1-indexed. """ self.body = body self.name = name if not isinstance(location_offset, SourceLocation): location_offset = SourceLocation._make(location_offset) if location_offset.line <= 0: raise ValueError( "line in location_offset is 1-indexed and must be positive." ) if location_offset.column <= 0: raise ValueError( "column in location_offset is 1-indexed and must be positive." ) self.location_offset = location_offset def get_location(self, position: int) -> SourceLocation: lines = self.body[:position].splitlines() if lines: line = len(lines) column = len(lines[-1]) + 1 else: line = 1 column = 1 return SourceLocation(line, column) def __repr__(self) -> str: return f"<{self.__class__.__name__} name={self.name!r}>" def __eq__(self, other: Any) -> bool: return (isinstance(other, Source) and other.body == self.body) or ( isinstance(other, str) and other == self.body ) def __ne__(self, other: Any) -> bool: return not self == other def is_source(source: Any) -> bool: """Test if the given value is a Source object. For internal use only. """ return isinstance(source, Source) graphql-core-3.2.6/src/graphql/language/token_kind.py000066400000000000000000000010351474546154300226310ustar00rootroot00000000000000from enum import Enum __all__ = ["TokenKind"] class TokenKind(Enum): """The different kinds of tokens that the lexer emits""" SOF = "" EOF = "" BANG = "!" DOLLAR = "$" AMP = "&" PAREN_L = "(" PAREN_R = ")" SPREAD = "..." COLON = ":" EQUALS = "=" AT = "@" BRACKET_L = "[" BRACKET_R = "]" BRACE_L = "{" PIPE = "|" BRACE_R = "}" NAME = "Name" INT = "Int" FLOAT = "Float" STRING = "String" BLOCK_STRING = "BlockString" COMMENT = "Comment" graphql-core-3.2.6/src/graphql/language/visitor.py000066400000000000000000000320661474546154300222130ustar00rootroot00000000000000from copy import copy from enum import Enum from typing import ( Any, Callable, Collection, Dict, List, NamedTuple, Optional, Tuple, Union, ) from ..pyutils import inspect, snake_to_camel from . import ast from .ast import QUERY_DOCUMENT_KEYS, Node __all__ = [ "Visitor", "ParallelVisitor", "VisitorAction", "visit", "BREAK", "SKIP", "REMOVE", "IDLE", ] class VisitorActionEnum(Enum): """Special return values for the visitor methods. You can also use the values of this enum directly. """ BREAK = True SKIP = False REMOVE = Ellipsis VisitorAction = Optional[VisitorActionEnum] # Note that in GraphQL.js these are defined differently: # BREAK = {}, SKIP = false, REMOVE = null, IDLE = undefined BREAK = VisitorActionEnum.BREAK SKIP = VisitorActionEnum.SKIP REMOVE = VisitorActionEnum.REMOVE IDLE = None VisitorKeyMap = Dict[str, Tuple[str, ...]] class EnterLeaveVisitor(NamedTuple): """Visitor with functions for entering and leaving.""" enter: Optional[Callable[..., Optional[VisitorAction]]] leave: Optional[Callable[..., Optional[VisitorAction]]] class Visitor: """Visitor that walks through an AST. Visitors can define two generic methods "enter" and "leave". The former will be called when a node is entered in the traversal, the latter is called after visiting the node and its child nodes. These methods have the following signature:: def enter(self, node, key, parent, path, ancestors): # The return value has the following meaning: # IDLE (None): no action # SKIP: skip visiting this node # BREAK: stop visiting altogether # REMOVE: delete this node # any other value: replace this node with the returned value return def leave(self, node, key, parent, path, ancestors): # The return value has the following meaning: # IDLE (None) or SKIP: no action # BREAK: stop visiting altogether # REMOVE: delete this node # any other value: replace this node with the returned value return The parameters have the following meaning: :arg node: The current node being visiting. :arg key: The index or key to this node from the parent node or Array. :arg parent: the parent immediately above this node, which may be an Array. :arg path: The key path to get to this node from the root node. :arg ancestors: All nodes and Arrays visited before reaching parent of this node. These correspond to array indices in ``path``. Note: ancestors includes arrays which contain the parent of visited node. You can also define node kind specific methods by suffixing them with an underscore followed by the kind of the node to be visited. For instance, to visit ``field`` nodes, you would defined the methods ``enter_field()`` and/or ``leave_field()``, with the same signature as above. If no kind specific method has been defined for a given node, the generic method is called. """ # Provide special return values as attributes BREAK, SKIP, REMOVE, IDLE = BREAK, SKIP, REMOVE, IDLE enter_leave_map: Dict[str, EnterLeaveVisitor] def __init_subclass__(cls) -> None: """Verify that all defined handlers are valid.""" super().__init_subclass__() for attr, val in cls.__dict__.items(): if attr.startswith("_"): continue attr_kind = attr.split("_", 1) if len(attr_kind) < 2: kind: Optional[str] = None else: attr, kind = attr_kind if attr in ("enter", "leave") and kind: name = snake_to_camel(kind) + "Node" node_cls = getattr(ast, name, None) if ( not node_cls or not isinstance(node_cls, type) or not issubclass(node_cls, Node) ): raise TypeError(f"Invalid AST node kind: {kind}.") def __init__(self) -> None: self.enter_leave_map = {} def get_enter_leave_for_kind(self, kind: str) -> EnterLeaveVisitor: """Given a node kind, return the EnterLeaveVisitor for that kind.""" try: return self.enter_leave_map[kind] except KeyError: enter_fn = getattr(self, f"enter_{kind}", None) if not enter_fn: enter_fn = getattr(self, "enter", None) leave_fn = getattr(self, f"leave_{kind}", None) if not leave_fn: leave_fn = getattr(self, "leave", None) enter_leave = EnterLeaveVisitor(enter_fn, leave_fn) self.enter_leave_map[kind] = enter_leave return enter_leave def get_visit_fn( self, kind: str, is_leaving: bool = False ) -> Optional[Callable[..., Optional[VisitorAction]]]: """Get the visit function for the given node kind and direction. .. deprecated:: 3.2 Please use ``get_enter_leave_for_kind`` instead. Will be removed in v3.3. """ enter_leave = self.get_enter_leave_for_kind(kind) return enter_leave.leave if is_leaving else enter_leave.enter class Stack(NamedTuple): """A stack for the visit function.""" in_array: bool idx: int keys: Tuple[Node, ...] edits: List[Tuple[Union[int, str], Node]] prev: Any # 'Stack' (python/mypy/issues/731) def visit( root: Node, visitor: Visitor, visitor_keys: Optional[VisitorKeyMap] = None ) -> Any: """Visit each node in an AST. :func:`~.visit` will walk through an AST using a depth-first traversal, calling the visitor's enter methods at each node in the traversal, and calling the leave methods after visiting that node and all of its child nodes. By returning different values from the enter and leave methods, the behavior of the visitor can be altered, including skipping over a sub-tree of the AST (by returning False), editing the AST by returning a value or None to remove the value, or to stop the whole traversal by returning :data:`~.BREAK`. When using :func:`~.visit` to edit an AST, the original AST will not be modified, and a new version of the AST with the changes applied will be returned from the visit function. To customize the node attributes to be used for traversal, you can provide a dictionary visitor_keys mapping node kinds to node attributes. """ if not isinstance(root, Node): raise TypeError(f"Not an AST Node: {inspect(root)}.") if not isinstance(visitor, Visitor): raise TypeError(f"Not an AST Visitor: {inspect(visitor)}.") if visitor_keys is None: visitor_keys = QUERY_DOCUMENT_KEYS stack: Any = None in_array = False keys: Tuple[Node, ...] = (root,) idx = -1 edits: List[Any] = [] node: Any = root key: Any = None parent: Any = None path: List[Any] = [] path_append = path.append path_pop = path.pop ancestors: List[Any] = [] ancestors_append = ancestors.append ancestors_pop = ancestors.pop while True: idx += 1 is_leaving = idx == len(keys) is_edited = is_leaving and edits if is_leaving: key = path[-1] if ancestors else None node = parent parent = ancestors_pop() if ancestors else None if is_edited: if in_array: node = list(node) edit_offset = 0 for edit_key, edit_value in edits: array_key = edit_key - edit_offset if edit_value is REMOVE or edit_value is Ellipsis: node.pop(array_key) edit_offset += 1 else: node[array_key] = edit_value node = tuple(node) else: node = copy(node) for edit_key, edit_value in edits: setattr(node, edit_key, edit_value) idx = stack.idx keys = stack.keys edits = stack.edits in_array = stack.in_array stack = stack.prev elif parent: if in_array: key = idx node = parent[key] else: key = keys[idx] node = getattr(parent, key, None) if node is None: continue path_append(key) if isinstance(node, tuple): result = None else: if not isinstance(node, Node): raise TypeError(f"Invalid AST Node: {inspect(node)}.") enter_leave = visitor.get_enter_leave_for_kind(node.kind) visit_fn = enter_leave.leave if is_leaving else enter_leave.enter if visit_fn: result = visit_fn(node, key, parent, path, ancestors) if result is BREAK or result is True: break if result is SKIP or result is False: if not is_leaving: path_pop() continue elif result is not None: edits.append((key, result)) if not is_leaving: if isinstance(result, Node): node = result else: path_pop() continue else: result = None if result is None and is_edited: edits.append((key, node)) if is_leaving: if path: path_pop() else: stack = Stack(in_array, idx, keys, edits, stack) in_array = isinstance(node, tuple) keys = node if in_array else visitor_keys.get(node.kind, ()) # type: ignore idx = -1 edits = [] if parent: ancestors_append(parent) parent = node if not stack: break if edits: return edits[-1][1] return root class ParallelVisitor(Visitor): """A Visitor which delegates to many visitors to run in parallel. Each visitor will be visited for each node before moving on. If a prior visitor edits a node, no following visitors will see that node. """ def __init__(self, visitors: Collection[Visitor]): """Create a new visitor from the given list of parallel visitors.""" super().__init__() self.visitors = visitors self.skipping: List[Any] = [None] * len(visitors) def get_enter_leave_for_kind(self, kind: str) -> EnterLeaveVisitor: """Given a node kind, return the EnterLeaveVisitor for that kind.""" try: return self.enter_leave_map[kind] except KeyError: has_visitor = False enter_list: List[Optional[Callable[..., Optional[VisitorAction]]]] = [] leave_list: List[Optional[Callable[..., Optional[VisitorAction]]]] = [] for visitor in self.visitors: enter, leave = visitor.get_enter_leave_for_kind(kind) if not has_visitor and (enter or leave): has_visitor = True enter_list.append(enter) leave_list.append(leave) if has_visitor: def enter(node: Node, *args: Any) -> Optional[VisitorAction]: skipping = self.skipping for i, fn in enumerate(enter_list): if not skipping[i]: if fn: result = fn(node, *args) if result is SKIP or result is False: skipping[i] = node elif result is BREAK or result is True: skipping[i] = BREAK elif result is not None: return result return None def leave(node: Node, *args: Any) -> Optional[VisitorAction]: skipping = self.skipping for i, fn in enumerate(leave_list): if not skipping[i]: if fn: result = fn(node, *args) if result is BREAK or result is True: skipping[i] = BREAK elif ( result is not None and result is not SKIP and result is not False ): return result elif skipping[i] is node: skipping[i] = None return None else: enter = leave = None enter_leave = EnterLeaveVisitor(enter, leave) self.enter_leave_map[kind] = enter_leave return enter_leave graphql-core-3.2.6/src/graphql/py.typed000066400000000000000000000001021474546154300200400ustar00rootroot00000000000000# Marker file for PEP 561. The graphql package uses inline types. graphql-core-3.2.6/src/graphql/pyutils/000077500000000000000000000000001474546154300200615ustar00rootroot00000000000000graphql-core-3.2.6/src/graphql/pyutils/__init__.py000066400000000000000000000033641474546154300222000ustar00rootroot00000000000000"""Python Utils This package contains dependency-free Python utility functions used throughout the codebase. Each utility should belong in its own file and be the default export. These functions are not part of the module interface and are subject to change. """ from .convert_case import camel_to_snake, snake_to_camel from .cached_property import cached_property from .description import ( Description, is_description, register_description, unregister_description, ) from .did_you_mean import did_you_mean from .group_by import group_by from .identity_func import identity_func from .inspect import inspect from .is_awaitable import is_awaitable from .is_iterable import is_collection, is_iterable from .natural_compare import natural_comparison_key from .awaitable_or_value import AwaitableOrValue from .suggestion_list import suggestion_list from .frozen_error import FrozenError from .frozen_list import FrozenList from .frozen_dict import FrozenDict from .merge_kwargs import merge_kwargs from .path import Path from .print_path_list import print_path_list from .simple_pub_sub import SimplePubSub, SimplePubSubIterator from .undefined import Undefined, UndefinedType __all__ = [ "camel_to_snake", "snake_to_camel", "cached_property", "did_you_mean", "Description", "group_by", "is_description", "register_description", "unregister_description", "identity_func", "inspect", "is_awaitable", "is_collection", "is_iterable", "merge_kwargs", "natural_comparison_key", "AwaitableOrValue", "suggestion_list", "FrozenError", "FrozenList", "FrozenDict", "Path", "print_path_list", "SimplePubSub", "SimplePubSubIterator", "Undefined", "UndefinedType", ] graphql-core-3.2.6/src/graphql/pyutils/awaitable_or_value.py000066400000000000000000000002131474546154300242540ustar00rootroot00000000000000from typing import Awaitable, TypeVar, Union __all__ = ["AwaitableOrValue"] T = TypeVar("T") AwaitableOrValue = Union[Awaitable[T], T] graphql-core-3.2.6/src/graphql/pyutils/cached_property.py000066400000000000000000000020431474546154300236050ustar00rootroot00000000000000from typing import Any, Callable, TYPE_CHECKING if TYPE_CHECKING: standard_cached_property = None else: try: from functools import cached_property as standard_cached_property except ImportError: # Python < 3.8 standard_cached_property = None if standard_cached_property: cached_property = standard_cached_property else: # Code taken from https://github.com/bottlepy/bottle class CachedProperty: """A cached property. A property that is only computed once per instance and then replaces itself with an ordinary attribute. Deleting the attribute resets the property. """ def __init__(self, func: Callable) -> None: self.__doc__ = getattr(func, "__doc__") self.func = func def __get__(self, obj: object, cls: type) -> Any: if obj is None: return self value = obj.__dict__[self.func.__name__] = self.func(obj) return value cached_property = CachedProperty __all__ = ["cached_property"] graphql-core-3.2.6/src/graphql/pyutils/convert_case.py000066400000000000000000000013131474546154300231040ustar00rootroot00000000000000# uses code from https://github.com/daveoncode/python-string-utils import re __all__ = ["camel_to_snake", "snake_to_camel"] _re_camel_to_snake = re.compile(r"([a-z]|[A-Z0-9]+)(?=[A-Z])") _re_snake_to_camel = re.compile(r"(_)([a-z\d])") def camel_to_snake(s: str) -> str: """Convert from CamelCase to snake_case""" return _re_camel_to_snake.sub(r"\1_", s).lower() def snake_to_camel(s: str, upper: bool = True) -> str: """Convert from snake_case to CamelCase If upper is set, then convert to upper CamelCase, otherwise the first character keeps its case. """ s = _re_snake_to_camel.sub(lambda m: m.group(2).upper(), s) if upper: s = s[:1].upper() + s[1:] return s graphql-core-3.2.6/src/graphql/pyutils/description.py000066400000000000000000000036741474546154300227700ustar00rootroot00000000000000from typing import Any, Tuple, Union __all__ = [ "Description", "is_description", "register_description", "unregister_description", ] class Description: """Type checker for human readable descriptions. By default, only ordinary strings are accepted as descriptions, but you can register() other classes that will also be allowed, e.g. to support lazy string objects that are evaluated only at runtime. If you register(object), any object will be allowed as description. """ bases: Union[type, Tuple[type, ...]] = str @classmethod def isinstance(cls, obj: Any) -> bool: return isinstance(obj, cls.bases) @classmethod def register(cls, base: type) -> None: """Register a class that shall be accepted as a description.""" if not isinstance(base, type): raise TypeError("Only types can be registered.") if base is object: cls.bases = object elif cls.bases is object: cls.bases = base elif not isinstance(cls.bases, tuple): if base is not cls.bases: cls.bases = (cls.bases, base) elif base not in cls.bases: cls.bases += (base,) @classmethod def unregister(cls, base: type) -> None: """Unregister a class that shall no more be accepted as a description.""" if not isinstance(base, type): raise TypeError("Only types can be unregistered.") if isinstance(cls.bases, tuple): if base in cls.bases: # pragma: no branch cls.bases = tuple(b for b in cls.bases if b is not base) if not cls.bases: cls.bases = object elif len(cls.bases) == 1: cls.bases = cls.bases[0] elif cls.bases is base: cls.bases = object is_description = Description.isinstance register_description = Description.register unregister_description = Description.unregister graphql-core-3.2.6/src/graphql/pyutils/did_you_mean.py000066400000000000000000000014441474546154300230720ustar00rootroot00000000000000from typing import Optional, Sequence __all__ = ["did_you_mean"] MAX_LENGTH = 5 def did_you_mean(suggestions: Sequence[str], sub_message: Optional[str] = None) -> str: """Given [ A, B, C ] return ' Did you mean A, B, or C?'""" if not suggestions or not MAX_LENGTH: return "" parts = [" Did you mean "] if sub_message: parts.extend([sub_message, " "]) suggestions = suggestions[:MAX_LENGTH] n = len(suggestions) if n == 1: parts.append(f"'{suggestions[0]}'?") elif n == 2: parts.append(f"'{suggestions[0]}' or '{suggestions[1]}'?") else: parts.extend( [ ", ".join(f"'{s}'" for s in suggestions[:-1]), f", or '{suggestions[-1]}'?", ] ) return "".join(parts) graphql-core-3.2.6/src/graphql/pyutils/frozen_dict.py000066400000000000000000000022221474546154300227370ustar00rootroot00000000000000from copy import deepcopy from typing import Dict, TypeVar from .frozen_error import FrozenError __all__ = ["FrozenDict"] KT = TypeVar("KT") VT = TypeVar("VT") class FrozenDict(Dict[KT, VT]): """Dictionary that can only be read, but not changed. .. deprecated:: 3.2 Use dicts and the Mapping type instead. Will be removed in v3.3. """ def __delitem__(self, key): raise FrozenError def __setitem__(self, key, value): raise FrozenError def __iadd__(self, value): raise FrozenError def __hash__(self) -> int: # type: ignore return hash(tuple(self.items())) def __copy__(self) -> "FrozenDict": return FrozenDict(self) copy = __copy__ def __deepcopy__(self, memo: Dict) -> "FrozenDict": return FrozenDict({k: deepcopy(v, memo) for k, v in self.items()}) def clear(self): raise FrozenError def pop(self, key, default=None): raise FrozenError def popitem(self): raise FrozenError def setdefault(self, key, default=None): raise FrozenError def update(self, other=None): # type: ignore raise FrozenError graphql-core-3.2.6/src/graphql/pyutils/frozen_error.py000066400000000000000000000002011474546154300231400ustar00rootroot00000000000000__all__ = ["FrozenError"] class FrozenError(TypeError): """Error when trying to change a frozen (read only) collection.""" graphql-core-3.2.6/src/graphql/pyutils/frozen_list.py000066400000000000000000000027651474546154300230030ustar00rootroot00000000000000from copy import deepcopy from typing import Dict, List, TypeVar from .frozen_error import FrozenError __all__ = ["FrozenList"] T = TypeVar("T") class FrozenList(List[T]): """List that can only be read, but not changed. .. deprecated:: 3.2 Use tuples or lists and the Collection type instead. Will be removed in v3.3. """ def __delitem__(self, key): raise FrozenError def __setitem__(self, key, value): raise FrozenError def __add__(self, value): if isinstance(value, tuple): value = list(value) return list.__add__(self, value) def __iadd__(self, value): raise FrozenError def __mul__(self, value): return list.__mul__(self, value) def __imul__(self, value): raise FrozenError def __hash__(self) -> int: # type: ignore return hash(tuple(self)) def __copy__(self) -> "FrozenList": return FrozenList(self) def __deepcopy__(self, memo: Dict) -> "FrozenList": return FrozenList(deepcopy(value, memo) for value in self) def append(self, x): raise FrozenError def extend(self, iterable): raise FrozenError def insert(self, i, x): raise FrozenError def remove(self, x): raise FrozenError def pop(self, i=None): raise FrozenError def clear(self): raise FrozenError def sort(self, *, key=None, reverse=False): raise FrozenError def reverse(self): raise FrozenError graphql-core-3.2.6/src/graphql/pyutils/group_by.py000066400000000000000000000007271474546154300222670ustar00rootroot00000000000000from collections import defaultdict from typing import Callable, Collection, Dict, List, TypeVar __all__ = ["group_by"] K = TypeVar("K") T = TypeVar("T") def group_by(items: Collection[T], key_fn: Callable[[T], K]) -> Dict[K, List[T]]: """Group an unsorted collection of items by a key derived via a function.""" result: Dict[K, List[T]] = defaultdict(list) for item in items: key = key_fn(item) result[key].append(item) return result graphql-core-3.2.6/src/graphql/pyutils/identity_func.py000066400000000000000000000003671474546154300233050ustar00rootroot00000000000000from typing import cast, Any, TypeVar from .undefined import Undefined __all__ = ["identity_func"] T = TypeVar("T") def identity_func(x: T = cast(Any, Undefined), *_args: Any) -> T: """Return the first received argument.""" return x graphql-core-3.2.6/src/graphql/pyutils/inspect.py000066400000000000000000000133411474546154300221020ustar00rootroot00000000000000from inspect import ( isclass, ismethod, isfunction, isgeneratorfunction, isgenerator, iscoroutinefunction, iscoroutine, isasyncgenfunction, isasyncgen, ) from typing import Any, List from .undefined import Undefined __all__ = ["inspect"] max_recursive_depth = 2 max_str_size = 240 max_list_size = 10 def inspect(value: Any) -> str: """Inspect value and a return string representation for error messages. Used to print values in error messages. We do not use repr() in order to not leak too much of the inner Python representation of unknown objects, and we do not use json.dumps() because not all objects can be serialized as JSON and we want to output strings with single quotes like Python repr() does it. We also restrict the size of the representation by truncating strings and collections and allowing only a maximum recursion depth. """ return inspect_recursive(value, []) def inspect_recursive(value: Any, seen_values: List) -> str: if value is None or value is Undefined or isinstance(value, (bool, float, complex)): return repr(value) if isinstance(value, (int, str, bytes, bytearray)): return trunc_str(repr(value)) if len(seen_values) < max_recursive_depth and value not in seen_values: # check if we have a custom inspect method inspect_method = getattr(value, "__inspect__", None) if inspect_method is not None and callable(inspect_method): s = inspect_method() if isinstance(s, str): return trunc_str(s) seen_values = [*seen_values, value] return inspect_recursive(s, seen_values) # recursively inspect collections if isinstance(value, (list, tuple, dict, set, frozenset)): if not value: return repr(value) seen_values = [*seen_values, value] if isinstance(value, list): items = value elif isinstance(value, dict): items = list(value.items()) else: items = list(value) items = trunc_list(items) if isinstance(value, dict): s = ", ".join( ( "..." if v is ELLIPSIS else inspect_recursive(v[0], seen_values) + ": " + inspect_recursive(v[1], seen_values) ) for v in items ) else: s = ", ".join( "..." if v is ELLIPSIS else inspect_recursive(v, seen_values) for v in items ) if isinstance(value, tuple): if len(items) == 1: return f"({s},)" return f"({s})" if isinstance(value, (dict, set)): return "{" + s + "}" if isinstance(value, frozenset): return f"frozenset({{{s}}})" return f"[{s}]" else: # handle collections that are nested too deep if isinstance(value, (list, tuple, dict, set, frozenset)): if not value: return repr(value) if isinstance(value, list): return "[...]" if isinstance(value, tuple): return "(...)" if isinstance(value, dict): return "{...}" if isinstance(value, set): return "set(...)" return "frozenset(...)" if isinstance(value, Exception): type_ = "exception" value = type(value) elif isclass(value): type_ = "exception class" if issubclass(value, Exception) else "class" elif ismethod(value): type_ = "method" elif iscoroutinefunction(value): type_ = "coroutine function" elif isasyncgenfunction(value): type_ = "async generator function" elif isgeneratorfunction(value): type_ = "generator function" elif isfunction(value): type_ = "function" elif iscoroutine(value): type_ = "coroutine" elif isasyncgen(value): type_ = "async generator" elif isgenerator(value): type_ = "generator" else: # stringify (only) the well-known GraphQL types from ..type import ( GraphQLDirective, GraphQLNamedType, GraphQLScalarType, GraphQLWrappingType, ) if isinstance( value, ( GraphQLDirective, GraphQLNamedType, GraphQLScalarType, GraphQLWrappingType, ), ): return str(value) try: name = type(value).__name__ if not name or "<" in name or ">" in name: raise AttributeError except AttributeError: return "" else: return f"<{name} instance>" try: name = value.__name__ if not name or "<" in name or ">" in name: raise AttributeError except AttributeError: return f"<{type_}>" else: return f"<{type_} {name}>" def trunc_str(s: str) -> str: """Truncate strings to maximum length.""" if len(s) > max_str_size: i = max(0, (max_str_size - 3) // 2) j = max(0, max_str_size - 3 - i) s = s[:i] + "..." + s[-j:] return s def trunc_list(s: List) -> List: """Truncate lists to maximum length.""" if len(s) > max_list_size: i = max_list_size // 2 j = i - 1 s = s[:i] + [ELLIPSIS] + s[-j:] return s class InspectEllipsisType: """Singleton class for indicating ellipses in iterables.""" ELLIPSIS = InspectEllipsisType() graphql-core-3.2.6/src/graphql/pyutils/is_awaitable.py000066400000000000000000000014361474546154300230630ustar00rootroot00000000000000import inspect from typing import Any from types import CoroutineType, GeneratorType __all__ = ["is_awaitable"] CO_ITERABLE_COROUTINE = inspect.CO_ITERABLE_COROUTINE def is_awaitable(value: Any) -> bool: """Return true if object can be passed to an ``await`` expression. Instead of testing if the object is an instance of abc.Awaitable, it checks the existence of an `__await__` attribute. This is much faster. """ return ( # check for coroutine objects isinstance(value, CoroutineType) # check for old-style generator based coroutine objects or isinstance(value, GeneratorType) and bool(value.gi_code.co_flags & CO_ITERABLE_COROUTINE) # check for other awaitables (e.g. futures) or hasattr(value, "__await__") ) graphql-core-3.2.6/src/graphql/pyutils/is_iterable.py000066400000000000000000000014661474546154300227240ustar00rootroot00000000000000from collections.abc import Collection, Iterable, Mapping, ValuesView from typing import Any __all__ = ["is_collection", "is_iterable"] collection_types: Any = Collection if not isinstance({}.values(), Collection): # Python < 3.7.2 collection_types = (Collection, ValuesView) iterable_types: Any = Iterable not_iterable_types: Any = (bytes, bytearray, memoryview, str, Mapping) def is_collection(value: Any) -> bool: """Check if value is a collection, but not a string or a mapping.""" return isinstance(value, collection_types) and not isinstance( value, not_iterable_types ) def is_iterable(value: Any) -> bool: """Check if value is an iterable, but not a string or a mapping.""" return isinstance(value, iterable_types) and not isinstance( value, not_iterable_types ) graphql-core-3.2.6/src/graphql/pyutils/merge_kwargs.py000066400000000000000000000003721474546154300231120ustar00rootroot00000000000000from typing import cast, Any, Dict, TypeVar T = TypeVar("T") def merge_kwargs(base_dict: T, **kwargs: Any) -> T: """Return arbitrary typed dictionary with some keyword args merged in.""" return cast(T, {**cast(Dict, base_dict), **kwargs}) graphql-core-3.2.6/src/graphql/pyutils/natural_compare.py000066400000000000000000000007361474546154300236150ustar00rootroot00000000000000import re from typing import Tuple from itertools import cycle __all__ = ["natural_comparison_key"] _re_digits = re.compile(r"(\d+)") def natural_comparison_key(key: str) -> Tuple: """Comparison key function for sorting strings by natural sort order. See: https://en.wikipedia.org/wiki/Natural_sort_order """ return tuple( (int(part), part) if is_digit else part for part, is_digit in zip(_re_digits.split(key), cycle((False, True))) ) graphql-core-3.2.6/src/graphql/pyutils/path.py000066400000000000000000000016331474546154300213720ustar00rootroot00000000000000from typing import Any, List, NamedTuple, Optional, Union __all__ = ["Path"] class Path(NamedTuple): """A generic path of string or integer indices""" prev: Any # Optional['Path'] (python/mypy/issues/731) """path with the previous indices""" key: Union[str, int] """current index in the path (string or integer)""" typename: Optional[str] """name of the parent type to avoid path ambiguity""" def add_key(self, key: Union[str, int], typename: Optional[str] = None) -> "Path": """Return a new Path containing the given key.""" return Path(self, key, typename) def as_list(self) -> List[Union[str, int]]: """Return a list of the path keys.""" flattened: List[Union[str, int]] = [] append = flattened.append curr: Path = self while curr: append(curr.key) curr = curr.prev return flattened[::-1] graphql-core-3.2.6/src/graphql/pyutils/print_path_list.py000066400000000000000000000003521474546154300236360ustar00rootroot00000000000000from typing import Collection, Union def print_path_list(path: Collection[Union[str, int]]) -> str: """Build a string describing the path.""" return "".join(f"[{key}]" if isinstance(key, int) else f".{key}" for key in path) graphql-core-3.2.6/src/graphql/pyutils/simple_pub_sub.py000066400000000000000000000047531474546154300234540ustar00rootroot00000000000000from asyncio import Future, Queue, ensure_future, sleep from inspect import isawaitable from typing import Any, AsyncIterator, Callable, Optional, Set try: from asyncio import get_running_loop except ImportError: from asyncio import get_event_loop as get_running_loop # Python < 3.7 __all__ = ["SimplePubSub", "SimplePubSubIterator"] class SimplePubSub: """A very simple publish-subscript system. Creates an AsyncIterator from an EventEmitter. Useful for mocking a PubSub system for tests. """ subscribers: Set[Callable] def __init__(self) -> None: self.subscribers = set() def emit(self, event: Any) -> bool: """Emit an event.""" for subscriber in self.subscribers: result = subscriber(event) if isawaitable(result): ensure_future(result) return bool(self.subscribers) def get_subscriber( self, transform: Optional[Callable] = None ) -> "SimplePubSubIterator": return SimplePubSubIterator(self, transform) class SimplePubSubIterator(AsyncIterator): def __init__(self, pubsub: SimplePubSub, transform: Optional[Callable]) -> None: self.pubsub = pubsub self.transform = transform self.pull_queue: Queue[Future] = Queue() self.push_queue: Queue[Any] = Queue() self.listening = True pubsub.subscribers.add(self.push_value) def __aiter__(self) -> "SimplePubSubIterator": return self async def __anext__(self) -> Any: if not self.listening: raise StopAsyncIteration await sleep(0) if not self.push_queue.empty(): return await self.push_queue.get() future = get_running_loop().create_future() await self.pull_queue.put(future) return future async def aclose(self) -> None: if self.listening: await self.empty_queue() async def empty_queue(self) -> None: self.listening = False self.pubsub.subscribers.remove(self.push_value) while not self.pull_queue.empty(): future = await self.pull_queue.get() future.cancel() while not self.push_queue.empty(): await self.push_queue.get() async def push_value(self, event: Any) -> None: value = event if self.transform is None else self.transform(event) if self.pull_queue.empty(): await self.push_queue.put(value) else: (await self.pull_queue.get()).set_result(value) graphql-core-3.2.6/src/graphql/pyutils/suggestion_list.py000066400000000000000000000067621474546154300236700ustar00rootroot00000000000000from typing import Collection, Optional, List from .natural_compare import natural_comparison_key __all__ = ["suggestion_list"] def suggestion_list(input_: str, options: Collection[str]) -> List[str]: """Get list with suggestions for a given input. Given an invalid input string and list of valid options, returns a filtered list of valid options sorted based on their similarity with the input. """ options_by_distance = {} lexical_distance = LexicalDistance(input_) threshold = int(len(input_) * 0.4) + 1 for option in options: distance = lexical_distance.measure(option, threshold) if distance is not None: options_by_distance[option] = distance # noinspection PyShadowingNames return sorted( options_by_distance, key=lambda option: ( options_by_distance.get(option, 0), natural_comparison_key(option), ), ) class LexicalDistance: """Computes the lexical distance between strings A and B. The "distance" between two strings is given by counting the minimum number of edits needed to transform string A into string B. An edit can be an insertion, deletion, or substitution of a single character, or a swap of two adjacent characters. This distance can be useful for detecting typos in input or sorting. """ _input: str _input_lower_case: str _input_list: List[int] _rows: List[List[int]] def __init__(self, input_: str): self._input = input_ self._input_lower_case = input_.lower() row_size = len(input_) + 1 self._input_list = list(map(ord, self._input_lower_case)) self._rows = [[0] * row_size, [0] * row_size, [0] * row_size] def measure(self, option: str, threshold: int) -> Optional[int]: if self._input == option: return 0 option_lower_case = option.lower() # Any case change counts as a single edit if self._input_lower_case == option_lower_case: return 1 a, b = list(map(ord, option_lower_case)), self._input_list a_len, b_len = len(a), len(b) if a_len < b_len: a, b = b, a a_len, b_len = b_len, a_len if a_len - b_len > threshold: return None rows = self._rows for j in range(b_len + 1): rows[0][j] = j for i in range(1, a_len + 1): up_row = rows[(i - 1) % 3] current_row = rows[i % 3] smallest_cell = current_row[0] = i for j in range(1, b_len + 1): cost = 0 if a[i - 1] == b[j - 1] else 1 current_cell = min( up_row[j] + 1, # delete current_row[j - 1] + 1, # insert up_row[j - 1] + cost, # substitute ) if i > 1 and j > 1 and a[i - 1] == b[j - 2] and a[i - 2] == b[j - 1]: # transposition double_diagonal_cell = rows[(i - 2) % 3][j - 2] current_cell = min(current_cell, double_diagonal_cell + 1) if current_cell < smallest_cell: smallest_cell = current_cell current_row[j] = current_cell # Early exit, since distance can't go smaller than smallest element # of the previous row. if smallest_cell > threshold: return None distance = rows[a_len % 3][b_len] return distance if distance <= threshold else None graphql-core-3.2.6/src/graphql/pyutils/undefined.py000066400000000000000000000015031474546154300223730ustar00rootroot00000000000000from typing import Any __all__ = ["Undefined", "UndefinedType"] class UndefinedType(ValueError): """Auxiliary class for creating the Undefined singleton.""" def __repr__(self) -> str: return "Undefined" __str__ = __repr__ def __hash__(self) -> int: return hash(UndefinedType) def __bool__(self) -> bool: return False def __eq__(self, other: Any) -> bool: return other is Undefined def __ne__(self, other: Any) -> bool: return not self == other # Used to indicate undefined or invalid values (like "undefined" in JavaScript): Undefined = UndefinedType() Undefined.__doc__ = """Symbol for undefined values This singleton object is used to describe undefined or invalid values. It can be used in places where you would use ``undefined`` in GraphQL.js. """ graphql-core-3.2.6/src/graphql/subscription/000077500000000000000000000000001474546154300210745ustar00rootroot00000000000000graphql-core-3.2.6/src/graphql/subscription/__init__.py000066400000000000000000000013351474546154300232070ustar00rootroot00000000000000"""GraphQL Subscription The :mod:`graphql.subscription` package is responsible for subscribing to updates on specific data. .. deprecated:: 3.2 This package has been deprecated with its exported functions integrated into the :mod:`graphql.execution` package, to better conform with the terminology of the GraphQL specification. For backwards compatibility, the :mod:`graphql.subscription` package currently re-exports the moved functions from the :mod:`graphql.execution` package. In v3.3, the :mod:`graphql.subscription` package will be dropped entirely. """ from ..execution import subscribe, create_source_event_stream, MapAsyncIterator __all__ = ["subscribe", "create_source_event_stream", "MapAsyncIterator"] graphql-core-3.2.6/src/graphql/type/000077500000000000000000000000001474546154300173315ustar00rootroot00000000000000graphql-core-3.2.6/src/graphql/type/__init__.py000066400000000000000000000155601474546154300214510ustar00rootroot00000000000000"""GraphQL Type System The :mod:`graphql.type` package is responsible for defining GraphQL types and schema. """ from ..pyutils import Path as ResponsePath from .schema import ( # Predicate is_schema, # Assertion assert_schema, # GraphQL Schema definition GraphQLSchema, # Keyword Args GraphQLSchemaKwargs, ) # Uphold the spec rules about naming. from .assert_name import assert_name, assert_enum_value_name from .definition import ( # Predicates is_type, is_scalar_type, is_object_type, is_interface_type, is_union_type, is_enum_type, is_input_object_type, is_list_type, is_non_null_type, is_input_type, is_output_type, is_leaf_type, is_composite_type, is_abstract_type, is_wrapping_type, is_nullable_type, is_named_type, is_required_argument, is_required_input_field, # Assertions assert_type, assert_scalar_type, assert_object_type, assert_interface_type, assert_union_type, assert_enum_type, assert_input_object_type, assert_list_type, assert_non_null_type, assert_input_type, assert_output_type, assert_leaf_type, assert_composite_type, assert_abstract_type, assert_wrapping_type, assert_nullable_type, assert_named_type, # Un-modifiers get_nullable_type, get_named_type, # Thunk handling resolve_thunk, # Definitions GraphQLScalarType, GraphQLObjectType, GraphQLInterfaceType, GraphQLUnionType, GraphQLEnumType, GraphQLInputObjectType, # Type Wrappers GraphQLList, GraphQLNonNull, # Types GraphQLType, GraphQLInputType, GraphQLOutputType, GraphQLLeafType, GraphQLCompositeType, GraphQLAbstractType, GraphQLWrappingType, GraphQLNullableType, GraphQLNamedType, GraphQLNamedInputType, GraphQLNamedOutputType, Thunk, ThunkCollection, ThunkMapping, GraphQLArgument, GraphQLArgumentMap, GraphQLEnumValue, GraphQLEnumValueMap, GraphQLField, GraphQLFieldMap, GraphQLInputField, GraphQLInputFieldMap, GraphQLScalarSerializer, GraphQLScalarValueParser, GraphQLScalarLiteralParser, # Keyword Args GraphQLArgumentKwargs, GraphQLEnumTypeKwargs, GraphQLEnumValueKwargs, GraphQLFieldKwargs, GraphQLInputFieldKwargs, GraphQLInputObjectTypeKwargs, GraphQLInterfaceTypeKwargs, GraphQLNamedTypeKwargs, GraphQLObjectTypeKwargs, GraphQLScalarTypeKwargs, GraphQLUnionTypeKwargs, # Resolvers GraphQLFieldResolver, GraphQLTypeResolver, GraphQLIsTypeOfFn, GraphQLResolveInfo, ) from .directives import ( # Predicate is_directive, # Assertion assert_directive, # Directives Definition GraphQLDirective, # Built-in Directives defined by the Spec is_specified_directive, specified_directives, GraphQLIncludeDirective, GraphQLSkipDirective, GraphQLDeprecatedDirective, GraphQLSpecifiedByDirective, # Keyword Args GraphQLDirectiveKwargs, # Constant Deprecation Reason DEFAULT_DEPRECATION_REASON, ) # Common built-in scalar instances. from .scalars import ( # Predicate is_specified_scalar_type, # Standard GraphQL Scalars specified_scalar_types, GraphQLInt, GraphQLFloat, GraphQLString, GraphQLBoolean, GraphQLID, # Int boundaries constants GRAPHQL_MAX_INT, GRAPHQL_MIN_INT, ) from .introspection import ( # Predicate is_introspection_type, # GraphQL Types for introspection. introspection_types, # "Enum" of Type Kinds TypeKind, # Meta-field definitions. SchemaMetaFieldDef, TypeMetaFieldDef, TypeNameMetaFieldDef, ) # Validate GraphQL schema. from .validate import validate_schema, assert_valid_schema __all__ = [ "is_schema", "assert_schema", "assert_name", "assert_enum_value_name", "GraphQLSchema", "GraphQLSchemaKwargs", "is_type", "is_scalar_type", "is_object_type", "is_interface_type", "is_union_type", "is_enum_type", "is_input_object_type", "is_list_type", "is_non_null_type", "is_input_type", "is_output_type", "is_leaf_type", "is_composite_type", "is_abstract_type", "is_wrapping_type", "is_nullable_type", "is_named_type", "is_required_argument", "is_required_input_field", "assert_type", "assert_scalar_type", "assert_object_type", "assert_interface_type", "assert_union_type", "assert_enum_type", "assert_input_object_type", "assert_list_type", "assert_non_null_type", "assert_input_type", "assert_output_type", "assert_leaf_type", "assert_composite_type", "assert_abstract_type", "assert_wrapping_type", "assert_nullable_type", "assert_named_type", "get_nullable_type", "get_named_type", "resolve_thunk", "GraphQLScalarType", "GraphQLObjectType", "GraphQLInterfaceType", "GraphQLUnionType", "GraphQLEnumType", "GraphQLInputObjectType", "GraphQLInputType", "GraphQLArgument", "GraphQLList", "GraphQLNonNull", "GraphQLType", "GraphQLInputType", "GraphQLOutputType", "GraphQLLeafType", "GraphQLCompositeType", "GraphQLAbstractType", "GraphQLWrappingType", "GraphQLNullableType", "GraphQLNamedType", "GraphQLNamedInputType", "GraphQLNamedOutputType", "Thunk", "ThunkCollection", "ThunkMapping", "GraphQLArgument", "GraphQLArgumentMap", "GraphQLEnumValue", "GraphQLEnumValueMap", "GraphQLField", "GraphQLFieldMap", "GraphQLInputField", "GraphQLInputFieldMap", "GraphQLScalarSerializer", "GraphQLScalarValueParser", "GraphQLScalarLiteralParser", "GraphQLArgumentKwargs", "GraphQLEnumTypeKwargs", "GraphQLEnumValueKwargs", "GraphQLFieldKwargs", "GraphQLInputFieldKwargs", "GraphQLInputObjectTypeKwargs", "GraphQLInterfaceTypeKwargs", "GraphQLNamedTypeKwargs", "GraphQLObjectTypeKwargs", "GraphQLScalarTypeKwargs", "GraphQLUnionTypeKwargs", "GraphQLFieldResolver", "GraphQLTypeResolver", "GraphQLIsTypeOfFn", "GraphQLResolveInfo", "ResponsePath", "is_directive", "assert_directive", "is_specified_directive", "specified_directives", "GraphQLDirective", "GraphQLIncludeDirective", "GraphQLSkipDirective", "GraphQLDeprecatedDirective", "GraphQLSpecifiedByDirective", "GraphQLDirectiveKwargs", "DEFAULT_DEPRECATION_REASON", "is_specified_scalar_type", "specified_scalar_types", "GraphQLInt", "GraphQLFloat", "GraphQLString", "GraphQLBoolean", "GraphQLID", "GRAPHQL_MAX_INT", "GRAPHQL_MIN_INT", "is_introspection_type", "introspection_types", "TypeKind", "SchemaMetaFieldDef", "TypeMetaFieldDef", "TypeNameMetaFieldDef", "validate_schema", "assert_valid_schema", ] graphql-core-3.2.6/src/graphql/type/assert_name.py000066400000000000000000000020341474546154300222030ustar00rootroot00000000000000from ..error import GraphQLError from ..language.character_classes import is_name_start, is_name_continue __all__ = ["assert_name", "assert_enum_value_name"] def assert_name(name: str) -> str: """Uphold the spec rules about naming.""" if name is None: raise TypeError("Must provide name.") if not isinstance(name, str): raise TypeError("Expected name to be a string.") if not name: raise GraphQLError("Expected name to be a non-empty string.") if not all(is_name_continue(char) for char in name[1:]): raise GraphQLError( f"Names must only contain [_a-zA-Z0-9] but {name!r} does not." ) if not is_name_start(name[0]): raise GraphQLError(f"Names must start with [_a-zA-Z] but {name!r} does not.") return name def assert_enum_value_name(name: str) -> str: """Uphold the spec rules about naming enum values.""" assert_name(name) if name in {"true", "false", "null"}: raise GraphQLError(f"Enum values cannot be named: {name}.") return name graphql-core-3.2.6/src/graphql/type/definition.py000066400000000000000000001770021474546154300220420ustar00rootroot00000000000000from enum import Enum from typing import ( TYPE_CHECKING, Any, Callable, Collection, Dict, Generic, List, Mapping, NamedTuple, Optional, Tuple, Type, TypeVar, Union, cast, overload, ) from ..error import GraphQLError from ..language import ( EnumTypeDefinitionNode, EnumTypeExtensionNode, EnumValueDefinitionNode, EnumValueNode, FieldDefinitionNode, FieldNode, FragmentDefinitionNode, InputObjectTypeDefinitionNode, InputObjectTypeExtensionNode, InputValueDefinitionNode, InterfaceTypeDefinitionNode, InterfaceTypeExtensionNode, ObjectTypeDefinitionNode, ObjectTypeExtensionNode, OperationDefinitionNode, ScalarTypeDefinitionNode, ScalarTypeExtensionNode, TypeDefinitionNode, TypeExtensionNode, UnionTypeDefinitionNode, UnionTypeExtensionNode, ValueNode, print_ast, ) from ..pyutils import ( AwaitableOrValue, Path, Undefined, cached_property, did_you_mean, inspect, is_collection, is_description, suggestion_list, ) from ..utilities.value_from_ast_untyped import value_from_ast_untyped from .assert_name import assert_enum_value_name, assert_name try: from typing import TypedDict except ImportError: # Python < 3.8 from typing_extensions import TypedDict if TYPE_CHECKING: from .schema import GraphQLSchema # noqa: F401 __all__ = [ "is_type", "is_scalar_type", "is_object_type", "is_interface_type", "is_union_type", "is_enum_type", "is_input_object_type", "is_list_type", "is_non_null_type", "is_input_type", "is_output_type", "is_leaf_type", "is_composite_type", "is_abstract_type", "is_wrapping_type", "is_nullable_type", "is_named_type", "is_required_argument", "is_required_input_field", "assert_type", "assert_scalar_type", "assert_object_type", "assert_interface_type", "assert_union_type", "assert_enum_type", "assert_input_object_type", "assert_list_type", "assert_non_null_type", "assert_input_type", "assert_output_type", "assert_leaf_type", "assert_composite_type", "assert_abstract_type", "assert_wrapping_type", "assert_nullable_type", "assert_named_type", "get_nullable_type", "get_named_type", "resolve_thunk", "GraphQLAbstractType", "GraphQLArgument", "GraphQLArgumentKwargs", "GraphQLArgumentMap", "GraphQLCompositeType", "GraphQLEnumType", "GraphQLEnumTypeKwargs", "GraphQLEnumValue", "GraphQLEnumValueKwargs", "GraphQLEnumValueMap", "GraphQLField", "GraphQLFieldKwargs", "GraphQLFieldMap", "GraphQLFieldResolver", "GraphQLInputField", "GraphQLInputFieldKwargs", "GraphQLInputFieldMap", "GraphQLInputObjectType", "GraphQLInputObjectTypeKwargs", "GraphQLInputType", "GraphQLInterfaceType", "GraphQLInterfaceTypeKwargs", "GraphQLIsTypeOfFn", "GraphQLLeafType", "GraphQLList", "GraphQLNamedType", "GraphQLNamedTypeKwargs", "GraphQLNamedInputType", "GraphQLNamedOutputType", "GraphQLNullableType", "GraphQLNonNull", "GraphQLResolveInfo", "GraphQLScalarType", "GraphQLScalarTypeKwargs", "GraphQLScalarSerializer", "GraphQLScalarValueParser", "GraphQLScalarLiteralParser", "GraphQLObjectType", "GraphQLObjectTypeKwargs", "GraphQLOutputType", "GraphQLType", "GraphQLTypeResolver", "GraphQLUnionType", "GraphQLUnionTypeKwargs", "GraphQLWrappingType", "Thunk", "ThunkCollection", "ThunkMapping", ] class GraphQLType: """Base class for all GraphQL types""" # Note: We don't use slots for GraphQLType objects because memory considerations # are not really important for the schema definition and it would make caching # properties slower or more complicated. # There are predicates for each kind of GraphQL type. def is_type(type_: Any) -> bool: return isinstance(type_, GraphQLType) def assert_type(type_: Any) -> GraphQLType: if not is_type(type_): raise TypeError(f"Expected {type_} to be a GraphQL type.") return cast(GraphQLType, type_) # These types wrap and modify other types GT = TypeVar("GT", bound=GraphQLType) class GraphQLWrappingType(GraphQLType, Generic[GT]): """Base class for all GraphQL wrapping types""" of_type: GT def __init__(self, type_: GT) -> None: if not is_type(type_): raise TypeError( f"Can only create a wrapper for a GraphQLType, but got: {type_}." ) self.of_type = type_ def __repr__(self) -> str: return f"<{self.__class__.__name__} {self.of_type!r}>" def is_wrapping_type(type_: Any) -> bool: return isinstance(type_, GraphQLWrappingType) def assert_wrapping_type(type_: Any) -> GraphQLWrappingType: if not is_wrapping_type(type_): raise TypeError(f"Expected {type_} to be a GraphQL wrapping type.") return cast(GraphQLWrappingType, type_) class GraphQLNamedTypeKwargs(TypedDict, total=False): name: str description: Optional[str] extensions: Dict[str, Any] # unfortunately, we cannot make the following more specific, because they are # used by subclasses with different node types and typed dicts cannot be refined ast_node: Optional[Any] extension_ast_nodes: Tuple[Any, ...] class GraphQLNamedType(GraphQLType): """Base class for all GraphQL named types""" name: str description: Optional[str] extensions: Dict[str, Any] ast_node: Optional[TypeDefinitionNode] extension_ast_nodes: Tuple[TypeExtensionNode, ...] def __init__( self, name: str, description: Optional[str] = None, extensions: Optional[Dict[str, Any]] = None, ast_node: Optional[TypeDefinitionNode] = None, extension_ast_nodes: Optional[Collection[TypeExtensionNode]] = None, ) -> None: assert_name(name) if description is not None and not is_description(description): raise TypeError("The description must be a string.") if extensions is None: extensions = {} elif not isinstance(extensions, dict) or not all( isinstance(key, str) for key in extensions ): raise TypeError(f"{name} extensions must be a dictionary with string keys.") if ast_node and not isinstance(ast_node, TypeDefinitionNode): raise TypeError(f"{name} AST node must be a TypeDefinitionNode.") if extension_ast_nodes: if not is_collection(extension_ast_nodes) or not all( isinstance(node, TypeExtensionNode) for node in extension_ast_nodes ): raise TypeError( f"{name} extension AST nodes must be specified" " as a collection of TypeExtensionNode instances." ) if not isinstance(extension_ast_nodes, tuple): extension_ast_nodes = tuple(extension_ast_nodes) else: extension_ast_nodes = () self.name = name self.description = description self.extensions = extensions self.ast_node = ast_node self.extension_ast_nodes = extension_ast_nodes def __repr__(self) -> str: return f"<{self.__class__.__name__} {self.name!r}>" def __str__(self) -> str: return self.name def to_kwargs(self) -> GraphQLNamedTypeKwargs: return GraphQLNamedTypeKwargs( name=self.name, description=self.description, extensions=self.extensions, ast_node=self.ast_node, extension_ast_nodes=self.extension_ast_nodes, ) def __copy__(self) -> "GraphQLNamedType": # pragma: no cover return self.__class__(**self.to_kwargs()) T = TypeVar("T") ThunkCollection = Union[Callable[[], Collection[T]], Collection[T]] ThunkMapping = Union[Callable[[], Mapping[str, T]], Mapping[str, T]] Thunk = Union[Callable[[], T], T] def resolve_thunk(thunk: Thunk[T]) -> T: """Resolve the given thunk. Used while defining GraphQL types to allow for circular references in otherwise immutable type definitions. """ return thunk() if callable(thunk) else thunk GraphQLScalarSerializer = Callable[[Any], Any] GraphQLScalarValueParser = Callable[[Any], Any] GraphQLScalarLiteralParser = Callable[[ValueNode, Optional[Dict[str, Any]]], Any] class GraphQLScalarTypeKwargs(GraphQLNamedTypeKwargs, total=False): serialize: Optional[GraphQLScalarSerializer] parse_value: Optional[GraphQLScalarValueParser] parse_literal: Optional[GraphQLScalarLiteralParser] specified_by_url: Optional[str] class GraphQLScalarType(GraphQLNamedType): """Scalar Type Definition The leaf values of any request and input values to arguments are Scalars (or Enums) and are defined with a name and a series of functions used to parse input from ast or variables and to ensure validity. If a type's serialize function returns ``None``, then an error will be raised and a ``None`` value will be returned in the response. It is always better to validate. Example:: def serialize_odd(value: Any) -> int: try: value = int(value) except ValueError: raise GraphQLError( f"Scalar 'Odd' cannot represent '{value}'" " since it is not an integer.") if not value % 2: raise GraphQLError( f"Scalar 'Odd' cannot represent '{value}' since it is even.") return value odd_type = GraphQLScalarType('Odd', serialize=serialize_odd) """ specified_by_url: Optional[str] ast_node: Optional[ScalarTypeDefinitionNode] extension_ast_nodes: Tuple[ScalarTypeExtensionNode, ...] def __init__( self, name: str, serialize: Optional[GraphQLScalarSerializer] = None, parse_value: Optional[GraphQLScalarValueParser] = None, parse_literal: Optional[GraphQLScalarLiteralParser] = None, description: Optional[str] = None, specified_by_url: Optional[str] = None, extensions: Optional[Dict[str, Any]] = None, ast_node: Optional[ScalarTypeDefinitionNode] = None, extension_ast_nodes: Optional[Collection[ScalarTypeExtensionNode]] = None, ) -> None: super().__init__( name=name, description=description, extensions=extensions, ast_node=ast_node, extension_ast_nodes=extension_ast_nodes, ) if specified_by_url is not None and not isinstance(specified_by_url, str): raise TypeError( f"{name} must provide 'specified_by_url' as a string," f" but got: {inspect(specified_by_url)}." ) if serialize is not None and not callable(serialize): raise TypeError( f"{name} must provide 'serialize' as a function." " If this custom Scalar is also used as an input type," " ensure 'parse_value' and 'parse_literal' functions" " are also provided." ) if parse_literal is not None and ( not callable(parse_literal) or (parse_value is None or not callable(parse_value)) ): raise TypeError( f"{name} must provide" " both 'parse_value' and 'parse_literal' as functions." ) if ast_node and not isinstance(ast_node, ScalarTypeDefinitionNode): raise TypeError(f"{name} AST node must be a ScalarTypeDefinitionNode.") if extension_ast_nodes and not all( isinstance(node, ScalarTypeExtensionNode) for node in extension_ast_nodes ): raise TypeError( f"{name} extension AST nodes must be specified" " as a collection of ScalarTypeExtensionNode instances." ) if serialize is not None: self.serialize = serialize # type: ignore if parse_value is not None: self.parse_value = parse_value # type: ignore if parse_literal is not None: self.parse_literal = parse_literal # type: ignore self.specified_by_url = specified_by_url def __repr__(self) -> str: return f"<{self.__class__.__name__} {self.name!r}>" def __str__(self) -> str: return self.name @staticmethod def serialize(value: Any) -> Any: """Serializes an internal value to include in a response. This default method just passes the value through and should be replaced with a more specific version when creating a scalar type. """ return value @staticmethod def parse_value(value: Any) -> Any: """Parses an externally provided value to use as an input. This default method just passes the value through and should be replaced with a more specific version when creating a scalar type. """ return value def parse_literal( self, node: ValueNode, variables: Optional[Dict[str, Any]] = None ) -> Any: """Parses an externally provided literal value to use as an input. This default method uses the parse_value method and should be replaced with a more specific version when creating a scalar type. """ return self.parse_value(value_from_ast_untyped(node, variables)) def to_kwargs(self) -> GraphQLScalarTypeKwargs: # noinspection PyArgumentList return GraphQLScalarTypeKwargs( # type: ignore super().to_kwargs(), serialize=( None if self.serialize is GraphQLScalarType.serialize else self.serialize ), parse_value=( None if self.parse_value is GraphQLScalarType.parse_value else self.parse_value ), parse_literal=( None if getattr(self.parse_literal, "__func__", None) is GraphQLScalarType.parse_literal else self.parse_literal ), specified_by_url=self.specified_by_url, ) def __copy__(self) -> "GraphQLScalarType": # pragma: no cover return self.__class__(**self.to_kwargs()) def is_scalar_type(type_: Any) -> bool: return isinstance(type_, GraphQLScalarType) def assert_scalar_type(type_: Any) -> GraphQLScalarType: if not is_scalar_type(type_): raise TypeError(f"Expected {type_} to be a GraphQL Scalar type.") return cast(GraphQLScalarType, type_) GraphQLArgumentMap = Dict[str, "GraphQLArgument"] class GraphQLFieldKwargs(TypedDict, total=False): type_: "GraphQLOutputType" args: Optional[GraphQLArgumentMap] resolve: Optional["GraphQLFieldResolver"] subscribe: Optional["GraphQLFieldResolver"] description: Optional[str] deprecation_reason: Optional[str] extensions: Dict[str, Any] ast_node: Optional[FieldDefinitionNode] class GraphQLField: """Definition of a GraphQL field""" type: "GraphQLOutputType" args: GraphQLArgumentMap resolve: Optional["GraphQLFieldResolver"] subscribe: Optional["GraphQLFieldResolver"] description: Optional[str] deprecation_reason: Optional[str] extensions: Dict[str, Any] ast_node: Optional[FieldDefinitionNode] def __init__( self, type_: "GraphQLOutputType", args: Optional[GraphQLArgumentMap] = None, resolve: Optional["GraphQLFieldResolver"] = None, subscribe: Optional["GraphQLFieldResolver"] = None, description: Optional[str] = None, deprecation_reason: Optional[str] = None, extensions: Optional[Dict[str, Any]] = None, ast_node: Optional[FieldDefinitionNode] = None, ) -> None: if not is_output_type(type_): raise TypeError("Field type must be an output type.") if args is None: args = {} elif not isinstance(args, dict): raise TypeError("Field args must be a dict with argument names as keys.") elif not all( isinstance(value, GraphQLArgument) or is_input_type(value) for value in args.values() ): raise TypeError( "Field args must be GraphQLArguments or input type objects." ) else: args = { assert_name(name): ( value if isinstance(value, GraphQLArgument) else GraphQLArgument(cast(GraphQLInputType, value)) ) for name, value in args.items() } if resolve is not None and not callable(resolve): raise TypeError( "Field resolver must be a function if provided, " f" but got: {inspect(resolve)}." ) if description is not None and not is_description(description): raise TypeError("The description must be a string.") if deprecation_reason is not None and not is_description(deprecation_reason): raise TypeError("The deprecation reason must be a string.") if extensions is None: extensions = {} elif not isinstance(extensions, dict) or not all( isinstance(key, str) for key in extensions ): raise TypeError("Field extensions must be a dictionary with string keys.") if ast_node and not isinstance(ast_node, FieldDefinitionNode): raise TypeError("Field AST node must be a FieldDefinitionNode.") self.type = type_ self.args = args or {} self.resolve = resolve self.subscribe = subscribe self.description = description self.deprecation_reason = deprecation_reason self.extensions = extensions self.ast_node = ast_node def __repr__(self) -> str: return f"<{self.__class__.__name__} {self.type!r}>" def __str__(self) -> str: return f"Field: {self.type}" def __eq__(self, other: Any) -> bool: return self is other or ( isinstance(other, GraphQLField) and self.type == other.type and self.args == other.args and self.resolve == other.resolve and self.description == other.description and self.deprecation_reason == other.deprecation_reason and self.extensions == other.extensions ) def to_kwargs(self) -> GraphQLFieldKwargs: return GraphQLFieldKwargs( type_=self.type, args=self.args.copy() if self.args else None, resolve=self.resolve, subscribe=self.subscribe, deprecation_reason=self.deprecation_reason, description=self.description, extensions=self.extensions, ast_node=self.ast_node, ) def __copy__(self) -> "GraphQLField": # pragma: no cover return self.__class__(**self.to_kwargs()) class GraphQLResolveInfo(NamedTuple): """Collection of information passed to the resolvers. This is always passed as the first argument to the resolvers. Note that contrary to the JavaScript implementation, the context (commonly used to represent an authenticated user, or request-specific caches) is included here and not passed as an additional argument. """ field_name: str field_nodes: List[FieldNode] return_type: "GraphQLOutputType" parent_type: "GraphQLObjectType" path: Path schema: "GraphQLSchema" fragments: Dict[str, FragmentDefinitionNode] root_value: Any operation: OperationDefinitionNode variable_values: Dict[str, Any] context: Any is_awaitable: Callable[[Any], bool] # Note: Contrary to the Javascript implementation of GraphQLFieldResolver, # the context is passed as part of the GraphQLResolveInfo and any arguments # are passed individually as keyword arguments. GraphQLFieldResolverWithoutArgs = Callable[[Any, GraphQLResolveInfo], Any] # Unfortunately there is currently no syntax to indicate optional or keyword # arguments in Python, so we also allow any other Callable as a workaround: GraphQLFieldResolver = Callable[..., Any] # Note: Contrary to the Javascript implementation of GraphQLTypeResolver, # the context is passed as part of the GraphQLResolveInfo: GraphQLTypeResolver = Callable[ [Any, GraphQLResolveInfo, "GraphQLAbstractType"], AwaitableOrValue[Optional[str]], ] # Note: Contrary to the Javascript implementation of GraphQLIsTypeOfFn, # the context is passed as part of the GraphQLResolveInfo: GraphQLIsTypeOfFn = Callable[[Any, GraphQLResolveInfo], AwaitableOrValue[bool]] GraphQLFieldMap = Dict[str, GraphQLField] class GraphQLArgumentKwargs(TypedDict, total=False): type_: "GraphQLInputType" default_value: Any description: Optional[str] deprecation_reason: Optional[str] out_name: Optional[str] extensions: Dict[str, Any] ast_node: Optional[InputValueDefinitionNode] class GraphQLArgument: """Definition of a GraphQL argument""" type: "GraphQLInputType" default_value: Any description: Optional[str] deprecation_reason: Optional[str] out_name: Optional[str] # for transforming names (extension of GraphQL.js) extensions: Dict[str, Any] ast_node: Optional[InputValueDefinitionNode] def __init__( self, type_: "GraphQLInputType", default_value: Any = Undefined, description: Optional[str] = None, deprecation_reason: Optional[str] = None, out_name: Optional[str] = None, extensions: Optional[Dict[str, Any]] = None, ast_node: Optional[InputValueDefinitionNode] = None, ) -> None: if not is_input_type(type_): raise TypeError("Argument type must be a GraphQL input type.") if description is not None and not is_description(description): raise TypeError("Argument description must be a string.") if deprecation_reason is not None and not is_description(deprecation_reason): raise TypeError("Argument deprecation reason must be a string.") if out_name is not None and not isinstance(out_name, str): raise TypeError("Argument out name must be a string.") if extensions is None: extensions = {} elif not isinstance(extensions, dict) or not all( isinstance(key, str) for key in extensions ): raise TypeError( "Argument extensions must be a dictionary with string keys." ) if ast_node and not isinstance(ast_node, InputValueDefinitionNode): raise TypeError("Argument AST node must be an InputValueDefinitionNode.") self.type = type_ self.default_value = default_value self.description = description self.deprecation_reason = deprecation_reason self.out_name = out_name self.extensions = extensions self.ast_node = ast_node def __eq__(self, other: Any) -> bool: return self is other or ( isinstance(other, GraphQLArgument) and self.type == other.type and self.default_value == other.default_value and self.description == other.description and self.deprecation_reason == other.deprecation_reason and self.out_name == other.out_name and self.extensions == other.extensions ) def to_kwargs(self) -> GraphQLArgumentKwargs: return GraphQLArgumentKwargs( type_=self.type, default_value=self.default_value, description=self.description, deprecation_reason=self.deprecation_reason, out_name=self.out_name, extensions=self.extensions, ast_node=self.ast_node, ) def __copy__(self) -> "GraphQLArgument": # pragma: no cover return self.__class__(**self.to_kwargs()) def is_required_argument(arg: GraphQLArgument) -> bool: return is_non_null_type(arg.type) and arg.default_value is Undefined class GraphQLObjectTypeKwargs(GraphQLNamedTypeKwargs, total=False): fields: GraphQLFieldMap interfaces: Tuple["GraphQLInterfaceType", ...] is_type_of: Optional[GraphQLIsTypeOfFn] class GraphQLObjectType(GraphQLNamedType): """Object Type Definition Almost all the GraphQL types you define will be object types. Object types have a name, but most importantly describe their fields. Example:: AddressType = GraphQLObjectType('Address', { 'street': GraphQLField(GraphQLString), 'number': GraphQLField(GraphQLInt), 'formatted': GraphQLField(GraphQLString, lambda obj, info, **args: f'{obj.number} {obj.street}') }) When two types need to refer to each other, or a type needs to refer to itself in a field, you can use a lambda function with no arguments (a so-called "thunk") to supply the fields lazily. Example:: PersonType = GraphQLObjectType('Person', lambda: { 'name': GraphQLField(GraphQLString), 'bestFriend': GraphQLField(PersonType) }) """ is_type_of: Optional[GraphQLIsTypeOfFn] ast_node: Optional[ObjectTypeDefinitionNode] extension_ast_nodes: Tuple[ObjectTypeExtensionNode, ...] def __init__( self, name: str, fields: ThunkMapping[GraphQLField], interfaces: Optional[ThunkCollection["GraphQLInterfaceType"]] = None, is_type_of: Optional[GraphQLIsTypeOfFn] = None, extensions: Optional[Dict[str, Any]] = None, description: Optional[str] = None, ast_node: Optional[ObjectTypeDefinitionNode] = None, extension_ast_nodes: Optional[Collection[ObjectTypeExtensionNode]] = None, ) -> None: super().__init__( name=name, description=description, extensions=extensions, ast_node=ast_node, extension_ast_nodes=extension_ast_nodes, ) if is_type_of is not None and not callable(is_type_of): raise TypeError( f"{name} must provide 'is_type_of' as a function," f" but got: {inspect(is_type_of)}." ) if ast_node and not isinstance(ast_node, ObjectTypeDefinitionNode): raise TypeError(f"{name} AST node must be an ObjectTypeDefinitionNode.") if extension_ast_nodes and not all( isinstance(node, ObjectTypeExtensionNode) for node in extension_ast_nodes ): raise TypeError( f"{name} extension AST nodes must be specified" " as a collection of ObjectTypeExtensionNode instances." ) self._fields = fields self._interfaces = interfaces self.is_type_of = is_type_of def to_kwargs(self) -> GraphQLObjectTypeKwargs: # noinspection PyArgumentList return GraphQLObjectTypeKwargs( # type: ignore super().to_kwargs(), fields=self.fields.copy(), interfaces=self.interfaces, is_type_of=self.is_type_of, ) def __copy__(self) -> "GraphQLObjectType": # pragma: no cover return self.__class__(**self.to_kwargs()) @cached_property def fields(self) -> GraphQLFieldMap: """Get provided fields, wrapping them as GraphQLFields if needed.""" try: fields = resolve_thunk(self._fields) except Exception as error: cls = GraphQLError if isinstance(error, GraphQLError) else TypeError raise cls(f"{self.name} fields cannot be resolved. {error}") from error if not isinstance(fields, Mapping) or not all( isinstance(key, str) for key in fields ): raise TypeError( f"{self.name} fields must be specified" " as a mapping with field names as keys." ) if not all( isinstance(value, GraphQLField) or is_output_type(value) for value in fields.values() ): raise TypeError( f"{self.name} fields must be GraphQLField or output type objects." ) return { assert_name(name): ( value if isinstance(value, GraphQLField) else GraphQLField(value) # type: ignore ) for name, value in fields.items() } @cached_property def interfaces(self) -> Tuple["GraphQLInterfaceType", ...]: """Get provided interfaces.""" try: interfaces: Collection["GraphQLInterfaceType"] = resolve_thunk( self._interfaces # type: ignore ) except Exception as error: cls = GraphQLError if isinstance(error, GraphQLError) else TypeError raise cls(f"{self.name} interfaces cannot be resolved. {error}") from error if interfaces is None: interfaces = () elif not is_collection(interfaces) or not all( isinstance(value, GraphQLInterfaceType) for value in interfaces ): raise TypeError( f"{self.name} interfaces must be specified" " as a collection of GraphQLInterfaceType instances." ) return tuple(interfaces) def is_object_type(type_: Any) -> bool: return isinstance(type_, GraphQLObjectType) def assert_object_type(type_: Any) -> GraphQLObjectType: if not is_object_type(type_): raise TypeError(f"Expected {type_} to be a GraphQL Object type.") return cast(GraphQLObjectType, type_) class GraphQLInterfaceTypeKwargs(GraphQLNamedTypeKwargs, total=False): fields: GraphQLFieldMap interfaces: Tuple["GraphQLInterfaceType", ...] resolve_type: Optional[GraphQLTypeResolver] class GraphQLInterfaceType(GraphQLNamedType): """Interface Type Definition When a field can return one of a heterogeneous set of types, an Interface type is used to describe what types are possible, what fields are in common across all types, as well as a function to determine which type is actually used when the field is resolved. Example:: EntityType = GraphQLInterfaceType('Entity', { 'name': GraphQLField(GraphQLString), }) """ resolve_type: Optional[GraphQLTypeResolver] ast_node: Optional[InterfaceTypeDefinitionNode] extension_ast_nodes: Tuple[InterfaceTypeExtensionNode, ...] def __init__( self, name: str, fields: ThunkMapping[GraphQLField], interfaces: Optional[ThunkCollection["GraphQLInterfaceType"]] = None, resolve_type: Optional[GraphQLTypeResolver] = None, description: Optional[str] = None, extensions: Optional[Dict[str, Any]] = None, ast_node: Optional[InterfaceTypeDefinitionNode] = None, extension_ast_nodes: Optional[Collection[InterfaceTypeExtensionNode]] = None, ) -> None: super().__init__( name=name, description=description, extensions=extensions, ast_node=ast_node, extension_ast_nodes=extension_ast_nodes, ) if resolve_type is not None and not callable(resolve_type): raise TypeError( f"{name} must provide 'resolve_type' as a function," f" but got: {inspect(resolve_type)}." ) if ast_node and not isinstance(ast_node, InterfaceTypeDefinitionNode): raise TypeError(f"{name} AST node must be an InterfaceTypeDefinitionNode.") if extension_ast_nodes and not all( isinstance(node, InterfaceTypeExtensionNode) for node in extension_ast_nodes ): raise TypeError( f"{name} extension AST nodes must be specified" " as a collection of InterfaceTypeExtensionNode instances." ) self._fields = fields self._interfaces = interfaces self.resolve_type = resolve_type def to_kwargs(self) -> GraphQLInterfaceTypeKwargs: # noinspection PyArgumentList return GraphQLInterfaceTypeKwargs( # type: ignore super().to_kwargs(), fields=self.fields.copy(), interfaces=self.interfaces, resolve_type=self.resolve_type, ) def __copy__(self) -> "GraphQLInterfaceType": # pragma: no cover return self.__class__(**self.to_kwargs()) @cached_property def fields(self) -> GraphQLFieldMap: """Get provided fields, wrapping them as GraphQLFields if needed.""" try: fields = resolve_thunk(self._fields) except Exception as error: cls = GraphQLError if isinstance(error, GraphQLError) else TypeError raise cls(f"{self.name} fields cannot be resolved. {error}") from error if not isinstance(fields, Mapping) or not all( isinstance(key, str) for key in fields ): raise TypeError( f"{self.name} fields must be specified" " as a mapping with field names as keys." ) if not all( isinstance(value, GraphQLField) or is_output_type(value) for value in fields.values() ): raise TypeError( f"{self.name} fields must be GraphQLField or output type objects." ) return { assert_name(name): ( value if isinstance(value, GraphQLField) else GraphQLField(value) # type: ignore ) for name, value in fields.items() } @cached_property def interfaces(self) -> Tuple["GraphQLInterfaceType", ...]: """Get provided interfaces.""" try: interfaces: Collection["GraphQLInterfaceType"] = resolve_thunk( self._interfaces # type: ignore ) except Exception as error: cls = GraphQLError if isinstance(error, GraphQLError) else TypeError raise cls(f"{self.name} interfaces cannot be resolved. {error}") from error if interfaces is None: interfaces = () elif not is_collection(interfaces) or not all( isinstance(value, GraphQLInterfaceType) for value in interfaces ): raise TypeError( f"{self.name} interfaces must be specified" " as a collection of GraphQLInterfaceType instances." ) return tuple(interfaces) def is_interface_type(type_: Any) -> bool: return isinstance(type_, GraphQLInterfaceType) def assert_interface_type(type_: Any) -> GraphQLInterfaceType: if not is_interface_type(type_): raise TypeError(f"Expected {type_} to be a GraphQL Interface type.") return cast(GraphQLInterfaceType, type_) class GraphQLUnionTypeKwargs(GraphQLNamedTypeKwargs, total=False): types: Tuple[GraphQLObjectType, ...] resolve_type: Optional[GraphQLTypeResolver] class GraphQLUnionType(GraphQLNamedType): """Union Type Definition When a field can return one of a heterogeneous set of types, a Union type is used to describe what types are possible as well as providing a function to determine which type is actually used when the field is resolved. Example:: def resolve_type(obj, _info, _type): if isinstance(obj, Dog): return DogType() if isinstance(obj, Cat): return CatType() PetType = GraphQLUnionType('Pet', [DogType, CatType], resolve_type) """ resolve_type: Optional[GraphQLTypeResolver] ast_node: Optional[UnionTypeDefinitionNode] extension_ast_nodes: Tuple[UnionTypeExtensionNode, ...] def __init__( self, name: str, types: ThunkCollection[GraphQLObjectType], resolve_type: Optional[GraphQLTypeResolver] = None, description: Optional[str] = None, extensions: Optional[Dict[str, Any]] = None, ast_node: Optional[UnionTypeDefinitionNode] = None, extension_ast_nodes: Optional[Collection[UnionTypeExtensionNode]] = None, ) -> None: super().__init__( name=name, description=description, extensions=extensions, ast_node=ast_node, extension_ast_nodes=extension_ast_nodes, ) if resolve_type is not None and not callable(resolve_type): raise TypeError( f"{name} must provide 'resolve_type' as a function," f" but got: {inspect(resolve_type)}." ) if ast_node and not isinstance(ast_node, UnionTypeDefinitionNode): raise TypeError(f"{name} AST node must be a UnionTypeDefinitionNode.") if extension_ast_nodes and not all( isinstance(node, UnionTypeExtensionNode) for node in extension_ast_nodes ): raise TypeError( f"{name} extension AST nodes must be specified" " as a collection of UnionTypeExtensionNode instances." ) self._types = types self.resolve_type = resolve_type def to_kwargs(self) -> GraphQLUnionTypeKwargs: # noinspection PyArgumentList return GraphQLUnionTypeKwargs( # type: ignore super().to_kwargs(), types=self.types, resolve_type=self.resolve_type ) def __copy__(self) -> "GraphQLUnionType": # pragma: no cover return self.__class__(**self.to_kwargs()) @cached_property def types(self) -> Tuple[GraphQLObjectType, ...]: """Get provided types.""" try: types: Collection[GraphQLObjectType] = resolve_thunk(self._types) except Exception as error: cls = GraphQLError if isinstance(error, GraphQLError) else TypeError raise cls(f"{self.name} types cannot be resolved. {error}") from error if types is None: types = () elif not is_collection(types) or not all( isinstance(value, GraphQLObjectType) for value in types ): raise TypeError( f"{self.name} types must be specified" " as a collection of GraphQLObjectType instances." ) return tuple(types) def is_union_type(type_: Any) -> bool: return isinstance(type_, GraphQLUnionType) def assert_union_type(type_: Any) -> GraphQLUnionType: if not is_union_type(type_): raise TypeError(f"Expected {type_} to be a GraphQL Union type.") return cast(GraphQLUnionType, type_) GraphQLEnumValueMap = Dict[str, "GraphQLEnumValue"] class GraphQLEnumTypeKwargs(GraphQLNamedTypeKwargs, total=False): values: GraphQLEnumValueMap names_as_values: Optional[bool] class GraphQLEnumType(GraphQLNamedType): """Enum Type Definition Some leaf values of requests and input values are Enums. GraphQL serializes Enum values as strings, however internally Enums can be represented by any kind of type, often integers. They can also be provided as a Python Enum. In this case, the flag `names_as_values` determines what will be used as internal representation. The default value of `False` will use the enum values, the value `True` will use the enum names, and the value `None` will use the members themselves. Example:: RGBType = GraphQLEnumType('RGB', { 'RED': 0, 'GREEN': 1, 'BLUE': 2 }) Example using a Python Enum:: class RGBEnum(enum.Enum): RED = 0 GREEN = 1 BLUE = 2 RGBType = GraphQLEnumType('RGB', enum.Enum) Instead of raw values, you can also specify GraphQLEnumValue objects with more detail like description or deprecation information. Note: If a value is not provided in a definition, the name of the enum value will be used as its internal value when the value is serialized. """ values: GraphQLEnumValueMap ast_node: Optional[EnumTypeDefinitionNode] extension_ast_nodes: Tuple[EnumTypeExtensionNode, ...] def __init__( self, name: str, values: Union[GraphQLEnumValueMap, Mapping[str, Any], Type[Enum]], names_as_values: Optional[bool] = False, description: Optional[str] = None, extensions: Optional[Dict[str, Any]] = None, ast_node: Optional[EnumTypeDefinitionNode] = None, extension_ast_nodes: Optional[Collection[EnumTypeExtensionNode]] = None, ) -> None: super().__init__( name=name, description=description, extensions=extensions, ast_node=ast_node, extension_ast_nodes=extension_ast_nodes, ) try: # check for enum values = cast(Enum, values).__members__ # type: ignore except AttributeError: if not isinstance(values, Mapping) or not all( isinstance(name, str) for name in values ): try: # noinspection PyTypeChecker values = dict(values) except (TypeError, ValueError) as error: raise TypeError( f"{name} values must be an Enum or a mapping" " with value names as keys." ) from error values = cast(Dict[str, Any], values) else: values = cast(Dict[str, Enum], values) if names_as_values is False: values = {key: value.value for key, value in values.items()} elif names_as_values is True: values = {key: key for key in values} values = { assert_enum_value_name(key): ( value if isinstance(value, GraphQLEnumValue) else GraphQLEnumValue(value) ) for key, value in values.items() } if ast_node and not isinstance(ast_node, EnumTypeDefinitionNode): raise TypeError(f"{name} AST node must be an EnumTypeDefinitionNode.") if extension_ast_nodes and not all( isinstance(node, EnumTypeExtensionNode) for node in extension_ast_nodes ): raise TypeError( f"{name} extension AST nodes must be specified" " as a collection of EnumTypeExtensionNode instances." ) self.values = values def to_kwargs(self) -> GraphQLEnumTypeKwargs: # noinspection PyArgumentList return GraphQLEnumTypeKwargs( # type: ignore super().to_kwargs(), values=self.values.copy() ) def __copy__(self) -> "GraphQLEnumType": # pragma: no cover return self.__class__(**self.to_kwargs()) @cached_property def _value_lookup(self) -> Dict[Any, str]: # use first value or name as lookup lookup: Dict[Any, str] = {} for name, enum_value in self.values.items(): value = enum_value.value if value is None or value is Undefined: value = name try: if value not in lookup: lookup[value] = name except TypeError: pass # ignore unhashable values return lookup def serialize(self, output_value: Any) -> str: try: return self._value_lookup[output_value] except KeyError: # hashable value not found pass except TypeError: # unhashable value, we need to scan all values for enum_name, enum_value in self.values.items(): if enum_value.value == output_value: return enum_name raise GraphQLError( f"Enum '{self.name}' cannot represent value: {inspect(output_value)}" ) def parse_value(self, input_value: str) -> Any: if isinstance(input_value, str): try: enum_value = self.values[input_value] except KeyError: raise GraphQLError( f"Value '{input_value}' does not exist in '{self.name}' enum." + did_you_mean_enum_value(self, input_value) ) return enum_value.value value_str = inspect(input_value) raise GraphQLError( f"Enum '{self.name}' cannot represent non-string value: {value_str}." + did_you_mean_enum_value(self, value_str) ) def parse_literal( self, value_node: ValueNode, _variables: Optional[Dict[str, Any]] = None ) -> Any: # Note: variables will be resolved before calling this method. if isinstance(value_node, EnumValueNode): try: enum_value = self.values[value_node.value] except KeyError: value_str = print_ast(value_node) raise GraphQLError( f"Value '{value_str}' does not exist in '{self.name}' enum." + did_you_mean_enum_value(self, value_str), value_node, ) return enum_value.value value_str = print_ast(value_node) raise GraphQLError( f"Enum '{self.name}' cannot represent non-enum value: {value_str}." + did_you_mean_enum_value(self, value_str), value_node, ) def is_enum_type(type_: Any) -> bool: return isinstance(type_, GraphQLEnumType) def assert_enum_type(type_: Any) -> GraphQLEnumType: if not is_enum_type(type_): raise TypeError(f"Expected {type_} to be a GraphQL Enum type.") return cast(GraphQLEnumType, type_) def did_you_mean_enum_value(enum_type: GraphQLEnumType, unknown_value_str: str) -> str: suggested_values = suggestion_list(unknown_value_str, enum_type.values) return did_you_mean(suggested_values, "the enum value") class GraphQLEnumValueKwargs(TypedDict, total=False): value: Any description: Optional[str] deprecation_reason: Optional[str] extensions: Dict[str, Any] ast_node: Optional[EnumValueDefinitionNode] class GraphQLEnumValue: value: Any description: Optional[str] deprecation_reason: Optional[str] extensions: Dict[str, Any] ast_node: Optional[EnumValueDefinitionNode] def __init__( self, value: Any = None, description: Optional[str] = None, deprecation_reason: Optional[str] = None, extensions: Optional[Dict[str, Any]] = None, ast_node: Optional[EnumValueDefinitionNode] = None, ) -> None: if description is not None and not is_description(description): raise TypeError("The description of the enum value must be a string.") if deprecation_reason is not None and not is_description(deprecation_reason): raise TypeError( "The deprecation reason for the enum value must be a string." ) if extensions is None: extensions = {} elif not isinstance(extensions, dict) or not all( isinstance(key, str) for key in extensions ): raise TypeError( "Enum value extensions must be a dictionary with string keys." ) if ast_node and not isinstance(ast_node, EnumValueDefinitionNode): raise TypeError("AST node must be an EnumValueDefinitionNode.") self.value = value self.description = description self.deprecation_reason = deprecation_reason self.extensions = extensions self.ast_node = ast_node def __eq__(self, other: Any) -> bool: return self is other or ( isinstance(other, GraphQLEnumValue) and self.value == other.value and self.description == other.description and self.deprecation_reason == other.deprecation_reason and self.extensions == other.extensions ) def to_kwargs(self) -> GraphQLEnumValueKwargs: return GraphQLEnumValueKwargs( value=self.value, description=self.description, deprecation_reason=self.deprecation_reason, extensions=self.extensions, ast_node=self.ast_node, ) def __copy__(self) -> "GraphQLEnumValue": # pragma: no cover return self.__class__(**self.to_kwargs()) GraphQLInputFieldMap = Dict[str, "GraphQLInputField"] GraphQLInputFieldOutType = Callable[[Dict[str, Any]], Any] class GraphQLInputObjectTypeKwargs(GraphQLNamedTypeKwargs, total=False): fields: GraphQLInputFieldMap out_type: Optional[GraphQLInputFieldOutType] class GraphQLInputObjectType(GraphQLNamedType): """Input Object Type Definition An input object defines a structured collection of fields which may be supplied to a field argument. Using ``NonNull`` will ensure that a value must be provided by the query. Example:: NonNullFloat = GraphQLNonNull(GraphQLFloat) class GeoPoint(GraphQLInputObjectType): name = 'GeoPoint' fields = { 'lat': GraphQLInputField(NonNullFloat), 'lon': GraphQLInputField(NonNullFloat), 'alt': GraphQLInputField( GraphQLFloat, default_value=0) } The outbound values will be Python dictionaries by default, but you can have them converted to other types by specifying an ``out_type`` function or class. """ ast_node: Optional[InputObjectTypeDefinitionNode] extension_ast_nodes: Tuple[InputObjectTypeExtensionNode, ...] def __init__( self, name: str, fields: ThunkMapping["GraphQLInputField"], description: Optional[str] = None, out_type: Optional[GraphQLInputFieldOutType] = None, extensions: Optional[Dict[str, Any]] = None, ast_node: Optional[InputObjectTypeDefinitionNode] = None, extension_ast_nodes: Optional[Collection[InputObjectTypeExtensionNode]] = None, ) -> None: super().__init__( name=name, description=description, extensions=extensions, ast_node=ast_node, extension_ast_nodes=extension_ast_nodes, ) if out_type is not None and not callable(out_type): raise TypeError(f"The out type for {name} must be a function or a class.") if ast_node and not isinstance(ast_node, InputObjectTypeDefinitionNode): raise TypeError( f"{name} AST node must be an InputObjectTypeDefinitionNode." ) if extension_ast_nodes and not all( isinstance(node, InputObjectTypeExtensionNode) for node in extension_ast_nodes ): raise TypeError( f"{name} extension AST nodes must be specified" " as a collection of InputObjectTypeExtensionNode instances." ) self._fields = fields if out_type is not None: self.out_type = out_type # type: ignore @staticmethod def out_type(value: Dict[str, Any]) -> Any: """Transform outbound values (this is an extension of GraphQL.js). This default implementation passes values unaltered as dictionaries. """ return value def to_kwargs(self) -> GraphQLInputObjectTypeKwargs: # noinspection PyArgumentList return GraphQLInputObjectTypeKwargs( # type: ignore super().to_kwargs(), fields=self.fields.copy(), out_type=( None if self.out_type is GraphQLInputObjectType.out_type else self.out_type ), ) def __copy__(self) -> "GraphQLInputObjectType": # pragma: no cover return self.__class__(**self.to_kwargs()) @cached_property def fields(self) -> GraphQLInputFieldMap: """Get provided fields, wrap them as GraphQLInputField if needed.""" try: fields = resolve_thunk(self._fields) except Exception as error: cls = GraphQLError if isinstance(error, GraphQLError) else TypeError raise cls(f"{self.name} fields cannot be resolved. {error}") from error if not isinstance(fields, Mapping) or not all( isinstance(key, str) for key in fields ): raise TypeError( f"{self.name} fields must be specified" " as a mapping with field names as keys." ) if not all( isinstance(value, GraphQLInputField) or is_input_type(value) for value in fields.values() ): raise TypeError( f"{self.name} fields must be" " GraphQLInputField or input type objects." ) return { assert_name(name): ( value if isinstance(value, GraphQLInputField) else GraphQLInputField(value) # type: ignore ) for name, value in fields.items() } def is_input_object_type(type_: Any) -> bool: return isinstance(type_, GraphQLInputObjectType) def assert_input_object_type(type_: Any) -> GraphQLInputObjectType: if not is_input_object_type(type_): raise TypeError(f"Expected {type_} to be a GraphQL Input Object type.") return cast(GraphQLInputObjectType, type_) class GraphQLInputFieldKwargs(TypedDict, total=False): type_: "GraphQLInputType" default_value: Any description: Optional[str] deprecation_reason: Optional[str] out_name: Optional[str] extensions: Dict[str, Any] ast_node: Optional[InputValueDefinitionNode] class GraphQLInputField: """Definition of a GraphQL input field""" type: "GraphQLInputType" default_value: Any description: Optional[str] deprecation_reason: Optional[str] out_name: Optional[str] # for transforming names (extension of GraphQL.js) extensions: Dict[str, Any] ast_node: Optional[InputValueDefinitionNode] def __init__( self, type_: "GraphQLInputType", default_value: Any = Undefined, description: Optional[str] = None, deprecation_reason: Optional[str] = None, out_name: Optional[str] = None, extensions: Optional[Dict[str, Any]] = None, ast_node: Optional[InputValueDefinitionNode] = None, ) -> None: if not is_input_type(type_): raise TypeError("Input field type must be a GraphQL input type.") if description is not None and not is_description(description): raise TypeError("Input field description must be a string.") if deprecation_reason is not None and not is_description(deprecation_reason): raise TypeError("Input field deprecation reason must be a string.") if out_name is not None and not isinstance(out_name, str): raise TypeError("Input field out name must be a string.") if extensions is None: extensions = {} elif not isinstance(extensions, dict) or not all( isinstance(key, str) for key in extensions ): raise TypeError( "Input field extensions must be a dictionary with string keys." ) if ast_node and not isinstance(ast_node, InputValueDefinitionNode): raise TypeError("Input field AST node must be an InputValueDefinitionNode.") self.type = type_ self.default_value = default_value self.description = description self.deprecation_reason = deprecation_reason self.out_name = out_name self.extensions = extensions self.ast_node = ast_node def __eq__(self, other: Any) -> bool: return self is other or ( isinstance(other, GraphQLInputField) and self.type == other.type and self.default_value == other.default_value and self.description == other.description and self.deprecation_reason == other.deprecation_reason and self.extensions == other.extensions and self.out_name == other.out_name ) def to_kwargs(self) -> GraphQLInputFieldKwargs: return GraphQLInputFieldKwargs( type_=self.type, default_value=self.default_value, description=self.description, deprecation_reason=self.deprecation_reason, out_name=self.out_name, extensions=self.extensions, ast_node=self.ast_node, ) def __copy__(self) -> "GraphQLInputField": # pragma: no cover return self.__class__(**self.to_kwargs()) def is_required_input_field(field: GraphQLInputField) -> bool: return is_non_null_type(field.type) and field.default_value is Undefined # Wrapper types class GraphQLList(Generic[GT], GraphQLWrappingType[GT]): """List Type Wrapper A list is a wrapping type which points to another type. Lists are often created within the context of defining the fields of an object type. Example:: class PersonType(GraphQLObjectType): name = 'Person' @property def fields(self): return { 'parents': GraphQLField(GraphQLList(PersonType())), 'children': GraphQLField(GraphQLList(PersonType())), } """ def __init__(self, type_: GT) -> None: super().__init__(type_=type_) def __str__(self) -> str: return f"[{self.of_type}]" def is_list_type(type_: Any) -> bool: return isinstance(type_, GraphQLList) def assert_list_type(type_: Any) -> GraphQLList: if not is_list_type(type_): raise TypeError(f"Expected {type_} to be a GraphQL List type.") return cast(GraphQLList, type_) GNT = TypeVar("GNT", bound="GraphQLNullableType") class GraphQLNonNull(GraphQLWrappingType[GNT], Generic[GNT]): """Non-Null Type Wrapper A non-null is a wrapping type which points to another type. Non-null types enforce that their values are never null and can ensure an error is raised if this ever occurs during a request. It is useful for fields which you can make a strong guarantee on non-nullability, for example usually the id field of a database row will never be null. Example:: class RowType(GraphQLObjectType): name = 'Row' fields = { 'id': GraphQLField(GraphQLNonNull(GraphQLString)) } Note: the enforcement of non-nullability occurs within the executor. """ def __init__(self, type_: GNT): super().__init__(type_=type_) if isinstance(type_, GraphQLNonNull): raise TypeError( "Can only create NonNull of a Nullable GraphQLType but got:" f" {type_}." ) def __str__(self) -> str: return f"{self.of_type}!" def is_non_null_type(type_: Any) -> bool: return isinstance(type_, GraphQLNonNull) def assert_non_null_type(type_: Any) -> GraphQLNonNull: if not is_non_null_type(type_): raise TypeError(f"Expected {type_} to be a GraphQL Non-Null type.") return cast(GraphQLNonNull, type_) # These types can all accept null as a value. graphql_nullable_types = ( GraphQLScalarType, GraphQLObjectType, GraphQLInterfaceType, GraphQLUnionType, GraphQLEnumType, GraphQLInputObjectType, GraphQLList, ) GraphQLNullableType = Union[ GraphQLScalarType, GraphQLObjectType, GraphQLInterfaceType, GraphQLUnionType, GraphQLEnumType, GraphQLInputObjectType, GraphQLList, ] def is_nullable_type(type_: Any) -> bool: return isinstance(type_, graphql_nullable_types) def assert_nullable_type(type_: Any) -> GraphQLNullableType: if not is_nullable_type(type_): raise TypeError(f"Expected {type_} to be a GraphQL nullable type.") return cast(GraphQLNullableType, type_) @overload def get_nullable_type(type_: None) -> None: ... @overload def get_nullable_type(type_: GraphQLNullableType) -> GraphQLNullableType: ... @overload def get_nullable_type(type_: GraphQLNonNull) -> GraphQLNullableType: ... def get_nullable_type( type_: Optional[Union[GraphQLNullableType, GraphQLNonNull]] ) -> Optional[GraphQLNullableType]: """Unwrap possible non-null type""" if is_non_null_type(type_): type_ = cast(GraphQLNonNull, type_) type_ = type_.of_type return cast(Optional[GraphQLNullableType], type_) # These types may be used as input types for arguments and directives. graphql_input_types = (GraphQLScalarType, GraphQLEnumType, GraphQLInputObjectType) GraphQLInputType = Union[ GraphQLScalarType, GraphQLEnumType, GraphQLInputObjectType, GraphQLWrappingType ] def is_input_type(type_: Any) -> bool: return isinstance(type_, graphql_input_types) or ( isinstance(type_, GraphQLWrappingType) and is_input_type(type_.of_type) ) def assert_input_type(type_: Any) -> GraphQLInputType: if not is_input_type(type_): raise TypeError(f"Expected {type_} to be a GraphQL input type.") return cast(GraphQLInputType, type_) # These types may be used as output types as the result of fields. graphql_output_types = ( GraphQLScalarType, GraphQLObjectType, GraphQLInterfaceType, GraphQLUnionType, GraphQLEnumType, ) GraphQLOutputType = Union[ GraphQLScalarType, GraphQLObjectType, GraphQLInterfaceType, GraphQLUnionType, GraphQLEnumType, GraphQLWrappingType, ] def is_output_type(type_: Any) -> bool: return isinstance(type_, graphql_output_types) or ( isinstance(type_, GraphQLWrappingType) and is_output_type(type_.of_type) ) def assert_output_type(type_: Any) -> GraphQLOutputType: if not is_output_type(type_): raise TypeError(f"Expected {type_} to be a GraphQL output type.") return cast(GraphQLOutputType, type_) # These named types do not include modifiers like List or NonNull. GraphQLNamedInputType = Union[ GraphQLScalarType, GraphQLEnumType, GraphQLInputObjectType ] GraphQLNamedOutputType = Union[ GraphQLScalarType, GraphQLObjectType, GraphQLInterfaceType, GraphQLUnionType, GraphQLEnumType, ] def is_named_type(type_: Any) -> bool: return isinstance(type_, GraphQLNamedType) def assert_named_type(type_: Any) -> GraphQLNamedType: if not is_named_type(type_): raise TypeError(f"Expected {type_} to be a GraphQL named type.") return cast(GraphQLNamedType, type_) @overload def get_named_type(type_: None) -> None: ... @overload def get_named_type(type_: GraphQLType) -> GraphQLNamedType: ... def get_named_type(type_: Optional[GraphQLType]) -> Optional[GraphQLNamedType]: """Unwrap possible wrapping type""" if type_: unwrapped_type = type_ while is_wrapping_type(unwrapped_type): unwrapped_type = cast(GraphQLWrappingType, unwrapped_type) unwrapped_type = unwrapped_type.of_type return cast(GraphQLNamedType, unwrapped_type) return None # These types may describe types which may be leaf values. graphql_leaf_types = (GraphQLScalarType, GraphQLEnumType) GraphQLLeafType = Union[GraphQLScalarType, GraphQLEnumType] def is_leaf_type(type_: Any) -> bool: return isinstance(type_, graphql_leaf_types) def assert_leaf_type(type_: Any) -> GraphQLLeafType: if not is_leaf_type(type_): raise TypeError(f"Expected {type_} to be a GraphQL leaf type.") return cast(GraphQLLeafType, type_) # These types may describe the parent context of a selection set. graphql_composite_types = (GraphQLObjectType, GraphQLInterfaceType, GraphQLUnionType) GraphQLCompositeType = Union[GraphQLObjectType, GraphQLInterfaceType, GraphQLUnionType] def is_composite_type(type_: Any) -> bool: return isinstance(type_, graphql_composite_types) def assert_composite_type(type_: Any) -> GraphQLType: if not is_composite_type(type_): raise TypeError(f"Expected {type_} to be a GraphQL composite type.") return cast(GraphQLType, type_) # These types may describe abstract types. graphql_abstract_types = (GraphQLInterfaceType, GraphQLUnionType) GraphQLAbstractType = Union[GraphQLInterfaceType, GraphQLUnionType] def is_abstract_type(type_: Any) -> bool: return isinstance(type_, graphql_abstract_types) def assert_abstract_type(type_: Any) -> GraphQLAbstractType: if not is_abstract_type(type_): raise TypeError(f"Expected {type_} to be a GraphQL composite type.") return cast(GraphQLAbstractType, type_) graphql-core-3.2.6/src/graphql/type/directives.py000066400000000000000000000206341474546154300220510ustar00rootroot00000000000000from typing import Any, Collection, Dict, Optional, Tuple, cast from ..language import DirectiveLocation, ast from ..pyutils import inspect, is_description from .assert_name import assert_name from .definition import GraphQLArgument, GraphQLInputType, GraphQLNonNull, is_input_type from .scalars import GraphQLBoolean, GraphQLString try: from typing import TypedDict except ImportError: # Python < 3.8 from typing_extensions import TypedDict __all__ = [ "is_directive", "assert_directive", "is_specified_directive", "specified_directives", "GraphQLDirective", "GraphQLDirectiveKwargs", "GraphQLIncludeDirective", "GraphQLSkipDirective", "GraphQLDeprecatedDirective", "GraphQLSpecifiedByDirective", "DirectiveLocation", "DEFAULT_DEPRECATION_REASON", ] class GraphQLDirectiveKwargs(TypedDict, total=False): name: str locations: Tuple[DirectiveLocation, ...] args: Dict[str, GraphQLArgument] is_repeatable: bool description: Optional[str] extensions: Dict[str, Any] ast_node: Optional[ast.DirectiveDefinitionNode] class GraphQLDirective: """GraphQL Directive Directives are used by the GraphQL runtime as a way of modifying execution behavior. Type system creators will usually not create these directly. """ name: str locations: Tuple[DirectiveLocation, ...] is_repeatable: bool args: Dict[str, GraphQLArgument] description: Optional[str] extensions: Dict[str, Any] ast_node: Optional[ast.DirectiveDefinitionNode] def __init__( self, name: str, locations: Collection[DirectiveLocation], args: Optional[Dict[str, GraphQLArgument]] = None, is_repeatable: bool = False, description: Optional[str] = None, extensions: Optional[Dict[str, Any]] = None, ast_node: Optional[ast.DirectiveDefinitionNode] = None, ) -> None: assert_name(name) try: locations = tuple( ( value if isinstance(value, DirectiveLocation) else DirectiveLocation[cast(str, value)] ) for value in locations ) except (KeyError, TypeError): raise TypeError( f"{name} locations must be specified" " as a collection of DirectiveLocation enum values." ) if args is None: args = {} elif not isinstance(args, dict) or not all( isinstance(key, str) for key in args ): raise TypeError(f"{name} args must be a dict with argument names as keys.") elif not all( isinstance(value, GraphQLArgument) or is_input_type(value) for value in args.values() ): raise TypeError( f"{name} args must be GraphQLArgument or input type objects." ) else: args = { assert_name(name): ( value if isinstance(value, GraphQLArgument) else GraphQLArgument(cast(GraphQLInputType, value)) ) for name, value in args.items() } if not isinstance(is_repeatable, bool): raise TypeError(f"{name} is_repeatable flag must be True or False.") if ast_node and not isinstance(ast_node, ast.DirectiveDefinitionNode): raise TypeError(f"{name} AST node must be a DirectiveDefinitionNode.") if description is not None and not is_description(description): raise TypeError(f"{name} description must be a string.") if extensions is None: extensions = {} elif not isinstance(extensions, dict) or not all( isinstance(key, str) for key in extensions ): raise TypeError(f"{name} extensions must be a dictionary with string keys.") self.name = name self.locations = locations self.args = args self.is_repeatable = is_repeatable self.description = description self.extensions = extensions self.ast_node = ast_node def __str__(self) -> str: return f"@{self.name}" def __repr__(self) -> str: return f"<{self.__class__.__name__}({self})>" def __eq__(self, other: Any) -> bool: return self is other or ( isinstance(other, GraphQLDirective) and self.name == other.name and self.locations == other.locations and self.args == other.args and self.is_repeatable == other.is_repeatable and self.description == other.description and self.extensions == other.extensions ) def to_kwargs(self) -> GraphQLDirectiveKwargs: return GraphQLDirectiveKwargs( name=self.name, locations=self.locations, args=self.args, is_repeatable=self.is_repeatable, description=self.description, extensions=self.extensions, ast_node=self.ast_node, ) def __copy__(self) -> "GraphQLDirective": # pragma: no cover return self.__class__(**self.to_kwargs()) def is_directive(directive: Any) -> bool: """Test if the given value is a GraphQL directive.""" return isinstance(directive, GraphQLDirective) def assert_directive(directive: Any) -> GraphQLDirective: if not is_directive(directive): raise TypeError(f"Expected {inspect(directive)} to be a GraphQL directive.") return cast(GraphQLDirective, directive) # Used to conditionally include fields or fragments. GraphQLIncludeDirective = GraphQLDirective( name="include", locations=[ DirectiveLocation.FIELD, DirectiveLocation.FRAGMENT_SPREAD, DirectiveLocation.INLINE_FRAGMENT, ], args={ "if": GraphQLArgument( GraphQLNonNull(GraphQLBoolean), description="Included when true." ) }, description="Directs the executor to include this field or fragment" " only when the `if` argument is true.", ) # Used to conditionally skip (exclude) fields or fragments: GraphQLSkipDirective = GraphQLDirective( name="skip", locations=[ DirectiveLocation.FIELD, DirectiveLocation.FRAGMENT_SPREAD, DirectiveLocation.INLINE_FRAGMENT, ], args={ "if": GraphQLArgument( GraphQLNonNull(GraphQLBoolean), description="Skipped when true." ) }, description="Directs the executor to skip this field or fragment" " when the `if` argument is true.", ) # Constant string used for default reason for a deprecation: DEFAULT_DEPRECATION_REASON = "No longer supported" # Used to declare element of a GraphQL schema as deprecated: GraphQLDeprecatedDirective = GraphQLDirective( name="deprecated", locations=[ DirectiveLocation.FIELD_DEFINITION, DirectiveLocation.ARGUMENT_DEFINITION, DirectiveLocation.INPUT_FIELD_DEFINITION, DirectiveLocation.ENUM_VALUE, ], args={ "reason": GraphQLArgument( GraphQLString, description="Explains why this element was deprecated," " usually also including a suggestion for how to access" " supported similar data." " Formatted using the Markdown syntax, as specified by" " [CommonMark](https://commonmark.org/).", default_value=DEFAULT_DEPRECATION_REASON, ) }, description="Marks an element of a GraphQL schema as no longer supported.", ) # Used to provide a URL for specifying the behavior of custom scalar definitions: GraphQLSpecifiedByDirective = GraphQLDirective( name="specifiedBy", locations=[DirectiveLocation.SCALAR], args={ "url": GraphQLArgument( GraphQLNonNull(GraphQLString), description="The URL that specifies the behavior of this scalar.", ) }, description="Exposes a URL that specifies the behavior of this scalar.", ) specified_directives: Tuple[GraphQLDirective, ...] = ( GraphQLIncludeDirective, GraphQLSkipDirective, GraphQLDeprecatedDirective, GraphQLSpecifiedByDirective, ) """A tuple with all directives from the GraphQL specification""" def is_specified_directive(directive: GraphQLDirective) -> bool: """Check whether the given directive is one of the specified directives.""" return any( specified_directive.name == directive.name for specified_directive in specified_directives ) graphql-core-3.2.6/src/graphql/type/introspection.py000066400000000000000000000512531474546154300226110ustar00rootroot00000000000000from enum import Enum from typing import Mapping from .definition import ( GraphQLArgument, GraphQLEnumType, GraphQLEnumValue, GraphQLField, GraphQLList, GraphQLNamedType, GraphQLNonNull, GraphQLObjectType, is_abstract_type, is_enum_type, is_input_object_type, is_interface_type, is_list_type, is_non_null_type, is_object_type, is_scalar_type, is_union_type, ) from ..language import DirectiveLocation, print_ast from ..pyutils import inspect from .scalars import GraphQLBoolean, GraphQLString __all__ = [ "SchemaMetaFieldDef", "TypeKind", "TypeMetaFieldDef", "TypeNameMetaFieldDef", "introspection_types", "is_introspection_type", ] __Schema: GraphQLObjectType = GraphQLObjectType( name="__Schema", description="A GraphQL Schema defines the capabilities of a GraphQL" " server. It exposes all available types and directives" " on the server, as well as the entry points for query," " mutation, and subscription operations.", fields=lambda: { "description": GraphQLField( GraphQLString, resolve=lambda schema, _info: schema.description ), "types": GraphQLField( GraphQLNonNull(GraphQLList(GraphQLNonNull(__Type))), resolve=lambda schema, _info: schema.type_map.values(), description="A list of all types supported by this server.", ), "queryType": GraphQLField( GraphQLNonNull(__Type), resolve=lambda schema, _info: schema.query_type, description="The type that query operations will be rooted at.", ), "mutationType": GraphQLField( __Type, resolve=lambda schema, _info: schema.mutation_type, description="If this server supports mutation, the type that" " mutation operations will be rooted at.", ), "subscriptionType": GraphQLField( __Type, resolve=lambda schema, _info: schema.subscription_type, description="If this server support subscription, the type that" " subscription operations will be rooted at.", ), "directives": GraphQLField( GraphQLNonNull(GraphQLList(GraphQLNonNull(__Directive))), resolve=lambda schema, _info: schema.directives, description="A list of all directives supported by this server.", ), }, ) __Directive: GraphQLObjectType = GraphQLObjectType( name="__Directive", description="A Directive provides a way to describe alternate runtime" " execution and type validation behavior in a GraphQL" " document.\n\nIn some cases, you need to provide options" " to alter GraphQL's execution behavior in ways field" " arguments will not suffice, such as conditionally including" " or skipping a field. Directives provide this by describing" " additional information to the executor.", fields=lambda: { # Note: The fields onOperation, onFragment and onField are deprecated "name": GraphQLField( GraphQLNonNull(GraphQLString), resolve=DirectiveResolvers.name, ), "description": GraphQLField( GraphQLString, resolve=DirectiveResolvers.description, ), "isRepeatable": GraphQLField( GraphQLNonNull(GraphQLBoolean), resolve=DirectiveResolvers.is_repeatable, ), "locations": GraphQLField( GraphQLNonNull(GraphQLList(GraphQLNonNull(__DirectiveLocation))), resolve=DirectiveResolvers.locations, ), "args": GraphQLField( GraphQLNonNull(GraphQLList(GraphQLNonNull(__InputValue))), args={ "includeDeprecated": GraphQLArgument( GraphQLBoolean, default_value=False ) }, resolve=DirectiveResolvers.args, ), }, ) class DirectiveResolvers: @staticmethod def name(directive, _info): return directive.name @staticmethod def description(directive, _info): return directive.description @staticmethod def is_repeatable(directive, _info): return directive.is_repeatable @staticmethod def locations(directive, _info): return directive.locations # noinspection PyPep8Naming @staticmethod def args(directive, _info, includeDeprecated=False): items = directive.args.items() return ( list(items) if includeDeprecated else [item for item in items if item[1].deprecation_reason is None] ) __DirectiveLocation: GraphQLEnumType = GraphQLEnumType( name="__DirectiveLocation", description="A Directive can be adjacent to many parts of the GraphQL" " language, a __DirectiveLocation describes one such possible" " adjacencies.", values={ "QUERY": GraphQLEnumValue( DirectiveLocation.QUERY, description="Location adjacent to a query operation.", ), "MUTATION": GraphQLEnumValue( DirectiveLocation.MUTATION, description="Location adjacent to a mutation operation.", ), "SUBSCRIPTION": GraphQLEnumValue( DirectiveLocation.SUBSCRIPTION, description="Location adjacent to a subscription operation.", ), "FIELD": GraphQLEnumValue( DirectiveLocation.FIELD, description="Location adjacent to a field." ), "FRAGMENT_DEFINITION": GraphQLEnumValue( DirectiveLocation.FRAGMENT_DEFINITION, description="Location adjacent to a fragment definition.", ), "FRAGMENT_SPREAD": GraphQLEnumValue( DirectiveLocation.FRAGMENT_SPREAD, description="Location adjacent to a fragment spread.", ), "INLINE_FRAGMENT": GraphQLEnumValue( DirectiveLocation.INLINE_FRAGMENT, description="Location adjacent to an inline fragment.", ), "VARIABLE_DEFINITION": GraphQLEnumValue( DirectiveLocation.VARIABLE_DEFINITION, description="Location adjacent to a variable definition.", ), "SCHEMA": GraphQLEnumValue( DirectiveLocation.SCHEMA, description="Location adjacent to a schema definition.", ), "SCALAR": GraphQLEnumValue( DirectiveLocation.SCALAR, description="Location adjacent to a scalar definition.", ), "OBJECT": GraphQLEnumValue( DirectiveLocation.OBJECT, description="Location adjacent to an object type definition.", ), "FIELD_DEFINITION": GraphQLEnumValue( DirectiveLocation.FIELD_DEFINITION, description="Location adjacent to a field definition.", ), "ARGUMENT_DEFINITION": GraphQLEnumValue( DirectiveLocation.ARGUMENT_DEFINITION, description="Location adjacent to an argument definition.", ), "INTERFACE": GraphQLEnumValue( DirectiveLocation.INTERFACE, description="Location adjacent to an interface definition.", ), "UNION": GraphQLEnumValue( DirectiveLocation.UNION, description="Location adjacent to a union definition.", ), "ENUM": GraphQLEnumValue( DirectiveLocation.ENUM, description="Location adjacent to an enum definition.", ), "ENUM_VALUE": GraphQLEnumValue( DirectiveLocation.ENUM_VALUE, description="Location adjacent to an enum value definition.", ), "INPUT_OBJECT": GraphQLEnumValue( DirectiveLocation.INPUT_OBJECT, description="Location adjacent to an input object type definition.", ), "INPUT_FIELD_DEFINITION": GraphQLEnumValue( DirectiveLocation.INPUT_FIELD_DEFINITION, description="Location adjacent to an input object field definition.", ), }, ) __Type: GraphQLObjectType = GraphQLObjectType( name="__Type", description="The fundamental unit of any GraphQL Schema is the type." " There are many kinds of types in GraphQL as represented" " by the `__TypeKind` enum.\n\nDepending on the kind of a" " type, certain fields describe information about that type." " Scalar types provide no information beyond a name, description" " and optional `specifiedByURL`, while Enum types provide their values." " Object and Interface types provide the fields they describe." " Abstract types, Union and Interface, provide the Object" " types possible at runtime. List and NonNull types compose" " other types.", fields=lambda: { "kind": GraphQLField(GraphQLNonNull(__TypeKind), resolve=TypeResolvers.kind), "name": GraphQLField(GraphQLString, resolve=TypeResolvers.name), "description": GraphQLField(GraphQLString, resolve=TypeResolvers.description), "specifiedByURL": GraphQLField( GraphQLString, resolve=TypeResolvers.specified_by_url ), "fields": GraphQLField( GraphQLList(GraphQLNonNull(__Field)), args={ "includeDeprecated": GraphQLArgument( GraphQLBoolean, default_value=False ) }, resolve=TypeResolvers.fields, ), "interfaces": GraphQLField( GraphQLList(GraphQLNonNull(__Type)), resolve=TypeResolvers.interfaces ), "possibleTypes": GraphQLField( GraphQLList(GraphQLNonNull(__Type)), resolve=TypeResolvers.possible_types, ), "enumValues": GraphQLField( GraphQLList(GraphQLNonNull(__EnumValue)), args={ "includeDeprecated": GraphQLArgument( GraphQLBoolean, default_value=False ) }, resolve=TypeResolvers.enum_values, ), "inputFields": GraphQLField( GraphQLList(GraphQLNonNull(__InputValue)), args={ "includeDeprecated": GraphQLArgument( GraphQLBoolean, default_value=False ) }, resolve=TypeResolvers.input_fields, ), "ofType": GraphQLField(__Type, resolve=TypeResolvers.of_type), }, ) class TypeResolvers: @staticmethod def kind(type_, _info): if is_scalar_type(type_): return TypeKind.SCALAR if is_object_type(type_): return TypeKind.OBJECT if is_interface_type(type_): return TypeKind.INTERFACE if is_union_type(type_): return TypeKind.UNION if is_enum_type(type_): return TypeKind.ENUM if is_input_object_type(type_): return TypeKind.INPUT_OBJECT if is_list_type(type_): return TypeKind.LIST if is_non_null_type(type_): return TypeKind.NON_NULL # Not reachable. All possible types have been considered. raise TypeError(f"Unexpected type: {inspect(type_)}.") # pragma: no cover @staticmethod def name(type_, _info): return getattr(type_, "name", None) @staticmethod def description(type_, _info): return getattr(type_, "description", None) @staticmethod def specified_by_url(type_, _info): return getattr(type_, "specified_by_url", None) # noinspection PyPep8Naming @staticmethod def fields(type_, _info, includeDeprecated=False): if is_object_type(type_) or is_interface_type(type_): items = type_.fields.items() return ( list(items) if includeDeprecated else [item for item in items if item[1].deprecation_reason is None] ) @staticmethod def interfaces(type_, _info): if is_object_type(type_) or is_interface_type(type_): return type_.interfaces @staticmethod def possible_types(type_, info): if is_abstract_type(type_): return info.schema.get_possible_types(type_) # noinspection PyPep8Naming @staticmethod def enum_values(type_, _info, includeDeprecated=False): if is_enum_type(type_): items = type_.values.items() return ( items if includeDeprecated else [item for item in items if item[1].deprecation_reason is None] ) # noinspection PyPep8Naming @staticmethod def input_fields(type_, _info, includeDeprecated=False): if is_input_object_type(type_): items = type_.fields.items() return ( items if includeDeprecated else [item for item in items if item[1].deprecation_reason is None] ) @staticmethod def of_type(type_, _info): return getattr(type_, "of_type", None) __Field: GraphQLObjectType = GraphQLObjectType( name="__Field", description="Object and Interface types are described by a list of Fields," " each of which has a name, potentially a list of arguments," " and a return type.", fields=lambda: { "name": GraphQLField( GraphQLNonNull(GraphQLString), resolve=FieldResolvers.name ), "description": GraphQLField(GraphQLString, resolve=FieldResolvers.description), "args": GraphQLField( GraphQLNonNull(GraphQLList(GraphQLNonNull(__InputValue))), args={ "includeDeprecated": GraphQLArgument( GraphQLBoolean, default_value=False ) }, resolve=FieldResolvers.args, ), "type": GraphQLField(GraphQLNonNull(__Type), resolve=FieldResolvers.type), "isDeprecated": GraphQLField( GraphQLNonNull(GraphQLBoolean), resolve=FieldResolvers.is_deprecated, ), "deprecationReason": GraphQLField( GraphQLString, resolve=FieldResolvers.deprecation_reason ), }, ) class FieldResolvers: @staticmethod def name(item, _info): return item[0] @staticmethod def description(item, _info): return item[1].description # noinspection PyPep8Naming @staticmethod def args(item, _info, includeDeprecated=False): items = item[1].args.items() return ( items if includeDeprecated else [item for item in items if item[1].deprecation_reason is None] ) @staticmethod def type(item, _info): return item[1].type @staticmethod def is_deprecated(item, _info): return item[1].deprecation_reason is not None @staticmethod def deprecation_reason(item, _info): return item[1].deprecation_reason __InputValue: GraphQLObjectType = GraphQLObjectType( name="__InputValue", description="Arguments provided to Fields or Directives and the input" " fields of an InputObject are represented as Input Values" " which describe their type and optionally a default value.", fields=lambda: { "name": GraphQLField( GraphQLNonNull(GraphQLString), resolve=InputValueFieldResolvers.name ), "description": GraphQLField( GraphQLString, resolve=InputValueFieldResolvers.description ), "type": GraphQLField( GraphQLNonNull(__Type), resolve=InputValueFieldResolvers.type ), "defaultValue": GraphQLField( GraphQLString, description="A GraphQL-formatted string representing" " the default value for this input value.", resolve=InputValueFieldResolvers.default_value, ), "isDeprecated": GraphQLField( GraphQLNonNull(GraphQLBoolean), resolve=InputValueFieldResolvers.is_deprecated, ), "deprecationReason": GraphQLField( GraphQLString, resolve=InputValueFieldResolvers.deprecation_reason ), }, ) class InputValueFieldResolvers: @staticmethod def name(item, _info): return item[0] @staticmethod def description(item, _info): return item[1].description @staticmethod def type(item, _info): return item[1].type @staticmethod def default_value(item, _info): # Since ast_from_value needs graphql.type, it can only be imported later from ..utilities import ast_from_value value_ast = ast_from_value(item[1].default_value, item[1].type) return print_ast(value_ast) if value_ast else None @staticmethod def is_deprecated(item, _info): return item[1].deprecation_reason is not None @staticmethod def deprecation_reason(item, _info): return item[1].deprecation_reason __EnumValue: GraphQLObjectType = GraphQLObjectType( name="__EnumValue", description="One possible value for a given Enum. Enum values are unique" " values, not a placeholder for a string or numeric value." " However an Enum value is returned in a JSON response as a" " string.", fields=lambda: { "name": GraphQLField( GraphQLNonNull(GraphQLString), resolve=lambda item, _info: item[0] ), "description": GraphQLField( GraphQLString, resolve=lambda item, _info: item[1].description ), "isDeprecated": GraphQLField( GraphQLNonNull(GraphQLBoolean), resolve=lambda item, _info: item[1].deprecation_reason is not None, ), "deprecationReason": GraphQLField( GraphQLString, resolve=lambda item, _info: item[1].deprecation_reason ), }, ) class TypeKind(Enum): SCALAR = "scalar" OBJECT = "object" INTERFACE = "interface" UNION = "union" ENUM = "enum" INPUT_OBJECT = "input object" LIST = "list" NON_NULL = "non-null" __TypeKind: GraphQLEnumType = GraphQLEnumType( name="__TypeKind", description="An enum describing what kind of type a given `__Type` is.", values={ "SCALAR": GraphQLEnumValue( TypeKind.SCALAR, description="Indicates this type is a scalar." ), "OBJECT": GraphQLEnumValue( TypeKind.OBJECT, description="Indicates this type is an object." " `fields` and `interfaces` are valid fields.", ), "INTERFACE": GraphQLEnumValue( TypeKind.INTERFACE, description="Indicates this type is an interface." " `fields`, `interfaces`, and `possibleTypes` are valid fields.", ), "UNION": GraphQLEnumValue( TypeKind.UNION, description="Indicates this type is a union." " `possibleTypes` is a valid field.", ), "ENUM": GraphQLEnumValue( TypeKind.ENUM, description="Indicates this type is an enum." " `enumValues` is a valid field.", ), "INPUT_OBJECT": GraphQLEnumValue( TypeKind.INPUT_OBJECT, description="Indicates this type is an input object." " `inputFields` is a valid field.", ), "LIST": GraphQLEnumValue( TypeKind.LIST, description="Indicates this type is a list. `ofType` is a valid field.", ), "NON_NULL": GraphQLEnumValue( TypeKind.NON_NULL, description="Indicates this type is a non-null." " `ofType` is a valid field.", ), }, ) SchemaMetaFieldDef = GraphQLField( GraphQLNonNull(__Schema), # name = '__schema' description="Access the current type schema of this server.", args={}, resolve=lambda _source, info: info.schema, ) TypeMetaFieldDef = GraphQLField( __Type, # name = '__type' description="Request the type information of a single type.", args={"name": GraphQLArgument(GraphQLNonNull(GraphQLString))}, resolve=lambda _source, info, **args: info.schema.get_type(args["name"]), ) TypeNameMetaFieldDef = GraphQLField( GraphQLNonNull(GraphQLString), # name='__typename' description="The name of the current Object type at runtime.", args={}, resolve=lambda _source, info, **_args: info.parent_type.name, ) # Since double underscore names are subject to name mangling in Python, # the introspection classes are best imported via this dictionary: introspection_types: Mapping[str, GraphQLNamedType] = { # treat as read-only "__Schema": __Schema, "__Directive": __Directive, "__DirectiveLocation": __DirectiveLocation, "__Type": __Type, "__Field": __Field, "__InputValue": __InputValue, "__EnumValue": __EnumValue, "__TypeKind": __TypeKind, } """A mapping containing all introspection types with their names as keys""" def is_introspection_type(type_: GraphQLNamedType) -> bool: """Check whether the given named GraphQL type is an introspection type.""" return type_.name in introspection_types graphql-core-3.2.6/src/graphql/type/scalars.py000066400000000000000000000245261474546154300213440ustar00rootroot00000000000000from math import isfinite from typing import Any, Mapping from ..error import GraphQLError from ..pyutils import inspect from ..language.ast import ( BooleanValueNode, FloatValueNode, IntValueNode, StringValueNode, ValueNode, ) from ..language.printer import print_ast from .definition import GraphQLNamedType, GraphQLScalarType __all__ = [ "is_specified_scalar_type", "specified_scalar_types", "GraphQLInt", "GraphQLFloat", "GraphQLString", "GraphQLBoolean", "GraphQLID", "GRAPHQL_MAX_INT", "GRAPHQL_MIN_INT", ] # As per the GraphQL Spec, Integers are only treated as valid # when they can be represented as a 32-bit signed integer, # providing the broadest support across platforms. # n.b. JavaScript's numbers are safe between -(2^53 - 1) and 2^53 - 1 # because they are internally represented as IEEE 754 doubles, # while Python's integers may be arbitrarily large. GRAPHQL_MAX_INT = 2_147_483_647 """Maximum possible Int value as per GraphQL Spec (32-bit signed integer)""" GRAPHQL_MIN_INT = -2_147_483_648 """Minimum possible Int value as per GraphQL Spec (32-bit signed integer)""" def serialize_int(output_value: Any) -> int: if isinstance(output_value, bool): return 1 if output_value else 0 try: if isinstance(output_value, int): num = output_value elif isinstance(output_value, float): num = int(output_value) if num != output_value: raise ValueError elif not output_value and isinstance(output_value, str): output_value = "" raise ValueError else: num = int(output_value) # raises ValueError if not an integer except (OverflowError, ValueError, TypeError): raise GraphQLError( "Int cannot represent non-integer value: " + inspect(output_value) ) if not GRAPHQL_MIN_INT <= num <= GRAPHQL_MAX_INT: raise GraphQLError( "Int cannot represent non 32-bit signed integer value: " + inspect(output_value) ) return num def coerce_int(input_value: Any) -> int: if not ( isinstance(input_value, int) and not isinstance(input_value, bool) ) and not ( isinstance(input_value, float) and isfinite(input_value) and int(input_value) == input_value ): raise GraphQLError( "Int cannot represent non-integer value: " + inspect(input_value) ) if not GRAPHQL_MIN_INT <= input_value <= GRAPHQL_MAX_INT: raise GraphQLError( "Int cannot represent non 32-bit signed integer value: " + inspect(input_value) ) return int(input_value) def parse_int_literal(value_node: ValueNode, _variables: Any = None) -> int: """Parse an integer value node in the AST.""" if not isinstance(value_node, IntValueNode): raise GraphQLError( "Int cannot represent non-integer value: " + print_ast(value_node), value_node, ) num = int(value_node.value) if not GRAPHQL_MIN_INT <= num <= GRAPHQL_MAX_INT: raise GraphQLError( "Int cannot represent non 32-bit signed integer value: " + print_ast(value_node), value_node, ) return num GraphQLInt = GraphQLScalarType( name="Int", description="The `Int` scalar type represents" " non-fractional signed whole numeric values." " Int can represent values between -(2^31) and 2^31 - 1.", serialize=serialize_int, parse_value=coerce_int, parse_literal=parse_int_literal, ) def serialize_float(output_value: Any) -> float: if isinstance(output_value, bool): return 1 if output_value else 0 try: if not output_value and isinstance(output_value, str): output_value = "" raise ValueError num = output_value if isinstance(output_value, float) else float(output_value) if not isfinite(num): raise ValueError except (ValueError, TypeError): raise GraphQLError( "Float cannot represent non numeric value: " + inspect(output_value) ) return num def coerce_float(input_value: Any) -> float: if not ( isinstance(input_value, int) and not isinstance(input_value, bool) ) and not (isinstance(input_value, float) and isfinite(input_value)): raise GraphQLError( "Float cannot represent non numeric value: " + inspect(input_value) ) return float(input_value) def parse_float_literal(value_node: ValueNode, _variables: Any = None) -> float: """Parse a float value node in the AST.""" if not isinstance(value_node, (FloatValueNode, IntValueNode)): raise GraphQLError( "Float cannot represent non numeric value: " + print_ast(value_node), value_node, ) return float(value_node.value) GraphQLFloat = GraphQLScalarType( name="Float", description="The `Float` scalar type represents" " signed double-precision fractional values" " as specified by [IEEE 754]" "(https://en.wikipedia.org/wiki/IEEE_floating_point).", serialize=serialize_float, parse_value=coerce_float, parse_literal=parse_float_literal, ) def serialize_string(output_value: Any) -> str: if isinstance(output_value, str): return output_value if isinstance(output_value, bool): return "true" if output_value else "false" if isinstance(output_value, int) or ( isinstance(output_value, float) and isfinite(output_value) ): return str(output_value) # do not serialize builtin types as strings, but allow serialization of custom # types via their `__str__` method if type(output_value).__module__ == "builtins": raise GraphQLError("String cannot represent value: " + inspect(output_value)) return str(output_value) def coerce_string(input_value: Any) -> str: if not isinstance(input_value, str): raise GraphQLError( "String cannot represent a non string value: " + inspect(input_value) ) return input_value def parse_string_literal(value_node: ValueNode, _variables: Any = None) -> str: """Parse a string value node in the AST.""" if not isinstance(value_node, StringValueNode): raise GraphQLError( "String cannot represent a non string value: " + print_ast(value_node), value_node, ) return value_node.value GraphQLString = GraphQLScalarType( name="String", description="The `String` scalar type represents textual data," " represented as UTF-8 character sequences." " The String type is most often used by GraphQL" " to represent free-form human-readable text.", serialize=serialize_string, parse_value=coerce_string, parse_literal=parse_string_literal, ) def serialize_boolean(output_value: Any) -> bool: if isinstance(output_value, bool): return output_value if isinstance(output_value, int) or ( isinstance(output_value, float) and isfinite(output_value) ): return bool(output_value) raise GraphQLError( "Boolean cannot represent a non boolean value: " + inspect(output_value) ) def coerce_boolean(input_value: Any) -> bool: if not isinstance(input_value, bool): raise GraphQLError( "Boolean cannot represent a non boolean value: " + inspect(input_value) ) return input_value def parse_boolean_literal(value_node: ValueNode, _variables: Any = None) -> bool: """Parse a boolean value node in the AST.""" if not isinstance(value_node, BooleanValueNode): raise GraphQLError( "Boolean cannot represent a non boolean value: " + print_ast(value_node), value_node, ) return value_node.value GraphQLBoolean = GraphQLScalarType( name="Boolean", description="The `Boolean` scalar type represents `true` or `false`.", serialize=serialize_boolean, parse_value=coerce_boolean, parse_literal=parse_boolean_literal, ) def serialize_id(output_value: Any) -> str: if isinstance(output_value, str): return output_value if isinstance(output_value, int) and not isinstance(output_value, bool): return str(output_value) if ( isinstance(output_value, float) and isfinite(output_value) and int(output_value) == output_value ): return str(int(output_value)) # do not serialize builtin types as IDs, but allow serialization of custom types # via their `__str__` method if type(output_value).__module__ == "builtins": raise GraphQLError("ID cannot represent value: " + inspect(output_value)) return str(output_value) def coerce_id(input_value: Any) -> str: if isinstance(input_value, str): return input_value if isinstance(input_value, int) and not isinstance(input_value, bool): return str(input_value) if ( isinstance(input_value, float) and isfinite(input_value) and int(input_value) == input_value ): return str(int(input_value)) raise GraphQLError("ID cannot represent value: " + inspect(input_value)) def parse_id_literal(value_node: ValueNode, _variables: Any = None) -> str: """Parse an ID value node in the AST.""" if not isinstance(value_node, (StringValueNode, IntValueNode)): raise GraphQLError( "ID cannot represent a non-string and non-integer value: " + print_ast(value_node), value_node, ) return value_node.value GraphQLID = GraphQLScalarType( name="ID", description="The `ID` scalar type represents a unique identifier," " often used to refetch an object or as key for a cache." " The ID type appears in a JSON response as a String; however," " it is not intended to be human-readable. When expected as an" ' input type, any string (such as `"4"`) or integer (such as' " `4`) input value will be accepted as an ID.", serialize=serialize_id, parse_value=coerce_id, parse_literal=parse_id_literal, ) specified_scalar_types: Mapping[str, GraphQLScalarType] = { type_.name: type_ for type_ in ( GraphQLString, GraphQLInt, GraphQLFloat, GraphQLBoolean, GraphQLID, ) } def is_specified_scalar_type(type_: GraphQLNamedType) -> bool: """Check whether the given named GraphQL type is a specified scalar type.""" return type_.name in specified_scalar_types graphql-core-3.2.6/src/graphql/type/schema.py000066400000000000000000000470311474546154300211500ustar00rootroot00000000000000from copy import copy, deepcopy from typing import ( Any, Collection, Dict, List, NamedTuple, Optional, Set, Tuple, Union, cast, ) from ..error import GraphQLError from ..language import OperationType, ast from ..pyutils import inspect, is_collection, is_description from .definition import ( GraphQLAbstractType, GraphQLInputObjectType, GraphQLInputType, GraphQLInterfaceType, GraphQLNamedType, GraphQLObjectType, GraphQLType, GraphQLUnionType, GraphQLWrappingType, get_named_type, is_input_object_type, is_interface_type, is_object_type, is_union_type, is_wrapping_type, ) from .directives import GraphQLDirective, is_directive, specified_directives from .introspection import introspection_types try: from typing import TypedDict except ImportError: # Python < 3.8 from typing_extensions import TypedDict __all__ = ["GraphQLSchema", "GraphQLSchemaKwargs", "is_schema", "assert_schema"] TypeMap = Dict[str, GraphQLNamedType] class InterfaceImplementations(NamedTuple): objects: List[GraphQLObjectType] interfaces: List[GraphQLInterfaceType] class GraphQLSchemaKwargs(TypedDict, total=False): query: Optional[GraphQLObjectType] mutation: Optional[GraphQLObjectType] subscription: Optional[GraphQLObjectType] types: Optional[Tuple[GraphQLNamedType, ...]] directives: Tuple[GraphQLDirective, ...] description: Optional[str] extensions: Dict[str, Any] ast_node: Optional[ast.SchemaDefinitionNode] extension_ast_nodes: Tuple[ast.SchemaExtensionNode, ...] assume_valid: bool class GraphQLSchema: """Schema Definition A Schema is created by supplying the root types of each type of operation, query and mutation (optional). A schema definition is then supplied to the validator and executor. Schemas should be considered immutable once they are created. If you want to modify a schema, modify the result of the ``to_kwargs()`` method and recreate the schema. Example:: MyAppSchema = GraphQLSchema( query=MyAppQueryRootType, mutation=MyAppMutationRootType) Note: When the schema is constructed, by default only the types that are reachable by traversing the root types are included, other types must be explicitly referenced. Example:: character_interface = GraphQLInterfaceType('Character', ...) human_type = GraphQLObjectType( 'Human', interfaces=[character_interface], ...) droid_type = GraphQLObjectType( 'Droid', interfaces: [character_interface], ...) schema = GraphQLSchema( query=GraphQLObjectType('Query', fields={'hero': GraphQLField(character_interface, ....)}), ... # Since this schema references only the `Character` interface it's # necessary to explicitly list the types that implement it if # you want them to be included in the final schema. types=[human_type, droid_type]) Note: If a list of ``directives`` is provided to GraphQLSchema, that will be the exact list of directives represented and allowed. If ``directives`` is not provided, then a default set of the specified directives (e.g. @include and @skip) will be used. If you wish to provide *additional* directives to these specified directives, you must explicitly declare them. Example:: MyAppSchema = GraphQLSchema( ... directives=specified_directives + [my_custom_directive]) """ query_type: Optional[GraphQLObjectType] mutation_type: Optional[GraphQLObjectType] subscription_type: Optional[GraphQLObjectType] type_map: TypeMap directives: Tuple[GraphQLDirective, ...] description: Optional[str] extensions: Dict[str, Any] ast_node: Optional[ast.SchemaDefinitionNode] extension_ast_nodes: Tuple[ast.SchemaExtensionNode, ...] _implementations_map: Dict[str, InterfaceImplementations] _sub_type_map: Dict[str, Set[str]] _validation_errors: Optional[List[GraphQLError]] def __init__( self, query: Optional[GraphQLObjectType] = None, mutation: Optional[GraphQLObjectType] = None, subscription: Optional[GraphQLObjectType] = None, types: Optional[Collection[GraphQLNamedType]] = None, directives: Optional[Collection[GraphQLDirective]] = None, description: Optional[str] = None, extensions: Optional[Dict[str, Any]] = None, ast_node: Optional[ast.SchemaDefinitionNode] = None, extension_ast_nodes: Optional[Collection[ast.SchemaExtensionNode]] = None, assume_valid: bool = False, ) -> None: """Initialize GraphQL schema. If this schema was built from a source known to be valid, then it may be marked with ``assume_valid`` to avoid an additional type system validation. """ self._validation_errors = [] if assume_valid else None # Check for common mistakes during construction to produce clear and early # error messages, but we leave the specific tests for the validation. if query and not isinstance(query, GraphQLType): raise TypeError("Expected query to be a GraphQL type.") if mutation and not isinstance(mutation, GraphQLType): raise TypeError("Expected mutation to be a GraphQL type.") if subscription and not isinstance(subscription, GraphQLType): raise TypeError("Expected subscription to be a GraphQL type.") if types is None: types = [] else: if not is_collection(types) or not all( isinstance(type_, GraphQLType) for type_ in types ): raise TypeError( "Schema types must be specified as a collection of GraphQL types." ) if directives is not None: # noinspection PyUnresolvedReferences if not is_collection(directives): raise TypeError("Schema directives must be a collection.") if not isinstance(directives, tuple): directives = tuple(directives) if description is not None and not is_description(description): raise TypeError("Schema description must be a string.") if extensions is None: extensions = {} elif not isinstance(extensions, dict) or not all( isinstance(key, str) for key in extensions ): raise TypeError("Schema extensions must be a dictionary with string keys.") if ast_node and not isinstance(ast_node, ast.SchemaDefinitionNode): raise TypeError("Schema AST node must be a SchemaDefinitionNode.") if extension_ast_nodes: if not is_collection(extension_ast_nodes) or not all( isinstance(node, ast.SchemaExtensionNode) for node in extension_ast_nodes ): raise TypeError( "Schema extension AST nodes must be specified" " as a collection of SchemaExtensionNode instances." ) if not isinstance(extension_ast_nodes, tuple): extension_ast_nodes = tuple(extension_ast_nodes) else: extension_ast_nodes = () self.description = description self.extensions = extensions self.ast_node = ast_node self.extension_ast_nodes = extension_ast_nodes self.query_type = query self.mutation_type = mutation self.subscription_type = subscription # Provide specified directives (e.g. @include and @skip) by default self.directives = specified_directives if directives is None else directives # To preserve order of user-provided types, we add first to add them to # the set of "collected" types, so `collect_referenced_types` ignore them. if types: all_referenced_types = TypeSet.with_initial_types(types) collect_referenced_types = all_referenced_types.collect_referenced_types for type_ in types: # When we are ready to process this type, we remove it from "collected" # types and then add it together with all dependent types in the correct # position. del all_referenced_types[type_] collect_referenced_types(type_) else: all_referenced_types = TypeSet() collect_referenced_types = all_referenced_types.collect_referenced_types if query: collect_referenced_types(query) if mutation: collect_referenced_types(mutation) if subscription: collect_referenced_types(subscription) for directive in self.directives: # Directives are not validated until validate_schema() is called. if is_directive(directive): for arg in directive.args.values(): collect_referenced_types(arg.type) collect_referenced_types(introspection_types["__Schema"]) # Storing the resulting map for reference by the schema. type_map: TypeMap = {} self.type_map = type_map self._sub_type_map = {} # Keep track of all implementations by interface name. implementations_map: Dict[str, InterfaceImplementations] = {} self._implementations_map = implementations_map for named_type in all_referenced_types: if not named_type: continue type_name = getattr(named_type, "name", None) if not type_name: raise TypeError( "One of the provided types for building the Schema" " is missing a name.", ) if type_name in type_map: raise TypeError( "Schema must contain uniquely named types" f" but contains multiple types named '{type_name}'." ) type_map[type_name] = named_type if is_interface_type(named_type): named_type = cast(GraphQLInterfaceType, named_type) # Store implementations by interface. for iface in named_type.interfaces: if is_interface_type(iface): iface = cast(GraphQLInterfaceType, iface) if iface.name in implementations_map: implementations = implementations_map[iface.name] else: implementations = implementations_map[iface.name] = ( InterfaceImplementations(objects=[], interfaces=[]) ) implementations.interfaces.append(named_type) elif is_object_type(named_type): named_type = cast(GraphQLObjectType, named_type) # Store implementations by objects. for iface in named_type.interfaces: if is_interface_type(iface): iface = cast(GraphQLInterfaceType, iface) if iface.name in implementations_map: implementations = implementations_map[iface.name] else: implementations = implementations_map[iface.name] = ( InterfaceImplementations(objects=[], interfaces=[]) ) implementations.objects.append(named_type) def to_kwargs(self) -> GraphQLSchemaKwargs: return GraphQLSchemaKwargs( query=self.query_type, mutation=self.mutation_type, subscription=self.subscription_type, types=tuple(self.type_map.values()) or None, directives=self.directives, description=self.description, extensions=self.extensions, ast_node=self.ast_node, extension_ast_nodes=self.extension_ast_nodes, assume_valid=self._validation_errors is not None, ) def __copy__(self) -> "GraphQLSchema": # pragma: no cover return self.__class__(**self.to_kwargs()) def __deepcopy__(self, memo_: Dict) -> "GraphQLSchema": from ..type import ( is_introspection_type, is_specified_directive, is_specified_scalar_type, ) type_map: TypeMap = { name: copy(type_) for name, type_ in self.type_map.items() if not is_introspection_type(type_) and not is_specified_scalar_type(type_) } types = type_map.values() for type_ in types: remap_named_type(type_, type_map) directives = [ directive if is_specified_directive(directive) else copy(directive) for directive in self.directives ] for directive in directives: remap_directive(directive, type_map) return self.__class__( self.query_type and cast(GraphQLObjectType, type_map[self.query_type.name]), self.mutation_type and cast(GraphQLObjectType, type_map[self.mutation_type.name]), self.subscription_type and cast(GraphQLObjectType, type_map[self.subscription_type.name]), types, directives, self.description, extensions=deepcopy(self.extensions), ast_node=deepcopy(self.ast_node), extension_ast_nodes=deepcopy(self.extension_ast_nodes), assume_valid=True, ) def get_root_type(self, operation: OperationType) -> Optional[GraphQLObjectType]: return getattr(self, f"{operation.value}_type") def get_type(self, name: str) -> Optional[GraphQLNamedType]: return self.type_map.get(name) def get_possible_types( self, abstract_type: GraphQLAbstractType ) -> List[GraphQLObjectType]: """Get list of all possible concrete types for given abstract type.""" return ( cast(GraphQLUnionType, abstract_type).types if is_union_type(abstract_type) else self.get_implementations( cast(GraphQLInterfaceType, abstract_type) ).objects ) def get_implementations( self, interface_type: GraphQLInterfaceType ) -> InterfaceImplementations: return self._implementations_map.get( interface_type.name, InterfaceImplementations(objects=[], interfaces=[]) ) def is_sub_type( self, abstract_type: GraphQLAbstractType, maybe_sub_type: GraphQLNamedType, ) -> bool: """Check whether a type is a subtype of a given abstract type.""" types = self._sub_type_map.get(abstract_type.name) if types is None: types = set() add = types.add if is_union_type(abstract_type): for type_ in cast(GraphQLUnionType, abstract_type).types: add(type_.name) else: implementations = self.get_implementations( cast(GraphQLInterfaceType, abstract_type) ) for type_ in implementations.objects: add(type_.name) for type_ in implementations.interfaces: add(type_.name) self._sub_type_map[abstract_type.name] = types return maybe_sub_type.name in types def get_directive(self, name: str) -> Optional[GraphQLDirective]: for directive in self.directives: if directive.name == name: return directive return None @property def validation_errors(self) -> Optional[List[GraphQLError]]: return self._validation_errors class TypeSet(Dict[GraphQLNamedType, None]): """An ordered set of types that can be collected starting from initial types.""" @classmethod def with_initial_types(cls, types: Collection[GraphQLType]) -> "TypeSet": return cast(TypeSet, super().fromkeys(types)) def collect_referenced_types(self, type_: GraphQLType) -> None: """Recursive function supplementing the type starting from an initial type.""" named_type = get_named_type(type_) if named_type in self: return self[named_type] = None collect_referenced_types = self.collect_referenced_types if is_union_type(named_type): named_type = cast(GraphQLUnionType, named_type) for member_type in named_type.types: collect_referenced_types(member_type) elif is_object_type(named_type) or is_interface_type(named_type): named_type = cast( Union[GraphQLObjectType, GraphQLInterfaceType], named_type ) for interface_type in named_type.interfaces: collect_referenced_types(interface_type) for field in named_type.fields.values(): collect_referenced_types(field.type) for arg in field.args.values(): collect_referenced_types(arg.type) elif is_input_object_type(named_type): named_type = cast(GraphQLInputObjectType, named_type) for field in named_type.fields.values(): collect_referenced_types(field.type) def is_schema(schema: Any) -> bool: """Test if the given value is a GraphQL schema.""" return isinstance(schema, GraphQLSchema) def assert_schema(schema: Any) -> GraphQLSchema: if not is_schema(schema): raise TypeError(f"Expected {inspect(schema)} to be a GraphQL schema.") return cast(GraphQLSchema, schema) def remapped_type(type_: GraphQLType, type_map: TypeMap) -> GraphQLType: """Get a copy of the given type that uses this type map.""" if is_wrapping_type(type_): type_ = cast(GraphQLWrappingType, type_) return type_.__class__(remapped_type(type_.of_type, type_map)) type_ = cast(GraphQLNamedType, type_) return type_map.get(type_.name, type_) def remap_named_type(type_: GraphQLNamedType, type_map: TypeMap) -> None: """Change all references in the given named type to use this type map.""" if is_object_type(type_) or is_interface_type(type_): type_ = cast(Union[GraphQLObjectType, GraphQLInterfaceType], type_) type_.interfaces = [ type_map.get(interface_type.name, interface_type) for interface_type in type_.interfaces ] fields = type_.fields for field_name, field in fields.items(): field = copy(field) field.type = remapped_type(field.type, type_map) args = field.args for arg_name, arg in args.items(): arg = copy(arg) arg.type = remapped_type(arg.type, type_map) args[arg_name] = arg fields[field_name] = field elif is_union_type(type_): type_ = cast(GraphQLUnionType, type_) type_.types = [ type_map.get(member_type.name, member_type) for member_type in type_.types ] elif is_input_object_type(type_): type_ = cast(GraphQLInputObjectType, type_) fields = type_.fields for field_name, field in fields.items(): field = copy(field) field.type = remapped_type(field.type, type_map) fields[field_name] = field def remap_directive(directive: GraphQLDirective, type_map: TypeMap) -> None: """Change all references in the given directive to use this type map.""" args = directive.args for arg_name, arg in args.items(): arg = copy(arg) # noqa: PLW2901 arg.type = cast(GraphQLInputType, remapped_type(arg.type, type_map)) args[arg_name] = arg graphql-core-3.2.6/src/graphql/type/validate.py000066400000000000000000000567501474546154300215110ustar00rootroot00000000000000from operator import attrgetter, itemgetter from typing import ( Any, Collection, Dict, List, Optional, Set, Tuple, Union, cast, ) from ..error import GraphQLError from ..pyutils import inspect from ..language import ( DirectiveNode, InputValueDefinitionNode, NamedTypeNode, Node, OperationType, SchemaDefinitionNode, SchemaExtensionNode, ) from .definition import ( GraphQLEnumType, GraphQLInputField, GraphQLInputObjectType, GraphQLInterfaceType, GraphQLObjectType, GraphQLUnionType, is_enum_type, is_input_object_type, is_input_type, is_interface_type, is_named_type, is_non_null_type, is_object_type, is_output_type, is_union_type, is_required_argument, is_required_input_field, ) from ..utilities.type_comparators import is_equal_type, is_type_sub_type_of from .directives import is_directive, GraphQLDeprecatedDirective from .introspection import is_introspection_type from .schema import GraphQLSchema, assert_schema __all__ = ["validate_schema", "assert_valid_schema"] def validate_schema(schema: GraphQLSchema) -> List[GraphQLError]: """Validate a GraphQL schema. Implements the "Type Validation" sub-sections of the specification's "Type System" section. Validation runs synchronously, returning a list of encountered errors, or an empty list if no errors were encountered and the Schema is valid. """ # First check to ensure the provided value is in fact a GraphQLSchema. assert_schema(schema) # If this Schema has already been validated, return the previous results. # noinspection PyProtectedMember errors = schema._validation_errors if errors is None: # Validate the schema, producing a list of errors. context = SchemaValidationContext(schema) context.validate_root_types() context.validate_directives() context.validate_types() # Persist the results of validation before returning to ensure validation does # not run multiple times for this schema. errors = context.errors schema._validation_errors = errors return errors def assert_valid_schema(schema: GraphQLSchema) -> None: """Utility function which asserts a schema is valid. Throws a TypeError if the schema is invalid. """ errors = validate_schema(schema) if errors: raise TypeError("\n\n".join(error.message for error in errors)) class SchemaValidationContext: """Utility class providing a context for schema validation.""" errors: List[GraphQLError] schema: GraphQLSchema def __init__(self, schema: GraphQLSchema): self.errors = [] self.schema = schema def report_error( self, message: str, nodes: Union[Optional[Node], Collection[Optional[Node]]] = None, ) -> None: if nodes and not isinstance(nodes, Node): nodes = [node for node in nodes if node] nodes = cast(Optional[Collection[Node]], nodes) self.errors.append(GraphQLError(message, nodes)) def validate_root_types(self) -> None: schema = self.schema query_type = schema.query_type if not query_type: self.report_error("Query root type must be provided.", schema.ast_node) elif not is_object_type(query_type): self.report_error( f"Query root type must be Object type, it cannot be {query_type}.", get_operation_type_node(schema, OperationType.QUERY) or query_type.ast_node, ) mutation_type = schema.mutation_type if mutation_type and not is_object_type(mutation_type): self.report_error( "Mutation root type must be Object type if provided," f" it cannot be {mutation_type}.", get_operation_type_node(schema, OperationType.MUTATION) or mutation_type.ast_node, ) subscription_type = schema.subscription_type if subscription_type and not is_object_type(subscription_type): self.report_error( "Subscription root type must be Object type if provided," f" it cannot be {subscription_type}.", get_operation_type_node(schema, OperationType.SUBSCRIPTION) or subscription_type.ast_node, ) def validate_directives(self) -> None: directives = self.schema.directives for directive in directives: # Ensure all directives are in fact GraphQL directives. if not is_directive(directive): self.report_error( f"Expected directive but got: {inspect(directive)}.", getattr(directive, "ast_node", None), ) continue # Ensure they are named correctly. self.validate_name(directive) # Ensure the arguments are valid. for arg_name, arg in directive.args.items(): # Ensure they are named correctly. self.validate_name(arg, arg_name) # Ensure the type is an input type. if not is_input_type(arg.type): self.report_error( f"The type of @{directive.name}({arg_name}:)" f" must be Input Type but got: {inspect(arg.type)}.", arg.ast_node, ) if is_required_argument(arg) and arg.deprecation_reason is not None: self.report_error( f"Required argument @{directive.name}({arg_name}:)" " cannot be deprecated.", [ get_deprecated_directive_node(arg.ast_node), arg.ast_node and arg.ast_node.type, ], ) def validate_name(self, node: Any, name: Optional[str] = None) -> None: # Ensure names are valid, however introspection types opt out. try: if not name: name = node.name name = cast(str, name) ast_node = node.ast_node except AttributeError: # pragma: no cover pass else: if name.startswith("__"): self.report_error( f"Name {name!r} must not begin with '__'," " which is reserved by GraphQL introspection.", ast_node, ) def validate_types(self) -> None: validate_input_object_circular_refs = InputObjectCircularRefsValidator(self) for type_ in self.schema.type_map.values(): # Ensure all provided types are in fact GraphQL type. if not is_named_type(type_): self.report_error( f"Expected GraphQL named type but got: {inspect(type_)}.", type_.ast_node if is_named_type(type_) else None, ) continue # Ensure it is named correctly (excluding introspection types). if not is_introspection_type(type_): self.validate_name(type_) if is_object_type(type_): type_ = cast(GraphQLObjectType, type_) # Ensure fields are valid self.validate_fields(type_) # Ensure objects implement the interfaces they claim to. self.validate_interfaces(type_) elif is_interface_type(type_): type_ = cast(GraphQLInterfaceType, type_) # Ensure fields are valid. self.validate_fields(type_) # Ensure interfaces implement the interfaces they claim to. self.validate_interfaces(type_) elif is_union_type(type_): type_ = cast(GraphQLUnionType, type_) # Ensure Unions include valid member types. self.validate_union_members(type_) elif is_enum_type(type_): type_ = cast(GraphQLEnumType, type_) # Ensure Enums have valid values. self.validate_enum_values(type_) elif is_input_object_type(type_): type_ = cast(GraphQLInputObjectType, type_) # Ensure Input Object fields are valid. self.validate_input_fields(type_) # Ensure Input Objects do not contain non-nullable circular references validate_input_object_circular_refs(type_) def validate_fields( self, type_: Union[GraphQLObjectType, GraphQLInterfaceType] ) -> None: fields = type_.fields # Objects and Interfaces both must define one or more fields. if not fields: self.report_error( f"Type {type_.name} must define one or more fields.", [type_.ast_node, *type_.extension_ast_nodes], ) for field_name, field in fields.items(): # Ensure they are named correctly. self.validate_name(field, field_name) # Ensure the type is an output type if not is_output_type(field.type): self.report_error( f"The type of {type_.name}.{field_name}" f" must be Output Type but got: {inspect(field.type)}.", field.ast_node and field.ast_node.type, ) # Ensure the arguments are valid. for arg_name, arg in field.args.items(): # Ensure they are named correctly. self.validate_name(arg, arg_name) # Ensure the type is an input type. if not is_input_type(arg.type): self.report_error( f"The type of {type_.name}.{field_name}({arg_name}:)" f" must be Input Type but got: {inspect(arg.type)}.", arg.ast_node and arg.ast_node.type, ) if is_required_argument(arg) and arg.deprecation_reason is not None: self.report_error( f"Required argument {type_.name}.{field_name}({arg_name}:)" " cannot be deprecated.", [ get_deprecated_directive_node(arg.ast_node), arg.ast_node and arg.ast_node.type, ], ) def validate_interfaces( self, type_: Union[GraphQLObjectType, GraphQLInterfaceType] ) -> None: iface_type_names: Set[str] = set() for iface in type_.interfaces: if not is_interface_type(iface): self.report_error( f"Type {type_.name} must only implement Interface" f" types, it cannot implement {inspect(iface)}.", get_all_implements_interface_nodes(type_, iface), ) continue if type_ is iface: self.report_error( f"Type {type_.name} cannot implement itself" " because it would create a circular reference.", get_all_implements_interface_nodes(type_, iface), ) if iface.name in iface_type_names: self.report_error( f"Type {type_.name} can only implement {iface.name} once.", get_all_implements_interface_nodes(type_, iface), ) continue iface_type_names.add(iface.name) self.validate_type_implements_ancestors(type_, iface) self.validate_type_implements_interface(type_, iface) def validate_type_implements_interface( self, type_: Union[GraphQLObjectType, GraphQLInterfaceType], iface: GraphQLInterfaceType, ) -> None: type_fields, iface_fields = type_.fields, iface.fields # Assert each interface field is implemented. for field_name, iface_field in iface_fields.items(): type_field = type_fields.get(field_name) # Assert interface field exists on object. if not type_field: self.report_error( f"Interface field {iface.name}.{field_name}" f" expected but {type_.name} does not provide it.", [ iface_field.ast_node, type_.ast_node, *type_.extension_ast_nodes, ], ) continue # Assert interface field type is satisfied by type field type, by being # a valid subtype (covariant). if not is_type_sub_type_of(self.schema, type_field.type, iface_field.type): self.report_error( f"Interface field {iface.name}.{field_name}" f" expects type {iface_field.type}" f" but {type_.name}.{field_name}" f" is type {type_field.type}.", [ iface_field.ast_node and iface_field.ast_node.type, type_field.ast_node and type_field.ast_node.type, ], ) # Assert each interface field arg is implemented. for arg_name, iface_arg in iface_field.args.items(): type_arg = type_field.args.get(arg_name) # Assert interface field arg exists on object field. if not type_arg: self.report_error( "Interface field argument" f" {iface.name}.{field_name}({arg_name}:)" f" expected but {type_.name}.{field_name}" " does not provide it.", [iface_arg.ast_node, type_field.ast_node], ) continue # Assert interface field arg type matches object field arg type # (invariant). if not is_equal_type(iface_arg.type, type_arg.type): self.report_error( "Interface field argument" f" {iface.name}.{field_name}({arg_name}:)" f" expects type {iface_arg.type}" f" but {type_.name}.{field_name}({arg_name}:)" f" is type {type_arg.type}.", [ iface_arg.ast_node and iface_arg.ast_node.type, type_arg.ast_node and type_arg.ast_node.type, ], ) # Assert additional arguments must not be required. for arg_name, type_arg in type_field.args.items(): iface_arg = iface_field.args.get(arg_name) if not iface_arg and is_required_argument(type_arg): self.report_error( f"Object field {type_.name}.{field_name} includes" f" required argument {arg_name} that is missing from" f" the Interface field {iface.name}.{field_name}.", [type_arg.ast_node, iface_field.ast_node], ) def validate_type_implements_ancestors( self, type_: Union[GraphQLObjectType, GraphQLInterfaceType], iface: GraphQLInterfaceType, ) -> None: type_interfaces, iface_interfaces = type_.interfaces, iface.interfaces for transitive in iface_interfaces: if transitive not in type_interfaces: self.report_error( ( f"Type {type_.name} cannot implement {iface.name}" " because it would create a circular reference." if transitive is type_ else f"Type {type_.name} must implement {transitive.name}" f" because it is implemented by {iface.name}." ), get_all_implements_interface_nodes(iface, transitive) + get_all_implements_interface_nodes(type_, iface), ) def validate_union_members(self, union: GraphQLUnionType) -> None: member_types = union.types if not member_types: self.report_error( f"Union type {union.name} must define one or more member types.", [union.ast_node, *union.extension_ast_nodes], ) included_type_names: Set[str] = set() for member_type in member_types: if is_object_type(member_type): if member_type.name in included_type_names: self.report_error( f"Union type {union.name} can only include type" f" {member_type.name} once.", get_union_member_type_nodes(union, member_type.name), ) else: included_type_names.add(member_type.name) else: self.report_error( f"Union type {union.name} can only include Object types," f" it cannot include {inspect(member_type)}.", get_union_member_type_nodes(union, str(member_type)), ) def validate_enum_values(self, enum_type: GraphQLEnumType) -> None: enum_values = enum_type.values if not enum_values: self.report_error( f"Enum type {enum_type.name} must define one or more values.", [enum_type.ast_node, *enum_type.extension_ast_nodes], ) for value_name, enum_value in enum_values.items(): # Ensure valid name. self.validate_name(enum_value, value_name) def validate_input_fields(self, input_obj: GraphQLInputObjectType) -> None: fields = input_obj.fields if not fields: self.report_error( f"Input Object type {input_obj.name}" " must define one or more fields.", [input_obj.ast_node, *input_obj.extension_ast_nodes], ) # Ensure the arguments are valid for field_name, field in fields.items(): # Ensure they are named correctly. self.validate_name(field, field_name) # Ensure the type is an input type. if not is_input_type(field.type): self.report_error( f"The type of {input_obj.name}.{field_name}" f" must be Input Type but got: {inspect(field.type)}.", field.ast_node.type if field.ast_node else None, ) if is_required_input_field(field) and field.deprecation_reason is not None: self.report_error( f"Required input field {input_obj.name}.{field_name}" " cannot be deprecated.", [ get_deprecated_directive_node(field.ast_node), field.ast_node and field.ast_node.type, ], ) def get_operation_type_node( schema: GraphQLSchema, operation: OperationType ) -> Optional[Node]: ast_node: Optional[Union[SchemaDefinitionNode, SchemaExtensionNode]] for ast_node in [schema.ast_node, *(schema.extension_ast_nodes or ())]: if ast_node: operation_types = ast_node.operation_types if operation_types: # pragma: no cover else for operation_type in operation_types: if operation_type.operation == operation: return operation_type.type return None class InputObjectCircularRefsValidator: """Modified copy of algorithm from validation.rules.NoFragmentCycles""" def __init__(self, context: SchemaValidationContext): self.context = context # Tracks already visited types to maintain O(N) and to ensure that cycles # are not redundantly reported. self.visited_types: Set[str] = set() # Array of input fields used to produce meaningful errors self.field_path: List[Tuple[str, GraphQLInputField]] = [] # Position in the type path self.field_path_index_by_type_name: Dict[str, int] = {} def __call__(self, input_obj: GraphQLInputObjectType) -> None: """Detect cycles recursively.""" # This does a straight-forward DFS to find cycles. # It does not terminate when a cycle was found but continues to explore # the graph to find all possible cycles. name = input_obj.name if name in self.visited_types: return self.visited_types.add(name) self.field_path_index_by_type_name[name] = len(self.field_path) for field_name, field in input_obj.fields.items(): if is_non_null_type(field.type) and is_input_object_type( field.type.of_type ): field_type = cast(GraphQLInputObjectType, field.type.of_type) cycle_index = self.field_path_index_by_type_name.get(field_type.name) self.field_path.append((field_name, field)) if cycle_index is None: self(field_type) else: cycle_path = self.field_path[cycle_index:] field_names = map(itemgetter(0), cycle_path) self.context.report_error( f"Cannot reference Input Object '{field_type.name}'" " within itself through a series of non-null fields:" f" '{'.'.join(field_names)}'.", cast( Collection[Node], map(attrgetter("ast_node"), map(itemgetter(1), cycle_path)), ), ) self.field_path.pop() del self.field_path_index_by_type_name[name] def get_all_implements_interface_nodes( type_: Union[GraphQLObjectType, GraphQLInterfaceType], iface: GraphQLInterfaceType ) -> List[NamedTypeNode]: ast_node = type_.ast_node nodes = type_.extension_ast_nodes if ast_node is not None: nodes = [ast_node, *nodes] # type: ignore implements_nodes: List[NamedTypeNode] = [] for node in nodes: iface_nodes = node.interfaces if iface_nodes: # pragma: no cover else implements_nodes.extend( iface_node for iface_node in iface_nodes if iface_node.name.value == iface.name ) return implements_nodes def get_union_member_type_nodes( union: GraphQLUnionType, type_name: str ) -> List[NamedTypeNode]: ast_node = union.ast_node nodes = union.extension_ast_nodes if ast_node is not None: nodes = [ast_node, *nodes] # type: ignore member_type_nodes: List[NamedTypeNode] = [] for node in nodes: type_nodes = node.types if type_nodes: # pragma: no cover else member_type_nodes.extend( type_node for type_node in type_nodes if type_node.name.value == type_name ) return member_type_nodes def get_deprecated_directive_node( definition_node: Optional[Union[InputValueDefinitionNode]], ) -> Optional[DirectiveNode]: directives = definition_node and definition_node.directives if directives: for directive in directives: if ( directive.name.value == GraphQLDeprecatedDirective.name ): # pragma: no cover else return directive return None # pragma: no cover graphql-core-3.2.6/src/graphql/utilities/000077500000000000000000000000001474546154300203635ustar00rootroot00000000000000graphql-core-3.2.6/src/graphql/utilities/__init__.py000066400000000000000000000072251474546154300225020ustar00rootroot00000000000000"""GraphQL Utilities The :mod:`graphql.utilities` package contains common useful computations to use with the GraphQL language and type objects. """ # Produce the GraphQL query recommended for a full schema introspection. from .get_introspection_query import get_introspection_query, IntrospectionQuery # Get the target Operation from a Document. from .get_operation_ast import get_operation_ast # Get the Type for the target Operation AST. from .get_operation_root_type import get_operation_root_type # Convert a GraphQLSchema to an IntrospectionQuery. from .introspection_from_schema import introspection_from_schema # Build a GraphQLSchema from an introspection result. from .build_client_schema import build_client_schema # Build a GraphQLSchema from GraphQL Schema language. from .build_ast_schema import build_ast_schema, build_schema # Extend an existing GraphQLSchema from a parsed GraphQL Schema language AST. from .extend_schema import extend_schema # Sort a GraphQLSchema. from .lexicographic_sort_schema import lexicographic_sort_schema # Print a GraphQLSchema to GraphQL Schema language. from .print_schema import ( print_introspection_schema, print_schema, print_type, print_value, # deprecated ) # Create a GraphQLType from a GraphQL language AST. from .type_from_ast import type_from_ast # Convert a language AST to a dictionary. from .ast_to_dict import ast_to_dict # Create a Python value from a GraphQL language AST with a type. from .value_from_ast import value_from_ast # Create a Python value from a GraphQL language AST without a type. from .value_from_ast_untyped import value_from_ast_untyped # Create a GraphQL language AST from a Python value. from .ast_from_value import ast_from_value # A helper to use within recursive-descent visitors which need to be aware of # the GraphQL type system from .type_info import TypeInfo, TypeInfoVisitor # Coerce a Python value to a GraphQL type, or produce errors. from .coerce_input_value import coerce_input_value # Concatenate multiple ASTs together. from .concat_ast import concat_ast # Separate an AST into an AST per Operation. from .separate_operations import separate_operations # Strip characters that are not significant to the validity or execution # of a GraphQL document. from .strip_ignored_characters import strip_ignored_characters # Comparators for types from .type_comparators import is_equal_type, is_type_sub_type_of, do_types_overlap # Assert that a string is a valid GraphQL name. from .assert_valid_name import assert_valid_name, is_valid_name_error # Compare two GraphQLSchemas and detect breaking changes. from .find_breaking_changes import ( BreakingChange, BreakingChangeType, DangerousChange, DangerousChangeType, find_breaking_changes, find_dangerous_changes, ) __all__ = [ "BreakingChange", "BreakingChangeType", "DangerousChange", "DangerousChangeType", "IntrospectionQuery", "TypeInfo", "TypeInfoVisitor", "assert_valid_name", "ast_from_value", "ast_to_dict", "build_ast_schema", "build_client_schema", "build_schema", "coerce_input_value", "concat_ast", "do_types_overlap", "extend_schema", "find_breaking_changes", "find_dangerous_changes", "get_introspection_query", "get_operation_ast", "get_operation_root_type", "is_equal_type", "is_type_sub_type_of", "is_valid_name_error", "introspection_from_schema", "lexicographic_sort_schema", "print_introspection_schema", "print_schema", "print_type", "print_value", "separate_operations", "strip_ignored_characters", "type_from_ast", "value_from_ast", "value_from_ast_untyped", ] graphql-core-3.2.6/src/graphql/utilities/assert_valid_name.py000066400000000000000000000020021474546154300244070ustar00rootroot00000000000000from typing import Optional from ..type.assert_name import assert_name from ..error import GraphQLError __all__ = ["assert_valid_name", "is_valid_name_error"] def assert_valid_name(name: str) -> str: """Uphold the spec rules about naming. .. deprecated:: 3.2 Please use ``assert_name`` instead. Will be removed in v3.3. """ error = is_valid_name_error(name) if error: raise error return name def is_valid_name_error(name: str) -> Optional[GraphQLError]: """Return an Error if a name is invalid. .. deprecated:: 3.2 Please use ``assert_name`` instead. Will be removed in v3.3. """ if not isinstance(name, str): raise TypeError("Expected name to be a string.") if name.startswith("__"): return GraphQLError( f"Name {name!r} must not begin with '__'," " which is reserved by GraphQL introspection." ) try: assert_name(name) except GraphQLError as error: return error return None graphql-core-3.2.6/src/graphql/utilities/ast_from_value.py000066400000000000000000000112431474546154300237440ustar00rootroot00000000000000import re from math import isfinite from typing import Any, Mapping, Optional, cast from ..language import ( BooleanValueNode, EnumValueNode, FloatValueNode, IntValueNode, ListValueNode, NameNode, NullValueNode, ObjectFieldNode, ObjectValueNode, StringValueNode, ValueNode, ) from ..pyutils import inspect, is_iterable, Undefined from ..type import ( GraphQLID, GraphQLInputType, GraphQLInputObjectType, GraphQLList, GraphQLNonNull, is_enum_type, is_input_object_type, is_leaf_type, is_list_type, is_non_null_type, ) __all__ = ["ast_from_value"] _re_integer_string = re.compile("^-?(?:0|[1-9][0-9]*)$") def ast_from_value(value: Any, type_: GraphQLInputType) -> Optional[ValueNode]: """Produce a GraphQL Value AST given a Python object. This function will match Python/JSON values to GraphQL AST schema format by using the suggested GraphQLInputType. For example:: ast_from_value('value', GraphQLString) A GraphQL type must be provided, which will be used to interpret different Python values. ================ ======================= JSON Value GraphQL Value ================ ======================= Object Input Object Array List Boolean Boolean String String / Enum Value Number Int / Float Mixed Enum Value null NullValue ================ ======================= """ if is_non_null_type(type_): type_ = cast(GraphQLNonNull, type_) ast_value = ast_from_value(value, type_.of_type) if isinstance(ast_value, NullValueNode): return None return ast_value # only explicit None, not Undefined or NaN if value is None: return NullValueNode() # undefined if value is Undefined: return None # Convert Python list to GraphQL list. If the GraphQLType is a list, but the value # is not a list, convert the value using the list's item type. if is_list_type(type_): type_ = cast(GraphQLList, type_) item_type = type_.of_type if is_iterable(value): maybe_value_nodes = (ast_from_value(item, item_type) for item in value) value_nodes = tuple(node for node in maybe_value_nodes if node) return ListValueNode(values=value_nodes) return ast_from_value(value, item_type) # Populate the fields of the input object by creating ASTs from each value in the # Python dict according to the fields in the input type. if is_input_object_type(type_): if value is None or not isinstance(value, Mapping): return None type_ = cast(GraphQLInputObjectType, type_) field_items = ( (field_name, ast_from_value(value[field_name], field.type)) for field_name, field in type_.fields.items() if field_name in value ) field_nodes = tuple( ObjectFieldNode(name=NameNode(value=field_name), value=field_value) for field_name, field_value in field_items if field_value ) return ObjectValueNode(fields=field_nodes) if is_leaf_type(type_): # Since value is an internally represented value, it must be serialized to an # externally represented value before converting into an AST. serialized = type_.serialize(value) # type: ignore if serialized is None or serialized is Undefined: return None # Others serialize based on their corresponding Python scalar types. if isinstance(serialized, bool): return BooleanValueNode(value=serialized) # Python ints and floats correspond nicely to Int and Float values. if isinstance(serialized, int): return IntValueNode(value=str(serialized)) if isinstance(serialized, float) and isfinite(serialized): value = str(serialized) if value.endswith(".0"): value = value[:-2] return FloatValueNode(value=value) if isinstance(serialized, str): # Enum types use Enum literals. if is_enum_type(type_): return EnumValueNode(value=serialized) # ID types can use Int literals. if type_ is GraphQLID and _re_integer_string.match(serialized): return IntValueNode(value=serialized) return StringValueNode(value=serialized) raise TypeError(f"Cannot convert value to AST: {inspect(serialized)}.") # Not reachable. All possible input types have been considered. raise TypeError(f"Unexpected input type: {inspect(type_)}.") graphql-core-3.2.6/src/graphql/utilities/ast_to_dict.py000066400000000000000000000027671474546154300232450ustar00rootroot00000000000000from typing import Any, Collection, Dict, List, Optional, overload from ..language import Node, OperationType from ..pyutils import is_iterable __all__ = ["ast_to_dict"] @overload def ast_to_dict( node: Node, locations: bool = False, cache: Optional[Dict[Node, Any]] = None ) -> Dict: ... @overload def ast_to_dict( node: Collection[Node], locations: bool = False, cache: Optional[Dict[Node, Any]] = None, ) -> List[Node]: ... @overload def ast_to_dict( node: OperationType, locations: bool = False, cache: Optional[Dict[Node, Any]] = None, ) -> str: ... def ast_to_dict( node: Any, locations: bool = False, cache: Optional[Dict[Node, Any]] = None ) -> Any: """Convert a language AST to a nested Python dictionary. Set `locations` to True in order to get the locations as well. """ if isinstance(node, Node): if cache is None: cache = {} elif node in cache: return cache[node] cache[node] = res = {} res.update( { key: ast_to_dict(getattr(node, key), locations, cache) for key in ("kind",) + node.keys[1:] } ) if locations: loc = node.loc if loc: res["loc"] = dict(start=loc.start, end=loc.end) return res if is_iterable(node): return [ast_to_dict(sub_node, locations, cache) for sub_node in node] if isinstance(node, OperationType): return node.value return node graphql-core-3.2.6/src/graphql/utilities/build_ast_schema.py000066400000000000000000000070021474546154300242220ustar00rootroot00000000000000from typing import cast, Union from ..language import DocumentNode, Source, parse from ..type import ( GraphQLObjectType, GraphQLSchema, GraphQLSchemaKwargs, specified_directives, ) from .extend_schema import extend_schema_impl __all__ = [ "build_ast_schema", "build_schema", ] def build_ast_schema( document_ast: DocumentNode, assume_valid: bool = False, assume_valid_sdl: bool = False, ) -> GraphQLSchema: """Build a GraphQL Schema from a given AST. This takes the ast of a schema document produced by the parse function in src/language/parser.py. If no schema definition is provided, then it will look for types named Query, Mutation and Subscription. Given that AST it constructs a GraphQLSchema. The resulting schema has no resolve methods, so execution will use default resolvers. When building a schema from a GraphQL service's introspection result, it might be safe to assume the schema is valid. Set ``assume_valid`` to ``True`` to assume the produced schema is valid. Set ``assume_valid_sdl`` to ``True`` to assume it is already a valid SDL document. """ if not isinstance(document_ast, DocumentNode): raise TypeError("Must provide valid Document AST.") if not (assume_valid or assume_valid_sdl): from ..validation.validate import assert_valid_sdl assert_valid_sdl(document_ast) empty_schema_kwargs = GraphQLSchemaKwargs( query=None, mutation=None, subscription=None, description=None, types=(), directives=(), extensions={}, ast_node=None, extension_ast_nodes=(), assume_valid=False, ) schema_kwargs = extend_schema_impl(empty_schema_kwargs, document_ast, assume_valid) if not schema_kwargs["ast_node"]: for type_ in schema_kwargs["types"] or (): # Note: While this could make early assertions to get the correctly # typed values below, that would throw immediately while type system # validation with validate_schema() will produce more actionable results. type_name = type_.name if type_name == "Query": schema_kwargs["query"] = cast(GraphQLObjectType, type_) elif type_name == "Mutation": schema_kwargs["mutation"] = cast(GraphQLObjectType, type_) elif type_name == "Subscription": schema_kwargs["subscription"] = cast(GraphQLObjectType, type_) # If specified directives were not explicitly declared, add them. directives = schema_kwargs["directives"] directive_names = set(directive.name for directive in directives) missing_directives = [] for directive in specified_directives: if directive.name not in directive_names: missing_directives.append(directive) if missing_directives: schema_kwargs["directives"] = directives + tuple(missing_directives) return GraphQLSchema(**schema_kwargs) def build_schema( source: Union[str, Source], assume_valid: bool = False, assume_valid_sdl: bool = False, no_location: bool = False, allow_legacy_fragment_variables: bool = False, ) -> GraphQLSchema: """Build a GraphQLSchema directly from a source document.""" return build_ast_schema( parse( source, no_location=no_location, allow_legacy_fragment_variables=allow_legacy_fragment_variables, ), assume_valid=assume_valid, assume_valid_sdl=assume_valid_sdl, ) graphql-core-3.2.6/src/graphql/utilities/build_client_schema.py000066400000000000000000000405231474546154300247160ustar00rootroot00000000000000from itertools import chain from typing import cast, Callable, Collection, Dict, List, Union from ..language import DirectiveLocation, parse_value from ..pyutils import inspect, Undefined from ..type import ( GraphQLArgument, GraphQLDirective, GraphQLEnumType, GraphQLEnumValue, GraphQLField, GraphQLInputField, GraphQLInputObjectType, GraphQLInputType, GraphQLInterfaceType, GraphQLList, GraphQLNamedType, GraphQLNonNull, GraphQLObjectType, GraphQLOutputType, GraphQLScalarType, GraphQLSchema, GraphQLType, GraphQLUnionType, TypeKind, assert_interface_type, assert_nullable_type, assert_object_type, introspection_types, is_input_type, is_output_type, specified_scalar_types, ) from .get_introspection_query import ( IntrospectionDirective, IntrospectionEnumType, IntrospectionField, IntrospectionInterfaceType, IntrospectionInputObjectType, IntrospectionInputValue, IntrospectionObjectType, IntrospectionQuery, IntrospectionScalarType, IntrospectionType, IntrospectionTypeRef, IntrospectionUnionType, ) from .value_from_ast import value_from_ast __all__ = ["build_client_schema"] def build_client_schema( introspection: IntrospectionQuery, assume_valid: bool = False ) -> GraphQLSchema: """Build a GraphQLSchema for use by client tools. Given the result of a client running the introspection query, creates and returns a GraphQLSchema instance which can be then used with all GraphQL-core 3 tools, but cannot be used to execute a query, as introspection does not represent the "resolver", "parse" or "serialize" functions or any other server-internal mechanisms. This function expects a complete introspection result. Don't forget to check the "errors" field of a server response before calling this function. """ if not isinstance(introspection, dict) or not isinstance( introspection.get("__schema"), dict ): raise TypeError( "Invalid or incomplete introspection result. Ensure that you" " are passing the 'data' attribute of an introspection response" f" and no 'errors' were returned alongside: {inspect(introspection)}." ) # Get the schema from the introspection result. schema_introspection = introspection["__schema"] # Given a type reference in introspection, return the GraphQLType instance, # preferring cached instances before building new instances. def get_type(type_ref: IntrospectionTypeRef) -> GraphQLType: kind = type_ref.get("kind") if kind == TypeKind.LIST.name: item_ref = type_ref.get("ofType") if not item_ref: raise TypeError("Decorated type deeper than introspection query.") item_ref = cast(IntrospectionTypeRef, item_ref) return GraphQLList(get_type(item_ref)) if kind == TypeKind.NON_NULL.name: nullable_ref = type_ref.get("ofType") if not nullable_ref: raise TypeError("Decorated type deeper than introspection query.") nullable_ref = cast(IntrospectionTypeRef, nullable_ref) nullable_type = get_type(nullable_ref) return GraphQLNonNull(assert_nullable_type(nullable_type)) type_ref = cast(IntrospectionType, type_ref) return get_named_type(type_ref) def get_named_type(type_ref: IntrospectionType) -> GraphQLNamedType: type_name = type_ref.get("name") if not type_name: raise TypeError(f"Unknown type reference: {inspect(type_ref)}.") type_ = type_map.get(type_name) if not type_: raise TypeError( f"Invalid or incomplete schema, unknown type: {type_name}." " Ensure that a full introspection query is used in order" " to build a client schema." ) return type_ def get_object_type(type_ref: IntrospectionObjectType) -> GraphQLObjectType: return assert_object_type(get_type(type_ref)) def get_interface_type( type_ref: IntrospectionInterfaceType, ) -> GraphQLInterfaceType: return assert_interface_type(get_type(type_ref)) # Given a type's introspection result, construct the correct GraphQLType instance. def build_type(type_: IntrospectionType) -> GraphQLNamedType: if type_ and "name" in type_ and "kind" in type_: builder = type_builders.get(type_["kind"]) if builder: # pragma: no cover else return builder(type_) raise TypeError( "Invalid or incomplete introspection result." " Ensure that a full introspection query is used in order" f" to build a client schema: {inspect(type_)}." ) def build_scalar_def( scalar_introspection: IntrospectionScalarType, ) -> GraphQLScalarType: return GraphQLScalarType( name=scalar_introspection["name"], description=scalar_introspection.get("description"), specified_by_url=scalar_introspection.get("specifiedByURL"), ) def build_implementations_list( implementing_introspection: Union[ IntrospectionObjectType, IntrospectionInterfaceType ], ) -> List[GraphQLInterfaceType]: maybe_interfaces = implementing_introspection.get("interfaces") if maybe_interfaces is None: # Temporary workaround until GraphQL ecosystem will fully support # 'interfaces' on interface types if implementing_introspection["kind"] == TypeKind.INTERFACE.name: return [] raise TypeError( "Introspection result missing interfaces:" f" {inspect(implementing_introspection)}." ) interfaces = cast(Collection[IntrospectionInterfaceType], maybe_interfaces) return [get_interface_type(interface) for interface in interfaces] def build_object_def( object_introspection: IntrospectionObjectType, ) -> GraphQLObjectType: return GraphQLObjectType( name=object_introspection["name"], description=object_introspection.get("description"), interfaces=lambda: build_implementations_list(object_introspection), fields=lambda: build_field_def_map(object_introspection), ) def build_interface_def( interface_introspection: IntrospectionInterfaceType, ) -> GraphQLInterfaceType: return GraphQLInterfaceType( name=interface_introspection["name"], description=interface_introspection.get("description"), interfaces=lambda: build_implementations_list(interface_introspection), fields=lambda: build_field_def_map(interface_introspection), ) def build_union_def( union_introspection: IntrospectionUnionType, ) -> GraphQLUnionType: maybe_possible_types = union_introspection.get("possibleTypes") if maybe_possible_types is None: raise TypeError( "Introspection result missing possibleTypes:" f" {inspect(union_introspection)}." ) possible_types = cast(Collection[IntrospectionObjectType], maybe_possible_types) return GraphQLUnionType( name=union_introspection["name"], description=union_introspection.get("description"), types=lambda: [get_object_type(type_) for type_ in possible_types], ) def build_enum_def(enum_introspection: IntrospectionEnumType) -> GraphQLEnumType: if enum_introspection.get("enumValues") is None: raise TypeError( "Introspection result missing enumValues:" f" {inspect(enum_introspection)}." ) return GraphQLEnumType( name=enum_introspection["name"], description=enum_introspection.get("description"), values={ value_introspect["name"]: GraphQLEnumValue( value=value_introspect["name"], description=value_introspect.get("description"), deprecation_reason=value_introspect.get("deprecationReason"), ) for value_introspect in enum_introspection["enumValues"] }, ) def build_input_object_def( input_object_introspection: IntrospectionInputObjectType, ) -> GraphQLInputObjectType: if input_object_introspection.get("inputFields") is None: raise TypeError( "Introspection result missing inputFields:" f" {inspect(input_object_introspection)}." ) return GraphQLInputObjectType( name=input_object_introspection["name"], description=input_object_introspection.get("description"), fields=lambda: build_input_value_def_map( input_object_introspection["inputFields"] ), ) type_builders: Dict[str, Callable[[IntrospectionType], GraphQLNamedType]] = { TypeKind.SCALAR.name: build_scalar_def, # type: ignore TypeKind.OBJECT.name: build_object_def, # type: ignore TypeKind.INTERFACE.name: build_interface_def, # type: ignore TypeKind.UNION.name: build_union_def, # type: ignore TypeKind.ENUM.name: build_enum_def, # type: ignore TypeKind.INPUT_OBJECT.name: build_input_object_def, # type: ignore } def build_field_def_map( type_introspection: Union[IntrospectionObjectType, IntrospectionInterfaceType], ) -> Dict[str, GraphQLField]: if type_introspection.get("fields") is None: raise TypeError( f"Introspection result missing fields: {type_introspection}." ) return { field_introspection["name"]: build_field(field_introspection) for field_introspection in type_introspection["fields"] } def build_field(field_introspection: IntrospectionField) -> GraphQLField: type_introspection = cast(IntrospectionType, field_introspection["type"]) type_ = get_type(type_introspection) if not is_output_type(type_): raise TypeError( "Introspection must provide output type for fields," f" but received: {inspect(type_)}." ) type_ = cast(GraphQLOutputType, type_) args_introspection = field_introspection.get("args") if args_introspection is None: raise TypeError( "Introspection result missing field args:" f" {inspect(field_introspection)}." ) return GraphQLField( type_, args=build_argument_def_map(args_introspection), description=field_introspection.get("description"), deprecation_reason=field_introspection.get("deprecationReason"), ) def build_argument_def_map( argument_value_introspections: Collection[IntrospectionInputValue], ) -> Dict[str, GraphQLArgument]: return { argument_introspection["name"]: build_argument(argument_introspection) for argument_introspection in argument_value_introspections } def build_argument( argument_introspection: IntrospectionInputValue, ) -> GraphQLArgument: type_introspection = cast(IntrospectionType, argument_introspection["type"]) type_ = get_type(type_introspection) if not is_input_type(type_): raise TypeError( "Introspection must provide input type for arguments," f" but received: {inspect(type_)}." ) type_ = cast(GraphQLInputType, type_) default_value_introspection = argument_introspection.get("defaultValue") default_value = ( Undefined if default_value_introspection is None else value_from_ast(parse_value(default_value_introspection), type_) ) return GraphQLArgument( type_, default_value=default_value, description=argument_introspection.get("description"), deprecation_reason=argument_introspection.get("deprecationReason"), ) def build_input_value_def_map( input_value_introspections: Collection[IntrospectionInputValue], ) -> Dict[str, GraphQLInputField]: return { input_value_introspection["name"]: build_input_value( input_value_introspection ) for input_value_introspection in input_value_introspections } def build_input_value( input_value_introspection: IntrospectionInputValue, ) -> GraphQLInputField: type_introspection = cast(IntrospectionType, input_value_introspection["type"]) type_ = get_type(type_introspection) if not is_input_type(type_): raise TypeError( "Introspection must provide input type for input fields," f" but received: {inspect(type_)}." ) type_ = cast(GraphQLInputType, type_) default_value_introspection = input_value_introspection.get("defaultValue") default_value = ( Undefined if default_value_introspection is None else value_from_ast(parse_value(default_value_introspection), type_) ) return GraphQLInputField( type_, default_value=default_value, description=input_value_introspection.get("description"), deprecation_reason=input_value_introspection.get("deprecationReason"), ) def build_directive( directive_introspection: IntrospectionDirective, ) -> GraphQLDirective: if directive_introspection.get("args") is None: raise TypeError( "Introspection result missing directive args:" f" {inspect(directive_introspection)}." ) if directive_introspection.get("locations") is None: raise TypeError( "Introspection result missing directive locations:" f" {inspect(directive_introspection)}." ) return GraphQLDirective( name=directive_introspection["name"], description=directive_introspection.get("description"), is_repeatable=directive_introspection.get("isRepeatable", False), locations=list( cast( Collection[DirectiveLocation], directive_introspection.get("locations"), ) ), args=build_argument_def_map(directive_introspection["args"]), ) # Iterate through all types, getting the type definition for each. type_map: Dict[str, GraphQLNamedType] = { type_introspection["name"]: build_type(type_introspection) for type_introspection in schema_introspection["types"] } # Include standard types only if they are used. for std_type_name, std_type in chain( specified_scalar_types.items(), introspection_types.items() ): if std_type_name in type_map: type_map[std_type_name] = std_type # Get the root Query, Mutation, and Subscription types. query_type_ref = schema_introspection.get("queryType") query_type = None if query_type_ref is None else get_object_type(query_type_ref) mutation_type_ref = schema_introspection.get("mutationType") mutation_type = ( None if mutation_type_ref is None else get_object_type(mutation_type_ref) ) subscription_type_ref = schema_introspection.get("subscriptionType") subscription_type = ( None if subscription_type_ref is None else get_object_type(subscription_type_ref) ) # Get the directives supported by Introspection, assuming empty-set if directives # were not queried for. directive_introspections = schema_introspection.get("directives") directives = ( [ build_directive(directive_introspection) for directive_introspection in directive_introspections ] if directive_introspections else [] ) # Then produce and return a Schema with these types. return GraphQLSchema( query=query_type, mutation=mutation_type, subscription=subscription_type, types=list(type_map.values()), directives=directives, description=schema_introspection.get("description"), assume_valid=assume_valid, ) graphql-core-3.2.6/src/graphql/utilities/coerce_input_value.py000066400000000000000000000126511474546154300246150ustar00rootroot00000000000000from typing import Any, Callable, Dict, List, Optional, Union, cast from ..error import GraphQLError from ..pyutils import ( Path, did_you_mean, inspect, is_iterable, print_path_list, suggestion_list, Undefined, ) from ..type import ( GraphQLInputObjectType, GraphQLInputType, GraphQLList, GraphQLScalarType, is_leaf_type, is_input_object_type, is_list_type, is_non_null_type, GraphQLNonNull, ) __all__ = ["coerce_input_value"] OnErrorCB = Callable[[List[Union[str, int]], Any, GraphQLError], None] def default_on_error( path: List[Union[str, int]], invalid_value: Any, error: GraphQLError ) -> None: error_prefix = "Invalid value " + inspect(invalid_value) if path: error_prefix += f" at 'value{print_path_list(path)}'" error.message = error_prefix + ": " + error.message raise error def coerce_input_value( input_value: Any, type_: GraphQLInputType, on_error: OnErrorCB = default_on_error, path: Optional[Path] = None, ) -> Any: """Coerce a Python value given a GraphQL Input Type.""" if is_non_null_type(type_): if input_value is not None and input_value is not Undefined: type_ = cast(GraphQLNonNull, type_) return coerce_input_value(input_value, type_.of_type, on_error, path) on_error( path.as_list() if path else [], input_value, GraphQLError( f"Expected non-nullable type '{inspect(type_)}' not to be None." ), ) return Undefined if input_value is None or input_value is Undefined: # Explicitly return the value null. return None if is_list_type(type_): type_ = cast(GraphQLList, type_) item_type = type_.of_type if is_iterable(input_value): coerced_list: List[Any] = [] append_item = coerced_list.append for index, item_value in enumerate(input_value): append_item( coerce_input_value( item_value, item_type, on_error, Path(path, index, None) ) ) return coerced_list # Lists accept a non-list value as a list of one. return [coerce_input_value(input_value, item_type, on_error, path)] if is_input_object_type(type_): type_ = cast(GraphQLInputObjectType, type_) if not isinstance(input_value, dict): on_error( path.as_list() if path else [], input_value, GraphQLError(f"Expected type '{type_.name}' to be a mapping."), ) return Undefined coerced_dict: Dict[str, Any] = {} fields = type_.fields for field_name, field in fields.items(): field_value = input_value.get(field_name, Undefined) if field_value is Undefined: if field.default_value is not Undefined: # Use out name as name if it exists (extension of GraphQL.js). coerced_dict[field.out_name or field_name] = field.default_value elif is_non_null_type(field.type): # pragma: no cover else type_str = inspect(field.type) on_error( path.as_list() if path else [], input_value, GraphQLError( f"Field '{field_name}' of required type '{type_str}'" " was not provided." ), ) continue coerced_dict[field.out_name or field_name] = coerce_input_value( field_value, field.type, on_error, Path(path, field_name, type_.name) ) # Ensure every provided field is defined. for field_name in input_value: if field_name not in fields: suggestions = suggestion_list(field_name, fields) on_error( path.as_list() if path else [], input_value, GraphQLError( f"Field '{field_name}' is not defined by type '{type_.name}'." + did_you_mean(suggestions) ), ) return type_.out_type(coerced_dict) if is_leaf_type(type_): # Scalars determine if a value is valid via `parse_value()`, which can throw to # indicate failure. If it throws, maintain a reference to the original error. type_ = cast(GraphQLScalarType, type_) try: parse_result = type_.parse_value(input_value) except GraphQLError as error: on_error(path.as_list() if path else [], input_value, error) return Undefined except Exception as error: on_error( path.as_list() if path else [], input_value, GraphQLError( f"Expected type '{type_.name}'. {error}", original_error=error ), ) return Undefined if parse_result is Undefined: on_error( path.as_list() if path else [], input_value, GraphQLError(f"Expected type '{type_.name}'."), ) return parse_result # Not reachable. All possible input types have been considered. raise TypeError(f"Unexpected input type: {inspect(type_)}.") graphql-core-3.2.6/src/graphql/utilities/concat_ast.py000066400000000000000000000010721474546154300230530ustar00rootroot00000000000000from itertools import chain from typing import Collection from ..language.ast import DocumentNode __all__ = ["concat_ast"] def concat_ast(asts: Collection[DocumentNode]) -> DocumentNode: """Concat ASTs. Provided a collection of ASTs, presumably each from different files, concatenate the ASTs together into batched AST, useful for validating many GraphQL source files which together represent one conceptual application. """ return DocumentNode( definitions=list(chain.from_iterable(document.definitions for document in asts)) ) graphql-core-3.2.6/src/graphql/utilities/extend_schema.py000066400000000000000000000651601474546154300235540ustar00rootroot00000000000000from collections import defaultdict from typing import ( Any, Callable, Collection, DefaultDict, Dict, List, Mapping, Optional, Union, cast, ) from ..language import ( DirectiveDefinitionNode, DirectiveLocation, DocumentNode, EnumTypeDefinitionNode, EnumTypeExtensionNode, EnumValueDefinitionNode, FieldDefinitionNode, InputObjectTypeDefinitionNode, InputObjectTypeExtensionNode, InputValueDefinitionNode, InterfaceTypeDefinitionNode, InterfaceTypeExtensionNode, ListTypeNode, NamedTypeNode, NonNullTypeNode, ObjectTypeDefinitionNode, ObjectTypeExtensionNode, OperationType, ScalarTypeDefinitionNode, ScalarTypeExtensionNode, SchemaExtensionNode, SchemaDefinitionNode, TypeDefinitionNode, TypeExtensionNode, TypeNode, UnionTypeDefinitionNode, UnionTypeExtensionNode, ) from ..pyutils import inspect, merge_kwargs from ..type import ( GraphQLArgument, GraphQLArgumentMap, GraphQLDeprecatedDirective, GraphQLDirective, GraphQLEnumType, GraphQLEnumValue, GraphQLEnumValueMap, GraphQLField, GraphQLFieldMap, GraphQLInputField, GraphQLInputObjectType, GraphQLInputType, GraphQLInputFieldMap, GraphQLInterfaceType, GraphQLList, GraphQLNamedType, GraphQLNonNull, GraphQLNullableType, GraphQLObjectType, GraphQLOutputType, GraphQLScalarType, GraphQLSchema, GraphQLSchemaKwargs, GraphQLSpecifiedByDirective, GraphQLType, GraphQLUnionType, assert_schema, is_enum_type, is_input_object_type, is_interface_type, is_list_type, is_non_null_type, is_object_type, is_scalar_type, is_union_type, is_introspection_type, is_specified_scalar_type, introspection_types, specified_scalar_types, ) from .value_from_ast import value_from_ast __all__ = [ "extend_schema", "extend_schema_impl", ] def extend_schema( schema: GraphQLSchema, document_ast: DocumentNode, assume_valid: bool = False, assume_valid_sdl: bool = False, ) -> GraphQLSchema: """Extend the schema with extensions from a given document. Produces a new schema given an existing schema and a document which may contain GraphQL type extensions and definitions. The original schema will remain unaltered. Because a schema represents a graph of references, a schema cannot be extended without effectively making an entire copy. We do not know until it's too late if subgraphs remain unchanged. This algorithm copies the provided schema, applying extensions while producing the copy. The original schema remains unaltered. When extending a schema with a known valid extension, it might be safe to assume the schema is valid. Set ``assume_valid`` to ``True`` to assume the produced schema is valid. Set ``assume_valid_sdl`` to ``True`` to assume it is already a valid SDL document. """ assert_schema(schema) if not isinstance(document_ast, DocumentNode): raise TypeError("Must provide valid Document AST.") if not (assume_valid or assume_valid_sdl): from ..validation.validate import assert_valid_sdl_extension assert_valid_sdl_extension(document_ast, schema) schema_kwargs = schema.to_kwargs() extended_kwargs = extend_schema_impl(schema_kwargs, document_ast, assume_valid) return ( schema if schema_kwargs is extended_kwargs else GraphQLSchema(**extended_kwargs) ) def extend_schema_impl( schema_kwargs: GraphQLSchemaKwargs, document_ast: DocumentNode, assume_valid: bool = False, ) -> GraphQLSchemaKwargs: """Extend the given schema arguments with extensions from a given document. For internal use only. """ # Note: schema_kwargs should become a TypedDict once we require Python 3.8 # Collect the type definitions and extensions found in the document. type_defs: List[TypeDefinitionNode] = [] type_extensions_map: DefaultDict[str, Any] = defaultdict(list) # New directives and types are separate because a directives and types can have the # same name. For example, a type named "skip". directive_defs: List[DirectiveDefinitionNode] = [] schema_def: Optional[SchemaDefinitionNode] = None # Schema extensions are collected which may add additional operation types. schema_extensions: List[SchemaExtensionNode] = [] for def_ in document_ast.definitions: if isinstance(def_, SchemaDefinitionNode): schema_def = def_ elif isinstance(def_, SchemaExtensionNode): schema_extensions.append(def_) elif isinstance(def_, TypeDefinitionNode): type_defs.append(def_) elif isinstance(def_, TypeExtensionNode): extended_type_name = def_.name.value type_extensions_map[extended_type_name].append(def_) elif isinstance(def_, DirectiveDefinitionNode): directive_defs.append(def_) # If this document contains no new types, extensions, or directives then return the # same unmodified GraphQLSchema instance. if ( not type_extensions_map and not type_defs and not directive_defs and not schema_extensions and not schema_def ): return schema_kwargs # Below are functions used for producing this schema that have closed over this # scope and have access to the schema, cache, and newly defined types. # noinspection PyTypeChecker,PyUnresolvedReferences def replace_type(type_: GraphQLType) -> GraphQLType: if is_list_type(type_): return GraphQLList(replace_type(type_.of_type)) # type: ignore if is_non_null_type(type_): return GraphQLNonNull(replace_type(type_.of_type)) # type: ignore return replace_named_type(type_) # type: ignore def replace_named_type(type_: GraphQLNamedType) -> GraphQLNamedType: # Note: While this could make early assertions to get the correctly # typed values below, that would throw immediately while type system # validation with validate_schema() will produce more actionable results. return type_map[type_.name] # noinspection PyShadowingNames def replace_directive(directive: GraphQLDirective) -> GraphQLDirective: kwargs = directive.to_kwargs() return GraphQLDirective( **merge_kwargs( kwargs, args={name: extend_arg(arg) for name, arg in kwargs["args"].items()}, ) ) def extend_named_type(type_: GraphQLNamedType) -> GraphQLNamedType: if is_introspection_type(type_) or is_specified_scalar_type(type_): # Builtin types are not extended. return type_ if is_scalar_type(type_): type_ = cast(GraphQLScalarType, type_) return extend_scalar_type(type_) if is_object_type(type_): type_ = cast(GraphQLObjectType, type_) return extend_object_type(type_) if is_interface_type(type_): type_ = cast(GraphQLInterfaceType, type_) return extend_interface_type(type_) if is_union_type(type_): type_ = cast(GraphQLUnionType, type_) return extend_union_type(type_) if is_enum_type(type_): type_ = cast(GraphQLEnumType, type_) return extend_enum_type(type_) if is_input_object_type(type_): type_ = cast(GraphQLInputObjectType, type_) return extend_input_object_type(type_) # Not reachable. All possible types have been considered. raise TypeError(f"Unexpected type: {inspect(type_)}.") # pragma: no cover # noinspection PyShadowingNames def extend_input_object_type( type_: GraphQLInputObjectType, ) -> GraphQLInputObjectType: kwargs = type_.to_kwargs() extensions = tuple(type_extensions_map[kwargs["name"]]) return GraphQLInputObjectType( **merge_kwargs( kwargs, fields=lambda: { **{ name: GraphQLInputField( **merge_kwargs( field.to_kwargs(), type_=replace_type(field.type), ) ) for name, field in kwargs["fields"].items() }, **build_input_field_map(extensions), }, extension_ast_nodes=kwargs["extension_ast_nodes"] + extensions, ) ) def extend_enum_type(type_: GraphQLEnumType) -> GraphQLEnumType: kwargs = type_.to_kwargs() extensions = tuple(type_extensions_map[kwargs["name"]]) return GraphQLEnumType( **merge_kwargs( kwargs, values={**kwargs["values"], **build_enum_value_map(extensions)}, extension_ast_nodes=kwargs["extension_ast_nodes"] + extensions, ) ) def extend_scalar_type(type_: GraphQLScalarType) -> GraphQLScalarType: kwargs = type_.to_kwargs() extensions = tuple(type_extensions_map[kwargs["name"]]) specified_by_url = kwargs["specified_by_url"] for extension_node in extensions: specified_by_url = get_specified_by_url(extension_node) or specified_by_url return GraphQLScalarType( **merge_kwargs( kwargs, specified_by_url=specified_by_url, extension_ast_nodes=kwargs["extension_ast_nodes"] + extensions, ) ) # noinspection PyShadowingNames def extend_object_type(type_: GraphQLObjectType) -> GraphQLObjectType: kwargs = type_.to_kwargs() extensions = tuple(type_extensions_map[kwargs["name"]]) return GraphQLObjectType( **merge_kwargs( kwargs, interfaces=lambda: [ cast(GraphQLInterfaceType, replace_named_type(interface)) for interface in kwargs["interfaces"] ] + build_interfaces(extensions), fields=lambda: { **{ name: extend_field(field) for name, field in kwargs["fields"].items() }, **build_field_map(extensions), }, extension_ast_nodes=kwargs["extension_ast_nodes"] + extensions, ) ) # noinspection PyShadowingNames def extend_interface_type(type_: GraphQLInterfaceType) -> GraphQLInterfaceType: kwargs = type_.to_kwargs() extensions = tuple(type_extensions_map[kwargs["name"]]) return GraphQLInterfaceType( **merge_kwargs( kwargs, interfaces=lambda: [ cast(GraphQLInterfaceType, replace_named_type(interface)) for interface in kwargs["interfaces"] ] + build_interfaces(extensions), fields=lambda: { **{ name: extend_field(field) for name, field in kwargs["fields"].items() }, **build_field_map(extensions), }, extension_ast_nodes=kwargs["extension_ast_nodes"] + extensions, ) ) def extend_union_type(type_: GraphQLUnionType) -> GraphQLUnionType: kwargs = type_.to_kwargs() extensions = tuple(type_extensions_map[kwargs["name"]]) return GraphQLUnionType( **merge_kwargs( kwargs, types=lambda: [ cast(GraphQLObjectType, replace_named_type(member_type)) for member_type in kwargs["types"] ] + build_union_types(extensions), extension_ast_nodes=kwargs["extension_ast_nodes"] + extensions, ) ) # noinspection PyShadowingNames def extend_field(field: GraphQLField) -> GraphQLField: return GraphQLField( **merge_kwargs( field.to_kwargs(), type_=replace_type(field.type), args={name: extend_arg(arg) for name, arg in field.args.items()}, ) ) def extend_arg(arg: GraphQLArgument) -> GraphQLArgument: return GraphQLArgument( **merge_kwargs( arg.to_kwargs(), type_=replace_type(arg.type), ) ) # noinspection PyShadowingNames def get_operation_types( nodes: Collection[Union[SchemaDefinitionNode, SchemaExtensionNode]] ) -> Dict[OperationType, GraphQLNamedType]: # Note: While this could make early assertions to get the correctly # typed values below, that would throw immediately while type system # validation with validate_schema() will produce more actionable results. return { operation_type.operation: get_named_type(operation_type.type) for node in nodes for operation_type in node.operation_types or [] } # noinspection PyShadowingNames def get_named_type(node: NamedTypeNode) -> GraphQLNamedType: name = node.name.value type_ = std_type_map.get(name) or type_map.get(name) if not type_: raise TypeError(f"Unknown type: '{name}'.") return type_ def get_wrapped_type(node: TypeNode) -> GraphQLType: if isinstance(node, ListTypeNode): return GraphQLList(get_wrapped_type(node.type)) if isinstance(node, NonNullTypeNode): return GraphQLNonNull( cast(GraphQLNullableType, get_wrapped_type(node.type)) ) return get_named_type(cast(NamedTypeNode, node)) def build_directive(node: DirectiveDefinitionNode) -> GraphQLDirective: locations = [DirectiveLocation[node.value] for node in node.locations] return GraphQLDirective( name=node.name.value, description=node.description.value if node.description else None, locations=locations, is_repeatable=node.repeatable, args=build_argument_map(node.arguments), ast_node=node, ) def build_field_map( nodes: Collection[ Union[ InterfaceTypeDefinitionNode, InterfaceTypeExtensionNode, ObjectTypeDefinitionNode, ObjectTypeExtensionNode, ] ], ) -> GraphQLFieldMap: field_map: GraphQLFieldMap = {} for node in nodes: for field in node.fields or []: # Note: While this could make assertions to get the correctly typed # value, that would throw immediately while type system validation # with validate_schema() will produce more actionable results. field_map[field.name.value] = GraphQLField( type_=cast(GraphQLOutputType, get_wrapped_type(field.type)), description=field.description.value if field.description else None, args=build_argument_map(field.arguments), deprecation_reason=get_deprecation_reason(field), ast_node=field, ) return field_map def build_argument_map( args: Optional[Collection[InputValueDefinitionNode]], ) -> GraphQLArgumentMap: arg_map: GraphQLArgumentMap = {} for arg in args or []: # Note: While this could make assertions to get the correctly typed # value, that would throw immediately while type system validation # with validate_schema() will produce more actionable results. type_ = cast(GraphQLInputType, get_wrapped_type(arg.type)) arg_map[arg.name.value] = GraphQLArgument( type_=type_, description=arg.description.value if arg.description else None, default_value=value_from_ast(arg.default_value, type_), deprecation_reason=get_deprecation_reason(arg), ast_node=arg, ) return arg_map def build_input_field_map( nodes: Collection[ Union[InputObjectTypeDefinitionNode, InputObjectTypeExtensionNode] ], ) -> GraphQLInputFieldMap: input_field_map: GraphQLInputFieldMap = {} for node in nodes: for field in node.fields or []: # Note: While this could make assertions to get the correctly typed # value, that would throw immediately while type system validation # with validate_schema() will produce more actionable results. type_ = cast(GraphQLInputType, get_wrapped_type(field.type)) input_field_map[field.name.value] = GraphQLInputField( type_=type_, description=field.description.value if field.description else None, default_value=value_from_ast(field.default_value, type_), deprecation_reason=get_deprecation_reason(field), ast_node=field, ) return input_field_map def build_enum_value_map( nodes: Collection[Union[EnumTypeDefinitionNode, EnumTypeExtensionNode]] ) -> GraphQLEnumValueMap: enum_value_map: GraphQLEnumValueMap = {} for node in nodes: for value in node.values or []: # Note: While this could make assertions to get the correctly typed # value, that would throw immediately while type system validation # with validate_schema() will produce more actionable results. value_name = value.name.value enum_value_map[value_name] = GraphQLEnumValue( value=value_name, description=value.description.value if value.description else None, deprecation_reason=get_deprecation_reason(value), ast_node=value, ) return enum_value_map def build_interfaces( nodes: Collection[ Union[ InterfaceTypeDefinitionNode, InterfaceTypeExtensionNode, ObjectTypeDefinitionNode, ObjectTypeExtensionNode, ] ], ) -> List[GraphQLInterfaceType]: interfaces: List[GraphQLInterfaceType] = [] for node in nodes: for type_ in node.interfaces or []: # Note: While this could make assertions to get the correctly typed # value, that would throw immediately while type system validation # with validate_schema() will produce more actionable results. interfaces.append(cast(GraphQLInterfaceType, get_named_type(type_))) return interfaces def build_union_types( nodes: Collection[Union[UnionTypeDefinitionNode, UnionTypeExtensionNode]], ) -> List[GraphQLObjectType]: types: List[GraphQLObjectType] = [] for node in nodes: for type_ in node.types or []: # Note: While this could make assertions to get the correctly typed # value, that would throw immediately while type system validation # with validate_schema() will produce more actionable results. types.append(cast(GraphQLObjectType, get_named_type(type_))) return types def build_object_type(ast_node: ObjectTypeDefinitionNode) -> GraphQLObjectType: extension_nodes = type_extensions_map[ast_node.name.value] all_nodes: List[Union[ObjectTypeDefinitionNode, ObjectTypeExtensionNode]] = [ ast_node, *extension_nodes, ] return GraphQLObjectType( name=ast_node.name.value, description=ast_node.description.value if ast_node.description else None, interfaces=lambda: build_interfaces(all_nodes), fields=lambda: build_field_map(all_nodes), ast_node=ast_node, extension_ast_nodes=extension_nodes, ) def build_interface_type( ast_node: InterfaceTypeDefinitionNode, ) -> GraphQLInterfaceType: extension_nodes = type_extensions_map[ast_node.name.value] all_nodes: List[ Union[InterfaceTypeDefinitionNode, InterfaceTypeExtensionNode] ] = [ast_node, *extension_nodes] return GraphQLInterfaceType( name=ast_node.name.value, description=ast_node.description.value if ast_node.description else None, interfaces=lambda: build_interfaces(all_nodes), fields=lambda: build_field_map(all_nodes), ast_node=ast_node, extension_ast_nodes=extension_nodes, ) def build_enum_type(ast_node: EnumTypeDefinitionNode) -> GraphQLEnumType: extension_nodes = type_extensions_map[ast_node.name.value] all_nodes: List[Union[EnumTypeDefinitionNode, EnumTypeExtensionNode]] = [ ast_node, *extension_nodes, ] return GraphQLEnumType( name=ast_node.name.value, description=ast_node.description.value if ast_node.description else None, values=build_enum_value_map(all_nodes), ast_node=ast_node, extension_ast_nodes=extension_nodes, ) def build_union_type(ast_node: UnionTypeDefinitionNode) -> GraphQLUnionType: extension_nodes = type_extensions_map[ast_node.name.value] all_nodes: List[Union[UnionTypeDefinitionNode, UnionTypeExtensionNode]] = [ ast_node, *extension_nodes, ] return GraphQLUnionType( name=ast_node.name.value, description=ast_node.description.value if ast_node.description else None, types=lambda: build_union_types(all_nodes), ast_node=ast_node, extension_ast_nodes=extension_nodes, ) def build_scalar_type(ast_node: ScalarTypeDefinitionNode) -> GraphQLScalarType: extension_nodes = type_extensions_map[ast_node.name.value] return GraphQLScalarType( name=ast_node.name.value, description=ast_node.description.value if ast_node.description else None, specified_by_url=get_specified_by_url(ast_node), ast_node=ast_node, extension_ast_nodes=extension_nodes, ) def build_input_object_type( ast_node: InputObjectTypeDefinitionNode, ) -> GraphQLInputObjectType: extension_nodes = type_extensions_map[ast_node.name.value] all_nodes: List[ Union[InputObjectTypeDefinitionNode, InputObjectTypeExtensionNode] ] = [ast_node, *extension_nodes] return GraphQLInputObjectType( name=ast_node.name.value, description=ast_node.description.value if ast_node.description else None, fields=lambda: build_input_field_map(all_nodes), ast_node=ast_node, extension_ast_nodes=extension_nodes, ) build_type_for_kind = cast( Dict[str, Callable[[TypeDefinitionNode], GraphQLNamedType]], { "object_type_definition": build_object_type, "interface_type_definition": build_interface_type, "enum_type_definition": build_enum_type, "union_type_definition": build_union_type, "scalar_type_definition": build_scalar_type, "input_object_type_definition": build_input_object_type, }, ) def build_type(ast_node: TypeDefinitionNode) -> GraphQLNamedType: try: # object_type_definition_node is built with _build_object_type etc. build_function = build_type_for_kind[ast_node.kind] except KeyError: # pragma: no cover # Not reachable. All possible type definition nodes have been considered. raise TypeError( # pragma: no cover f"Unexpected type definition node: {inspect(ast_node)}." ) else: return build_function(ast_node) type_map: Dict[str, GraphQLNamedType] = {} for existing_type in schema_kwargs["types"] or (): type_map[existing_type.name] = extend_named_type(existing_type) for type_node in type_defs: name = type_node.name.value type_map[name] = std_type_map.get(name) or build_type(type_node) # Get the extended root operation types. operation_types: Dict[OperationType, GraphQLNamedType] = {} for operation_type in OperationType: original_type = schema_kwargs[operation_type.value] if original_type: operation_types[operation_type] = replace_named_type(original_type) # Then, incorporate schema definition and all schema extensions. if schema_def: operation_types.update(get_operation_types([schema_def])) if schema_extensions: operation_types.update(get_operation_types(schema_extensions)) # Then produce and return the kwargs for a Schema with these types. get_operation = operation_types.get return GraphQLSchemaKwargs( query=get_operation(OperationType.QUERY), # type: ignore mutation=get_operation(OperationType.MUTATION), # type: ignore subscription=get_operation(OperationType.SUBSCRIPTION), # type: ignore types=tuple(type_map.values()), directives=tuple( replace_directive(directive) for directive in schema_kwargs["directives"] ) + tuple(build_directive(directive) for directive in directive_defs), description=( schema_def.description.value if schema_def and schema_def.description else None ), extensions={}, ast_node=schema_def or schema_kwargs["ast_node"], extension_ast_nodes=schema_kwargs["extension_ast_nodes"] + tuple(schema_extensions), assume_valid=assume_valid, ) std_type_map: Mapping[str, Union[GraphQLNamedType, GraphQLObjectType]] = { **specified_scalar_types, **introspection_types, } def get_deprecation_reason( node: Union[EnumValueDefinitionNode, FieldDefinitionNode, InputValueDefinitionNode] ) -> Optional[str]: """Given a field or enum value node, get deprecation reason as string.""" from ..execution import get_directive_values deprecated = get_directive_values(GraphQLDeprecatedDirective, node) return deprecated["reason"] if deprecated else None def get_specified_by_url( node: Union[ScalarTypeDefinitionNode, ScalarTypeExtensionNode] ) -> Optional[str]: """Given a scalar node, return the string value for the specifiedByURL.""" from ..execution import get_directive_values specified_by_url = get_directive_values(GraphQLSpecifiedByDirective, node) return specified_by_url["url"] if specified_by_url else None graphql-core-3.2.6/src/graphql/utilities/find_breaking_changes.py000066400000000000000000000504241474546154300252140ustar00rootroot00000000000000from enum import Enum from typing import Any, Collection, Dict, List, NamedTuple, Union, cast from ..language import print_ast from ..pyutils import inspect, Undefined from ..type import ( GraphQLEnumType, GraphQLField, GraphQLList, GraphQLNamedType, GraphQLNonNull, GraphQLInputType, GraphQLInterfaceType, GraphQLObjectType, GraphQLSchema, GraphQLType, GraphQLUnionType, is_enum_type, is_input_object_type, is_interface_type, is_list_type, is_named_type, is_non_null_type, is_object_type, is_required_argument, is_required_input_field, is_scalar_type, is_specified_scalar_type, is_union_type, ) from ..utilities.sort_value_node import sort_value_node from .ast_from_value import ast_from_value __all__ = [ "BreakingChange", "BreakingChangeType", "DangerousChange", "DangerousChangeType", "find_breaking_changes", "find_dangerous_changes", ] class BreakingChangeType(Enum): TYPE_REMOVED = 10 TYPE_CHANGED_KIND = 11 TYPE_REMOVED_FROM_UNION = 20 VALUE_REMOVED_FROM_ENUM = 21 REQUIRED_INPUT_FIELD_ADDED = 22 IMPLEMENTED_INTERFACE_REMOVED = 23 FIELD_REMOVED = 30 FIELD_CHANGED_KIND = 31 REQUIRED_ARG_ADDED = 40 ARG_REMOVED = 41 ARG_CHANGED_KIND = 42 DIRECTIVE_REMOVED = 50 DIRECTIVE_ARG_REMOVED = 51 REQUIRED_DIRECTIVE_ARG_ADDED = 52 DIRECTIVE_REPEATABLE_REMOVED = 53 DIRECTIVE_LOCATION_REMOVED = 54 class DangerousChangeType(Enum): VALUE_ADDED_TO_ENUM = 60 TYPE_ADDED_TO_UNION = 61 OPTIONAL_INPUT_FIELD_ADDED = 62 OPTIONAL_ARG_ADDED = 63 IMPLEMENTED_INTERFACE_ADDED = 64 ARG_DEFAULT_VALUE_CHANGE = 65 class BreakingChange(NamedTuple): type: BreakingChangeType description: str class DangerousChange(NamedTuple): type: DangerousChangeType description: str Change = Union[BreakingChange, DangerousChange] def find_breaking_changes( old_schema: GraphQLSchema, new_schema: GraphQLSchema ) -> List[BreakingChange]: """Find breaking changes. Given two schemas, returns a list containing descriptions of all the types of breaking changes covered by the other functions down below. """ return [ change for change in find_schema_changes(old_schema, new_schema) if isinstance(change.type, BreakingChangeType) ] def find_dangerous_changes( old_schema: GraphQLSchema, new_schema: GraphQLSchema ) -> List[DangerousChange]: """Find dangerous changes. Given two schemas, returns a list containing descriptions of all the types of potentially dangerous changes covered by the other functions down below. """ return [ change for change in find_schema_changes(old_schema, new_schema) if isinstance(change.type, DangerousChangeType) ] def find_schema_changes( old_schema: GraphQLSchema, new_schema: GraphQLSchema ) -> List[Change]: return find_type_changes(old_schema, new_schema) + find_directive_changes( old_schema, new_schema ) def find_directive_changes( old_schema: GraphQLSchema, new_schema: GraphQLSchema ) -> List[Change]: schema_changes: List[Change] = [] directives_diff = list_diff(old_schema.directives, new_schema.directives) for directive in directives_diff.removed: schema_changes.append( BreakingChange( BreakingChangeType.DIRECTIVE_REMOVED, f"{directive.name} was removed." ) ) for old_directive, new_directive in directives_diff.persisted: args_diff = dict_diff(old_directive.args, new_directive.args) for arg_name, new_arg in args_diff.added.items(): if is_required_argument(new_arg): schema_changes.append( BreakingChange( BreakingChangeType.REQUIRED_DIRECTIVE_ARG_ADDED, f"A required arg {arg_name} on directive" f" {old_directive.name} was added.", ) ) for arg_name in args_diff.removed: schema_changes.append( BreakingChange( BreakingChangeType.DIRECTIVE_ARG_REMOVED, f"{arg_name} was removed from {new_directive.name}.", ) ) if old_directive.is_repeatable and not new_directive.is_repeatable: schema_changes.append( BreakingChange( BreakingChangeType.DIRECTIVE_REPEATABLE_REMOVED, f"Repeatable flag was removed from {old_directive.name}.", ) ) for location in old_directive.locations: if location not in new_directive.locations: schema_changes.append( BreakingChange( BreakingChangeType.DIRECTIVE_LOCATION_REMOVED, f"{location.name} was removed from {new_directive.name}.", ) ) return schema_changes def find_type_changes( old_schema: GraphQLSchema, new_schema: GraphQLSchema ) -> List[Change]: schema_changes: List[Change] = [] types_diff = dict_diff(old_schema.type_map, new_schema.type_map) for type_name, old_type in types_diff.removed.items(): schema_changes.append( BreakingChange( BreakingChangeType.TYPE_REMOVED, ( f"Standard scalar {type_name} was removed" " because it is not referenced anymore." if is_specified_scalar_type(old_type) else f"{type_name} was removed." ), ) ) for type_name, (old_type, new_type) in types_diff.persisted.items(): if is_enum_type(old_type) and is_enum_type(new_type): schema_changes.extend(find_enum_type_changes(old_type, new_type)) elif is_union_type(old_type) and is_union_type(new_type): schema_changes.extend(find_union_type_changes(old_type, new_type)) elif is_input_object_type(old_type) and is_input_object_type(new_type): schema_changes.extend(find_input_object_type_changes(old_type, new_type)) elif is_object_type(old_type) and is_object_type(new_type): schema_changes.extend(find_field_changes(old_type, new_type)) schema_changes.extend( find_implemented_interfaces_changes(old_type, new_type) ) elif is_interface_type(old_type) and is_interface_type(new_type): schema_changes.extend(find_field_changes(old_type, new_type)) schema_changes.extend( find_implemented_interfaces_changes(old_type, new_type) ) elif old_type.__class__ is not new_type.__class__: schema_changes.append( BreakingChange( BreakingChangeType.TYPE_CHANGED_KIND, f"{type_name} changed from {type_kind_name(old_type)}" f" to {type_kind_name(new_type)}.", ) ) return schema_changes def find_input_object_type_changes( old_type: Union[GraphQLObjectType, GraphQLInterfaceType], new_type: Union[GraphQLObjectType, GraphQLInterfaceType], ) -> List[Change]: schema_changes: List[Change] = [] fields_diff = dict_diff(old_type.fields, new_type.fields) for field_name, new_field in fields_diff.added.items(): if is_required_input_field(new_field): schema_changes.append( BreakingChange( BreakingChangeType.REQUIRED_INPUT_FIELD_ADDED, f"A required field {field_name} on" f" input type {old_type.name} was added.", ) ) else: schema_changes.append( DangerousChange( DangerousChangeType.OPTIONAL_INPUT_FIELD_ADDED, f"An optional field {field_name} on" f" input type {old_type.name} was added.", ) ) for field_name in fields_diff.removed: schema_changes.append( BreakingChange( BreakingChangeType.FIELD_REMOVED, f"{old_type.name}.{field_name} was removed.", ) ) for field_name, (old_field, new_field) in fields_diff.persisted.items(): is_safe = is_change_safe_for_input_object_field_or_field_arg( old_field.type, new_field.type ) if not is_safe: schema_changes.append( BreakingChange( BreakingChangeType.FIELD_CHANGED_KIND, f"{old_type.name}.{field_name} changed type" f" from {old_field.type} to {new_field.type}.", ) ) return schema_changes def find_union_type_changes( old_type: GraphQLUnionType, new_type: GraphQLUnionType ) -> List[Change]: schema_changes: List[Change] = [] possible_types_diff = list_diff(old_type.types, new_type.types) for possible_type in possible_types_diff.added: schema_changes.append( DangerousChange( DangerousChangeType.TYPE_ADDED_TO_UNION, f"{possible_type.name} was added" f" to union type {old_type.name}.", ) ) for possible_type in possible_types_diff.removed: schema_changes.append( BreakingChange( BreakingChangeType.TYPE_REMOVED_FROM_UNION, f"{possible_type.name} was removed from union type {old_type.name}.", ) ) return schema_changes def find_enum_type_changes( old_type: GraphQLEnumType, new_type: GraphQLEnumType ) -> List[Change]: schema_changes: List[Change] = [] values_diff = dict_diff(old_type.values, new_type.values) for value_name in values_diff.added: schema_changes.append( DangerousChange( DangerousChangeType.VALUE_ADDED_TO_ENUM, f"{value_name} was added to enum type {old_type.name}.", ) ) for value_name in values_diff.removed: schema_changes.append( BreakingChange( BreakingChangeType.VALUE_REMOVED_FROM_ENUM, f"{value_name} was removed from enum type {old_type.name}.", ) ) return schema_changes def find_implemented_interfaces_changes( old_type: Union[GraphQLObjectType, GraphQLInterfaceType], new_type: Union[GraphQLObjectType, GraphQLInterfaceType], ) -> List[Change]: schema_changes: List[Change] = [] interfaces_diff = list_diff(old_type.interfaces, new_type.interfaces) for interface in interfaces_diff.added: schema_changes.append( DangerousChange( DangerousChangeType.IMPLEMENTED_INTERFACE_ADDED, f"{interface.name} added to interfaces implemented by {old_type.name}.", ) ) for interface in interfaces_diff.removed: schema_changes.append( BreakingChange( BreakingChangeType.IMPLEMENTED_INTERFACE_REMOVED, f"{old_type.name} no longer implements interface {interface.name}.", ) ) return schema_changes def find_field_changes( old_type: Union[GraphQLObjectType, GraphQLInterfaceType], new_type: Union[GraphQLObjectType, GraphQLInterfaceType], ) -> List[Change]: schema_changes: List[Change] = [] fields_diff = dict_diff(old_type.fields, new_type.fields) for field_name in fields_diff.removed: schema_changes.append( BreakingChange( BreakingChangeType.FIELD_REMOVED, f"{old_type.name}.{field_name} was removed.", ) ) for field_name, (old_field, new_field) in fields_diff.persisted.items(): schema_changes.extend( find_arg_changes(old_type, field_name, old_field, new_field) ) is_safe = is_change_safe_for_object_or_interface_field( old_field.type, new_field.type ) if not is_safe: schema_changes.append( BreakingChange( BreakingChangeType.FIELD_CHANGED_KIND, f"{old_type.name}.{field_name} changed type" f" from {old_field.type} to {new_field.type}.", ) ) return schema_changes def find_arg_changes( old_type: Union[GraphQLObjectType, GraphQLInterfaceType], field_name: str, old_field: GraphQLField, new_field: GraphQLField, ) -> List[Change]: schema_changes: List[Change] = [] args_diff = dict_diff(old_field.args, new_field.args) for arg_name in args_diff.removed: schema_changes.append( BreakingChange( BreakingChangeType.ARG_REMOVED, f"{old_type.name}.{field_name} arg" f" {arg_name} was removed.", ) ) for arg_name, (old_arg, new_arg) in args_diff.persisted.items(): is_safe = is_change_safe_for_input_object_field_or_field_arg( old_arg.type, new_arg.type ) if not is_safe: schema_changes.append( BreakingChange( BreakingChangeType.ARG_CHANGED_KIND, f"{old_type.name}.{field_name} arg" f" {arg_name} has changed type from" f" {old_arg.type} to {new_arg.type}.", ) ) elif old_arg.default_value is not Undefined: if new_arg.default_value is Undefined: schema_changes.append( DangerousChange( DangerousChangeType.ARG_DEFAULT_VALUE_CHANGE, f"{old_type.name}.{field_name} arg" f" {arg_name} defaultValue was removed.", ) ) else: # Since we are looking only for client's observable changes we should # compare default values in the same representation as they are # represented inside introspection. old_value_str = stringify_value(old_arg.default_value, old_arg.type) new_value_str = stringify_value(new_arg.default_value, new_arg.type) if old_value_str != new_value_str: schema_changes.append( DangerousChange( DangerousChangeType.ARG_DEFAULT_VALUE_CHANGE, f"{old_type.name}.{field_name} arg" f" {arg_name} has changed defaultValue" f" from {old_value_str} to {new_value_str}.", ) ) for arg_name, new_arg in args_diff.added.items(): if is_required_argument(new_arg): schema_changes.append( BreakingChange( BreakingChangeType.REQUIRED_ARG_ADDED, f"A required arg {arg_name} on" f" {old_type.name}.{field_name} was added.", ) ) else: schema_changes.append( DangerousChange( DangerousChangeType.OPTIONAL_ARG_ADDED, f"An optional arg {arg_name} on" f" {old_type.name}.{field_name} was added.", ) ) return schema_changes def is_change_safe_for_object_or_interface_field( old_type: GraphQLType, new_type: GraphQLType ) -> bool: if is_list_type(old_type): return ( # if they're both lists, make sure underlying types are compatible is_list_type(new_type) and is_change_safe_for_object_or_interface_field( cast(GraphQLList, old_type).of_type, cast(GraphQLList, new_type).of_type ) ) or ( # moving from nullable to non-null of same underlying type is safe is_non_null_type(new_type) and is_change_safe_for_object_or_interface_field( old_type, cast(GraphQLNonNull, new_type).of_type ) ) if is_non_null_type(old_type): # if they're both non-null, make sure underlying types are compatible return is_non_null_type( new_type ) and is_change_safe_for_object_or_interface_field( cast(GraphQLNonNull, old_type).of_type, cast(GraphQLNonNull, new_type).of_type, ) return ( # if they're both named types, see if their names are equivalent is_named_type(new_type) and cast(GraphQLNamedType, old_type).name == cast(GraphQLNamedType, new_type).name ) or ( # moving from nullable to non-null of same underlying type is safe is_non_null_type(new_type) and is_change_safe_for_object_or_interface_field( old_type, cast(GraphQLNonNull, new_type).of_type ) ) def is_change_safe_for_input_object_field_or_field_arg( old_type: GraphQLType, new_type: GraphQLType ) -> bool: if is_list_type(old_type): return is_list_type( # if they're both lists, make sure underlying types are compatible new_type ) and is_change_safe_for_input_object_field_or_field_arg( cast(GraphQLList, old_type).of_type, cast(GraphQLList, new_type).of_type ) if is_non_null_type(old_type): return ( # if they're both non-null, make sure the underlying types are compatible is_non_null_type(new_type) and is_change_safe_for_input_object_field_or_field_arg( cast(GraphQLNonNull, old_type).of_type, cast(GraphQLNonNull, new_type).of_type, ) ) or ( # moving from non-null to nullable of same underlying type is safe not is_non_null_type(new_type) and is_change_safe_for_input_object_field_or_field_arg( cast(GraphQLNonNull, old_type).of_type, new_type ) ) return ( # if they're both named types, see if their names are equivalent is_named_type(new_type) and cast(GraphQLNamedType, old_type).name == cast(GraphQLNamedType, new_type).name ) def type_kind_name(type_: GraphQLNamedType) -> str: if is_scalar_type(type_): return "a Scalar type" if is_object_type(type_): return "an Object type" if is_interface_type(type_): return "an Interface type" if is_union_type(type_): return "a Union type" if is_enum_type(type_): return "an Enum type" if is_input_object_type(type_): return "an Input type" # Not reachable. All possible output types have been considered. raise TypeError(f"Unexpected type {inspect(type)}") def stringify_value(value: Any, type_: GraphQLInputType) -> str: ast = ast_from_value(value, type_) if ast is None: # pragma: no cover raise TypeError(f"Invalid value: {inspect(value)}") return print_ast(sort_value_node(ast)) class ListDiff(NamedTuple): """Tuple with added, removed and persisted list items.""" added: List removed: List persisted: List def list_diff(old_list: Collection, new_list: Collection) -> ListDiff: """Get differences between two lists of named items.""" added = [] persisted = [] removed = [] old_set = {item.name for item in old_list} new_map = {item.name: item for item in new_list} for old_item in old_list: new_item = new_map.get(old_item.name) if new_item: persisted.append([old_item, new_item]) else: removed.append(old_item) for new_item in new_list: if new_item.name not in old_set: added.append(new_item) return ListDiff(added, removed, persisted) class DictDiff(NamedTuple): """Tuple with added, removed and persisted dict entries.""" added: Dict removed: Dict persisted: Dict def dict_diff(old_dict: Dict, new_dict: Dict) -> DictDiff: """Get differences between two dicts.""" added = {} removed = {} persisted = {} for old_name, old_item in old_dict.items(): new_item = new_dict.get(old_name) if new_item: persisted[old_name] = [old_item, new_item] else: removed[old_name] = old_item for new_name, new_item in new_dict.items(): if new_name not in old_dict: added[new_name] = new_item return DictDiff(added, removed, persisted) graphql-core-3.2.6/src/graphql/utilities/get_introspection_query.py000066400000000000000000000175301474546154300257270ustar00rootroot00000000000000from textwrap import dedent from typing import Any, Dict, List, Optional, Union from ..language import DirectiveLocation try: from typing import Literal, TypedDict except ImportError: # Python < 3.8 from typing_extensions import Literal, TypedDict # type: ignore __all__ = [ "get_introspection_query", "IntrospectionDirective", "IntrospectionEnumType", "IntrospectionField", "IntrospectionInputObjectType", "IntrospectionInputValue", "IntrospectionInterfaceType", "IntrospectionListType", "IntrospectionNonNullType", "IntrospectionObjectType", "IntrospectionQuery", "IntrospectionScalarType", "IntrospectionSchema", "IntrospectionType", "IntrospectionTypeRef", "IntrospectionUnionType", ] def get_introspection_query( descriptions: bool = True, specified_by_url: bool = False, directive_is_repeatable: bool = False, schema_description: bool = False, input_value_deprecation: bool = False, ) -> str: """Get a query for introspection. Optionally, you can exclude descriptions, include specification URLs, include repeatability of directives, and specify whether to include the schema description as well. """ maybe_description = "description" if descriptions else "" maybe_specified_by_url = "specifiedByURL" if specified_by_url else "" maybe_directive_is_repeatable = "isRepeatable" if directive_is_repeatable else "" maybe_schema_description = maybe_description if schema_description else "" def input_deprecation(string: str) -> Optional[str]: return string if input_value_deprecation else "" return dedent( f""" query IntrospectionQuery {{ __schema {{ {maybe_schema_description} queryType {{ name }} mutationType {{ name }} subscriptionType {{ name }} types {{ ...FullType }} directives {{ name {maybe_description} {maybe_directive_is_repeatable} locations args{input_deprecation("(includeDeprecated: true)")} {{ ...InputValue }} }} }} }} fragment FullType on __Type {{ kind name {maybe_description} {maybe_specified_by_url} fields(includeDeprecated: true) {{ name {maybe_description} args{input_deprecation("(includeDeprecated: true)")} {{ ...InputValue }} type {{ ...TypeRef }} isDeprecated deprecationReason }} inputFields{input_deprecation("(includeDeprecated: true)")} {{ ...InputValue }} interfaces {{ ...TypeRef }} enumValues(includeDeprecated: true) {{ name {maybe_description} isDeprecated deprecationReason }} possibleTypes {{ ...TypeRef }} }} fragment InputValue on __InputValue {{ name {maybe_description} type {{ ...TypeRef }} defaultValue {input_deprecation("isDeprecated")} {input_deprecation("deprecationReason")} }} fragment TypeRef on __Type {{ kind name ofType {{ kind name ofType {{ kind name ofType {{ kind name ofType {{ kind name ofType {{ kind name ofType {{ kind name ofType {{ kind name ofType {{ kind name ofType {{ kind name }} }} }} }} }} }} }} }} }} }} """ ) # Unfortunately, the following type definitions are a bit simplistic # because of current restrictions in the typing system (mypy): # - no recursion, see https://github.com/python/mypy/issues/731 # - no generic typed dicts, see https://github.com/python/mypy/issues/3863 # simplified IntrospectionNamedType to avoids cycles SimpleIntrospectionType = Dict[str, Any] class MaybeWithDescription(TypedDict, total=False): description: Optional[str] class WithName(MaybeWithDescription): name: str class MaybeWithSpecifiedByUrl(TypedDict, total=False): specifiedByURL: Optional[str] class WithDeprecated(TypedDict): isDeprecated: bool deprecationReason: Optional[str] class MaybeWithDeprecated(TypedDict, total=False): isDeprecated: bool deprecationReason: Optional[str] class IntrospectionInputValue(WithName, MaybeWithDeprecated): type: SimpleIntrospectionType # should be IntrospectionInputType defaultValue: Optional[str] class IntrospectionField(WithName, WithDeprecated): args: List[IntrospectionInputValue] type: SimpleIntrospectionType # should be IntrospectionOutputType class IntrospectionEnumValue(WithName, WithDeprecated): pass class MaybeWithIsRepeatable(TypedDict, total=False): isRepeatable: bool class IntrospectionDirective(WithName, MaybeWithIsRepeatable): locations: List[DirectiveLocation] args: List[IntrospectionInputValue] class IntrospectionScalarType(WithName, MaybeWithSpecifiedByUrl): kind: Literal["scalar"] class IntrospectionInterfaceType(WithName): kind: Literal["interface"] fields: List[IntrospectionField] interfaces: List[SimpleIntrospectionType] # should be InterfaceType possibleTypes: List[SimpleIntrospectionType] # should be NamedType class IntrospectionObjectType(WithName): kind: Literal["object"] fields: List[IntrospectionField] interfaces: List[SimpleIntrospectionType] # should be InterfaceType class IntrospectionUnionType(WithName): kind: Literal["union"] possibleTypes: List[SimpleIntrospectionType] # should be NamedType class IntrospectionEnumType(WithName): kind: Literal["enum"] enumValues: List[IntrospectionEnumValue] class IntrospectionInputObjectType(WithName): kind: Literal["input_object"] inputFields: List[IntrospectionInputValue] IntrospectionType = Union[ IntrospectionScalarType, IntrospectionObjectType, IntrospectionInterfaceType, IntrospectionUnionType, IntrospectionEnumType, IntrospectionInputObjectType, ] IntrospectionOutputType = Union[ IntrospectionScalarType, IntrospectionObjectType, IntrospectionInterfaceType, IntrospectionUnionType, IntrospectionEnumType, ] IntrospectionInputType = Union[ IntrospectionScalarType, IntrospectionEnumType, IntrospectionInputObjectType ] class IntrospectionListType(TypedDict): kind: Literal["list"] ofType: SimpleIntrospectionType # should be IntrospectionType class IntrospectionNonNullType(TypedDict): kind: Literal["non_null"] ofType: SimpleIntrospectionType # should be IntrospectionType IntrospectionTypeRef = Union[ IntrospectionType, IntrospectionListType, IntrospectionNonNullType ] class IntrospectionSchema(MaybeWithDescription): queryType: IntrospectionObjectType mutationType: Optional[IntrospectionObjectType] subscriptionType: Optional[IntrospectionObjectType] types: List[IntrospectionType] directives: List[IntrospectionDirective] class IntrospectionQuery(TypedDict): """The root typed dictionary for schema introspections.""" __schema: IntrospectionSchema graphql-core-3.2.6/src/graphql/utilities/get_operation_ast.py000066400000000000000000000020771474546154300244510ustar00rootroot00000000000000from typing import Optional from ..language import DocumentNode, OperationDefinitionNode __all__ = ["get_operation_ast"] def get_operation_ast( document_ast: DocumentNode, operation_name: Optional[str] = None ) -> Optional[OperationDefinitionNode]: """Get operation AST node. Returns an operation AST given a document AST and optionally an operation name. If a name is not provided, an operation is only returned if only one is provided in the document. """ operation = None for definition in document_ast.definitions: if isinstance(definition, OperationDefinitionNode): if operation_name is None: # If no operation name was provided, only return an Operation if there # is one defined in the document. # Upon encountering the second, return None. if operation: return None operation = definition elif definition.name and definition.name.value == operation_name: return definition return operation graphql-core-3.2.6/src/graphql/utilities/get_operation_root_type.py000066400000000000000000000027501474546154300257040ustar00rootroot00000000000000from typing import Union from ..error import GraphQLError from ..language import ( OperationType, OperationDefinitionNode, OperationTypeDefinitionNode, ) from ..type import GraphQLObjectType, GraphQLSchema __all__ = ["get_operation_root_type"] def get_operation_root_type( schema: GraphQLSchema, operation: Union[OperationDefinitionNode, OperationTypeDefinitionNode], ) -> GraphQLObjectType: """Extract the root type of the operation from the schema. .. deprecated:: 3.2 Please use `GraphQLSchema.getRootType` instead. Will be removed in v3.3. """ operation_type = operation.operation if operation_type == OperationType.QUERY: query_type = schema.query_type if not query_type: raise GraphQLError( "Schema does not define the required query root type.", operation ) return query_type if operation_type == OperationType.MUTATION: mutation_type = schema.mutation_type if not mutation_type: raise GraphQLError("Schema is not configured for mutations.", operation) return mutation_type if operation_type == OperationType.SUBSCRIPTION: subscription_type = schema.subscription_type if not subscription_type: raise GraphQLError("Schema is not configured for subscriptions.", operation) return subscription_type raise GraphQLError( "Can only have query, mutation and subscription operations.", operation ) graphql-core-3.2.6/src/graphql/utilities/introspection_from_schema.py000066400000000000000000000030731474546154300262030ustar00rootroot00000000000000from typing import cast from ..error import GraphQLError from ..language import parse from ..type import GraphQLSchema from .get_introspection_query import get_introspection_query, IntrospectionQuery __all__ = ["introspection_from_schema"] def introspection_from_schema( schema: GraphQLSchema, descriptions: bool = True, specified_by_url: bool = True, directive_is_repeatable: bool = True, schema_description: bool = True, input_value_deprecation: bool = True, ) -> IntrospectionQuery: """Build an IntrospectionQuery from a GraphQLSchema IntrospectionQuery is useful for utilities that care about type and field relationships, but do not need to traverse through those relationships. This is the inverse of build_client_schema. The primary use case is outside of the server context, for instance when doing schema comparisons. """ document = parse( get_introspection_query( descriptions, specified_by_url, directive_is_repeatable, schema_description, input_value_deprecation, ) ) from ..execution.execute import execute_sync, ExecutionResult result = execute_sync(schema, document) if not isinstance(result, ExecutionResult): # pragma: no cover raise RuntimeError("Introspection cannot be executed") if result.errors: # pragma: no cover raise result.errors[0] if not result.data: # pragma: no cover raise GraphQLError("Introspection did not return a result") return cast(IntrospectionQuery, result.data) graphql-core-3.2.6/src/graphql/utilities/lexicographic_sort_schema.py000066400000000000000000000147731474546154300261610ustar00rootroot00000000000000from typing import Collection, Dict, Optional, Tuple, Union, cast from ..language import DirectiveLocation from ..pyutils import inspect, merge_kwargs, natural_comparison_key from ..type import ( GraphQLArgument, GraphQLDirective, GraphQLEnumType, GraphQLEnumValue, GraphQLField, GraphQLInputField, GraphQLInputObjectType, GraphQLInputType, GraphQLInterfaceType, GraphQLList, GraphQLNamedType, GraphQLNonNull, GraphQLObjectType, GraphQLSchema, GraphQLUnionType, is_enum_type, is_input_object_type, is_interface_type, is_introspection_type, is_list_type, is_non_null_type, is_object_type, is_scalar_type, is_union_type, ) __all__ = ["lexicographic_sort_schema"] def lexicographic_sort_schema(schema: GraphQLSchema) -> GraphQLSchema: """Sort GraphQLSchema. This function returns a sorted copy of the given GraphQLSchema. """ def replace_type( type_: Union[GraphQLList, GraphQLNonNull, GraphQLNamedType] ) -> Union[GraphQLList, GraphQLNonNull, GraphQLNamedType]: if is_list_type(type_): return GraphQLList(replace_type(cast(GraphQLList, type_).of_type)) if is_non_null_type(type_): return GraphQLNonNull(replace_type(cast(GraphQLNonNull, type_).of_type)) return replace_named_type(cast(GraphQLNamedType, type_)) def replace_named_type(type_: GraphQLNamedType) -> GraphQLNamedType: return type_map[type_.name] def replace_maybe_type( maybe_type: Optional[GraphQLNamedType], ) -> Optional[GraphQLNamedType]: return maybe_type and replace_named_type(maybe_type) def sort_directive(directive: GraphQLDirective) -> GraphQLDirective: return GraphQLDirective( **merge_kwargs( directive.to_kwargs(), locations=sorted(directive.locations, key=sort_by_name_key), args=sort_args(directive.args), ) ) def sort_args(args_map: Dict[str, GraphQLArgument]) -> Dict[str, GraphQLArgument]: args = {} for name, arg in sorted(args_map.items()): args[name] = GraphQLArgument( **merge_kwargs( arg.to_kwargs(), type_=replace_type(cast(GraphQLNamedType, arg.type)), ) ) return args def sort_fields(fields_map: Dict[str, GraphQLField]) -> Dict[str, GraphQLField]: fields = {} for name, field in sorted(fields_map.items()): fields[name] = GraphQLField( **merge_kwargs( field.to_kwargs(), type_=replace_type(cast(GraphQLNamedType, field.type)), args=sort_args(field.args), ) ) return fields def sort_input_fields( fields_map: Dict[str, GraphQLInputField] ) -> Dict[str, GraphQLInputField]: return { name: GraphQLInputField( cast( GraphQLInputType, replace_type(cast(GraphQLNamedType, field.type)) ), description=field.description, default_value=field.default_value, ast_node=field.ast_node, ) for name, field in sorted(fields_map.items()) } def sort_types(array: Collection[GraphQLNamedType]) -> Tuple[GraphQLNamedType, ...]: return tuple( replace_named_type(type_) for type_ in sorted(array, key=sort_by_name_key) ) def sort_named_type(type_: GraphQLNamedType) -> GraphQLNamedType: if is_scalar_type(type_) or is_introspection_type(type_): return type_ if is_object_type(type_): type_ = cast(GraphQLObjectType, type_) return GraphQLObjectType( **merge_kwargs( type_.to_kwargs(), interfaces=lambda: sort_types(type_.interfaces), fields=lambda: sort_fields(type_.fields), ) ) if is_interface_type(type_): type_ = cast(GraphQLInterfaceType, type_) return GraphQLInterfaceType( **merge_kwargs( type_.to_kwargs(), interfaces=lambda: sort_types(type_.interfaces), fields=lambda: sort_fields(type_.fields), ) ) if is_union_type(type_): type_ = cast(GraphQLUnionType, type_) return GraphQLUnionType( **merge_kwargs(type_.to_kwargs(), types=lambda: sort_types(type_.types)) ) if is_enum_type(type_): type_ = cast(GraphQLEnumType, type_) return GraphQLEnumType( **merge_kwargs( type_.to_kwargs(), values={ name: GraphQLEnumValue( val.value, description=val.description, deprecation_reason=val.deprecation_reason, ast_node=val.ast_node, ) for name, val in sorted(type_.values.items()) }, ) ) if is_input_object_type(type_): type_ = cast(GraphQLInputObjectType, type_) return GraphQLInputObjectType( **merge_kwargs( type_.to_kwargs(), fields=lambda: sort_input_fields(type_.fields), ) ) # Not reachable. All possible types have been considered. raise TypeError(f"Unexpected type: {inspect(type_)}.") type_map: Dict[str, GraphQLNamedType] = { type_.name: sort_named_type(type_) for type_ in sorted(schema.type_map.values(), key=sort_by_name_key) } return GraphQLSchema( types=type_map.values(), directives=[ sort_directive(directive) for directive in sorted(schema.directives, key=sort_by_name_key) ], query=cast(Optional[GraphQLObjectType], replace_maybe_type(schema.query_type)), mutation=cast( Optional[GraphQLObjectType], replace_maybe_type(schema.mutation_type) ), subscription=cast( Optional[GraphQLObjectType], replace_maybe_type(schema.subscription_type) ), ast_node=schema.ast_node, ) def sort_by_name_key( type_: Union[GraphQLNamedType, GraphQLDirective, DirectiveLocation] ) -> Tuple: return natural_comparison_key(type_.name) graphql-core-3.2.6/src/graphql/utilities/print_schema.py000066400000000000000000000216661474546154300234240ustar00rootroot00000000000000from typing import Any, Callable, Dict, List, Optional, Union, cast from ..language import print_ast, StringValueNode from ..language.block_string import is_printable_as_block_string from ..pyutils import inspect from ..type import ( DEFAULT_DEPRECATION_REASON, GraphQLArgument, GraphQLDirective, GraphQLEnumType, GraphQLEnumValue, GraphQLInputObjectType, GraphQLInputType, GraphQLInterfaceType, GraphQLNamedType, GraphQLObjectType, GraphQLScalarType, GraphQLSchema, GraphQLUnionType, is_enum_type, is_input_object_type, is_interface_type, is_introspection_type, is_object_type, is_scalar_type, is_specified_directive, is_specified_scalar_type, is_union_type, ) from .ast_from_value import ast_from_value __all__ = ["print_schema", "print_introspection_schema", "print_type", "print_value"] def print_schema(schema: GraphQLSchema) -> str: return print_filtered_schema( schema, lambda n: not is_specified_directive(n), is_defined_type ) def print_introspection_schema(schema: GraphQLSchema) -> str: return print_filtered_schema(schema, is_specified_directive, is_introspection_type) def is_defined_type(type_: GraphQLNamedType) -> bool: return not is_specified_scalar_type(type_) and not is_introspection_type(type_) def print_filtered_schema( schema: GraphQLSchema, directive_filter: Callable[[GraphQLDirective], bool], type_filter: Callable[[GraphQLNamedType], bool], ) -> str: directives = filter(directive_filter, schema.directives) types = filter(type_filter, schema.type_map.values()) return "\n\n".join( ( *filter(None, (print_schema_definition(schema),)), *map(print_directive, directives), *map(print_type, types), ) ) def print_schema_definition(schema: GraphQLSchema) -> Optional[str]: if schema.description is None and is_schema_of_common_names(schema): return None operation_types = [] query_type = schema.query_type if query_type: operation_types.append(f" query: {query_type.name}") mutation_type = schema.mutation_type if mutation_type: operation_types.append(f" mutation: {mutation_type.name}") subscription_type = schema.subscription_type if subscription_type: operation_types.append(f" subscription: {subscription_type.name}") return print_description(schema) + "schema {\n" + "\n".join(operation_types) + "\n}" def is_schema_of_common_names(schema: GraphQLSchema) -> bool: """Check whether this schema uses the common naming convention. GraphQL schema define root types for each type of operation. These types are the same as any other type and can be named in any manner, however there is a common naming convention: schema { query: Query mutation: Mutation subscription: Subscription } When using this naming convention, the schema description can be omitted. """ query_type = schema.query_type if query_type and query_type.name != "Query": return False mutation_type = schema.mutation_type if mutation_type and mutation_type.name != "Mutation": return False subscription_type = schema.subscription_type return not subscription_type or subscription_type.name == "Subscription" def print_type(type_: GraphQLNamedType) -> str: if is_scalar_type(type_): type_ = cast(GraphQLScalarType, type_) return print_scalar(type_) if is_object_type(type_): type_ = cast(GraphQLObjectType, type_) return print_object(type_) if is_interface_type(type_): type_ = cast(GraphQLInterfaceType, type_) return print_interface(type_) if is_union_type(type_): type_ = cast(GraphQLUnionType, type_) return print_union(type_) if is_enum_type(type_): type_ = cast(GraphQLEnumType, type_) return print_enum(type_) if is_input_object_type(type_): type_ = cast(GraphQLInputObjectType, type_) return print_input_object(type_) # Not reachable. All possible types have been considered. raise TypeError(f"Unexpected type: {inspect(type_)}.") def print_scalar(type_: GraphQLScalarType) -> str: return ( print_description(type_) + f"scalar {type_.name}" + print_specified_by_url(type_) ) def print_implemented_interfaces( type_: Union[GraphQLObjectType, GraphQLInterfaceType] ) -> str: interfaces = type_.interfaces return " implements " + " & ".join(i.name for i in interfaces) if interfaces else "" def print_object(type_: GraphQLObjectType) -> str: return ( print_description(type_) + f"type {type_.name}" + print_implemented_interfaces(type_) + print_fields(type_) ) def print_interface(type_: GraphQLInterfaceType) -> str: return ( print_description(type_) + f"interface {type_.name}" + print_implemented_interfaces(type_) + print_fields(type_) ) def print_union(type_: GraphQLUnionType) -> str: types = type_.types possible_types = " = " + " | ".join(t.name for t in types) if types else "" return print_description(type_) + f"union {type_.name}" + possible_types def print_enum(type_: GraphQLEnumType) -> str: values = [ print_description(value, " ", not i) + f" {name}" + print_deprecated(value.deprecation_reason) for i, (name, value) in enumerate(type_.values.items()) ] return print_description(type_) + f"enum {type_.name}" + print_block(values) def print_input_object(type_: GraphQLInputObjectType) -> str: fields = [ print_description(field, " ", not i) + " " + print_input_value(name, field) for i, (name, field) in enumerate(type_.fields.items()) ] return print_description(type_) + f"input {type_.name}" + print_block(fields) def print_fields(type_: Union[GraphQLObjectType, GraphQLInterfaceType]) -> str: fields = [ print_description(field, " ", not i) + f" {name}" + print_args(field.args, " ") + f": {field.type}" + print_deprecated(field.deprecation_reason) for i, (name, field) in enumerate(type_.fields.items()) ] return print_block(fields) def print_block(items: List[str]) -> str: return " {\n" + "\n".join(items) + "\n}" if items else "" def print_args(args: Dict[str, GraphQLArgument], indentation: str = "") -> str: if not args: return "" # If every arg does not have a description, print them on one line. if not any(arg.description for arg in args.values()): return ( "(" + ", ".join(print_input_value(name, arg) for name, arg in args.items()) + ")" ) return ( "(\n" + "\n".join( print_description(arg, f" {indentation}", not i) + f" {indentation}" + print_input_value(name, arg) for i, (name, arg) in enumerate(args.items()) ) + f"\n{indentation})" ) def print_input_value(name: str, arg: GraphQLArgument) -> str: default_ast = ast_from_value(arg.default_value, arg.type) arg_decl = f"{name}: {arg.type}" if default_ast: arg_decl += f" = {print_ast(default_ast)}" return arg_decl + print_deprecated(arg.deprecation_reason) def print_directive(directive: GraphQLDirective) -> str: return ( print_description(directive) + f"directive @{directive.name}" + print_args(directive.args) + (" repeatable" if directive.is_repeatable else "") + " on " + " | ".join(location.name for location in directive.locations) ) def print_deprecated(reason: Optional[str]) -> str: if reason is None: return "" if reason != DEFAULT_DEPRECATION_REASON: ast_value = print_ast(StringValueNode(value=reason)) return f" @deprecated(reason: {ast_value})" return " @deprecated" def print_specified_by_url(scalar: GraphQLScalarType) -> str: if scalar.specified_by_url is None: return "" ast_value = print_ast(StringValueNode(value=scalar.specified_by_url)) return f" @specifiedBy(url: {ast_value})" def print_description( def_: Union[ GraphQLArgument, GraphQLDirective, GraphQLEnumValue, GraphQLNamedType, GraphQLSchema, ], indentation: str = "", first_in_block: bool = True, ) -> str: description = def_.description if description is None: return "" block_string = print_ast( StringValueNode( value=description, block=is_printable_as_block_string(description) ) ) prefix = "\n" + indentation if indentation and not first_in_block else indentation return prefix + block_string.replace("\n", "\n" + indentation) + "\n" def print_value(value: Any, type_: GraphQLInputType) -> str: """@deprecated: Convenience function for printing a Python value""" return print_ast(ast_from_value(value, type_)) # type: ignore graphql-core-3.2.6/src/graphql/utilities/separate_operations.py000066400000000000000000000065161474546154300250140ustar00rootroot00000000000000from typing import Any, Dict, List, Set from ..language import ( DocumentNode, FragmentDefinitionNode, FragmentSpreadNode, OperationDefinitionNode, SelectionSetNode, Visitor, visit, ) __all__ = ["separate_operations"] DepGraph = Dict[str, List[str]] def separate_operations(document_ast: DocumentNode) -> Dict[str, DocumentNode]: """Separate operations in a given AST document. This function accepts a single AST document which may contain many operations and fragments and returns a collection of AST documents each of which contains a single operation as well the fragment definitions it refers to. """ operations: List[OperationDefinitionNode] = [] dep_graph: DepGraph = {} # Populate metadata and build a dependency graph. for definition_node in document_ast.definitions: if isinstance(definition_node, OperationDefinitionNode): operations.append(definition_node) elif isinstance( definition_node, FragmentDefinitionNode ): # pragma: no cover else dep_graph[definition_node.name.value] = collect_dependencies( definition_node.selection_set ) # For each operation, produce a new synthesized AST which includes only what is # necessary for completing that operation. separated_document_asts: Dict[str, DocumentNode] = {} for operation in operations: dependencies: Set[str] = set() for fragment_name in collect_dependencies(operation.selection_set): collect_transitive_dependencies(dependencies, dep_graph, fragment_name) # Provides the empty string for anonymous operations. operation_name = operation.name.value if operation.name else "" # The list of definition nodes to be included for this operation, sorted # to retain the same order as the original document. separated_document_asts[operation_name] = DocumentNode( definitions=[ node for node in document_ast.definitions if node is operation or ( isinstance(node, FragmentDefinitionNode) and node.name.value in dependencies ) ] ) return separated_document_asts def collect_transitive_dependencies( collected: Set[str], dep_graph: DepGraph, from_name: str ) -> None: """Collect transitive dependencies. From a dependency graph, collects a list of transitive dependencies by recursing through a dependency graph. """ if from_name not in collected: collected.add(from_name) immediate_deps = dep_graph.get(from_name) if immediate_deps is not None: for to_name in immediate_deps: collect_transitive_dependencies(collected, dep_graph, to_name) class DependencyCollector(Visitor): dependencies: List[str] def __init__(self) -> None: super().__init__() self.dependencies = [] self.add_dependency = self.dependencies.append def enter_fragment_spread(self, node: FragmentSpreadNode, *_args: Any) -> None: self.add_dependency(node.name.value) def collect_dependencies(selection_set: SelectionSetNode) -> List[str]: collector = DependencyCollector() visit(selection_set, collector) return collector.dependencies graphql-core-3.2.6/src/graphql/utilities/sort_value_node.py000066400000000000000000000021651474546154300241310ustar00rootroot00000000000000from copy import copy from typing import Tuple from ..language import ListValueNode, ObjectFieldNode, ObjectValueNode, ValueNode from ..pyutils import natural_comparison_key __all__ = ["sort_value_node"] def sort_value_node(value_node: ValueNode) -> ValueNode: """Sort ValueNode. This function returns a sorted copy of the given ValueNode For internal use only. """ if isinstance(value_node, ObjectValueNode): value_node = copy(value_node) value_node.fields = sort_fields(value_node.fields) elif isinstance(value_node, ListValueNode): value_node = copy(value_node) value_node.values = tuple(sort_value_node(value) for value in value_node.values) return value_node def sort_field(field: ObjectFieldNode) -> ObjectFieldNode: field = copy(field) field.value = sort_value_node(field.value) return field def sort_fields(fields: Tuple[ObjectFieldNode, ...]) -> Tuple[ObjectFieldNode, ...]: return tuple( sorted( (sort_field(field) for field in fields), key=lambda field: natural_comparison_key(field.name.value), ) ) graphql-core-3.2.6/src/graphql/utilities/strip_ignored_characters.py000066400000000000000000000056011474546154300260060ustar00rootroot00000000000000from typing import Union, cast from ..language import Lexer, TokenKind from ..language.source import Source, is_source from ..language.block_string import print_block_string from ..language.lexer import is_punctuator_token_kind __all__ = ["strip_ignored_characters"] def strip_ignored_characters(source: Union[str, Source]) -> str: """Strip characters that are ignored anyway. Strips characters that are not significant to the validity or execution of a GraphQL document: - UnicodeBOM - WhiteSpace - LineTerminator - Comment - Comma - BlockString indentation Note: It is required to have a delimiter character between neighboring non-punctuator tokes and this function always uses single space as delimiter. It is guaranteed that both input and output documents if parsed would result in the exact same AST except for nodes location. Warning: It is guaranteed that this function will always produce stable results. However, it's not guaranteed that it will stay the same between different releases due to bugfixes or changes in the GraphQL specification. """ ''' Query example:: query SomeQuery($foo: String!, $bar: String) { someField(foo: $foo, bar: $bar) { a b { c d } } } Becomes:: query SomeQuery($foo:String!$bar:String){someField(foo:$foo bar:$bar){a b{c d}}} SDL example:: """ Type description """ type Foo { """ Field description """ bar: String } Becomes:: """Type description""" type Foo{"""Field description""" bar:String} ''' source = cast(Source, source) if is_source(source) else Source(cast(str, source)) body = source.body lexer = Lexer(source) stripped_body = "" was_last_added_token_non_punctuator = False while lexer.advance().kind != TokenKind.EOF: current_token = lexer.token token_kind = current_token.kind # Every two non-punctuator tokens should have space between them. # Also prevent case of non-punctuator token following by spread resulting # in invalid token (e.g.`1...` is invalid Float token). is_non_punctuator = not is_punctuator_token_kind(current_token.kind) if was_last_added_token_non_punctuator and ( is_non_punctuator or current_token.kind == TokenKind.SPREAD ): stripped_body += " " token_body = body[current_token.start : current_token.end] if token_kind == TokenKind.BLOCK_STRING: stripped_body += print_block_string( current_token.value or "", minimize=True ) else: stripped_body += token_body was_last_added_token_non_punctuator = is_non_punctuator return stripped_body graphql-core-3.2.6/src/graphql/utilities/type_comparators.py000066400000000000000000000110251474546154300243270ustar00rootroot00000000000000from typing import cast from ..type import ( GraphQLAbstractType, GraphQLCompositeType, GraphQLList, GraphQLNonNull, GraphQLObjectType, GraphQLSchema, GraphQLType, is_abstract_type, is_interface_type, is_list_type, is_non_null_type, is_object_type, ) __all__ = ["is_equal_type", "is_type_sub_type_of", "do_types_overlap"] def is_equal_type(type_a: GraphQLType, type_b: GraphQLType) -> bool: """Check whether two types are equal. Provided two types, return true if the types are equal (invariant).""" # Equivalent types are equal. if type_a is type_b: return True # If either type is non-null, the other must also be non-null. if is_non_null_type(type_a) and is_non_null_type(type_b): # noinspection PyUnresolvedReferences return is_equal_type(type_a.of_type, type_b.of_type) # type:ignore # If either type is a list, the other must also be a list. if is_list_type(type_a) and is_list_type(type_b): # noinspection PyUnresolvedReferences return is_equal_type(type_a.of_type, type_b.of_type) # type:ignore # Otherwise the types are not equal. return False def is_type_sub_type_of( schema: GraphQLSchema, maybe_subtype: GraphQLType, super_type: GraphQLType ) -> bool: """Check whether a type is subtype of another type in a given schema. Provided a type and a super type, return true if the first type is either equal or a subset of the second super type (covariant). """ # Equivalent type is a valid subtype if maybe_subtype is super_type: return True # If super_type is non-null, maybe_subtype must also be non-null. if is_non_null_type(super_type): if is_non_null_type(maybe_subtype): return is_type_sub_type_of( schema, cast(GraphQLNonNull, maybe_subtype).of_type, cast(GraphQLNonNull, super_type).of_type, ) return False elif is_non_null_type(maybe_subtype): # If super_type is nullable, maybe_subtype may be non-null or nullable. return is_type_sub_type_of( schema, cast(GraphQLNonNull, maybe_subtype).of_type, super_type ) # If super_type type is a list, maybeSubType type must also be a list. if is_list_type(super_type): if is_list_type(maybe_subtype): return is_type_sub_type_of( schema, cast(GraphQLList, maybe_subtype).of_type, cast(GraphQLList, super_type).of_type, ) return False elif is_list_type(maybe_subtype): # If super_type is not a list, maybe_subtype must also be not a list. return False # If super_type type is abstract, check if it is super type of maybe_subtype. # Otherwise, the child type is not a valid subtype of the parent type. return ( is_abstract_type(super_type) and (is_interface_type(maybe_subtype) or is_object_type(maybe_subtype)) and schema.is_sub_type( cast(GraphQLAbstractType, super_type), cast(GraphQLObjectType, maybe_subtype), ) ) def do_types_overlap( schema: GraphQLSchema, type_a: GraphQLCompositeType, type_b: GraphQLCompositeType ) -> bool: """Check whether two types overlap in a given schema. Provided two composite types, determine if they "overlap". Two composite types overlap when the Sets of possible concrete types for each intersect. This is often used to determine if a fragment of a given type could possibly be visited in a context of another type. This function is commutative. """ # Equivalent types overlap if type_a is type_b: return True if is_abstract_type(type_a): type_a = cast(GraphQLAbstractType, type_a) if is_abstract_type(type_b): # If both types are abstract, then determine if there is any intersection # between possible concrete types of each. type_b = cast(GraphQLAbstractType, type_b) return any( schema.is_sub_type(type_b, type_) for type_ in schema.get_possible_types(type_a) ) # Determine if latter type is a possible concrete type of the former. return schema.is_sub_type(type_a, type_b) if is_abstract_type(type_b): # Determine if former type is a possible concrete type of the latter. type_b = cast(GraphQLAbstractType, type_b) return schema.is_sub_type(type_b, type_a) # Otherwise the types do not overlap. return False graphql-core-3.2.6/src/graphql/utilities/type_from_ast.py000066400000000000000000000037101474546154300236110ustar00rootroot00000000000000from typing import Optional, cast, overload from ..language import ListTypeNode, NamedTypeNode, NonNullTypeNode, TypeNode from ..pyutils import inspect from ..type import ( GraphQLList, GraphQLNamedType, GraphQLNonNull, GraphQLNullableType, GraphQLSchema, GraphQLType, ) __all__ = ["type_from_ast"] @overload def type_from_ast( schema: GraphQLSchema, type_node: NamedTypeNode ) -> Optional[GraphQLNamedType]: ... @overload def type_from_ast( schema: GraphQLSchema, type_node: ListTypeNode ) -> Optional[GraphQLList]: ... @overload def type_from_ast( schema: GraphQLSchema, type_node: NonNullTypeNode ) -> Optional[GraphQLNonNull]: ... @overload def type_from_ast( schema: GraphQLSchema, type_node: TypeNode ) -> Optional[GraphQLType]: ... def type_from_ast( schema: GraphQLSchema, type_node: TypeNode, ) -> Optional[GraphQLType]: """Get the GraphQL type definition from an AST node. Given a Schema and an AST node describing a type, return a GraphQLType definition which applies to that type. For example, if provided the parsed AST node for ``[User]``, a GraphQLList instance will be returned, containing the type called "User" found in the schema. If a type called "User" is not found in the schema, then None will be returned. """ inner_type: Optional[GraphQLType] if isinstance(type_node, ListTypeNode): inner_type = type_from_ast(schema, type_node.type) return GraphQLList(inner_type) if inner_type else None if isinstance(type_node, NonNullTypeNode): inner_type = type_from_ast(schema, type_node.type) inner_type = cast(GraphQLNullableType, inner_type) return GraphQLNonNull(inner_type) if inner_type else None if isinstance(type_node, NamedTypeNode): return schema.get_type(type_node.name.value) # Not reachable. All possible type nodes have been considered. raise TypeError(f"Unexpected type node: {inspect(type_node)}.") graphql-core-3.2.6/src/graphql/utilities/type_info.py000066400000000000000000000260441474546154300227370ustar00rootroot00000000000000from typing import Any, Callable, List, Optional, Union, cast from ..language import ( ArgumentNode, DirectiveNode, EnumValueNode, FieldNode, InlineFragmentNode, ListValueNode, Node, ObjectFieldNode, OperationDefinitionNode, SelectionSetNode, VariableDefinitionNode, Visitor, ) from ..pyutils import Undefined from ..type import ( GraphQLArgument, GraphQLCompositeType, GraphQLDirective, GraphQLEnumType, GraphQLEnumValue, GraphQLField, GraphQLInputObjectType, GraphQLInputType, GraphQLInterfaceType, GraphQLList, GraphQLObjectType, GraphQLOutputType, GraphQLSchema, GraphQLType, is_composite_type, is_input_type, is_output_type, get_named_type, SchemaMetaFieldDef, TypeMetaFieldDef, TypeNameMetaFieldDef, is_object_type, is_interface_type, get_nullable_type, is_list_type, is_input_object_type, is_enum_type, ) from .type_from_ast import type_from_ast __all__ = ["TypeInfo", "TypeInfoVisitor"] GetFieldDefFn = Callable[ [GraphQLSchema, GraphQLType, FieldNode], Optional[GraphQLField] ] class TypeInfo: """Utility class for keeping track of type definitions. TypeInfo is a utility class which, given a GraphQL schema, can keep track of the current field and type definitions at any point in a GraphQL document AST during a recursive descent by calling :meth:`enter(node) <.TypeInfo.enter>` and :meth:`leave(node) <.TypeInfo.leave>`. """ def __init__( self, schema: GraphQLSchema, initial_type: Optional[GraphQLType] = None, get_field_def_fn: Optional[GetFieldDefFn] = None, ) -> None: """Initialize the TypeInfo for the given GraphQL schema. Initial type may be provided in rare cases to facilitate traversals beginning somewhere other than documents. The optional last parameter is deprecated and will be removed in v3.3. """ self._schema = schema self._type_stack: List[Optional[GraphQLOutputType]] = [] self._parent_type_stack: List[Optional[GraphQLCompositeType]] = [] self._input_type_stack: List[Optional[GraphQLInputType]] = [] self._field_def_stack: List[Optional[GraphQLField]] = [] self._default_value_stack: List[Any] = [] self._directive: Optional[GraphQLDirective] = None self._argument: Optional[GraphQLArgument] = None self._enum_value: Optional[GraphQLEnumValue] = None self._get_field_def: GetFieldDefFn = get_field_def_fn or get_field_def if initial_type: if is_input_type(initial_type): self._input_type_stack.append(cast(GraphQLInputType, initial_type)) if is_composite_type(initial_type): self._parent_type_stack.append(cast(GraphQLCompositeType, initial_type)) if is_output_type(initial_type): self._type_stack.append(cast(GraphQLOutputType, initial_type)) def get_type(self) -> Optional[GraphQLOutputType]: if self._type_stack: return self._type_stack[-1] return None def get_parent_type(self) -> Optional[GraphQLCompositeType]: if self._parent_type_stack: return self._parent_type_stack[-1] return None def get_input_type(self) -> Optional[GraphQLInputType]: if self._input_type_stack: return self._input_type_stack[-1] return None def get_parent_input_type(self) -> Optional[GraphQLInputType]: if len(self._input_type_stack) > 1: return self._input_type_stack[-2] return None def get_field_def(self) -> Optional[GraphQLField]: if self._field_def_stack: return self._field_def_stack[-1] return None def get_default_value(self) -> Any: if self._default_value_stack: return self._default_value_stack[-1] return None def get_directive(self) -> Optional[GraphQLDirective]: return self._directive def get_argument(self) -> Optional[GraphQLArgument]: return self._argument def get_enum_value(self) -> Optional[GraphQLEnumValue]: return self._enum_value def enter(self, node: Node) -> None: method = getattr(self, "enter_" + node.kind, None) if method: method(node) def leave(self, node: Node) -> None: method = getattr(self, "leave_" + node.kind, None) if method: method() # noinspection PyUnusedLocal def enter_selection_set(self, node: SelectionSetNode) -> None: named_type = get_named_type(self.get_type()) self._parent_type_stack.append( cast(GraphQLCompositeType, named_type) if is_composite_type(named_type) else None ) def enter_field(self, node: FieldNode) -> None: parent_type = self.get_parent_type() if parent_type: field_def = self._get_field_def(self._schema, parent_type, node) field_type = field_def.type if field_def else None else: field_def = field_type = None self._field_def_stack.append(field_def) self._type_stack.append(field_type if is_output_type(field_type) else None) def enter_directive(self, node: DirectiveNode) -> None: self._directive = self._schema.get_directive(node.name.value) def enter_operation_definition(self, node: OperationDefinitionNode) -> None: root_type = self._schema.get_root_type(node.operation) self._type_stack.append(root_type if is_object_type(root_type) else None) def enter_inline_fragment(self, node: InlineFragmentNode) -> None: type_condition_ast = node.type_condition output_type = ( type_from_ast(self._schema, type_condition_ast) if type_condition_ast else get_named_type(self.get_type()) ) self._type_stack.append( cast(GraphQLOutputType, output_type) if is_output_type(output_type) else None ) enter_fragment_definition = enter_inline_fragment def enter_variable_definition(self, node: VariableDefinitionNode) -> None: input_type = type_from_ast(self._schema, node.type) self._input_type_stack.append( cast(GraphQLInputType, input_type) if is_input_type(input_type) else None ) def enter_argument(self, node: ArgumentNode) -> None: field_or_directive = self.get_directive() or self.get_field_def() if field_or_directive: arg_def = field_or_directive.args.get(node.name.value) arg_type = arg_def.type if arg_def else None else: arg_def = arg_type = None self._argument = arg_def self._default_value_stack.append( arg_def.default_value if arg_def else Undefined ) self._input_type_stack.append(arg_type if is_input_type(arg_type) else None) # noinspection PyUnusedLocal def enter_list_value(self, node: ListValueNode) -> None: list_type = get_nullable_type(self.get_input_type()) # type: ignore item_type = ( cast(GraphQLList, list_type).of_type if is_list_type(list_type) else list_type ) # List positions never have a default value. self._default_value_stack.append(Undefined) self._input_type_stack.append(item_type if is_input_type(item_type) else None) def enter_object_field(self, node: ObjectFieldNode) -> None: object_type = get_named_type(self.get_input_type()) if is_input_object_type(object_type): input_field = cast(GraphQLInputObjectType, object_type).fields.get( node.name.value ) input_field_type = input_field.type if input_field else None else: input_field = input_field_type = None self._default_value_stack.append( input_field.default_value if input_field else Undefined ) self._input_type_stack.append( input_field_type if is_input_type(input_field_type) else None ) def enter_enum_value(self, node: EnumValueNode) -> None: enum_type = get_named_type(self.get_input_type()) if is_enum_type(enum_type): enum_value = cast(GraphQLEnumType, enum_type).values.get(node.value) else: enum_value = None self._enum_value = enum_value def leave_selection_set(self) -> None: del self._parent_type_stack[-1:] def leave_field(self) -> None: del self._field_def_stack[-1:] del self._type_stack[-1:] def leave_directive(self) -> None: self._directive = None def leave_operation_definition(self) -> None: del self._type_stack[-1:] leave_inline_fragment = leave_operation_definition leave_fragment_definition = leave_operation_definition def leave_variable_definition(self) -> None: del self._input_type_stack[-1:] def leave_argument(self) -> None: self._argument = None del self._default_value_stack[-1:] del self._input_type_stack[-1:] def leave_list_value(self) -> None: del self._default_value_stack[-1:] del self._input_type_stack[-1:] leave_object_field = leave_list_value def leave_enum_value(self) -> None: self._enum_value = None def get_field_def( schema: GraphQLSchema, parent_type: GraphQLType, field_node: FieldNode ) -> Optional[GraphQLField]: """Get field definition. Not exactly the same as the executor's definition of :func:`graphql.execution.get_field_def`, in this statically evaluated environment we do not always have an Object type, and need to handle Interface and Union types. """ name = field_node.name.value if name == "__schema" and schema.query_type is parent_type: return SchemaMetaFieldDef if name == "__type" and schema.query_type is parent_type: return TypeMetaFieldDef if name == "__typename" and is_composite_type(parent_type): return TypeNameMetaFieldDef if is_object_type(parent_type) or is_interface_type(parent_type): parent_type = cast(Union[GraphQLObjectType, GraphQLInterfaceType], parent_type) return parent_type.fields.get(name) return None class TypeInfoVisitor(Visitor): """A visitor which maintains a provided TypeInfo.""" def __init__(self, type_info: "TypeInfo", visitor: Visitor): super().__init__() self.type_info = type_info self.visitor = visitor def enter(self, node: Node, *args: Any) -> Any: self.type_info.enter(node) fn = self.visitor.get_enter_leave_for_kind(node.kind).enter if fn: result = fn(node, *args) if result is not None: self.type_info.leave(node) if isinstance(result, Node): self.type_info.enter(result) return result def leave(self, node: Node, *args: Any) -> Any: fn = self.visitor.get_enter_leave_for_kind(node.kind).leave result = fn(node, *args) if fn else None self.type_info.leave(node) return result graphql-core-3.2.6/src/graphql/utilities/value_from_ast.py000066400000000000000000000131741474546154300237510ustar00rootroot00000000000000from typing import Any, Dict, List, Optional, cast from ..language import ( ListValueNode, NullValueNode, ObjectValueNode, ValueNode, VariableNode, ) from ..pyutils import inspect, Undefined from ..type import ( GraphQLInputObjectType, GraphQLInputType, GraphQLList, GraphQLNonNull, GraphQLScalarType, is_input_object_type, is_leaf_type, is_list_type, is_non_null_type, ) __all__ = ["value_from_ast"] def value_from_ast( value_node: Optional[ValueNode], type_: GraphQLInputType, variables: Optional[Dict[str, Any]] = None, ) -> Any: """Produce a Python value given a GraphQL Value AST. A GraphQL type must be provided, which will be used to interpret different GraphQL Value literals. Returns ``Undefined`` when the value could not be validly coerced according to the provided type. =================== ============== ================ GraphQL Value JSON Value Python Value =================== ============== ================ Input Object Object dict List Array list Boolean Boolean bool String String str Int / Float Number int / float Enum Value Mixed Any NullValue null None =================== ============== ================ """ if not value_node: # When there is no node, then there is also no value. # Importantly, this is different from returning the value null. return Undefined if isinstance(value_node, VariableNode): variable_name = value_node.name.value if not variables: return Undefined variable_value = variables.get(variable_name, Undefined) if variable_value is None and is_non_null_type(type_): return Undefined # Note: This does no further checking that this variable is correct. # This assumes that this query has been validated and the variable usage here # is of the correct type. return variable_value if is_non_null_type(type_): if isinstance(value_node, NullValueNode): return Undefined type_ = cast(GraphQLNonNull, type_) return value_from_ast(value_node, type_.of_type, variables) if isinstance(value_node, NullValueNode): return None # This is explicitly returning the value None. if is_list_type(type_): type_ = cast(GraphQLList, type_) item_type = type_.of_type if isinstance(value_node, ListValueNode): coerced_values: List[Any] = [] append_value = coerced_values.append for item_node in value_node.values: if is_missing_variable(item_node, variables): # If an array contains a missing variable, it is either coerced to # None or if the item type is non-null, it is considered invalid. if is_non_null_type(item_type): return Undefined append_value(None) else: item_value = value_from_ast(item_node, item_type, variables) if item_value is Undefined: return Undefined append_value(item_value) return coerced_values coerced_value = value_from_ast(value_node, item_type, variables) if coerced_value is Undefined: return Undefined return [coerced_value] if is_input_object_type(type_): if not isinstance(value_node, ObjectValueNode): return Undefined type_ = cast(GraphQLInputObjectType, type_) coerced_obj: Dict[str, Any] = {} fields = type_.fields field_nodes = {field.name.value: field for field in value_node.fields} for field_name, field in fields.items(): field_node = field_nodes.get(field_name) if not field_node or is_missing_variable(field_node.value, variables): if field.default_value is not Undefined: # Use out name as name if it exists (extension of GraphQL.js). coerced_obj[field.out_name or field_name] = field.default_value elif is_non_null_type(field.type): # pragma: no cover else return Undefined continue field_value = value_from_ast(field_node.value, field.type, variables) if field_value is Undefined: return Undefined coerced_obj[field.out_name or field_name] = field_value return type_.out_type(coerced_obj) if is_leaf_type(type_): # Scalars fulfill parsing a literal value via `parse_literal()`. Invalid values # represent a failure to parse correctly, in which case Undefined is returned. type_ = cast(GraphQLScalarType, type_) # noinspection PyBroadException try: if variables: result = type_.parse_literal(value_node, variables) else: result = type_.parse_literal(value_node) except Exception: return Undefined return result # Not reachable. All possible input types have been considered. raise TypeError(f"Unexpected input type: {inspect(type_)}.") def is_missing_variable( value_node: ValueNode, variables: Optional[Dict[str, Any]] = None ) -> bool: """Check if ``value_node`` is a variable not defined in the ``variables`` dict.""" return isinstance(value_node, VariableNode) and ( not variables or variables.get(value_node.name.value, Undefined) is Undefined ) graphql-core-3.2.6/src/graphql/utilities/value_from_ast_untyped.py000066400000000000000000000060541474546154300255200ustar00rootroot00000000000000from math import nan from typing import Any, Callable, Dict, Optional, Union from ..language import ( ValueNode, BooleanValueNode, EnumValueNode, FloatValueNode, IntValueNode, ListValueNode, NullValueNode, ObjectValueNode, StringValueNode, VariableNode, ) from ..pyutils import inspect, Undefined __all__ = ["value_from_ast_untyped"] def value_from_ast_untyped( value_node: ValueNode, variables: Optional[Dict[str, Any]] = None ) -> Any: """Produce a Python value given a GraphQL Value AST. Unlike :func:`~graphql.utilities.value_from_ast`, no type is provided. The resulting Python value will reflect the provided GraphQL value AST. =================== ============== ================ GraphQL Value JSON Value Python Value =================== ============== ================ Input Object Object dict List Array list Boolean Boolean bool String / Enum String str Int / Float Number int / float Null null None =================== ============== ================ """ func = _value_from_kind_functions.get(value_node.kind) if func: return func(value_node, variables) # Not reachable. All possible value nodes have been considered. raise TypeError( # pragma: no cover f"Unexpected value node: {inspect(value_node)}." ) def value_from_null(_value_node: NullValueNode, _variables: Any) -> Any: return None def value_from_int(value_node: IntValueNode, _variables: Any) -> Any: try: return int(value_node.value) except ValueError: return nan def value_from_float(value_node: FloatValueNode, _variables: Any) -> Any: try: return float(value_node.value) except ValueError: return nan def value_from_string( value_node: Union[BooleanValueNode, EnumValueNode, StringValueNode], _variables: Any ) -> Any: return value_node.value def value_from_list( value_node: ListValueNode, variables: Optional[Dict[str, Any]] ) -> Any: return [value_from_ast_untyped(node, variables) for node in value_node.values] def value_from_object( value_node: ObjectValueNode, variables: Optional[Dict[str, Any]] ) -> Any: return { field.name.value: value_from_ast_untyped(field.value, variables) for field in value_node.fields } def value_from_variable( value_node: VariableNode, variables: Optional[Dict[str, Any]] ) -> Any: variable_name = value_node.name.value if not variables: return Undefined return variables.get(variable_name, Undefined) _value_from_kind_functions: Dict[str, Callable] = { "null_value": value_from_null, "int_value": value_from_int, "float_value": value_from_float, "string_value": value_from_string, "enum_value": value_from_string, "boolean_value": value_from_string, "list_value": value_from_list, "object_value": value_from_object, "variable": value_from_variable, } graphql-core-3.2.6/src/graphql/validation/000077500000000000000000000000001474546154300205025ustar00rootroot00000000000000graphql-core-3.2.6/src/graphql/validation/__init__.py000066400000000000000000000127131474546154300226170ustar00rootroot00000000000000"""GraphQL Validation The :mod:`graphql.validation` package fulfills the Validation phase of fulfilling a GraphQL result. """ from .validate import validate from .validation_context import ( ASTValidationContext, SDLValidationContext, ValidationContext, ) from .rules import ValidationRule, ASTValidationRule, SDLValidationRule # All validation rules in the GraphQL Specification. from .specified_rules import specified_rules # Spec Section: "Executable Definitions" from .rules.executable_definitions import ExecutableDefinitionsRule # Spec Section: "Field Selections on Objects, Interfaces, and Unions Types" from .rules.fields_on_correct_type import FieldsOnCorrectTypeRule # Spec Section: "Fragments on Composite Types" from .rules.fragments_on_composite_types import FragmentsOnCompositeTypesRule # Spec Section: "Argument Names" from .rules.known_argument_names import KnownArgumentNamesRule # Spec Section: "Directives Are Defined" from .rules.known_directives import KnownDirectivesRule # Spec Section: "Fragment spread target defined" from .rules.known_fragment_names import KnownFragmentNamesRule # Spec Section: "Fragment Spread Type Existence" from .rules.known_type_names import KnownTypeNamesRule # Spec Section: "Lone Anonymous Operation" from .rules.lone_anonymous_operation import LoneAnonymousOperationRule # Spec Section: "Fragments must not form cycles" from .rules.no_fragment_cycles import NoFragmentCyclesRule # Spec Section: "All Variable Used Defined" from .rules.no_undefined_variables import NoUndefinedVariablesRule # Spec Section: "Fragments must be used" from .rules.no_unused_fragments import NoUnusedFragmentsRule # Spec Section: "All Variables Used" from .rules.no_unused_variables import NoUnusedVariablesRule # Spec Section: "Field Selection Merging" from .rules.overlapping_fields_can_be_merged import OverlappingFieldsCanBeMergedRule # Spec Section: "Fragment spread is possible" from .rules.possible_fragment_spreads import PossibleFragmentSpreadsRule # Spec Section: "Argument Optionality" from .rules.provided_required_arguments import ProvidedRequiredArgumentsRule # Spec Section: "Leaf Field Selections" from .rules.scalar_leafs import ScalarLeafsRule # Spec Section: "Subscriptions with Single Root Field" from .rules.single_field_subscriptions import SingleFieldSubscriptionsRule # Spec Section: "Argument Uniqueness" from .rules.unique_argument_names import UniqueArgumentNamesRule # Spec Section: "Directives Are Unique Per Location" from .rules.unique_directives_per_location import UniqueDirectivesPerLocationRule # Spec Section: "Fragment Name Uniqueness" from .rules.unique_fragment_names import UniqueFragmentNamesRule # Spec Section: "Input Object Field Uniqueness" from .rules.unique_input_field_names import UniqueInputFieldNamesRule # Spec Section: "Operation Name Uniqueness" from .rules.unique_operation_names import UniqueOperationNamesRule # Spec Section: "Variable Uniqueness" from .rules.unique_variable_names import UniqueVariableNamesRule # Spec Section: "Value Type Correctness" from .rules.values_of_correct_type import ValuesOfCorrectTypeRule # Spec Section: "Variables are Input Types" from .rules.variables_are_input_types import VariablesAreInputTypesRule # Spec Section: "All Variable Usages Are Allowed" from .rules.variables_in_allowed_position import VariablesInAllowedPositionRule # SDL-specific validation rules from .rules.lone_schema_definition import LoneSchemaDefinitionRule from .rules.unique_operation_types import UniqueOperationTypesRule from .rules.unique_type_names import UniqueTypeNamesRule from .rules.unique_enum_value_names import UniqueEnumValueNamesRule from .rules.unique_field_definition_names import UniqueFieldDefinitionNamesRule from .rules.unique_argument_definition_names import UniqueArgumentDefinitionNamesRule from .rules.unique_directive_names import UniqueDirectiveNamesRule from .rules.possible_type_extensions import PossibleTypeExtensionsRule # Optional rules not defined by the GraphQL Specification from .rules.custom.no_deprecated import NoDeprecatedCustomRule from .rules.custom.no_schema_introspection import NoSchemaIntrospectionCustomRule __all__ = [ "validate", "ASTValidationContext", "ASTValidationRule", "SDLValidationContext", "SDLValidationRule", "ValidationContext", "ValidationRule", "specified_rules", "ExecutableDefinitionsRule", "FieldsOnCorrectTypeRule", "FragmentsOnCompositeTypesRule", "KnownArgumentNamesRule", "KnownDirectivesRule", "KnownFragmentNamesRule", "KnownTypeNamesRule", "LoneAnonymousOperationRule", "NoFragmentCyclesRule", "NoUndefinedVariablesRule", "NoUnusedFragmentsRule", "NoUnusedVariablesRule", "OverlappingFieldsCanBeMergedRule", "PossibleFragmentSpreadsRule", "ProvidedRequiredArgumentsRule", "ScalarLeafsRule", "SingleFieldSubscriptionsRule", "UniqueArgumentNamesRule", "UniqueDirectivesPerLocationRule", "UniqueFragmentNamesRule", "UniqueInputFieldNamesRule", "UniqueOperationNamesRule", "UniqueVariableNamesRule", "ValuesOfCorrectTypeRule", "VariablesAreInputTypesRule", "VariablesInAllowedPositionRule", "LoneSchemaDefinitionRule", "UniqueOperationTypesRule", "UniqueTypeNamesRule", "UniqueEnumValueNamesRule", "UniqueFieldDefinitionNamesRule", "UniqueArgumentDefinitionNamesRule", "UniqueDirectiveNamesRule", "PossibleTypeExtensionsRule", "NoDeprecatedCustomRule", "NoSchemaIntrospectionCustomRule", ] graphql-core-3.2.6/src/graphql/validation/rules/000077500000000000000000000000001474546154300216345ustar00rootroot00000000000000graphql-core-3.2.6/src/graphql/validation/rules/__init__.py000066400000000000000000000020701474546154300237440ustar00rootroot00000000000000"""graphql.validation.rules package""" from ...error import GraphQLError from ...language.visitor import Visitor from ..validation_context import ( ASTValidationContext, SDLValidationContext, ValidationContext, ) __all__ = ["ASTValidationRule", "SDLValidationRule", "ValidationRule"] class ASTValidationRule(Visitor): """Visitor for validation of an AST.""" context: ASTValidationContext def __init__(self, context: ASTValidationContext): super().__init__() self.context = context def report_error(self, error: GraphQLError) -> None: self.context.report_error(error) class SDLValidationRule(ASTValidationRule): """Visitor for validation of an SDL AST.""" context: SDLValidationContext def __init__(self, context: SDLValidationContext) -> None: super().__init__(context) class ValidationRule(ASTValidationRule): """Visitor for validation using a GraphQL schema.""" context: ValidationContext def __init__(self, context: ValidationContext) -> None: super().__init__(context) graphql-core-3.2.6/src/graphql/validation/rules/custom/000077500000000000000000000000001474546154300231465ustar00rootroot00000000000000graphql-core-3.2.6/src/graphql/validation/rules/custom/__init__.py000066400000000000000000000000561474546154300252600ustar00rootroot00000000000000"""graphql.validation.rules.custom package""" graphql-core-3.2.6/src/graphql/validation/rules/custom/no_deprecated.py000066400000000000000000000105101474546154300263110ustar00rootroot00000000000000from typing import Any, cast from ....error import GraphQLError from ....language import ArgumentNode, EnumValueNode, FieldNode, ObjectFieldNode from ....type import GraphQLInputObjectType, get_named_type, is_input_object_type from .. import ValidationRule __all__ = ["NoDeprecatedCustomRule"] class NoDeprecatedCustomRule(ValidationRule): """No deprecated A GraphQL document is only valid if all selected fields and all used enum values have not been deprecated. Note: This rule is optional and is not part of the Validation section of the GraphQL Specification. The main purpose of this rule is detection of deprecated usages and not necessarily to forbid their use when querying a service. """ def enter_field(self, node: FieldNode, *_args: Any) -> None: context = self.context field_def = context.get_field_def() if field_def: deprecation_reason = field_def.deprecation_reason if deprecation_reason is not None: parent_type = context.get_parent_type() parent_name = parent_type.name # type: ignore self.report_error( GraphQLError( f"The field {parent_name}.{node.name.value}" f" is deprecated. {deprecation_reason}", node, ) ) def enter_argument(self, node: ArgumentNode, *_args: Any) -> None: context = self.context arg_def = context.get_argument() if arg_def: deprecation_reason = arg_def.deprecation_reason if deprecation_reason is not None: directive_def = context.get_directive() arg_name = node.name.value if directive_def is None: parent_type = context.get_parent_type() parent_name = parent_type.name # type: ignore field_def = context.get_field_def() field_name = field_def.ast_node.name.value # type: ignore self.report_error( GraphQLError( f"Field '{parent_name}.{field_name}' argument" f" '{arg_name}' is deprecated. {deprecation_reason}", node, ) ) else: self.report_error( GraphQLError( f"Directive '@{directive_def.name}' argument" f" '{arg_name}' is deprecated. {deprecation_reason}", node, ) ) def enter_object_field(self, node: ObjectFieldNode, *_args: Any) -> None: context = self.context input_object_def = get_named_type(context.get_parent_input_type()) if is_input_object_type(input_object_def): input_field_def = cast(GraphQLInputObjectType, input_object_def).fields.get( node.name.value ) if input_field_def: deprecation_reason = input_field_def.deprecation_reason if deprecation_reason is not None: field_name = node.name.value input_object_name = input_object_def.name # type: ignore self.report_error( GraphQLError( f"The input field {input_object_name}.{field_name}" f" is deprecated. {deprecation_reason}", node, ) ) def enter_enum_value(self, node: EnumValueNode, *_args: Any) -> None: context = self.context enum_value_def = context.get_enum_value() if enum_value_def: deprecation_reason = enum_value_def.deprecation_reason if deprecation_reason is not None: # pragma: no cover else enum_type_def = get_named_type(context.get_input_type()) enum_type_name = enum_type_def.name # type: ignore self.report_error( GraphQLError( f"The enum value '{enum_type_name}.{node.value}'" f" is deprecated. {deprecation_reason}", node, ) ) graphql-core-3.2.6/src/graphql/validation/rules/custom/no_schema_introspection.py000066400000000000000000000021631474546154300304360ustar00rootroot00000000000000from typing import Any from ....error import GraphQLError from ....language import FieldNode from ....type import get_named_type, is_introspection_type from .. import ValidationRule __all__ = ["NoSchemaIntrospectionCustomRule"] class NoSchemaIntrospectionCustomRule(ValidationRule): """Prohibit introspection queries A GraphQL document is only valid if all fields selected are not fields that return an introspection type. Note: This rule is optional and is not part of the Validation section of the GraphQL Specification. This rule effectively disables introspection, which does not reflect best practices and should only be done if absolutely necessary. """ def enter_field(self, node: FieldNode, *_args: Any) -> None: type_ = get_named_type(self.context.get_type()) if type_ and is_introspection_type(type_): self.report_error( GraphQLError( "GraphQL introspection has been disabled, but the requested query" f" contained the field '{node.name.value}'.", node, ) ) graphql-core-3.2.6/src/graphql/validation/rules/executable_definitions.py000066400000000000000000000027701474546154300267300ustar00rootroot00000000000000from typing import Any, Union, cast from ...error import GraphQLError from ...language import ( DirectiveDefinitionNode, DocumentNode, ExecutableDefinitionNode, SchemaDefinitionNode, SchemaExtensionNode, TypeDefinitionNode, VisitorAction, SKIP, ) from . import ASTValidationRule __all__ = ["ExecutableDefinitionsRule"] class ExecutableDefinitionsRule(ASTValidationRule): """Executable definitions A GraphQL document is only valid for execution if all definitions are either operation or fragment definitions. See https://spec.graphql.org/draft/#sec-Executable-Definitions """ def enter_document(self, node: DocumentNode, *_args: Any) -> VisitorAction: for definition in node.definitions: if not isinstance(definition, ExecutableDefinitionNode): def_name = ( "schema" if isinstance( definition, (SchemaDefinitionNode, SchemaExtensionNode) ) else "'{}'".format( cast( Union[DirectiveDefinitionNode, TypeDefinitionNode], definition, ).name.value ) ) self.report_error( GraphQLError( f"The {def_name} definition is not executable.", definition, ) ) return SKIP graphql-core-3.2.6/src/graphql/validation/rules/fields_on_correct_type.py000066400000000000000000000113331474546154300267330ustar00rootroot00000000000000from collections import defaultdict from functools import cmp_to_key from typing import Any, Dict, List, Union, cast from ...type import ( GraphQLAbstractType, GraphQLInterfaceType, GraphQLObjectType, GraphQLOutputType, GraphQLSchema, is_abstract_type, is_interface_type, is_object_type, ) from ...error import GraphQLError from ...language import FieldNode from ...pyutils import did_you_mean, natural_comparison_key, suggestion_list from . import ValidationRule __all__ = ["FieldsOnCorrectTypeRule"] class FieldsOnCorrectTypeRule(ValidationRule): """Fields on correct type A GraphQL document is only valid if all fields selected are defined by the parent type, or are an allowed meta field such as ``__typename``. See https://spec.graphql.org/draft/#sec-Field-Selections """ def enter_field(self, node: FieldNode, *_args: Any) -> None: type_ = self.context.get_parent_type() if not type_: return field_def = self.context.get_field_def() if field_def: return # This field doesn't exist, lets look for suggestions. schema = self.context.schema field_name = node.name.value # First determine if there are any suggested types to condition on. suggestion = did_you_mean( get_suggested_type_names(schema, type_, field_name), "to use an inline fragment on", ) # If there are no suggested types, then perhaps this was a typo? if not suggestion: suggestion = did_you_mean(get_suggested_field_names(type_, field_name)) # Report an error, including helpful suggestions. self.report_error( GraphQLError( f"Cannot query field '{field_name}' on type '{type_}'." + suggestion, node, ) ) def get_suggested_type_names( schema: GraphQLSchema, type_: GraphQLOutputType, field_name: str ) -> List[str]: """ Get a list of suggested type names. Go through all of the implementations of type, as well as the interfaces that they implement. If any of those types include the provided field, suggest them, sorted by how often the type is referenced. """ if not is_abstract_type(type_): # Must be an Object type, which does not have possible fields. return [] type_ = cast(GraphQLAbstractType, type_) # Use a dict instead of a set for stable sorting when usage counts are the same suggested_types: Dict[Union[GraphQLObjectType, GraphQLInterfaceType], None] = {} usage_count: Dict[str, int] = defaultdict(int) for possible_type in schema.get_possible_types(type_): if field_name not in possible_type.fields: continue # This object type defines this field. suggested_types[possible_type] = None usage_count[possible_type.name] = 1 for possible_interface in possible_type.interfaces: if field_name not in possible_interface.fields: continue # This interface type defines this field. suggested_types[possible_interface] = None usage_count[possible_interface.name] += 1 def cmp( type_a: Union[GraphQLObjectType, GraphQLInterfaceType], type_b: Union[GraphQLObjectType, GraphQLInterfaceType], ) -> int: # pragma: no cover # Suggest both interface and object types based on how common they are. usage_count_diff = usage_count[type_b.name] - usage_count[type_a.name] if usage_count_diff: return usage_count_diff # Suggest super types first followed by subtypes if is_interface_type(type_a) and schema.is_sub_type( cast(GraphQLInterfaceType, type_a), type_b ): return -1 if is_interface_type(type_b) and schema.is_sub_type( cast(GraphQLInterfaceType, type_b), type_a ): return 1 name_a = natural_comparison_key(type_a.name) name_b = natural_comparison_key(type_b.name) if name_a > name_b: return 1 if name_a < name_b: return -1 return 0 return [type_.name for type_ in sorted(suggested_types, key=cmp_to_key(cmp))] def get_suggested_field_names(type_: GraphQLOutputType, field_name: str) -> List[str]: """Get a list of suggested field names. For the field name provided, determine if there are any similar field names that may be the result of a typo. """ if is_object_type(type_) or is_interface_type(type_): possible_field_names = list(type_.fields) # type: ignore return suggestion_list(field_name, possible_field_names) # Otherwise, must be a Union type, which does not define fields. return [] graphql-core-3.2.6/src/graphql/validation/rules/fragments_on_composite_types.py000066400000000000000000000035121474546154300301770ustar00rootroot00000000000000from typing import Any from ...error import GraphQLError from ...language import ( FragmentDefinitionNode, InlineFragmentNode, print_ast, ) from ...type import is_composite_type from ...utilities import type_from_ast from . import ValidationRule __all__ = ["FragmentsOnCompositeTypesRule"] class FragmentsOnCompositeTypesRule(ValidationRule): """Fragments on composite type Fragments use a type condition to determine if they apply, since fragments can only be spread into a composite type (object, interface, or union), the type condition must also be a composite type. See https://spec.graphql.org/draft/#sec-Fragments-On-Composite-Types """ def enter_inline_fragment(self, node: InlineFragmentNode, *_args: Any) -> None: type_condition = node.type_condition if type_condition: type_ = type_from_ast(self.context.schema, type_condition) if type_ and not is_composite_type(type_): type_str = print_ast(type_condition) self.report_error( GraphQLError( "Fragment cannot condition" f" on non composite type '{type_str}'.", type_condition, ) ) def enter_fragment_definition( self, node: FragmentDefinitionNode, *_args: Any ) -> None: type_condition = node.type_condition type_ = type_from_ast(self.context.schema, type_condition) if type_ and not is_composite_type(type_): type_str = print_ast(type_condition) self.report_error( GraphQLError( f"Fragment '{node.name.value}' cannot condition" f" on non composite type '{type_str}'.", type_condition, ) ) graphql-core-3.2.6/src/graphql/validation/rules/known_argument_names.py000066400000000000000000000070051474546154300264310ustar00rootroot00000000000000from typing import cast, Any, Dict, List, Union from ...error import GraphQLError from ...language import ( ArgumentNode, DirectiveDefinitionNode, DirectiveNode, SKIP, VisitorAction, ) from ...pyutils import did_you_mean, suggestion_list from ...type import specified_directives from . import ASTValidationRule, SDLValidationContext, ValidationContext __all__ = ["KnownArgumentNamesRule", "KnownArgumentNamesOnDirectivesRule"] class KnownArgumentNamesOnDirectivesRule(ASTValidationRule): """Known argument names on directives A GraphQL directive is only valid if all supplied arguments are defined. For internal use only. """ context: Union[ValidationContext, SDLValidationContext] def __init__(self, context: Union[ValidationContext, SDLValidationContext]): super().__init__(context) directive_args: Dict[str, List[str]] = {} schema = context.schema defined_directives = schema.directives if schema else specified_directives for directive in cast(List, defined_directives): directive_args[directive.name] = list(directive.args) ast_definitions = context.document.definitions for def_ in ast_definitions: if isinstance(def_, DirectiveDefinitionNode): directive_args[def_.name.value] = [ arg.name.value for arg in def_.arguments or [] ] self.directive_args = directive_args def enter_directive( self, directive_node: DirectiveNode, *_args: Any ) -> VisitorAction: directive_name = directive_node.name.value known_args = self.directive_args.get(directive_name) if directive_node.arguments and known_args is not None: for arg_node in directive_node.arguments: arg_name = arg_node.name.value if arg_name not in known_args: suggestions = suggestion_list(arg_name, known_args) self.report_error( GraphQLError( f"Unknown argument '{arg_name}'" f" on directive '@{directive_name}'." + did_you_mean(suggestions), arg_node, ) ) return SKIP class KnownArgumentNamesRule(KnownArgumentNamesOnDirectivesRule): """Known argument names A GraphQL field is only valid if all supplied arguments are defined by that field. See https://spec.graphql.org/draft/#sec-Argument-Names See https://spec.graphql.org/draft/#sec-Directives-Are-In-Valid-Locations """ context: ValidationContext def __init__(self, context: ValidationContext): super().__init__(context) def enter_argument(self, arg_node: ArgumentNode, *args: Any) -> None: context = self.context arg_def = context.get_argument() field_def = context.get_field_def() parent_type = context.get_parent_type() if not arg_def and field_def and parent_type: arg_name = arg_node.name.value field_name = args[3][-1].name.value known_args_names = list(field_def.args) suggestions = suggestion_list(arg_name, known_args_names) context.report_error( GraphQLError( f"Unknown argument '{arg_name}'" f" on field '{parent_type.name}.{field_name}'." + did_you_mean(suggestions), arg_node, ) ) graphql-core-3.2.6/src/graphql/validation/rules/known_directives.py000066400000000000000000000105511474546154300255650ustar00rootroot00000000000000from typing import cast, Any, Dict, List, Optional, Tuple, Union from ...error import GraphQLError from ...language import ( DirectiveLocation, DirectiveDefinitionNode, DirectiveNode, Node, OperationDefinitionNode, ) from ...type import specified_directives from . import ASTValidationRule, SDLValidationContext, ValidationContext __all__ = ["KnownDirectivesRule"] class KnownDirectivesRule(ASTValidationRule): """Known directives A GraphQL document is only valid if all ``@directives`` are known by the schema and legally positioned. See https://spec.graphql.org/draft/#sec-Directives-Are-Defined """ context: Union[ValidationContext, SDLValidationContext] def __init__(self, context: Union[ValidationContext, SDLValidationContext]): super().__init__(context) locations_map: Dict[str, Tuple[DirectiveLocation, ...]] = {} schema = context.schema defined_directives = ( schema.directives if schema else cast(List, specified_directives) ) for directive in defined_directives: locations_map[directive.name] = directive.locations ast_definitions = context.document.definitions for def_ in ast_definitions: if isinstance(def_, DirectiveDefinitionNode): locations_map[def_.name.value] = tuple( DirectiveLocation[name.value] for name in def_.locations ) self.locations_map = locations_map def enter_directive( self, node: DirectiveNode, _key: Any, _parent: Any, _path: Any, ancestors: List[Node], ) -> None: name = node.name.value locations = self.locations_map.get(name) if locations: candidate_location = get_directive_location_for_ast_path(ancestors) if candidate_location and candidate_location not in locations: self.report_error( GraphQLError( f"Directive '@{name}'" f" may not be used on {candidate_location.value}.", node, ) ) else: self.report_error(GraphQLError(f"Unknown directive '@{name}'.", node)) _operation_location = { "query": DirectiveLocation.QUERY, "mutation": DirectiveLocation.MUTATION, "subscription": DirectiveLocation.SUBSCRIPTION, } _directive_location = { "field": DirectiveLocation.FIELD, "fragment_spread": DirectiveLocation.FRAGMENT_SPREAD, "inline_fragment": DirectiveLocation.INLINE_FRAGMENT, "fragment_definition": DirectiveLocation.FRAGMENT_DEFINITION, "variable_definition": DirectiveLocation.VARIABLE_DEFINITION, "schema_definition": DirectiveLocation.SCHEMA, "schema_extension": DirectiveLocation.SCHEMA, "scalar_type_definition": DirectiveLocation.SCALAR, "scalar_type_extension": DirectiveLocation.SCALAR, "object_type_definition": DirectiveLocation.OBJECT, "object_type_extension": DirectiveLocation.OBJECT, "field_definition": DirectiveLocation.FIELD_DEFINITION, "interface_type_definition": DirectiveLocation.INTERFACE, "interface_type_extension": DirectiveLocation.INTERFACE, "union_type_definition": DirectiveLocation.UNION, "union_type_extension": DirectiveLocation.UNION, "enum_type_definition": DirectiveLocation.ENUM, "enum_type_extension": DirectiveLocation.ENUM, "enum_value_definition": DirectiveLocation.ENUM_VALUE, "input_object_type_definition": DirectiveLocation.INPUT_OBJECT, "input_object_type_extension": DirectiveLocation.INPUT_OBJECT, } def get_directive_location_for_ast_path( ancestors: List[Node], ) -> Optional[DirectiveLocation]: applied_to = ancestors[-1] if not isinstance(applied_to, Node): # pragma: no cover raise TypeError("Unexpected error in directive.") kind = applied_to.kind if kind == "operation_definition": applied_to = cast(OperationDefinitionNode, applied_to) return _operation_location[applied_to.operation.value] elif kind == "input_value_definition": parent_node = ancestors[-3] return ( DirectiveLocation.INPUT_FIELD_DEFINITION if parent_node.kind == "input_object_type_definition" else DirectiveLocation.ARGUMENT_DEFINITION ) else: return _directive_location.get(kind) graphql-core-3.2.6/src/graphql/validation/rules/known_fragment_names.py000066400000000000000000000014321474546154300264100ustar00rootroot00000000000000from typing import Any from ...error import GraphQLError from ...language import FragmentSpreadNode from . import ValidationRule __all__ = ["KnownFragmentNamesRule"] class KnownFragmentNamesRule(ValidationRule): """Known fragment names A GraphQL document is only valid if all ``...Fragment`` fragment spreads refer to fragments defined in the same document. See https://spec.graphql.org/draft/#sec-Fragment-spread-target-defined """ def enter_fragment_spread(self, node: FragmentSpreadNode, *_args: Any) -> None: fragment_name = node.name.value fragment = self.context.get_fragment(fragment_name) if not fragment: self.report_error( GraphQLError(f"Unknown fragment '{fragment_name}'.", node.name) ) graphql-core-3.2.6/src/graphql/validation/rules/known_type_names.py000066400000000000000000000054201474546154300255670ustar00rootroot00000000000000from typing import Any, Collection, List, Union, cast from ...error import GraphQLError from ...language import ( is_type_definition_node, is_type_system_definition_node, is_type_system_extension_node, Node, NamedTypeNode, TypeDefinitionNode, ) from ...type import introspection_types, specified_scalar_types from ...pyutils import did_you_mean, suggestion_list from . import ASTValidationRule, ValidationContext, SDLValidationContext __all__ = ["KnownTypeNamesRule"] class KnownTypeNamesRule(ASTValidationRule): """Known type names A GraphQL document is only valid if referenced types (specifically variable definitions and fragment conditions) are defined by the type schema. See https://spec.graphql.org/draft/#sec-Fragment-Spread-Type-Existence """ def __init__(self, context: Union[ValidationContext, SDLValidationContext]): super().__init__(context) schema = context.schema self.existing_types_map = schema.type_map if schema else {} defined_types = [] for def_ in context.document.definitions: if is_type_definition_node(def_): def_ = cast(TypeDefinitionNode, def_) defined_types.append(def_.name.value) self.defined_types = set(defined_types) self.type_names = list(self.existing_types_map) + defined_types def enter_named_type( self, node: NamedTypeNode, _key: Any, parent: Node, _path: Any, ancestors: List[Node], ) -> None: type_name = node.name.value if ( type_name not in self.existing_types_map and type_name not in self.defined_types ): try: definition_node = ancestors[2] except IndexError: definition_node = parent is_sdl = is_sdl_node(definition_node) if is_sdl and type_name in standard_type_names: return suggested_types = suggestion_list( type_name, ( list(standard_type_names) + self.type_names if is_sdl else self.type_names ), ) self.report_error( GraphQLError( f"Unknown type '{type_name}'." + did_you_mean(suggested_types), node, ) ) standard_type_names = set(specified_scalar_types).union(introspection_types) def is_sdl_node(value: Union[Node, Collection[Node], None]) -> bool: return ( value is not None and not isinstance(value, list) and ( is_type_system_definition_node(cast(Node, value)) or is_type_system_extension_node(cast(Node, value)) ) ) graphql-core-3.2.6/src/graphql/validation/rules/lone_anonymous_operation.py000066400000000000000000000023241474546154300273340ustar00rootroot00000000000000from typing import Any from ...error import GraphQLError from ...language import DocumentNode, OperationDefinitionNode from . import ASTValidationContext, ASTValidationRule __all__ = ["LoneAnonymousOperationRule"] class LoneAnonymousOperationRule(ASTValidationRule): """Lone anonymous operation A GraphQL document is only valid if when it contains an anonymous operation (the query short-hand) that it contains only that one operation definition. See https://spec.graphql.org/draft/#sec-Lone-Anonymous-Operation """ def __init__(self, context: ASTValidationContext): super().__init__(context) self.operation_count = 0 def enter_document(self, node: DocumentNode, *_args: Any) -> None: self.operation_count = sum( isinstance(definition, OperationDefinitionNode) for definition in node.definitions ) def enter_operation_definition( self, node: OperationDefinitionNode, *_args: Any ) -> None: if not node.name and self.operation_count > 1: self.report_error( GraphQLError( "This anonymous operation must be the only defined operation.", node ) ) graphql-core-3.2.6/src/graphql/validation/rules/lone_schema_definition.py000066400000000000000000000024101474546154300266700ustar00rootroot00000000000000from typing import Any from ...error import GraphQLError from ...language import SchemaDefinitionNode from . import SDLValidationRule, SDLValidationContext __all__ = ["LoneSchemaDefinitionRule"] class LoneSchemaDefinitionRule(SDLValidationRule): """Lone Schema definition A GraphQL document is only valid if it contains only one schema definition. """ def __init__(self, context: SDLValidationContext): super().__init__(context) old_schema = context.schema self.already_defined = old_schema and ( old_schema.ast_node or old_schema.query_type or old_schema.mutation_type or old_schema.subscription_type ) self.schema_definitions_count = 0 def enter_schema_definition(self, node: SchemaDefinitionNode, *_args: Any) -> None: if self.already_defined: self.report_error( GraphQLError( "Cannot define a new schema within a schema extension.", node ) ) else: if self.schema_definitions_count: self.report_error( GraphQLError("Must provide only one schema definition.", node) ) self.schema_definitions_count += 1 graphql-core-3.2.6/src/graphql/validation/rules/no_fragment_cycles.py000066400000000000000000000060511474546154300260510ustar00rootroot00000000000000from typing import Any, Dict, List, Set from ...error import GraphQLError from ...language import FragmentDefinitionNode, FragmentSpreadNode, VisitorAction, SKIP from . import ASTValidationContext, ASTValidationRule __all__ = ["NoFragmentCyclesRule"] class NoFragmentCyclesRule(ASTValidationRule): """No fragment cycles The graph of fragment spreads must not form any cycles including spreading itself. Otherwise an operation could infinitely spread or infinitely execute on cycles in the underlying data. See https://spec.graphql.org/draft/#sec-Fragment-spreads-must-not-form-cycles """ def __init__(self, context: ASTValidationContext): super().__init__(context) # Tracks already visited fragments to maintain O(N) and to ensure that # cycles are not redundantly reported. self.visited_frags: Set[str] = set() # List of AST nodes used to produce meaningful errors self.spread_path: List[FragmentSpreadNode] = [] # Position in the spread path self.spread_path_index_by_name: Dict[str, int] = {} @staticmethod def enter_operation_definition(*_args: Any) -> VisitorAction: return SKIP def enter_fragment_definition( self, node: FragmentDefinitionNode, *_args: Any ) -> VisitorAction: self.detect_cycle_recursive(node) return SKIP def detect_cycle_recursive(self, fragment: FragmentDefinitionNode) -> None: # This does a straight-forward DFS to find cycles. # It does not terminate when a cycle was found but continues to explore # the graph to find all possible cycles. if fragment.name.value in self.visited_frags: return fragment_name = fragment.name.value visited_frags = self.visited_frags visited_frags.add(fragment_name) spread_nodes = self.context.get_fragment_spreads(fragment.selection_set) if not spread_nodes: return spread_path = self.spread_path spread_path_index = self.spread_path_index_by_name spread_path_index[fragment_name] = len(spread_path) get_fragment = self.context.get_fragment for spread_node in spread_nodes: spread_name = spread_node.name.value cycle_index = spread_path_index.get(spread_name) spread_path.append(spread_node) if cycle_index is None: spread_fragment = get_fragment(spread_name) if spread_fragment: self.detect_cycle_recursive(spread_fragment) else: cycle_path = spread_path[cycle_index:] via_path = ", ".join("'" + s.name.value + "'" for s in cycle_path[:-1]) self.report_error( GraphQLError( f"Cannot spread fragment '{spread_name}' within itself" + (f" via {via_path}." if via_path else "."), cycle_path, ) ) spread_path.pop() del spread_path_index[fragment_name] graphql-core-3.2.6/src/graphql/validation/rules/no_undefined_variables.py000066400000000000000000000034131474546154300266740ustar00rootroot00000000000000from typing import Any, Set from ...error import GraphQLError from ...language import OperationDefinitionNode, VariableDefinitionNode from . import ValidationContext, ValidationRule __all__ = ["NoUndefinedVariablesRule"] class NoUndefinedVariablesRule(ValidationRule): """No undefined variables A GraphQL operation is only valid if all variables encountered, both directly and via fragment spreads, are defined by that operation. See https://spec.graphql.org/draft/#sec-All-Variable-Uses-Defined """ def __init__(self, context: ValidationContext): super().__init__(context) self.defined_variable_names: Set[str] = set() def enter_operation_definition(self, *_args: Any) -> None: self.defined_variable_names.clear() def leave_operation_definition( self, operation: OperationDefinitionNode, *_args: Any ) -> None: usages = self.context.get_recursive_variable_usages(operation) defined_variables = self.defined_variable_names for usage in usages: node = usage.node var_name = node.name.value if var_name not in defined_variables: self.report_error( GraphQLError( ( f"Variable '${var_name}' is not defined" f" by operation '{operation.name.value}'." if operation.name else f"Variable '${var_name}' is not defined." ), [node, operation], ) ) def enter_variable_definition( self, node: VariableDefinitionNode, *_args: Any ) -> None: self.defined_variable_names.add(node.variable.name.value) graphql-core-3.2.6/src/graphql/validation/rules/no_unused_fragments.py000066400000000000000000000033471474546154300262620ustar00rootroot00000000000000from typing import Any, List from ...error import GraphQLError from ...language import ( FragmentDefinitionNode, OperationDefinitionNode, VisitorAction, SKIP, ) from . import ASTValidationContext, ASTValidationRule __all__ = ["NoUnusedFragmentsRule"] class NoUnusedFragmentsRule(ASTValidationRule): """No unused fragments A GraphQL document is only valid if all fragment definitions are spread within operations, or spread within other fragments spread within operations. See https://spec.graphql.org/draft/#sec-Fragments-Must-Be-Used """ def __init__(self, context: ASTValidationContext): super().__init__(context) self.operation_defs: List[OperationDefinitionNode] = [] self.fragment_defs: List[FragmentDefinitionNode] = [] def enter_operation_definition( self, node: OperationDefinitionNode, *_args: Any ) -> VisitorAction: self.operation_defs.append(node) return SKIP def enter_fragment_definition( self, node: FragmentDefinitionNode, *_args: Any ) -> VisitorAction: self.fragment_defs.append(node) return SKIP def leave_document(self, *_args: Any) -> None: fragment_names_used = set() get_fragments = self.context.get_recursively_referenced_fragments for operation in self.operation_defs: for fragment in get_fragments(operation): fragment_names_used.add(fragment.name.value) for fragment_def in self.fragment_defs: frag_name = fragment_def.name.value if frag_name not in fragment_names_used: self.report_error( GraphQLError(f"Fragment '{frag_name}' is never used.", fragment_def) ) graphql-core-3.2.6/src/graphql/validation/rules/no_unused_variables.py000066400000000000000000000035171474546154300262430ustar00rootroot00000000000000from typing import Any, List, Set from ...error import GraphQLError from ...language import OperationDefinitionNode, VariableDefinitionNode from . import ValidationContext, ValidationRule __all__ = ["NoUnusedVariablesRule"] class NoUnusedVariablesRule(ValidationRule): """No unused variables A GraphQL operation is only valid if all variables defined by an operation are used, either directly or within a spread fragment. See https://spec.graphql.org/draft/#sec-All-Variables-Used """ def __init__(self, context: ValidationContext): super().__init__(context) self.variable_defs: List[VariableDefinitionNode] = [] def enter_operation_definition(self, *_args: Any) -> None: self.variable_defs.clear() def leave_operation_definition( self, operation: OperationDefinitionNode, *_args: Any ) -> None: variable_name_used: Set[str] = set() usages = self.context.get_recursive_variable_usages(operation) for usage in usages: variable_name_used.add(usage.node.name.value) for variable_def in self.variable_defs: variable_name = variable_def.variable.name.value if variable_name not in variable_name_used: self.report_error( GraphQLError( ( f"Variable '${variable_name}' is never used" f" in operation '{operation.name.value}'." if operation.name else f"Variable '${variable_name}' is never used." ), variable_def, ) ) def enter_variable_definition( self, definition: VariableDefinitionNode, *_args: Any ) -> None: self.variable_defs.append(definition) graphql-core-3.2.6/src/graphql/validation/rules/overlapping_fields_can_be_merged.py000066400000000000000000000702001474546154300306730ustar00rootroot00000000000000from itertools import chain from typing import Any, Dict, List, Optional, Tuple, Union, cast from ...error import GraphQLError from ...language import ( DirectiveNode, FieldNode, FragmentDefinitionNode, FragmentSpreadNode, InlineFragmentNode, SelectionSetNode, ValueNode, print_ast, ) from ...type import ( GraphQLCompositeType, GraphQLField, GraphQLList, GraphQLNamedType, GraphQLNonNull, GraphQLOutputType, get_named_type, is_interface_type, is_leaf_type, is_list_type, is_non_null_type, is_object_type, ) from ...utilities import type_from_ast from ...utilities.sort_value_node import sort_value_node from . import ValidationContext, ValidationRule MYPY = False __all__ = ["OverlappingFieldsCanBeMergedRule"] def reason_message(reason: "ConflictReasonMessage") -> str: if isinstance(reason, list): return " and ".join( f"subfields '{response_name}' conflict" f" because {reason_message(sub_reason)}" for response_name, sub_reason in reason ) return reason class OverlappingFieldsCanBeMergedRule(ValidationRule): """Overlapping fields can be merged A selection set is only valid if all fields (including spreading any fragments) either correspond to distinct response names or can be merged without ambiguity. See https://spec.graphql.org/draft/#sec-Field-Selection-Merging """ def __init__(self, context: ValidationContext): super().__init__(context) # A memoization for when two fragments are compared "between" each other for # conflicts. Two fragments may be compared many times, so memoizing this can # dramatically improve the performance of this validator. self.compared_fragment_pairs = PairSet() # A cache for the "field map" and list of fragment names found in any given # selection set. Selection sets may be asked for this information multiple # times, so this improves the performance of this validator. self.cached_fields_and_fragment_names: Dict = {} def enter_selection_set(self, selection_set: SelectionSetNode, *_args: Any) -> None: conflicts = find_conflicts_within_selection_set( self.context, self.cached_fields_and_fragment_names, self.compared_fragment_pairs, self.context.get_parent_type(), selection_set, ) for (reason_name, reason), fields1, fields2 in conflicts: reason_msg = reason_message(reason) self.report_error( GraphQLError( f"Fields '{reason_name}' conflict because {reason_msg}." " Use different aliases on the fields to fetch both" " if this was intentional.", fields1 + fields2, ) ) Conflict = Tuple["ConflictReason", List[FieldNode], List[FieldNode]] # Field name and reason. ConflictReason = Tuple[str, "ConflictReasonMessage"] # Reason is a string, or a nested list of conflicts. if MYPY: # recursive types not fully supported yet (/python/mypy/issues/731) ConflictReasonMessage = Union[str, List] else: ConflictReasonMessage = Union[str, List[ConflictReason]] # Tuple defining a field node in a context. NodeAndDef = Tuple[GraphQLCompositeType, FieldNode, Optional[GraphQLField]] # Dictionary of lists of those. NodeAndDefCollection = Dict[str, List[NodeAndDef]] # Algorithm: # # Conflicts occur when two fields exist in a query which will produce the same # response name, but represent differing values, thus creating a conflict. # The algorithm below finds all conflicts via making a series of comparisons # between fields. In order to compare as few fields as possible, this makes # a series of comparisons "within" sets of fields and "between" sets of fields. # # Given any selection set, a collection produces both a set of fields by # also including all inline fragments, as well as a list of fragments # referenced by fragment spreads. # # A) Each selection set represented in the document first compares "within" its # collected set of fields, finding any conflicts between every pair of # overlapping fields. # Note: This is the#only time* that a the fields "within" a set are compared # to each other. After this only fields "between" sets are compared. # # B) Also, if any fragment is referenced in a selection set, then a # comparison is made "between" the original set of fields and the # referenced fragment. # # C) Also, if multiple fragments are referenced, then comparisons # are made "between" each referenced fragment. # # D) When comparing "between" a set of fields and a referenced fragment, first # a comparison is made between each field in the original set of fields and # each field in the the referenced set of fields. # # E) Also, if any fragment is referenced in the referenced selection set, # then a comparison is made "between" the original set of fields and the # referenced fragment (recursively referring to step D). # # F) When comparing "between" two fragments, first a comparison is made between # each field in the first referenced set of fields and each field in the the # second referenced set of fields. # # G) Also, any fragments referenced by the first must be compared to the # second, and any fragments referenced by the second must be compared to the # first (recursively referring to step F). # # H) When comparing two fields, if both have selection sets, then a comparison # is made "between" both selection sets, first comparing the set of fields in # the first selection set with the set of fields in the second. # # I) Also, if any fragment is referenced in either selection set, then a # comparison is made "between" the other set of fields and the # referenced fragment. # # J) Also, if two fragments are referenced in both selection sets, then a # comparison is made "between" the two fragments. def find_conflicts_within_selection_set( context: ValidationContext, cached_fields_and_fragment_names: Dict, compared_fragment_pairs: "PairSet", parent_type: Optional[GraphQLNamedType], selection_set: SelectionSetNode, ) -> List[Conflict]: """Find conflicts within selection set. Find all conflicts found "within" a selection set, including those found via spreading in fragments. Called when visiting each SelectionSet in the GraphQL Document. """ conflicts: List[Conflict] = [] field_map, fragment_names = get_fields_and_fragment_names( context, cached_fields_and_fragment_names, parent_type, selection_set ) # (A) Find all conflicts "within" the fields of this selection set. # Note: this is the *only place* `collect_conflicts_within` is called. collect_conflicts_within( context, conflicts, cached_fields_and_fragment_names, compared_fragment_pairs, field_map, ) if fragment_names: # (B) Then collect conflicts between these fields and those represented by each # spread fragment name found. for i, fragment_name in enumerate(fragment_names): collect_conflicts_between_fields_and_fragment( context, conflicts, cached_fields_and_fragment_names, compared_fragment_pairs, False, field_map, fragment_name, ) # (C) Then compare this fragment with all other fragments found in this # selection set to collect conflicts within fragments spread together. # This compares each item in the list of fragment names to every other # item in that same list (except for itself). for other_fragment_name in fragment_names[i + 1 :]: collect_conflicts_between_fragments( context, conflicts, cached_fields_and_fragment_names, compared_fragment_pairs, False, fragment_name, other_fragment_name, ) return conflicts def collect_conflicts_between_fields_and_fragment( context: ValidationContext, conflicts: List[Conflict], cached_fields_and_fragment_names: Dict, compared_fragment_pairs: "PairSet", are_mutually_exclusive: bool, field_map: NodeAndDefCollection, fragment_name: str, ) -> None: """Collect conflicts between fields and fragment. Collect all conflicts found between a set of fields and a fragment reference including via spreading in any nested fragments. """ fragment = context.get_fragment(fragment_name) if not fragment: return None field_map2, referenced_fragment_names = get_referenced_fields_and_fragment_names( context, cached_fields_and_fragment_names, fragment ) # Do not compare a fragment's fieldMap to itself. if field_map is field_map2: return # (D) First collect any conflicts between the provided collection of fields and the # collection of fields represented by the given fragment. collect_conflicts_between( context, conflicts, cached_fields_and_fragment_names, compared_fragment_pairs, are_mutually_exclusive, field_map, field_map2, ) # (E) Then collect any conflicts between the provided collection of fields and any # fragment names found in the given fragment. for referenced_fragment_name in referenced_fragment_names: # Memoize so two fragments are not compared for conflicts more than once. if compared_fragment_pairs.has( referenced_fragment_name, fragment_name, are_mutually_exclusive ): continue compared_fragment_pairs.add( referenced_fragment_name, fragment_name, are_mutually_exclusive ) collect_conflicts_between_fields_and_fragment( context, conflicts, cached_fields_and_fragment_names, compared_fragment_pairs, are_mutually_exclusive, field_map, referenced_fragment_name, ) def collect_conflicts_between_fragments( context: ValidationContext, conflicts: List[Conflict], cached_fields_and_fragment_names: Dict, compared_fragment_pairs: "PairSet", are_mutually_exclusive: bool, fragment_name1: str, fragment_name2: str, ) -> None: """Collect conflicts between fragments. Collect all conflicts found between two fragments, including via spreading in any nested fragments. """ # No need to compare a fragment to itself. if fragment_name1 == fragment_name2: return # Memoize so two fragments are not compared for conflicts more than once. if compared_fragment_pairs.has( fragment_name1, fragment_name2, are_mutually_exclusive ): return compared_fragment_pairs.add(fragment_name1, fragment_name2, are_mutually_exclusive) fragment1 = context.get_fragment(fragment_name1) fragment2 = context.get_fragment(fragment_name2) if not fragment1 or not fragment2: return None field_map1, referenced_fragment_names1 = get_referenced_fields_and_fragment_names( context, cached_fields_and_fragment_names, fragment1 ) field_map2, referenced_fragment_names2 = get_referenced_fields_and_fragment_names( context, cached_fields_and_fragment_names, fragment2 ) # (F) First, collect all conflicts between these two collections of fields # (not including any nested fragments) collect_conflicts_between( context, conflicts, cached_fields_and_fragment_names, compared_fragment_pairs, are_mutually_exclusive, field_map1, field_map2, ) # (G) Then collect conflicts between the first fragment and any nested fragments # spread in the second fragment. for referenced_fragment_name2 in referenced_fragment_names2: collect_conflicts_between_fragments( context, conflicts, cached_fields_and_fragment_names, compared_fragment_pairs, are_mutually_exclusive, fragment_name1, referenced_fragment_name2, ) # (G) Then collect conflicts between the second fragment and any nested fragments # spread in the first fragment. for referenced_fragment_name1 in referenced_fragment_names1: collect_conflicts_between_fragments( context, conflicts, cached_fields_and_fragment_names, compared_fragment_pairs, are_mutually_exclusive, referenced_fragment_name1, fragment_name2, ) def find_conflicts_between_sub_selection_sets( context: ValidationContext, cached_fields_and_fragment_names: Dict, compared_fragment_pairs: "PairSet", are_mutually_exclusive: bool, parent_type1: Optional[GraphQLNamedType], selection_set1: SelectionSetNode, parent_type2: Optional[GraphQLNamedType], selection_set2: SelectionSetNode, ) -> List[Conflict]: """Find conflicts between sub selection sets. Find all conflicts found between two selection sets, including those found via spreading in fragments. Called when determining if conflicts exist between the sub-fields of two overlapping fields. """ conflicts: List[Conflict] = [] field_map1, fragment_names1 = get_fields_and_fragment_names( context, cached_fields_and_fragment_names, parent_type1, selection_set1 ) field_map2, fragment_names2 = get_fields_and_fragment_names( context, cached_fields_and_fragment_names, parent_type2, selection_set2 ) # (H) First, collect all conflicts between these two collections of field. collect_conflicts_between( context, conflicts, cached_fields_and_fragment_names, compared_fragment_pairs, are_mutually_exclusive, field_map1, field_map2, ) # (I) Then collect conflicts between the first collection of fields and those # referenced by each fragment name associated with the second. if fragment_names2: for fragment_name2 in fragment_names2: collect_conflicts_between_fields_and_fragment( context, conflicts, cached_fields_and_fragment_names, compared_fragment_pairs, are_mutually_exclusive, field_map1, fragment_name2, ) # (I) Then collect conflicts between the second collection of fields and those # referenced by each fragment name associated with the first. if fragment_names1: for fragment_name1 in fragment_names1: collect_conflicts_between_fields_and_fragment( context, conflicts, cached_fields_and_fragment_names, compared_fragment_pairs, are_mutually_exclusive, field_map2, fragment_name1, ) # (J) Also collect conflicts between any fragment names by the first and fragment # names by the second. This compares each item in the first set of names to each # item in the second set of names. for fragment_name1 in fragment_names1: for fragment_name2 in fragment_names2: collect_conflicts_between_fragments( context, conflicts, cached_fields_and_fragment_names, compared_fragment_pairs, are_mutually_exclusive, fragment_name1, fragment_name2, ) return conflicts def collect_conflicts_within( context: ValidationContext, conflicts: List[Conflict], cached_fields_and_fragment_names: Dict, compared_fragment_pairs: "PairSet", field_map: NodeAndDefCollection, ) -> None: """Collect all Conflicts "within" one collection of fields.""" # A field map is a keyed collection, where each key represents a response name and # the value at that key is a list of all fields which provide that response name. # For every response name, if there are multiple fields, they must be compared to # find a potential conflict. for response_name, fields in field_map.items(): # This compares every field in the list to every other field in this list # (except to itself). If the list only has one item, nothing needs to be # compared. if len(fields) > 1: for i, field in enumerate(fields): for other_field in fields[i + 1 :]: conflict = find_conflict( context, cached_fields_and_fragment_names, compared_fragment_pairs, # within one collection is never mutually exclusive False, response_name, field, other_field, ) if conflict: conflicts.append(conflict) def collect_conflicts_between( context: ValidationContext, conflicts: List[Conflict], cached_fields_and_fragment_names: Dict, compared_fragment_pairs: "PairSet", parent_fields_are_mutually_exclusive: bool, field_map1: NodeAndDefCollection, field_map2: NodeAndDefCollection, ) -> None: """Collect all Conflicts between two collections of fields. This is similar to, but different from the :func:`~.collect_conflicts_within` function above. This check assumes that :func:`~.collect_conflicts_within` has already been called on each provided collection of fields. This is true because this validator traverses each individual selection set. """ # A field map is a keyed collection, where each key represents a response name and # the value at that key is a list of all fields which provide that response name. # For any response name which appears in both provided field maps, each field from # the first field map must be compared to every field in the second field map to # find potential conflicts. for response_name, fields1 in field_map1.items(): fields2 = field_map2.get(response_name) if fields2: for field1 in fields1: for field2 in fields2: conflict = find_conflict( context, cached_fields_and_fragment_names, compared_fragment_pairs, parent_fields_are_mutually_exclusive, response_name, field1, field2, ) if conflict: conflicts.append(conflict) def find_conflict( context: ValidationContext, cached_fields_and_fragment_names: Dict, compared_fragment_pairs: "PairSet", parent_fields_are_mutually_exclusive: bool, response_name: str, field1: NodeAndDef, field2: NodeAndDef, ) -> Optional[Conflict]: """Find conflict. Determines if there is a conflict between two particular fields, including comparing their sub-fields. """ parent_type1, node1, def1 = field1 parent_type2, node2, def2 = field2 # If it is known that two fields could not possibly apply at the same time, due to # the parent types, then it is safe to permit them to diverge in aliased field or # arguments used as they will not present any ambiguity by differing. It is known # that two parent types could never overlap if they are different Object types. # Interface or Union types might overlap - if not in the current state of the # schema, then perhaps in some future version, thus may not safely diverge. are_mutually_exclusive = parent_fields_are_mutually_exclusive or ( parent_type1 != parent_type2 and is_object_type(parent_type1) and is_object_type(parent_type2) ) # The return type for each field. type1 = cast(Optional[GraphQLOutputType], def1 and def1.type) type2 = cast(Optional[GraphQLOutputType], def2 and def2.type) if not are_mutually_exclusive: # Two aliases must refer to the same field. name1 = node1.name.value name2 = node2.name.value if name1 != name2: return ( (response_name, f"'{name1}' and '{name2}' are different fields"), [node1], [node2], ) # Two field calls must have the same arguments. if not same_arguments(node1, node2): return (response_name, "they have differing arguments"), [node1], [node2] if type1 and type2 and do_types_conflict(type1, type2): return ( (response_name, f"they return conflicting types '{type1}' and '{type2}'"), [node1], [node2], ) # Collect and compare sub-fields. Use the same "visited fragment names" list for # both collections so fields in a fragment reference are never compared to # themselves. selection_set1 = node1.selection_set selection_set2 = node2.selection_set if selection_set1 and selection_set2: conflicts = find_conflicts_between_sub_selection_sets( context, cached_fields_and_fragment_names, compared_fragment_pairs, are_mutually_exclusive, get_named_type(type1), selection_set1, get_named_type(type2), selection_set2, ) return subfield_conflicts(conflicts, response_name, node1, node2) return None # no conflict def same_arguments( node1: Union[FieldNode, DirectiveNode], node2: Union[FieldNode, DirectiveNode] ) -> bool: args1 = node1.arguments args2 = node2.arguments if not args1: return not args2 if not args2: return False if len(args1) != len(args2): return False # pragma: no cover values2 = {arg.name.value: arg.value for arg in args2} for arg1 in args1: value1 = arg1.value value2 = values2.get(arg1.name.value) if value2 is None or stringify_value(value1) != stringify_value(value2): return False return True def stringify_value(value: ValueNode) -> str: return print_ast(sort_value_node(value)) def do_types_conflict(type1: GraphQLOutputType, type2: GraphQLOutputType) -> bool: """Check whether two types conflict Two types conflict if both types could not apply to a value simultaneously. Composite types are ignored as their individual field types will be compared later recursively. However List and Non-Null types must match. """ if is_list_type(type1): return ( do_types_conflict( cast(GraphQLList, type1).of_type, cast(GraphQLList, type2).of_type ) if is_list_type(type2) else True ) if is_list_type(type2): return True if is_non_null_type(type1): return ( do_types_conflict( cast(GraphQLNonNull, type1).of_type, cast(GraphQLNonNull, type2).of_type ) if is_non_null_type(type2) else True ) if is_non_null_type(type2): return True if is_leaf_type(type1) or is_leaf_type(type2): return type1 is not type2 return False def get_fields_and_fragment_names( context: ValidationContext, cached_fields_and_fragment_names: Dict, parent_type: Optional[GraphQLNamedType], selection_set: SelectionSetNode, ) -> Tuple[NodeAndDefCollection, List[str]]: """Get fields and referenced fragment names Given a selection set, return the collection of fields (a mapping of response name to field nodes and definitions) as well as a list of fragment names referenced via fragment spreads. """ cached = cached_fields_and_fragment_names.get(selection_set) if not cached: node_and_defs: NodeAndDefCollection = {} fragment_names: Dict[str, bool] = {} collect_fields_and_fragment_names( context, parent_type, selection_set, node_and_defs, fragment_names ) cached = (node_and_defs, list(fragment_names)) cached_fields_and_fragment_names[selection_set] = cached return cached def get_referenced_fields_and_fragment_names( context: ValidationContext, cached_fields_and_fragment_names: Dict, fragment: FragmentDefinitionNode, ) -> Tuple[NodeAndDefCollection, List[str]]: """Get referenced fields and nested fragment names Given a reference to a fragment, return the represented collection of fields as well as a list of nested fragment names referenced via fragment spreads. """ # Short-circuit building a type from the node if possible. cached = cached_fields_and_fragment_names.get(fragment.selection_set) if cached: return cached fragment_type = type_from_ast(context.schema, fragment.type_condition) return get_fields_and_fragment_names( context, cached_fields_and_fragment_names, fragment_type, fragment.selection_set ) def collect_fields_and_fragment_names( context: ValidationContext, parent_type: Optional[GraphQLNamedType], selection_set: SelectionSetNode, node_and_defs: NodeAndDefCollection, fragment_names: Dict[str, bool], ) -> None: for selection in selection_set.selections: if isinstance(selection, FieldNode): field_name = selection.name.value field_def = ( parent_type.fields.get(field_name) # type: ignore if is_object_type(parent_type) or is_interface_type(parent_type) else None ) response_name = selection.alias.value if selection.alias else field_name if not node_and_defs.get(response_name): node_and_defs[response_name] = [] node_and_defs[response_name].append( cast(NodeAndDef, (parent_type, selection, field_def)) ) elif isinstance(selection, FragmentSpreadNode): fragment_names[selection.name.value] = True elif isinstance(selection, InlineFragmentNode): # pragma: no cover else type_condition = selection.type_condition inline_fragment_type = ( type_from_ast(context.schema, type_condition) if type_condition else parent_type ) collect_fields_and_fragment_names( context, inline_fragment_type, selection.selection_set, node_and_defs, fragment_names, ) def subfield_conflicts( conflicts: List[Conflict], response_name: str, node1: FieldNode, node2: FieldNode ) -> Optional[Conflict]: """Check whether there are conflicts between sub-fields. Given a series of Conflicts which occurred between two sub-fields, generate a single Conflict. """ if conflicts: return ( (response_name, [conflict[0] for conflict in conflicts]), list(chain([node1], *[conflict[1] for conflict in conflicts])), list(chain([node2], *[conflict[2] for conflict in conflicts])), ) return None # no conflict class PairSet: """Pair set A way to keep track of pairs of things when the ordering of the pair doesn't matter. """ __slots__ = ("_data",) _data: Dict[str, Dict[str, bool]] def __init__(self) -> None: self._data = {} def has(self, a: str, b: str, are_mutually_exclusive: bool) -> bool: key1, key2 = (a, b) if a < b else (b, a) map_ = self._data.get(key1) if map_ is None: return False result = map_.get(key2) if result is None: return False # are_mutually_exclusive being False is a superset of being True, # hence if we want to know if this PairSet "has" these two with no exclusivity, # we have to ensure it was added as such. return True if are_mutually_exclusive else are_mutually_exclusive == result def add(self, a: str, b: str, are_mutually_exclusive: bool) -> None: key1, key2 = (a, b) if a < b else (b, a) map_ = self._data.get(key1) if map_ is None: self._data[key1] = {key2: are_mutually_exclusive} else: map_[key2] = are_mutually_exclusive graphql-core-3.2.6/src/graphql/validation/rules/possible_fragment_spreads.py000066400000000000000000000046401474546154300274360ustar00rootroot00000000000000from typing import cast, Any, Optional from ...error import GraphQLError from ...language import FragmentSpreadNode, InlineFragmentNode from ...type import GraphQLCompositeType, is_composite_type from ...utilities import do_types_overlap, type_from_ast from . import ValidationRule __all__ = ["PossibleFragmentSpreadsRule"] class PossibleFragmentSpreadsRule(ValidationRule): """Possible fragment spread A fragment spread is only valid if the type condition could ever possibly be true: if there is a non-empty intersection of the possible parent types, and possible types which pass the type condition. """ def enter_inline_fragment(self, node: InlineFragmentNode, *_args: Any) -> None: context = self.context frag_type = context.get_type() parent_type = context.get_parent_type() if ( is_composite_type(frag_type) and is_composite_type(parent_type) and not do_types_overlap( context.schema, cast(GraphQLCompositeType, frag_type), cast(GraphQLCompositeType, parent_type), ) ): context.report_error( GraphQLError( f"Fragment cannot be spread here as objects" f" of type '{parent_type}' can never be of type '{frag_type}'.", node, ) ) def enter_fragment_spread(self, node: FragmentSpreadNode, *_args: Any) -> None: context = self.context frag_name = node.name.value frag_type = self.get_fragment_type(frag_name) parent_type = context.get_parent_type() if ( frag_type and parent_type and not do_types_overlap(context.schema, frag_type, parent_type) ): context.report_error( GraphQLError( f"Fragment '{frag_name}' cannot be spread here as objects" f" of type '{parent_type}' can never be of type '{frag_type}'.", node, ) ) def get_fragment_type(self, name: str) -> Optional[GraphQLCompositeType]: context = self.context frag = context.get_fragment(name) if frag: type_ = type_from_ast(context.schema, frag.type_condition) if is_composite_type(type_): return cast(GraphQLCompositeType, type_) return None graphql-core-3.2.6/src/graphql/validation/rules/possible_type_extensions.py000066400000000000000000000071571474546154300273600ustar00rootroot00000000000000import re from functools import partial from typing import Any, Optional from ...error import GraphQLError from ...language import TypeDefinitionNode, TypeExtensionNode from ...pyutils import did_you_mean, inspect, suggestion_list from ...type import ( is_enum_type, is_input_object_type, is_interface_type, is_object_type, is_scalar_type, is_union_type, ) from . import SDLValidationContext, SDLValidationRule __all__ = ["PossibleTypeExtensionsRule"] class PossibleTypeExtensionsRule(SDLValidationRule): """Possible type extension A type extension is only valid if the type is defined and has the same kind. """ def __init__(self, context: SDLValidationContext): super().__init__(context) self.schema = context.schema self.defined_types = { def_.name.value: def_ for def_ in context.document.definitions if isinstance(def_, TypeDefinitionNode) } def check_extension(self, node: TypeExtensionNode, *_args: Any) -> None: schema = self.schema type_name = node.name.value def_node = self.defined_types.get(type_name) existing_type = schema.get_type(type_name) if schema else None expected_kind: Optional[str] if def_node: expected_kind = def_kind_to_ext_kind(def_node.kind) elif existing_type: expected_kind = type_to_ext_kind(existing_type) else: expected_kind = None if expected_kind: if expected_kind != node.kind: kind_str = extension_kind_to_type_name(node.kind) self.report_error( GraphQLError( f"Cannot extend non-{kind_str} type '{type_name}'.", [def_node, node] if def_node else node, ) ) else: all_type_names = list(self.defined_types) if self.schema: all_type_names.extend(self.schema.type_map) suggested_types = suggestion_list(type_name, all_type_names) self.report_error( GraphQLError( f"Cannot extend type '{type_name}' because it is not defined." + did_you_mean(suggested_types), node.name, ) ) enter_scalar_type_extension = enter_object_type_extension = check_extension enter_interface_type_extension = enter_union_type_extension = check_extension enter_enum_type_extension = enter_input_object_type_extension = check_extension def_kind_to_ext_kind = partial(re.compile("(?<=_type_)definition$").sub, "extension") def type_to_ext_kind(type_: Any) -> str: if is_scalar_type(type_): return "scalar_type_extension" if is_object_type(type_): return "object_type_extension" if is_interface_type(type_): return "interface_type_extension" if is_union_type(type_): return "union_type_extension" if is_enum_type(type_): return "enum_type_extension" if is_input_object_type(type_): return "input_object_type_extension" # Not reachable. All possible types have been considered. raise TypeError(f"Unexpected type: {inspect(type_)}.") _type_names_for_extension_kinds = { "scalar_type_extension": "scalar", "object_type_extension": "object", "interface_type_extension": "interface", "union_type_extension": "union", "enum_type_extension": "enum", "input_object_type_extension": "input object", } def extension_kind_to_type_name(kind: str) -> str: return _type_names_for_extension_kinds.get(kind, "unknown type") graphql-core-3.2.6/src/graphql/validation/rules/provided_required_arguments.py000066400000000000000000000105561474546154300300160ustar00rootroot00000000000000from typing import cast, Any, Dict, List, Union from ...error import GraphQLError from ...language import ( DirectiveDefinitionNode, DirectiveNode, FieldNode, InputValueDefinitionNode, NonNullTypeNode, TypeNode, VisitorAction, SKIP, print_ast, ) from ...type import GraphQLArgument, is_required_argument, is_type, specified_directives from . import ASTValidationRule, SDLValidationContext, ValidationContext __all__ = ["ProvidedRequiredArgumentsRule", "ProvidedRequiredArgumentsOnDirectivesRule"] class ProvidedRequiredArgumentsOnDirectivesRule(ASTValidationRule): """Provided required arguments on directives A directive is only valid if all required (non-null without a default value) arguments have been provided. For internal use only. """ context: Union[ValidationContext, SDLValidationContext] def __init__(self, context: Union[ValidationContext, SDLValidationContext]): super().__init__(context) required_args_map: Dict[ str, Dict[str, Union[GraphQLArgument, InputValueDefinitionNode]] ] = {} schema = context.schema defined_directives = schema.directives if schema else specified_directives for directive in cast(List, defined_directives): required_args_map[directive.name] = { name: arg for name, arg in directive.args.items() if is_required_argument(arg) } ast_definitions = context.document.definitions for def_ in ast_definitions: if isinstance(def_, DirectiveDefinitionNode): required_args_map[def_.name.value] = { arg.name.value: arg for arg in filter(is_required_argument_node, def_.arguments or ()) } self.required_args_map = required_args_map def leave_directive(self, directive_node: DirectiveNode, *_args: Any) -> None: # Validate on leave to allow for deeper errors to appear first. directive_name = directive_node.name.value required_args = self.required_args_map.get(directive_name) if required_args: arg_nodes = directive_node.arguments or () arg_node_set = {arg.name.value for arg in arg_nodes} for arg_name in required_args: if arg_name not in arg_node_set: arg_type = required_args[arg_name].type arg_type_str = ( str(arg_type) if is_type(arg_type) else print_ast(cast(TypeNode, arg_type)) ) self.report_error( GraphQLError( f"Directive '@{directive_name}' argument '{arg_name}'" f" of type '{arg_type_str}' is required," " but it was not provided.", directive_node, ) ) class ProvidedRequiredArgumentsRule(ProvidedRequiredArgumentsOnDirectivesRule): """Provided required arguments A field or directive is only valid if all required (non-null without a default value) field arguments have been provided. """ context: ValidationContext def __init__(self, context: ValidationContext): super().__init__(context) def leave_field(self, field_node: FieldNode, *_args: Any) -> VisitorAction: # Validate on leave to allow for deeper errors to appear first. field_def = self.context.get_field_def() if not field_def: return SKIP arg_nodes = field_node.arguments or () arg_node_map = {arg.name.value: arg for arg in arg_nodes} for arg_name, arg_def in field_def.args.items(): arg_node = arg_node_map.get(arg_name) if not arg_node and is_required_argument(arg_def): self.report_error( GraphQLError( f"Field '{field_node.name.value}' argument '{arg_name}'" f" of type '{arg_def.type}' is required," " but it was not provided.", field_node, ) ) return None def is_required_argument_node(arg: InputValueDefinitionNode) -> bool: return isinstance(arg.type, NonNullTypeNode) and arg.default_value is None graphql-core-3.2.6/src/graphql/validation/rules/scalar_leafs.py000066400000000000000000000026311474546154300246270ustar00rootroot00000000000000from typing import Any from ...error import GraphQLError from ...language import FieldNode from ...type import get_named_type, is_leaf_type from . import ValidationRule __all__ = ["ScalarLeafsRule"] class ScalarLeafsRule(ValidationRule): """Scalar leafs A GraphQL document is valid only if all leaf fields (fields without sub selections) are of scalar or enum types. """ def enter_field(self, node: FieldNode, *_args: Any) -> None: type_ = self.context.get_type() if type_: selection_set = node.selection_set if is_leaf_type(get_named_type(type_)): if selection_set: field_name = node.name.value self.report_error( GraphQLError( f"Field '{field_name}' must not have a selection" f" since type '{type_}' has no subfields.", selection_set, ) ) elif not selection_set: field_name = node.name.value self.report_error( GraphQLError( f"Field '{field_name}' of type '{type_}'" " must have a selection of subfields." f" Did you mean '{field_name} {{ ... }}'?", node, ) ) graphql-core-3.2.6/src/graphql/validation/rules/single_field_subscriptions.py000066400000000000000000000062041474546154300276230ustar00rootroot00000000000000from typing import Any, Dict, cast from ...error import GraphQLError from ...execution.collect_fields import collect_fields from ...language import ( FieldNode, FragmentDefinitionNode, OperationDefinitionNode, OperationType, ) from . import ValidationRule __all__ = ["SingleFieldSubscriptionsRule"] class SingleFieldSubscriptionsRule(ValidationRule): """Subscriptions must only include a single non-introspection field. A GraphQL subscription is valid only if it contains a single root field and that root field is not an introspection field. See https://spec.graphql.org/draft/#sec-Single-root-field """ def enter_operation_definition( self, node: OperationDefinitionNode, *_args: Any ) -> None: if node.operation != OperationType.SUBSCRIPTION: return schema = self.context.schema subscription_type = schema.subscription_type if subscription_type: operation_name = node.name.value if node.name else None variable_values: Dict[str, Any] = {} document = self.context.document fragments: Dict[str, FragmentDefinitionNode] = { definition.name.value: definition for definition in document.definitions if isinstance(definition, FragmentDefinitionNode) } fields = collect_fields( schema, fragments, variable_values, subscription_type, node.selection_set, ) if len(fields) > 1: field_selection_lists = list(fields.values()) extra_field_selection_lists = field_selection_lists[1:] extra_field_selection = [ field for fields in extra_field_selection_lists for field in ( fields if isinstance(fields, list) else [cast(FieldNode, fields)] ) ] self.report_error( GraphQLError( ( "Anonymous Subscription" if operation_name is None else f"Subscription '{operation_name}'" ) + " must select only one top level field.", extra_field_selection, ) ) for field_nodes in fields.values(): field = field_nodes[0] field_name = field.name.value if field_name.startswith("__"): self.report_error( GraphQLError( ( "Anonymous Subscription" if operation_name is None else f"Subscription '{operation_name}'" ) + " must not select an introspection top level field.", field_nodes, ) ) graphql-core-3.2.6/src/graphql/validation/rules/unique_argument_definition_names.py000066400000000000000000000054701474546154300310170ustar00rootroot00000000000000from operator import attrgetter from typing import Any, Collection from ...error import GraphQLError from ...language import ( DirectiveDefinitionNode, FieldDefinitionNode, InputValueDefinitionNode, InterfaceTypeDefinitionNode, InterfaceTypeExtensionNode, NameNode, ObjectTypeDefinitionNode, ObjectTypeExtensionNode, VisitorAction, SKIP, ) from ...pyutils import group_by from . import SDLValidationRule __all__ = ["UniqueArgumentDefinitionNamesRule"] class UniqueArgumentDefinitionNamesRule(SDLValidationRule): """Unique argument definition names A GraphQL Object or Interface type is only valid if all its fields have uniquely named arguments. A GraphQL Directive is only valid if all its arguments are uniquely named. See https://spec.graphql.org/draft/#sec-Argument-Uniqueness """ def enter_directive_definition( self, node: DirectiveDefinitionNode, *_args: Any ) -> VisitorAction: return self.check_arg_uniqueness(f"@{node.name.value}", node.arguments) def enter_interface_type_definition( self, node: InterfaceTypeDefinitionNode, *_args: Any ) -> VisitorAction: return self.check_arg_uniqueness_per_field(node.name, node.fields) def enter_interface_type_extension( self, node: InterfaceTypeExtensionNode, *_args: Any ) -> VisitorAction: return self.check_arg_uniqueness_per_field(node.name, node.fields) def enter_object_type_definition( self, node: ObjectTypeDefinitionNode, *_args: Any ) -> VisitorAction: return self.check_arg_uniqueness_per_field(node.name, node.fields) def enter_object_type_extension( self, node: ObjectTypeExtensionNode, *_args: Any ) -> VisitorAction: return self.check_arg_uniqueness_per_field(node.name, node.fields) def check_arg_uniqueness_per_field( self, name: NameNode, fields: Collection[FieldDefinitionNode], ) -> VisitorAction: type_name = name.value for field_def in fields: field_name = field_def.name.value argument_nodes = field_def.arguments or () self.check_arg_uniqueness(f"{type_name}.{field_name}", argument_nodes) return SKIP def check_arg_uniqueness( self, parent_name: str, argument_nodes: Collection[InputValueDefinitionNode] ) -> VisitorAction: seen_args = group_by(argument_nodes, attrgetter("name.value")) for arg_name, arg_nodes in seen_args.items(): if len(arg_nodes) > 1: self.report_error( GraphQLError( f"Argument '{parent_name}({arg_name}:)'" " can only be defined once.", [node.name for node in arg_nodes], ) ) return SKIP graphql-core-3.2.6/src/graphql/validation/rules/unique_argument_names.py000066400000000000000000000023411474546154300266010ustar00rootroot00000000000000from operator import attrgetter from typing import Any, Collection from ...error import GraphQLError from ...language import ArgumentNode, DirectiveNode, FieldNode from ...pyutils import group_by from . import ASTValidationRule __all__ = ["UniqueArgumentNamesRule"] class UniqueArgumentNamesRule(ASTValidationRule): """Unique argument names A GraphQL field or directive is only valid if all supplied arguments are uniquely named. See https://spec.graphql.org/draft/#sec-Argument-Names """ def enter_field(self, node: FieldNode, *_args: Any) -> None: self.check_arg_uniqueness(node.arguments) def enter_directive(self, node: DirectiveNode, *args: Any) -> None: self.check_arg_uniqueness(node.arguments) def check_arg_uniqueness(self, argument_nodes: Collection[ArgumentNode]) -> None: seen_args = group_by(argument_nodes, attrgetter("name.value")) for arg_name, arg_nodes in seen_args.items(): if len(arg_nodes) > 1: self.report_error( GraphQLError( f"There can be only one argument named '{arg_name}'.", [node.name for node in arg_nodes], ) ) graphql-core-3.2.6/src/graphql/validation/rules/unique_directive_names.py000066400000000000000000000030421474546154300267340ustar00rootroot00000000000000from typing import Any, Dict from ...error import GraphQLError from ...language import DirectiveDefinitionNode, NameNode, VisitorAction, SKIP from . import SDLValidationContext, SDLValidationRule __all__ = ["UniqueDirectiveNamesRule"] class UniqueDirectiveNamesRule(SDLValidationRule): """Unique directive names A GraphQL document is only valid if all defined directives have unique names. """ def __init__(self, context: SDLValidationContext): super().__init__(context) self.known_directive_names: Dict[str, NameNode] = {} self.schema = context.schema def enter_directive_definition( self, node: DirectiveDefinitionNode, *_args: Any ) -> VisitorAction: directive_name = node.name.value if self.schema and self.schema.get_directive(directive_name): self.report_error( GraphQLError( f"Directive '@{directive_name}' already exists in the schema." " It cannot be redefined.", node.name, ) ) else: if directive_name in self.known_directive_names: self.report_error( GraphQLError( f"There can be only one directive named '@{directive_name}'.", [self.known_directive_names[directive_name], node.name], ) ) else: self.known_directive_names[directive_name] = node.name return SKIP return None graphql-core-3.2.6/src/graphql/validation/rules/unique_directives_per_location.py000066400000000000000000000062461474546154300305030ustar00rootroot00000000000000from collections import defaultdict from typing import Any, Dict, List, Union, cast from ...error import GraphQLError from ...language import ( DirectiveDefinitionNode, DirectiveNode, Node, SchemaDefinitionNode, SchemaExtensionNode, TypeDefinitionNode, TypeExtensionNode, is_type_definition_node, is_type_extension_node, ) from ...type import specified_directives from . import ASTValidationRule, SDLValidationContext, ValidationContext __all__ = ["UniqueDirectivesPerLocationRule"] class UniqueDirectivesPerLocationRule(ASTValidationRule): """Unique directive names per location A GraphQL document is only valid if all non-repeatable directives at a given location are uniquely named. See https://spec.graphql.org/draft/#sec-Directives-Are-Unique-Per-Location """ context: Union[ValidationContext, SDLValidationContext] def __init__(self, context: Union[ValidationContext, SDLValidationContext]): super().__init__(context) unique_directive_map: Dict[str, bool] = {} schema = context.schema defined_directives = ( schema.directives if schema else cast(List, specified_directives) ) for directive in defined_directives: unique_directive_map[directive.name] = not directive.is_repeatable ast_definitions = context.document.definitions for def_ in ast_definitions: if isinstance(def_, DirectiveDefinitionNode): unique_directive_map[def_.name.value] = not def_.repeatable self.unique_directive_map = unique_directive_map self.schema_directives: Dict[str, DirectiveNode] = {} self.type_directives_map: Dict[str, Dict[str, DirectiveNode]] = defaultdict( dict ) # Many different AST nodes may contain directives. Rather than listing them all, # just listen for entering any node, and check to see if it defines any directives. def enter(self, node: Node, *_args: Any) -> None: directives = getattr(node, "directives", None) if not directives: return directives = cast(List[DirectiveNode], directives) if isinstance(node, (SchemaDefinitionNode, SchemaExtensionNode)): seen_directives = self.schema_directives elif is_type_definition_node(node) or is_type_extension_node(node): node = cast(Union[TypeDefinitionNode, TypeExtensionNode], node) type_name = node.name.value seen_directives = self.type_directives_map[type_name] else: seen_directives = {} for directive in directives: directive_name = directive.name.value if self.unique_directive_map.get(directive_name): if directive_name in seen_directives: self.report_error( GraphQLError( f"The directive '@{directive_name}'" " can only be used once at this location.", [seen_directives[directive_name], directive], ) ) else: seen_directives[directive_name] = directive graphql-core-3.2.6/src/graphql/validation/rules/unique_enum_value_names.py000066400000000000000000000042641474546154300271250ustar00rootroot00000000000000from collections import defaultdict from typing import cast, Any, Dict from ...error import GraphQLError from ...language import NameNode, EnumTypeDefinitionNode, VisitorAction, SKIP from ...type import is_enum_type, GraphQLEnumType from . import SDLValidationContext, SDLValidationRule __all__ = ["UniqueEnumValueNamesRule"] class UniqueEnumValueNamesRule(SDLValidationRule): """Unique enum value names A GraphQL enum type is only valid if all its values are uniquely named. """ def __init__(self, context: SDLValidationContext): super().__init__(context) schema = context.schema self.existing_type_map = schema.type_map if schema else {} self.known_value_names: Dict[str, Dict[str, NameNode]] = defaultdict(dict) def check_value_uniqueness( self, node: EnumTypeDefinitionNode, *_args: Any ) -> VisitorAction: existing_type_map = self.existing_type_map type_name = node.name.value value_names = self.known_value_names[type_name] for value_def in node.values or []: value_name = value_def.name.value existing_type = existing_type_map.get(type_name) if ( is_enum_type(existing_type) and value_name in cast(GraphQLEnumType, existing_type).values ): self.report_error( GraphQLError( f"Enum value '{type_name}.{value_name}'" " already exists in the schema." " It cannot also be defined in this type extension.", value_def.name, ) ) elif value_name in value_names: self.report_error( GraphQLError( f"Enum value '{type_name}.{value_name}'" " can only be defined once.", [value_names[value_name], value_def.name], ) ) else: value_names[value_name] = value_def.name return SKIP enter_enum_type_definition = check_value_uniqueness enter_enum_type_extension = check_value_uniqueness graphql-core-3.2.6/src/graphql/validation/rules/unique_field_definition_names.py000066400000000000000000000050161474546154300302540ustar00rootroot00000000000000from collections import defaultdict from typing import Any, Dict from ...error import GraphQLError from ...language import NameNode, ObjectTypeDefinitionNode, VisitorAction, SKIP from ...type import is_object_type, is_interface_type, is_input_object_type from . import SDLValidationContext, SDLValidationRule __all__ = ["UniqueFieldDefinitionNamesRule"] class UniqueFieldDefinitionNamesRule(SDLValidationRule): """Unique field definition names A GraphQL complex type is only valid if all its fields are uniquely named. """ def __init__(self, context: SDLValidationContext): super().__init__(context) schema = context.schema self.existing_type_map = schema.type_map if schema else {} self.known_field_names: Dict[str, Dict[str, NameNode]] = defaultdict(dict) def check_field_uniqueness( self, node: ObjectTypeDefinitionNode, *_args: Any ) -> VisitorAction: existing_type_map = self.existing_type_map type_name = node.name.value field_names = self.known_field_names[type_name] for field_def in node.fields or []: field_name = field_def.name.value if has_field(existing_type_map.get(type_name), field_name): self.report_error( GraphQLError( f"Field '{type_name}.{field_name}'" " already exists in the schema." " It cannot also be defined in this type extension.", field_def.name, ) ) elif field_name in field_names: self.report_error( GraphQLError( f"Field '{type_name}.{field_name}'" " can only be defined once.", [field_names[field_name], field_def.name], ) ) else: field_names[field_name] = field_def.name return SKIP enter_input_object_type_definition = check_field_uniqueness enter_input_object_type_extension = check_field_uniqueness enter_interface_type_definition = check_field_uniqueness enter_interface_type_extension = check_field_uniqueness enter_object_type_definition = check_field_uniqueness enter_object_type_extension = check_field_uniqueness def has_field(type_: Any, field_name: str) -> bool: if is_object_type(type_) or is_interface_type(type_) or is_input_object_type(type_): return field_name in type_.fields return False graphql-core-3.2.6/src/graphql/validation/rules/unique_fragment_names.py000066400000000000000000000024631474546154300265670ustar00rootroot00000000000000from typing import Any, Dict from ...error import GraphQLError from ...language import NameNode, FragmentDefinitionNode, VisitorAction, SKIP from . import ASTValidationContext, ASTValidationRule __all__ = ["UniqueFragmentNamesRule"] class UniqueFragmentNamesRule(ASTValidationRule): """Unique fragment names A GraphQL document is only valid if all defined fragments have unique names. See https://spec.graphql.org/draft/#sec-Fragment-Name-Uniqueness """ def __init__(self, context: ASTValidationContext): super().__init__(context) self.known_fragment_names: Dict[str, NameNode] = {} @staticmethod def enter_operation_definition(*_args: Any) -> VisitorAction: return SKIP def enter_fragment_definition( self, node: FragmentDefinitionNode, *_args: Any ) -> VisitorAction: known_fragment_names = self.known_fragment_names fragment_name = node.name.value if fragment_name in known_fragment_names: self.report_error( GraphQLError( f"There can be only one fragment named '{fragment_name}'.", [known_fragment_names[fragment_name], node.name], ) ) else: known_fragment_names[fragment_name] = node.name return SKIP graphql-core-3.2.6/src/graphql/validation/rules/unique_input_field_names.py000066400000000000000000000026171474546154300272670ustar00rootroot00000000000000from typing import Any, Dict, List from ...error import GraphQLError from ...language import NameNode, ObjectFieldNode from . import ASTValidationContext, ASTValidationRule __all__ = ["UniqueInputFieldNamesRule"] class UniqueInputFieldNamesRule(ASTValidationRule): """Unique input field names A GraphQL input object value is only valid if all supplied fields are uniquely named. See https://spec.graphql.org/draft/#sec-Input-Object-Field-Uniqueness """ def __init__(self, context: ASTValidationContext): super().__init__(context) self.known_names_stack: List[Dict[str, NameNode]] = [] self.known_names: Dict[str, NameNode] = {} def enter_object_value(self, *_args: Any) -> None: self.known_names_stack.append(self.known_names) self.known_names = {} def leave_object_value(self, *_args: Any) -> None: self.known_names = self.known_names_stack.pop() def enter_object_field(self, node: ObjectFieldNode, *_args: Any) -> None: known_names = self.known_names field_name = node.name.value if field_name in known_names: self.report_error( GraphQLError( f"There can be only one input field named '{field_name}'.", [known_names[field_name], node.name], ) ) else: known_names[field_name] = node.name graphql-core-3.2.6/src/graphql/validation/rules/unique_operation_names.py000066400000000000000000000027001474546154300267560ustar00rootroot00000000000000from typing import Any, Dict from ...error import GraphQLError from ...language import NameNode, OperationDefinitionNode, VisitorAction, SKIP from . import ASTValidationContext, ASTValidationRule __all__ = ["UniqueOperationNamesRule"] class UniqueOperationNamesRule(ASTValidationRule): """Unique operation names A GraphQL document is only valid if all defined operations have unique names. See https://spec.graphql.org/draft/#sec-Operation-Name-Uniqueness """ def __init__(self, context: ASTValidationContext): super().__init__(context) self.known_operation_names: Dict[str, NameNode] = {} def enter_operation_definition( self, node: OperationDefinitionNode, *_args: Any ) -> VisitorAction: operation_name = node.name if operation_name: known_operation_names = self.known_operation_names if operation_name.value in known_operation_names: self.report_error( GraphQLError( "There can be only one operation" f" named '{operation_name.value}'.", [known_operation_names[operation_name.value], operation_name], ) ) else: known_operation_names[operation_name.value] = operation_name return SKIP @staticmethod def enter_fragment_definition(*_args: Any) -> VisitorAction: return SKIP graphql-core-3.2.6/src/graphql/validation/rules/unique_operation_types.py000066400000000000000000000045071474546154300270260ustar00rootroot00000000000000from typing import Any, Dict, Optional, Union from ...error import GraphQLError from ...language import ( OperationTypeDefinitionNode, OperationType, SchemaDefinitionNode, SchemaExtensionNode, VisitorAction, SKIP, ) from ...type import GraphQLObjectType from . import SDLValidationContext, SDLValidationRule __all__ = ["UniqueOperationTypesRule"] class UniqueOperationTypesRule(SDLValidationRule): """Unique operation types A GraphQL document is only valid if it has only one type per operation. """ def __init__(self, context: SDLValidationContext): super().__init__(context) schema = context.schema self.defined_operation_types: Dict[ OperationType, OperationTypeDefinitionNode ] = {} self.existing_operation_types: Dict[ OperationType, Optional[GraphQLObjectType] ] = ( { OperationType.QUERY: schema.query_type, OperationType.MUTATION: schema.mutation_type, OperationType.SUBSCRIPTION: schema.subscription_type, } if schema else {} ) self.schema = schema def check_operation_types( self, node: Union[SchemaDefinitionNode, SchemaExtensionNode], *_args: Any ) -> VisitorAction: for operation_type in node.operation_types or []: operation = operation_type.operation already_defined_operation_type = self.defined_operation_types.get(operation) if self.existing_operation_types.get(operation): self.report_error( GraphQLError( f"Type for {operation.value} already defined in the schema." " It cannot be redefined.", operation_type, ) ) elif already_defined_operation_type: self.report_error( GraphQLError( f"There can be only one {operation.value} type in schema.", [already_defined_operation_type, operation_type], ) ) else: self.defined_operation_types[operation] = operation_type return SKIP enter_schema_definition = enter_schema_extension = check_operation_types graphql-core-3.2.6/src/graphql/validation/rules/unique_type_names.py000066400000000000000000000032731474546154300257450ustar00rootroot00000000000000from typing import Any, Dict from ...error import GraphQLError from ...language import NameNode, TypeDefinitionNode, VisitorAction, SKIP from . import SDLValidationContext, SDLValidationRule __all__ = ["UniqueTypeNamesRule"] class UniqueTypeNamesRule(SDLValidationRule): """Unique type names A GraphQL document is only valid if all defined types have unique names. """ def __init__(self, context: SDLValidationContext): super().__init__(context) self.known_type_names: Dict[str, NameNode] = {} self.schema = context.schema def check_type_name(self, node: TypeDefinitionNode, *_args: Any) -> VisitorAction: type_name = node.name.value if self.schema and self.schema.get_type(type_name): self.report_error( GraphQLError( f"Type '{type_name}' already exists in the schema." " It cannot also be defined in this type definition.", node.name, ) ) else: if type_name in self.known_type_names: self.report_error( GraphQLError( f"There can be only one type named '{type_name}'.", [self.known_type_names[type_name], node.name], ) ) else: self.known_type_names[type_name] = node.name return SKIP return None enter_scalar_type_definition = enter_object_type_definition = check_type_name enter_interface_type_definition = enter_union_type_definition = check_type_name enter_enum_type_definition = enter_input_object_type_definition = check_type_name graphql-core-3.2.6/src/graphql/validation/rules/unique_variable_names.py000066400000000000000000000021011474546154300265360ustar00rootroot00000000000000from operator import attrgetter from typing import Any from ...error import GraphQLError from ...language import OperationDefinitionNode from ...pyutils import group_by from . import ASTValidationRule __all__ = ["UniqueVariableNamesRule"] class UniqueVariableNamesRule(ASTValidationRule): """Unique variable names A GraphQL operation is only valid if all its variables are uniquely named. """ def enter_operation_definition( self, node: OperationDefinitionNode, *_args: Any ) -> None: variable_definitions = node.variable_definitions seen_variable_definitions = group_by( variable_definitions, attrgetter("variable.name.value") ) for variable_name, variable_nodes in seen_variable_definitions.items(): if len(variable_nodes) > 1: self.report_error( GraphQLError( f"There can be only one variable named '${variable_name}'.", [node.variable.name for node in variable_nodes], ) ) graphql-core-3.2.6/src/graphql/validation/rules/values_of_correct_type.py000066400000000000000000000133201474546154300267520ustar00rootroot00000000000000from typing import cast, Any from ...error import GraphQLError from ...language import ( BooleanValueNode, EnumValueNode, FloatValueNode, IntValueNode, NullValueNode, ListValueNode, ObjectFieldNode, ObjectValueNode, StringValueNode, ValueNode, VisitorAction, SKIP, print_ast, ) from ...pyutils import did_you_mean, suggestion_list, Undefined from ...type import ( GraphQLInputObjectType, GraphQLScalarType, get_named_type, get_nullable_type, is_input_object_type, is_leaf_type, is_list_type, is_non_null_type, is_required_input_field, ) from . import ValidationRule __all__ = ["ValuesOfCorrectTypeRule"] class ValuesOfCorrectTypeRule(ValidationRule): """Value literals of correct type A GraphQL document is only valid if all value literals are of the type expected at their position. See https://spec.graphql.org/draft/#sec-Values-of-Correct-Type """ def enter_list_value(self, node: ListValueNode, *_args: Any) -> VisitorAction: # Note: TypeInfo will traverse into a list's item type, so look to the parent # input type to check if it is a list. type_ = get_nullable_type(self.context.get_parent_input_type()) # type: ignore if not is_list_type(type_): self.is_valid_value_node(node) return SKIP # Don't traverse further. return None def enter_object_value(self, node: ObjectValueNode, *_args: Any) -> VisitorAction: type_ = get_named_type(self.context.get_input_type()) if not is_input_object_type(type_): self.is_valid_value_node(node) return SKIP # Don't traverse further. type_ = cast(GraphQLInputObjectType, type_) # Ensure every required field exists. field_node_map = {field.name.value: field for field in node.fields} for field_name, field_def in type_.fields.items(): field_node = field_node_map.get(field_name) if not field_node and is_required_input_field(field_def): field_type = field_def.type self.report_error( GraphQLError( f"Field '{type_.name}.{field_name}' of required type" f" '{field_type}' was not provided.", node, ) ) return None def enter_object_field(self, node: ObjectFieldNode, *_args: Any) -> None: parent_type = get_named_type(self.context.get_parent_input_type()) field_type = self.context.get_input_type() if not field_type and is_input_object_type(parent_type): parent_type = cast(GraphQLInputObjectType, parent_type) suggestions = suggestion_list(node.name.value, list(parent_type.fields)) self.report_error( GraphQLError( f"Field '{node.name.value}'" f" is not defined by type '{parent_type.name}'." + did_you_mean(suggestions), node, ) ) def enter_null_value(self, node: NullValueNode, *_args: Any) -> None: type_ = self.context.get_input_type() if is_non_null_type(type_): self.report_error( GraphQLError( f"Expected value of type '{type_}', found {print_ast(node)}.", node ) ) def enter_enum_value(self, node: EnumValueNode, *_args: Any) -> None: self.is_valid_value_node(node) def enter_int_value(self, node: IntValueNode, *_args: Any) -> None: self.is_valid_value_node(node) def enter_float_value(self, node: FloatValueNode, *_args: Any) -> None: self.is_valid_value_node(node) def enter_string_value(self, node: StringValueNode, *_args: Any) -> None: self.is_valid_value_node(node) def enter_boolean_value(self, node: BooleanValueNode, *_args: Any) -> None: self.is_valid_value_node(node) def is_valid_value_node(self, node: ValueNode) -> None: """Check whether this is a valid value node. Any value literal may be a valid representation of a Scalar, depending on that scalar type. """ # Report any error at the full type expected by the location. location_type = self.context.get_input_type() if not location_type: return type_ = get_named_type(location_type) if not is_leaf_type(type_): self.report_error( GraphQLError( f"Expected value of type '{location_type}'," f" found {print_ast(node)}.", node, ) ) return # Scalars determine if a literal value is valid via `parse_literal()` which may # throw or return an invalid value to indicate failure. type_ = cast(GraphQLScalarType, type_) try: parse_result = type_.parse_literal(node) if parse_result is Undefined: self.report_error( GraphQLError( f"Expected value of type '{location_type}'," f" found {print_ast(node)}.", node, ) ) except GraphQLError as error: self.report_error(error) except Exception as error: self.report_error( GraphQLError( f"Expected value of type '{location_type}'," f" found {print_ast(node)}; {error}", node, # Ensure a reference to the original error is maintained. original_error=error, ) ) return graphql-core-3.2.6/src/graphql/validation/rules/variables_are_input_types.py000066400000000000000000000022441474546154300274520ustar00rootroot00000000000000from typing import Any from ...error import GraphQLError from ...language import VariableDefinitionNode, print_ast from ...type import is_input_type from ...utilities import type_from_ast from . import ValidationRule __all__ = ["VariablesAreInputTypesRule"] class VariablesAreInputTypesRule(ValidationRule): """Variables are input types A GraphQL operation is only valid if all the variables it defines are of input types (scalar, enum, or input object). See https://spec.graphql.org/draft/#sec-Variables-Are-Input-Types """ def enter_variable_definition( self, node: VariableDefinitionNode, *_args: Any ) -> None: type_ = type_from_ast(self.context.schema, node.type) # If the variable type is not an input type, return an error. if type_ is not None and not is_input_type(type_): variable_name = node.variable.name.value type_name = print_ast(node.type) self.report_error( GraphQLError( f"Variable '${variable_name}'" f" cannot be non-input type '{type_name}'.", node.type, ) ) graphql-core-3.2.6/src/graphql/validation/rules/variables_in_allowed_position.py000066400000000000000000000071771474546154300303130ustar00rootroot00000000000000from typing import Any, Dict, Optional, cast from ...error import GraphQLError from ...language import ( NullValueNode, OperationDefinitionNode, ValueNode, VariableDefinitionNode, ) from ...pyutils import Undefined from ...type import GraphQLNonNull, GraphQLSchema, GraphQLType, is_non_null_type from ...utilities import type_from_ast, is_type_sub_type_of from . import ValidationContext, ValidationRule __all__ = ["VariablesInAllowedPositionRule"] class VariablesInAllowedPositionRule(ValidationRule): """Variables in allowed position Variable usages must be compatible with the arguments they are passed to. See https://spec.graphql.org/draft/#sec-All-Variable-Usages-are-Allowed """ def __init__(self, context: ValidationContext): super().__init__(context) self.var_def_map: Dict[str, Any] = {} def enter_operation_definition(self, *_args: Any) -> None: self.var_def_map.clear() def leave_operation_definition( self, operation: OperationDefinitionNode, *_args: Any ) -> None: var_def_map = self.var_def_map usages = self.context.get_recursive_variable_usages(operation) for usage in usages: node, type_ = usage.node, usage.type default_value = usage.default_value var_name = node.name.value var_def = var_def_map.get(var_name) if var_def and type_: # A var type is allowed if it is the same or more strict (e.g. is a # subtype of) than the expected type. It can be more strict if the # variable type is non-null when the expected type is nullable. If both # are list types, the variable item type can be more strict than the # expected item type (contravariant). schema = self.context.schema var_type = type_from_ast(schema, var_def.type) if var_type and not allowed_variable_usage( schema, var_type, var_def.default_value, type_, default_value ): self.report_error( GraphQLError( f"Variable '${var_name}' of type '{var_type}' used" f" in position expecting type '{type_}'.", [var_def, node], ) ) def enter_variable_definition( self, node: VariableDefinitionNode, *_args: Any ) -> None: self.var_def_map[node.variable.name.value] = node def allowed_variable_usage( schema: GraphQLSchema, var_type: GraphQLType, var_default_value: Optional[ValueNode], location_type: GraphQLType, location_default_value: Any, ) -> bool: """Check for allowed variable usage. Returns True if the variable is allowed in the location it was found, which includes considering if default values exist for either the variable or the location at which it is located. """ if is_non_null_type(location_type) and not is_non_null_type(var_type): has_non_null_variable_default_value = ( var_default_value is not None and not isinstance(var_default_value, NullValueNode) ) has_location_default_value = location_default_value is not Undefined if not has_non_null_variable_default_value and not has_location_default_value: return False location_type = cast(GraphQLNonNull, location_type) nullable_location_type = location_type.of_type return is_type_sub_type_of(schema, var_type, nullable_location_type) return is_type_sub_type_of(schema, var_type, location_type) graphql-core-3.2.6/src/graphql/validation/specified_rules.py000066400000000000000000000131511474546154300242220ustar00rootroot00000000000000from typing import Tuple, Type from .rules import ASTValidationRule # Spec Section: "Executable Definitions" from .rules.executable_definitions import ExecutableDefinitionsRule # Spec Section: "Operation Name Uniqueness" from .rules.unique_operation_names import UniqueOperationNamesRule # Spec Section: "Lone Anonymous Operation" from .rules.lone_anonymous_operation import LoneAnonymousOperationRule # Spec Section: "Subscriptions with Single Root Field" from .rules.single_field_subscriptions import SingleFieldSubscriptionsRule # Spec Section: "Fragment Spread Type Existence" from .rules.known_type_names import KnownTypeNamesRule # Spec Section: "Fragments on Composite Types" from .rules.fragments_on_composite_types import FragmentsOnCompositeTypesRule # Spec Section: "Variables are Input Types" from .rules.variables_are_input_types import VariablesAreInputTypesRule # Spec Section: "Leaf Field Selections" from .rules.scalar_leafs import ScalarLeafsRule # Spec Section: "Field Selections on Objects, Interfaces, and Unions Types" from .rules.fields_on_correct_type import FieldsOnCorrectTypeRule # Spec Section: "Fragment Name Uniqueness" from .rules.unique_fragment_names import UniqueFragmentNamesRule # Spec Section: "Fragment spread target defined" from .rules.known_fragment_names import KnownFragmentNamesRule # Spec Section: "Fragments must be used" from .rules.no_unused_fragments import NoUnusedFragmentsRule # Spec Section: "Fragment spread is possible" from .rules.possible_fragment_spreads import PossibleFragmentSpreadsRule # Spec Section: "Fragments must not form cycles" from .rules.no_fragment_cycles import NoFragmentCyclesRule # Spec Section: "Variable Uniqueness" from .rules.unique_variable_names import UniqueVariableNamesRule # Spec Section: "All Variable Used Defined" from .rules.no_undefined_variables import NoUndefinedVariablesRule # Spec Section: "All Variables Used" from .rules.no_unused_variables import NoUnusedVariablesRule # Spec Section: "Directives Are Defined" from .rules.known_directives import KnownDirectivesRule # Spec Section: "Directives Are Unique Per Location" from .rules.unique_directives_per_location import UniqueDirectivesPerLocationRule # Spec Section: "Argument Names" from .rules.known_argument_names import KnownArgumentNamesRule from .rules.known_argument_names import KnownArgumentNamesOnDirectivesRule # Spec Section: "Argument Uniqueness" from .rules.unique_argument_names import UniqueArgumentNamesRule # Spec Section: "Value Type Correctness" from .rules.values_of_correct_type import ValuesOfCorrectTypeRule # Spec Section: "Argument Optionality" from .rules.provided_required_arguments import ProvidedRequiredArgumentsRule from .rules.provided_required_arguments import ProvidedRequiredArgumentsOnDirectivesRule # Spec Section: "All Variable Usages Are Allowed" from .rules.variables_in_allowed_position import VariablesInAllowedPositionRule # Spec Section: "Field Selection Merging" from .rules.overlapping_fields_can_be_merged import OverlappingFieldsCanBeMergedRule # Spec Section: "Input Object Field Uniqueness" from .rules.unique_input_field_names import UniqueInputFieldNamesRule # Schema definition language: from .rules.lone_schema_definition import LoneSchemaDefinitionRule from .rules.unique_operation_types import UniqueOperationTypesRule from .rules.unique_type_names import UniqueTypeNamesRule from .rules.unique_enum_value_names import UniqueEnumValueNamesRule from .rules.unique_field_definition_names import UniqueFieldDefinitionNamesRule from .rules.unique_argument_definition_names import UniqueArgumentDefinitionNamesRule from .rules.unique_directive_names import UniqueDirectiveNamesRule from .rules.possible_type_extensions import PossibleTypeExtensionsRule __all__ = ["specified_rules", "specified_sdl_rules"] # This list includes all validation rules defined by the GraphQL spec. # # The order of the rules in this list has been adjusted to lead to the # most clear output when encountering multiple validation errors. specified_rules: Tuple[Type[ASTValidationRule], ...] = ( ExecutableDefinitionsRule, UniqueOperationNamesRule, LoneAnonymousOperationRule, SingleFieldSubscriptionsRule, KnownTypeNamesRule, FragmentsOnCompositeTypesRule, VariablesAreInputTypesRule, ScalarLeafsRule, FieldsOnCorrectTypeRule, UniqueFragmentNamesRule, KnownFragmentNamesRule, NoUnusedFragmentsRule, PossibleFragmentSpreadsRule, NoFragmentCyclesRule, UniqueVariableNamesRule, NoUndefinedVariablesRule, NoUnusedVariablesRule, KnownDirectivesRule, UniqueDirectivesPerLocationRule, KnownArgumentNamesRule, UniqueArgumentNamesRule, ValuesOfCorrectTypeRule, ProvidedRequiredArgumentsRule, VariablesInAllowedPositionRule, OverlappingFieldsCanBeMergedRule, UniqueInputFieldNamesRule, ) """A tuple with all validation rules defined by the GraphQL specification. The order of the rules in this tuple has been adjusted to lead to the most clear output when encountering multiple validation errors. """ specified_sdl_rules: Tuple[Type[ASTValidationRule], ...] = ( LoneSchemaDefinitionRule, UniqueOperationTypesRule, UniqueTypeNamesRule, UniqueEnumValueNamesRule, UniqueFieldDefinitionNamesRule, UniqueArgumentDefinitionNamesRule, UniqueDirectiveNamesRule, KnownTypeNamesRule, KnownDirectivesRule, UniqueDirectivesPerLocationRule, PossibleTypeExtensionsRule, KnownArgumentNamesOnDirectivesRule, UniqueArgumentNamesRule, UniqueInputFieldNamesRule, ProvidedRequiredArgumentsOnDirectivesRule, ) """This tuple includes all rules for validating SDL. For internal use only. """ graphql-core-3.2.6/src/graphql/validation/validate.py000066400000000000000000000114651474546154300226540ustar00rootroot00000000000000from typing import Collection, List, Optional, Type from ..error import GraphQLError from ..language import DocumentNode, ParallelVisitor, visit from ..pyutils import inspect, is_collection from ..type import GraphQLSchema, assert_valid_schema from ..utilities import TypeInfo, TypeInfoVisitor from .rules import ASTValidationRule from .specified_rules import specified_rules, specified_sdl_rules from .validation_context import SDLValidationContext, ValidationContext __all__ = ["assert_valid_sdl", "assert_valid_sdl_extension", "validate", "validate_sdl"] class ValidationAbortedError(RuntimeError): """Error when a validation has been aborted (error limit reached).""" def validate( schema: GraphQLSchema, document_ast: DocumentNode, rules: Optional[Collection[Type[ASTValidationRule]]] = None, max_errors: Optional[int] = None, type_info: Optional[TypeInfo] = None, ) -> List[GraphQLError]: """Implements the "Validation" section of the spec. Validation runs synchronously, returning a list of encountered errors, or an empty list if no errors were encountered and the document is valid. A list of specific validation rules may be provided. If not provided, the default list of rules defined by the GraphQL specification will be used. Each validation rule is a ValidationRule object which is a visitor object that holds a ValidationContext (see the language/visitor API). Visitor methods are expected to return GraphQLErrors, or lists of GraphQLErrors when invalid. Validate will stop validation after a ``max_errors`` limit has been reached. Attackers can send pathologically invalid queries to induce a DoS attack, so by default ``max_errors`` set to 100 errors. Providing a custom TypeInfo instance is deprecated and will be removed in v3.3. """ if not document_ast or not isinstance(document_ast, DocumentNode): raise TypeError("Must provide document.") # If the schema used for validation is invalid, throw an error. assert_valid_schema(schema) if max_errors is None: max_errors = 100 elif not isinstance(max_errors, int): raise TypeError("The maximum number of errors must be passed as an int.") if type_info is None: type_info = TypeInfo(schema) elif not isinstance(type_info, TypeInfo): raise TypeError(f"Not a TypeInfo object: {inspect(type_info)}.") if rules is None: rules = specified_rules elif not is_collection(rules) or not all( isinstance(rule, type) and issubclass(rule, ASTValidationRule) for rule in rules ): raise TypeError( "Rules must be specified as a collection of ASTValidationRule subclasses." ) errors: List[GraphQLError] = [] def on_error(error: GraphQLError) -> None: if len(errors) >= max_errors: errors.append( GraphQLError( "Too many validation errors, error limit reached." " Validation aborted." ) ) raise ValidationAbortedError errors.append(error) context = ValidationContext(schema, document_ast, type_info, on_error) # This uses a specialized visitor which runs multiple visitors in parallel, # while maintaining the visitor skip and break API. visitors = [rule(context) for rule in rules] # Visit the whole document with each instance of all provided rules. try: visit(document_ast, TypeInfoVisitor(type_info, ParallelVisitor(visitors))) except ValidationAbortedError: pass return errors def validate_sdl( document_ast: DocumentNode, schema_to_extend: Optional[GraphQLSchema] = None, rules: Optional[Collection[Type[ASTValidationRule]]] = None, ) -> List[GraphQLError]: """Validate an SDL document. For internal use only. """ errors: List[GraphQLError] = [] context = SDLValidationContext(document_ast, schema_to_extend, errors.append) if rules is None: rules = specified_sdl_rules visitors = [rule(context) for rule in rules] visit(document_ast, ParallelVisitor(visitors)) return errors def assert_valid_sdl(document_ast: DocumentNode) -> None: """Assert document is valid SDL. Utility function which asserts a SDL document is valid by throwing an error if it is invalid. """ errors = validate_sdl(document_ast) if errors: raise TypeError("\n\n".join(error.message for error in errors)) def assert_valid_sdl_extension( document_ast: DocumentNode, schema: GraphQLSchema ) -> None: """Assert document is a valid SDL extension. Utility function which asserts a SDL document is valid by throwing an error if it is invalid. """ errors = validate_sdl(document_ast, schema) if errors: raise TypeError("\n\n".join(error.message for error in errors)) graphql-core-3.2.6/src/graphql/validation/validation_context.py000066400000000000000000000206031474546154300247530ustar00rootroot00000000000000from typing import Any, Callable, Dict, List, NamedTuple, Optional, Set, Union, cast from ..error import GraphQLError from ..language import ( DocumentNode, FragmentDefinitionNode, FragmentSpreadNode, OperationDefinitionNode, SelectionSetNode, VariableNode, Visitor, VisitorAction, visit, ) from ..type import ( GraphQLArgument, GraphQLCompositeType, GraphQLDirective, GraphQLEnumValue, GraphQLField, GraphQLInputType, GraphQLOutputType, GraphQLSchema, ) from ..utilities import TypeInfo, TypeInfoVisitor __all__ = [ "ASTValidationContext", "SDLValidationContext", "ValidationContext", "VariableUsage", "VariableUsageVisitor", ] NodeWithSelectionSet = Union[OperationDefinitionNode, FragmentDefinitionNode] class VariableUsage(NamedTuple): node: VariableNode type: Optional[GraphQLInputType] default_value: Any class VariableUsageVisitor(Visitor): """Visitor adding all variable usages to a given list.""" usages: List[VariableUsage] def __init__(self, type_info: TypeInfo): super().__init__() self.usages = [] self._append_usage = self.usages.append self._type_info = type_info def enter_variable_definition(self, *_args: Any) -> VisitorAction: return self.SKIP def enter_variable(self, node: VariableNode, *_args: Any) -> VisitorAction: type_info = self._type_info usage = VariableUsage( node, type_info.get_input_type(), type_info.get_default_value() ) self._append_usage(usage) return None class ASTValidationContext: """Utility class providing a context for validation of an AST. An instance of this class is passed as the context attribute to all Validators, allowing access to commonly useful contextual information from within a validation rule. """ document: DocumentNode _fragments: Optional[Dict[str, FragmentDefinitionNode]] _fragment_spreads: Dict[SelectionSetNode, List[FragmentSpreadNode]] _recursively_referenced_fragments: Dict[ OperationDefinitionNode, List[FragmentDefinitionNode] ] def __init__( self, ast: DocumentNode, on_error: Callable[[GraphQLError], None] ) -> None: self.document = ast self.on_error = on_error # type: ignore self._fragments = None self._fragment_spreads = {} self._recursively_referenced_fragments = {} def on_error(self, error: GraphQLError) -> None: pass def report_error(self, error: GraphQLError) -> None: self.on_error(error) def get_fragment(self, name: str) -> Optional[FragmentDefinitionNode]: fragments = self._fragments if fragments is None: fragments = { statement.name.value: statement for statement in self.document.definitions if isinstance(statement, FragmentDefinitionNode) } self._fragments = fragments return fragments.get(name) def get_fragment_spreads(self, node: SelectionSetNode) -> List[FragmentSpreadNode]: spreads = self._fragment_spreads.get(node) if spreads is None: spreads = [] append_spread = spreads.append sets_to_visit = [node] append_set = sets_to_visit.append pop_set = sets_to_visit.pop while sets_to_visit: visited_set = pop_set() for selection in visited_set.selections: if isinstance(selection, FragmentSpreadNode): append_spread(selection) else: set_to_visit = cast( NodeWithSelectionSet, selection ).selection_set if set_to_visit: append_set(set_to_visit) self._fragment_spreads[node] = spreads return spreads def get_recursively_referenced_fragments( self, operation: OperationDefinitionNode ) -> List[FragmentDefinitionNode]: fragments = self._recursively_referenced_fragments.get(operation) if fragments is None: fragments = [] append_fragment = fragments.append collected_names: Set[str] = set() add_name = collected_names.add nodes_to_visit = [operation.selection_set] append_node = nodes_to_visit.append pop_node = nodes_to_visit.pop get_fragment = self.get_fragment get_fragment_spreads = self.get_fragment_spreads while nodes_to_visit: visited_node = pop_node() for spread in get_fragment_spreads(visited_node): frag_name = spread.name.value if frag_name not in collected_names: add_name(frag_name) fragment = get_fragment(frag_name) if fragment: append_fragment(fragment) append_node(fragment.selection_set) self._recursively_referenced_fragments[operation] = fragments return fragments class SDLValidationContext(ASTValidationContext): """Utility class providing a context for validation of an SDL AST. An instance of this class is passed as the context attribute to all Validators, allowing access to commonly useful contextual information from within a validation rule. """ schema: Optional[GraphQLSchema] def __init__( self, ast: DocumentNode, schema: Optional[GraphQLSchema], on_error: Callable[[GraphQLError], None], ) -> None: super().__init__(ast, on_error) self.schema = schema class ValidationContext(ASTValidationContext): """Utility class providing a context for validation using a GraphQL schema. An instance of this class is passed as the context attribute to all Validators, allowing access to commonly useful contextual information from within a validation rule. """ schema: GraphQLSchema _type_info: TypeInfo _variable_usages: Dict[NodeWithSelectionSet, List[VariableUsage]] _recursive_variable_usages: Dict[OperationDefinitionNode, List[VariableUsage]] def __init__( self, schema: GraphQLSchema, ast: DocumentNode, type_info: TypeInfo, on_error: Callable[[GraphQLError], None], ) -> None: super().__init__(ast, on_error) self.schema = schema self._type_info = type_info self._variable_usages = {} self._recursive_variable_usages = {} def get_variable_usages(self, node: NodeWithSelectionSet) -> List[VariableUsage]: usages = self._variable_usages.get(node) if usages is None: usage_visitor = VariableUsageVisitor(self._type_info) visit(node, TypeInfoVisitor(self._type_info, usage_visitor)) usages = usage_visitor.usages self._variable_usages[node] = usages return usages def get_recursive_variable_usages( self, operation: OperationDefinitionNode ) -> List[VariableUsage]: usages = self._recursive_variable_usages.get(operation) if usages is None: get_variable_usages = self.get_variable_usages usages = get_variable_usages(operation) for fragment in self.get_recursively_referenced_fragments(operation): usages.extend(get_variable_usages(fragment)) self._recursive_variable_usages[operation] = usages return usages def get_type(self) -> Optional[GraphQLOutputType]: return self._type_info.get_type() def get_parent_type(self) -> Optional[GraphQLCompositeType]: return self._type_info.get_parent_type() def get_input_type(self) -> Optional[GraphQLInputType]: return self._type_info.get_input_type() def get_parent_input_type(self) -> Optional[GraphQLInputType]: return self._type_info.get_parent_input_type() def get_field_def(self) -> Optional[GraphQLField]: return self._type_info.get_field_def() def get_directive(self) -> Optional[GraphQLDirective]: return self._type_info.get_directive() def get_argument(self) -> Optional[GraphQLArgument]: return self._type_info.get_argument() def get_enum_value(self) -> Optional[GraphQLEnumValue]: return self._type_info.get_enum_value() graphql-core-3.2.6/src/graphql/version.py000066400000000000000000000024221474546154300204070ustar00rootroot00000000000000import re from typing import NamedTuple __all__ = ["version", "version_info", "version_js", "version_info_js"] version = "3.2.6" version_js = "16.8.2" _re_version = re.compile(r"(\d+)\.(\d+)\.(\d+)(\D*)(\d*)") class VersionInfo(NamedTuple): major: int minor: int micro: int releaselevel: str serial: int @classmethod def from_str(cls, v: str) -> "VersionInfo": groups = _re_version.match(v).groups() # type: ignore major, minor, micro = map(int, groups[:3]) level = (groups[3] or "")[:1] if level == "a": level = "alpha" elif level == "b": level = "beta" elif level in ("c", "r"): level = "candidate" else: level = "final" serial = groups[4] serial = int(serial) if serial else 0 return cls(major, minor, micro, level, serial) def __str__(self) -> str: v = f"{self.major}.{self.minor}.{self.micro}" level = self.releaselevel if level and level != "final": level = level[:1] if level == "c": level = "rc" v = f"{v}{level}{self.serial}" return v version_info = VersionInfo.from_str(version) version_info_js = VersionInfo.from_str(version_js) graphql-core-3.2.6/tests/000077500000000000000000000000001474546154300152655ustar00rootroot00000000000000graphql-core-3.2.6/tests/__init__.py000066400000000000000000000000301474546154300173670ustar00rootroot00000000000000"""Tests for graphql""" graphql-core-3.2.6/tests/benchmarks/000077500000000000000000000000001474546154300174025ustar00rootroot00000000000000graphql-core-3.2.6/tests/benchmarks/__init__.py000066400000000000000000000004611474546154300215140ustar00rootroot00000000000000"""Benchmarks for graphql Benchmarks are disabled (only executed as tests) by default in setup.cfg. You can enable them with --benchmark-enable if your want to execute them. E.g. in order to execute all the benchmarks with tox using Python 3.9:: tox -e py39 -- -k benchmarks --benchmark-enable """ graphql-core-3.2.6/tests/benchmarks/test_build_ast_schema.py000066400000000000000000000005701474546154300243030ustar00rootroot00000000000000from graphql import parse, build_ast_schema, GraphQLSchema from ..fixtures import big_schema_sdl # noqa: F401 def test_build_schema_from_ast(benchmark, big_schema_sdl): # noqa: F811 schema_ast = parse(big_schema_sdl) schema: GraphQLSchema = benchmark( lambda: build_ast_schema(schema_ast, assume_valid=True) ) assert schema.query_type is not None graphql-core-3.2.6/tests/benchmarks/test_build_client_schema.py000066400000000000000000000006651474546154300247770ustar00rootroot00000000000000from graphql import build_client_schema, GraphQLSchema from ..fixtures import big_schema_introspection_result # noqa: F401 def test_build_schema_from_introspection( benchmark, big_schema_introspection_result # noqa: F811 ): schema: GraphQLSchema = benchmark( lambda: build_client_schema( big_schema_introspection_result["data"], assume_valid=True ) ) assert schema.query_type is not None graphql-core-3.2.6/tests/benchmarks/test_execution_async.py000066400000000000000000000022451474546154300242160ustar00rootroot00000000000000import asyncio from graphql import ( GraphQLSchema, GraphQLObjectType, GraphQLField, GraphQLString, graphql, ) user = GraphQLObjectType( name="User", fields={ "id": GraphQLField(GraphQLString), "name": GraphQLField(GraphQLString), }, ) async def resolve_user(obj, info): return { "id": "1", "name": "Sarah", } schema = GraphQLSchema( query=GraphQLObjectType( name="Query", fields={ "user": GraphQLField( user, resolve=resolve_user, ) }, ) ) def test_execute_basic_async(benchmark): # Note: we are creating the async loop outside of the benchmark code so that # the setup is not included in the benchmark timings loop = asyncio.events.new_event_loop() asyncio.events.set_event_loop(loop) result = benchmark( lambda: loop.run_until_complete(graphql(schema, "query { user { id, name }}")) ) asyncio.events.set_event_loop(None) loop.close() assert not result.errors assert result.data == { "user": { "id": "1", "name": "Sarah", }, } graphql-core-3.2.6/tests/benchmarks/test_execution_sync.py000066400000000000000000000015341474546154300240550ustar00rootroot00000000000000from graphql import ( GraphQLSchema, GraphQLObjectType, GraphQLField, GraphQLString, graphql_sync, ) user = GraphQLObjectType( name="User", fields={ "id": GraphQLField(GraphQLString), "name": GraphQLField(GraphQLString), }, ) def resolve_user(obj, info): return { "id": "1", "name": "Sarah", } schema = GraphQLSchema( query=GraphQLObjectType( name="Query", fields={ "user": GraphQLField( user, resolve=resolve_user, ) }, ) ) def test_execute_basic_sync(benchmark): result = benchmark(lambda: graphql_sync(schema, "query { user { id, name }}")) assert not result.errors assert result.data == { "user": { "id": "1", "name": "Sarah", }, } graphql-core-3.2.6/tests/benchmarks/test_introspection_from_schema.py000066400000000000000000000007171474546154300262630ustar00rootroot00000000000000from graphql import build_schema, parse, execute_sync from graphql.utilities import get_introspection_query from ..fixtures import big_schema_sdl # noqa: F401 def test_execute_introspection_query(benchmark, big_schema_sdl): # noqa: F811 schema = build_schema(big_schema_sdl, assume_valid=True) document = parse(get_introspection_query()) result = benchmark(lambda: execute_sync(schema=schema, document=document)) assert result.errors is None graphql-core-3.2.6/tests/benchmarks/test_parser.py000066400000000000000000000004211474546154300223040ustar00rootroot00000000000000from graphql import parse, DocumentNode from ..fixtures import kitchen_sink_query # noqa: F401 def test_parse_kitchen_sink(benchmark, kitchen_sink_query): # noqa: F811 query = benchmark(lambda: parse(kitchen_sink_query)) assert isinstance(query, DocumentNode) graphql-core-3.2.6/tests/benchmarks/test_repeated_fields.py000066400000000000000000000010511474546154300241270ustar00rootroot00000000000000from graphql import ( GraphQLField, GraphQLObjectType, GraphQLSchema, GraphQLString, graphql_sync, ) schema = GraphQLSchema( query=GraphQLObjectType( name="Query", fields={ "hello": GraphQLField( GraphQLString, resolve=lambda _obj, _info: "world", ) }, ) ) source = f"{{ {'hello ' * 250}}}" def test_many_repeated_fields(benchmark): result = benchmark(lambda: graphql_sync(schema, source)) assert result == ({"hello": "world"}, None) graphql-core-3.2.6/tests/benchmarks/test_validate_gql.py000066400000000000000000000006511474546154300234510ustar00rootroot00000000000000from graphql import build_schema, parse, validate from graphql.utilities import get_introspection_query from ..fixtures import big_schema_sdl # noqa: F401 def test_validate_introspection_query(benchmark, big_schema_sdl): # noqa: F811 schema = build_schema(big_schema_sdl, assume_valid=True) query = parse(get_introspection_query()) result = benchmark(lambda: validate(schema, query)) assert result == [] graphql-core-3.2.6/tests/benchmarks/test_validate_invalid_gql.py000066400000000000000000000021061474546154300251540ustar00rootroot00000000000000from graphql import build_schema, parse, validate from ..fixtures import big_schema_sdl # noqa: F401 def test_validate_invalid_query(benchmark, big_schema_sdl): # noqa: F811 schema = build_schema(big_schema_sdl, assume_valid=True) query_ast = parse( """ { unknownField ... on unknownType { anotherUnknownField ...unknownFragment } } fragment TestFragment on anotherUnknownType { yetAnotherUnknownField } """ ) result = benchmark(lambda: validate(schema, query_ast)) assert result == [ { "message": "Cannot query field 'unknownField' on type 'Query'.", "locations": [(3, 11)], }, {"message": "Unknown type 'unknownType'.", "locations": [(4, 18)]}, {"message": "Unknown fragment 'unknownFragment'.", "locations": [(6, 16)]}, {"message": "Unknown type 'anotherUnknownType'.", "locations": [(10, 34)]}, {"message": "Fragment 'TestFragment' is never used.", "locations": [(10, 9)]}, ] graphql-core-3.2.6/tests/benchmarks/test_validate_sdl.py000066400000000000000000000005011474546154300234420ustar00rootroot00000000000000from graphql import parse from graphql.validation.validate import validate_sdl from ..fixtures import big_schema_sdl # noqa: F401 def test_validate_sdl_document(benchmark, big_schema_sdl): # noqa: F811 sdl_ast = parse(big_schema_sdl) result = benchmark(lambda: validate_sdl(sdl_ast)) assert result == [] graphql-core-3.2.6/tests/benchmarks/test_visit.py000066400000000000000000000013501474546154300221500ustar00rootroot00000000000000from graphql import parse from graphql.language import visit, Visitor, ParallelVisitor from ..fixtures import big_schema_sdl # noqa: F401 class DummyVisitor(Visitor): @staticmethod def enter(*args): pass @staticmethod def leave(*args): pass def test_visit_all_ast_nodes(benchmark, big_schema_sdl): # noqa: F811 document_ast = parse(big_schema_sdl) visitor = DummyVisitor() benchmark(lambda: visit(document_ast, visitor)) def test_visit_all_ast_nodes_in_parallel(benchmark, big_schema_sdl): # noqa: F811 document_ast = parse(big_schema_sdl) visitor = DummyVisitor() parallel_visitor = ParallelVisitor([visitor] * 50) benchmark(lambda: visit(document_ast, parallel_visitor)) graphql-core-3.2.6/tests/conftest.py000066400000000000000000000011561474546154300174670ustar00rootroot00000000000000# pytest configuration import pytest def pytest_addoption(parser): parser.addoption( "--run-slow", action="store_true", default=False, help="run slow tests" ) def pytest_configure(config): config.addinivalue_line("markers", "slow: mark test as slow to run") def pytest_collection_modifyitems(config, items): if not config.getoption("--run-slow"): # without --run-slow option: skip all slow tests skip_slow = pytest.mark.skip(reason="need --run-slow option to run") for item in items: if "slow" in item.keywords: item.add_marker(skip_slow) graphql-core-3.2.6/tests/error/000077500000000000000000000000001474546154300164165ustar00rootroot00000000000000graphql-core-3.2.6/tests/error/__init__.py000066400000000000000000000000361474546154300205260ustar00rootroot00000000000000"""Tests for graphql.error""" graphql-core-3.2.6/tests/error/test_graphql_error.py000066400000000000000000000337011474546154300227020ustar00rootroot00000000000000from typing import cast, List, Union from pytest import raises from graphql.error import GraphQLError from graphql.language import ( parse, Node, OperationDefinitionNode, ObjectTypeDefinitionNode, Source, ) from ..utils import dedent source = Source( dedent( """ { field } """ ) ) ast = parse(source) operation_node = ast.definitions[0] operation_node = cast(OperationDefinitionNode, operation_node) assert operation_node and operation_node.kind == "operation_definition" field_node = operation_node.selection_set.selections[0] assert field_node def describe_graphql_error(): def is_a_class_and_is_a_subclass_of_exception(): assert type(GraphQLError) is type assert issubclass(GraphQLError, Exception) assert isinstance(GraphQLError("str"), Exception) assert isinstance(GraphQLError("str"), GraphQLError) def has_a_name_message_extensions_and_stack_trace(): e = GraphQLError("msg") assert e.__class__.__name__ == "GraphQLError" assert e.message == "msg" assert e.extensions == {} assert e.__traceback__ is None assert str(e) == "msg" def can_pass_positional_and_keyword_arguments(): e1 = GraphQLError( "msg", [field_node], source, [1, 2, 3], ["a", "b", "c"], Exception("test"), {"foo": "bar"}, ) e2 = GraphQLError( message="msg", nodes=[field_node], source=source, positions=[1, 2, 3], path=["a", "b", "c"], original_error=Exception("test"), extensions={"foo": "bar"}, ) assert e1 == e2 def formatted_dict_has_only_keys_prescribed_in_the_spec(): e = GraphQLError( "msg", [field_node], source, [1, 2, 3], ["a", "b", "c"], Exception("test"), {"foo": "bar"}, ) assert set(e.formatted) == {"message", "path", "locations", "extensions"} def uses_the_stack_of_an_original_error(): try: raise RuntimeError("original") except RuntimeError as runtime_error: original = runtime_error e = GraphQLError("msg", original_error=original) assert e.__class__.__name__ == "GraphQLError" assert e.__traceback__ is original.__traceback__ assert e.message == "msg" assert e.original_error is original assert str(e.original_error) == "original" def passes_the_context_of_an_original_error(): context = ValueError("cause") try: raise context except ValueError: try: raise RuntimeError("effect") except RuntimeError as runtime_error: original = runtime_error e = GraphQLError("msg", original_error=original) assert e.__context__ is context def passes_the_cause_of_an_original_error(): cause = ValueError("cause") try: raise RuntimeError("effect") from cause except RuntimeError as runtime_error: original = runtime_error e = GraphQLError("msg", original_error=original) assert e.__cause__ is cause def creates_new_stack_if_original_error_has_no_stack(): try: raise RuntimeError except RuntimeError as original_with_traceback: original_traceback = original_with_traceback.__traceback__ original = RuntimeError("original") e = GraphQLError("msg", original_error=original) assert e.__class__.__name__ == "GraphQLError" assert original.__traceback__ is None assert original_traceback is not None assert e.__traceback__ is original_traceback assert e.message == "msg" assert e.original_error is original assert str(e.original_error) == "original" def converts_nodes_to_positions_and_locations(): e = GraphQLError("msg", [field_node]) assert e.nodes == [field_node] assert e.source is source assert e.positions == [4] assert e.locations == [(2, 3)] def converts_single_node_to_positions_and_locations(): e = GraphQLError("msg", field_node) # Non-array value. assert e.nodes == [field_node] assert e.source is source assert e.positions == [4] assert e.locations == [(2, 3)] def converts_node_with_loc_start_zero_to_positions_and_locations(): e = GraphQLError("msg", operation_node) assert e.nodes == [operation_node] assert e.source is source assert e.positions == [0] assert e.locations == [(1, 1)] def converts_node_without_location_to_source_positions_and_locations_as_none(): document_node = parse("{ foo }", no_location=True) e = GraphQLError("msg", document_node) assert e.nodes == [document_node] assert e.source is None assert e.positions is None assert e.locations is None def converts_source_and_positions_to_locations(): e = GraphQLError("msg", None, source, [6]) assert e.nodes is None assert e.source is source assert e.positions == [6] assert e.locations == [(2, 5)] def defaults_to_original_error_extension_only_if_arg_is_not_passed(): original_extensions = {"original": "extensions"} original_error = GraphQLError("original", extensions=original_extensions) inherited_error = GraphQLError("InheritedError", original_error=original_error) assert inherited_error.message == "InheritedError" assert inherited_error.original_error is original_error assert inherited_error.extensions is original_extensions own_extensions = {"own": "extensions"} own_error = GraphQLError( "OwnError", original_error=original_error, extensions=own_extensions ) assert own_error.message == "OwnError" assert own_error.original_error is original_error assert own_error.extensions is own_extensions own_empty_error = GraphQLError( "OwnEmptyError", original_error=original_error, extensions={} ) assert own_empty_error.message == "OwnEmptyError" assert own_empty_error.original_error is original_error assert own_empty_error.extensions == {} def serializes_to_include_message(): e = GraphQLError("msg") assert str(e) == "msg" assert repr(e) == "GraphQLError('msg')" def serializes_to_include_message_and_locations(): e = GraphQLError("msg", field_node) assert "msg" in str(e) assert ":2:3" in str(e) assert repr(e) == ( "GraphQLError('msg', locations=[SourceLocation(line=2, column=3)])" ) assert e.formatted == { "locations": [{"column": 3, "line": 2}], "message": "msg", } def serializes_to_include_path(): path: List[Union[int, str]] = ["path", 3, "to", "field"] e = GraphQLError("msg", path=path) assert e.path is path assert repr(e) == "GraphQLError('msg', path=['path', 3, 'to', 'field'])" assert e.formatted == { "message": "msg", "path": ["path", 3, "to", "field"], } def serializes_to_include_all_standard_fields(): e_short = GraphQLError("msg") assert str(e_short) == "msg" assert repr(e_short) == "GraphQLError('msg')" path: List[Union[str, int]] = ["path", 2, "field"] extensions = {"foo": "bar "} e_full = GraphQLError("msg", field_node, None, None, path, None, extensions) assert str(e_full) == ( "msg\n\nGraphQL request:2:3\n" "1 | {\n2 | field\n | ^\n3 | }" ) assert repr(e_full) == ( "GraphQLError('msg', locations=[SourceLocation(line=2, column=3)]," " path=['path', 2, 'field'], extensions={'foo': 'bar '})" ) assert e_full.formatted == { "message": "msg", "locations": [{"line": 2, "column": 3}], "path": ["path", 2, "field"], "extensions": {"foo": "bar "}, } def repr_includes_extensions(): e = GraphQLError("msg", extensions={"foo": "bar"}) assert repr(e) == "GraphQLError('msg', extensions={'foo': 'bar'})" def always_stores_path_as_list(): path: List[Union[int, str]] = ["path", 3, "to", "field"] e = GraphQLError("msg,", path=tuple(path)) assert isinstance(e.path, list) assert e.path == path def is_comparable(): e1 = GraphQLError("msg,", path=["field", 1]) assert e1 == e1 assert e1 == e1.formatted assert not e1 != e1 assert not e1 != e1.formatted e2 = GraphQLError("msg,", path=["field", 1]) assert e1 == e2 assert not e1 != e2 assert e2.path and e2.path[1] == 1 e2.path[1] = 2 assert not e1 == e2 assert e1 != e2 assert not e1 == e2.formatted assert e1 != e2.formatted def is_hashable(): hash(GraphQLError("msg")) def hashes_are_unique_per_instance(): e1 = GraphQLError("msg") e2 = GraphQLError("msg") assert hash(e1) != hash(e2) def describe_to_string(): def deprecated_prints_an_error_using_print_error(): # noinspection PyProtectedMember from graphql.error.graphql_error import print_error error = GraphQLError("Error") assert print_error(error) == "Error" with raises(TypeError) as exc_info: # noinspection PyTypeChecker print_error(Exception) # type: ignore assert str(exc_info.value) == "Expected a GraphQLError." def prints_an_error_without_location(): error = GraphQLError("Error without location") assert str(error) == "Error without location" def prints_an_error_using_node_without_location(): error = GraphQLError( "Error attached to node without location", parse("{ foo }", no_location=True), ) assert str(error) == "Error attached to node without location" def prints_an_error_with_nodes_from_different_sources(): doc_a = parse( Source( dedent( """ type Foo { field: String } """ ), "SourceA", ) ) op_a = doc_a.definitions[0] op_a = cast(ObjectTypeDefinitionNode, op_a) assert op_a and op_a.kind == "object_type_definition" and op_a.fields field_a = op_a.fields[0] doc_b = parse( Source( dedent( """ type Foo { field: Int } """ ), "SourceB", ) ) op_b = doc_b.definitions[0] op_b = cast(ObjectTypeDefinitionNode, op_b) assert op_b and op_b.kind == "object_type_definition" and op_b.fields field_b = op_b.fields[0] error = GraphQLError( "Example error with two nodes", [field_a.type, field_b.type] ) assert str(error) == dedent( """ Example error with two nodes SourceA:2:10 1 | type Foo { 2 | field: String | ^ 3 | } SourceB:2:10 1 | type Foo { 2 | field: Int | ^ 3 | } """ ) def describe_formatted(): def deprecated_formats_an_error_using_format_error(): # noinspection PyProtectedMember from graphql.error.graphql_error import format_error error = GraphQLError("Example Error") assert format_error(error) == { "message": "Example Error", } with raises(TypeError) as exc_info: # noinspection PyTypeChecker format_error(Exception) # type: ignore assert str(exc_info.value) == "Expected a GraphQLError." def formats_graphql_error(): path: List[Union[int, str]] = ["one", 2] extensions = {"ext": None} error = GraphQLError( "test message", Node(), Source( """ query { something } """ ), [16, 41], ["one", 2], ValueError("original"), extensions=extensions, ) assert error.formatted == { "message": "test message", "locations": [{"line": 2, "column": 16}, {"line": 3, "column": 17}], "path": path, "extensions": extensions, } def uses_default_message(): # noinspection PyTypeChecker formatted = GraphQLError(None).formatted # type: ignore assert formatted == { "message": "An unknown error occurred.", } def includes_path(): path: List[Union[int, str]] = ["path", 3, "to", "field"] error = GraphQLError("msg", path=path) assert error.formatted == {"message": "msg", "path": path} def includes_extension_fields(): error = GraphQLError("msg", extensions={"foo": "bar"}) assert error.formatted == { "message": "msg", "extensions": {"foo": "bar"}, } def can_be_created_from_dict(): args = dict( nodes=[operation_node], source=source, positions=[6], path=["path", 2, "a"], original_error=Exception("I like turtles"), extensions=dict(hee="I like turtles"), ) error = GraphQLError("msg", **args) # type: ignore assert error.formatted == { "message": "msg", "locations": [{"column": 5, "line": 2}], "path": ["path", 2, "a"], "extensions": {"hee": "I like turtles"}, } graphql-core-3.2.6/tests/error/test_located_error.py000066400000000000000000000023251474546154300226550ustar00rootroot00000000000000from typing import cast, Any from graphql.error import GraphQLError, located_error def describe_located_error(): def throws_without_an_original_error(): e = located_error([], [], []).original_error # type: ignore assert isinstance(e, TypeError) assert str(e) == "Unexpected error value: []" def passes_graphql_error_through(): path = ["path", 3, "to", "field"] e = GraphQLError("msg", None, None, None, cast(Any, path)) assert located_error(e, [], []) == e def passes_graphql_error_ish_through(): e = GraphQLError("I am a located GraphQL error") e.path = [] assert located_error(e, [], []) is e def does_not_pass_through_elasticsearch_like_errors(): e = Exception("I am from elasticsearch") cast(Any, e).path = "/something/feed/_search" assert located_error(e, [], []) is not e def handles_lazy_error_messages(): class LazyString: def __str__(self) -> str: return "lazy" class LazyError(Exception): def __init__(self): self.message = LazyString() super().__init__() assert str(located_error(LazyError())) == "lazy" graphql-core-3.2.6/tests/error/test_print_location.py000066400000000000000000000054151474546154300230600ustar00rootroot00000000000000from graphql.language import print_source_location, Source, SourceLocation from ..utils import dedent def describe_print_location(): def prints_minified_documents(): minified_source = Source( "query SomeMinifiedQueryWithErrorInside(" "$foo:String!=FIRST_ERROR_HERE$bar:String)" "{someField(foo:$foo bar:$bar baz:SECOND_ERROR_HERE)" "{fieldA fieldB{fieldC fieldD...on THIRD_ERROR_HERE}}}" ) first_location = print_source_location( minified_source, SourceLocation(1, minified_source.body.index("FIRST_ERROR_HERE") + 1), ) assert first_location == dedent( """ GraphQL request:1:53 1 | query SomeMinifiedQueryWithErrorInside($foo:String!=FIRST_ERROR_HERE$bar:String) | ^ | {someField(foo:$foo bar:$bar baz:SECOND_ERROR_HERE){fieldA fieldB{fieldC fieldD. """ # noqa: E501 ) second_location = print_source_location( minified_source, SourceLocation(1, minified_source.body.index("SECOND_ERROR_HERE") + 1), ) assert second_location == dedent( """ GraphQL request:1:114 1 | query SomeMinifiedQueryWithErrorInside($foo:String!=FIRST_ERROR_HERE$bar:String) | {someField(foo:$foo bar:$bar baz:SECOND_ERROR_HERE){fieldA fieldB{fieldC fieldD. | ^ | ..on THIRD_ERROR_HERE}}} """ # noqa: E501 ) third_location = print_source_location( minified_source, SourceLocation(1, minified_source.body.index("THIRD_ERROR_HERE") + 1), ) assert third_location == dedent( """ GraphQL request:1:166 1 | query SomeMinifiedQueryWithErrorInside($foo:String!=FIRST_ERROR_HERE$bar:String) | {someField(foo:$foo bar:$bar baz:SECOND_ERROR_HERE){fieldA fieldB{fieldC fieldD. | ..on THIRD_ERROR_HERE}}} | ^ """ # noqa: E501 ) def prints_single_digit_line_number_with_no_padding(): result = print_source_location( Source("*", "Test", SourceLocation(9, 1)), SourceLocation(1, 1) ) assert result == dedent( """ Test:9:1 9 | * | ^ """ ) def prints_line_numbers_with_correct_padding(): result = print_source_location( Source("*\n", "Test", SourceLocation(9, 1)), SourceLocation(1, 1) ) assert result == dedent( """ Test:9:1 9 | * | ^ 10 | """ ) graphql-core-3.2.6/tests/execution/000077500000000000000000000000001474546154300172705ustar00rootroot00000000000000graphql-core-3.2.6/tests/execution/__init__.py000066400000000000000000000000421474546154300213750ustar00rootroot00000000000000"""Tests for graphql.execution""" graphql-core-3.2.6/tests/execution/test_abstract.py000066400000000000000000000420101474546154300225010ustar00rootroot00000000000000from inspect import isawaitable from typing import Any, NamedTuple, Optional from pytest import mark from graphql.execution import ExecutionResult, execute, execute_sync from graphql.language import parse from graphql.type import ( GraphQLBoolean, GraphQLField, GraphQLInterfaceType, GraphQLList, GraphQLObjectType, GraphQLSchema, GraphQLString, GraphQLUnionType, ) from graphql.utilities import build_schema def sync_and_async(spec): """Decorator for running a test synchronously and asynchronously.""" return mark.asyncio( mark.parametrize("sync", (True, False), ids=("sync", "async"))(spec) ) def access_variants(spec): """Decorator for tests with dict and object access, including inheritance.""" return mark.asyncio( mark.parametrize("access", ("dict", "object", "inheritance"))(spec) ) async def execute_query( sync: bool, schema: GraphQLSchema, query: str, root_value: Any = None ) -> ExecutionResult: """Execute the query against the given schema synchronously or asynchronously.""" assert isinstance(sync, bool) assert isinstance(schema, GraphQLSchema) assert isinstance(query, str) document = parse(query) result = (execute_sync if sync else execute)(schema, document, root_value) if not sync and isawaitable(result): result = await result assert isinstance(result, ExecutionResult) return result def get_is_type_of(type_, sync=True): """Get a sync or async is_type_of function for the given type.""" if sync: def is_type_of(obj, _info): return isinstance(obj, type_) else: async def is_type_of(obj, _info): return isinstance(obj, type_) return is_type_of def get_type_error(sync=True): """Get a sync or async is_type_of or type resolver function that raises an error.""" error = RuntimeError("We are testing this error") if sync: def type_error(*_args): raise error else: async def type_error(*_args): raise error return type_error class Dog(NamedTuple): name: str woofs: bool class Cat(NamedTuple): name: str meows: bool def describe_execute_handles_synchronous_execution_of_abstract_types(): @sync_and_async async def is_type_of_used_to_resolve_runtime_type_for_interface(sync): pet_type = GraphQLInterfaceType("Pet", {"name": GraphQLField(GraphQLString)}) dog_type = GraphQLObjectType( "Dog", { "name": GraphQLField(GraphQLString), "woofs": GraphQLField(GraphQLBoolean), }, interfaces=[pet_type], is_type_of=get_is_type_of(Dog, sync), ) cat_type = GraphQLObjectType( "Cat", { "name": GraphQLField(GraphQLString), "meows": GraphQLField(GraphQLBoolean), }, interfaces=[pet_type], is_type_of=get_is_type_of(Cat, sync), ) schema = GraphQLSchema( GraphQLObjectType( "Query", { "pets": GraphQLField( GraphQLList(pet_type), resolve=lambda *_args: [ Dog("Odie", True), Cat("Garfield", False), ], ) }, ), types=[cat_type, dog_type], ) query = """ { pets { name ... on Dog { woofs } ... on Cat { meows } } } """ assert await execute_query(sync, schema, query) == ( { "pets": [ {"name": "Odie", "woofs": True}, {"name": "Garfield", "meows": False}, ] }, None, ) @sync_and_async async def is_type_of_can_throw(sync): pet_type = GraphQLInterfaceType("Pet", {"name": GraphQLField(GraphQLString)}) dog_type = GraphQLObjectType( "Dog", { "name": GraphQLField(GraphQLString), "woofs": GraphQLField(GraphQLBoolean), }, interfaces=[pet_type], is_type_of=get_type_error(sync), ) cat_type = GraphQLObjectType( "Cat", { "name": GraphQLField(GraphQLString), "meows": GraphQLField(GraphQLBoolean), }, interfaces=[pet_type], is_type_of=None, ) schema = GraphQLSchema( GraphQLObjectType( "Query", { "pets": GraphQLField( GraphQLList(pet_type), resolve=lambda *_args: [ Dog("Odie", True), Cat("Garfield", False), ], ) }, ), types=[dog_type, cat_type], ) query = """ { pets { name ... on Dog { woofs } ... on Cat { meows } } } """ assert await execute_query(sync, schema, query) == ( {"pets": [None, None]}, [ { "message": "We are testing this error", "locations": [(3, 15)], "path": ["pets", 0], }, { "message": "We are testing this error", "locations": [(3, 15)], "path": ["pets", 1], }, ], ) @sync_and_async async def is_type_of_with_no_suitable_type(sync): # added in GraphQL-core to improve coverage pet_type = GraphQLInterfaceType("Pet", {"name": GraphQLField(GraphQLString)}) dog_type = GraphQLObjectType( "Dog", { "name": GraphQLField(GraphQLString), "woofs": GraphQLField(GraphQLBoolean), }, interfaces=[pet_type], is_type_of=get_is_type_of(Cat, sync), ) schema = GraphQLSchema( GraphQLObjectType( "Query", { "pets": GraphQLField( GraphQLList(pet_type), resolve=lambda *_args: [Dog("Odie", True)], ) }, ), types=[dog_type], ) query = """ { pets { name ... on Dog { woofs } } } """ message = ( "Abstract type 'Pet' must resolve to an Object type at runtime" " for field 'Query.pets'." " Either the 'Pet' type should provide a 'resolve_type' function" " or each possible type should provide an 'is_type_of' function." ) assert await execute_query(sync, schema, query) == ( {"pets": [None]}, [{"message": message, "locations": [(3, 15)], "path": ["pets", 0]}], ) @sync_and_async async def is_type_of_used_to_resolve_runtime_type_for_union(sync): dog_type = GraphQLObjectType( "Dog", { "name": GraphQLField(GraphQLString), "woofs": GraphQLField(GraphQLBoolean), }, is_type_of=get_is_type_of(Dog, sync), ) cat_type = GraphQLObjectType( "Cat", { "name": GraphQLField(GraphQLString), "meows": GraphQLField(GraphQLBoolean), }, is_type_of=get_is_type_of(Cat, sync), ) pet_type = GraphQLUnionType("Pet", [cat_type, dog_type]) schema = GraphQLSchema( GraphQLObjectType( "Query", { "pets": GraphQLField( GraphQLList(pet_type), resolve=lambda *_args: [ Dog("Odie", True), Cat("Garfield", False), ], ) }, ) ) query = """ { pets { ... on Dog { name woofs } ... on Cat { name meows } } } """ assert await execute_query(sync, schema, query) == ( { "pets": [ {"name": "Odie", "woofs": True}, {"name": "Garfield", "meows": False}, ] }, None, ) @sync_and_async async def resolve_type_can_throw(sync): pet_type = GraphQLInterfaceType( "Pet", {"name": GraphQLField(GraphQLString)}, resolve_type=get_type_error(sync), ) dog_type = GraphQLObjectType( "Dog", { "name": GraphQLField(GraphQLString), "woofs": GraphQLField(GraphQLBoolean), }, interfaces=[pet_type], ) cat_type = GraphQLObjectType( "Cat", { "name": GraphQLField(GraphQLString), "meows": GraphQLField(GraphQLBoolean), }, interfaces=[pet_type], ) schema = GraphQLSchema( GraphQLObjectType( "Query", { "pets": GraphQLField( GraphQLList(pet_type), resolve=lambda *_args: [ Dog("Odie", True), Cat("Garfield", False), ], ) }, ), types=[dog_type, cat_type], ) query = """ { pets { name ... on Dog { woofs } ... on Cat { meows } } } """ assert await execute_query(sync, schema, query) == ( {"pets": [None, None]}, [ { "message": "We are testing this error", "locations": [(3, 15)], "path": ["pets", 0], }, { "message": "We are testing this error", "locations": [(3, 15)], "path": ["pets", 1], }, ], ) def describe_using_typename_on_source_object(): expected = ( { "pets": [ {"name": "Odie", "woofs": True}, {"name": "Garfield", "meows": False}, ] }, None, ) # noinspection PyShadowingNames def _root_value(access: str) -> Any: if access == "dict": return { "pets": [ {"__typename": "Dog", "name": "Odie", "woofs": True}, {"__typename": "Cat", "name": "Garfield", "meows": False}, ], } if access == "object": class DogObject: __typename = "Dog" name = "Odie" woofs = True class CatObject: __typename = "Cat" name = "Garfield" meows = False class RootValueAsObject: pets = [DogObject(), CatObject()] return RootValueAsObject() if access == "inheritance": class Pet: __typename = "Pet" name: Optional[str] = None class DogPet(Pet): __typename = "Dog" woofs: Optional[bool] = None class Odie(DogPet): name = "Odie" woofs = True class CatPet(Pet): __typename = "Cat" meows: Optional[bool] = None class Tabby(CatPet): pass class Garfield(Tabby): name = "Garfield" meows = False class RootValueWithInheritance: pets = [Odie(), Garfield()] return RootValueWithInheritance() assert False, f"Unknown access variant: {access}" # pragma: no cover def describe_union_type(): schema = build_schema( """ type Query { pets: [Pet] } union Pet = Cat | Dog type Cat { name: String meows: Boolean } type Dog { name: String woofs: Boolean } """ ) query = """ { pets { name ... on Dog { woofs } ... on Cat { meows } } } """ @sync_and_async @access_variants async def resolve(sync, access): root_value = _root_value(access) assert await execute_query(sync, schema, query, root_value) == expected def describe_interface_type(): schema = build_schema( """ type Query { pets: [Pet] } interface Pet { name: String } type Cat implements Pet { name: String meows: Boolean } type Dog implements Pet { name: String woofs: Boolean } """ ) query = """ { pets { name ... on Dog { woofs } ... on Cat { meows } } } """ @sync_and_async @access_variants async def resolve(sync, access): root_value = _root_value(access) assert await execute_query(sync, schema, query, root_value) == expected def resolve_type_on_interface_yields_useful_error(): schema = build_schema( """ type Query { pet: Pet } interface Pet { name: String } type Cat implements Pet { name: String } type Dog implements Pet { name: String } """ ) document = parse( """ { pet { name } } """ ) def expect_error(for_type_name: Any, message: str) -> None: root_value = {"pet": {"__typename": for_type_name}} result = execute_sync(schema, document, root_value) expected = ( {"pet": None}, [{"message": message, "locations": [(3, 15)], "path": ["pet"]}], ) assert result == expected expect_error( None, "Abstract type 'Pet' must resolve" " to an Object type at runtime for field 'Query.pet'." " Either the 'Pet' type should provide a 'resolve_type' function" " or each possible type should provide an 'is_type_of' function.", ) expect_error( "Human", "Abstract type 'Pet' was resolved to a type 'Human'" " that does not exist inside the schema.", ) expect_error( "String", "Abstract type 'Pet' was resolved to a non-object type 'String'." ) expect_error( "__Schema", "Runtime Object type '__Schema' is not a possible type for 'Pet'.", ) # workaround since we can't inject resolve_type into SDL schema.get_type("Pet").resolve_type = lambda *_args: [] # type: ignore expect_error( None, "Abstract type 'Pet' must resolve" " to an Object type at runtime for field 'Query.pet'" " with value {'__typename': None}, received '[]'.", ) graphql-core-3.2.6/tests/execution/test_customize.py000066400000000000000000000025671474546154300227350ustar00rootroot00000000000000from graphql.execution import execute, ExecutionContext from graphql.language import parse from graphql.type import GraphQLSchema, GraphQLObjectType, GraphQLString, GraphQLField def describe_customize_execution(): def uses_a_custom_field_resolver(): query = parse("{ foo }") schema = GraphQLSchema( GraphQLObjectType("Query", {"foo": GraphQLField(GraphQLString)}) ) # For the purposes of test, just return the name of the field! def custom_resolver(_source, info, **_args): return info.field_name assert execute(schema, query, field_resolver=custom_resolver) == ( {"foo": "foo"}, None, ) def uses_a_custom_execution_context_class(): query = parse("{ foo }") schema = GraphQLSchema( GraphQLObjectType( "Query", {"foo": GraphQLField(GraphQLString, resolve=lambda *_args: "bar")}, ) ) class TestExecutionContext(ExecutionContext): def execute_field(self, parent_type, source, field_nodes, path): result = super().execute_field(parent_type, source, field_nodes, path) return result * 2 # type: ignore assert execute(schema, query, execution_context_class=TestExecutionContext) == ( {"foo": "barbar"}, None, ) graphql-core-3.2.6/tests/execution/test_directives.py000066400000000000000000000155571474546154300230570ustar00rootroot00000000000000from graphql.execution import execute_sync, ExecutionResult from graphql.language import parse from graphql.type import GraphQLObjectType, GraphQLField, GraphQLSchema, GraphQLString schema = GraphQLSchema( GraphQLObjectType( "TestType", {"a": GraphQLField(GraphQLString), "b": GraphQLField(GraphQLString)} ) ) # noinspection PyMethodMayBeStatic class RootValue: def a(self, *_args): return "a" def b(self, *_args): return "b" def execute_test_query(query: str) -> ExecutionResult: document = parse(query) return execute_sync(schema, document, RootValue()) def describe_execute_handles_directives(): def describe_works_without_directives(): def basic_query_works(): result = execute_test_query("{ a, b }") assert result == ({"a": "a", "b": "b"}, None) def describe_works_on_scalars(): def if_true_includes_scalar(): result = execute_test_query("{ a, b @include(if: true) }") assert result == ({"a": "a", "b": "b"}, None) def if_false_omits_on_scalar(): result = execute_test_query("{ a, b @include(if: false) }") assert result == ({"a": "a"}, None) def unless_false_includes_scalar(): result = execute_test_query("{ a, b @skip(if: false) }") assert result == ({"a": "a", "b": "b"}, None) def unless_true_omits_scalar(): result = execute_test_query("{ a, b @skip(if: true) }") assert result == ({"a": "a"}, None) def describe_works_on_fragment_spreads(): def if_false_omits_fragment_spread(): result = execute_test_query( """ query Q { a ...Frag @include(if: false) } fragment Frag on TestType { b } """ ) assert result == ({"a": "a"}, None) def if_true_includes_fragment_spread(): result = execute_test_query( """ query Q { a ...Frag @include(if: true) } fragment Frag on TestType { b } """ ) assert result == ({"a": "a", "b": "b"}, None) def unless_false_includes_fragment_spread(): result = execute_test_query( """ query Q { a ...Frag @skip(if: false) } fragment Frag on TestType { b } """ ) assert result == ({"a": "a", "b": "b"}, None) def unless_true_omits_fragment_spread(): result = execute_test_query( """ query Q { a ...Frag @skip(if: true) } fragment Frag on TestType { b } """ ) assert result == ({"a": "a"}, None) def describe_works_on_inline_fragment(): def if_false_omits_inline_fragment(): result = execute_test_query( """ query Q { a ... on TestType @include(if: false) { b } } """ ) assert result == ({"a": "a"}, None) def if_true_includes_inline_fragment(): result = execute_test_query( """ query Q { a ... on TestType @include(if: true) { b } } """ ) assert result == ({"a": "a", "b": "b"}, None) def unless_false_includes_inline_fragment(): result = execute_test_query( """ query Q { a ... on TestType @skip(if: false) { b } } """ ) assert result == ({"a": "a", "b": "b"}, None) def unless_true_omits_inline_fragment(): result = execute_test_query( """ query Q { a ... on TestType @skip(if: true) { b } } """ ) assert result == ({"a": "a"}, None) def describe_works_on_anonymous_inline_fragment(): def if_false_omits_anonymous_inline_fragment(): result = execute_test_query( """ query { a ... @include(if: false) { b } } """ ) assert result == ({"a": "a"}, None) def if_true_includes_anonymous_inline_fragment(): result = execute_test_query( """ query { a ... @include(if: true) { b } } """ ) assert result == ({"a": "a", "b": "b"}, None) def unless_false_includes_anonymous_inline_fragment(): result = execute_test_query( """ query { a ... @skip(if: false) { b } } """ ) assert result == ({"a": "a", "b": "b"}, None) def unless_true_omits_anonymous_inline_fragment(): result = execute_test_query( """ query { a ... @skip(if: true) { b } } """ ) assert result == ({"a": "a"}, None) def describe_works_with_skip_and_include_directives(): def include_and_no_skip(): result = execute_test_query( """ { a b @include(if: true) @skip(if: false) } """ ) assert result == ({"a": "a", "b": "b"}, None) def include_and_skip(): result = execute_test_query( """ { a b @include(if: true) @skip(if: true) } """ ) assert result == ({"a": "a"}, None) def no_include_or_skip(): result = execute_test_query( """ { a b @include(if: false) @skip(if: false) } """ ) assert result == ({"a": "a"}, None) graphql-core-3.2.6/tests/execution/test_execution_result.py000066400000000000000000000107171474546154300243100ustar00rootroot00000000000000from pytest import raises from graphql.error import GraphQLError from graphql.execution import ExecutionResult def describe_execution_result(): data = {"foo": "Some data"} error = GraphQLError("Some error") errors = [error] extensions = {"bar": "Some extension"} def initializes_properly(): res = ExecutionResult(data, errors) assert res.data is data assert res.errors is errors assert res.extensions is None res = ExecutionResult(data, errors, extensions) assert res.data is data assert res.errors is errors assert res.extensions is extensions def prints_a_representation(): assert repr(ExecutionResult(data, errors)) == ( "ExecutionResult(data={'foo': 'Some data'}," " errors=[GraphQLError('Some error')])" ) assert repr(ExecutionResult(data, errors, extensions)) == ( "ExecutionResult(data={'foo': 'Some data'}," " errors=[GraphQLError('Some error')]," " extensions={'bar': 'Some extension'})" ) def formats_properly(): res = ExecutionResult(data, None) assert res.formatted == {"data": data} res = ExecutionResult(data, errors) assert res.formatted == { "data": data, "errors": [{"message": "Some error"}], } res = ExecutionResult(data, None, extensions) assert res.formatted == { "data": data, "extensions": extensions, } res = ExecutionResult(data, errors, extensions) assert res.formatted == { "data": data, "errors": [{"message": "Some error"}], "extensions": extensions, } def compares_to_dict(): res = ExecutionResult(data, errors) assert res == {"data": data, "errors": errors} assert res == {"data": data, "errors": errors, "extensions": None} assert res != {"data": data, "errors": None} assert res != {"data": None, "errors": errors} assert res != {"data": data, "errors": errors, "extensions": extensions} res = ExecutionResult(data, errors, extensions) assert res == {"data": data, "errors": errors} assert res == {"data": data, "errors": errors, "extensions": extensions} assert res != {"data": data, "errors": None} assert res != {"data": None, "errors": errors} assert res != {"data": data, "errors": errors, "extensions": None} def compares_to_tuple(): res = ExecutionResult(data, errors) assert res == (data, errors) assert res == (data, errors, None) assert res != (data, None) assert res != (None, errors) assert res != (data, errors, extensions) res = ExecutionResult(data, errors, extensions) assert res == (data, errors) assert res == (data, errors, extensions) assert res != (data, None) assert res != (None, errors) assert res != (data, errors, None) def does_not_compare_to_list(): res = ExecutionResult(data, errors) assert res != [data, errors] res = ExecutionResult(data, errors, extensions) assert res != [data, errors, extensions] def compares_to_another_execution_result(): res1 = ExecutionResult(data, errors) res2 = ExecutionResult(data, errors) assert res1 == res2 res2 = ExecutionResult({"foo": "other data"}, errors) assert res1 != res2 res2 = ExecutionResult(data, [GraphQLError("Another error")]) assert res1 != res2 res2 = ExecutionResult(data, errors, extensions) assert res1 != res2 res1 = ExecutionResult(data, errors, extensions) res2 = ExecutionResult(data, errors, extensions) assert res1 == res2 res2 = ExecutionResult({"foo": "other data"}, errors, extensions) assert res1 != res2 res2 = ExecutionResult(data, [GraphQLError("Another error")], extensions) assert res1 != res2 res2 = ExecutionResult(data, errors, {"bar": "Another extension"}) assert res1 != res2 def unpacks_as_two_tuple(): res = ExecutionResult(data, errors) res_data, res_errors = res # type: ignore assert res_data == data # type: ignore assert res_errors == errors # type: ignore with raises(ValueError): res = ExecutionResult(data, errors, extensions) _res_data, _res_errors, _res_extensions = res # type: ignore graphql-core-3.2.6/tests/execution/test_executor.py000066400000000000000000001042041474546154300225400ustar00rootroot00000000000000import asyncio from typing import Any, Awaitable, Optional, cast from graphql.error import GraphQLError from graphql.execution import execute, execute_sync from graphql.language import FieldNode, OperationDefinitionNode, parse from graphql.pyutils import Undefined, inspect from graphql.type import ( GraphQLArgument, GraphQLBoolean, GraphQLField, GraphQLInt, GraphQLInterfaceType, GraphQLList, GraphQLNonNull, GraphQLObjectType, GraphQLResolveInfo, GraphQLScalarType, GraphQLSchema, GraphQLString, GraphQLUnionType, ResponsePath, ) from pytest import mark, raises def describe_execute_handles_basic_execution_tasks(): # noinspection PyTypeChecker def throws_if_no_document_is_provided(): schema = GraphQLSchema( GraphQLObjectType("Type", {"a": GraphQLField(GraphQLString)}) ) with raises(TypeError) as exc_info: assert execute_sync(schema=schema, document=None) # type: ignore assert str(exc_info.value) == "Must provide document." # noinspection PyTypeChecker def throws_if_no_schema_is_provided(): document = parse("{ field }") with raises(TypeError) as exc_info: assert execute_sync(schema=None, document=document) # type: ignore assert str(exc_info.value) == "Expected None to be a GraphQL schema." def throws_on_invalid_variables(): schema = GraphQLSchema( GraphQLObjectType( "Type", { "fieldA": GraphQLField( GraphQLString, args={"argA": GraphQLArgument(GraphQLInt)} ) }, ) ) document = parse( """ query ($a: Int) { fieldA(argA: $a) } """ ) variable_values = "{'a': 1}" with raises(TypeError) as exc_info: assert execute_sync( schema=schema, document=document, variable_values=variable_values, # type: ignore ) assert str(exc_info.value) == ( "Variable values must be provided as a dictionary" " with variable names as keys. Perhaps look to see" " if an unparsed JSON string was provided." ) def accepts_positional_arguments(): schema = GraphQLSchema( GraphQLObjectType( "Type", {"a": GraphQLField(GraphQLString, resolve=lambda obj, *args: obj)}, ) ) result = execute_sync(schema, parse("{ a }"), "rootValue") assert result == ({"a": "rootValue"}, None) @mark.asyncio async def executes_arbitrary_code(): # noinspection PyMethodMayBeStatic,PyMethodMayBeStatic class Data: def a(self, _info): return "Apple" def b(self, _info): return "Banana" def c(self, _info): return "Cookie" def d(self, _info): return "Donut" def e(self, _info): return "Egg" f = "Fish" # Called only by DataType::pic static resolver def pic(self, _info, size: int): return f"Pic of size: {size}" def deep(self, _info): return DeepData() def promise(self, _info): return promise_data() # noinspection PyMethodMayBeStatic,PyMethodMayBeStatic class DeepData: def a(self, _info): return "Already Been Done" def b(self, _info): return "Boring" def c(self, _info): return ["Contrived", None, "Confusing"] def deeper(self, _info): return [Data(), None, Data()] async def promise_data(): await asyncio.sleep(0) return Data() DeepDataType: GraphQLObjectType DataType = GraphQLObjectType( "DataType", lambda: { "a": GraphQLField(GraphQLString), "b": GraphQLField(GraphQLString), "c": GraphQLField(GraphQLString), "d": GraphQLField(GraphQLString), "e": GraphQLField(GraphQLString), "f": GraphQLField(GraphQLString), "pic": GraphQLField( GraphQLString, args={"size": GraphQLArgument(GraphQLInt)}, resolve=lambda obj, info, size: obj.pic(info, size), ), "deep": GraphQLField(DeepDataType), "promise": GraphQLField(DataType), }, ) DeepDataType = GraphQLObjectType( "DeepDataType", { "a": GraphQLField(GraphQLString), "b": GraphQLField(GraphQLString), "c": GraphQLField(GraphQLList(GraphQLString)), "deeper": GraphQLField(GraphQLList(DataType)), }, ) document = parse( """ query ($size: Int) { a, b, x: c ...c f ...on DataType { pic(size: $size) promise { a } } deep { a b c deeper { a b } } } fragment c on DataType { d e } """ ) awaitable_result = execute( GraphQLSchema(DataType), document, Data(), variable_values={"size": 100} ) assert isinstance(awaitable_result, Awaitable) result = await awaitable_result assert result == ( { "a": "Apple", "b": "Banana", "x": "Cookie", "d": "Donut", "e": "Egg", "f": "Fish", "pic": "Pic of size: 100", "promise": {"a": "Apple"}, "deep": { "a": "Already Been Done", "b": "Boring", "c": ["Contrived", None, "Confusing"], "deeper": [ {"a": "Apple", "b": "Banana"}, None, {"a": "Apple", "b": "Banana"}, ], }, }, None, ) def merges_parallel_fragments(): Type = GraphQLObjectType( "Type", lambda: { "a": GraphQLField(GraphQLString, resolve=lambda *_args: "Apple"), "b": GraphQLField(GraphQLString, resolve=lambda *_args: "Banana"), "c": GraphQLField(GraphQLString, resolve=lambda *_args: "Cherry"), "deep": GraphQLField(Type, resolve=lambda *_args: {}), }, ) schema = GraphQLSchema(Type) ast = parse( """ { a, ...FragOne, ...FragTwo } fragment FragOne on Type { b deep { b, deeper: deep { b } } } fragment FragTwo on Type { c deep { c, deeper: deep { c } } } """ ) result = execute_sync(schema, ast) assert result == ( { "a": "Apple", "b": "Banana", "c": "Cherry", "deep": { "b": "Banana", "c": "Cherry", "deeper": {"b": "Banana", "c": "Cherry"}, }, }, None, ) def provides_info_about_current_execution_state(): resolved_infos = [] def resolve(_obj, info): resolved_infos.append(info) test_type = GraphQLObjectType( "Test", {"test": GraphQLField(GraphQLString, resolve=resolve)} ) schema = GraphQLSchema(test_type) document = parse("query ($var: String) { result: test }") root_value = {"root": "val"} variable_values = {"var": "abc"} execute_sync(schema, document, root_value, variable_values=variable_values) assert len(resolved_infos) == 1 operation = cast(OperationDefinitionNode, document.definitions[0]) assert operation and operation.kind == "operation_definition" field = cast(FieldNode, operation.selection_set.selections[0]) assert resolved_infos[0] == GraphQLResolveInfo( field_name="test", field_nodes=[field], return_type=GraphQLString, parent_type=cast(GraphQLObjectType, schema.query_type), path=ResponsePath(None, "result", "Test"), schema=schema, fragments={}, root_value=root_value, operation=operation, variable_values=variable_values, context=None, is_awaitable=resolved_infos[0].is_awaitable, ) def it_populates_path_correctly_with_complex_types(): path: Optional[ResponsePath] = None def resolve(_val, info): nonlocal path path = info.path def resolve_type(_val, _info, _type): return "SomeObject" some_object = GraphQLObjectType( "SomeObject", {"test": GraphQLField(GraphQLString, resolve=resolve)} ) some_union = GraphQLUnionType( "SomeUnion", [some_object], resolve_type=resolve_type ) test_type = GraphQLObjectType( "SomeQuery", { "test": GraphQLField( GraphQLNonNull(GraphQLList(GraphQLNonNull(some_union))) ) }, ) schema = GraphQLSchema(test_type) root_value: Any = {"test": [{}]} document = parse( """ query { l1: test { ... on SomeObject { l2: test } } } """ ) execute_sync(schema, document, root_value) assert path is not None prev, key, typename = path assert key == "l2" assert typename == "SomeObject" prev, key, typename = prev assert key == 0 assert typename is None prev, key, typename = prev assert key == "l1" assert typename == "SomeQuery" assert prev is None def threads_root_value_context_correctly(): resolved_values = [] class Data: context_thing = "thing" def resolve(obj, _info): resolved_values.append(obj) schema = GraphQLSchema( GraphQLObjectType( "Type", {"a": GraphQLField(GraphQLString, resolve=resolve)} ) ) document = parse("query Example { a }") root_value = Data() execute_sync(schema, document, root_value) assert len(resolved_values) == 1 assert resolved_values[0] is root_value def correctly_threads_arguments(): resolved_args = [] def resolve(_obj, _info, **args): resolved_args.append(args) schema = GraphQLSchema( GraphQLObjectType( "Type", { "b": GraphQLField( GraphQLString, args={ "numArg": GraphQLArgument(GraphQLInt), "stringArg": GraphQLArgument(GraphQLString), }, resolve=resolve, ) }, ) ) document = parse( """ query Example { b(numArg: 123, stringArg: "foo") } """ ) execute_sync(schema, document) assert len(resolved_args) == 1 assert resolved_args[0] == {"numArg": 123, "stringArg": "foo"} @mark.asyncio async def nulls_out_error_subtrees(): document = parse( """ { syncOk syncError syncRawError syncReturnError syncReturnErrorList asyncOk asyncError asyncRawError asyncReturnError asyncReturnErrorWithExtensions } """ ) schema = GraphQLSchema( GraphQLObjectType( "Type", { "syncOk": GraphQLField(GraphQLString), "syncError": GraphQLField(GraphQLString), "syncRawError": GraphQLField(GraphQLString), "syncReturnError": GraphQLField(GraphQLString), "syncReturnErrorList": GraphQLField(GraphQLList(GraphQLString)), "asyncOk": GraphQLField(GraphQLString), "asyncError": GraphQLField(GraphQLString), "asyncErrorWithExtensions": GraphQLField(GraphQLString), "asyncRawError": GraphQLField(GraphQLString), "asyncReturnError": GraphQLField(GraphQLString), "asyncReturnErrorWithExtensions": GraphQLField(GraphQLString), }, ) ) # noinspection PyPep8Naming,PyMethodMayBeStatic class Data: def syncOk(self, _info): return "sync ok" def syncError(self, _info): raise GraphQLError("Error getting syncError") def syncRawError(self, _info): raise Exception("Error getting syncRawError") def syncReturnError(self, _info): return Exception("Error getting syncReturnError") def syncReturnErrorList(self, _info): return [ "sync0", Exception("Error getting syncReturnErrorList1"), "sync2", Exception("Error getting syncReturnErrorList3"), ] async def asyncOk(self, _info): return "async ok" async def asyncError(self, _info): raise GraphQLError("Error getting asyncError") async def asyncRawError(self, _info): raise Exception("Error getting asyncRawError") async def asyncReturnError(self, _info): return GraphQLError("Error getting asyncReturnError") async def asyncReturnErrorWithExtensions(self, _info): return GraphQLError( "Error getting asyncReturnErrorWithExtensions", extensions={"foo": "bar"}, ) awaitable_result = execute(schema, document, Data()) assert isinstance(awaitable_result, Awaitable) result = await awaitable_result assert result == ( { "syncOk": "sync ok", "syncError": None, "syncRawError": None, "syncReturnError": None, "syncReturnErrorList": ["sync0", None, "sync2", None], "asyncOk": "async ok", "asyncError": None, "asyncRawError": None, "asyncReturnError": None, "asyncReturnErrorWithExtensions": None, }, [ { "message": "Error getting syncError", "locations": [(4, 15)], "path": ["syncError"], }, { "message": "Error getting syncRawError", "locations": [(5, 15)], "path": ["syncRawError"], }, { "message": "Error getting syncReturnError", "locations": [(6, 15)], "path": ["syncReturnError"], }, { "message": "Error getting syncReturnErrorList1", "locations": [(7, 15)], "path": ["syncReturnErrorList", 1], }, { "message": "Error getting syncReturnErrorList3", "locations": [(7, 15)], "path": ["syncReturnErrorList", 3], }, { "message": "Error getting asyncError", "locations": [(9, 15)], "path": ["asyncError"], }, { "message": "Error getting asyncRawError", "locations": [(10, 15)], "path": ["asyncRawError"], }, { "message": "Error getting asyncReturnError", "locations": [(11, 15)], "path": ["asyncReturnError"], }, { "message": "Error getting asyncReturnErrorWithExtensions", "locations": [(12, 15)], "path": ["asyncReturnErrorWithExtensions"], "extensions": {"foo": "bar"}, }, ], ) @mark.filterwarnings("ignore:.* was never awaited:RuntimeWarning") def handles_sync_errors_combined_with_async_ones(): is_async_resolver_finished = False async def async_resolver(_obj, _info): nonlocal is_async_resolver_finished is_async_resolver_finished = True # pragma: no cover schema = GraphQLSchema( GraphQLObjectType( "Query", { "syncNullError": GraphQLField( GraphQLNonNull(GraphQLString), resolve=lambda _obj, _info: None ), "asyncNullError": GraphQLField( GraphQLNonNull(GraphQLString), resolve=async_resolver ), }, ) ) document = parse( """ { asyncNullError syncNullError } """ ) result = execute(schema, document) assert is_async_resolver_finished is False assert result == ( None, [ { "message": "Cannot return null" " for non-nullable field Query.syncNullError.", "locations": [(4, 15)], "path": ["syncNullError"], } ], ) @mark.filterwarnings("ignore:.* was never awaited:RuntimeWarning") def full_response_path_is_included_for_non_nullable_fields(): def resolve_ok(*_args): return {} def resolve_error(*_args): raise Exception("Catch me if you can") A = GraphQLObjectType( "A", lambda: { "nullableA": GraphQLField(A, resolve=resolve_ok), "nonNullA": GraphQLField(GraphQLNonNull(A), resolve=resolve_ok), "throws": GraphQLField(GraphQLNonNull(A), resolve=resolve_error), }, ) schema = GraphQLSchema( GraphQLObjectType( "query", lambda: {"nullableA": GraphQLField(A, resolve=resolve_ok)} ) ) document = parse( """ query { nullableA { aliasedA: nullableA { nonNullA { anotherA: nonNullA { throws } } } } } """ ) assert execute_sync(schema, document) == ( {"nullableA": {"aliasedA": None}}, [ { "message": "Catch me if you can", "locations": [(7, 23)], "path": ["nullableA", "aliasedA", "nonNullA", "anotherA", "throws"], } ], ) @mark.filterwarnings("ignore:.* was never awaited:RuntimeWarning") def uses_the_inline_operation_if_no_operation_name_is_provided(): schema = GraphQLSchema( GraphQLObjectType("Type", {"a": GraphQLField(GraphQLString)}) ) document = parse("{ a }") class Data: a = "b" result = execute_sync(schema, document, Data()) assert result == ({"a": "b"}, None) @mark.filterwarnings("ignore:.* was never awaited:RuntimeWarning") def uses_the_only_operation_if_no_operation_name_is_provided(): schema = GraphQLSchema( GraphQLObjectType("Type", {"a": GraphQLField(GraphQLString)}) ) document = parse("query Example { a }") class Data: a = "b" result = execute_sync(schema, document, Data()) assert result == ({"a": "b"}, None) @mark.filterwarnings("ignore:.* was never awaited:RuntimeWarning") def uses_the_named_operation_if_operation_name_is_provided(): schema = GraphQLSchema( GraphQLObjectType("Type", {"a": GraphQLField(GraphQLString)}) ) document = parse( """ query Example { first: a } query OtherExample { second: a } """ ) class Data: a = "b" result = execute_sync(schema, document, Data(), operation_name="OtherExample") assert result == ({"second": "b"}, None) def provides_error_if_no_operation_is_provided(): schema = GraphQLSchema( GraphQLObjectType("Type", {"a": GraphQLField(GraphQLString)}) ) document = parse("fragment Example on Type { a }") class Data: a = "b" result = execute_sync(schema, document, Data()) assert result == (None, [{"message": "Must provide an operation."}]) def errors_if_no_operation_name_is_provided_with_multiple_operations(): schema = GraphQLSchema( GraphQLObjectType("Type", {"a": GraphQLField(GraphQLString)}) ) document = parse( """ query Example { a } query OtherExample { a } """ ) result = execute_sync(schema, document) assert result == ( None, [ { "message": "Must provide operation name if query contains" " multiple operations." } ], ) def errors_if_unknown_operation_name_is_provided(): schema = GraphQLSchema( GraphQLObjectType("Type", {"a": GraphQLField(GraphQLString)}) ) document = parse( """ query Example { a } query OtherExample { a } """ ) result = execute_sync(schema, document, operation_name="UnknownExample") assert result == ( None, [{"message": "Unknown operation named 'UnknownExample'."}], ) def errors_if_empty_string_is_provided_as_operation_name(): schema = GraphQLSchema( GraphQLObjectType("Type", {"a": GraphQLField(GraphQLString)}) ) document = parse("{ a }") result = execute_sync(schema, document, operation_name="") assert result == ( None, [{"message": "Unknown operation named ''."}], ) def uses_the_query_schema_for_queries(): schema = GraphQLSchema( GraphQLObjectType("Q", {"a": GraphQLField(GraphQLString)}), GraphQLObjectType("M", {"c": GraphQLField(GraphQLString)}), GraphQLObjectType("S", {"a": GraphQLField(GraphQLString)}), ) document = parse( """ query Q { a } mutation M { c } subscription S { a } """ ) class Data: a = "b" c = "d" result = execute_sync(schema, document, Data(), operation_name="Q") assert result == ({"a": "b"}, None) def uses_the_mutation_schema_for_mutations(): schema = GraphQLSchema( GraphQLObjectType("Q", {"a": GraphQLField(GraphQLString)}), GraphQLObjectType("M", {"c": GraphQLField(GraphQLString)}), ) document = parse( """ query Q { a } mutation M { c } """ ) class Data: a = "b" c = "d" result = execute_sync(schema, document, Data(), operation_name="M") assert result == ({"c": "d"}, None) def uses_the_subscription_schema_for_subscriptions(): schema = GraphQLSchema( query=GraphQLObjectType("Q", {"a": GraphQLField(GraphQLString)}), subscription=GraphQLObjectType("S", {"a": GraphQLField(GraphQLString)}), ) document = parse( """ query Q { a } subscription S { a } """ ) class Data: a = "b" c = "d" result = execute_sync(schema, document, Data(), operation_name="S") assert result == ({"a": "b"}, None) def resolves_to_an_error_if_schema_does_not_support_operation(): schema = GraphQLSchema(assume_valid=True) document = parse( """ query Q { __typename } mutation M { __typename } subscription S { __typename } """ ) assert execute_sync(schema, document, operation_name="Q") == ( None, [ { "message": "Schema is not configured to execute query operation.", "locations": [(2, 13)], } ], ) assert execute_sync(schema, document, operation_name="M") == ( None, [ { "message": "Schema is not configured to execute" " mutation operation.", "locations": [(3, 13)], } ], ) assert execute_sync(schema, document, operation_name="S") == ( None, [ { "message": "Schema is not configured to execute" " subscription operation.", "locations": [(4, 13)], } ], ) @mark.asyncio async def correct_field_ordering_despite_execution_order(): schema = GraphQLSchema( GraphQLObjectType( "Type", { "a": GraphQLField(GraphQLString), "b": GraphQLField(GraphQLString), "c": GraphQLField(GraphQLString), "d": GraphQLField(GraphQLString), "e": GraphQLField(GraphQLString), }, ) ) document = parse("{ a, b, c, d, e}") # noinspection PyMethodMayBeStatic,PyMethodMayBeStatic class Data: def a(self, _info): return "a" async def b(self, _info): return "b" def c(self, _info): return "c" async def d(self, _info): return "d" def e(self, _info): return "e" awaitable_result = execute(schema, document, Data()) assert isinstance(awaitable_result, Awaitable) result = await awaitable_result assert result == ({"a": "a", "b": "b", "c": "c", "d": "d", "e": "e"}, None) def avoids_recursion(): schema = GraphQLSchema( GraphQLObjectType("Type", {"a": GraphQLField(GraphQLString)}) ) document = parse( """ query Q { a ...Frag ...Frag } fragment Frag on Type { a, ...Frag } """ ) class Data: a = "b" result = execute_sync(schema, document, Data(), operation_name="Q") assert result == ({"a": "b"}, None) def ignores_missing_sub_selections_on_fields(): some_type = GraphQLObjectType("SomeType", {"b": GraphQLField(GraphQLString)}) schema = GraphQLSchema( GraphQLObjectType("Query", {"a": GraphQLField(some_type)}) ) document = parse("{ a }") root_value = {"a": {"b": "c"}} result = execute_sync(schema, document, root_value) assert result == ({"a": {}}, None) def does_not_include_illegal_fields_in_output(): schema = GraphQLSchema( GraphQLObjectType("Q", {"a": GraphQLField(GraphQLString)}) ) document = parse("{ thisIsIllegalDoNotIncludeMe }") result = execute_sync(schema, document) assert result == ({}, None) def does_not_include_arguments_that_were_not_set(): schema = GraphQLSchema( GraphQLObjectType( "Type", { "field": GraphQLField( GraphQLString, args={ "a": GraphQLArgument(GraphQLBoolean), "b": GraphQLArgument(GraphQLBoolean), "c": GraphQLArgument(GraphQLBoolean), "d": GraphQLArgument(GraphQLInt), "e": GraphQLArgument(GraphQLInt), }, resolve=lambda _source, _info, **args: inspect(args), ) }, ) ) document = parse("{ field(a: true, c: false, e: 0) }") assert execute_sync(schema, document) == ( {"field": "{'a': True, 'c': False, 'e': 0}"}, None, ) @mark.asyncio async def fails_when_is_type_of_check_is_not_met(): class Special: value: str def __init__(self, value): self.value = value class NotSpecial: value: str def __init__(self, value): self.value = value def is_type_of_special(obj, _info): is_special = isinstance(obj, Special) if not _info.context["async"]: return is_special async def async_is_special(): return is_special return async_is_special() SpecialType = GraphQLObjectType( "SpecialType", {"value": GraphQLField(GraphQLString)}, is_type_of=is_type_of_special, ) schema = GraphQLSchema( GraphQLObjectType( "Query", {"specials": GraphQLField(GraphQLList(SpecialType))} ) ) document = parse("{ specials { value } }") root_value = {"specials": [Special("foo"), NotSpecial("bar")]} result = execute_sync(schema, document, root_value, {"async": False}) assert not isinstance(result, Awaitable) assert result == ( {"specials": [{"value": "foo"}, None]}, [ { "message": "Expected value of type 'SpecialType' but got:" " .", "locations": [(1, 3)], "path": ["specials", 1], } ], ) async_result = execute(schema, document, root_value, {"async": True}) assert isinstance(async_result, Awaitable) awaited_result = await async_result assert awaited_result == result def fails_when_serialize_of_custom_scalar_does_not_return_a_value(): custom_scalar = GraphQLScalarType( "CustomScalar", serialize=lambda _value: Undefined # returns nothing ) schema = GraphQLSchema( GraphQLObjectType( "Query", { "customScalar": GraphQLField( custom_scalar, resolve=lambda *_args: "CUSTOM_VALUE" ) }, ) ) result = execute_sync(schema, parse("{ customScalar }")) assert result == ( {"customScalar": None}, [ { "message": "Expected `CustomScalar.serialize('CUSTOM_VALUE')`" " to return non-nullable value, returned: Undefined", "locations": [(1, 3)], "path": ["customScalar"], } ], ) def executes_ignoring_invalid_non_executable_definitions(): schema = GraphQLSchema( GraphQLObjectType("Query", {"foo": GraphQLField(GraphQLString)}) ) document = parse( """ { foo } type Query { bar: String } """ ) result = execute_sync(schema, document) assert result == ({"foo": None}, None) def uses_a_custom_field_resolver(): schema = GraphQLSchema( GraphQLObjectType("Query", {"foo": GraphQLField(GraphQLString)}) ) document = parse("{ foo }") def field_resolver(_source, info): # For the purposes of test, just return the name of the field! return info.field_name result = execute_sync(schema, document, field_resolver=field_resolver) assert result == ({"foo": "foo"}, None) def uses_a_custom_type_resolver(): document = parse("{ foo { bar } }") foo_interface = GraphQLInterfaceType( "FooInterface", {"bar": GraphQLField(GraphQLString)} ) foo_object = GraphQLObjectType( "FooObject", {"bar": GraphQLField(GraphQLString)}, [foo_interface] ) schema = GraphQLSchema( GraphQLObjectType("Query", {"foo": GraphQLField(foo_interface)}), types=[foo_object], ) possible_types = None def type_resolver(_source, info, abstract_type): # Resolver should be able to figure out all possible types on its own nonlocal possible_types possible_types = info.schema.get_possible_types(abstract_type) return "FooObject" root_value = {"foo": {"bar": "bar"}} result = execute_sync(schema, document, root_value, type_resolver=type_resolver) assert result == ({"foo": {"bar": "bar"}}, None) assert possible_types == [foo_object] graphql-core-3.2.6/tests/execution/test_lists.py000066400000000000000000000200611474546154300220360ustar00rootroot00000000000000from typing import cast, Any, Awaitable from pytest import mark from graphql.execution import execute, execute_sync, ExecutionResult from graphql.language import parse from graphql.pyutils import is_awaitable from graphql.utilities import build_schema class Data: def __init__(self, value): self.listField = value async def get_async(value): return value def describe_execute_accepts_any_iterable_as_list_value(): def _complete(list_field): return execute_sync( build_schema("type Query { listField: [String] }"), parse("{ listField }"), Data(list_field), ) def accepts_a_set_as_a_list_value(): # Note that sets are not ordered in Python. list_field = {"apple", "banana", "coconut"} result = _complete(list_field) assert result.errors is None assert isinstance(result.data, dict) assert list(result.data) == ["listField"] assert isinstance(result.data["listField"], list) assert set(result.data["listField"]) == list_field def accepts_a_generator_as_a_list_value(): def list_field(): yield "one" yield 2 yield True assert _complete(list_field()) == ( {"listField": ["one", "2", "true"]}, None, ) def accepts_a_custom_iterable_as_a_list_value(): class ListField: def __iter__(self): self.last = "hello" return self def __next__(self): last = self.last if last == "stop": raise StopIteration self.last = "world" if last == "hello" else "stop" return last assert _complete(ListField()) == ( {"listField": ["hello", "world"]}, None, ) def accepts_function_arguments_as_a_list_value(): def get_args(*args): return args # actually just a tuple, nothing special in Python assert _complete(get_args("one", "two")) == ( {"listField": ["one", "two"]}, None, ) def does_not_accept_a_dict_as_a_list_value(): assert _complete({1: "one", 2: "two"}) == ( {"listField": None}, [ { "message": "Expected Iterable," " but did not find one for field 'Query.listField'.", "locations": [(1, 3)], "path": ["listField"], } ], ) def does_not_accept_iterable_string_literal_as_a_list_value(): assert _complete("Singular") == ( {"listField": None}, [ { "message": "Expected Iterable," " but did not find one for field 'Query.listField'.", "locations": [(1, 3)], "path": ["listField"], } ], ) def describe_execute_handles_list_nullability(): async def _complete(list_field: Any, as_type: str) -> ExecutionResult: schema = build_schema(f"type Query {{ listField: {as_type} }}") document = parse("{ listField }") def execute_query(list_value: Any) -> Any: return execute(schema, document, Data(list_value)) result = execute_query(list_field) assert isinstance(result, ExecutionResult) assert await execute_query(get_async(list_field)) == result if isinstance(list_field, list): assert await execute_query(list(map(get_async, list_field))) == result assert await execute_query(get_async(list_field)) == result return result @mark.asyncio async def contains_values(): list_field = [1, 2] assert await _complete(list_field, "[Int]") == ({"listField": [1, 2]}, None) assert await _complete(list_field, "[Int]!") == ({"listField": [1, 2]}, None) assert await _complete(list_field, "[Int!]") == ({"listField": [1, 2]}, None) assert await _complete(list_field, "[Int!]!") == ({"listField": [1, 2]}, None) @mark.asyncio async def contains_null(): list_field = [1, None, 2] errors = [ { "message": "Cannot return null for non-nullable field Query.listField.", "locations": [(1, 3)], "path": ["listField", 1], } ] assert await _complete(list_field, "[Int]") == ( {"listField": [1, None, 2]}, None, ) assert await _complete(list_field, "[Int]!") == ( {"listField": [1, None, 2]}, None, ) assert await _complete(list_field, "[Int!]") == ({"listField": None}, errors) assert await _complete(list_field, "[Int!]!") == (None, errors) @mark.asyncio async def returns_null(): list_field = None errors = [ { "message": "Cannot return null for non-nullable field Query.listField.", "locations": [(1, 3)], "path": ["listField"], } ] assert await _complete(list_field, "[Int]") == ({"listField": None}, None) assert await _complete(list_field, "[Int]!") == (None, errors) assert await _complete(list_field, "[Int!]") == ({"listField": None}, None) assert await _complete(list_field, "[Int!]!") == (None, errors) @mark.asyncio async def contains_error(): list_field = [1, RuntimeError("bad"), 2] errors = [ { "message": "bad", "locations": [(1, 3)], "path": ["listField", 1], } ] assert await _complete(list_field, "[Int]") == ( {"listField": [1, None, 2]}, errors, ) assert await _complete(list_field, "[Int]!") == ( {"listField": [1, None, 2]}, errors, ) assert await _complete(list_field, "[Int!]") == ( {"listField": None}, errors, ) assert await _complete(list_field, "[Int!]!") == ( None, errors, ) @mark.asyncio async def results_in_errors(): list_field = RuntimeError("bad") errors = [ { "message": "bad", "locations": [(1, 3)], "path": ["listField"], } ] assert await _complete(list_field, "[Int]") == ( {"listField": None}, errors, ) assert await _complete(list_field, "[Int]!") == ( None, errors, ) assert await _complete(list_field, "[Int!]") == ( {"listField": None}, errors, ) assert await _complete(list_field, "[Int!]!") == ( None, errors, ) def describe_experimental_execute_accepts_async_iterables_as_list_value(): async def _complete(list_field): result = execute( build_schema("type Query { listField: [String] }"), parse("{ listField }"), Data(list_field), ) assert is_awaitable(result) result = cast(Awaitable, result) return await result @mark.asyncio async def accepts_an_async_generator_as_a_list_value(): async def list_field(): yield "one" yield 2 yield True assert await _complete(list_field()) == ( {"listField": ["one", "2", "true"]}, None, ) @mark.asyncio async def accepts_a_custom_async_iterable_as_a_list_value(): class ListField: def __aiter__(self): self.last = "hello" return self async def __anext__(self): last = self.last if last == "stop": raise StopAsyncIteration self.last = "world" if last == "hello" else "stop" return last assert await _complete(ListField()) == ( {"listField": ["hello", "world"]}, None, ) graphql-core-3.2.6/tests/execution/test_map_async_iterator.py000066400000000000000000000336671474546154300246030ustar00rootroot00000000000000import platform import sys from asyncio import CancelledError, Event, ensure_future, sleep from graphql.execution import MapAsyncIterator from pytest import mark, raises is_pypy = platform.python_implementation() == "PyPy" try: # pragma: no cover anext # type: ignore except NameError: # pragma: no cover (Python < 3.10) # noinspection PyShadowingBuiltins async def anext(iterator): """Return the next item from an async iterator.""" return await iterator.__anext__() def describe_map_async_iterator(): @mark.asyncio async def maps_over_async_generator(): async def source(): yield 1 yield 2 yield 3 doubles = MapAsyncIterator(source(), lambda x: x + x) assert await anext(doubles) == 2 assert await anext(doubles) == 4 assert await anext(doubles) == 6 with raises(StopAsyncIteration): assert await anext(doubles) @mark.asyncio async def maps_over_async_iterable(): items = [1, 2, 3] class Iterable: def __aiter__(self): return self async def __anext__(self): try: return items.pop(0) except IndexError: raise StopAsyncIteration doubles = MapAsyncIterator(Iterable(), lambda x: x + x) values = [value async for value in doubles] assert not items assert values == [2, 4, 6] @mark.asyncio async def compatible_with_async_for(): async def source(): yield 1 yield 2 yield 3 doubles = MapAsyncIterator(source(), lambda x: x + x) values = [value async for value in doubles] assert values == [2, 4, 6] @mark.asyncio async def maps_over_async_values_with_async_function(): async def source(): yield 1 yield 2 yield 3 async def double(x): return x + x doubles = MapAsyncIterator(source(), double) values = [value async for value in doubles] assert values == [2, 4, 6] @mark.asyncio async def allows_returning_early_from_mapped_async_generator(): async def source(): yield 1 yield 2 yield 3 # pragma: no cover doubles = MapAsyncIterator(source(), lambda x: x + x) assert await anext(doubles) == 2 assert await anext(doubles) == 4 # Early return await doubles.aclose() # Subsequent next calls with raises(StopAsyncIteration): await anext(doubles) with raises(StopAsyncIteration): await anext(doubles) @mark.asyncio async def allows_returning_early_from_mapped_async_iterable(): items = [1, 2, 3] class Iterable: def __aiter__(self): return self async def __anext__(self): try: return items.pop(0) except IndexError: # pragma: no cover raise StopAsyncIteration doubles = MapAsyncIterator(Iterable(), lambda x: x + x) assert await anext(doubles) == 2 assert await anext(doubles) == 4 # Early return await doubles.aclose() # Subsequent next calls with raises(StopAsyncIteration): await anext(doubles) with raises(StopAsyncIteration): await anext(doubles) @mark.asyncio async def passes_through_early_return_from_async_values(): async def source(): try: yield 1 yield 2 yield 3 # pragma: no cover finally: yield "Done" yield "Last" doubles = MapAsyncIterator(source(), lambda x: x + x) assert await anext(doubles) == 2 assert await anext(doubles) == 4 # Early return await doubles.aclose() # Subsequent next calls may yield from finally block assert await anext(doubles) == "LastLast" with raises(GeneratorExit): assert await anext(doubles) @mark.asyncio async def allows_throwing_errors_through_async_iterable(): items = [1, 2, 3] class Iterable: def __aiter__(self): return self async def __anext__(self): try: return items.pop(0) except IndexError: # pragma: no cover raise StopAsyncIteration doubles = MapAsyncIterator(Iterable(), lambda x: x + x) assert await anext(doubles) == 2 assert await anext(doubles) == 4 # Throw error with raises(RuntimeError, match="Ouch") as exc_info: await doubles.athrow(RuntimeError("Ouch")) assert str(exc_info.value) == "Ouch" with raises(StopAsyncIteration): await anext(doubles) with raises(StopAsyncIteration): await anext(doubles) @mark.asyncio async def allows_throwing_errors_with_values_through_async_iterators(): class Iterator: def __aiter__(self): return self async def __anext__(self): return 1 one = MapAsyncIterator(Iterator(), lambda x: x) assert await anext(one) == 1 # Throw error with value passed separately try: raise RuntimeError("Ouch") except RuntimeError as error: with raises(RuntimeError, match="Ouch") as exc_info: await one.athrow(error.__class__, error) assert exc_info.value is error assert exc_info.tb is error.__traceback__ with raises(StopAsyncIteration): await anext(one) @mark.asyncio async def allows_throwing_errors_with_traceback_through_async_iterators(): class Iterator: def __aiter__(self): return self async def __anext__(self): return 1 one = MapAsyncIterator(Iterator(), lambda x: x) assert await anext(one) == 1 # Throw error with traceback passed separately try: raise RuntimeError("Ouch") except RuntimeError as error: with raises(RuntimeError) as exc_info: await one.athrow(error.__class__, None, error.__traceback__) assert exc_info.tb and error.__traceback__ assert exc_info.tb.tb_frame is error.__traceback__.tb_frame with raises(StopAsyncIteration): await anext(one) @mark.asyncio async def passes_through_caught_errors_through_async_generators(): async def source(): try: yield 1 yield 2 yield 3 # pragma: no cover except Exception as e: yield e doubles = MapAsyncIterator(source(), lambda x: x + x) assert await anext(doubles) == 2 assert await anext(doubles) == 4 # Throw error await doubles.athrow(RuntimeError("ouch")) with raises(StopAsyncIteration): await anext(doubles) with raises(StopAsyncIteration): await anext(doubles) @mark.asyncio async def does_not_normally_map_over_thrown_errors(): async def source(): yield "Hello" raise RuntimeError("Goodbye") doubles = MapAsyncIterator(source(), lambda x: x + x) assert await anext(doubles) == "HelloHello" with raises(RuntimeError) as exc_info: await anext(doubles) assert str(exc_info.value) == "Goodbye" @mark.asyncio async def does_not_normally_map_over_externally_thrown_errors(): async def source(): yield "Hello" doubles = MapAsyncIterator(source(), lambda x: x + x) assert await anext(doubles) == "HelloHello" with raises(RuntimeError) as exc_info: await doubles.athrow(RuntimeError("Goodbye")) assert str(exc_info.value) == "Goodbye" @mark.asyncio async def can_use_simple_iterator_instead_of_generator(): async def source(): yield 1 yield 2 yield 3 class Source: def __init__(self): self.counter = 0 def __aiter__(self): return self async def __anext__(self): self.counter += 1 if self.counter > 3: raise StopAsyncIteration return self.counter def double(x): return x + x for iterator in source, Source: doubles = MapAsyncIterator(iterator(), double) await doubles.aclose() with raises(StopAsyncIteration): await anext(doubles) doubles = MapAsyncIterator(iterator(), double) assert await anext(doubles) == 2 assert await anext(doubles) == 4 assert await anext(doubles) == 6 with raises(StopAsyncIteration): await anext(doubles) doubles = MapAsyncIterator(iterator(), double) assert await anext(doubles) == 2 assert await anext(doubles) == 4 # Throw error with raises(RuntimeError) as exc_info: await doubles.athrow(RuntimeError("ouch")) assert str(exc_info.value) == "ouch" with raises(StopAsyncIteration): await anext(doubles) with raises(StopAsyncIteration): await anext(doubles) # no more exceptions should be thrown if is_pypy: # need to investigate why this is needed with PyPy await doubles.aclose() # pragma: no cover await doubles.athrow(RuntimeError("no more ouch")) with raises(StopAsyncIteration): await anext(doubles) await doubles.aclose() doubles = MapAsyncIterator(iterator(), double) assert await anext(doubles) == 2 assert await anext(doubles) == 4 try: raise ValueError("bad") except ValueError: tb = sys.exc_info()[2] # Throw error with raises(ValueError): await doubles.athrow(ValueError, None, tb) await sleep(0) @mark.asyncio async def stops_async_iteration_on_close(): async def source(): yield 1 await Event().wait() # Block forever yield 2 # pragma: no cover yield 3 # pragma: no cover singles = source() doubles = MapAsyncIterator(singles, lambda x: x * 2) result = await anext(doubles) assert result == 2 # Make sure it is blocked doubles_future = ensure_future(anext(doubles)) await sleep(0.05) assert not doubles_future.done() # Unblock and watch StopAsyncIteration propagate await doubles.aclose() await sleep(0.05) assert doubles_future.done() assert isinstance(doubles_future.exception(), StopAsyncIteration) with raises(StopAsyncIteration): await anext(singles) @mark.asyncio async def can_unset_closed_state_of_async_iterator(): items = [1, 2, 3] class Iterator: def __init__(self): self.is_closed = False def __aiter__(self): return self async def __anext__(self): if self.is_closed: raise StopAsyncIteration try: return items.pop(0) except IndexError: raise StopAsyncIteration async def aclose(self): self.is_closed = True iterator = Iterator() doubles = MapAsyncIterator(iterator, lambda x: x + x) assert await anext(doubles) == 2 assert await anext(doubles) == 4 assert not iterator.is_closed await doubles.aclose() assert iterator.is_closed with raises(StopAsyncIteration): await anext(iterator) with raises(StopAsyncIteration): await anext(doubles) assert doubles.is_closed iterator.is_closed = False doubles.is_closed = False assert not doubles.is_closed assert await anext(doubles) == 6 assert not doubles.is_closed assert not iterator.is_closed with raises(StopAsyncIteration): await anext(iterator) with raises(StopAsyncIteration): await anext(doubles) assert not doubles.is_closed assert not iterator.is_closed @mark.asyncio async def can_cancel_async_iterator_while_waiting(): class Iterator: def __init__(self): self.is_closed = False self.value = 1 def __aiter__(self): return self async def __anext__(self): try: await sleep(0.5) return self.value # pragma: no cover except CancelledError: self.value = -1 raise async def aclose(self): self.is_closed = True iterator = Iterator() doubles = MapAsyncIterator(iterator, lambda x: x + x) # pragma: no cover exit cancelled = False async def iterator_task(): nonlocal cancelled try: async for _ in doubles: assert False # pragma: no cover except CancelledError: cancelled = True task = ensure_future(iterator_task()) await sleep(0.05) assert not cancelled assert not doubles.is_closed assert iterator.value == 1 assert not iterator.is_closed task.cancel() await sleep(0.05) assert cancelled assert iterator.value == -1 assert doubles.is_closed assert iterator.is_closed graphql-core-3.2.6/tests/execution/test_middleware.py000066400000000000000000000262441474546154300230260ustar00rootroot00000000000000from typing import Awaitable from pytest import mark, raises from graphql.execution import MiddlewareManager, execute from graphql.language.parser import parse from graphql.type import GraphQLField, GraphQLObjectType, GraphQLSchema, GraphQLString def describe_middleware(): def describe_with_manager(): def default(): doc = parse("{ field }") # noinspection PyMethodMayBeStatic class Data: def field(self, _info): return "resolved" test_type = GraphQLObjectType( "TestType", {"field": GraphQLField(GraphQLString)} ) middlewares = MiddlewareManager() result = execute( GraphQLSchema(test_type), doc, Data(), middleware=middlewares ) assert result.data["field"] == "resolved" # type: ignore def single_function(): doc = parse("{ first second }") # noinspection PyMethodMayBeStatic class Data: def first(self, _info): return "one" def second(self, _info): return "two" test_type = GraphQLObjectType( "TestType", { "first": GraphQLField(GraphQLString), "second": GraphQLField(GraphQLString), }, ) def reverse_middleware(next_, *args, **kwargs): return next_(*args, **kwargs)[::-1] middlewares = MiddlewareManager(reverse_middleware) result = execute( GraphQLSchema(test_type), doc, Data(), middleware=middlewares ) assert result.data == {"first": "eno", "second": "owt"} # type: ignore def two_functions_and_field_resolvers(): doc = parse("{ first second }") # noinspection PyMethodMayBeStatic class Data: first = "one" second = "two" test_type = GraphQLObjectType( "TestType", { "first": GraphQLField( GraphQLString, resolve=lambda obj, _info: obj.first ), "second": GraphQLField( GraphQLString, resolve=lambda obj, _info: obj.second ), }, ) def reverse_middleware(next_, *args, **kwargs): return next_(*args, **kwargs)[::-1] def capitalize_middleware(next_, *args, **kwargs): return next_(*args, **kwargs).capitalize() middlewares = MiddlewareManager(reverse_middleware, capitalize_middleware) result = execute( GraphQLSchema(test_type), doc, Data(), middleware=middlewares ) assert result.data == {"first": "Eno", "second": "Owt"} # type: ignore @mark.asyncio async def single_async_function(): doc = parse("{ first second }") # noinspection PyMethodMayBeStatic class Data: async def first(self, _info): return "one" async def second(self, _info): return "two" test_type = GraphQLObjectType( "TestType", { "first": GraphQLField(GraphQLString), "second": GraphQLField(GraphQLString), }, ) async def reverse_middleware(next_, *args, **kwargs): return (await next_(*args, **kwargs))[::-1] middlewares = MiddlewareManager(reverse_middleware) awaitable_result = execute( GraphQLSchema(test_type), doc, Data(), middleware=middlewares ) assert isinstance(awaitable_result, Awaitable) result = await awaitable_result assert result.data == {"first": "eno", "second": "owt"} def single_object(): doc = parse("{ first second }") # noinspection PyMethodMayBeStatic class Data: def first(self, _info): return "one" def second(self, _info): return "two" test_type = GraphQLObjectType( "TestType", { "first": GraphQLField(GraphQLString), "second": GraphQLField(GraphQLString), }, ) class ReverseMiddleware: # noinspection PyMethodMayBeStatic def resolve(self, next_, *args, **kwargs): return next_(*args, **kwargs)[::-1] middlewares = MiddlewareManager(ReverseMiddleware()) result = execute( GraphQLSchema(test_type), doc, Data(), middleware=middlewares ) assert result.data == {"first": "eno", "second": "owt"} # type: ignore def skip_middleware_without_resolve_method(): class BadMiddleware: pass # no resolve method here assert execute( GraphQLSchema( GraphQLObjectType( "TestType", {"foo": GraphQLField(GraphQLString)}, ) ), parse("{ foo }"), {"foo": "bar"}, middleware=MiddlewareManager(BadMiddleware()), ) == ({"foo": "bar"}, None) def with_function_and_object(): doc = parse("{ field }") # noinspection PyMethodMayBeStatic class Data: def field(self, _info): return "resolved" test_type = GraphQLObjectType( "TestType", {"field": GraphQLField(GraphQLString)} ) def reverse_middleware(next_, *args, **kwargs): return next_(*args, **kwargs)[::-1] class CaptitalizeMiddleware: # noinspection PyMethodMayBeStatic def resolve(self, next_, *args, **kwargs): return next_(*args, **kwargs).capitalize() middlewares = MiddlewareManager(reverse_middleware, CaptitalizeMiddleware()) result = execute( GraphQLSchema(test_type), doc, Data(), middleware=middlewares ) assert result.data == {"field": "Devloser"} # type: ignore middlewares = MiddlewareManager(CaptitalizeMiddleware(), reverse_middleware) result = execute( GraphQLSchema(test_type), doc, Data(), middleware=middlewares ) assert result.data == {"field": "devloseR"} # type: ignore @mark.asyncio async def with_async_function_and_object(): doc = parse("{ field }") # noinspection PyMethodMayBeStatic class Data: async def field(self, _info): return "resolved" test_type = GraphQLObjectType( "TestType", {"field": GraphQLField(GraphQLString)} ) async def reverse_middleware(next_, *args, **kwargs): return (await next_(*args, **kwargs))[::-1] class CaptitalizeMiddleware: # noinspection PyMethodMayBeStatic async def resolve(self, next_, *args, **kwargs): return (await next_(*args, **kwargs)).capitalize() middlewares = MiddlewareManager(reverse_middleware, CaptitalizeMiddleware()) awaitable_result = execute( GraphQLSchema(test_type), doc, Data(), middleware=middlewares ) assert isinstance(awaitable_result, Awaitable) result = await awaitable_result assert result.data == {"field": "Devloser"} middlewares = MiddlewareManager(CaptitalizeMiddleware(), reverse_middleware) awaitable_result = execute( GraphQLSchema(test_type), doc, Data(), middleware=middlewares ) assert isinstance(awaitable_result, Awaitable) result = await awaitable_result assert result.data == {"field": "devloseR"} def describe_without_manager(): def no_middleware(): doc = parse("{ field }") # noinspection PyMethodMayBeStatic class Data: def field(self, _info): return "resolved" test_type = GraphQLObjectType( "TestType", {"field": GraphQLField(GraphQLString)} ) result = execute(GraphQLSchema(test_type), doc, Data(), middleware=None) assert result.data["field"] == "resolved" # type: ignore def empty_middleware_list(): doc = parse("{ field }") # noinspection PyMethodMayBeStatic class Data: def field(self, _info): return "resolved" test_type = GraphQLObjectType( "TestType", {"field": GraphQLField(GraphQLString)} ) result = execute(GraphQLSchema(test_type), doc, Data(), middleware=[]) assert result.data["field"] == "resolved" # type: ignore def bad_middleware_object(): doc = parse("{ field }") test_type = GraphQLObjectType( "TestType", {"field": GraphQLField(GraphQLString)} ) with raises(TypeError) as exc_info: # noinspection PyTypeChecker execute( GraphQLSchema(test_type), doc, None, middleware={"bad": "value"}, # type: ignore ) assert str(exc_info.value) == ( "Middleware must be passed as a list or tuple of functions" " or objects, or as a single MiddlewareManager object." " Got {'bad': 'value'} instead." ) def list_of_functions(): doc = parse("{ field }") # noinspection PyMethodMayBeStatic class Data: def field(self, _info): return "resolved" test_type = GraphQLObjectType( "TestType", {"field": GraphQLField(GraphQLString)} ) log = [] class LogMiddleware: def __init__(self, name): self.name = name # noinspection PyMethodMayBeStatic def resolve(self, next_, *args, **kwargs): log.append(f"enter {self.name}") value = next_(*args, **kwargs) log.append(f"exit {self.name}") return value middlewares = [LogMiddleware("A"), LogMiddleware("B"), LogMiddleware("C")] result = execute( GraphQLSchema(test_type), doc, Data(), middleware=middlewares ) assert result.data == {"field": "resolved"} # type: ignore assert log == [ "enter C", "enter B", "enter A", "exit A", "exit B", "exit C", ] graphql-core-3.2.6/tests/execution/test_mutations.py000066400000000000000000000137521474546154300227340ustar00rootroot00000000000000import asyncio from typing import Awaitable from pytest import mark from graphql.execution import execute, execute_sync from graphql.language import parse from graphql.type import ( GraphQLArgument, GraphQLField, GraphQLInt, GraphQLObjectType, GraphQLSchema, ) # noinspection PyPep8Naming class NumberHolder: theNumber: int def __init__(self, originalNumber: int): self.theNumber = originalNumber # noinspection PyPep8Naming class Root: numberHolder: NumberHolder def __init__(self, originalNumber: int): self.numberHolder = NumberHolder(originalNumber) def immediately_change_the_number(self, newNumber: int) -> NumberHolder: self.numberHolder.theNumber = newNumber return self.numberHolder async def promise_to_change_the_number(self, new_number: int) -> NumberHolder: await asyncio.sleep(0) return self.immediately_change_the_number(new_number) def fail_to_change_the_number(self, newNumber: int): raise RuntimeError(f"Cannot change the number to {newNumber}") async def promise_and_fail_to_change_the_number(self, newNumber: int): await asyncio.sleep(0) self.fail_to_change_the_number(newNumber) numberHolderType = GraphQLObjectType( "NumberHolder", {"theNumber": GraphQLField(GraphQLInt)} ) # noinspection PyPep8Naming schema = GraphQLSchema( GraphQLObjectType("Query", {"numberHolder": GraphQLField(numberHolderType)}), GraphQLObjectType( "Mutation", { "immediatelyChangeTheNumber": GraphQLField( numberHolderType, args={"newNumber": GraphQLArgument(GraphQLInt)}, resolve=lambda obj, _info, newNumber: obj.immediately_change_the_number( newNumber ), ), "promiseToChangeTheNumber": GraphQLField( numberHolderType, args={"newNumber": GraphQLArgument(GraphQLInt)}, resolve=lambda obj, _info, newNumber: obj.promise_to_change_the_number( newNumber ), ), "failToChangeTheNumber": GraphQLField( numberHolderType, args={"newNumber": GraphQLArgument(GraphQLInt)}, resolve=lambda obj, _info, newNumber: obj.fail_to_change_the_number( newNumber ), ), "promiseAndFailToChangeTheNumber": GraphQLField( numberHolderType, args={"newNumber": GraphQLArgument(GraphQLInt)}, resolve=lambda obj, _info, newNumber: ( obj.promise_and_fail_to_change_the_number(newNumber) ), ), }, ), ) def describe_execute_handles_mutation_execution_ordering(): @mark.asyncio async def evaluates_mutations_serially(): document = parse( """ mutation M { first: immediatelyChangeTheNumber(newNumber: 1) { theNumber }, second: promiseToChangeTheNumber(newNumber: 2) { theNumber }, third: immediatelyChangeTheNumber(newNumber: 3) { theNumber } fourth: promiseToChangeTheNumber(newNumber: 4) { theNumber }, fifth: immediatelyChangeTheNumber(newNumber: 5) { theNumber } } """ ) root_value = Root(6) awaitable_result = execute( schema=schema, document=document, root_value=root_value ) assert isinstance(awaitable_result, Awaitable) mutation_result = await awaitable_result assert mutation_result == ( { "first": {"theNumber": 1}, "second": {"theNumber": 2}, "third": {"theNumber": 3}, "fourth": {"theNumber": 4}, "fifth": {"theNumber": 5}, }, None, ) def does_not_include_illegal_mutation_fields_in_output(): document = parse("mutation { thisIsIllegalDoNotIncludeMe }") result = execute_sync(schema=schema, document=document) assert result == ({}, None) @mark.asyncio async def evaluates_mutations_correctly_in_presence_of_a_failed_mutation(): document = parse( """ mutation M { first: immediatelyChangeTheNumber(newNumber: 1) { theNumber }, second: promiseToChangeTheNumber(newNumber: 2) { theNumber }, third: failToChangeTheNumber(newNumber: 3) { theNumber } fourth: promiseToChangeTheNumber(newNumber: 4) { theNumber }, fifth: immediatelyChangeTheNumber(newNumber: 5) { theNumber } sixth: promiseAndFailToChangeTheNumber(newNumber: 6) { theNumber } } """ ) root_value = Root(6) awaitable_result = execute( schema=schema, document=document, root_value=root_value ) assert isinstance(awaitable_result, Awaitable) result = await awaitable_result assert result == ( { "first": {"theNumber": 1}, "second": {"theNumber": 2}, "third": None, "fourth": {"theNumber": 4}, "fifth": {"theNumber": 5}, "sixth": None, }, [ { "message": "Cannot change the number to 3", "locations": [(9, 15)], "path": ["third"], }, { "message": "Cannot change the number to 6", "locations": [(18, 15)], "path": ["sixth"], }, ], ) graphql-core-3.2.6/tests/execution/test_nonnull.py000066400000000000000000000536501474546154300223770ustar00rootroot00000000000000import re from typing import Any, Awaitable, cast from pytest import mark from graphql.execution import execute, execute_sync, ExecutionResult from graphql.language import parse from graphql.pyutils import AwaitableOrValue from graphql.type import ( GraphQLArgument, GraphQLField, GraphQLNonNull, GraphQLObjectType, GraphQLSchema, GraphQLString, ) from graphql.utilities import build_schema sync_error = RuntimeError("sync") sync_non_null_error = RuntimeError("syncNonNull") promise_error = RuntimeError("promise") promise_non_null_error = RuntimeError("promiseNonNull") # noinspection PyPep8Naming,PyMethodMayBeStatic class ThrowingData: def sync(self, _info): raise sync_error def syncNonNull(self, _info): raise sync_non_null_error async def promise(self, _info): raise promise_error async def promiseNonNull(self, _info): raise promise_non_null_error def syncNest(self, _info): return ThrowingData() def syncNonNullNest(self, _info): return ThrowingData() async def promiseNest(self, _info): return ThrowingData() async def promiseNonNullNest(self, _info): return ThrowingData() # noinspection PyPep8Naming,PyMethodMayBeStatic class NullingData: def sync(self, _info): return None def syncNonNull(self, _info): return None async def promise(self, _info): return None async def promiseNonNull(self, _info): return None def syncNest(self, _info): return NullingData() def syncNonNullNest(self, _info): return NullingData() async def promiseNest(self, _info): return NullingData() async def promiseNonNullNest(self, _info): return NullingData() schema = build_schema( """ type DataType { sync: String syncNonNull: String! promise: String promiseNonNull: String! syncNest: DataType syncNonNullNest: DataType! promiseNest: DataType promiseNonNullNest: DataType! } schema { query: DataType } """ ) def execute_query(query: str, root_value: Any) -> AwaitableOrValue[ExecutionResult]: return execute(schema=schema, document=parse(query), root_value=root_value) # avoids also doing any nests def patch(data: str) -> str: return re.sub( r"\bsyncNonNull\b", "promiseNonNull", re.sub(r"\bsync\b", "promise", data) ) async def execute_sync_and_async(query: str, root_value: Any) -> ExecutionResult: sync_result = execute_sync(schema, parse(query), root_value) async_result = await cast( Awaitable[ExecutionResult], execute(schema, parse(patch(query)), root_value) ) assert repr(async_result) == patch(repr(sync_result)) return sync_result def describe_execute_handles_non_nullable_types(): def describe_nulls_a_nullable_field(): query = """ { sync } """ @mark.asyncio async def returns_null(): result = await execute_sync_and_async(query, NullingData()) assert result == ({"sync": None}, None) @mark.asyncio async def throws(): result = await execute_sync_and_async(query, ThrowingData()) assert result == ( {"sync": None}, [ { "message": str(sync_error), "path": ["sync"], "locations": [(3, 15)], } ], ) def describe_nulls_a_returned_object_that_contains_a_non_null_field(): query = """ { syncNest { syncNonNull, } } """ @mark.asyncio async def that_returns_null(): result = await execute_sync_and_async(query, NullingData()) assert result == ( {"syncNest": None}, [ { "message": "Cannot return null for non-nullable field" " DataType.syncNonNull.", "path": ["syncNest", "syncNonNull"], "locations": [(4, 17)], } ], ) @mark.asyncio async def that_throws(): result = await execute_sync_and_async(query, ThrowingData()) assert result == ( {"syncNest": None}, [ { "message": str(sync_non_null_error), "path": ["syncNest", "syncNonNull"], "locations": [(4, 17)], } ], ) def describe_nulls_a_complex_tree_of_nullable_fields_each(): query = """ { syncNest { sync promise syncNest { sync promise } promiseNest { sync promise } } promiseNest { sync promise syncNest { sync promise } promiseNest { sync promise } } } """ data = { "syncNest": { "sync": None, "promise": None, "syncNest": {"sync": None, "promise": None}, "promiseNest": {"sync": None, "promise": None}, }, "promiseNest": { "sync": None, "promise": None, "syncNest": {"sync": None, "promise": None}, "promiseNest": {"sync": None, "promise": None}, }, } @mark.asyncio async def returns_null(): result = await cast( Awaitable[ExecutionResult], execute_query(query, NullingData()) ) assert result == (data, None) @mark.asyncio async def throws(): result = await cast( Awaitable[ExecutionResult], execute_query(query, ThrowingData()) ) assert result == ( data, [ { "message": str(sync_error), "path": ["syncNest", "sync"], "locations": [(4, 17)], }, { "message": str(promise_error), "path": ["syncNest", "promise"], "locations": [(5, 17)], }, { "message": str(sync_error), "path": ["syncNest", "syncNest", "sync"], "locations": [(6, 28)], }, { "message": str(promise_error), "path": ["syncNest", "syncNest", "promise"], "locations": [(6, 33)], }, { "message": str(sync_error), "path": ["syncNest", "promiseNest", "sync"], "locations": [(7, 31)], }, { "message": str(promise_error), "path": ["syncNest", "promiseNest", "promise"], "locations": [(7, 36)], }, { "message": str(sync_error), "path": ["promiseNest", "sync"], "locations": [(10, 17)], }, { "message": str(promise_error), "path": ["promiseNest", "promise"], "locations": [(11, 17)], }, { "message": str(sync_error), "path": ["promiseNest", "syncNest", "sync"], "locations": [(12, 28)], }, { "message": str(promise_error), "path": ["promiseNest", "syncNest", "promise"], "locations": [(12, 33)], }, { "message": str(sync_error), "path": ["promiseNest", "promiseNest", "sync"], "locations": [(13, 31)], }, { "message": str(promise_error), "path": ["promiseNest", "promiseNest", "promise"], "locations": [(13, 36)], }, ], ) def describe_nulls_first_nullable_after_long_chain_of_non_null_fields(): query = """ { syncNest { syncNonNullNest { promiseNonNullNest { syncNonNullNest { promiseNonNullNest { syncNonNull } } } } } promiseNest { syncNonNullNest { promiseNonNullNest { syncNonNullNest { promiseNonNullNest { syncNonNull } } } } } anotherNest: syncNest { syncNonNullNest { promiseNonNullNest { syncNonNullNest { promiseNonNullNest { promiseNonNull } } } } } anotherPromiseNest: promiseNest { syncNonNullNest { promiseNonNullNest { syncNonNullNest { promiseNonNullNest { promiseNonNull } } } } } } """ data = { "syncNest": None, "promiseNest": None, "anotherNest": None, "anotherPromiseNest": None, } @mark.asyncio async def returns_null(): result = await cast( Awaitable[ExecutionResult], execute_query(query, NullingData()) ) assert result == ( data, [ { "message": "Cannot return null for non-nullable field" " DataType.syncNonNull.", "path": [ "syncNest", "syncNonNullNest", "promiseNonNullNest", "syncNonNullNest", "promiseNonNullNest", "syncNonNull", ], "locations": [(8, 25)], }, { "message": "Cannot return null for non-nullable field" " DataType.syncNonNull.", "path": [ "promiseNest", "syncNonNullNest", "promiseNonNullNest", "syncNonNullNest", "promiseNonNullNest", "syncNonNull", ], "locations": [(19, 25)], }, { "message": "Cannot return null for non-nullable field" " DataType.promiseNonNull.", "path": [ "anotherNest", "syncNonNullNest", "promiseNonNullNest", "syncNonNullNest", "promiseNonNullNest", "promiseNonNull", ], "locations": [(30, 25)], }, { "message": "Cannot return null for non-nullable field" " DataType.promiseNonNull.", "path": [ "anotherPromiseNest", "syncNonNullNest", "promiseNonNullNest", "syncNonNullNest", "promiseNonNullNest", "promiseNonNull", ], "locations": [(41, 25)], }, ], ) @mark.asyncio async def throws(): result = await cast( Awaitable[ExecutionResult], execute_query(query, ThrowingData()) ) assert result == ( data, [ { "message": str(sync_non_null_error), "path": [ "syncNest", "syncNonNullNest", "promiseNonNullNest", "syncNonNullNest", "promiseNonNullNest", "syncNonNull", ], "locations": [(8, 25)], }, { "message": str(sync_non_null_error), "path": [ "promiseNest", "syncNonNullNest", "promiseNonNullNest", "syncNonNullNest", "promiseNonNullNest", "syncNonNull", ], "locations": [(19, 25)], }, { "message": str(promise_non_null_error), "path": [ "anotherNest", "syncNonNullNest", "promiseNonNullNest", "syncNonNullNest", "promiseNonNullNest", "promiseNonNull", ], "locations": [(30, 25)], }, { "message": str(promise_non_null_error), "path": [ "anotherPromiseNest", "syncNonNullNest", "promiseNonNullNest", "syncNonNullNest", "promiseNonNullNest", "promiseNonNull", ], "locations": [(41, 25)], }, ], ) def describe_nulls_the_top_level_if_non_nullable_field(): query = """ { syncNonNull } """ @mark.asyncio async def returns_null(): result = await execute_sync_and_async(query, NullingData()) assert result == ( None, [ { "message": "Cannot return null for non-nullable field" " DataType.syncNonNull.", "path": ["syncNonNull"], "locations": [(3, 17)], } ], ) @mark.asyncio async def throws(): result = await execute_sync_and_async(query, ThrowingData()) assert result == ( None, [ { "message": str(sync_non_null_error), "path": ["syncNonNull"], "locations": [(3, 17)], } ], ) def describe_handles_non_null_argument(): # noinspection PyPep8Naming schema_with_non_null_arg = GraphQLSchema( GraphQLObjectType( "Query", { "withNonNullArg": GraphQLField( GraphQLString, args={ "cannotBeNull": GraphQLArgument( GraphQLNonNull(GraphQLString) ) }, resolve=lambda _obj, _info, cannotBeNull: "Passed: " + str(cannotBeNull), ) }, ) ) def succeeds_when_passed_non_null_literal_value(): result = execute_sync( schema_with_non_null_arg, parse( """ query { withNonNullArg (cannotBeNull: "literal value") } """ ), ) assert result == ({"withNonNullArg": "Passed: literal value"}, None) def succeeds_when_passed_non_null_variable_value(): result = execute_sync( schema_with_non_null_arg, parse( """ query ($testVar: String!) { withNonNullArg (cannotBeNull: $testVar) } """ ), variable_values={ "testVar": "variable value", }, ) assert result == ({"withNonNullArg": "Passed: variable value"}, None) def succeeds_when_missing_variable_has_default_value(): result = execute_sync( schema_with_non_null_arg, parse( """ query ($testVar: String = "default value") { withNonNullArg (cannotBeNull: $testVar) } """ ), variable_values={}, # intentionally missing variable ) assert result == ({"withNonNullArg": "Passed: default value"}, None) def field_error_when_missing_non_null_arg(): # Note: validation should identify this issue first # (missing args rule) however execution should still # protect against this. result = execute_sync( schema_with_non_null_arg, parse( """ query { withNonNullArg } """ ), ) assert result == ( {"withNonNullArg": None}, [ { "message": "Argument 'cannotBeNull' of required type" " 'String!' was not provided.", "locations": [(3, 23)], "path": ["withNonNullArg"], } ], ) def field_error_when_non_null_arg_provided_null(): # Note: validation should identify this issue first # (values of correct type rule) however execution # should still protect against this. result = execute_sync( schema_with_non_null_arg, parse( """ query { withNonNullArg(cannotBeNull: null) } """ ), ) assert result == ( {"withNonNullArg": None}, [ { "message": "Argument 'cannotBeNull' of non-null type" " 'String!' must not be null.", "locations": [(3, 52)], "path": ["withNonNullArg"], } ], ) def field_error_when_non_null_arg_not_provided_variable_value(): # Note: validation should identify this issue first # (variables in allowed position rule) however execution # should still protect against this. result = execute_sync( schema_with_non_null_arg, parse( """ query ($testVar: String) { withNonNullArg(cannotBeNull: $testVar) } """ ), variable_values={}, ) # intentionally missing variable assert result == ( {"withNonNullArg": None}, [ { "message": "Argument 'cannotBeNull' of required type" " 'String!' was provided the variable" " '$testVar' which was not provided" " a runtime value.", "locations": [(3, 52)], "path": ["withNonNullArg"], } ], ) def field_error_when_non_null_arg_provided_explicit_null_variable(): result = execute_sync( schema_with_non_null_arg, parse( """ query ($testVar: String = "default value") { withNonNullArg (cannotBeNull: $testVar) } """ ), variable_values={"testVar": None}, ) assert result == ( {"withNonNullArg": None}, [ { "message": "Argument 'cannotBeNull' of non-null type" " 'String!' must not be null.", "locations": [(3, 53)], "path": ["withNonNullArg"], } ], ) graphql-core-3.2.6/tests/execution/test_parallel.py000066400000000000000000000102611474546154300224750ustar00rootroot00000000000000import asyncio from typing import Awaitable from pytest import mark from graphql.execution import execute from graphql.language import parse from graphql.type import ( GraphQLSchema, GraphQLObjectType, GraphQLField, GraphQLList, GraphQLInterfaceType, GraphQLBoolean, GraphQLInt, GraphQLString, ) class Barrier: """Barrier that makes progress only after a certain number of waits.""" def __init__(self, number: int): self.event = asyncio.Event() self.number = number async def wait(self) -> bool: self.number -= 1 if not self.number: self.event.set() return await self.event.wait() def describe_parallel_execution(): @mark.asyncio async def resolve_fields_in_parallel(): barrier = Barrier(2) async def resolve(*_args): return await barrier.wait() schema = GraphQLSchema( GraphQLObjectType( "Query", { "foo": GraphQLField(GraphQLBoolean, resolve=resolve), "bar": GraphQLField(GraphQLBoolean, resolve=resolve), }, ) ) ast = parse("{foo, bar}") # raises TimeoutError if not parallel awaitable_result = execute(schema, ast) assert isinstance(awaitable_result, Awaitable) result = await asyncio.wait_for(awaitable_result, 1.0) assert result == ({"foo": True, "bar": True}, None) @mark.asyncio async def resolve_list_in_parallel(): barrier = Barrier(2) async def resolve(*_args): return await barrier.wait() async def resolve_list(*args): return [resolve(*args), resolve(*args)] schema = GraphQLSchema( GraphQLObjectType( "Query", { "foo": GraphQLField( GraphQLList(GraphQLBoolean), resolve=resolve_list ) }, ) ) ast = parse("{foo}") # raises TimeoutError if not parallel awaitable_result = execute(schema, ast) assert isinstance(awaitable_result, Awaitable) result = await asyncio.wait_for(awaitable_result, 1.0) assert result == ({"foo": [True, True]}, None) @mark.asyncio async def resolve_is_type_of_in_parallel(): FooType = GraphQLInterfaceType("Foo", {"foo": GraphQLField(GraphQLString)}) barrier = Barrier(4) async def is_type_of_bar(obj, *_args): await barrier.wait() return obj["foo"] == "bar" BarType = GraphQLObjectType( "Bar", {"foo": GraphQLField(GraphQLString), "foobar": GraphQLField(GraphQLInt)}, interfaces=[FooType], is_type_of=is_type_of_bar, ) async def is_type_of_baz(obj, *_args): await barrier.wait() return obj["foo"] == "baz" BazType = GraphQLObjectType( "Baz", {"foo": GraphQLField(GraphQLString), "foobaz": GraphQLField(GraphQLInt)}, interfaces=[FooType], is_type_of=is_type_of_baz, ) schema = GraphQLSchema( GraphQLObjectType( "Query", { "foo": GraphQLField( GraphQLList(FooType), resolve=lambda *_args: [ {"foo": "bar", "foobar": 1}, {"foo": "baz", "foobaz": 2}, ], ) }, ), types=[BarType, BazType], ) ast = parse( """ { foo { foo ... on Bar { foobar } ... on Baz { foobaz } } } """ ) # raises TimeoutError if not parallel awaitable_result = execute(schema, ast) assert isinstance(awaitable_result, Awaitable) result = await asyncio.wait_for(awaitable_result, 1.0) assert result == ( {"foo": [{"foo": "bar", "foobar": 1}, {"foo": "baz", "foobaz": 2}]}, None, ) graphql-core-3.2.6/tests/execution/test_resolve.py000066400000000000000000000252161474546154300223660ustar00rootroot00000000000000from collections import ChainMap from typing import Any from graphql.error import GraphQLError from graphql.execution import ExecutionResult, execute_sync from graphql.language import SourceLocation, parse from graphql.type import ( GraphQLArgument, GraphQLField, GraphQLID, GraphQLInputField, GraphQLInputObjectType, GraphQLInt, GraphQLList, GraphQLObjectType, GraphQLSchema, GraphQLString, ) def describe_execute_resolve_function(): def _test_schema(test_field: GraphQLField) -> GraphQLSchema: return GraphQLSchema(GraphQLObjectType("Query", {"test": test_field})) def default_function_accesses_attributes(): class RootValue: test = "testValue" assert execute_sync( schema=_test_schema(GraphQLField(GraphQLString)), document=parse("{ test }"), root_value=RootValue(), ) == ( {"test": "testValue"}, None, ) def default_function_accesses_keys_of_dict(): root_value = {"test": "testValue"} assert execute_sync( schema=_test_schema(GraphQLField(GraphQLString)), document=parse("{ test }"), root_value=root_value, ) == ({"test": "testValue"}, None) def default_function_accesses_keys_of_chain_map(): # use a mapping that is not a subclass of dict root_value = ChainMap({"test": "testValue"}) assert execute_sync( schema=_test_schema(GraphQLField(GraphQLString)), document=parse("{ test }"), root_value=root_value, ) == ({"test": "testValue"}, None) def default_function_calls_methods(): class RootValue: _secret = "secretValue" def test(self, _info): return self._secret assert execute_sync( schema=_test_schema(GraphQLField(GraphQLString)), document=parse("{ test }"), root_value=RootValue(), ) == ( {"test": "secretValue"}, None, ) def default_function_passes_args_and_context(): class Adder: _num: int def __init__(self, num): self._num = num def test(self, info, addend1: int): return self._num + addend1 + info.context.addend2 root_value = Adder(700) schema = _test_schema( GraphQLField(GraphQLInt, args={"addend1": GraphQLArgument(GraphQLInt)}) ) class ContextValue: addend2 = 9 context_value = ContextValue() document = parse("{ test(addend1: 80) }") assert execute_sync( schema=schema, document=document, root_value=root_value, context_value=context_value, ) == ( {"test": 789}, None, ) def uses_provided_resolve_function(): schema = _test_schema( GraphQLField( GraphQLString, args={ "aStr": GraphQLArgument(GraphQLString), "aInt": GraphQLArgument(GraphQLInt), }, resolve=lambda source, info, **args: repr([source, args]), ) ) def execute_query(query: str, root_value: Any = None) -> ExecutionResult: document = parse(query) return execute_sync( schema=schema, document=document, root_value=root_value, ) assert execute_query("{ test }") == ({"test": "[None, {}]"}, None) assert execute_query("{ test }", "Source!") == ( {"test": "['Source!', {}]"}, None, ) assert execute_query('{ test(aStr: "String!") }', "Source!") == ( {"test": "['Source!', {'aStr': 'String!'}]"}, None, ) assert execute_query('{ test(aInt: -123, aStr: "String!") }', "Source!") == ( {"test": "['Source!', {'aStr': 'String!', 'aInt': -123}]"}, None, ) def transforms_arguments_using_out_names(): # This is an extension of GraphQL.js. schema = _test_schema( GraphQLField( GraphQLString, args={ "aStr": GraphQLArgument(GraphQLString, out_name="a_str"), "aInt": GraphQLArgument(GraphQLInt, out_name="a_int"), }, resolve=lambda source, info, **args: repr([source, args]), ) ) def execute_query(query: str, root_value: Any = None) -> ExecutionResult: document = parse(query) return execute_sync(schema=schema, document=document, root_value=root_value) assert execute_query("{ test }") == ({"test": "[None, {}]"}, None) assert execute_query("{ test }", "Source!") == ( {"test": "['Source!', {}]"}, None, ) assert execute_query('{ test(aStr: "String!") }', "Source!") == ( {"test": "['Source!', {'a_str': 'String!'}]"}, None, ) assert execute_query('{ test(aInt: -123, aStr: "String!") }', "Source!") == ( {"test": "['Source!', {'a_str': 'String!', 'a_int': -123}]"}, None, ) def transforms_arguments_with_inputs_using_out_names(): # This is an extension of GraphQL.js. TestInputObject = GraphQLInputObjectType( "TestInputObjectType", lambda: { "inputOne": GraphQLInputField(GraphQLString, out_name="input_one"), "inputRecursive": GraphQLInputField( TestInputObject, out_name="input_recursive" ), }, ) schema = _test_schema( GraphQLField( GraphQLString, args={"aInput": GraphQLArgument(TestInputObject, out_name="a_input")}, resolve=lambda source, info, **args: repr([source, args]), ) ) def execute_query(query: str, root_value: Any = None) -> ExecutionResult: document = parse(query) return execute_sync(schema=schema, document=document, root_value=root_value) assert execute_query("{ test }") == ({"test": "[None, {}]"}, None) assert execute_query('{ test(aInput: {inputOne: "String!"}) }', "Source!") == ( {"test": "['Source!', {'a_input': {'input_one': 'String!'}}]"}, None, ) assert execute_query( '{ test(aInput: {inputRecursive: {inputOne: "SourceRecursive!"}}) }', "Source!", ) == ( { "test": "['Source!'," " {'a_input': {'input_recursive': {'input_one': 'SourceRecursive!'}}}]" }, None, ) def transforms_default_values_using_out_names(): # This is an extension of GraphQL.js. resolver_kwargs: Any def search_resolver(_obj: None, _info, **kwargs): nonlocal resolver_kwargs resolver_kwargs = kwargs return [{"id": "42"}] filters_type = GraphQLInputObjectType( "SearchFilters", {"pageSize": GraphQLInputField(GraphQLInt, out_name="page_size")}, ) result_type = GraphQLObjectType("SearchResult", {"id": GraphQLField(GraphQLID)}) query = GraphQLObjectType( "Query", { "search": GraphQLField( GraphQLList(result_type), { "searchFilters": GraphQLArgument( filters_type, {"pageSize": 10}, out_name="search_filters" ) }, resolve=search_resolver, ) }, ) schema = GraphQLSchema(query) resolver_kwargs = None result = execute_sync(schema, parse("{ search { id } }")) assert result == ({"search": [{"id": "42"}]}, None) assert resolver_kwargs == {"search_filters": {"page_size": 10}} resolver_kwargs = None result = execute_sync( schema, parse("{ search(searchFilters:{pageSize: 25}) { id } }") ) assert result == ({"search": [{"id": "42"}]}, None) assert resolver_kwargs == {"search_filters": {"page_size": 25}} resolver_kwargs = None result = execute_sync( schema, parse( """ query ($searchFilters: SearchFilters) { search(searchFilters: $searchFilters) { id } } """ ), ) assert result == ({"search": [{"id": "42"}]}, None) assert resolver_kwargs == {"search_filters": {"page_size": 10}} resolver_kwargs = None result = execute_sync( schema, parse( """ query ($searchFilters: SearchFilters) { search(searchFilters: $searchFilters) { id } } """ ), variable_values={"searchFilters": {"pageSize": 25}}, ) assert result == ({"search": [{"id": "42"}]}, None) assert resolver_kwargs == {"search_filters": {"page_size": 25}} resolver_kwargs = None result = execute_sync( schema, parse( """ query ($searchFilters: SearchFilters = {pageSize: 25}) { search(searchFilters: $searchFilters) { id } } """ ), ) assert result == ({"search": [{"id": "42"}]}, None) assert resolver_kwargs == {"search_filters": {"page_size": 25}} def pass_error_from_resolver_wrapped_as_located_graphql_error(): def resolve(_obj, _info): raise ValueError("Some error") schema = _test_schema(GraphQLField(GraphQLString, resolve=resolve)) result = execute_sync(schema, parse("{ test }")) assert result == ( {"test": None}, [{"message": "Some error", "locations": [(1, 3)], "path": ["test"]}], ) assert result.errors is not None error = result.errors[0] assert isinstance(error, GraphQLError) assert str(error) == "Some error\n\nGraphQL request:1:3\n1 | { test }\n | ^" assert error.positions == [2] locations = error.locations assert locations == [(1, 3)] location = locations[0] assert isinstance(location, SourceLocation) assert location == SourceLocation(1, 3) original_error = error.original_error assert isinstance(original_error, ValueError) assert str(original_error) == "Some error" graphql-core-3.2.6/tests/execution/test_schema.py000066400000000000000000000134631474546154300221500ustar00rootroot00000000000000from graphql.execution import execute_sync from graphql.language import parse from graphql.type import ( GraphQLArgument, GraphQLBoolean, GraphQLField, GraphQLID, GraphQLInt, GraphQLList, GraphQLNonNull, GraphQLObjectType, GraphQLSchema, GraphQLString, ) def describe_execute_handles_execution_with_a_complex_schema(): def executes_using_a_schema(): class Article: # noinspection PyShadowingBuiltins def __init__(self, id: int): self.id = id self.isPublished = True self.author = JohnSmith() self.title = f"My Article {id}" self.body = "This is a post" self.hidden = "This data is not exposed in the schema" self.keywords = ["foo", "bar", 1, True, None] BlogImage = GraphQLObjectType( "Image", { "url": GraphQLField(GraphQLString), "width": GraphQLField(GraphQLInt), "height": GraphQLField(GraphQLInt), }, ) BlogArticle: GraphQLObjectType BlogAuthor = GraphQLObjectType( "Author", lambda: { "id": GraphQLField(GraphQLString), "name": GraphQLField(GraphQLString), "pic": GraphQLField( BlogImage, args={ "width": GraphQLArgument(GraphQLInt), "height": GraphQLArgument(GraphQLInt), }, resolve=lambda obj, info, width, height: obj.pic( info, width, height ), ), "recentArticle": GraphQLField(BlogArticle), }, ) BlogArticle = GraphQLObjectType( "Article", { "id": GraphQLField(GraphQLNonNull(GraphQLString)), "isPublished": GraphQLField(GraphQLBoolean), "author": GraphQLField(BlogAuthor), "title": GraphQLField(GraphQLString), "body": GraphQLField(GraphQLString), "keywords": GraphQLField(GraphQLList(GraphQLString)), }, ) # noinspection PyShadowingBuiltins BlogQuery = GraphQLObjectType( "Query", { "article": GraphQLField( BlogArticle, args={"id": GraphQLArgument(GraphQLID)}, resolve=lambda _obj, _info, id: Article(id), ), "feed": GraphQLField( GraphQLList(BlogArticle), resolve=lambda *_args: [Article(n + 1) for n in range(10)], ), }, ) BlogSchema = GraphQLSchema(BlogQuery) # noinspection PyPep8Naming,PyMethodMayBeStatic class Author: def pic(self, info_, width: int, height: int) -> "Pic": return Pic(123, width, height) @property def recentArticle(self) -> Article: return Article(1) class JohnSmith(Author): id = 123 name = "John Smith" class Pic: def __init__(self, uid: int, width: int, height: int): self.url = f"cdn://{uid}" self.width = f"{width}" self.height = f"{height}" document = parse( """ { feed { id, title }, article(id: "1") { ...articleFields, author { id, name, pic(width: 640, height: 480) { url, width, height }, recentArticle { ...articleFields, keywords } } } } fragment articleFields on Article { id, isPublished, title, body, hidden, notDefined } """ ) # Note: this is intentionally not validating to ensure appropriate # behavior occurs when executing an invalid query. assert execute_sync(schema=BlogSchema, document=document) == ( { "feed": [ {"id": "1", "title": "My Article 1"}, {"id": "2", "title": "My Article 2"}, {"id": "3", "title": "My Article 3"}, {"id": "4", "title": "My Article 4"}, {"id": "5", "title": "My Article 5"}, {"id": "6", "title": "My Article 6"}, {"id": "7", "title": "My Article 7"}, {"id": "8", "title": "My Article 8"}, {"id": "9", "title": "My Article 9"}, {"id": "10", "title": "My Article 10"}, ], "article": { "id": "1", "isPublished": True, "title": "My Article 1", "body": "This is a post", "author": { "id": "123", "name": "John Smith", "pic": {"url": "cdn://123", "width": 640, "height": 480}, "recentArticle": { "id": "1", "isPublished": True, "title": "My Article 1", "body": "This is a post", "keywords": ["foo", "bar", "1", "true", None], }, }, }, }, None, ) graphql-core-3.2.6/tests/execution/test_subscribe.py000066400000000000000000000644471474546154300227010ustar00rootroot00000000000000import asyncio from typing import Any, Callable, Dict, List from graphql.execution import ( ExecutionResult, MapAsyncIterator, create_source_event_stream, subscribe, ) from graphql.language import parse from graphql.pyutils import SimplePubSub from graphql.type import ( GraphQLArgument, GraphQLBoolean, GraphQLField, GraphQLInt, GraphQLList, GraphQLObjectType, GraphQLSchema, GraphQLString, ) from pytest import mark, raises try: anext # type: ignore except NameError: # pragma: no cover (Python < 3.10) # noinspection PyShadowingBuiltins async def anext(iterator): """Return the next item from an async iterator.""" return await iterator.__anext__() Email = Dict # should become a TypedDict once we require Python 3.8 EmailType = GraphQLObjectType( "Email", { "from": GraphQLField(GraphQLString), "subject": GraphQLField(GraphQLString), "message": GraphQLField(GraphQLString), "unread": GraphQLField(GraphQLBoolean), }, ) InboxType = GraphQLObjectType( "Inbox", { "total": GraphQLField( GraphQLInt, resolve=lambda inbox, _info: len(inbox["emails"]) ), "unread": GraphQLField( GraphQLInt, resolve=lambda inbox, _info: sum( 1 for email in inbox["emails"] if email["unread"] ), ), "emails": GraphQLField(GraphQLList(EmailType)), }, ) QueryType = GraphQLObjectType("Query", {"inbox": GraphQLField(InboxType)}) EmailEventType = GraphQLObjectType( "EmailEvent", {"email": GraphQLField(EmailType), "inbox": GraphQLField(InboxType)} ) email_schema = GraphQLSchema( query=QueryType, subscription=GraphQLObjectType( "Subscription", { "importantEmail": GraphQLField( EmailEventType, args={"priority": GraphQLArgument(GraphQLInt)}, ) }, ), ) def create_subscription(pubsub: SimplePubSub): document = parse( """ subscription ($priority: Int = 0) { importantEmail(priority: $priority) { email { from subject } inbox { unread total } } } """ ) emails: List[Email] = [ { "from": "joe@graphql.org", "subject": "Hello", "message": "Hello World", "unread": False, } ] def transform(new_email): emails.append(new_email) return {"importantEmail": {"email": new_email, "inbox": data["inbox"]}} data: Dict[str, Any] = { "inbox": {"emails": emails}, "importantEmail": pubsub.get_subscriber(transform), } return subscribe(email_schema, document, data) DummyQueryType = GraphQLObjectType("Query", {"dummy": GraphQLField(GraphQLString)}) # Check all error cases when initializing the subscription. def describe_subscription_initialization_phase(): @mark.asyncio async def accepts_positional_arguments(): document = parse( """ subscription { importantEmail } """ ) async def empty_async_iterator(_info): for value in (): # type: ignore yield value # pragma: no cover ai = await subscribe( email_schema, document, {"importantEmail": empty_async_iterator} ) with raises(StopAsyncIteration): await anext(ai) await ai.aclose() # type: ignore @mark.asyncio async def accepts_multiple_subscription_fields_defined_in_schema(): schema = GraphQLSchema( query=DummyQueryType, subscription=GraphQLObjectType( "Subscription", { "foo": GraphQLField(GraphQLString), "bar": GraphQLField(GraphQLString), }, ), ) async def foo_generator(_info): yield {"foo": "FooValue"} subscription = await subscribe( schema, parse("subscription { foo }"), {"foo": foo_generator} ) assert isinstance(subscription, MapAsyncIterator) assert await anext(subscription) == ({"foo": "FooValue"}, None) await subscription.aclose() @mark.asyncio async def accepts_type_definition_with_sync_subscribe_function(): async def foo_generator(_obj, _info): yield {"foo": "FooValue"} schema = GraphQLSchema( query=DummyQueryType, subscription=GraphQLObjectType( "Subscription", {"foo": GraphQLField(GraphQLString, subscribe=foo_generator)}, ), ) subscription = await subscribe(schema, parse("subscription { foo }")) assert isinstance(subscription, MapAsyncIterator) assert await anext(subscription) == ({"foo": "FooValue"}, None) await subscription.aclose() @mark.asyncio async def accepts_type_definition_with_async_subscribe_function(): async def foo_generator(_obj, _info): await asyncio.sleep(0) yield {"foo": "FooValue"} schema = GraphQLSchema( query=DummyQueryType, subscription=GraphQLObjectType( "Subscription", {"foo": GraphQLField(GraphQLString, subscribe=foo_generator)}, ), ) subscription = await subscribe(schema, parse("subscription { foo }")) assert isinstance(subscription, MapAsyncIterator) assert await anext(subscription) == ({"foo": "FooValue"}, None) await subscription.aclose() @mark.asyncio async def uses_a_custom_default_subscribe_field_resolver(): schema = GraphQLSchema( query=DummyQueryType, subscription=GraphQLObjectType( "Subscription", {"foo": GraphQLField(GraphQLString)} ), ) class Root: @staticmethod async def custom_foo(): yield {"foo": "FooValue"} subscription = await subscribe( schema, document=parse("subscription { foo }"), root_value=Root(), subscribe_field_resolver=lambda root, _info: root.custom_foo(), ) assert isinstance(subscription, MapAsyncIterator) assert await anext(subscription) == ( {"foo": "FooValue"}, None, ) await subscription.aclose() @mark.asyncio async def should_only_resolve_the_first_field_of_invalid_multi_field(): did_resolve = {"foo": False, "bar": False} async def subscribe_foo(_obj, _info): did_resolve["foo"] = True yield {"foo": "FooValue"} async def subscribe_bar(_obj, _info): # pragma: no cover did_resolve["bar"] = True yield {"bar": "BarValue"} schema = GraphQLSchema( query=DummyQueryType, subscription=GraphQLObjectType( "Subscription", { "foo": GraphQLField(GraphQLString, subscribe=subscribe_foo), "bar": GraphQLField(GraphQLString, subscribe=subscribe_bar), }, ), ) subscription = await subscribe(schema, parse("subscription { foo bar }")) assert isinstance(subscription, MapAsyncIterator) assert await anext(subscription) == ( {"foo": "FooValue", "bar": None}, None, ) assert did_resolve == {"foo": True, "bar": False} await subscription.aclose() @mark.asyncio async def throws_an_error_if_some_of_required_arguments_are_missing(): document = parse("subscription { foo }") schema = GraphQLSchema( query=DummyQueryType, subscription=GraphQLObjectType( "Subscription", {"foo": GraphQLField(GraphQLString)} ), ) with raises(TypeError, match="^Expected None to be a GraphQL schema\\.$"): await subscribe(None, document) # type: ignore with raises(TypeError, match="missing .* positional argument: 'schema'"): await subscribe(document=document) # type: ignore with raises(TypeError, match="^Must provide document\\.$"): await subscribe(schema, None) # type: ignore with raises(TypeError, match="missing .* positional argument: 'document'"): await subscribe(schema=schema) # type: ignore @mark.asyncio async def resolves_to_an_error_if_schema_does_not_support_subscriptions(): schema = GraphQLSchema(query=DummyQueryType) document = parse("subscription { unknownField }") result = await subscribe(schema, document) assert result == ( None, [ { "message": "Schema is not configured to execute" " subscription operation.", "locations": [(1, 1)], } ], ) @mark.asyncio async def resolves_to_an_error_for_unknown_subscription_field(): schema = GraphQLSchema( query=DummyQueryType, subscription=GraphQLObjectType( "Subscription", {"foo": GraphQLField(GraphQLString)} ), ) document = parse("subscription { unknownField }") result = await subscribe(schema, document) assert result == ( None, [ { "message": "The subscription field 'unknownField' is not defined.", "locations": [(1, 16)], } ], ) @mark.asyncio async def should_pass_through_unexpected_errors_thrown_in_subscribe(): schema = GraphQLSchema( query=DummyQueryType, subscription=GraphQLObjectType( "Subscription", {"foo": GraphQLField(GraphQLString)} ), ) with raises(TypeError, match="^Must provide document\\.$"): await subscribe(schema=schema, document={}) # type: ignore @mark.asyncio @mark.filterwarnings("ignore:.* was never awaited:RuntimeWarning") async def throws_an_error_if_subscribe_does_not_return_an_iterator(): schema = GraphQLSchema( query=DummyQueryType, subscription=GraphQLObjectType( "Subscription", { "foo": GraphQLField( GraphQLString, subscribe=lambda _obj, _info: "test" ) }, ), ) document = parse("subscription { foo }") with raises(TypeError) as exc_info: await subscribe(schema, document) assert str(exc_info.value) == ( "Subscription field must return AsyncIterable. Received: 'test'." ) @mark.asyncio async def resolves_to_an_error_for_subscription_resolver_errors(): async def subscribe_with_fn(subscribe_fn: Callable): schema = GraphQLSchema( query=DummyQueryType, subscription=GraphQLObjectType( "Subscription", {"foo": GraphQLField(GraphQLString, subscribe=subscribe_fn)}, ), ) document = parse("subscription { foo }") result = await subscribe(schema, document) assert await create_source_event_stream(schema, document) == result return result expected_result = ( None, [ { "message": "test error", "locations": [(1, 16)], "path": ["foo"], } ], ) # Returning an error def return_error(_obj, _info): return TypeError("test error") assert await subscribe_with_fn(return_error) == expected_result # Throwing an error def throw_error(*_args): raise TypeError("test error") assert await subscribe_with_fn(throw_error) == expected_result # Resolving to an error async def resolve_error(*_args): return TypeError("test error") assert await subscribe_with_fn(resolve_error) == expected_result # Rejecting with an error async def reject_error(*_args): return TypeError("test error") assert await subscribe_with_fn(reject_error) == expected_result @mark.asyncio async def resolves_to_an_error_if_variables_were_wrong_type(): schema = GraphQLSchema( query=DummyQueryType, subscription=GraphQLObjectType( "Subscription", { "foo": GraphQLField( GraphQLString, {"arg": GraphQLArgument(GraphQLInt)} ) }, ), ) variable_values = {"arg": "meow"} document = parse( """ subscription ($arg: Int) { foo(arg: $arg) } """ ) # If we receive variables that cannot be coerced correctly, subscribe() will # resolve to an ExecutionResult that contains an informative error description. result = await subscribe(schema, document, variable_values=variable_values) assert isinstance(result, ExecutionResult) assert result == ( None, [ { "message": "Variable '$arg' got invalid value 'meow';" " Int cannot represent non-integer value: 'meow'", "locations": [(2, 27)], } ], ) errors = result.errors assert errors assert errors[0].original_error # Once a subscription returns a valid AsyncIterator, it can still yield errors. def describe_subscription_publish_phase(): @mark.asyncio async def produces_a_payload_for_multiple_subscribe_in_same_subscription(): pubsub = SimplePubSub() subscription = await create_subscription(pubsub) assert isinstance(subscription, MapAsyncIterator) second_subscription = await create_subscription(pubsub) assert isinstance(subscription, MapAsyncIterator) payload1 = anext(subscription) payload2 = anext(second_subscription) assert ( pubsub.emit( { "from": "yuzhi@graphql.org", "subject": "Alright", "message": "Tests are good", "unread": True, } ) is True ) expected_payload = { "importantEmail": { "email": {"from": "yuzhi@graphql.org", "subject": "Alright"}, "inbox": {"unread": 1, "total": 2}, } } assert await payload1 == (expected_payload, None) assert await payload2 == (expected_payload, None) @mark.asyncio async def produces_a_payload_per_subscription_event(): pubsub = SimplePubSub() subscription = await create_subscription(pubsub) assert isinstance(subscription, MapAsyncIterator) # Wait for the next subscription payload. payload = anext(subscription) # A new email arrives! assert ( pubsub.emit( { "from": "yuzhi@graphql.org", "subject": "Alright", "message": "Tests are good", "unread": True, } ) is True ) # The previously waited on payload now has a value. assert await payload == ( { "importantEmail": { "email": {"from": "yuzhi@graphql.org", "subject": "Alright"}, "inbox": {"unread": 1, "total": 2}, } }, None, ) # Another new email arrives, before anext(subscription) is called. assert ( pubsub.emit( { "from": "hyo@graphql.org", "subject": "Tools", "message": "I <3 making things", "unread": True, } ) is True ) # The next waited on payload will have a value. assert await anext(subscription) == ( { "importantEmail": { "email": {"from": "hyo@graphql.org", "subject": "Tools"}, "inbox": {"unread": 2, "total": 3}, } }, None, ) # The client decides to disconnect. # noinspection PyUnresolvedReferences await subscription.aclose() # Which may result in disconnecting upstream services as well. assert ( pubsub.emit( { "from": "adam@graphql.org", "subject": "Important", "message": "Read me please", "unread": True, } ) is False ) # No more listeners. # Awaiting subscription after closing it results in completed results. with raises(StopAsyncIteration): assert await anext(subscription) @mark.asyncio async def produces_a_payload_when_there_are_multiple_events(): pubsub = SimplePubSub() subscription = await create_subscription(pubsub) assert isinstance(subscription, MapAsyncIterator) payload = anext(subscription) # A new email arrives! assert ( pubsub.emit( { "from": "yuzhi@graphql.org", "subject": "Alright", "message": "Tests are good", "unread": True, } ) is True ) assert await payload == ( { "importantEmail": { "email": {"from": "yuzhi@graphql.org", "subject": "Alright"}, "inbox": {"unread": 1, "total": 2}, } }, None, ) payload = anext(subscription) # A new email arrives! assert ( pubsub.emit( { "from": "yuzhi@graphql.org", "subject": "Alright 2", "message": "Tests are good 2", "unread": True, } ) is True ) assert await payload == ( { "importantEmail": { "email": {"from": "yuzhi@graphql.org", "subject": "Alright 2"}, "inbox": {"unread": 2, "total": 3}, } }, None, ) @mark.asyncio async def should_not_trigger_when_subscription_is_already_done(): pubsub = SimplePubSub() subscription = await create_subscription(pubsub) assert isinstance(subscription, MapAsyncIterator) payload = anext(subscription) # A new email arrives! assert ( pubsub.emit( { "from": "yuzhi@graphql.org", "subject": "Alright", "message": "Tests are good", "unread": True, } ) is True ) assert await payload == ( { "importantEmail": { "email": {"from": "yuzhi@graphql.org", "subject": "Alright"}, "inbox": {"unread": 1, "total": 2}, } }, None, ) payload = anext(subscription) await subscription.aclose() # A new email arrives! assert ( pubsub.emit( { "from": "yuzhi@graphql.org", "subject": "Alright 2", "message": "Tests are good 2", "unread": True, } ) is False ) with raises(StopAsyncIteration): await payload @mark.asyncio async def should_not_trigger_when_subscription_is_thrown(): pubsub = SimplePubSub() subscription = await create_subscription(pubsub) assert isinstance(subscription, MapAsyncIterator) payload = anext(subscription) # A new email arrives! assert ( pubsub.emit( { "from": "yuzhi@graphql.org", "subject": "Alright", "message": "Tests are good", "unread": True, } ) is True ) assert await payload == ( { "importantEmail": { "email": {"from": "yuzhi@graphql.org", "subject": "Alright"}, "inbox": {"unread": 1, "total": 2}, } }, None, ) payload = anext(subscription) # Throw error with raises(RuntimeError) as exc_info: await subscription.athrow(RuntimeError("ouch")) assert str(exc_info.value) == "ouch" with raises(StopAsyncIteration): await payload @mark.asyncio async def event_order_is_correct_for_multiple_publishes(): pubsub = SimplePubSub() subscription = await create_subscription(pubsub) assert isinstance(subscription, MapAsyncIterator) payload = anext(subscription) # A new email arrives! assert ( pubsub.emit( { "from": "yuzhi@graphql.org", "subject": "Message", "message": "Tests are good", "unread": True, } ) is True ) # A new email arrives! assert ( pubsub.emit( { "from": "yuzhi@graphql.org", "subject": "Message 2", "message": "Tests are good 2", "unread": True, } ) is True ) assert await payload == ( { "importantEmail": { "email": {"from": "yuzhi@graphql.org", "subject": "Message"}, "inbox": {"unread": 2, "total": 3}, } }, None, ) payload = anext(subscription) assert await payload == ( { "importantEmail": { "email": {"from": "yuzhi@graphql.org", "subject": "Message 2"}, "inbox": {"unread": 2, "total": 3}, } }, None, ) @mark.asyncio async def should_handle_error_during_execution_of_source_event(): async def generate_messages(_obj, _info): yield "Hello" yield "Goodbye" yield "Bonjour" def resolve_message(message, _info): if message == "Goodbye": raise RuntimeError("Never leave.") return message schema = GraphQLSchema( query=DummyQueryType, subscription=GraphQLObjectType( "Subscription", { "newMessage": GraphQLField( GraphQLString, subscribe=generate_messages, resolve=resolve_message, ) }, ), ) document = parse("subscription { newMessage }") subscription = await subscribe(schema, document) assert isinstance(subscription, MapAsyncIterator) assert await anext(subscription) == ({"newMessage": "Hello"}, None) # An error in execution is presented as such. assert await anext(subscription) == ( {"newMessage": None}, [ { "message": "Never leave.", "locations": [(1, 16)], "path": ["newMessage"], } ], ) # However that does not close the response event stream. # Subsequent events are still executed. assert await anext(subscription) == ({"newMessage": "Bonjour"}, None) @mark.asyncio async def should_pass_through_error_thrown_in_source_event_stream(): async def generate_messages(_obj, _info): yield "Hello" raise RuntimeError("test error") def resolve_message(message, _info): return message schema = GraphQLSchema( query=DummyQueryType, subscription=GraphQLObjectType( "Subscription", { "newMessage": GraphQLField( GraphQLString, resolve=resolve_message, subscribe=generate_messages, ) }, ), ) document = parse("subscription { newMessage }") subscription = await subscribe(schema, document) assert isinstance(subscription, MapAsyncIterator) assert await anext(subscription) == ({"newMessage": "Hello"}, None) with raises(RuntimeError) as exc_info: await anext(subscription) assert str(exc_info.value) == "test error" with raises(StopAsyncIteration): await anext(subscription) @mark.asyncio async def should_work_with_async_resolve_function(): async def generate_messages(_obj, _info): yield "Hello" def resolve_message(message, _info): return message schema = GraphQLSchema( query=QueryType, subscription=GraphQLObjectType( "Subscription", { "newMessage": GraphQLField( GraphQLString, resolve=resolve_message, subscribe=generate_messages, ) }, ), ) document = parse("subscription { newMessage }") subscription = await subscribe(schema, document) assert isinstance(subscription, MapAsyncIterator) assert await anext(subscription) == ({"newMessage": "Hello"}, None) graphql-core-3.2.6/tests/execution/test_sync.py000066400000000000000000000156411474546154300216640ustar00rootroot00000000000000from gc import collect from inspect import isawaitable from pytest import mark, raises from graphql import graphql_sync from graphql.execution import execute, execute_sync from graphql.language import parse from graphql.type import GraphQLField, GraphQLObjectType, GraphQLSchema, GraphQLString from graphql.validation import validate def describe_execute_synchronously_when_possible(): def _resolve_sync(root_value, _info): return root_value async def _resolve_async(root_value, _info): return root_value schema = GraphQLSchema( GraphQLObjectType( "Query", { "syncField": GraphQLField(GraphQLString, resolve=_resolve_sync), "asyncField": GraphQLField(GraphQLString, resolve=_resolve_async), }, ), GraphQLObjectType( "Mutation", {"syncMutationField": GraphQLField(GraphQLString, resolve=_resolve_sync)}, ), ) def does_not_return_an_awaitable_for_initial_errors(): doc = "fragment Example on Query { syncField }" assert execute(schema, parse(doc), "rootValue") == ( None, [{"message": "Must provide an operation."}], ) def does_not_return_an_awaitable_if_fields_are_all_synchronous(): doc = "query Example { syncField }" assert execute(schema, parse(doc), "rootValue") == ( {"syncField": "rootValue"}, None, ) def does_not_return_an_awaitable_if_mutation_fields_are_all_synchronous(): doc = "mutation Example { syncMutationField }" assert execute(schema, parse(doc), "rootValue") == ( {"syncMutationField": "rootValue"}, None, ) @mark.asyncio async def returns_an_awaitable_if_any_field_is_asynchronous(): doc = "query Example { syncField, asyncField }" result = execute(schema, parse(doc), "rootValue") assert isawaitable(result) assert await result == ( {"syncField": "rootValue", "asyncField": "rootValue"}, None, ) def describe_execute_sync(): def does_not_return_an_awaitable_for_sync_execution(): doc = "query Example { syncField }" result = execute_sync(schema, document=parse(doc), root_value="rootValue") assert result == ( {"syncField": "rootValue"}, None, ) def does_not_throw_if_not_encountering_async_execution_with_check_sync(): doc = "query Example { syncField }" result = execute_sync( schema, document=parse(doc), root_value="rootValue", check_sync=True ) assert result == ( {"syncField": "rootValue"}, None, ) @mark.asyncio @mark.filterwarnings("ignore:.* was never awaited:RuntimeWarning") async def throws_if_encountering_async_execution_with_check_sync(): doc = "query Example { syncField, asyncField }" with raises(RuntimeError) as exc_info: execute_sync( schema, document=parse(doc), root_value="rootValue", check_sync=True ) msg = str(exc_info.value) assert msg == "GraphQL execution failed to complete synchronously." @mark.asyncio @mark.filterwarnings("ignore:.* was never awaited:RuntimeWarning") async def throws_if_encountering_async_operation_without_check_sync(): doc = "query Example { syncField, asyncField }" result = execute_sync(schema, document=parse(doc), root_value="rootValue") assert result == ( {"syncField": "rootValue", "asyncField": None}, [ { "message": "String cannot represent value:" " ", "locations": [(1, 28)], "path": ["asyncField"], } ], ) # garbage collect coroutine in order to not postpone the warning del result collect() def describe_graphql_sync(): def reports_errors_raised_during_schema_validation(): bad_schema = GraphQLSchema() result = graphql_sync(schema=bad_schema, source="{ __typename }") assert result == (None, [{"message": "Query root type must be provided."}]) def does_not_return_an_awaitable_for_syntax_errors(): doc = "fragment Example on Query { { { syncField }" assert graphql_sync(schema, doc) == ( None, [ { "message": "Syntax Error: Expected Name, found '{'.", "locations": [(1, 29)], } ], ) def does_not_return_an_awaitable_for_validation_errors(): doc = "fragment Example on Query { unknownField }" validation_errors = validate(schema, parse(doc)) result = graphql_sync(schema, doc) assert result == (None, validation_errors) def does_not_return_an_awaitable_for_sync_execution(): doc = "query Example { syncField }" assert graphql_sync(schema, doc, "rootValue") == ( {"syncField": "rootValue"}, None, ) def does_not_throw_if_not_encountering_async_operation_with_check_sync(): doc = "query Example { syncField }" assert graphql_sync(schema, doc, "rootValue") == ( {"syncField": "rootValue"}, None, ) @mark.asyncio @mark.filterwarnings("ignore:.* was never awaited:RuntimeWarning") async def throws_if_encountering_async_operation_with_check_sync(): doc = "query Example { syncField, asyncField }" with raises(RuntimeError) as exc_info: graphql_sync(schema, doc, "rootValue", check_sync=True) msg = str(exc_info.value) assert msg == "GraphQL execution failed to complete synchronously." @mark.asyncio @mark.filterwarnings("ignore:.* was never awaited:RuntimeWarning") async def throws_if_encountering_async_operation_without_check_sync(): doc = "query Example { syncField, asyncField }" result = graphql_sync(schema, doc, "rootValue") assert result == ( {"syncField": "rootValue", "asyncField": None}, [ { "message": "String cannot represent value:" " ", "locations": [(1, 28)], "path": ["asyncField"], } ], ) # garbage collect coroutine in order to not postpone the warning del result collect() graphql-core-3.2.6/tests/execution/test_union_interface.py000066400000000000000000000350421474546154300240550ustar00rootroot00000000000000from typing import Optional, Union, List from graphql.execution import execute_sync from graphql.language import parse from graphql.type import ( GraphQLBoolean, GraphQLField, GraphQLInterfaceType, GraphQLList, GraphQLObjectType, GraphQLSchema, GraphQLString, GraphQLUnionType, ) class Dog: name: str barks: bool mother: Optional["Dog"] father: Optional["Dog"] progeny: List["Dog"] def __init__(self, name: str, barks: bool): self.name = name self.barks = barks self.mother = None self.father = None self.progeny = [] class Cat: name: str meows: bool mother: Optional["Cat"] father: Optional["Cat"] progeny: List["Cat"] def __init__(self, name: str, meows: bool): self.name = name self.meows = meows self.mother = None self.father = None self.progeny = [] class Person: name: str pets: Optional[List[Union[Dog, Cat]]] friends: Optional[List[Union[Dog, Cat, "Person"]]] def __init__( self, name: str, pets: Optional[List[Union[Dog, Cat]]] = None, friends: Optional[List[Union[Dog, Cat, "Person"]]] = None, ): self.name = name self.pets = pets self.friends = friends NamedType = GraphQLInterfaceType("Named", {"name": GraphQLField(GraphQLString)}) LifeType = GraphQLInterfaceType( "Life", lambda: {"progeny": GraphQLField(GraphQLList(LifeType))} # type: ignore ) MammalType = GraphQLInterfaceType( "Mammal", lambda: { "progeny": GraphQLField(GraphQLList(MammalType)), # type: ignore "mother": GraphQLField(MammalType), # type: ignore "father": GraphQLField(MammalType), # type: ignore }, interfaces=[LifeType], ) DogType = GraphQLObjectType( "Dog", lambda: { "name": GraphQLField(GraphQLString), "barks": GraphQLField(GraphQLBoolean), "progeny": GraphQLField(GraphQLList(DogType)), # type: ignore "mother": GraphQLField(DogType), # type: ignore "father": GraphQLField(DogType), # type: ignore }, interfaces=[MammalType, LifeType, NamedType], is_type_of=lambda value, info: isinstance(value, Dog), ) CatType = GraphQLObjectType( "Cat", lambda: { "name": GraphQLField(GraphQLString), "meows": GraphQLField(GraphQLBoolean), "progeny": GraphQLField(GraphQLList(CatType)), # type: ignore "mother": GraphQLField(CatType), # type: ignore "father": GraphQLField(CatType), # type: ignore }, interfaces=[MammalType, LifeType, NamedType], is_type_of=lambda value, info: isinstance(value, Cat), ) def resolve_pet_type(value, _info, _type): if isinstance(value, Dog): return DogType.name if isinstance(value, Cat): return CatType.name # Not reachable. All possible types have been considered. assert False, "Unexpected pet type" PetType = GraphQLUnionType("Pet", [DogType, CatType], resolve_type=resolve_pet_type) PersonType = GraphQLObjectType( "Person", lambda: { "name": GraphQLField(GraphQLString), "pets": GraphQLField(GraphQLList(PetType)), "friends": GraphQLField(GraphQLList(NamedType)), "progeny": GraphQLField(GraphQLList(PersonType)), # type: ignore "mother": GraphQLField(PersonType), # type: ignore "father": GraphQLField(PersonType), # type: ignore }, interfaces=[NamedType, MammalType, LifeType], is_type_of=lambda value, _info: isinstance(value, Person), ) schema = GraphQLSchema(PersonType, types=[PetType]) garfield = Cat("Garfield", False) garfield.mother = Cat("Garfield's Mom", False) garfield.mother.progeny = [garfield] odie = Dog("Odie", True) odie.mother = Dog("Odie's Mom", True) odie.mother.progeny = [odie] liz = Person("Liz", [], []) john = Person("John", [garfield, odie], [liz, odie]) def describe_execute_union_and_intersection_types(): def can_introspect_on_union_and_intersection_types(): document = parse( """ { Named: __type(name: "Named") { kind name fields { name } interfaces { name } possibleTypes { name } enumValues { name } inputFields { name } } Mammal: __type(name: "Mammal") { kind name fields { name } interfaces { name } possibleTypes { name } enumValues { name } inputFields { name } } Pet: __type(name: "Pet") { kind name fields { name } interfaces { name } possibleTypes { name } enumValues { name } inputFields { name } } } """ ) assert execute_sync(schema=schema, document=document) == ( { "Named": { "kind": "INTERFACE", "name": "Named", "fields": [{"name": "name"}], "interfaces": [], "possibleTypes": [ {"name": "Dog"}, {"name": "Cat"}, {"name": "Person"}, ], "enumValues": None, "inputFields": None, }, "Mammal": { "kind": "INTERFACE", "name": "Mammal", "fields": [ {"name": "progeny"}, {"name": "mother"}, {"name": "father"}, ], "interfaces": [{"name": "Life"}], "possibleTypes": [ {"name": "Dog"}, {"name": "Cat"}, {"name": "Person"}, ], "enumValues": None, "inputFields": None, }, "Pet": { "kind": "UNION", "name": "Pet", "fields": None, "interfaces": None, "possibleTypes": [{"name": "Dog"}, {"name": "Cat"}], "enumValues": None, "inputFields": None, }, }, None, ) def executes_using_union_types(): # NOTE: This is an *invalid* query, but it should be *executable*. document = parse( """ { __typename name pets { __typename name barks meows } } """ ) assert execute_sync(schema=schema, document=document, root_value=john) == ( { "__typename": "Person", "name": "John", "pets": [ {"__typename": "Cat", "name": "Garfield", "meows": False}, {"__typename": "Dog", "name": "Odie", "barks": True}, ], }, None, ) def executes_union_types_with_inline_fragment(): # This is the valid version of the query in the above test. document = parse( """ { __typename name pets { __typename ... on Dog { name barks } ... on Cat { name meows } } } """ ) assert execute_sync(schema=schema, document=document, root_value=john) == ( { "__typename": "Person", "name": "John", "pets": [ {"__typename": "Cat", "name": "Garfield", "meows": False}, {"__typename": "Dog", "name": "Odie", "barks": True}, ], }, None, ) def executes_using_interface_types(): # NOTE: This is an *invalid* query, but it should be a *executable*. document = parse( """ { __typename name friends { __typename name barks meows } } """ ) assert execute_sync(schema=schema, document=document, root_value=john) == ( { "__typename": "Person", "name": "John", "friends": [ {"__typename": "Person", "name": "Liz"}, {"__typename": "Dog", "name": "Odie", "barks": True}, ], }, None, ) def executes_interface_types_with_inline_fragment(): # This is the valid version of the query in the above test. document = parse( """ { __typename name friends { __typename name ... on Dog { barks } ... on Cat { meows } ... on Mammal { mother { __typename ... on Dog { name barks } ... on Cat { name meows } } } } } """ ) assert execute_sync(schema=schema, document=document, root_value=john) == ( { "__typename": "Person", "name": "John", "friends": [ {"__typename": "Person", "name": "Liz", "mother": None}, { "__typename": "Dog", "name": "Odie", "barks": True, "mother": { "__typename": "Dog", "name": "Odie's Mom", "barks": True, }, }, ], }, None, ) def executes_interface_types_with_named_fragments(): document = parse( """ { __typename name friends { __typename name ...DogBarks ...CatMeows } } fragment DogBarks on Dog { barks } fragment CatMeows on Cat { meows } """ ) assert execute_sync(schema=schema, document=document, root_value=john) == ( { "__typename": "Person", "name": "John", "friends": [ {"__typename": "Person", "name": "Liz"}, {"__typename": "Dog", "name": "Odie", "barks": True}, ], }, None, ) def allows_fragment_conditions_to_be_abstract_types(): document = parse( """ { __typename name pets { ...PetFields, ...on Mammal { mother { ...ProgenyFields } } } friends { ...FriendFields } } fragment PetFields on Pet { __typename ... on Dog { name barks } ... on Cat { name meows } } fragment FriendFields on Named { __typename name ... on Dog { barks } ... on Cat { meows } } fragment ProgenyFields on Life { progeny { __typename } } """ ) assert execute_sync(schema=schema, document=document, root_value=john) == ( { "__typename": "Person", "name": "John", "pets": [ { "__typename": "Cat", "name": "Garfield", "meows": False, "mother": {"progeny": [{"__typename": "Cat"}]}, }, { "__typename": "Dog", "name": "Odie", "barks": True, "mother": {"progeny": [{"__typename": "Dog"}]}, }, ], "friends": [ {"__typename": "Person", "name": "Liz"}, {"__typename": "Dog", "name": "Odie", "barks": True}, ], }, None, ) # noinspection PyPep8Naming def gets_execution_info_in_resolver(): encountered = {} def resolve_type(_source, info, _type): encountered["context"] = info.context encountered["schema"] = info.schema encountered["root_value"] = info.root_value return PersonType2.name NamedType2 = GraphQLInterfaceType( "Named", {"name": GraphQLField(GraphQLString)}, resolve_type=resolve_type ) PersonType2 = GraphQLObjectType( "Person", { "name": GraphQLField(GraphQLString), "friends": GraphQLField(GraphQLList(NamedType2)), }, interfaces=[NamedType2], ) schema2 = GraphQLSchema(PersonType2) document = parse("{ name, friends { name } }") root_value = Person("John", [], [liz]) context_value = {"authToken": "123abc"} assert execute_sync( schema=schema2, document=document, root_value=root_value, context_value=context_value, ) == ( {"name": "John", "friends": [{"name": "Liz"}]}, None, ) assert encountered == { "schema": schema2, "root_value": root_value, "context": context_value, } graphql-core-3.2.6/tests/execution/test_variables.py000066400000000000000000001076751474546154300226710ustar00rootroot00000000000000from math import nan from typing import Any, Dict, Optional from graphql.error import GraphQLError from graphql.execution import ExecutionResult, execute_sync from graphql.execution.values import get_variable_values from graphql.language import OperationDefinitionNode, StringValueNode, ValueNode, parse from graphql.pyutils import Undefined from graphql.type import ( GraphQLArgument, GraphQLEnumType, GraphQLEnumValue, GraphQLField, GraphQLFloat, GraphQLInputField, GraphQLInputObjectType, GraphQLList, GraphQLNonNull, GraphQLObjectType, GraphQLScalarType, GraphQLSchema, GraphQLString, ) TestFaultyScalarGraphQLError = GraphQLError( "FaultyScalarErrorMessage", extensions={"code": "FaultyScalarExtensionCode"} ) def faulty_parse_value(value: str) -> str: raise TestFaultyScalarGraphQLError def faulty_parse_literal(ast: ValueNode, _variables=None) -> str: raise TestFaultyScalarGraphQLError TestFaultyScalar = GraphQLScalarType( name="FaultyScalar", parse_value=faulty_parse_value, parse_literal=faulty_parse_literal, ) def parse_serialized_value(value: str) -> str: assert value == "SerializedValue" return "DeserializedValue" def parse_literal_value(ast: ValueNode, _variables=None) -> str: assert isinstance(ast, StringValueNode) assert ast.value == "SerializedValue" return parse_serialized_value(ast.value) TestComplexScalar = GraphQLScalarType( name="ComplexScalar", parse_value=parse_serialized_value, parse_literal=parse_literal_value, ) TestInputObject = GraphQLInputObjectType( "TestInputObject", { "a": GraphQLInputField(GraphQLString), "b": GraphQLInputField(GraphQLList(GraphQLString)), "c": GraphQLInputField(GraphQLNonNull(GraphQLString)), "d": GraphQLInputField(TestComplexScalar), "e": GraphQLInputField(TestFaultyScalar), }, ) TestCustomInputObject = GraphQLInputObjectType( "TestCustomInputObject", {"x": GraphQLInputField(GraphQLFloat), "y": GraphQLInputField(GraphQLFloat)}, out_type=lambda value: f"(x|y) = ({value['x']}|{value['y']})", ) TestNestedInputObject = GraphQLInputObjectType( "TestNestedInputObject", { "na": GraphQLInputField(GraphQLNonNull(TestInputObject)), "nb": GraphQLInputField(GraphQLNonNull(GraphQLString)), }, ) TestEnum = GraphQLEnumType( "TestEnum", { "NULL": None, "UNDEFINED": Undefined, "NAN": nan, "FALSE": False, "CUSTOM": "custom value", "DEFAULT_VALUE": GraphQLEnumValue(), }, ) def field_with_input_arg(input_arg: GraphQLArgument): return GraphQLField( GraphQLString, args={"input": input_arg}, resolve=lambda _obj, _info, **args: ( repr(args["input"]) if "input" in args else None ), ) TestType = GraphQLObjectType( "TestType", { "fieldWithEnumInput": field_with_input_arg(GraphQLArgument(TestEnum)), "fieldWithNonNullableEnumInput": field_with_input_arg( GraphQLArgument(GraphQLNonNull(TestEnum)) ), "fieldWithObjectInput": field_with_input_arg(GraphQLArgument(TestInputObject)), "fieldWithCustomObjectInput": field_with_input_arg( GraphQLArgument(TestCustomInputObject) ), "fieldWithNullableStringInput": field_with_input_arg( GraphQLArgument(GraphQLString) ), "fieldWithNonNullableStringInput": field_with_input_arg( GraphQLArgument(GraphQLNonNull(GraphQLString)) ), "fieldWithDefaultArgumentValue": field_with_input_arg( GraphQLArgument(GraphQLString, default_value="Hello World") ), "fieldWithNonNullableStringInputAndDefaultArgValue": field_with_input_arg( GraphQLArgument(GraphQLNonNull(GraphQLString), default_value="Hello World") ), "fieldWithNestedInputObject": field_with_input_arg( GraphQLArgument(TestNestedInputObject, default_value="Hello World") ), "list": field_with_input_arg(GraphQLArgument(GraphQLList(GraphQLString))), "nnList": field_with_input_arg( GraphQLArgument(GraphQLNonNull(GraphQLList(GraphQLString))) ), "listNN": field_with_input_arg( GraphQLArgument(GraphQLList(GraphQLNonNull(GraphQLString))) ), "nnListNN": field_with_input_arg( GraphQLArgument(GraphQLNonNull(GraphQLList(GraphQLNonNull(GraphQLString)))) ), }, ) schema = GraphQLSchema(TestType) def execute_query( query: str, variable_values: Optional[Dict[str, Any]] = None ) -> ExecutionResult: document = parse(query) return execute_sync(schema, document, variable_values=variable_values) def describe_execute_handles_inputs(): def describe_handles_objects_and_nullability(): def describe_using_inline_struct(): def executes_with_complex_input(): result = execute_query( """ { fieldWithObjectInput( input: {a: "foo", b: ["bar"], c: "baz"}) } """ ) assert result == ( {"fieldWithObjectInput": "{'a': 'foo', 'b': ['bar'], 'c': 'baz'}"}, None, ) def executes_with_custom_input(): # This is an extension of GraphQL.js. result = execute_query( """ { fieldWithCustomObjectInput( input: {x: -3.0, y: 4.5}) } """ ) assert result == ( {"fieldWithCustomObjectInput": "'(x|y) = (-3.0|4.5)'"}, None, ) def properly_parses_single_value_to_list(): result = execute_query( """ { fieldWithObjectInput(input: {a: "foo", b: "bar", c: "baz"}) } """ ) assert result == ( {"fieldWithObjectInput": "{'a': 'foo', 'b': ['bar'], 'c': 'baz'}"}, None, ) def properly_parses_null_value_to_null(): result = execute_query( """ { fieldWithObjectInput( input: {a: null, b: null, c: "C", d: null}) } """ ) assert result == ( { "fieldWithObjectInput": "{'a': None, 'b': None," " 'c': 'C', 'd': None}" }, None, ) def properly_parses_null_value_in_list(): result = execute_query( """ { fieldWithObjectInput(input: {b: ["A",null,"C"], c: "C"}) } """ ) assert result == ( {"fieldWithObjectInput": "{'b': ['A', None, 'C'], 'c': 'C'}"}, None, ) def does_not_use_incorrect_value(): result = execute_query( """ { fieldWithObjectInput(input: ["foo", "bar", "baz"]) } """ ) assert result == ( {"fieldWithObjectInput": None}, [ { "message": "Argument 'input' has invalid value" ' ["foo", "bar", "baz"].', "path": ["fieldWithObjectInput"], "locations": [(3, 51)], } ], ) def properly_runs_parse_literal_on_complex_scalar_types(): result = execute_query( """ { fieldWithObjectInput(input: {c: "foo", d: "SerializedValue"}) } """ ) assert result == ( {"fieldWithObjectInput": "{'c': 'foo', 'd': 'DeserializedValue'}"}, None, ) def errors_on_faulty_scalar_type_input(): result = execute_query( """ { fieldWithObjectInput(input: {c: "foo", e: "bar"}) } """ ) assert result == ( {"fieldWithObjectInput": None}, [ { "message": "Argument 'input' has invalid value" ' {c: "foo", e: "bar"}.', "path": ["fieldWithObjectInput"], "locations": [(3, 51)], } ], ) def describe_using_variables(): doc = """ query ($input: TestInputObject) { fieldWithObjectInput(input: $input) } """ def executes_with_complex_input(): params = {"input": {"a": "foo", "b": ["bar"], "c": "baz"}} result = execute_query(doc, params) assert result == ( {"fieldWithObjectInput": "{'a': 'foo', 'b': ['bar'], 'c': 'baz'}"}, None, ) def uses_undefined_when_variable_not_provided(): result = execute_query( """ query q($input: String) { fieldWithNullableStringInput(input: $input) } """, {}, ) # Intentionally missing variable values. assert result == ({"fieldWithNullableStringInput": None}, None) def uses_null_when_variable_provided_explicit_null_value(): result = execute_query( """ query q($input: String) { fieldWithNullableStringInput(input: $input) } """, {"input": None}, ) assert result == ({"fieldWithNullableStringInput": "None"}, None) def uses_default_value_when_not_provided(): result = execute_query( """ query ($input: TestInputObject = { a: "foo", b: ["bar"], c: "baz"}) { fieldWithObjectInput(input: $input) } """ ) assert result == ( {"fieldWithObjectInput": "{'a': 'foo', 'b': ['bar'], 'c': 'baz'}"}, None, ) def does_not_use_default_value_when_provided(): result = execute_query( """ query q($input: String = "Default value") { fieldWithNullableStringInput(input: $input) } """, {"input": "Variable value"}, ) assert result == ( {"fieldWithNullableStringInput": "'Variable value'"}, None, ) def uses_explicit_null_value_instead_of_default_value(): result = execute_query( """ query q($input: String = "Default value") { fieldWithNullableStringInput(input: $input) } """, {"input": None}, ) assert result == ({"fieldWithNullableStringInput": "None"}, None) def uses_null_default_value_when_not_provided(): result = execute_query( """ query q($input: String = null) { fieldWithNullableStringInput(input: $input) } """, {}, ) # Intentionally missing variable values. assert result == ({"fieldWithNullableStringInput": "None"}, None) def properly_parses_single_value_to_list(): params = {"input": {"a": "foo", "b": "bar", "c": "baz"}} result = execute_query(doc, params) assert result == ( {"fieldWithObjectInput": "{'a': 'foo', 'b': ['bar'], 'c': 'baz'}"}, None, ) def executes_with_complex_scalar_input(): params = {"input": {"c": "foo", "d": "SerializedValue"}} result = execute_query(doc, params) assert result == ( {"fieldWithObjectInput": "{'c': 'foo', 'd': 'DeserializedValue'}"}, None, ) def errors_on_faulty_scalar_type_input(): params = {"input": {"c": "foo", "e": "SerializedValue"}} result = execute_query(doc, params) assert result == ( None, [ { "message": "Variable '$input' got invalid value" " 'SerializedValue' at 'input.e'; FaultyScalarErrorMessage", "locations": [(2, 24)], "extensions": {"code": "FaultyScalarExtensionCode"}, } ], ) def errors_on_null_for_nested_non_null(): params = {"input": {"a": "foo", "b": "bar", "c": None}} result = execute_query(doc, params) assert result == ( None, [ { "message": "Variable '$input' got invalid value" " None at 'input.c';" " Expected non-nullable type 'String!' not to be None.", "locations": [(2, 24)], } ], ) def errors_on_incorrect_type(): result = execute_query(doc, {"input": "foo bar"}) assert result == ( None, [ { "message": "Variable '$input' got invalid value 'foo bar';" " Expected type 'TestInputObject' to be a mapping.", "locations": [(2, 24)], "path": None, } ], ) def errors_on_omission_of_nested_non_null(): result = execute_query(doc, {"input": {"a": "foo", "b": "bar"}}) assert result == ( None, [ { "message": "Variable '$input' got invalid value" " {'a': 'foo', 'b': 'bar'};" " Field 'c' of required type 'String!' was not provided.", "locations": [(2, 24)], } ], ) def errors_on_deep_nested_errors_and_with_many_errors(): nested_doc = """ query ($input: TestNestedInputObject) { fieldWithNestedObjectInput(input: $input) } """ result = execute_query(nested_doc, {"input": {"na": {"a": "foo"}}}) assert result == ( None, [ { "message": "Variable '$input' got invalid value" " {'a': 'foo'} at 'input.na';" " Field 'c' of required type 'String!' was not provided.", "locations": [(2, 28)], }, { "message": "Variable '$input' got invalid value" " {'na': {'a': 'foo'}};" " Field 'nb' of required type 'String!' was not provided.", "locations": [(2, 28)], }, ], ) def errors_on_addition_of_unknown_input_field(): params = {"input": {"a": "foo", "b": "bar", "c": "baz", "extra": "dog"}} result = execute_query(doc, params) assert result == ( None, [ { "message": "Variable '$input' got invalid value {'a':" " 'foo', 'b': 'bar', 'c': 'baz', 'extra': 'dog'}; Field" " 'extra' is not defined by type 'TestInputObject'.", "locations": [(2, 24)], } ], ) def describe_handles_custom_enum_values(): def allows_custom_enum_values_as_inputs(): result = execute_query( """ { null: fieldWithEnumInput(input: NULL) NaN: fieldWithEnumInput(input: NAN) false: fieldWithEnumInput(input: FALSE) customValue: fieldWithEnumInput(input: CUSTOM) defaultValue: fieldWithEnumInput(input: DEFAULT_VALUE) } """ ) assert result == ( { "null": "None", "NaN": "nan", "false": "False", "customValue": "'custom value'", # different from graphql.js, enum values are always wrapped "defaultValue": "None", }, None, ) def allows_non_nullable_inputs_to_have_null_as_enum_custom_value(): result = execute_query( """ { fieldWithNonNullableEnumInput(input: NULL) } """ ) assert result == ({"fieldWithNonNullableEnumInput": "None"}, None) def describe_handles_nullable_scalars(): def allows_nullable_inputs_to_be_omitted(): result = execute_query( """ { fieldWithNullableStringInput } """ ) assert result == ({"fieldWithNullableStringInput": None}, None) def allows_nullable_inputs_to_be_omitted_in_a_variable(): result = execute_query( """ query ($value: String) { fieldWithNullableStringInput(input: $value) } """ ) assert result == ({"fieldWithNullableStringInput": None}, None) def allows_nullable_inputs_to_be_omitted_in_an_unlisted_variable(): result = execute_query( """ query SetsNullable { fieldWithNullableStringInput(input: $value) } """ ) assert result == ({"fieldWithNullableStringInput": None}, None) def allows_nullable_inputs_to_be_set_to_null_in_a_variable(): doc = """ query SetsNullable($value: String) { fieldWithNullableStringInput(input: $value) } """ result = execute_query(doc, {"value": None}) assert result == ({"fieldWithNullableStringInput": "None"}, None) def allows_nullable_inputs_to_be_set_to_a_value_in_a_variable(): doc = """ query SetsNullable($value: String) { fieldWithNullableStringInput(input: $value) } """ result = execute_query(doc, {"value": "a"}) assert result == ({"fieldWithNullableStringInput": "'a'"}, None) def allows_nullable_inputs_to_be_set_to_a_value_directly(): result = execute_query( """ { fieldWithNullableStringInput(input: "a") } """ ) assert result == ({"fieldWithNullableStringInput": "'a'"}, None) def describe_handles_non_nullable_scalars(): def allows_non_nullable_variable_to_be_omitted_given_a_default(): result = execute_query( """ query ($value: String! = "default") { fieldWithNullableStringInput(input: $value) } """ ) assert result == ({"fieldWithNullableStringInput": "'default'"}, None) def allows_non_nullable_inputs_to_be_omitted_given_a_default(): result = execute_query( """ query ($value: String = "default") { fieldWithNonNullableStringInput(input: $value) } """ ) assert result == ({"fieldWithNonNullableStringInput": "'default'"}, None) def does_not_allow_non_nullable_inputs_to_be_omitted_in_a_variable(): result = execute_query( """ query ($value: String!) { fieldWithNonNullableStringInput(input: $value) } """ ) assert result == ( None, [ { "message": "Variable '$value' of required type 'String!'" " was not provided.", "locations": [(2, 24)], "path": None, } ], ) def does_not_allow_non_nullable_inputs_to_be_set_to_null_in_variable(): doc = """ query ($value: String!) { fieldWithNonNullableStringInput(input: $value) } """ result = execute_query(doc, {"value": None}) assert result == ( None, [ { "message": "Variable '$value' of non-null type 'String!'" " must not be null.", "locations": [(2, 24)], "path": None, } ], ) def allows_non_nullable_inputs_to_be_set_to_a_value_in_a_variable(): doc = """ query ($value: String!) { fieldWithNonNullableStringInput(input: $value) } """ result = execute_query(doc, {"value": "a"}) assert result == ({"fieldWithNonNullableStringInput": "'a'"}, None) def allows_non_nullable_inputs_to_be_set_to_a_value_directly(): result = execute_query( """ { fieldWithNonNullableStringInput(input: "a") } """ ) assert result == ({"fieldWithNonNullableStringInput": "'a'"}, None) def reports_error_for_missing_non_nullable_inputs(): result = execute_query("{ fieldWithNonNullableStringInput }") assert result == ( {"fieldWithNonNullableStringInput": None}, [ { "message": "Argument 'input' of required type 'String!'" " was not provided.", "locations": [(1, 3)], "path": ["fieldWithNonNullableStringInput"], } ], ) def reports_error_for_array_passed_into_string_input(): doc = """ query ($value: String!) { fieldWithNonNullableStringInput(input: $value) } """ result = execute_query(doc, {"value": [1, 2, 3]}) assert result == ( None, [ { "message": "Variable '$value' got invalid value [1, 2, 3];" " String cannot represent a non string value: [1, 2, 3]", "locations": [(2, 24)], "path": None, } ], ) errors = result.errors assert errors assert errors[0].original_error def reports_error_for_non_provided_variables_for_non_nullable_inputs(): # Note: this test would typically fail validation before # encountering this execution error, however for queries which # previously validated and are being run against a new schema which # have introduced a breaking change to make a formerly non-required # argument required, this asserts failure before allowing the # underlying code to receive a non-null value. result = execute_query( """ { fieldWithNonNullableStringInput(input: $foo) } """ ) assert result == ( {"fieldWithNonNullableStringInput": None}, [ { "message": "Argument 'input' of required type 'String!'" " was provided the variable '$foo' which was" " not provided a runtime value.", "locations": [(3, 58)], "path": ["fieldWithNonNullableStringInput"], } ], ) def describe_handles_lists_and_nullability(): def allows_lists_to_be_null(): doc = """ query ($input: [String]) { list(input: $input) } """ result = execute_query(doc, {"input": None}) assert result == ({"list": "None"}, None) def allows_lists_to_contain_values(): doc = """ query ($input: [String]) { list(input: $input) } """ result = execute_query(doc, {"input": ["A"]}) assert result == ({"list": "['A']"}, None) def allows_lists_to_contain_null(): doc = """ query ($input: [String]) { list(input: $input) } """ result = execute_query(doc, {"input": ["A", None, "B"]}) assert result == ({"list": "['A', None, 'B']"}, None) def does_not_allow_non_null_lists_to_be_null(): doc = """ query ($input: [String]!) { nnList(input: $input) } """ result = execute_query(doc, {"input": None}) assert result == ( None, [ { "message": "Variable '$input' of non-null type '[String]!'" " must not be null.", "locations": [(2, 24)], "path": None, } ], ) def allows_non_null_lists_to_contain_values(): doc = """ query ($input: [String]!) { nnList(input: $input) } """ result = execute_query(doc, {"input": ["A"]}) assert result == ({"nnList": "['A']"}, None) def allows_non_null_lists_to_contain_null(): doc = """ query ($input: [String]!) { nnList(input: $input) } """ result = execute_query(doc, {"input": ["A", None, "B"]}) assert result == ({"nnList": "['A', None, 'B']"}, None) def allows_lists_of_non_nulls_to_be_null(): doc = """ query ($input: [String!]) { listNN(input: $input) } """ result = execute_query(doc, {"input": None}) assert result == ({"listNN": "None"}, None) def allows_lists_of_non_nulls_to_contain_values(): doc = """ query ($input: [String!]) { listNN(input: $input) } """ result = execute_query(doc, {"input": ["A"]}) assert result == ({"listNN": "['A']"}, None) def does_not_allow_lists_of_non_nulls_to_contain_null(): doc = """ query ($input: [String!]) { listNN(input: $input) } """ result = execute_query(doc, {"input": ["A", None, "B"]}) assert result == ( None, [ { "message": "Variable '$input' got invalid value None" " at 'input[1]';" " Expected non-nullable type 'String!' not to be None.", "locations": [(2, 24)], } ], ) def does_not_allow_non_null_lists_of_non_nulls_to_be_null(): doc = """ query ($input: [String!]!) { nnListNN(input: $input) } """ result = execute_query(doc, {"input": None}) assert result == ( None, [ { "message": "Variable '$input' of non-null type '[String!]!'" " must not be null.", "locations": [(2, 24)], } ], ) def allows_non_null_lists_of_non_nulls_to_contain_values(): doc = """ query ($input: [String!]!) { nnListNN(input: $input) } """ result = execute_query(doc, {"input": ["A"]}) assert result == ({"nnListNN": "['A']"}, None) def does_not_allow_non_null_lists_of_non_nulls_to_contain_null(): doc = """ query ($input: [String!]!) { nnListNN(input: $input) } """ result = execute_query(doc, {"input": ["A", None, "B"]}) assert result == ( None, [ { "message": "Variable '$input' got invalid value None" " at 'input[1]';" " Expected non-nullable type 'String!' not to be None.", "locations": [(2, 24)], "path": None, } ], ) def does_not_allow_invalid_types_to_be_used_as_values(): doc = """ query ($input: TestType!) { fieldWithObjectInput(input: $input) } """ result = execute_query(doc, {"input": {"list": ["A", "B"]}}) assert result == ( None, [ { "message": "Variable '$input' expected value" " of type 'TestType!' which cannot" " be used as an input type.", "locations": [(2, 32)], } ], ) def does_not_allow_unknown_types_to_be_used_as_values(): doc = """ query ($input: UnknownType!) { fieldWithObjectInput(input: $input) } """ result = execute_query(doc, {"input": "whoKnows"}) assert result == ( None, [ { "message": "Variable '$input' expected value" " of type 'UnknownType!' which cannot" " be used as an input type.", "locations": [(2, 32)], } ], ) def describe_execute_uses_argument_default_values(): def when_no_argument_provided(): result = execute_query("{ fieldWithDefaultArgumentValue }") assert result == ({"fieldWithDefaultArgumentValue": "'Hello World'"}, None) def when_omitted_variable_provided(): result = execute_query( """ query ($optional: String) { fieldWithDefaultArgumentValue(input: $optional) } """ ) assert result == ({"fieldWithDefaultArgumentValue": "'Hello World'"}, None) def not_when_argument_cannot_be_coerced(): result = execute_query( """ { fieldWithDefaultArgumentValue(input: WRONG_TYPE) } """ ) assert result == ( {"fieldWithDefaultArgumentValue": None}, [ { "message": "Argument 'input' has invalid value WRONG_TYPE.", "locations": [(3, 56)], "path": ["fieldWithDefaultArgumentValue"], } ], ) def when_no_runtime_value_is_provided_to_a_non_null_argument(): result = execute_query( """ query optionalVariable($optional: String) { fieldWithNonNullableStringInputAndDefaultArgValue(input: $optional) } """ ) assert result == ( {"fieldWithNonNullableStringInputAndDefaultArgValue": "'Hello World'"}, None, ) def describe_get_variable_values_limit_maximum_number_of_coercion_errors(): doc = parse( """ query ($input: [String!]) { listNN(input: $input) } """ ) operation = doc.definitions[0] assert isinstance(operation, OperationDefinitionNode) variable_definitions = operation.variable_definitions assert variable_definitions is not None input_value = {"input": [0, 1, 2]} def _invalid_value_error(value: int, index: int) -> Dict[str, Any]: return { "message": "Variable '$input' got invalid value" f" {value} at 'input[{index}]';" f" String cannot represent a non string value: {value}", "locations": [(2, 20)], } def return_all_errors_by_default(): result = get_variable_values(schema, variable_definitions, input_value) assert result == [ _invalid_value_error(0, 0), _invalid_value_error(1, 1), _invalid_value_error(2, 2), ] def when_max_errors_is_equal_to_number_of_errors(): result = get_variable_values( schema, variable_definitions, input_value, max_errors=3 ) assert result == [ _invalid_value_error(0, 0), _invalid_value_error(1, 1), _invalid_value_error(2, 2), ] def when_max_errors_is_less_than_number_of_errors(): result = get_variable_values( schema, variable_definitions, input_value, max_errors=2 ) assert result == [ _invalid_value_error(0, 0), _invalid_value_error(1, 1), { "message": "Too many errors processing variables," " error limit reached. Execution aborted." }, ] graphql-core-3.2.6/tests/fixtures/000077500000000000000000000000001474546154300171365ustar00rootroot00000000000000graphql-core-3.2.6/tests/fixtures/__init__.py000066400000000000000000000015471474546154300212560ustar00rootroot00000000000000"""Fixtures for graphql tests""" import json from os.path import dirname, join from pytest import fixture __all__ = [ "kitchen_sink_query", "kitchen_sink_sdl", "big_schema_sdl", "big_schema_introspection_result", ] def read_graphql(name): path = join(dirname(__file__), name + ".graphql") return open(path, encoding="utf-8").read() def read_json(name): path = join(dirname(__file__), name + ".json") return json.load(open(path, encoding="utf-8")) @fixture(scope="module") def kitchen_sink_query(): return read_graphql("kitchen_sink") @fixture(scope="module") def kitchen_sink_sdl(): return read_graphql("schema_kitchen_sink") @fixture(scope="module") def big_schema_sdl(): return read_graphql("github_schema") @fixture(scope="module") def big_schema_introspection_result(): return read_json("github_schema") graphql-core-3.2.6/tests/fixtures/github_schema.graphql000066400000000000000000012435061474546154300233330ustar00rootroot00000000000000"""Autogenerated input type of AcceptTopicSuggestion""" input AcceptTopicSuggestionInput { """The Node ID of the repository.""" repositoryId: ID! """The name of the suggested topic.""" name: String! """A unique identifier for the client performing the mutation.""" clientMutationId: String } """Autogenerated return type of AcceptTopicSuggestion""" type AcceptTopicSuggestionPayload { """A unique identifier for the client performing the mutation.""" clientMutationId: String """The accepted topic.""" topic: Topic } """ Represents an object which can take actions on GitHub. Typically a User or Bot. """ interface Actor { """A URL pointing to the actor's public avatar.""" avatarUrl( """The size of the resulting square image.""" size: Int ): URI! """The username of the actor.""" login: String! """The HTTP path for this actor.""" resourcePath: URI! """The HTTP URL for this actor.""" url: URI! } """Autogenerated input type of AddAssigneesToAssignable""" input AddAssigneesToAssignableInput { """The id of the assignable object to add assignees to.""" assignableId: ID! """The id of users to add as assignees.""" assigneeIds: [ID!]! """A unique identifier for the client performing the mutation.""" clientMutationId: String } """Autogenerated return type of AddAssigneesToAssignable""" type AddAssigneesToAssignablePayload { """The item that was assigned.""" assignable: Assignable """A unique identifier for the client performing the mutation.""" clientMutationId: String } """Autogenerated input type of AddComment""" input AddCommentInput { """The Node ID of the subject to modify.""" subjectId: ID! """The contents of the comment.""" body: String! """A unique identifier for the client performing the mutation.""" clientMutationId: String } """Autogenerated return type of AddComment""" type AddCommentPayload { """A unique identifier for the client performing the mutation.""" clientMutationId: String """The edge from the subject's comment connection.""" commentEdge: IssueCommentEdge """The subject""" subject: Node """The edge from the subject's timeline connection.""" timelineEdge: IssueTimelineItemEdge } """ Represents a 'added_to_project' event on a given issue or pull request. """ type AddedToProjectEvent implements Node { """Identifies the actor who performed the event.""" actor: Actor """Identifies the date and time when the object was created.""" createdAt: DateTime! """Identifies the primary key from the database.""" databaseId: Int id: ID! } """Autogenerated input type of AddLabelsToLabelable""" input AddLabelsToLabelableInput { """The id of the labelable object to add labels to.""" labelableId: ID! """The ids of the labels to add.""" labelIds: [ID!]! """A unique identifier for the client performing the mutation.""" clientMutationId: String } """Autogenerated return type of AddLabelsToLabelable""" type AddLabelsToLabelablePayload { """A unique identifier for the client performing the mutation.""" clientMutationId: String """The item that was labeled.""" labelable: Labelable } """Autogenerated input type of AddProjectCard""" input AddProjectCardInput { """The Node ID of the ProjectColumn.""" projectColumnId: ID! """The content of the card. Must be a member of the ProjectCardItem union""" contentId: ID """The note on the card.""" note: String """A unique identifier for the client performing the mutation.""" clientMutationId: String } """Autogenerated return type of AddProjectCard""" type AddProjectCardPayload { """The edge from the ProjectColumn's card connection.""" cardEdge: ProjectCardEdge """A unique identifier for the client performing the mutation.""" clientMutationId: String """The ProjectColumn""" projectColumn: ProjectColumn } """Autogenerated input type of AddProjectColumn""" input AddProjectColumnInput { """The Node ID of the project.""" projectId: ID! """The name of the column.""" name: String! """A unique identifier for the client performing the mutation.""" clientMutationId: String } """Autogenerated return type of AddProjectColumn""" type AddProjectColumnPayload { """A unique identifier for the client performing the mutation.""" clientMutationId: String """The edge from the project's column connection.""" columnEdge: ProjectColumnEdge """The project""" project: Project } """Autogenerated input type of AddPullRequestReviewComment""" input AddPullRequestReviewCommentInput { """The Node ID of the review to modify.""" pullRequestReviewId: ID! """The SHA of the commit to comment on.""" commitOID: GitObjectID """The text of the comment.""" body: String! """The relative path of the file to comment on.""" path: String """The line index in the diff to comment on.""" position: Int """The comment id to reply to.""" inReplyTo: ID """A unique identifier for the client performing the mutation.""" clientMutationId: String } """Autogenerated return type of AddPullRequestReviewComment""" type AddPullRequestReviewCommentPayload { """A unique identifier for the client performing the mutation.""" clientMutationId: String """The newly created comment.""" comment: PullRequestReviewComment """The edge from the review's comment connection.""" commentEdge: PullRequestReviewCommentEdge } """Autogenerated input type of AddPullRequestReview""" input AddPullRequestReviewInput { """The Node ID of the pull request to modify.""" pullRequestId: ID! """The commit OID the review pertains to.""" commitOID: GitObjectID """The contents of the review body comment.""" body: String """The event to perform on the pull request review.""" event: PullRequestReviewEvent """The review line comments.""" comments: [DraftPullRequestReviewComment] """A unique identifier for the client performing the mutation.""" clientMutationId: String } """Autogenerated return type of AddPullRequestReview""" type AddPullRequestReviewPayload { """A unique identifier for the client performing the mutation.""" clientMutationId: String """The newly created pull request review.""" pullRequestReview: PullRequestReview """The edge from the pull request's review connection.""" reviewEdge: PullRequestReviewEdge } """Autogenerated input type of AddReaction""" input AddReactionInput { """The Node ID of the subject to modify.""" subjectId: ID! """The name of the emoji to react with.""" content: ReactionContent! """A unique identifier for the client performing the mutation.""" clientMutationId: String } """Autogenerated return type of AddReaction""" type AddReactionPayload { """A unique identifier for the client performing the mutation.""" clientMutationId: String """The reaction object.""" reaction: Reaction """The reactable subject.""" subject: Reactable } """Autogenerated input type of AddStar""" input AddStarInput { """The Starrable ID to star.""" starrableId: ID! """A unique identifier for the client performing the mutation.""" clientMutationId: String } """Autogenerated return type of AddStar""" type AddStarPayload { """A unique identifier for the client performing the mutation.""" clientMutationId: String """The starrable.""" starrable: Starrable } """A GitHub App.""" type App implements Node { """Identifies the date and time when the object was created.""" createdAt: DateTime! """Identifies the primary key from the database.""" databaseId: Int """The description of the app.""" description: String id: ID! """The hex color code, without the leading '#', for the logo background.""" logoBackgroundColor: String! """A URL pointing to the app's logo.""" logoUrl( """The size of the resulting image.""" size: Int ): URI! """The name of the app.""" name: String! """A slug based on the name of the app for use in URLs.""" slug: String! """Identifies the date and time when the object was last updated.""" updatedAt: DateTime! """The URL to the app's homepage.""" url: URI! } """An edge in a connection.""" type AppEdge { """A cursor for use in pagination.""" cursor: String! """The item at the end of the edge.""" node: App } """An object that can have users assigned to it.""" interface Assignable { """A list of Users assigned to this object.""" assignees( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): UserConnection! } """Represents an 'assigned' event on any assignable object.""" type AssignedEvent implements Node { """Identifies the actor who performed the event.""" actor: Actor """Identifies the assignable associated with the event.""" assignable: Assignable! """Identifies the date and time when the object was created.""" createdAt: DateTime! id: ID! """Identifies the user who was assigned.""" user: User } """ Represents a 'base_ref_changed' event on a given issue or pull request. """ type BaseRefChangedEvent implements Node { """Identifies the actor who performed the event.""" actor: Actor """Identifies the date and time when the object was created.""" createdAt: DateTime! """Identifies the primary key from the database.""" databaseId: Int id: ID! } """Represents a 'base_ref_force_pushed' event on a given pull request.""" type BaseRefForcePushedEvent implements Node { """Identifies the actor who performed the event.""" actor: Actor """Identifies the after commit SHA for the 'base_ref_force_pushed' event.""" afterCommit: Commit """ Identifies the before commit SHA for the 'base_ref_force_pushed' event. """ beforeCommit: Commit """Identifies the date and time when the object was created.""" createdAt: DateTime! id: ID! """PullRequest referenced by event.""" pullRequest: PullRequest! """ Identifies the fully qualified ref name for the 'base_ref_force_pushed' event. """ ref: Ref } """Represents a Git blame.""" type Blame { """The list of ranges from a Git blame.""" ranges: [BlameRange!]! } """Represents a range of information from a Git blame.""" type BlameRange { """ Identifies the recency of the change, from 1 (new) to 10 (old). This is calculated as a 2-quantile and determines the length of distance between the median age of all the changes in the file and the recency of the current range's change. """ age: Int! """Identifies the line author""" commit: Commit! """The ending line for the range""" endingLine: Int! """The starting line for the range""" startingLine: Int! } """Represents a Git blob.""" type Blob implements Node & GitObject { """An abbreviated version of the Git object ID""" abbreviatedOid: String! """Byte size of Blob object""" byteSize: Int! """The HTTP path for this Git object""" commitResourcePath: URI! """The HTTP URL for this Git object""" commitUrl: URI! id: ID! """Indicates whether the Blob is binary or text""" isBinary: Boolean! """Indicates whether the contents is truncated""" isTruncated: Boolean! """The Git object ID""" oid: GitObjectID! """The Repository the Git object belongs to""" repository: Repository! """UTF8 text data or null if the Blob is binary""" text: String } """A special type of user which takes actions on behalf of GitHub Apps.""" type Bot implements Node & Actor & UniformResourceLocatable { """A URL pointing to the GitHub App's public avatar.""" avatarUrl( """The size of the resulting square image.""" size: Int ): URI! """Identifies the date and time when the object was created.""" createdAt: DateTime! """Identifies the primary key from the database.""" databaseId: Int id: ID! """The username of the actor.""" login: String! """The HTTP path for this bot""" resourcePath: URI! """Identifies the date and time when the object was last updated.""" updatedAt: DateTime! """The HTTP URL for this bot""" url: URI! } """A branch protection rule.""" type BranchProtectionRule implements Node { """ A list of conflicts matching branches protection rule and other branch protection rules """ branchProtectionRuleConflicts( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): BranchProtectionRuleConflictConnection! """The actor who created this branch protection rule.""" creator: Actor """Identifies the primary key from the database.""" databaseId: Int """ Will new commits pushed to matching branches dismiss pull request review approvals. """ dismissesStaleReviews: Boolean! id: ID! """Can admins overwrite branch protection.""" isAdminEnforced: Boolean! """Repository refs that are protected by this rule""" matchingRefs( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): RefConnection! """Identifies the protection rule pattern.""" pattern: String! """A list push allowances for this branch protection rule.""" pushAllowances( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): PushAllowanceConnection! """The repository associated with this branch protection rule.""" repository: Repository """Number of approving reviews required to update matching branches.""" requiredApprovingReviewCount: Int """ List of required status check contexts that must pass for commits to be accepted to matching branches. """ requiredStatusCheckContexts: [String] """Are approving reviews required to update matching branches.""" requiresApprovingReviews: Boolean! """Are commits required to be signed.""" requiresCommitSignatures: Boolean! """Are status checks required to update matching branches.""" requiresStatusChecks: Boolean! """Are branches required to be up to date before merging.""" requiresStrictStatusChecks: Boolean! """Is pushing to matching branches restricted.""" restrictsPushes: Boolean! """Is dismissal of pull request reviews restricted.""" restrictsReviewDismissals: Boolean! """A list review dismissal allowances for this branch protection rule.""" reviewDismissalAllowances( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): ReviewDismissalAllowanceConnection! } """A conflict between two branch protection rules.""" type BranchProtectionRuleConflict { """Identifies the branch protection rule.""" branchProtectionRule: BranchProtectionRule """Identifies the conflicting branch protection rule.""" conflictingBranchProtectionRule: BranchProtectionRule """Identifies the branch ref that has conflicting rules""" ref: Ref } """The connection type for BranchProtectionRuleConflict.""" type BranchProtectionRuleConflictConnection { """A list of edges.""" edges: [BranchProtectionRuleConflictEdge] """A list of nodes.""" nodes: [BranchProtectionRuleConflict] """Information to aid in pagination.""" pageInfo: PageInfo! """Identifies the total count of items in the connection.""" totalCount: Int! } """An edge in a connection.""" type BranchProtectionRuleConflictEdge { """A cursor for use in pagination.""" cursor: String! """The item at the end of the edge.""" node: BranchProtectionRuleConflict } """The connection type for BranchProtectionRule.""" type BranchProtectionRuleConnection { """A list of edges.""" edges: [BranchProtectionRuleEdge] """A list of nodes.""" nodes: [BranchProtectionRule] """Information to aid in pagination.""" pageInfo: PageInfo! """Identifies the total count of items in the connection.""" totalCount: Int! } """An edge in a connection.""" type BranchProtectionRuleEdge { """A cursor for use in pagination.""" cursor: String! """The item at the end of the edge.""" node: BranchProtectionRule } """Autogenerated input type of ChangeUserStatus""" input ChangeUserStatusInput { """ The emoji to represent your status. Can either be a native Unicode emoji or an emoji name with colons, e.g., :grinning:. """ emoji: String """A short description of your current status.""" message: String """ The ID of the organization whose members will be allowed to see the status. If omitted, the status will be publicly visible. """ organizationId: ID """ Whether this status should indicate you are not fully available on GitHub, e.g., you are away. """ limitedAvailability: Boolean = false """A unique identifier for the client performing the mutation.""" clientMutationId: String } """Autogenerated return type of ChangeUserStatus""" type ChangeUserStatusPayload { """A unique identifier for the client performing the mutation.""" clientMutationId: String """Your updated status.""" status: UserStatus } """Autogenerated input type of ClearLabelsFromLabelable""" input ClearLabelsFromLabelableInput { """The id of the labelable object to clear the labels from.""" labelableId: ID! """A unique identifier for the client performing the mutation.""" clientMutationId: String } """Autogenerated return type of ClearLabelsFromLabelable""" type ClearLabelsFromLabelablePayload { """A unique identifier for the client performing the mutation.""" clientMutationId: String """The item that was unlabeled.""" labelable: Labelable } """Autogenerated input type of CloneProject""" input CloneProjectInput { """The owner ID to create the project under.""" targetOwnerId: ID! """The source project to clone.""" sourceId: ID! """Whether or not to clone the source project's workflows.""" includeWorkflows: Boolean! """The name of the project.""" name: String! """The description of the project.""" body: String """The visibility of the project, defaults to false (private).""" public: Boolean """A unique identifier for the client performing the mutation.""" clientMutationId: String } """Autogenerated return type of CloneProject""" type CloneProjectPayload { """A unique identifier for the client performing the mutation.""" clientMutationId: String """The id of the JobStatus for populating cloned fields.""" jobStatusId: String """The new cloned project.""" project: Project } """An object that can be closed""" interface Closable { """ `true` if the object is closed (definition of closed may depend on type) """ closed: Boolean! """Identifies the date and time when the object was closed.""" closedAt: DateTime } """Represents a 'closed' event on any `Closable`.""" type ClosedEvent implements Node & UniformResourceLocatable { """Identifies the actor who performed the event.""" actor: Actor """Object that was closed.""" closable: Closable! """Object which triggered the creation of this event.""" closer: Closer """Identifies the date and time when the object was created.""" createdAt: DateTime! id: ID! """The HTTP path for this closed event.""" resourcePath: URI! """The HTTP URL for this closed event.""" url: URI! } """Autogenerated input type of CloseIssue""" input CloseIssueInput { """ID of the issue to be closed.""" issueId: ID! """A unique identifier for the client performing the mutation.""" clientMutationId: String } """Autogenerated return type of CloseIssue""" type CloseIssuePayload { """A unique identifier for the client performing the mutation.""" clientMutationId: String """The issue that was closed.""" issue: Issue } """Autogenerated input type of ClosePullRequest""" input ClosePullRequestInput { """ID of the pull request to be closed.""" pullRequestId: ID! """A unique identifier for the client performing the mutation.""" clientMutationId: String } """Autogenerated return type of ClosePullRequest""" type ClosePullRequestPayload { """A unique identifier for the client performing the mutation.""" clientMutationId: String """The pull request that was closed.""" pullRequest: PullRequest } """The object which triggered a `ClosedEvent`.""" union Closer = Commit | PullRequest """The Code of Conduct for a repository""" type CodeOfConduct implements Node { """The body of the Code of Conduct""" body: String id: ID! """The key for the Code of Conduct""" key: String! """The formal name of the Code of Conduct""" name: String! """The HTTP path for this Code of Conduct""" resourcePath: URI """The HTTP URL for this Code of Conduct""" url: URI } """Collaborators affiliation level with a subject.""" enum CollaboratorAffiliation { """All outside collaborators of an organization-owned subject.""" OUTSIDE """ All collaborators with permissions to an organization-owned subject, regardless of organization membership status. """ DIRECT """All collaborators the authenticated user can see.""" ALL } """Types that can be inside Collection Items.""" union CollectionItemContent = Repository | Organization | User """Represents a comment.""" interface Comment { """The actor who authored the comment.""" author: Actor """Author's association with the subject of the comment.""" authorAssociation: CommentAuthorAssociation! """The body as Markdown.""" body: String! """The body rendered to HTML.""" bodyHTML: HTML! """The body rendered to text.""" bodyText: String! """Identifies the date and time when the object was created.""" createdAt: DateTime! """Check if this comment was created via an email reply.""" createdViaEmail: Boolean! """The actor who edited the comment.""" editor: Actor id: ID! """ Check if this comment was edited and includes an edit with the creation data """ includesCreatedEdit: Boolean! """The moment the editor made the last edit""" lastEditedAt: DateTime """Identifies when the comment was published at.""" publishedAt: DateTime """Identifies the date and time when the object was last updated.""" updatedAt: DateTime! """A list of edits to this content.""" userContentEdits( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): UserContentEditConnection """Did the viewer author this comment.""" viewerDidAuthor: Boolean! } """A comment author association with repository.""" enum CommentAuthorAssociation { """Author is a member of the organization that owns the repository.""" MEMBER """Author is the owner of the repository.""" OWNER """Author has been invited to collaborate on the repository.""" COLLABORATOR """Author has previously committed to the repository.""" CONTRIBUTOR """Author has not previously committed to the repository.""" FIRST_TIME_CONTRIBUTOR """Author has not previously committed to GitHub.""" FIRST_TIMER """Author has no association with the repository.""" NONE } """The possible errors that will prevent a user from updating a comment.""" enum CommentCannotUpdateReason { """ You must be the author or have write access to this repository to update this comment. """ INSUFFICIENT_ACCESS """Unable to create comment because issue is locked.""" LOCKED """You must be logged in to update this comment.""" LOGIN_REQUIRED """Repository is under maintenance.""" MAINTENANCE """At least one email address must be verified to update this comment.""" VERIFIED_EMAIL_REQUIRED """You cannot update this comment""" DENIED } """Represents a 'comment_deleted' event on a given issue or pull request.""" type CommentDeletedEvent implements Node { """Identifies the actor who performed the event.""" actor: Actor """Identifies the date and time when the object was created.""" createdAt: DateTime! """Identifies the primary key from the database.""" databaseId: Int id: ID! } """Represents a Git commit.""" type Commit implements Node & GitObject & Subscribable & UniformResourceLocatable { """An abbreviated version of the Git object ID""" abbreviatedOid: String! """The number of additions in this commit.""" additions: Int! """The pull requests associated with a commit""" associatedPullRequests( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int """Ordering options for pull requests.""" orderBy: PullRequestOrder ): PullRequestConnection """Authorship details of the commit.""" author: GitActor """Check if the committer and the author match.""" authoredByCommitter: Boolean! """The datetime when this commit was authored.""" authoredDate: DateTime! """Fetches `git blame` information.""" blame( """The file whose Git blame information you want.""" path: String! ): Blame! """The number of changed files in this commit.""" changedFiles: Int! """Comments made on the commit.""" comments( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): CommitCommentConnection! """The HTTP path for this Git object""" commitResourcePath: URI! """The HTTP URL for this Git object""" commitUrl: URI! """The datetime when this commit was committed.""" committedDate: DateTime! """Check if commited via GitHub web UI.""" committedViaWeb: Boolean! """Committership details of the commit.""" committer: GitActor """The number of deletions in this commit.""" deletions: Int! """The deployments associated with a commit.""" deployments( """Environments to list deployments for""" environments: [String!] """Ordering options for deployments returned from the connection.""" orderBy: DeploymentOrder """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): DeploymentConnection """ The linear commit history starting from (and including) this commit, in the same order as `git log`. """ history( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int """ If non-null, filters history to only show commits touching files under this path. """ path: String """ If non-null, filters history to only show commits with matching authorship. """ author: CommitAuthor """Allows specifying a beginning time or date for fetching commits.""" since: GitTimestamp """Allows specifying an ending time or date for fetching commits.""" until: GitTimestamp ): CommitHistoryConnection! id: ID! """The Git commit message""" message: String! """The Git commit message body""" messageBody: String! """The commit message body rendered to HTML.""" messageBodyHTML: HTML! """The Git commit message headline""" messageHeadline: String! """The commit message headline rendered to HTML.""" messageHeadlineHTML: HTML! """The Git object ID""" oid: GitObjectID! """The parents of a commit.""" parents( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): CommitConnection! """The datetime when this commit was pushed.""" pushedDate: DateTime """The Repository this commit belongs to""" repository: Repository! """The HTTP path for this commit""" resourcePath: URI! """Commit signing information, if present.""" signature: GitSignature """Status information for this commit""" status: Status """ Returns a URL to download a tarball archive for a repository. Note: For private repositories, these links are temporary and expire after five minutes. """ tarballUrl: URI! """Commit's root Tree""" tree: Tree! """The HTTP path for the tree of this commit""" treeResourcePath: URI! """The HTTP URL for the tree of this commit""" treeUrl: URI! """The HTTP URL for this commit""" url: URI! """ Check if the viewer is able to change their subscription status for the repository. """ viewerCanSubscribe: Boolean! """ Identifies if the viewer is watching, not watching, or ignoring the subscribable entity. """ viewerSubscription: SubscriptionState """ Returns a URL to download a zipball archive for a repository. Note: For private repositories, these links are temporary and expire after five minutes. """ zipballUrl: URI! } """Specifies an author for filtering Git commits.""" input CommitAuthor { """ ID of a User to filter by. If non-null, only commits authored by this user will be returned. This field takes precedence over emails. """ id: ID """ Email addresses to filter by. Commits authored by any of the specified email addresses will be returned. """ emails: [String!] } """Represents a comment on a given Commit.""" type CommitComment implements Node & Comment & Deletable & Updatable & UpdatableComment & Reactable & RepositoryNode { """The actor who authored the comment.""" author: Actor """Author's association with the subject of the comment.""" authorAssociation: CommentAuthorAssociation! """Identifies the comment body.""" body: String! """Identifies the comment body rendered to HTML.""" bodyHTML: HTML! """The body rendered to text.""" bodyText: String! """ Identifies the commit associated with the comment, if the commit exists. """ commit: Commit """Identifies the date and time when the object was created.""" createdAt: DateTime! """Check if this comment was created via an email reply.""" createdViaEmail: Boolean! """Identifies the primary key from the database.""" databaseId: Int """The actor who edited the comment.""" editor: Actor id: ID! """ Check if this comment was edited and includes an edit with the creation data """ includesCreatedEdit: Boolean! """Returns whether or not a comment has been minimized.""" isMinimized: Boolean! """The moment the editor made the last edit""" lastEditedAt: DateTime """Returns why the comment was minimized.""" minimizedReason: String """Identifies the file path associated with the comment.""" path: String """Identifies the line position associated with the comment.""" position: Int """Identifies when the comment was published at.""" publishedAt: DateTime """A list of reactions grouped by content left on the subject.""" reactionGroups: [ReactionGroup!] """A list of Reactions left on the Issue.""" reactions( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int """Allows filtering Reactions by emoji.""" content: ReactionContent """Allows specifying the order in which reactions are returned.""" orderBy: ReactionOrder ): ReactionConnection! """The repository associated with this node.""" repository: Repository! """The HTTP path permalink for this commit comment.""" resourcePath: URI! """Identifies the date and time when the object was last updated.""" updatedAt: DateTime! """The HTTP URL permalink for this commit comment.""" url: URI! """A list of edits to this content.""" userContentEdits( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): UserContentEditConnection """Check if the current viewer can delete this object.""" viewerCanDelete: Boolean! """Check if the current viewer can minimize this object.""" viewerCanMinimize: Boolean! """Can user react to this subject""" viewerCanReact: Boolean! """Check if the current viewer can update this object.""" viewerCanUpdate: Boolean! """Reasons why the current viewer can not update this comment.""" viewerCannotUpdateReasons: [CommentCannotUpdateReason!]! """Did the viewer author this comment.""" viewerDidAuthor: Boolean! } """The connection type for CommitComment.""" type CommitCommentConnection { """A list of edges.""" edges: [CommitCommentEdge] """A list of nodes.""" nodes: [CommitComment] """Information to aid in pagination.""" pageInfo: PageInfo! """Identifies the total count of items in the connection.""" totalCount: Int! } """An edge in a connection.""" type CommitCommentEdge { """A cursor for use in pagination.""" cursor: String! """The item at the end of the edge.""" node: CommitComment } """A thread of comments on a commit.""" type CommitCommentThread implements Node & RepositoryNode { """The comments that exist in this thread.""" comments( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): CommitCommentConnection! """The commit the comments were made on.""" commit: Commit! id: ID! """The file the comments were made on.""" path: String """The position in the diff for the commit that the comment was made on.""" position: Int """The repository associated with this node.""" repository: Repository! } """The connection type for Commit.""" type CommitConnection { """A list of edges.""" edges: [CommitEdge] """A list of nodes.""" nodes: [Commit] """Information to aid in pagination.""" pageInfo: PageInfo! """Identifies the total count of items in the connection.""" totalCount: Int! } """Ordering options for commit contribution connections.""" input CommitContributionOrder { """The field by which to order commit contributions.""" field: CommitContributionOrderField! """The ordering direction.""" direction: OrderDirection! } """Properties by which commit contribution connections can be ordered.""" enum CommitContributionOrderField { """Order commit contributions by when they were made.""" OCCURRED_AT """Order commit contributions by how many commits they represent.""" COMMIT_COUNT } """This aggregates commits made by a user within one repository.""" type CommitContributionsByRepository { """The commit contributions, each representing a day.""" contributions( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int """ Ordering options for commit contributions returned from the connection. """ orderBy: CommitContributionOrder ): CreatedCommitContributionConnection! """The repository in which the commits were made.""" repository: Repository! """ The HTTP path for the user's commits to the repository in this time range. """ resourcePath: URI! """ The HTTP URL for the user's commits to the repository in this time range. """ url: URI! } """An edge in a connection.""" type CommitEdge { """A cursor for use in pagination.""" cursor: String! """The item at the end of the edge.""" node: Commit } """The connection type for Commit.""" type CommitHistoryConnection { """A list of edges.""" edges: [CommitEdge] """A list of nodes.""" nodes: [Commit] """Information to aid in pagination.""" pageInfo: PageInfo! """Identifies the total count of items in the connection.""" totalCount: Int! } """A content attachment""" type ContentAttachment { """ The body text of the content attachment. This parameter supports markdown. """ body: String! """The content reference that the content attachment is attached to.""" contentReference: ContentReference! """Identifies the primary key from the database.""" databaseId: Int! id: ID! """The title of the content attachment.""" title: String! } """A content reference""" type ContentReference { """Identifies the primary key from the database.""" databaseId: Int! id: ID! """The reference of the content reference.""" reference: String! } """ Represents a contribution a user made on GitHub, such as opening an issue. """ interface Contribution { """ Whether this contribution is associated with a record you do not have access to. For example, your own 'first issue' contribution may have been made on a repository you can no longer access. """ isRestricted: Boolean! """When this contribution was made.""" occurredAt: DateTime! """The HTTP path for this contribution.""" resourcePath: URI! """The HTTP URL for this contribution.""" url: URI! """ The user who made this contribution. """ user: User! } """A calendar of contributions made on GitHub by a user.""" type ContributionCalendar { """ A list of hex color codes used in this calendar. The darker the color, the more contributions it represents. """ colors: [String!]! """ Determine if the color set was chosen because it's currently Halloween. """ isHalloween: Boolean! """A list of the months of contributions in this calendar.""" months: [ContributionCalendarMonth!]! """The count of total contributions in the calendar.""" totalContributions: Int! """A list of the weeks of contributions in this calendar.""" weeks: [ContributionCalendarWeek!]! } """Represents a single day of contributions on GitHub by a user.""" type ContributionCalendarDay { """ The hex color code that represents how many contributions were made on this day compared to others in the calendar. """ color: String! """How many contributions were made by the user on this day.""" contributionCount: Int! """The day this square represents.""" date: Date! """ A number representing which day of the week this square represents, e.g., 1 is Monday. """ weekday: Int! } """A month of contributions in a user's contribution graph.""" type ContributionCalendarMonth { """The date of the first day of this month.""" firstDay: Date! """The name of the month.""" name: String! """How many weeks started in this month.""" totalWeeks: Int! """The year the month occurred in.""" year: Int! } """A week of contributions in a user's contribution graph.""" type ContributionCalendarWeek { """The days of contributions in this week.""" contributionDays: [ContributionCalendarDay!]! """The date of the earliest square in this week.""" firstDay: Date! } """Ordering options for contribution connections.""" input ContributionOrder { """The field by which to order contributions.""" field: ContributionOrderField! """The ordering direction.""" direction: OrderDirection! } """Properties by which contribution connections can be ordered.""" enum ContributionOrderField { """Order contributions by when they were made.""" OCCURRED_AT } """ A contributions collection aggregates contributions such as opened issues and commits created by a user. """ type ContributionsCollection { """Commit contributions made by the user, grouped by repository.""" commitContributionsByRepository( """How many repositories should be included.""" maxRepositories: Int = 25 ): [CommitContributionsByRepository!]! """A calendar of this user's contributions on GitHub.""" contributionCalendar: ContributionCalendar! """ The years the user has been making contributions with the most recent year first. """ contributionYears: [Int!]! """ Determine if this collection's time span ends in the current month. """ doesEndInCurrentMonth: Boolean! """ The date of the first restricted contribution the user made in this time period. Can only be non-null when the user has enabled private contribution counts. """ earliestRestrictedContributionDate: Date """The ending date and time of this collection.""" endedAt: DateTime! """ The first issue the user opened on GitHub. This will be null if that issue was opened outside the collection's time range and ignoreTimeRange is false. If the issue is not visible but the user has opted to show private contributions, a RestrictedContribution will be returned. """ firstIssueContribution( """ If true, the first issue will be returned even if it was opened outside of the collection's time range. **Upcoming Change on 2019-07-01 UTC** **Description:** `ignoreTimeRange` will be removed. Use a `ContributionsCollection` starting sufficiently far back **Reason:** ignore_time_range will be removed """ ignoreTimeRange: Boolean = false ): CreatedIssueOrRestrictedContribution """ The first pull request the user opened on GitHub. This will be null if that pull request was opened outside the collection's time range and ignoreTimeRange is not true. If the pull request is not visible but the user has opted to show private contributions, a RestrictedContribution will be returned. """ firstPullRequestContribution( """ If true, the first pull request will be returned even if it was opened outside of the collection's time range. **Upcoming Change on 2019-07-01 UTC** **Description:** `ignoreTimeRange` will be removed. Use a `ContributionsCollection` starting sufficiently far back **Reason:** ignore_time_range will be removed """ ignoreTimeRange: Boolean = false ): CreatedPullRequestOrRestrictedContribution """ The first repository the user created on GitHub. This will be null if that first repository was created outside the collection's time range and ignoreTimeRange is false. If the repository is not visible, then a RestrictedContribution is returned. """ firstRepositoryContribution( """ If true, the first repository will be returned even if it was opened outside of the collection's time range. **Upcoming Change on 2019-07-01 UTC** **Description:** `ignoreTimeRange` will be removed. Use a `ContributionsCollection` starting sufficiently far back **Reason:** ignore_time_range will be removed """ ignoreTimeRange: Boolean = false ): CreatedRepositoryOrRestrictedContribution """ Does the user have any more activity in the timeline that occurred prior to the collection's time range? """ hasActivityInThePast: Boolean! """Determine if there are any contributions in this collection.""" hasAnyContributions: Boolean! """ Determine if the user made any contributions in this time frame whose details are not visible because they were made in a private repository. Can only be true if the user enabled private contribution counts. """ hasAnyRestrictedContributions: Boolean! """Whether or not the collector's time span is all within the same day.""" isSingleDay: Boolean! """A list of issues the user opened.""" issueContributions( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int """Should the user's first issue ever be excluded from the result.""" excludeFirst: Boolean = false """Should the user's most commented issue be excluded from the result.""" excludePopular: Boolean = false """Ordering options for contributions returned from the connection.""" orderBy: ContributionOrder ): CreatedIssueContributionConnection! """Issue contributions made by the user, grouped by repository.""" issueContributionsByRepository( """How many repositories should be included.""" maxRepositories: Int = 25 """Should the user's first issue ever be excluded from the result.""" excludeFirst: Boolean = false """Should the user's most commented issue be excluded from the result.""" excludePopular: Boolean = false ): [IssueContributionsByRepository!]! """ When the user signed up for GitHub. This will be null if that sign up date falls outside the collection's time range and ignoreTimeRange is false. """ joinedGitHubContribution( """ If true, the contribution will be returned even if the user signed up outside of the collection's time range. **Upcoming Change on 2019-07-01 UTC** **Description:** `ignoreTimeRange` will be removed. Use a `ContributionsCollection` starting sufficiently far back **Reason:** ignore_time_range will be removed """ ignoreTimeRange: Boolean = false ): JoinedGitHubContribution """ The date of the most recent restricted contribution the user made in this time period. Can only be non-null when the user has enabled private contribution counts. """ latestRestrictedContributionDate: Date """ When this collection's time range does not include any activity from the user, use this to get a different collection from an earlier time range that does have activity. """ mostRecentCollectionWithActivity: ContributionsCollection """ Returns a different contributions collection from an earlier time range than this one that does not have any contributions. """ mostRecentCollectionWithoutActivity: ContributionsCollection """ The issue the user opened on GitHub that received the most comments in the specified time frame. """ popularIssueContribution: CreatedIssueContribution """ The pull request the user opened on GitHub that received the most comments in the specified time frame. """ popularPullRequestContribution: CreatedPullRequestContribution """Pull request contributions made by the user.""" pullRequestContributions( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int """Should the user's first pull request ever be excluded from the result.""" excludeFirst: Boolean = false """ Should the user's most commented pull request be excluded from the result. """ excludePopular: Boolean = false """Ordering options for contributions returned from the connection.""" orderBy: ContributionOrder ): CreatedPullRequestContributionConnection! """Pull request contributions made by the user, grouped by repository.""" pullRequestContributionsByRepository( """How many repositories should be included.""" maxRepositories: Int = 25 """Should the user's first pull request ever be excluded from the result.""" excludeFirst: Boolean = false """ Should the user's most commented pull request be excluded from the result. """ excludePopular: Boolean = false ): [PullRequestContributionsByRepository!]! """Pull request review contributions made by the user.""" pullRequestReviewContributions( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int """Ordering options for contributions returned from the connection.""" orderBy: ContributionOrder ): CreatedPullRequestReviewContributionConnection! """ Pull request review contributions made by the user, grouped by repository. """ pullRequestReviewContributionsByRepository( """How many repositories should be included.""" maxRepositories: Int = 25 ): [PullRequestReviewContributionsByRepository!]! """ A list of repositories owned by the user that the user created in this time range. """ repositoryContributions( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int """Should the user's first repository ever be excluded from the result.""" excludeFirst: Boolean = false """Ordering options for contributions returned from the connection.""" orderBy: ContributionOrder ): CreatedRepositoryContributionConnection! """ A count of contributions made by the user that the viewer cannot access. Only non-zero when the user has chosen to share their private contribution counts. """ restrictedContributionsCount: Int! """The beginning date and time of this collection.""" startedAt: DateTime! """How many commits were made by the user in this time span.""" totalCommitContributions: Int! """How many issues the user opened.""" totalIssueContributions( """Should the user's first issue ever be excluded from this count.""" excludeFirst: Boolean = false """Should the user's most commented issue be excluded from this count.""" excludePopular: Boolean = false ): Int! """How many pull requests the user opened.""" totalPullRequestContributions( """Should the user's first pull request ever be excluded from this count.""" excludeFirst: Boolean = false """ Should the user's most commented pull request be excluded from this count. """ excludePopular: Boolean = false ): Int! """How many pull request reviews the user left.""" totalPullRequestReviewContributions: Int! """How many different repositories the user committed to.""" totalRepositoriesWithContributedCommits: Int! """How many different repositories the user opened issues in.""" totalRepositoriesWithContributedIssues( """Should the user's first issue ever be excluded from this count.""" excludeFirst: Boolean = false """Should the user's most commented issue be excluded from this count.""" excludePopular: Boolean = false ): Int! """How many different repositories the user left pull request reviews in.""" totalRepositoriesWithContributedPullRequestReviews: Int! """How many different repositories the user opened pull requests in.""" totalRepositoriesWithContributedPullRequests( """Should the user's first pull request ever be excluded from this count.""" excludeFirst: Boolean = false """ Should the user's most commented pull request be excluded from this count. """ excludePopular: Boolean = false ): Int! """How many repositories the user created.""" totalRepositoryContributions( """Should the user's first repository ever be excluded from this count.""" excludeFirst: Boolean = false ): Int! """The user who made the contributions in this collection.""" user: User! } """ Represents a 'converted_note_to_issue' event on a given issue or pull request. """ type ConvertedNoteToIssueEvent implements Node { """Identifies the actor who performed the event.""" actor: Actor """Identifies the date and time when the object was created.""" createdAt: DateTime! """Identifies the primary key from the database.""" databaseId: Int id: ID! } """Autogenerated input type of ConvertProjectCardNoteToIssue""" input ConvertProjectCardNoteToIssueInput { """The ProjectCard ID to convert.""" projectCardId: ID! """The ID of the repository to create the issue in.""" repositoryId: ID! """ The title of the newly created issue. Defaults to the card's note text. """ title: String """The body of the newly created issue.""" body: String """A unique identifier for the client performing the mutation.""" clientMutationId: String } """Autogenerated return type of ConvertProjectCardNoteToIssue""" type ConvertProjectCardNoteToIssuePayload { """A unique identifier for the client performing the mutation.""" clientMutationId: String """The updated ProjectCard.""" projectCard: ProjectCard } """Autogenerated input type of CreateBranchProtectionRule""" input CreateBranchProtectionRuleInput { """ The global relay id of the repository in which a new branch protection rule should be created in. """ repositoryId: ID! """The glob-like pattern used to determine matching branches.""" pattern: String! """Are approving reviews required to update matching branches.""" requiresApprovingReviews: Boolean """Number of approving reviews required to update matching branches.""" requiredApprovingReviewCount: Int """Are commits required to be signed.""" requiresCommitSignatures: Boolean """Can admins overwrite branch protection.""" isAdminEnforced: Boolean """Are status checks required to update matching branches.""" requiresStatusChecks: Boolean """Are branches required to be up to date before merging.""" requiresStrictStatusChecks: Boolean """Are reviews from code owners required to update matching branches.""" requiresCodeOwnerReviews: Boolean """ Will new commits pushed to matching branches dismiss pull request review approvals. """ dismissesStaleReviews: Boolean """Is dismissal of pull request reviews restricted.""" restrictsReviewDismissals: Boolean """ A list of User or Team IDs allowed to dismiss reviews on pull requests targeting matching branches. """ reviewDismissalActorIds: [ID!] """Is pushing to matching branches restricted.""" restrictsPushes: Boolean """A list of User or Team IDs allowed to push to matching branches.""" pushActorIds: [ID!] """ List of required status check contexts that must pass for commits to be accepted to matching branches. """ requiredStatusCheckContexts: [String!] """A unique identifier for the client performing the mutation.""" clientMutationId: String } """Autogenerated return type of CreateBranchProtectionRule""" type CreateBranchProtectionRulePayload { """The newly created BranchProtectionRule.""" branchProtectionRule: BranchProtectionRule """A unique identifier for the client performing the mutation.""" clientMutationId: String } """Autogenerated input type of CreateContentAttachment""" input CreateContentAttachmentInput { """The node ID of the content_reference.""" contentReferenceId: ID! """The title of the content attachment.""" title: String! """The body of the content attachment, which may contain markdown.""" body: String! """A unique identifier for the client performing the mutation.""" clientMutationId: String } """Represents the contribution a user made by committing to a repository.""" type CreatedCommitContribution implements Contribution { """How many commits were made on this day to this repository by the user.""" commitCount: Int! """ Whether this contribution is associated with a record you do not have access to. For example, your own 'first issue' contribution may have been made on a repository you can no longer access. """ isRestricted: Boolean! """When this contribution was made.""" occurredAt: DateTime! """The repository the user made a commit in.""" repository: Repository! """The HTTP path for this contribution.""" resourcePath: URI! """The HTTP URL for this contribution.""" url: URI! """ The user who made this contribution. """ user: User! } """The connection type for CreatedCommitContribution.""" type CreatedCommitContributionConnection { """A list of edges.""" edges: [CreatedCommitContributionEdge] """A list of nodes.""" nodes: [CreatedCommitContribution] """Information to aid in pagination.""" pageInfo: PageInfo! """ Identifies the total count of commits across days and repositories in the connection. """ totalCount: Int! } """An edge in a connection.""" type CreatedCommitContributionEdge { """A cursor for use in pagination.""" cursor: String! """The item at the end of the edge.""" node: CreatedCommitContribution } """Represents the contribution a user made on GitHub by opening an issue.""" type CreatedIssueContribution implements Contribution { """ Whether this contribution is associated with a record you do not have access to. For example, your own 'first issue' contribution may have been made on a repository you can no longer access. """ isRestricted: Boolean! """The issue that was opened.""" issue: Issue! """When this contribution was made.""" occurredAt: DateTime! """The HTTP path for this contribution.""" resourcePath: URI! """The HTTP URL for this contribution.""" url: URI! """ The user who made this contribution. """ user: User! } """The connection type for CreatedIssueContribution.""" type CreatedIssueContributionConnection { """A list of edges.""" edges: [CreatedIssueContributionEdge] """A list of nodes.""" nodes: [CreatedIssueContribution] """Information to aid in pagination.""" pageInfo: PageInfo! """Identifies the total count of items in the connection.""" totalCount: Int! } """An edge in a connection.""" type CreatedIssueContributionEdge { """A cursor for use in pagination.""" cursor: String! """The item at the end of the edge.""" node: CreatedIssueContribution } """ Represents either a issue the viewer can access or a restricted contribution. """ union CreatedIssueOrRestrictedContribution = CreatedIssueContribution | RestrictedContribution """ Represents the contribution a user made on GitHub by opening a pull request. """ type CreatedPullRequestContribution implements Contribution { """ Whether this contribution is associated with a record you do not have access to. For example, your own 'first issue' contribution may have been made on a repository you can no longer access. """ isRestricted: Boolean! """When this contribution was made.""" occurredAt: DateTime! """The pull request that was opened.""" pullRequest: PullRequest! """The HTTP path for this contribution.""" resourcePath: URI! """The HTTP URL for this contribution.""" url: URI! """ The user who made this contribution. """ user: User! } """The connection type for CreatedPullRequestContribution.""" type CreatedPullRequestContributionConnection { """A list of edges.""" edges: [CreatedPullRequestContributionEdge] """A list of nodes.""" nodes: [CreatedPullRequestContribution] """Information to aid in pagination.""" pageInfo: PageInfo! """Identifies the total count of items in the connection.""" totalCount: Int! } """An edge in a connection.""" type CreatedPullRequestContributionEdge { """A cursor for use in pagination.""" cursor: String! """The item at the end of the edge.""" node: CreatedPullRequestContribution } """ Represents either a pull request the viewer can access or a restricted contribution. """ union CreatedPullRequestOrRestrictedContribution = CreatedPullRequestContribution | RestrictedContribution """ Represents the contribution a user made by leaving a review on a pull request. """ type CreatedPullRequestReviewContribution implements Contribution { """ Whether this contribution is associated with a record you do not have access to. For example, your own 'first issue' contribution may have been made on a repository you can no longer access. """ isRestricted: Boolean! """When this contribution was made.""" occurredAt: DateTime! """The pull request the user reviewed.""" pullRequest: PullRequest! """The review the user left on the pull request.""" pullRequestReview: PullRequestReview! """The repository containing the pull request that the user reviewed.""" repository: Repository! """The HTTP path for this contribution.""" resourcePath: URI! """The HTTP URL for this contribution.""" url: URI! """ The user who made this contribution. """ user: User! } """The connection type for CreatedPullRequestReviewContribution.""" type CreatedPullRequestReviewContributionConnection { """A list of edges.""" edges: [CreatedPullRequestReviewContributionEdge] """A list of nodes.""" nodes: [CreatedPullRequestReviewContribution] """Information to aid in pagination.""" pageInfo: PageInfo! """Identifies the total count of items in the connection.""" totalCount: Int! } """An edge in a connection.""" type CreatedPullRequestReviewContributionEdge { """A cursor for use in pagination.""" cursor: String! """The item at the end of the edge.""" node: CreatedPullRequestReviewContribution } """ Represents the contribution a user made on GitHub by creating a repository. """ type CreatedRepositoryContribution implements Contribution { """ Whether this contribution is associated with a record you do not have access to. For example, your own 'first issue' contribution may have been made on a repository you can no longer access. """ isRestricted: Boolean! """When this contribution was made.""" occurredAt: DateTime! """The repository that was created.""" repository: Repository! """The HTTP path for this contribution.""" resourcePath: URI! """The HTTP URL for this contribution.""" url: URI! """ The user who made this contribution. """ user: User! } """The connection type for CreatedRepositoryContribution.""" type CreatedRepositoryContributionConnection { """A list of edges.""" edges: [CreatedRepositoryContributionEdge] """A list of nodes.""" nodes: [CreatedRepositoryContribution] """Information to aid in pagination.""" pageInfo: PageInfo! """Identifies the total count of items in the connection.""" totalCount: Int! } """An edge in a connection.""" type CreatedRepositoryContributionEdge { """A cursor for use in pagination.""" cursor: String! """The item at the end of the edge.""" node: CreatedRepositoryContribution } """ Represents either a repository the viewer can access or a restricted contribution. """ union CreatedRepositoryOrRestrictedContribution = CreatedRepositoryContribution | RestrictedContribution """Autogenerated input type of CreateIssue""" input CreateIssueInput { """The Node ID of the repository.""" repositoryId: ID! """The title for the issue.""" title: String! """The body for the issue description.""" body: String """The Node ID for the user assignee for this issue.""" assigneeIds: [ID!] """The Node ID of the milestone for this issue.""" milestoneId: ID """An array of Node IDs of labels for this issue.""" labelIds: [ID!] """An array of Node IDs for projects associated with this issue.""" projectIds: [ID!] """A unique identifier for the client performing the mutation.""" clientMutationId: String } """Autogenerated return type of CreateIssue""" type CreateIssuePayload { """A unique identifier for the client performing the mutation.""" clientMutationId: String """The new issue.""" issue: Issue } """Autogenerated input type of CreateProject""" input CreateProjectInput { """The owner ID to create the project under.""" ownerId: ID! """The name of project.""" name: String! """The description of project.""" body: String """A unique identifier for the client performing the mutation.""" clientMutationId: String } """Autogenerated return type of CreateProject""" type CreateProjectPayload { """A unique identifier for the client performing the mutation.""" clientMutationId: String """The new project.""" project: Project } """Autogenerated input type of CreatePullRequest""" input CreatePullRequestInput { """The Node ID of the repository.""" repositoryId: ID! """ The name of the branch you want your changes pulled into. This should be an existing branch on the current repository. You cannot update the base branch on a pull request to point to another repository. """ baseRefName: String! """ The name of the branch where your changes are implemented. For cross-repository pull requests in the same network, namespace `head_ref_name` with a user like this: `username:branch`. """ headRefName: String! """The title of the pull request.""" title: String! """The contents of the pull request.""" body: String """Indicates whether maintainers can modify the pull request.""" maintainerCanModify: Boolean = true """A unique identifier for the client performing the mutation.""" clientMutationId: String } """Autogenerated return type of CreatePullRequest""" type CreatePullRequestPayload { """A unique identifier for the client performing the mutation.""" clientMutationId: String """The new pull request.""" pullRequest: PullRequest } """Represents a mention made by one issue or pull request to another.""" type CrossReferencedEvent implements Node & UniformResourceLocatable { """Identifies the actor who performed the event.""" actor: Actor """Identifies the date and time when the object was created.""" createdAt: DateTime! id: ID! """Reference originated in a different repository.""" isCrossRepository: Boolean! """Identifies when the reference was made.""" referencedAt: DateTime! """The HTTP path for this pull request.""" resourcePath: URI! """Issue or pull request that made the reference.""" source: ReferencedSubject! """Issue or pull request to which the reference was made.""" target: ReferencedSubject! """The HTTP URL for this pull request.""" url: URI! """Checks if the target will be closed when the source is merged.""" willCloseTarget: Boolean! } """An ISO-8601 encoded date string.""" scalar Date """An ISO-8601 encoded UTC date string.""" scalar DateTime """Autogenerated input type of DeclineTopicSuggestion""" input DeclineTopicSuggestionInput { """The Node ID of the repository.""" repositoryId: ID! """The name of the suggested topic.""" name: String! """The reason why the suggested topic is declined.""" reason: TopicSuggestionDeclineReason! """A unique identifier for the client performing the mutation.""" clientMutationId: String } """Autogenerated return type of DeclineTopicSuggestion""" type DeclineTopicSuggestionPayload { """A unique identifier for the client performing the mutation.""" clientMutationId: String """The declined topic.""" topic: Topic } """The possible default permissions for repositories.""" enum DefaultRepositoryPermissionField { """No access""" NONE """Can read repos by default""" READ """Can read and write repos by default""" WRITE """Can read, write, and administrate repos by default""" ADMIN } """Entities that can be deleted.""" interface Deletable { """Check if the current viewer can delete this object.""" viewerCanDelete: Boolean! } """Autogenerated input type of DeleteBranchProtectionRule""" input DeleteBranchProtectionRuleInput { """The global relay id of the branch protection rule to be deleted.""" branchProtectionRuleId: ID! """A unique identifier for the client performing the mutation.""" clientMutationId: String } """Autogenerated return type of DeleteBranchProtectionRule""" type DeleteBranchProtectionRulePayload { """A unique identifier for the client performing the mutation.""" clientMutationId: String } """Autogenerated input type of DeleteIssueComment""" input DeleteIssueCommentInput { """The ID of the comment to delete.""" id: ID! """A unique identifier for the client performing the mutation.""" clientMutationId: String } """Autogenerated return type of DeleteIssueComment""" type DeleteIssueCommentPayload { """A unique identifier for the client performing the mutation.""" clientMutationId: String } """Autogenerated input type of DeleteIssue""" input DeleteIssueInput { """The ID of the issue to delete.""" issueId: ID! """A unique identifier for the client performing the mutation.""" clientMutationId: String } """Autogenerated return type of DeleteIssue""" type DeleteIssuePayload { """A unique identifier for the client performing the mutation.""" clientMutationId: String """The repository the issue belonged to""" repository: Repository } """Autogenerated input type of DeleteProjectCard""" input DeleteProjectCardInput { """The id of the card to delete.""" cardId: ID! """A unique identifier for the client performing the mutation.""" clientMutationId: String } """Autogenerated return type of DeleteProjectCard""" type DeleteProjectCardPayload { """A unique identifier for the client performing the mutation.""" clientMutationId: String """The column the deleted card was in.""" column: ProjectColumn """The deleted card ID.""" deletedCardId: ID } """Autogenerated input type of DeleteProjectColumn""" input DeleteProjectColumnInput { """The id of the column to delete.""" columnId: ID! """A unique identifier for the client performing the mutation.""" clientMutationId: String } """Autogenerated return type of DeleteProjectColumn""" type DeleteProjectColumnPayload { """A unique identifier for the client performing the mutation.""" clientMutationId: String """The deleted column ID.""" deletedColumnId: ID """The project the deleted column was in.""" project: Project } """Autogenerated input type of DeleteProject""" input DeleteProjectInput { """The Project ID to update.""" projectId: ID! """A unique identifier for the client performing the mutation.""" clientMutationId: String } """Autogenerated return type of DeleteProject""" type DeleteProjectPayload { """A unique identifier for the client performing the mutation.""" clientMutationId: String """The repository or organization the project was removed from.""" owner: ProjectOwner } """Autogenerated input type of DeletePullRequestReviewComment""" input DeletePullRequestReviewCommentInput { """The ID of the comment to delete.""" id: ID! """A unique identifier for the client performing the mutation.""" clientMutationId: String } """Autogenerated return type of DeletePullRequestReviewComment""" type DeletePullRequestReviewCommentPayload { """A unique identifier for the client performing the mutation.""" clientMutationId: String """The pull request review the deleted comment belonged to.""" pullRequestReview: PullRequestReview } """Autogenerated input type of DeletePullRequestReview""" input DeletePullRequestReviewInput { """The Node ID of the pull request review to delete.""" pullRequestReviewId: ID! """A unique identifier for the client performing the mutation.""" clientMutationId: String } """Autogenerated return type of DeletePullRequestReview""" type DeletePullRequestReviewPayload { """A unique identifier for the client performing the mutation.""" clientMutationId: String """The deleted pull request review.""" pullRequestReview: PullRequestReview } """Represents a 'demilestoned' event on a given issue or pull request.""" type DemilestonedEvent implements Node { """Identifies the actor who performed the event.""" actor: Actor """Identifies the date and time when the object was created.""" createdAt: DateTime! id: ID! """ Identifies the milestone title associated with the 'demilestoned' event. """ milestoneTitle: String! """Object referenced by event.""" subject: MilestoneItem! } """Represents a 'deployed' event on a given pull request.""" type DeployedEvent implements Node { """Identifies the actor who performed the event.""" actor: Actor """Identifies the date and time when the object was created.""" createdAt: DateTime! """Identifies the primary key from the database.""" databaseId: Int """The deployment associated with the 'deployed' event.""" deployment: Deployment! id: ID! """PullRequest referenced by event.""" pullRequest: PullRequest! """The ref associated with the 'deployed' event.""" ref: Ref } """A repository deploy key.""" type DeployKey implements Node { """Identifies the date and time when the object was created.""" createdAt: DateTime! id: ID! """The deploy key.""" key: String! """Whether or not the deploy key is read only.""" readOnly: Boolean! """The deploy key title.""" title: String! """Whether or not the deploy key has been verified.""" verified: Boolean! } """The connection type for DeployKey.""" type DeployKeyConnection { """A list of edges.""" edges: [DeployKeyEdge] """A list of nodes.""" nodes: [DeployKey] """Information to aid in pagination.""" pageInfo: PageInfo! """Identifies the total count of items in the connection.""" totalCount: Int! } """An edge in a connection.""" type DeployKeyEdge { """A cursor for use in pagination.""" cursor: String! """The item at the end of the edge.""" node: DeployKey } """Represents triggered deployment instance.""" type Deployment implements Node { """Identifies the commit sha of the deployment.""" commit: Commit """ Identifies the oid of the deployment commit, even if the commit has been deleted. """ commitOid: String! """Identifies the date and time when the object was created.""" createdAt: DateTime! """Identifies the actor who triggered the deployment.""" creator: Actor """Identifies the primary key from the database.""" databaseId: Int """The deployment description.""" description: String """The environment to which this deployment was made.""" environment: String id: ID! """The latest status of this deployment.""" latestStatus: DeploymentStatus """Extra information that a deployment system might need.""" payload: String """ Identifies the Ref of the deployment, if the deployment was created by ref. """ ref: Ref """Identifies the repository associated with the deployment.""" repository: Repository! """The current state of the deployment.""" state: DeploymentState """A list of statuses associated with the deployment.""" statuses( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): DeploymentStatusConnection """The deployment task.""" task: String """Identifies the date and time when the object was last updated.""" updatedAt: DateTime! } """The connection type for Deployment.""" type DeploymentConnection { """A list of edges.""" edges: [DeploymentEdge] """A list of nodes.""" nodes: [Deployment] """Information to aid in pagination.""" pageInfo: PageInfo! """Identifies the total count of items in the connection.""" totalCount: Int! } """An edge in a connection.""" type DeploymentEdge { """A cursor for use in pagination.""" cursor: String! """The item at the end of the edge.""" node: Deployment } """ Represents a 'deployment_environment_changed' event on a given pull request. """ type DeploymentEnvironmentChangedEvent implements Node { """Identifies the actor who performed the event.""" actor: Actor """Identifies the date and time when the object was created.""" createdAt: DateTime! """The deployment status that updated the deployment environment.""" deploymentStatus: DeploymentStatus! id: ID! """PullRequest referenced by event.""" pullRequest: PullRequest! } """Ordering options for deployment connections""" input DeploymentOrder { """The field to order deployments by.""" field: DeploymentOrderField! """The ordering direction.""" direction: OrderDirection! } """Properties by which deployment connections can be ordered.""" enum DeploymentOrderField { """Order collection by creation time""" CREATED_AT } """The possible states in which a deployment can be.""" enum DeploymentState { """The pending deployment was not updated after 30 minutes.""" ABANDONED """The deployment is currently active.""" ACTIVE """An inactive transient deployment.""" DESTROYED """The deployment experienced an error.""" ERROR """The deployment has failed.""" FAILURE """The deployment is inactive.""" INACTIVE """The deployment is pending.""" PENDING """The deployment has queued""" QUEUED """The deployment is in progress.""" IN_PROGRESS } """Describes the status of a given deployment attempt.""" type DeploymentStatus implements Node { """Identifies the date and time when the object was created.""" createdAt: DateTime! """Identifies the actor who triggered the deployment.""" creator: Actor """Identifies the deployment associated with status.""" deployment: Deployment! """Identifies the description of the deployment.""" description: String """Identifies the environment URL of the deployment.""" environmentUrl: URI id: ID! """Identifies the log URL of the deployment.""" logUrl: URI """Identifies the current state of the deployment.""" state: DeploymentStatusState! """Identifies the date and time when the object was last updated.""" updatedAt: DateTime! } """The connection type for DeploymentStatus.""" type DeploymentStatusConnection { """A list of edges.""" edges: [DeploymentStatusEdge] """A list of nodes.""" nodes: [DeploymentStatus] """Information to aid in pagination.""" pageInfo: PageInfo! """Identifies the total count of items in the connection.""" totalCount: Int! } """An edge in a connection.""" type DeploymentStatusEdge { """A cursor for use in pagination.""" cursor: String! """The item at the end of the edge.""" node: DeploymentStatus } """The possible states for a deployment status.""" enum DeploymentStatusState { """The deployment is pending.""" PENDING """The deployment was successful.""" SUCCESS """The deployment has failed.""" FAILURE """The deployment is inactive.""" INACTIVE """The deployment experienced an error.""" ERROR """The deployment is queued""" QUEUED """The deployment is in progress.""" IN_PROGRESS } """Autogenerated input type of DismissPullRequestReview""" input DismissPullRequestReviewInput { """The Node ID of the pull request review to modify.""" pullRequestReviewId: ID! """The contents of the pull request review dismissal message.""" message: String! """A unique identifier for the client performing the mutation.""" clientMutationId: String } """Autogenerated return type of DismissPullRequestReview""" type DismissPullRequestReviewPayload { """A unique identifier for the client performing the mutation.""" clientMutationId: String """The dismissed pull request review.""" pullRequestReview: PullRequestReview } """Specifies a review comment to be left with a Pull Request Review.""" input DraftPullRequestReviewComment { """Path to the file being commented on.""" path: String! """Position in the file to leave a comment on.""" position: Int! """Body of the comment to leave.""" body: String! } """An external identity provisioned by SAML SSO or SCIM.""" type ExternalIdentity implements Node { """The GUID for this identity""" guid: String! id: ID! """Organization invitation for this SCIM-provisioned external identity""" organizationInvitation: OrganizationInvitation """SAML Identity attributes""" samlIdentity: ExternalIdentitySamlAttributes """SCIM Identity attributes""" scimIdentity: ExternalIdentityScimAttributes """ User linked to this external identity. Will be NULL if this identity has not been claimed by an organization member. """ user: User } """The connection type for ExternalIdentity.""" type ExternalIdentityConnection { """A list of edges.""" edges: [ExternalIdentityEdge] """A list of nodes.""" nodes: [ExternalIdentity] """Information to aid in pagination.""" pageInfo: PageInfo! """Identifies the total count of items in the connection.""" totalCount: Int! } """An edge in a connection.""" type ExternalIdentityEdge { """A cursor for use in pagination.""" cursor: String! """The item at the end of the edge.""" node: ExternalIdentity } """SAML attributes for the External Identity""" type ExternalIdentitySamlAttributes { """The NameID of the SAML identity""" nameId: String } """SCIM attributes for the External Identity""" type ExternalIdentityScimAttributes { """The userName of the SCIM identity""" username: String } """The connection type for User.""" type FollowerConnection { """A list of edges.""" edges: [UserEdge] """A list of nodes.""" nodes: [User] """Information to aid in pagination.""" pageInfo: PageInfo! """Identifies the total count of items in the connection.""" totalCount: Int! } """The connection type for User.""" type FollowingConnection { """A list of edges.""" edges: [UserEdge] """A list of nodes.""" nodes: [User] """Information to aid in pagination.""" pageInfo: PageInfo! """Identifies the total count of items in the connection.""" totalCount: Int! } """A Gist.""" type Gist implements Node & Starrable { """A list of comments associated with the gist""" comments( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): GistCommentConnection! """Identifies the date and time when the object was created.""" createdAt: DateTime! """The gist description.""" description: String """The files in this gist.""" files( """The maximum number of files to return.""" limit: Int = 10 ): [GistFile] id: ID! """Identifies if the gist is a fork.""" isFork: Boolean! """Whether the gist is public or not.""" isPublic: Boolean! """The gist name.""" name: String! """The gist owner.""" owner: RepositoryOwner """Identifies when the gist was last pushed to.""" pushedAt: DateTime """A list of users who have starred this starrable.""" stargazers( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int """Order for connection""" orderBy: StarOrder ): StargazerConnection! """Identifies the date and time when the object was last updated.""" updatedAt: DateTime! """ Returns a boolean indicating whether the viewing user has starred this starrable. """ viewerHasStarred: Boolean! } """Represents a comment on an Gist.""" type GistComment implements Node & Comment & Deletable & Updatable & UpdatableComment { """The actor who authored the comment.""" author: Actor """Author's association with the gist.""" authorAssociation: CommentAuthorAssociation! """Identifies the comment body.""" body: String! """The comment body rendered to HTML.""" bodyHTML: HTML! """The body rendered to text.""" bodyText: String! """Identifies the date and time when the object was created.""" createdAt: DateTime! """Check if this comment was created via an email reply.""" createdViaEmail: Boolean! """Identifies the primary key from the database.""" databaseId: Int """The actor who edited the comment.""" editor: Actor """The associated gist.""" gist: Gist! id: ID! """ Check if this comment was edited and includes an edit with the creation data """ includesCreatedEdit: Boolean! """Returns whether or not a comment has been minimized.""" isMinimized: Boolean! """The moment the editor made the last edit""" lastEditedAt: DateTime """Returns why the comment was minimized.""" minimizedReason: String """Identifies when the comment was published at.""" publishedAt: DateTime """Identifies the date and time when the object was last updated.""" updatedAt: DateTime! """A list of edits to this content.""" userContentEdits( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): UserContentEditConnection """Check if the current viewer can delete this object.""" viewerCanDelete: Boolean! """Check if the current viewer can minimize this object.""" viewerCanMinimize: Boolean! """Check if the current viewer can update this object.""" viewerCanUpdate: Boolean! """Reasons why the current viewer can not update this comment.""" viewerCannotUpdateReasons: [CommentCannotUpdateReason!]! """Did the viewer author this comment.""" viewerDidAuthor: Boolean! } """The connection type for GistComment.""" type GistCommentConnection { """A list of edges.""" edges: [GistCommentEdge] """A list of nodes.""" nodes: [GistComment] """Information to aid in pagination.""" pageInfo: PageInfo! """Identifies the total count of items in the connection.""" totalCount: Int! } """An edge in a connection.""" type GistCommentEdge { """A cursor for use in pagination.""" cursor: String! """The item at the end of the edge.""" node: GistComment } """The connection type for Gist.""" type GistConnection { """A list of edges.""" edges: [GistEdge] """A list of nodes.""" nodes: [Gist] """Information to aid in pagination.""" pageInfo: PageInfo! """Identifies the total count of items in the connection.""" totalCount: Int! } """An edge in a connection.""" type GistEdge { """A cursor for use in pagination.""" cursor: String! """The item at the end of the edge.""" node: Gist } """A file in a gist.""" type GistFile { """ The file name encoded to remove characters that are invalid in URL paths. """ encodedName: String """The gist file encoding.""" encoding: String """The file extension from the file name.""" extension: String """Indicates if this file is an image.""" isImage: Boolean! """Whether the file's contents were truncated.""" isTruncated: Boolean! """The programming language this file is written in.""" language: Language """The gist file name.""" name: String """The gist file size in bytes.""" size: Int """UTF8 text data or null if the file is binary""" text( """Optionally truncate the returned file to this length.""" truncate: Int ): String } """Ordering options for gist connections""" input GistOrder { """The field to order repositories by.""" field: GistOrderField! """The ordering direction.""" direction: OrderDirection! } """Properties by which gist connections can be ordered.""" enum GistOrderField { """Order gists by creation time""" CREATED_AT """Order gists by update time""" UPDATED_AT """Order gists by push time""" PUSHED_AT } """The privacy of a Gist""" enum GistPrivacy { """Public""" PUBLIC """Secret""" SECRET """Gists that are public and secret""" ALL } """Represents an actor in a Git commit (ie. an author or committer).""" type GitActor { """A URL pointing to the author's public avatar.""" avatarUrl( """The size of the resulting square image.""" size: Int ): URI! """The timestamp of the Git action (authoring or committing).""" date: GitTimestamp """The email in the Git commit.""" email: String """The name in the Git commit.""" name: String """ The GitHub user corresponding to the email field. Null if no such user exists. """ user: User } """Represents information about the GitHub instance.""" type GitHubMetadata { """Returns a String that's a SHA of `github-services`""" gitHubServicesSha: GitObjectID! """IP addresses that users connect to for git operations""" gitIpAddresses: [String!] """IP addresses that service hooks are sent from""" hookIpAddresses: [String!] """IP addresses that the importer connects from""" importerIpAddresses: [String!] """Whether or not users are verified""" isPasswordAuthenticationVerifiable: Boolean! """IP addresses for GitHub Pages' A records""" pagesIpAddresses: [String!] } """Represents a Git object.""" interface GitObject { """An abbreviated version of the Git object ID""" abbreviatedOid: String! """The HTTP path for this Git object""" commitResourcePath: URI! """The HTTP URL for this Git object""" commitUrl: URI! id: ID! """The Git object ID""" oid: GitObjectID! """The Repository the Git object belongs to""" repository: Repository! } """A Git object ID.""" scalar GitObjectID """Information about a signature (GPG or S/MIME) on a Commit or Tag.""" interface GitSignature { """Email used to sign this object.""" email: String! """True if the signature is valid and verified by GitHub.""" isValid: Boolean! """ Payload for GPG signing object. Raw ODB object without the signature header. """ payload: String! """ASCII-armored signature header from object.""" signature: String! """GitHub user corresponding to the email signing this commit.""" signer: User """ The state of this signature. `VALID` if signature is valid and verified by GitHub, otherwise represents reason why signature is considered invalid. """ state: GitSignatureState! """True if the signature was made with GitHub's signing key.""" wasSignedByGitHub: Boolean! } """The state of a Git signature.""" enum GitSignatureState { """Valid signature and verified by GitHub""" VALID """Invalid signature""" INVALID """Malformed signature""" MALFORMED_SIG """Key used for signing not known to GitHub""" UNKNOWN_KEY """Invalid email used for signing""" BAD_EMAIL """Email used for signing unverified on GitHub""" UNVERIFIED_EMAIL """Email used for signing not known to GitHub""" NO_USER """Unknown signature type""" UNKNOWN_SIG_TYPE """Unsigned""" UNSIGNED """ Internal error - the GPG verification service is unavailable at the moment """ GPGVERIFY_UNAVAILABLE """Internal error - the GPG verification service misbehaved""" GPGVERIFY_ERROR """The usage flags for the key that signed this don't allow signing""" NOT_SIGNING_KEY """Signing key expired""" EXPIRED_KEY """Valid signature, pending certificate revocation checking""" OCSP_PENDING """Valid siganture, though certificate revocation check failed""" OCSP_ERROR """The signing certificate or its chain could not be verified""" BAD_CERT """One or more certificates in chain has been revoked""" OCSP_REVOKED } """Git SSH string""" scalar GitSSHRemote """ An ISO-8601 encoded date string. Unlike the DateTime type, GitTimestamp is not converted in UTC. """ scalar GitTimestamp """Represents a GPG signature on a Commit or Tag.""" type GpgSignature implements GitSignature { """Email used to sign this object.""" email: String! """True if the signature is valid and verified by GitHub.""" isValid: Boolean! """Hex-encoded ID of the key that signed this object.""" keyId: String """ Payload for GPG signing object. Raw ODB object without the signature header. """ payload: String! """ASCII-armored signature header from object.""" signature: String! """GitHub user corresponding to the email signing this commit.""" signer: User """ The state of this signature. `VALID` if signature is valid and verified by GitHub, otherwise represents reason why signature is considered invalid. """ state: GitSignatureState! """True if the signature was made with GitHub's signing key.""" wasSignedByGitHub: Boolean! } """Represents a 'head_ref_deleted' event on a given pull request.""" type HeadRefDeletedEvent implements Node { """Identifies the actor who performed the event.""" actor: Actor """Identifies the date and time when the object was created.""" createdAt: DateTime! """Identifies the Ref associated with the `head_ref_deleted` event.""" headRef: Ref """ Identifies the name of the Ref associated with the `head_ref_deleted` event. """ headRefName: String! id: ID! """PullRequest referenced by event.""" pullRequest: PullRequest! } """Represents a 'head_ref_force_pushed' event on a given pull request.""" type HeadRefForcePushedEvent implements Node { """Identifies the actor who performed the event.""" actor: Actor """Identifies the after commit SHA for the 'head_ref_force_pushed' event.""" afterCommit: Commit """ Identifies the before commit SHA for the 'head_ref_force_pushed' event. """ beforeCommit: Commit """Identifies the date and time when the object was created.""" createdAt: DateTime! id: ID! """PullRequest referenced by event.""" pullRequest: PullRequest! """ Identifies the fully qualified ref name for the 'head_ref_force_pushed' event. """ ref: Ref } """Represents a 'head_ref_restored' event on a given pull request.""" type HeadRefRestoredEvent implements Node { """Identifies the actor who performed the event.""" actor: Actor """Identifies the date and time when the object was created.""" createdAt: DateTime! id: ID! """PullRequest referenced by event.""" pullRequest: PullRequest! } """A string containing HTML code.""" scalar HTML """ The possible states in which authentication can be configured with an identity provider. """ enum IdentityProviderConfigurationState { """Authentication with an identity provider is configured and enforced.""" ENFORCED """ Authentication with an identity provider is configured but not enforced. """ CONFIGURED """Authentication with an identity provider is not configured.""" UNCONFIGURED } """Autogenerated input type of ImportProject""" input ImportProjectInput { """The name of the Organization or User to create the Project under.""" ownerName: String! """The name of Project.""" name: String! """The description of Project.""" body: String """Whether the Project is public or not.""" public: Boolean = false """A list of columns containing issues and pull requests.""" columnImports: [ProjectColumnImport!]! """A unique identifier for the client performing the mutation.""" clientMutationId: String } """ An Issue is a place to discuss ideas, enhancements, tasks, and bugs for a project. """ type Issue implements Node & Assignable & Closable & Comment & Updatable & UpdatableComment & Labelable & Lockable & Reactable & RepositoryNode & Subscribable & UniformResourceLocatable { """Reason that the conversation was locked.""" activeLockReason: LockReason """A list of Users assigned to this object.""" assignees( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): UserConnection! """The actor who authored the comment.""" author: Actor """Author's association with the subject of the comment.""" authorAssociation: CommentAuthorAssociation! """Identifies the body of the issue.""" body: String! """Identifies the body of the issue rendered to HTML.""" bodyHTML: HTML! """Identifies the body of the issue rendered to text.""" bodyText: String! """ `true` if the object is closed (definition of closed may depend on type) """ closed: Boolean! """Identifies the date and time when the object was closed.""" closedAt: DateTime """A list of comments associated with the Issue.""" comments( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): IssueCommentConnection! """Identifies the date and time when the object was created.""" createdAt: DateTime! """Check if this comment was created via an email reply.""" createdViaEmail: Boolean! """Identifies the primary key from the database.""" databaseId: Int """The actor who edited the comment.""" editor: Actor id: ID! """ Check if this comment was edited and includes an edit with the creation data """ includesCreatedEdit: Boolean! """A list of labels associated with the object.""" labels( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): LabelConnection """The moment the editor made the last edit""" lastEditedAt: DateTime """`true` if the object is locked""" locked: Boolean! """Identifies the milestone associated with the issue.""" milestone: Milestone """Identifies the issue number.""" number: Int! """A list of Users that are participating in the Issue conversation.""" participants( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): UserConnection! """List of project cards associated with this issue.""" projectCards( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int """A list of archived states to filter the cards by""" archivedStates: [ProjectCardArchivedState] ): ProjectCardConnection! """Identifies when the comment was published at.""" publishedAt: DateTime """A list of reactions grouped by content left on the subject.""" reactionGroups: [ReactionGroup!] """A list of Reactions left on the Issue.""" reactions( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int """Allows filtering Reactions by emoji.""" content: ReactionContent """Allows specifying the order in which reactions are returned.""" orderBy: ReactionOrder ): ReactionConnection! """The repository associated with this node.""" repository: Repository! """The HTTP path for this issue""" resourcePath: URI! """Identifies the state of the issue.""" state: IssueState! """A list of events, comments, commits, etc. associated with the issue.""" timeline( """Allows filtering timeline events by a `since` timestamp.""" since: DateTime """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): IssueTimelineConnection! """A list of events, comments, commits, etc. associated with the issue.""" timelineItems( """Filter timeline items by a `since` timestamp.""" since: DateTime """Skips the first _n_ elements in the list.""" skip: Int """Filter timeline items by type.""" itemTypes: [IssueTimelineItemsItemType!] """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): IssueTimelineItemsConnection! """Identifies the issue title.""" title: String! """Identifies the date and time when the object was last updated.""" updatedAt: DateTime! """The HTTP URL for this issue""" url: URI! """A list of edits to this content.""" userContentEdits( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): UserContentEditConnection """Can user react to this subject""" viewerCanReact: Boolean! """ Check if the viewer is able to change their subscription status for the repository. """ viewerCanSubscribe: Boolean! """Check if the current viewer can update this object.""" viewerCanUpdate: Boolean! """Reasons why the current viewer can not update this comment.""" viewerCannotUpdateReasons: [CommentCannotUpdateReason!]! """Did the viewer author this comment.""" viewerDidAuthor: Boolean! """ Identifies if the viewer is watching, not watching, or ignoring the subscribable entity. """ viewerSubscription: SubscriptionState } """Represents a comment on an Issue.""" type IssueComment implements Node & Comment & Deletable & Updatable & UpdatableComment & Reactable & RepositoryNode { """The actor who authored the comment.""" author: Actor """Author's association with the subject of the comment.""" authorAssociation: CommentAuthorAssociation! """The body as Markdown.""" body: String! """The body rendered to HTML.""" bodyHTML: HTML! """The body rendered to text.""" bodyText: String! """Identifies the date and time when the object was created.""" createdAt: DateTime! """Check if this comment was created via an email reply.""" createdViaEmail: Boolean! """Identifies the primary key from the database.""" databaseId: Int """The actor who edited the comment.""" editor: Actor id: ID! """ Check if this comment was edited and includes an edit with the creation data """ includesCreatedEdit: Boolean! """Returns whether or not a comment has been minimized.""" isMinimized: Boolean! """Identifies the issue associated with the comment.""" issue: Issue! """The moment the editor made the last edit""" lastEditedAt: DateTime """Returns why the comment was minimized.""" minimizedReason: String """Identifies when the comment was published at.""" publishedAt: DateTime """ Returns the pull request associated with the comment, if this comment was made on a pull request. """ pullRequest: PullRequest """A list of reactions grouped by content left on the subject.""" reactionGroups: [ReactionGroup!] """A list of Reactions left on the Issue.""" reactions( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int """Allows filtering Reactions by emoji.""" content: ReactionContent """Allows specifying the order in which reactions are returned.""" orderBy: ReactionOrder ): ReactionConnection! """The repository associated with this node.""" repository: Repository! """The HTTP path for this issue comment""" resourcePath: URI! """Identifies the date and time when the object was last updated.""" updatedAt: DateTime! """The HTTP URL for this issue comment""" url: URI! """A list of edits to this content.""" userContentEdits( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): UserContentEditConnection """Check if the current viewer can delete this object.""" viewerCanDelete: Boolean! """Check if the current viewer can minimize this object.""" viewerCanMinimize: Boolean! """Can user react to this subject""" viewerCanReact: Boolean! """Check if the current viewer can update this object.""" viewerCanUpdate: Boolean! """Reasons why the current viewer can not update this comment.""" viewerCannotUpdateReasons: [CommentCannotUpdateReason!]! """Did the viewer author this comment.""" viewerDidAuthor: Boolean! } """The connection type for IssueComment.""" type IssueCommentConnection { """A list of edges.""" edges: [IssueCommentEdge] """A list of nodes.""" nodes: [IssueComment] """Information to aid in pagination.""" pageInfo: PageInfo! """Identifies the total count of items in the connection.""" totalCount: Int! } """An edge in a connection.""" type IssueCommentEdge { """A cursor for use in pagination.""" cursor: String! """The item at the end of the edge.""" node: IssueComment } """The connection type for Issue.""" type IssueConnection { """A list of edges.""" edges: [IssueEdge] """A list of nodes.""" nodes: [Issue] """Information to aid in pagination.""" pageInfo: PageInfo! """Identifies the total count of items in the connection.""" totalCount: Int! } """This aggregates issues opened by a user within one repository.""" type IssueContributionsByRepository { """The issue contributions.""" contributions( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int """Ordering options for contributions returned from the connection.""" orderBy: ContributionOrder ): CreatedIssueContributionConnection! """The repository in which the issues were opened.""" repository: Repository! } """An edge in a connection.""" type IssueEdge { """A cursor for use in pagination.""" cursor: String! """The item at the end of the edge.""" node: Issue } """Ways in which to filter lists of issues.""" input IssueFilters { """ List issues assigned to given name. Pass in `null` for issues with no assigned user, and `*` for issues assigned to any user. """ assignee: String """List issues created by given name.""" createdBy: String """List issues where the list of label names exist on the issue.""" labels: [String!] """List issues where the given name is mentioned in the issue.""" mentioned: String """ List issues by given milestone argument. If an string representation of an integer is passed, it should refer to a milestone by its number field. Pass in `null` for issues with no milestone, and `*` for issues that are assigned to any milestone. """ milestone: String """List issues that have been updated at or after the given date.""" since: DateTime """List issues filtered by the list of states given.""" states: [IssueState!] """List issues subscribed to by viewer.""" viewerSubscribed: Boolean = false } """Ways in which lists of issues can be ordered upon return.""" input IssueOrder { """The field in which to order issues by.""" field: IssueOrderField! """The direction in which to order issues by the specified field.""" direction: OrderDirection! } """Properties by which issue connections can be ordered.""" enum IssueOrderField { """Order issues by creation time""" CREATED_AT """Order issues by update time""" UPDATED_AT """Order issues by comment count""" COMMENTS } """Used for return value of Repository.issueOrPullRequest.""" union IssueOrPullRequest = Issue | PullRequest """The possible PubSub channels for an issue.""" enum IssuePubSubTopic { """The channel ID for observing issue updates.""" UPDATED """The channel ID for marking an issue as read.""" MARKASREAD """The channel ID for updating items on the issue timeline.""" TIMELINE """The channel ID for observing issue state updates.""" STATE } """The possible states of an issue.""" enum IssueState { """An issue that is still open""" OPEN """An issue that has been closed""" CLOSED } """The connection type for IssueTimelineItem.""" type IssueTimelineConnection { """A list of edges.""" edges: [IssueTimelineItemEdge] """A list of nodes.""" nodes: [IssueTimelineItem] """Information to aid in pagination.""" pageInfo: PageInfo! """Identifies the total count of items in the connection.""" totalCount: Int! } """An item in an issue timeline""" union IssueTimelineItem = Commit | IssueComment | CrossReferencedEvent | ClosedEvent | ReopenedEvent | SubscribedEvent | UnsubscribedEvent | ReferencedEvent | AssignedEvent | UnassignedEvent | LabeledEvent | UnlabeledEvent | UserBlockedEvent | MilestonedEvent | DemilestonedEvent | RenamedTitleEvent | LockedEvent | UnlockedEvent | TransferredEvent """An edge in a connection.""" type IssueTimelineItemEdge { """A cursor for use in pagination.""" cursor: String! """The item at the end of the edge.""" node: IssueTimelineItem } """An item in an issue timeline""" union IssueTimelineItems = IssueComment | CrossReferencedEvent | AddedToProjectEvent | AssignedEvent | ClosedEvent | CommentDeletedEvent | ConvertedNoteToIssueEvent | DemilestonedEvent | LabeledEvent | LockedEvent | MentionedEvent | MilestonedEvent | MovedColumnsInProjectEvent | PinnedEvent | ReferencedEvent | RemovedFromProjectEvent | RenamedTitleEvent | ReopenedEvent | SubscribedEvent | TransferredEvent | UnassignedEvent | UnlabeledEvent | UnlockedEvent | UserBlockedEvent | UnpinnedEvent | UnsubscribedEvent """The connection type for IssueTimelineItems.""" type IssueTimelineItemsConnection { """A list of edges.""" edges: [IssueTimelineItemsEdge] """ Identifies the count of items after applying `before` and `after` filters. """ filteredCount: Int! """A list of nodes.""" nodes: [IssueTimelineItems] """ Identifies the count of items after applying `before`/`after` filters and `first`/`last`/`skip` slicing. """ pageCount: Int! """Information to aid in pagination.""" pageInfo: PageInfo! """Identifies the total count of items in the connection.""" totalCount: Int! """Identifies the date and time when the timeline was last updated.""" updatedAt: DateTime! } """An edge in a connection.""" type IssueTimelineItemsEdge { """A cursor for use in pagination.""" cursor: String! """The item at the end of the edge.""" node: IssueTimelineItems } """The possible item types found in a timeline.""" enum IssueTimelineItemsItemType { """Represents a comment on an Issue.""" ISSUE_COMMENT """Represents a mention made by one issue or pull request to another.""" CROSS_REFERENCED_EVENT """ Represents a 'added_to_project' event on a given issue or pull request. """ ADDED_TO_PROJECT_EVENT """Represents an 'assigned' event on any assignable object.""" ASSIGNED_EVENT """Represents a 'closed' event on any `Closable`.""" CLOSED_EVENT """Represents a 'comment_deleted' event on a given issue or pull request.""" COMMENT_DELETED_EVENT """ Represents a 'converted_note_to_issue' event on a given issue or pull request. """ CONVERTED_NOTE_TO_ISSUE_EVENT """Represents a 'demilestoned' event on a given issue or pull request.""" DEMILESTONED_EVENT """Represents a 'labeled' event on a given issue or pull request.""" LABELED_EVENT """Represents a 'locked' event on a given issue or pull request.""" LOCKED_EVENT """Represents a 'mentioned' event on a given issue or pull request.""" MENTIONED_EVENT """Represents a 'milestoned' event on a given issue or pull request.""" MILESTONED_EVENT """ Represents a 'moved_columns_in_project' event on a given issue or pull request. """ MOVED_COLUMNS_IN_PROJECT_EVENT """Represents a 'pinned' event on a given issue or pull request.""" PINNED_EVENT """Represents a 'referenced' event on a given `ReferencedSubject`.""" REFERENCED_EVENT """ Represents a 'removed_from_project' event on a given issue or pull request. """ REMOVED_FROM_PROJECT_EVENT """Represents a 'renamed' event on a given issue or pull request""" RENAMED_TITLE_EVENT """Represents a 'reopened' event on any `Closable`.""" REOPENED_EVENT """Represents a 'subscribed' event on a given `Subscribable`.""" SUBSCRIBED_EVENT """Represents a 'transferred' event on a given issue or pull request.""" TRANSFERRED_EVENT """Represents an 'unassigned' event on any assignable object.""" UNASSIGNED_EVENT """Represents an 'unlabeled' event on a given issue or pull request.""" UNLABELED_EVENT """Represents an 'unlocked' event on a given issue or pull request.""" UNLOCKED_EVENT """Represents a 'user_blocked' event on a given user.""" USER_BLOCKED_EVENT """Represents an 'unpinned' event on a given issue or pull request.""" UNPINNED_EVENT """Represents an 'unsubscribed' event on a given `Subscribable`.""" UNSUBSCRIBED_EVENT } """Represents a user signing up for a GitHub account.""" type JoinedGitHubContribution implements Contribution { """ Whether this contribution is associated with a record you do not have access to. For example, your own 'first issue' contribution may have been made on a repository you can no longer access. """ isRestricted: Boolean! """When this contribution was made.""" occurredAt: DateTime! """The HTTP path for this contribution.""" resourcePath: URI! """The HTTP URL for this contribution.""" url: URI! """ The user who made this contribution. """ user: User! } """A label for categorizing Issues or Milestones with a given Repository.""" type Label implements Node { """Identifies the label color.""" color: String! """Identifies the date and time when the label was created.""" createdAt: DateTime """A brief description of this label.""" description: String id: ID! """Indicates whether or not this is a default label.""" isDefault: Boolean! """A list of issues associated with this label.""" issues( """Ordering options for issues returned from the connection.""" orderBy: IssueOrder """A list of label names to filter the pull requests by.""" labels: [String!] """A list of states to filter the issues by.""" states: [IssueState!] """Filtering options for issues returned from the connection.""" filterBy: IssueFilters """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): IssueConnection! """Identifies the label name.""" name: String! """A list of pull requests associated with this label.""" pullRequests( """A list of states to filter the pull requests by.""" states: [PullRequestState!] """A list of label names to filter the pull requests by.""" labels: [String!] """The head ref name to filter the pull requests by.""" headRefName: String """The base ref name to filter the pull requests by.""" baseRefName: String """Ordering options for pull requests returned from the connection.""" orderBy: IssueOrder """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): PullRequestConnection! """The repository associated with this label.""" repository: Repository! """The HTTP path for this label.""" resourcePath: URI! """Identifies the date and time when the label was last updated.""" updatedAt: DateTime """The HTTP URL for this label.""" url: URI! } """An object that can have labels assigned to it.""" interface Labelable { """A list of labels associated with the object.""" labels( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): LabelConnection } """The connection type for Label.""" type LabelConnection { """A list of edges.""" edges: [LabelEdge] """A list of nodes.""" nodes: [Label] """Information to aid in pagination.""" pageInfo: PageInfo! """Identifies the total count of items in the connection.""" totalCount: Int! } """Represents a 'labeled' event on a given issue or pull request.""" type LabeledEvent implements Node { """Identifies the actor who performed the event.""" actor: Actor """Identifies the date and time when the object was created.""" createdAt: DateTime! id: ID! """Identifies the label associated with the 'labeled' event.""" label: Label! """Identifies the `Labelable` associated with the event.""" labelable: Labelable! } """An edge in a connection.""" type LabelEdge { """A cursor for use in pagination.""" cursor: String! """The item at the end of the edge.""" node: Label } """Represents a given language found in repositories.""" type Language implements Node { """The color defined for the current language.""" color: String id: ID! """The name of the current language.""" name: String! } """A list of languages associated with the parent.""" type LanguageConnection { """A list of edges.""" edges: [LanguageEdge] """A list of nodes.""" nodes: [Language] """Information to aid in pagination.""" pageInfo: PageInfo! """Identifies the total count of items in the connection.""" totalCount: Int! """The total size in bytes of files written in that language.""" totalSize: Int! } """Represents the language of a repository.""" type LanguageEdge { cursor: String! node: Language! """The number of bytes of code written in the language.""" size: Int! } """Ordering options for language connections.""" input LanguageOrder { """The field to order languages by.""" field: LanguageOrderField! """The ordering direction.""" direction: OrderDirection! } """Properties by which language connections can be ordered.""" enum LanguageOrderField { """Order languages by the size of all files containing the language""" SIZE } """A repository's open source license""" type License implements Node { """The full text of the license""" body: String! """The conditions set by the license""" conditions: [LicenseRule]! """A human-readable description of the license""" description: String """Whether the license should be featured""" featured: Boolean! """Whether the license should be displayed in license pickers""" hidden: Boolean! id: ID! """Instructions on how to implement the license""" implementation: String """The lowercased SPDX ID of the license""" key: String! """The limitations set by the license""" limitations: [LicenseRule]! """The license full name specified by """ name: String! """Customary short name if applicable (e.g, GPLv3)""" nickname: String """The permissions set by the license""" permissions: [LicenseRule]! """ Whether the license is a pseudo-license placeholder (e.g., other, no-license) """ pseudoLicense: Boolean! """Short identifier specified by """ spdxId: String """URL to the license on """ url: URI } """Describes a License's conditions, permissions, and limitations""" type LicenseRule { """A description of the rule""" description: String! """The machine-readable rule key""" key: String! """The human-readable rule label""" label: String! } """An object that can be locked.""" interface Lockable { """Reason that the conversation was locked.""" activeLockReason: LockReason """`true` if the object is locked""" locked: Boolean! } """Represents a 'locked' event on a given issue or pull request.""" type LockedEvent implements Node { """Identifies the actor who performed the event.""" actor: Actor """Identifies the date and time when the object was created.""" createdAt: DateTime! id: ID! """Reason that the conversation was locked (optional).""" lockReason: LockReason """Object that was locked.""" lockable: Lockable! } """Autogenerated input type of LockLockable""" input LockLockableInput { """ID of the issue or pull request to be locked.""" lockableId: ID! """A reason for why the issue or pull request will be locked.""" lockReason: LockReason """A unique identifier for the client performing the mutation.""" clientMutationId: String } """Autogenerated return type of LockLockable""" type LockLockablePayload { """A unique identifier for the client performing the mutation.""" clientMutationId: String """The item that was locked.""" lockedRecord: Lockable } """The possible reasons that an issue or pull request was locked.""" enum LockReason { """ The issue or pull request was locked because the conversation was off-topic. """ OFF_TOPIC """ The issue or pull request was locked because the conversation was too heated. """ TOO_HEATED """ The issue or pull request was locked because the conversation was resolved. """ RESOLVED """ The issue or pull request was locked because the conversation was spam. """ SPAM } """A placeholder user for attribution of imported data on GitHub.""" type Mannequin implements Node & Actor & UniformResourceLocatable { """A URL pointing to the GitHub App's public avatar.""" avatarUrl( """The size of the resulting square image.""" size: Int ): URI! """Identifies the date and time when the object was created.""" createdAt: DateTime! """Identifies the primary key from the database.""" databaseId: Int id: ID! """The username of the actor.""" login: String! """The HTML path to this resource.""" resourcePath: URI! """Identifies the date and time when the object was last updated.""" updatedAt: DateTime! """The URL to this resource.""" url: URI! } """A public description of a Marketplace category.""" type MarketplaceCategory implements Node { """The category's description.""" description: String """ The technical description of how apps listed in this category work with GitHub. """ howItWorks: String id: ID! """The category's name.""" name: String! """How many Marketplace listings have this as their primary category.""" primaryListingCount: Int! """The HTTP path for this Marketplace category.""" resourcePath: URI! """How many Marketplace listings have this as their secondary category.""" secondaryListingCount: Int! """The short name of the category used in its URL.""" slug: String! """The HTTP URL for this Marketplace category.""" url: URI! } """A listing in the GitHub integration marketplace.""" type MarketplaceListing implements Node { """The GitHub App this listing represents.""" app: App """URL to the listing owner's company site.""" companyUrl: URI """ The HTTP path for configuring access to the listing's integration or OAuth app """ configurationResourcePath: URI! """ The HTTP URL for configuring access to the listing's integration or OAuth app """ configurationUrl: URI! """URL to the listing's documentation.""" documentationUrl: URI """The listing's detailed description.""" extendedDescription: String """The listing's detailed description rendered to HTML.""" extendedDescriptionHTML: HTML! """The listing's introductory description.""" fullDescription: String! """The listing's introductory description rendered to HTML.""" fullDescriptionHTML: HTML! """ Whether this listing has been submitted for review from GitHub for approval to be displayed in the Marketplace. """ hasApprovalBeenRequested: Boolean! @deprecated(reason: "`hasApprovalBeenRequested` will be removed. Use `isVerificationPendingFromDraft` instead. Removal on 2019-10-01 UTC.") """Does this listing have any plans with a free trial?""" hasPublishedFreeTrialPlans: Boolean! """Does this listing have a terms of service link?""" hasTermsOfService: Boolean! """A technical description of how this app works with GitHub.""" howItWorks: String """The listing's technical description rendered to HTML.""" howItWorksHTML: HTML! id: ID! """URL to install the product to the viewer's account or organization.""" installationUrl: URI """Whether this listing's app has been installed for the current viewer""" installedForViewer: Boolean! """Whether this listing has been approved for display in the Marketplace.""" isApproved: Boolean! @deprecated(reason: "`isApproved` will be removed. Use `isPublic` instead. Removal on 2019-10-01 UTC.") """Whether this listing has been removed from the Marketplace.""" isArchived: Boolean! """Whether this listing has been removed from the Marketplace.""" isDelisted: Boolean! @deprecated(reason: "`isDelisted` will be removed. Use `isArchived` instead. Removal on 2019-10-01 UTC.") """ Whether this listing is still an editable draft that has not been submitted for review and is not publicly visible in the Marketplace. """ isDraft: Boolean! """ Whether the product this listing represents is available as part of a paid plan. """ isPaid: Boolean! """Whether this listing has been approved for display in the Marketplace.""" isPublic: Boolean! """ Whether this listing has been rejected by GitHub for display in the Marketplace. """ isRejected: Boolean! """ Whether this listing has been approved for unverified display in the Marketplace. """ isUnverified: Boolean! """ Whether this draft listing has been submitted for review for approval to be unverified in the Marketplace. """ isUnverifiedPending: Boolean! """ Whether this draft listing has been submitted for review from GitHub for approval to be verified in the Marketplace. """ isVerificationPendingFromDraft: Boolean! """ Whether this unverified listing has been submitted for review from GitHub for approval to be verified in the Marketplace. """ isVerificationPendingFromUnverified: Boolean! """ Whether this listing has been approved for verified display in the Marketplace. """ isVerified: Boolean! """The hex color code, without the leading '#', for the logo background.""" logoBackgroundColor: String! """URL for the listing's logo image.""" logoUrl( """The size in pixels of the resulting square image.""" size: Int = 400 ): URI """The listing's full name.""" name: String! """ The listing's very short description without a trailing period or ampersands. """ normalizedShortDescription: String! """URL to the listing's detailed pricing.""" pricingUrl: URI """The category that best describes the listing.""" primaryCategory: MarketplaceCategory! """ URL to the listing's privacy policy, may return an empty string for listings that do not require a privacy policy URL. """ privacyPolicyUrl: URI! """The HTTP path for the Marketplace listing.""" resourcePath: URI! """The URLs for the listing's screenshots.""" screenshotUrls: [String]! """An alternate category that describes the listing.""" secondaryCategory: MarketplaceCategory """The listing's very short description.""" shortDescription: String! """The short name of the listing used in its URL.""" slug: String! """URL to the listing's status page.""" statusUrl: URI """An email address for support for this listing's app.""" supportEmail: String """ Either a URL or an email address for support for this listing's app, may return an empty string for listings that do not require a support URL. """ supportUrl: URI! """URL to the listing's terms of service.""" termsOfServiceUrl: URI """The HTTP URL for the Marketplace listing.""" url: URI! """Can the current viewer add plans for this Marketplace listing.""" viewerCanAddPlans: Boolean! """Can the current viewer approve this Marketplace listing.""" viewerCanApprove: Boolean! """Can the current viewer delist this Marketplace listing.""" viewerCanDelist: Boolean! """Can the current viewer edit this Marketplace listing.""" viewerCanEdit: Boolean! """ Can the current viewer edit the primary and secondary category of this Marketplace listing. """ viewerCanEditCategories: Boolean! """Can the current viewer edit the plans for this Marketplace listing.""" viewerCanEditPlans: Boolean! """ Can the current viewer return this Marketplace listing to draft state so it becomes editable again. """ viewerCanRedraft: Boolean! """ Can the current viewer reject this Marketplace listing by returning it to an editable draft state or rejecting it entirely. """ viewerCanReject: Boolean! """ Can the current viewer request this listing be reviewed for display in the Marketplace as verified. """ viewerCanRequestApproval: Boolean! """ Indicates whether the current user has an active subscription to this Marketplace listing. """ viewerHasPurchased: Boolean! """ Indicates if the current user has purchased a subscription to this Marketplace listing for all of the organizations the user owns. """ viewerHasPurchasedForAllOrganizations: Boolean! """ Does the current viewer role allow them to administer this Marketplace listing. """ viewerIsListingAdmin: Boolean! } """Look up Marketplace Listings""" type MarketplaceListingConnection { """A list of edges.""" edges: [MarketplaceListingEdge] """A list of nodes.""" nodes: [MarketplaceListing] """Information to aid in pagination.""" pageInfo: PageInfo! """Identifies the total count of items in the connection.""" totalCount: Int! } """An edge in a connection.""" type MarketplaceListingEdge { """A cursor for use in pagination.""" cursor: String! """The item at the end of the edge.""" node: MarketplaceListing } """Entities that have members who can set status messages.""" interface MemberStatusable { """ Get the status messages members of this entity have set that are either public or visible only to the organization. """ memberStatuses( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int """Ordering options for user statuses returned from the connection.""" orderBy: UserStatusOrder ): UserStatusConnection! } """Represents a 'mentioned' event on a given issue or pull request.""" type MentionedEvent implements Node { """Identifies the actor who performed the event.""" actor: Actor """Identifies the date and time when the object was created.""" createdAt: DateTime! """Identifies the primary key from the database.""" databaseId: Int id: ID! } """Whether or not a PullRequest can be merged.""" enum MergeableState { """The pull request can be merged.""" MERGEABLE """The pull request cannot be merged due to merge conflicts.""" CONFLICTING """The mergeability of the pull request is still being calculated.""" UNKNOWN } """Represents a 'merged' event on a given pull request.""" type MergedEvent implements Node & UniformResourceLocatable { """Identifies the actor who performed the event.""" actor: Actor """Identifies the commit associated with the `merge` event.""" commit: Commit """Identifies the date and time when the object was created.""" createdAt: DateTime! id: ID! """Identifies the Ref associated with the `merge` event.""" mergeRef: Ref """Identifies the name of the Ref associated with the `merge` event.""" mergeRefName: String! """PullRequest referenced by event.""" pullRequest: PullRequest! """The HTTP path for this merged event.""" resourcePath: URI! """The HTTP URL for this merged event.""" url: URI! } """Autogenerated input type of MergePullRequest""" input MergePullRequestInput { """ID of the pull request to be merged.""" pullRequestId: ID! """ Commit headline to use for the merge commit; if omitted, a default message will be used. """ commitHeadline: String """ Commit body to use for the merge commit; if omitted, a default message will be used """ commitBody: String """ OID that the pull request head ref must match to allow merge; if omitted, no check is performed. """ expectedHeadOid: GitObjectID """A unique identifier for the client performing the mutation.""" clientMutationId: String } """Autogenerated return type of MergePullRequest""" type MergePullRequestPayload { """A unique identifier for the client performing the mutation.""" clientMutationId: String """The pull request that was merged.""" pullRequest: PullRequest } """Represents a Milestone object on a given repository.""" type Milestone implements Node & Closable & UniformResourceLocatable { """ `true` if the object is closed (definition of closed may depend on type) """ closed: Boolean! """Identifies the date and time when the object was closed.""" closedAt: DateTime """Identifies the date and time when the object was created.""" createdAt: DateTime! """Identifies the actor who created the milestone.""" creator: Actor """Identifies the description of the milestone.""" description: String """Identifies the due date of the milestone.""" dueOn: DateTime id: ID! """A list of issues associated with the milestone.""" issues( """Ordering options for issues returned from the connection.""" orderBy: IssueOrder """A list of label names to filter the pull requests by.""" labels: [String!] """A list of states to filter the issues by.""" states: [IssueState!] """Filtering options for issues returned from the connection.""" filterBy: IssueFilters """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): IssueConnection! """Identifies the number of the milestone.""" number: Int! """A list of pull requests associated with the milestone.""" pullRequests( """A list of states to filter the pull requests by.""" states: [PullRequestState!] """A list of label names to filter the pull requests by.""" labels: [String!] """The head ref name to filter the pull requests by.""" headRefName: String """The base ref name to filter the pull requests by.""" baseRefName: String """Ordering options for pull requests returned from the connection.""" orderBy: IssueOrder """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): PullRequestConnection! """The repository associated with this milestone.""" repository: Repository! """The HTTP path for this milestone""" resourcePath: URI! """Identifies the state of the milestone.""" state: MilestoneState! """Identifies the title of the milestone.""" title: String! """Identifies the date and time when the object was last updated.""" updatedAt: DateTime! """The HTTP URL for this milestone""" url: URI! } """The connection type for Milestone.""" type MilestoneConnection { """A list of edges.""" edges: [MilestoneEdge] """A list of nodes.""" nodes: [Milestone] """Information to aid in pagination.""" pageInfo: PageInfo! """Identifies the total count of items in the connection.""" totalCount: Int! } """Represents a 'milestoned' event on a given issue or pull request.""" type MilestonedEvent implements Node { """Identifies the actor who performed the event.""" actor: Actor """Identifies the date and time when the object was created.""" createdAt: DateTime! id: ID! """Identifies the milestone title associated with the 'milestoned' event.""" milestoneTitle: String! """Object referenced by event.""" subject: MilestoneItem! } """An edge in a connection.""" type MilestoneEdge { """A cursor for use in pagination.""" cursor: String! """The item at the end of the edge.""" node: Milestone } """Types that can be inside a Milestone.""" union MilestoneItem = Issue | PullRequest """Ordering options for milestone connections.""" input MilestoneOrder { """The field to order milestones by.""" field: MilestoneOrderField! """The ordering direction.""" direction: OrderDirection! } """Properties by which milestone connections can be ordered.""" enum MilestoneOrderField { """Order milestones by when they are due.""" DUE_DATE """Order milestones by when they were created.""" CREATED_AT """Order milestones by when they were last updated.""" UPDATED_AT """Order milestones by their number.""" NUMBER } """The possible states of a milestone.""" enum MilestoneState { """A milestone that is still open.""" OPEN """A milestone that has been closed.""" CLOSED } """Autogenerated input type of MinimizeComment""" input MinimizeCommentInput { """The Node ID of the subject to modify.""" subjectId: ID! """The classification of comment""" classifier: ReportedContentClassifiers! """A unique identifier for the client performing the mutation.""" clientMutationId: String } """ Represents a 'moved_columns_in_project' event on a given issue or pull request. """ type MovedColumnsInProjectEvent implements Node { """Identifies the actor who performed the event.""" actor: Actor """Identifies the date and time when the object was created.""" createdAt: DateTime! """Identifies the primary key from the database.""" databaseId: Int id: ID! } """Autogenerated input type of MoveProjectCard""" input MoveProjectCardInput { """The id of the card to move.""" cardId: ID! """The id of the column to move it into.""" columnId: ID! """ Place the new card after the card with this id. Pass null to place it at the top. """ afterCardId: ID """A unique identifier for the client performing the mutation.""" clientMutationId: String } """Autogenerated return type of MoveProjectCard""" type MoveProjectCardPayload { """The new edge of the moved card.""" cardEdge: ProjectCardEdge """A unique identifier for the client performing the mutation.""" clientMutationId: String } """Autogenerated input type of MoveProjectColumn""" input MoveProjectColumnInput { """The id of the column to move.""" columnId: ID! """ Place the new column after the column with this id. Pass null to place it at the front. """ afterColumnId: ID """A unique identifier for the client performing the mutation.""" clientMutationId: String } """Autogenerated return type of MoveProjectColumn""" type MoveProjectColumnPayload { """A unique identifier for the client performing the mutation.""" clientMutationId: String """The new edge of the moved column.""" columnEdge: ProjectColumnEdge } """The root query for implementing GraphQL mutations.""" type Mutation { """Applies a suggested topic to the repository.""" acceptTopicSuggestion(input: AcceptTopicSuggestionInput!): AcceptTopicSuggestionPayload """Adds assignees to an assignable object.""" addAssigneesToAssignable(input: AddAssigneesToAssignableInput!): AddAssigneesToAssignablePayload """Adds a comment to an Issue or Pull Request.""" addComment(input: AddCommentInput!): AddCommentPayload """Adds labels to a labelable object.""" addLabelsToLabelable(input: AddLabelsToLabelableInput!): AddLabelsToLabelablePayload """ Adds a card to a ProjectColumn. Either `contentId` or `note` must be provided but **not** both. """ addProjectCard(input: AddProjectCardInput!): AddProjectCardPayload """Adds a column to a Project.""" addProjectColumn(input: AddProjectColumnInput!): AddProjectColumnPayload """Adds a review to a Pull Request.""" addPullRequestReview(input: AddPullRequestReviewInput!): AddPullRequestReviewPayload """Adds a comment to a review.""" addPullRequestReviewComment(input: AddPullRequestReviewCommentInput!): AddPullRequestReviewCommentPayload """Adds a reaction to a subject.""" addReaction(input: AddReactionInput!): AddReactionPayload """Adds a star to a Starrable.""" addStar(input: AddStarInput!): AddStarPayload """Update your status on GitHub.""" changeUserStatus(input: ChangeUserStatusInput!): ChangeUserStatusPayload """Clears all labels from a labelable object.""" clearLabelsFromLabelable(input: ClearLabelsFromLabelableInput!): ClearLabelsFromLabelablePayload """ Creates a new project by cloning configuration from an existing project. """ cloneProject(input: CloneProjectInput!): CloneProjectPayload """Close an issue.""" closeIssue(input: CloseIssueInput!): CloseIssuePayload """Close a pull request.""" closePullRequest(input: ClosePullRequestInput!): ClosePullRequestPayload """ Convert a project note card to one associated with a newly created issue. """ convertProjectCardNoteToIssue(input: ConvertProjectCardNoteToIssueInput!): ConvertProjectCardNoteToIssuePayload """Create a new branch protection rule""" createBranchProtectionRule(input: CreateBranchProtectionRuleInput!): CreateBranchProtectionRulePayload """Creates a new issue.""" createIssue(input: CreateIssueInput!): CreateIssuePayload """Creates a new project.""" createProject(input: CreateProjectInput!): CreateProjectPayload """Create a new pull request""" createPullRequest(input: CreatePullRequestInput!): CreatePullRequestPayload """Rejects a suggested topic for the repository.""" declineTopicSuggestion(input: DeclineTopicSuggestionInput!): DeclineTopicSuggestionPayload """Delete a branch protection rule""" deleteBranchProtectionRule(input: DeleteBranchProtectionRuleInput!): DeleteBranchProtectionRulePayload """Deletes an Issue object.""" deleteIssue(input: DeleteIssueInput!): DeleteIssuePayload """Deletes an IssueComment object.""" deleteIssueComment(input: DeleteIssueCommentInput!): DeleteIssueCommentPayload """Deletes a project.""" deleteProject(input: DeleteProjectInput!): DeleteProjectPayload """Deletes a project card.""" deleteProjectCard(input: DeleteProjectCardInput!): DeleteProjectCardPayload """Deletes a project column.""" deleteProjectColumn(input: DeleteProjectColumnInput!): DeleteProjectColumnPayload """Deletes a pull request review.""" deletePullRequestReview(input: DeletePullRequestReviewInput!): DeletePullRequestReviewPayload """Deletes a pull request review comment.""" deletePullRequestReviewComment(input: DeletePullRequestReviewCommentInput!): DeletePullRequestReviewCommentPayload """Dismisses an approved or rejected pull request review.""" dismissPullRequestReview(input: DismissPullRequestReviewInput!): DismissPullRequestReviewPayload """Lock a lockable object""" lockLockable(input: LockLockableInput!): LockLockablePayload """Merge a pull request.""" mergePullRequest(input: MergePullRequestInput!): MergePullRequestPayload """Moves a project card to another place.""" moveProjectCard(input: MoveProjectCardInput!): MoveProjectCardPayload """Moves a project column to another place.""" moveProjectColumn(input: MoveProjectColumnInput!): MoveProjectColumnPayload """Removes assignees from an assignable object.""" removeAssigneesFromAssignable(input: RemoveAssigneesFromAssignableInput!): RemoveAssigneesFromAssignablePayload """Removes labels from a Labelable object.""" removeLabelsFromLabelable(input: RemoveLabelsFromLabelableInput!): RemoveLabelsFromLabelablePayload """Removes outside collaborator from all repositories in an organization.""" removeOutsideCollaborator(input: RemoveOutsideCollaboratorInput!): RemoveOutsideCollaboratorPayload """Removes a reaction from a subject.""" removeReaction(input: RemoveReactionInput!): RemoveReactionPayload """Removes a star from a Starrable.""" removeStar(input: RemoveStarInput!): RemoveStarPayload """Reopen a issue.""" reopenIssue(input: ReopenIssueInput!): ReopenIssuePayload """Reopen a pull request.""" reopenPullRequest(input: ReopenPullRequestInput!): ReopenPullRequestPayload """Set review requests on a pull request.""" requestReviews(input: RequestReviewsInput!): RequestReviewsPayload """Marks a review thread as resolved.""" resolveReviewThread(input: ResolveReviewThreadInput!): ResolveReviewThreadPayload """Submits a pending pull request review.""" submitPullRequestReview(input: SubmitPullRequestReviewInput!): SubmitPullRequestReviewPayload """Unlock a lockable object""" unlockLockable(input: UnlockLockableInput!): UnlockLockablePayload """Unmark an issue as a duplicate of another issue.""" unmarkIssueAsDuplicate(input: UnmarkIssueAsDuplicateInput!): UnmarkIssueAsDuplicatePayload """Marks a review thread as unresolved.""" unresolveReviewThread(input: UnresolveReviewThreadInput!): UnresolveReviewThreadPayload """Create a new branch protection rule""" updateBranchProtectionRule(input: UpdateBranchProtectionRuleInput!): UpdateBranchProtectionRulePayload """Updates an Issue.""" updateIssue(input: UpdateIssueInput!): UpdateIssuePayload """Updates an IssueComment object.""" updateIssueComment(input: UpdateIssueCommentInput!): UpdateIssueCommentPayload """Updates an existing project.""" updateProject(input: UpdateProjectInput!): UpdateProjectPayload """Updates an existing project card.""" updateProjectCard(input: UpdateProjectCardInput!): UpdateProjectCardPayload """Updates an existing project column.""" updateProjectColumn(input: UpdateProjectColumnInput!): UpdateProjectColumnPayload """Update a pull request""" updatePullRequest(input: UpdatePullRequestInput!): UpdatePullRequestPayload """Updates the body of a pull request review.""" updatePullRequestReview(input: UpdatePullRequestReviewInput!): UpdatePullRequestReviewPayload """Updates a pull request review comment.""" updatePullRequestReviewComment(input: UpdatePullRequestReviewCommentInput!): UpdatePullRequestReviewCommentPayload """Updates the state for subscribable subjects.""" updateSubscription(input: UpdateSubscriptionInput!): UpdateSubscriptionPayload """Replaces the repository's topics with the given topics.""" updateTopics(input: UpdateTopicsInput!): UpdateTopicsPayload } """An object with an ID.""" interface Node { """ID of the object.""" id: ID! } """ Possible directions in which to order a list of items when provided an `orderBy` argument. """ enum OrderDirection { """Specifies an ascending order for a given `orderBy` argument.""" ASC """Specifies a descending order for a given `orderBy` argument.""" DESC } """ An account on GitHub, with one or more owners, that has repositories, members and teams. """ type Organization implements Node & Actor & RegistryPackageOwner & RegistryPackageSearch & ProjectOwner & RepositoryOwner & UniformResourceLocatable & MemberStatusable & ProfileOwner { """ Determine if this repository owner has any items that can be pinned to their profile. """ anyPinnableItems( """Filter to only a particular kind of pinnable item.""" type: PinnableItemType ): Boolean! """A URL pointing to the organization's public avatar.""" avatarUrl( """The size of the resulting square image.""" size: Int ): URI! """Identifies the primary key from the database.""" databaseId: Int """The organization's public profile description.""" description: String """The organization's public email.""" email: String id: ID! """Whether the organization has verified its profile email and website.""" isVerified: Boolean! """ Showcases a selection of repositories and gists that the profile owner has either curated or that have been selected automatically based on popularity. """ itemShowcase: ProfileItemShowcase! """The organization's public profile location.""" location: String """The organization's login name.""" login: String! """ Get the status messages members of this entity have set that are either public or visible only to the organization. """ memberStatuses( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int """Ordering options for user statuses returned from the connection.""" orderBy: UserStatusOrder ): UserStatusConnection! """A list of users who are members of this organization.""" membersWithRole( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): OrganizationMemberConnection! """The organization's public profile name.""" name: String """The HTTP path creating a new team""" newTeamResourcePath: URI! """The HTTP URL creating a new team""" newTeamUrl: URI! """The billing email for the organization.""" organizationBillingEmail: String """A list of users who have been invited to join this organization.""" pendingMembers( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): UserConnection! """ A list of repositories and gists this profile owner can pin to their profile. """ pinnableItems( """Filter the types of pinnable items that are returned.""" types: [PinnableItemType!] """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): PinnableItemConnection! """ A list of repositories and gists this profile owner has pinned to their profile """ pinnedItems( """Filter the types of pinned items that are returned.""" types: [PinnableItemType!] """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): PinnableItemConnection! """ Returns how many more items this profile owner can pin to their profile. """ pinnedItemsRemaining: Int! """A list of repositories this user has pinned to their profile""" pinnedRepositories( """If non-null, filters repositories according to privacy""" privacy: RepositoryPrivacy """Ordering options for repositories returned from the connection""" orderBy: RepositoryOrder """ Array of viewer's affiliation options for repositories returned from the connection. For example, OWNER will include only repositories that the current viewer owns. """ affiliations: [RepositoryAffiliation] """ Array of owner's affiliation options for repositories returned from the connection. For example, OWNER will include only repositories that the organization or user being viewed owns. """ ownerAffiliations: [RepositoryAffiliation] """ If non-null, filters repositories according to whether they have been locked """ isLocked: Boolean """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): RepositoryConnection! @deprecated(reason: "pinnedRepositories will be removed Use ProfileOwner.pinnedItems instead. Removal on 2019-07-01 UTC.") """Find project by number.""" project( """The project number to find.""" number: Int! ): Project """A list of projects under the owner.""" projects( """Ordering options for projects returned from the connection""" orderBy: ProjectOrder """Query to search projects by, currently only searching by name.""" search: String """A list of states to filter the projects by.""" states: [ProjectState!] """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): ProjectConnection! """The HTTP path listing organization's projects""" projectsResourcePath: URI! """The HTTP URL listing organization's projects""" projectsUrl: URI! """A list of repositories that the user owns.""" repositories( """If non-null, filters repositories according to privacy""" privacy: RepositoryPrivacy """Ordering options for repositories returned from the connection""" orderBy: RepositoryOrder """ Array of viewer's affiliation options for repositories returned from the connection. For example, OWNER will include only repositories that the current viewer owns. """ affiliations: [RepositoryAffiliation] """ Array of owner's affiliation options for repositories returned from the connection. For example, OWNER will include only repositories that the organization or user being viewed owns. """ ownerAffiliations: [RepositoryAffiliation] """ If non-null, filters repositories according to whether they have been locked """ isLocked: Boolean """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int """ If non-null, filters repositories according to whether they are forks of another repository """ isFork: Boolean ): RepositoryConnection! """Find Repository.""" repository( """Name of Repository to find.""" name: String! ): Repository """ When true the organization requires all members, billing managers, and outside collaborators to enable two-factor authentication. """ requiresTwoFactorAuthentication: Boolean """The HTTP path for this organization.""" resourcePath: URI! """The Organization's SAML identity providers""" samlIdentityProvider: OrganizationIdentityProvider """Find an organization's team by its slug.""" team( """The name or slug of the team to find.""" slug: String! ): Team """A list of teams in this organization.""" teams( """If non-null, filters teams according to privacy""" privacy: TeamPrivacy """ If non-null, filters teams according to whether the viewer is an admin or member on team """ role: TeamRole """If non-null, filters teams with query on team name and team slug""" query: String """User logins to filter by""" userLogins: [String!] """Ordering options for teams returned from the connection""" orderBy: TeamOrder """ If true, filters teams that are mapped to an LDAP Group (Enterprise only) """ ldapMapped: Boolean """If true, restrict to only root teams""" rootTeamsOnly: Boolean = false """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): TeamConnection! """The HTTP path listing organization's teams""" teamsResourcePath: URI! """The HTTP URL listing organization's teams""" teamsUrl: URI! """The HTTP URL for this organization.""" url: URI! """Organization is adminable by the viewer.""" viewerCanAdminister: Boolean! """Can the viewer pin repositories and gists to the profile?""" viewerCanChangePinnedItems: Boolean! """Can the current viewer create new projects on this owner.""" viewerCanCreateProjects: Boolean! """Viewer can create repositories on this organization""" viewerCanCreateRepositories: Boolean! """Viewer can create teams on this organization.""" viewerCanCreateTeams: Boolean! """Viewer is an active member of this organization.""" viewerIsAMember: Boolean! """The organization's public profile URL.""" websiteUrl: URI } """The connection type for Organization.""" type OrganizationConnection { """A list of edges.""" edges: [OrganizationEdge] """A list of nodes.""" nodes: [Organization] """Information to aid in pagination.""" pageInfo: PageInfo! """Identifies the total count of items in the connection.""" totalCount: Int! } """An edge in a connection.""" type OrganizationEdge { """A cursor for use in pagination.""" cursor: String! """The item at the end of the edge.""" node: Organization } """ An Identity Provider configured to provision SAML and SCIM identities for Organizations """ type OrganizationIdentityProvider implements Node { """ The digest algorithm used to sign SAML requests for the Identity Provider. """ digestMethod: URI """External Identities provisioned by this Identity Provider""" externalIdentities( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): ExternalIdentityConnection! id: ID! """ The x509 certificate used by the Identity Provder to sign assertions and responses. """ idpCertificate: X509Certificate """The Issuer Entity ID for the SAML Identity Provider""" issuer: String """Organization this Identity Provider belongs to""" organization: Organization """ The signature algorithm used to sign SAML requests for the Identity Provider. """ signatureMethod: URI """The URL endpoint for the Identity Provider's SAML SSO.""" ssoUrl: URI } """An Invitation for a user to an organization.""" type OrganizationInvitation implements Node { """Identifies the date and time when the object was created.""" createdAt: DateTime! """The email address of the user invited to the organization.""" email: String id: ID! """The type of invitation that was sent (e.g. email, user).""" invitationType: OrganizationInvitationType! """The user who was invited to the organization.""" invitee: User """The user who created the invitation.""" inviter: User! """The organization the invite is for""" organization: Organization! """The user's pending role in the organization (e.g. member, owner).""" role: OrganizationInvitationRole! } """The connection type for OrganizationInvitation.""" type OrganizationInvitationConnection { """A list of edges.""" edges: [OrganizationInvitationEdge] """A list of nodes.""" nodes: [OrganizationInvitation] """Information to aid in pagination.""" pageInfo: PageInfo! """Identifies the total count of items in the connection.""" totalCount: Int! } """An edge in a connection.""" type OrganizationInvitationEdge { """A cursor for use in pagination.""" cursor: String! """The item at the end of the edge.""" node: OrganizationInvitation } """The possible organization invitation roles.""" enum OrganizationInvitationRole { """The user is invited to be a direct member of the organization.""" DIRECT_MEMBER """The user is invited to be an admin of the organization.""" ADMIN """The user is invited to be a billing manager of the organization.""" BILLING_MANAGER """The user's previous role will be reinstated.""" REINSTATE } """The possible organization invitation types.""" enum OrganizationInvitationType { """The invitation was to an existing user.""" USER """The invitation was to an email address.""" EMAIL } """The connection type for User.""" type OrganizationMemberConnection { """A list of edges.""" edges: [OrganizationMemberEdge] """A list of nodes.""" nodes: [User] """Information to aid in pagination.""" pageInfo: PageInfo! """Identifies the total count of items in the connection.""" totalCount: Int! } """Represents a user within an organization.""" type OrganizationMemberEdge { """A cursor for use in pagination.""" cursor: String! """ Whether the organization member has two factor enabled or not. Returns null if information is not available to viewer. """ hasTwoFactorEnabled: Boolean """The item at the end of the edge.""" node: User """The role this user has in the organization.""" role: OrganizationMemberRole } """The possible roles within an organization for its members.""" enum OrganizationMemberRole { """The user is a member of the organization.""" MEMBER """The user is an administrator of the organization.""" ADMIN } """Information about pagination in a connection.""" type PageInfo { """When paginating forwards, the cursor to continue.""" endCursor: String """When paginating forwards, are there more items?""" hasNextPage: Boolean! """When paginating backwards, are there more items?""" hasPreviousPage: Boolean! """When paginating backwards, the cursor to continue.""" startCursor: String } """Types that can grant permissions on a repository to a user""" union PermissionGranter = Organization | Repository | Team """A level of permission and source for a user's access to a repository.""" type PermissionSource { """The organization the repository belongs to.""" organization: Organization! """The level of access this source has granted to the user.""" permission: DefaultRepositoryPermissionField! """The source of this permission.""" source: PermissionGranter! } """Autogenerated input type of PinIssue""" input PinIssueInput { """The ID of the issue to be pinned""" issueId: ID! """A unique identifier for the client performing the mutation.""" clientMutationId: String } """Types that can be pinned to a profile page.""" union PinnableItem = Gist | Repository """The connection type for PinnableItem.""" type PinnableItemConnection { """A list of edges.""" edges: [PinnableItemEdge] """A list of nodes.""" nodes: [PinnableItem] """Information to aid in pagination.""" pageInfo: PageInfo! """Identifies the total count of items in the connection.""" totalCount: Int! } """An edge in a connection.""" type PinnableItemEdge { """A cursor for use in pagination.""" cursor: String! """The item at the end of the edge.""" node: PinnableItem } """Represents items that can be pinned to a profile page or dashboard.""" enum PinnableItemType { """A repository.""" REPOSITORY """A gist.""" GIST """An issue.""" ISSUE } """Represents a 'pinned' event on a given issue or pull request.""" type PinnedEvent implements Node { """Identifies the actor who performed the event.""" actor: Actor """Identifies the date and time when the object was created.""" createdAt: DateTime! id: ID! """Identifies the issue associated with the event.""" issue: Issue! } """ A curatable list of repositories relating to a repository owner, which defaults to showing the most popular repositories they own. """ type ProfileItemShowcase { """Whether or not the owner has pinned any repositories or gists.""" hasPinnedItems: Boolean! """ The repositories and gists in the showcase. If the profile owner has any pinned items, those will be returned. Otherwise, the profile owner's popular repositories will be returned. """ items( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): PinnableItemConnection! } """Represents any entity on GitHub that has a profile page.""" interface ProfileOwner { """ Determine if this repository owner has any items that can be pinned to their profile. """ anyPinnableItems( """Filter to only a particular kind of pinnable item.""" type: PinnableItemType ): Boolean! """The public profile email.""" email: String id: ID! """ Showcases a selection of repositories and gists that the profile owner has either curated or that have been selected automatically based on popularity. """ itemShowcase: ProfileItemShowcase! """The public profile location.""" location: String """The username used to login.""" login: String! """The public profile name.""" name: String """ A list of repositories and gists this profile owner can pin to their profile. """ pinnableItems( """Filter the types of pinnable items that are returned.""" types: [PinnableItemType!] """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): PinnableItemConnection! """ A list of repositories and gists this profile owner has pinned to their profile """ pinnedItems( """Filter the types of pinned items that are returned.""" types: [PinnableItemType!] """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): PinnableItemConnection! """ Returns how many more items this profile owner can pin to their profile. """ pinnedItemsRemaining: Int! """Can the viewer pin repositories and gists to the profile?""" viewerCanChangePinnedItems: Boolean! """The public profile website URL.""" websiteUrl: URI } """ Projects manage issues, pull requests and notes within a project owner. """ type Project implements Node & Closable & Updatable { """The project's description body.""" body: String """The projects description body rendered to HTML.""" bodyHTML: HTML! """ `true` if the object is closed (definition of closed may depend on type) """ closed: Boolean! """Identifies the date and time when the object was closed.""" closedAt: DateTime """List of columns in the project""" columns( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): ProjectColumnConnection! """Identifies the date and time when the object was created.""" createdAt: DateTime! """The actor who originally created the project.""" creator: Actor """Identifies the primary key from the database.""" databaseId: Int id: ID! """The project's name.""" name: String! """The project's number.""" number: Int! """ The project's owner. Currently limited to repositories, organizations, and users. """ owner: ProjectOwner! """List of pending cards in this project""" pendingCards( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int """A list of archived states to filter the cards by""" archivedStates: [ProjectCardArchivedState] ): ProjectCardConnection! """The HTTP path for this project""" resourcePath: URI! """Whether the project is open or closed.""" state: ProjectState! """Identifies the date and time when the object was last updated.""" updatedAt: DateTime! """The HTTP URL for this project""" url: URI! """Check if the current viewer can update this object.""" viewerCanUpdate: Boolean! } """A card in a project.""" type ProjectCard implements Node { """ The project column this card is associated under. A card may only belong to one project column at a time. The column field will be null if the card is created in a pending state and has yet to be associated with a column. Once cards are associated with a column, they will not become pending in the future. """ column: ProjectColumn """The card content item""" content: ProjectCardItem """Identifies the date and time when the object was created.""" createdAt: DateTime! """The actor who created this card""" creator: Actor """Identifies the primary key from the database.""" databaseId: Int id: ID! """Whether the card is archived""" isArchived: Boolean! """The card note""" note: String """The project that contains this card.""" project: Project! """The HTTP path for this card""" resourcePath: URI! """The state of ProjectCard""" state: ProjectCardState """Identifies the date and time when the object was last updated.""" updatedAt: DateTime! """The HTTP URL for this card""" url: URI! } """The possible archived states of a project card.""" enum ProjectCardArchivedState { """A project card that is archived""" ARCHIVED """A project card that is not archived""" NOT_ARCHIVED } """The connection type for ProjectCard.""" type ProjectCardConnection { """A list of edges.""" edges: [ProjectCardEdge] """A list of nodes.""" nodes: [ProjectCard] """Information to aid in pagination.""" pageInfo: PageInfo! """Identifies the total count of items in the connection.""" totalCount: Int! } """An edge in a connection.""" type ProjectCardEdge { """A cursor for use in pagination.""" cursor: String! """The item at the end of the edge.""" node: ProjectCard } """An issue or PR and its owning repository to be used in a project card.""" input ProjectCardImport { """Repository name with owner (owner/repository).""" repository: String! """The issue or pull request number.""" number: Int! } """Types that can be inside Project Cards.""" union ProjectCardItem = Issue | PullRequest """Various content states of a ProjectCard""" enum ProjectCardState { """The card has content only.""" CONTENT_ONLY """The card has a note only.""" NOTE_ONLY """The card is redacted.""" REDACTED } """A column inside a project.""" type ProjectColumn implements Node { """List of cards in the column""" cards( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int """A list of archived states to filter the cards by""" archivedStates: [ProjectCardArchivedState] ): ProjectCardConnection! """Identifies the date and time when the object was created.""" createdAt: DateTime! """Identifies the primary key from the database.""" databaseId: Int id: ID! """The project column's name.""" name: String! """The project that contains this column.""" project: Project! """The semantic purpose of the column""" purpose: ProjectColumnPurpose """The HTTP path for this project column""" resourcePath: URI! """Identifies the date and time when the object was last updated.""" updatedAt: DateTime! """The HTTP URL for this project column""" url: URI! } """The connection type for ProjectColumn.""" type ProjectColumnConnection { """A list of edges.""" edges: [ProjectColumnEdge] """A list of nodes.""" nodes: [ProjectColumn] """Information to aid in pagination.""" pageInfo: PageInfo! """Identifies the total count of items in the connection.""" totalCount: Int! } """An edge in a connection.""" type ProjectColumnEdge { """A cursor for use in pagination.""" cursor: String! """The item at the end of the edge.""" node: ProjectColumn } """A project column and a list of its issues and PRs.""" input ProjectColumnImport { """The name of the column.""" columnName: String! """The position of the column, starting from 0.""" position: Int! """A list of issues and pull requests in the column.""" issues: [ProjectCardImport!] } """The semantic purpose of the column - todo, in progress, or done.""" enum ProjectColumnPurpose { """The column contains cards still to be worked on""" TODO """The column contains cards which are currently being worked on""" IN_PROGRESS """The column contains cards which are complete""" DONE } """A list of projects associated with the owner.""" type ProjectConnection { """A list of edges.""" edges: [ProjectEdge] """A list of nodes.""" nodes: [Project] """Information to aid in pagination.""" pageInfo: PageInfo! """Identifies the total count of items in the connection.""" totalCount: Int! } """An edge in a connection.""" type ProjectEdge { """A cursor for use in pagination.""" cursor: String! """The item at the end of the edge.""" node: Project } """Ways in which lists of projects can be ordered upon return.""" input ProjectOrder { """The field in which to order projects by.""" field: ProjectOrderField! """The direction in which to order projects by the specified field.""" direction: OrderDirection! } """Properties by which project connections can be ordered.""" enum ProjectOrderField { """Order projects by creation time""" CREATED_AT """Order projects by update time""" UPDATED_AT """Order projects by name""" NAME } """Represents an owner of a Project.""" interface ProjectOwner { id: ID! """Find project by number.""" project( """The project number to find.""" number: Int! ): Project """A list of projects under the owner.""" projects( """Ordering options for projects returned from the connection""" orderBy: ProjectOrder """Query to search projects by, currently only searching by name.""" search: String """A list of states to filter the projects by.""" states: [ProjectState!] """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): ProjectConnection! """The HTTP path listing owners projects""" projectsResourcePath: URI! """The HTTP URL listing owners projects""" projectsUrl: URI! """Can the current viewer create new projects on this owner.""" viewerCanCreateProjects: Boolean! } """State of the project; either 'open' or 'closed'""" enum ProjectState { """The project is open.""" OPEN """The project is closed.""" CLOSED } """A user's public key.""" type PublicKey implements Node { """The last time this authorization was used to perform an action""" accessedAt: DateTime """Identifies the date and time when the object was created.""" createdAt: DateTime! """The fingerprint for this PublicKey""" fingerprint: String id: ID! """Whether this PublicKey is read-only or not""" isReadOnly: Boolean! """The public key string""" key: String! """Identifies the date and time when the object was last updated.""" updatedAt: DateTime! } """The connection type for PublicKey.""" type PublicKeyConnection { """A list of edges.""" edges: [PublicKeyEdge] """A list of nodes.""" nodes: [PublicKey] """Information to aid in pagination.""" pageInfo: PageInfo! """Identifies the total count of items in the connection.""" totalCount: Int! } """An edge in a connection.""" type PublicKeyEdge { """A cursor for use in pagination.""" cursor: String! """The item at the end of the edge.""" node: PublicKey } """A repository pull request.""" type PullRequest implements Node & Assignable & Closable & Comment & Updatable & UpdatableComment & Labelable & Lockable & Reactable & RepositoryNode & Subscribable & UniformResourceLocatable { """Reason that the conversation was locked.""" activeLockReason: LockReason """The number of additions in this pull request.""" additions: Int! """A list of Users assigned to this object.""" assignees( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): UserConnection! """The actor who authored the comment.""" author: Actor """Author's association with the subject of the comment.""" authorAssociation: CommentAuthorAssociation! """Identifies the base Ref associated with the pull request.""" baseRef: Ref """ Identifies the name of the base Ref associated with the pull request, even if the ref has been deleted. """ baseRefName: String! """ Identifies the oid of the base ref associated with the pull request, even if the ref has been deleted. """ baseRefOid: GitObjectID! """The repository associated with this pull request's base Ref.""" baseRepository: Repository """The body as Markdown.""" body: String! """The body rendered to HTML.""" bodyHTML: HTML! """The body rendered to text.""" bodyText: String! """The number of changed files in this pull request.""" changedFiles: Int! """`true` if the pull request is closed""" closed: Boolean! """Identifies the date and time when the object was closed.""" closedAt: DateTime """A list of comments associated with the pull request.""" comments( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): IssueCommentConnection! """ A list of commits present in this pull request's head branch not present in the base branch. """ commits( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): PullRequestCommitConnection! """Identifies the date and time when the object was created.""" createdAt: DateTime! """Check if this comment was created via an email reply.""" createdViaEmail: Boolean! """Identifies the primary key from the database.""" databaseId: Int """The number of deletions in this pull request.""" deletions: Int! """The actor who edited this pull request's body.""" editor: Actor """Lists the files changed within this pull request.""" files( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): PullRequestChangedFileConnection """Identifies the head Ref associated with the pull request.""" headRef: Ref """ Identifies the name of the head Ref associated with the pull request, even if the ref has been deleted. """ headRefName: String! """ Identifies the oid of the head ref associated with the pull request, even if the ref has been deleted. """ headRefOid: GitObjectID! """The repository associated with this pull request's head Ref.""" headRepository: Repository """ The owner of the repository associated with this pull request's head Ref. """ headRepositoryOwner: RepositoryOwner id: ID! """ Check if this comment was edited and includes an edit with the creation data """ includesCreatedEdit: Boolean! """The head and base repositories are different.""" isCrossRepository: Boolean! """A list of labels associated with the object.""" labels( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): LabelConnection """The moment the editor made the last edit""" lastEditedAt: DateTime """`true` if the pull request is locked""" locked: Boolean! """Indicates whether maintainers can modify the pull request.""" maintainerCanModify: Boolean! """The commit that was created when this pull request was merged.""" mergeCommit: Commit """ Whether or not the pull request can be merged based on the existence of merge conflicts. """ mergeable: MergeableState! """Whether or not the pull request was merged.""" merged: Boolean! """The date and time that the pull request was merged.""" mergedAt: DateTime """The actor who merged the pull request.""" mergedBy: Actor """Identifies the milestone associated with the pull request.""" milestone: Milestone """Identifies the pull request number.""" number: Int! """ A list of Users that are participating in the Pull Request conversation. """ participants( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): UserConnection! """The permalink to the pull request.""" permalink: URI! """ The commit that GitHub automatically generated to test if this pull request could be merged. This field will not return a value if the pull request is merged, or if the test merge commit is still being generated. See the `mergeable` field for more details on the mergeability of the pull request. """ potentialMergeCommit: Commit """List of project cards associated with this pull request.""" projectCards( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int """A list of archived states to filter the cards by""" archivedStates: [ProjectCardArchivedState] ): ProjectCardConnection! """Identifies when the comment was published at.""" publishedAt: DateTime """A list of reactions grouped by content left on the subject.""" reactionGroups: [ReactionGroup!] """A list of Reactions left on the Issue.""" reactions( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int """Allows filtering Reactions by emoji.""" content: ReactionContent """Allows specifying the order in which reactions are returned.""" orderBy: ReactionOrder ): ReactionConnection! """The repository associated with this node.""" repository: Repository! """The HTTP path for this pull request.""" resourcePath: URI! """The HTTP path for reverting this pull request.""" revertResourcePath: URI! """The HTTP URL for reverting this pull request.""" revertUrl: URI! """A list of review requests associated with the pull request.""" reviewRequests( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): ReviewRequestConnection """The list of all review threads for this pull request.""" reviewThreads( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): PullRequestReviewThreadConnection! """A list of reviews associated with the pull request.""" reviews( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int """A list of states to filter the reviews.""" states: [PullRequestReviewState!] """Filter by author of the review.""" author: String ): PullRequestReviewConnection """Identifies the state of the pull request.""" state: PullRequestState! """ A list of reviewer suggestions based on commit history and past review comments. """ suggestedReviewers: [SuggestedReviewer]! """ A list of events, comments, commits, etc. associated with the pull request. """ timeline( """Allows filtering timeline events by a `since` timestamp.""" since: DateTime """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): PullRequestTimelineConnection! """ A list of events, comments, commits, etc. associated with the pull request. """ timelineItems( """Filter timeline items by a `since` timestamp.""" since: DateTime """Skips the first _n_ elements in the list.""" skip: Int """Filter timeline items by type.""" itemTypes: [PullRequestTimelineItemsItemType!] """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): PullRequestTimelineItemsConnection! """Identifies the pull request title.""" title: String! """Identifies the date and time when the object was last updated.""" updatedAt: DateTime! """The HTTP URL for this pull request.""" url: URI! """A list of edits to this content.""" userContentEdits( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): UserContentEditConnection """Whether or not the viewer can apply suggestion.""" viewerCanApplySuggestion: Boolean! """Can user react to this subject""" viewerCanReact: Boolean! """ Check if the viewer is able to change their subscription status for the repository. """ viewerCanSubscribe: Boolean! """Check if the current viewer can update this object.""" viewerCanUpdate: Boolean! """Reasons why the current viewer can not update this comment.""" viewerCannotUpdateReasons: [CommentCannotUpdateReason!]! """Did the viewer author this comment.""" viewerDidAuthor: Boolean! """ Identifies if the viewer is watching, not watching, or ignoring the subscribable entity. """ viewerSubscription: SubscriptionState } """A file changed in a pull request.""" type PullRequestChangedFile { """The number of additions to the file.""" additions: Int! """The number of deletions to the file.""" deletions: Int! """The path of the file.""" path: String! } """The connection type for PullRequestChangedFile.""" type PullRequestChangedFileConnection { """A list of edges.""" edges: [PullRequestChangedFileEdge] """A list of nodes.""" nodes: [PullRequestChangedFile] """Information to aid in pagination.""" pageInfo: PageInfo! """Identifies the total count of items in the connection.""" totalCount: Int! } """An edge in a connection.""" type PullRequestChangedFileEdge { """A cursor for use in pagination.""" cursor: String! """The item at the end of the edge.""" node: PullRequestChangedFile } """Represents a Git commit part of a pull request.""" type PullRequestCommit implements Node & UniformResourceLocatable { """The Git commit object""" commit: Commit! id: ID! """The pull request this commit belongs to""" pullRequest: PullRequest! """The HTTP path for this pull request commit""" resourcePath: URI! """The HTTP URL for this pull request commit""" url: URI! } """Represents a commit comment thread part of a pull request.""" type PullRequestCommitCommentThread implements Node & RepositoryNode { """The comments that exist in this thread.""" comments( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): CommitCommentConnection! """The commit the comments were made on.""" commit: Commit! id: ID! """The file the comments were made on.""" path: String """The position in the diff for the commit that the comment was made on.""" position: Int """The pull request this commit comment thread belongs to""" pullRequest: PullRequest! """The repository associated with this node.""" repository: Repository! } """The connection type for PullRequestCommit.""" type PullRequestCommitConnection { """A list of edges.""" edges: [PullRequestCommitEdge] """A list of nodes.""" nodes: [PullRequestCommit] """Information to aid in pagination.""" pageInfo: PageInfo! """Identifies the total count of items in the connection.""" totalCount: Int! } """An edge in a connection.""" type PullRequestCommitEdge { """A cursor for use in pagination.""" cursor: String! """The item at the end of the edge.""" node: PullRequestCommit } """The connection type for PullRequest.""" type PullRequestConnection { """A list of edges.""" edges: [PullRequestEdge] """A list of nodes.""" nodes: [PullRequest] """Information to aid in pagination.""" pageInfo: PageInfo! """Identifies the total count of items in the connection.""" totalCount: Int! } """This aggregates pull requests opened by a user within one repository.""" type PullRequestContributionsByRepository { """The pull request contributions.""" contributions( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int """Ordering options for contributions returned from the connection.""" orderBy: ContributionOrder ): CreatedPullRequestContributionConnection! """The repository in which the pull requests were opened.""" repository: Repository! } """An edge in a connection.""" type PullRequestEdge { """A cursor for use in pagination.""" cursor: String! """The item at the end of the edge.""" node: PullRequest } """Ways in which lists of issues can be ordered upon return.""" input PullRequestOrder { """The field in which to order pull requests by.""" field: PullRequestOrderField! """The direction in which to order pull requests by the specified field.""" direction: OrderDirection! } """Properties by which pull_requests connections can be ordered.""" enum PullRequestOrderField { """Order pull_requests by creation time""" CREATED_AT """Order pull_requests by update time""" UPDATED_AT } """The possible PubSub channels for a pull request.""" enum PullRequestPubSubTopic { """The channel ID for observing pull request updates.""" UPDATED """The channel ID for marking an pull request as read.""" MARKASREAD """The channel ID for observing head ref updates.""" HEAD_REF """The channel ID for updating items on the pull request timeline.""" TIMELINE """The channel ID for observing pull request state updates.""" STATE } """A review object for a given pull request.""" type PullRequestReview implements Node & Comment & Deletable & Updatable & UpdatableComment & Reactable & RepositoryNode { """The actor who authored the comment.""" author: Actor """Author's association with the subject of the comment.""" authorAssociation: CommentAuthorAssociation! """Identifies the pull request review body.""" body: String! """The body of this review rendered to HTML.""" bodyHTML: HTML! """The body of this review rendered as plain text.""" bodyText: String! """A list of review comments for the current pull request review.""" comments( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): PullRequestReviewCommentConnection! """Identifies the commit associated with this pull request review.""" commit: Commit """Identifies the date and time when the object was created.""" createdAt: DateTime! """Check if this comment was created via an email reply.""" createdViaEmail: Boolean! """Identifies the primary key from the database.""" databaseId: Int """The actor who edited the comment.""" editor: Actor id: ID! """ Check if this comment was edited and includes an edit with the creation data """ includesCreatedEdit: Boolean! """The moment the editor made the last edit""" lastEditedAt: DateTime """A list of teams that this review was made on behalf of.""" onBehalfOf( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): TeamConnection! """Identifies when the comment was published at.""" publishedAt: DateTime """Identifies the pull request associated with this pull request review.""" pullRequest: PullRequest! """A list of reactions grouped by content left on the subject.""" reactionGroups: [ReactionGroup!] """A list of Reactions left on the Issue.""" reactions( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int """Allows filtering Reactions by emoji.""" content: ReactionContent """Allows specifying the order in which reactions are returned.""" orderBy: ReactionOrder ): ReactionConnection! """The repository associated with this node.""" repository: Repository! """The HTTP path permalink for this PullRequestReview.""" resourcePath: URI! """Identifies the current state of the pull request review.""" state: PullRequestReviewState! """Identifies when the Pull Request Review was submitted""" submittedAt: DateTime """Identifies the date and time when the object was last updated.""" updatedAt: DateTime! """The HTTP URL permalink for this PullRequestReview.""" url: URI! """A list of edits to this content.""" userContentEdits( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): UserContentEditConnection """Check if the current viewer can delete this object.""" viewerCanDelete: Boolean! """Can user react to this subject""" viewerCanReact: Boolean! """Check if the current viewer can update this object.""" viewerCanUpdate: Boolean! """Reasons why the current viewer can not update this comment.""" viewerCannotUpdateReasons: [CommentCannotUpdateReason!]! """Did the viewer author this comment.""" viewerDidAuthor: Boolean! } """A review comment associated with a given repository pull request.""" type PullRequestReviewComment implements Node & Comment & Deletable & Updatable & UpdatableComment & Reactable & RepositoryNode { """The actor who authored the comment.""" author: Actor """Author's association with the subject of the comment.""" authorAssociation: CommentAuthorAssociation! """The comment body of this review comment.""" body: String! """The comment body of this review comment rendered to HTML.""" bodyHTML: HTML! """The comment body of this review comment rendered as plain text.""" bodyText: String! """Identifies the commit associated with the comment.""" commit: Commit! """Identifies when the comment was created.""" createdAt: DateTime! """Check if this comment was created via an email reply.""" createdViaEmail: Boolean! """Identifies the primary key from the database.""" databaseId: Int """The diff hunk to which the comment applies.""" diffHunk: String! """Identifies when the comment was created in a draft state.""" draftedAt: DateTime! """The actor who edited the comment.""" editor: Actor id: ID! """ Check if this comment was edited and includes an edit with the creation data """ includesCreatedEdit: Boolean! """Returns whether or not a comment has been minimized.""" isMinimized: Boolean! """The moment the editor made the last edit""" lastEditedAt: DateTime """Returns why the comment was minimized.""" minimizedReason: String """Identifies the original commit associated with the comment.""" originalCommit: Commit """The original line index in the diff to which the comment applies.""" originalPosition: Int! """Identifies when the comment body is outdated""" outdated: Boolean! """The path to which the comment applies.""" path: String! """The line index in the diff to which the comment applies.""" position: Int """Identifies when the comment was published at.""" publishedAt: DateTime """The pull request associated with this review comment.""" pullRequest: PullRequest! """The pull request review associated with this review comment.""" pullRequestReview: PullRequestReview """A list of reactions grouped by content left on the subject.""" reactionGroups: [ReactionGroup!] """A list of Reactions left on the Issue.""" reactions( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int """Allows filtering Reactions by emoji.""" content: ReactionContent """Allows specifying the order in which reactions are returned.""" orderBy: ReactionOrder ): ReactionConnection! """The comment this is a reply to.""" replyTo: PullRequestReviewComment """The repository associated with this node.""" repository: Repository! """The HTTP path permalink for this review comment.""" resourcePath: URI! """Identifies the state of the comment.""" state: PullRequestReviewCommentState! """Identifies when the comment was last updated.""" updatedAt: DateTime! """The HTTP URL permalink for this review comment.""" url: URI! """A list of edits to this content.""" userContentEdits( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): UserContentEditConnection """Check if the current viewer can delete this object.""" viewerCanDelete: Boolean! """Check if the current viewer can minimize this object.""" viewerCanMinimize: Boolean! """Can user react to this subject""" viewerCanReact: Boolean! """Check if the current viewer can update this object.""" viewerCanUpdate: Boolean! """Reasons why the current viewer can not update this comment.""" viewerCannotUpdateReasons: [CommentCannotUpdateReason!]! """Did the viewer author this comment.""" viewerDidAuthor: Boolean! } """The connection type for PullRequestReviewComment.""" type PullRequestReviewCommentConnection { """A list of edges.""" edges: [PullRequestReviewCommentEdge] """A list of nodes.""" nodes: [PullRequestReviewComment] """Information to aid in pagination.""" pageInfo: PageInfo! """Identifies the total count of items in the connection.""" totalCount: Int! } """An edge in a connection.""" type PullRequestReviewCommentEdge { """A cursor for use in pagination.""" cursor: String! """The item at the end of the edge.""" node: PullRequestReviewComment } """The possible states of a pull request review comment.""" enum PullRequestReviewCommentState { """A comment that is part of a pending review""" PENDING """A comment that is part of a submitted review""" SUBMITTED } """The connection type for PullRequestReview.""" type PullRequestReviewConnection { """A list of edges.""" edges: [PullRequestReviewEdge] """A list of nodes.""" nodes: [PullRequestReview] """Information to aid in pagination.""" pageInfo: PageInfo! """Identifies the total count of items in the connection.""" totalCount: Int! } """ This aggregates pull request reviews made by a user within one repository. """ type PullRequestReviewContributionsByRepository { """The pull request review contributions.""" contributions( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int """Ordering options for contributions returned from the connection.""" orderBy: ContributionOrder ): CreatedPullRequestReviewContributionConnection! """The repository in which the pull request reviews were made.""" repository: Repository! } """An edge in a connection.""" type PullRequestReviewEdge { """A cursor for use in pagination.""" cursor: String! """The item at the end of the edge.""" node: PullRequestReview } """The possible events to perform on a pull request review.""" enum PullRequestReviewEvent { """Submit general feedback without explicit approval.""" COMMENT """Submit feedback and approve merging these changes.""" APPROVE """Submit feedback that must be addressed before merging.""" REQUEST_CHANGES """Dismiss review so it now longer effects merging.""" DISMISS } """The possible states of a pull request review.""" enum PullRequestReviewState { """A review that has not yet been submitted.""" PENDING """An informational review.""" COMMENTED """A review allowing the pull request to merge.""" APPROVED """A review blocking the pull request from merging.""" CHANGES_REQUESTED """A review that has been dismissed.""" DISMISSED } """A threaded list of comments for a given pull request.""" type PullRequestReviewThread implements Node { """A list of pull request comments associated with the thread.""" comments( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): PullRequestReviewCommentConnection! id: ID! """Whether this thread has been resolved""" isResolved: Boolean! """Identifies the pull request associated with this thread.""" pullRequest: PullRequest! """Identifies the repository associated with this thread.""" repository: Repository! """The user who resolved this thread""" resolvedBy: User """Whether or not the viewer can resolve this thread""" viewerCanResolve: Boolean! """Whether or not the viewer can unresolve this thread""" viewerCanUnresolve: Boolean! } """Review comment threads for a pull request review.""" type PullRequestReviewThreadConnection { """A list of edges.""" edges: [PullRequestReviewThreadEdge] """A list of nodes.""" nodes: [PullRequestReviewThread] """Information to aid in pagination.""" pageInfo: PageInfo! """Identifies the total count of items in the connection.""" totalCount: Int! } """An edge in a connection.""" type PullRequestReviewThreadEdge { """A cursor for use in pagination.""" cursor: String! """The item at the end of the edge.""" node: PullRequestReviewThread } """ Represents the latest point in the pull request timeline for which the viewer has seen the pull request's commits. """ type PullRequestRevisionMarker { """Identifies the date and time when the object was created.""" createdAt: DateTime! """The last commit the viewer has seen.""" lastSeenCommit: Commit! """The pull request to which the marker belongs.""" pullRequest: PullRequest! } """The possible states of a pull request.""" enum PullRequestState { """A pull request that is still open.""" OPEN """A pull request that has been closed without being merged.""" CLOSED """A pull request that has been closed by being merged.""" MERGED } """The connection type for PullRequestTimelineItem.""" type PullRequestTimelineConnection { """A list of edges.""" edges: [PullRequestTimelineItemEdge] """A list of nodes.""" nodes: [PullRequestTimelineItem] """Information to aid in pagination.""" pageInfo: PageInfo! """Identifies the total count of items in the connection.""" totalCount: Int! } """An item in an pull request timeline""" union PullRequestTimelineItem = Commit | CommitCommentThread | PullRequestReview | PullRequestReviewThread | PullRequestReviewComment | IssueComment | ClosedEvent | ReopenedEvent | SubscribedEvent | UnsubscribedEvent | MergedEvent | ReferencedEvent | CrossReferencedEvent | AssignedEvent | UnassignedEvent | LabeledEvent | UnlabeledEvent | MilestonedEvent | DemilestonedEvent | RenamedTitleEvent | LockedEvent | UnlockedEvent | DeployedEvent | DeploymentEnvironmentChangedEvent | HeadRefDeletedEvent | HeadRefRestoredEvent | HeadRefForcePushedEvent | BaseRefForcePushedEvent | ReviewRequestedEvent | ReviewRequestRemovedEvent | ReviewDismissedEvent | UserBlockedEvent """An edge in a connection.""" type PullRequestTimelineItemEdge { """A cursor for use in pagination.""" cursor: String! """The item at the end of the edge.""" node: PullRequestTimelineItem } """An item in a pull request timeline""" union PullRequestTimelineItems = PullRequestCommit | PullRequestCommitCommentThread | PullRequestReview | PullRequestReviewThread | PullRequestRevisionMarker | BaseRefChangedEvent | BaseRefForcePushedEvent | DeployedEvent | DeploymentEnvironmentChangedEvent | HeadRefDeletedEvent | HeadRefForcePushedEvent | HeadRefRestoredEvent | MergedEvent | ReviewDismissedEvent | ReviewRequestedEvent | ReviewRequestRemovedEvent | IssueComment | CrossReferencedEvent | AddedToProjectEvent | AssignedEvent | ClosedEvent | CommentDeletedEvent | ConvertedNoteToIssueEvent | DemilestonedEvent | LabeledEvent | LockedEvent | MentionedEvent | MilestonedEvent | MovedColumnsInProjectEvent | PinnedEvent | ReferencedEvent | RemovedFromProjectEvent | RenamedTitleEvent | ReopenedEvent | SubscribedEvent | TransferredEvent | UnassignedEvent | UnlabeledEvent | UnlockedEvent | UserBlockedEvent | UnpinnedEvent | UnsubscribedEvent """The connection type for PullRequestTimelineItems.""" type PullRequestTimelineItemsConnection { """A list of edges.""" edges: [PullRequestTimelineItemsEdge] """ Identifies the count of items after applying `before` and `after` filters. """ filteredCount: Int! """A list of nodes.""" nodes: [PullRequestTimelineItems] """ Identifies the count of items after applying `before`/`after` filters and `first`/`last`/`skip` slicing. """ pageCount: Int! """Information to aid in pagination.""" pageInfo: PageInfo! """Identifies the total count of items in the connection.""" totalCount: Int! """Identifies the date and time when the timeline was last updated.""" updatedAt: DateTime! } """An edge in a connection.""" type PullRequestTimelineItemsEdge { """A cursor for use in pagination.""" cursor: String! """The item at the end of the edge.""" node: PullRequestTimelineItems } """The possible item types found in a timeline.""" enum PullRequestTimelineItemsItemType { """Represents a Git commit part of a pull request.""" PULL_REQUEST_COMMIT """Represents a commit comment thread part of a pull request.""" PULL_REQUEST_COMMIT_COMMENT_THREAD """A review object for a given pull request.""" PULL_REQUEST_REVIEW """A threaded list of comments for a given pull request.""" PULL_REQUEST_REVIEW_THREAD """ Represents the latest point in the pull request timeline for which the viewer has seen the pull request's commits. """ PULL_REQUEST_REVISION_MARKER """ Represents a 'base_ref_changed' event on a given issue or pull request. """ BASE_REF_CHANGED_EVENT """Represents a 'base_ref_force_pushed' event on a given pull request.""" BASE_REF_FORCE_PUSHED_EVENT """Represents a 'deployed' event on a given pull request.""" DEPLOYED_EVENT """ Represents a 'deployment_environment_changed' event on a given pull request. """ DEPLOYMENT_ENVIRONMENT_CHANGED_EVENT """Represents a 'head_ref_deleted' event on a given pull request.""" HEAD_REF_DELETED_EVENT """Represents a 'head_ref_force_pushed' event on a given pull request.""" HEAD_REF_FORCE_PUSHED_EVENT """Represents a 'head_ref_restored' event on a given pull request.""" HEAD_REF_RESTORED_EVENT """Represents a 'merged' event on a given pull request.""" MERGED_EVENT """ Represents a 'review_dismissed' event on a given issue or pull request. """ REVIEW_DISMISSED_EVENT """Represents an 'review_requested' event on a given pull request.""" REVIEW_REQUESTED_EVENT """Represents an 'review_request_removed' event on a given pull request.""" REVIEW_REQUEST_REMOVED_EVENT """Represents a comment on an Issue.""" ISSUE_COMMENT """Represents a mention made by one issue or pull request to another.""" CROSS_REFERENCED_EVENT """ Represents a 'added_to_project' event on a given issue or pull request. """ ADDED_TO_PROJECT_EVENT """Represents an 'assigned' event on any assignable object.""" ASSIGNED_EVENT """Represents a 'closed' event on any `Closable`.""" CLOSED_EVENT """Represents a 'comment_deleted' event on a given issue or pull request.""" COMMENT_DELETED_EVENT """ Represents a 'converted_note_to_issue' event on a given issue or pull request. """ CONVERTED_NOTE_TO_ISSUE_EVENT """Represents a 'demilestoned' event on a given issue or pull request.""" DEMILESTONED_EVENT """Represents a 'labeled' event on a given issue or pull request.""" LABELED_EVENT """Represents a 'locked' event on a given issue or pull request.""" LOCKED_EVENT """Represents a 'mentioned' event on a given issue or pull request.""" MENTIONED_EVENT """Represents a 'milestoned' event on a given issue or pull request.""" MILESTONED_EVENT """ Represents a 'moved_columns_in_project' event on a given issue or pull request. """ MOVED_COLUMNS_IN_PROJECT_EVENT """Represents a 'pinned' event on a given issue or pull request.""" PINNED_EVENT """Represents a 'referenced' event on a given `ReferencedSubject`.""" REFERENCED_EVENT """ Represents a 'removed_from_project' event on a given issue or pull request. """ REMOVED_FROM_PROJECT_EVENT """Represents a 'renamed' event on a given issue or pull request""" RENAMED_TITLE_EVENT """Represents a 'reopened' event on any `Closable`.""" REOPENED_EVENT """Represents a 'subscribed' event on a given `Subscribable`.""" SUBSCRIBED_EVENT """Represents a 'transferred' event on a given issue or pull request.""" TRANSFERRED_EVENT """Represents an 'unassigned' event on any assignable object.""" UNASSIGNED_EVENT """Represents an 'unlabeled' event on a given issue or pull request.""" UNLABELED_EVENT """Represents an 'unlocked' event on a given issue or pull request.""" UNLOCKED_EVENT """Represents a 'user_blocked' event on a given user.""" USER_BLOCKED_EVENT """Represents an 'unpinned' event on a given issue or pull request.""" UNPINNED_EVENT """Represents an 'unsubscribed' event on a given `Subscribable`.""" UNSUBSCRIBED_EVENT } """A team or user who has the ability to push to a protected branch.""" type PushAllowance implements Node { """The actor that can push.""" actor: PushAllowanceActor """ Identifies the branch protection rule associated with the allowed user or team. """ branchProtectionRule: BranchProtectionRule id: ID! } """Types that can be an actor.""" union PushAllowanceActor = User | Team """The connection type for PushAllowance.""" type PushAllowanceConnection { """A list of edges.""" edges: [PushAllowanceEdge] """A list of nodes.""" nodes: [PushAllowance] """Information to aid in pagination.""" pageInfo: PageInfo! """Identifies the total count of items in the connection.""" totalCount: Int! } """An edge in a connection.""" type PushAllowanceEdge { """A cursor for use in pagination.""" cursor: String! """The item at the end of the edge.""" node: PushAllowance } """The query root of GitHub's GraphQL interface.""" type Query { """Look up a code of conduct by its key""" codeOfConduct( """The code of conduct's key""" key: String! ): CodeOfConduct """Look up a code of conduct by its key""" codesOfConduct: [CodeOfConduct] """Look up an open source license by its key""" license( """The license's downcased SPDX ID""" key: String! ): License """Return a list of known open source licenses""" licenses: [License]! """Get alphabetically sorted list of Marketplace categories""" marketplaceCategories( """Return only the specified categories.""" includeCategories: [String!] """Exclude categories with no listings.""" excludeEmpty: Boolean """Returns top level categories only, excluding any subcategories.""" excludeSubcategories: Boolean ): [MarketplaceCategory!]! """Look up a Marketplace category by its slug.""" marketplaceCategory( """The URL slug of the category.""" slug: String! """Also check topic aliases for the category slug""" useTopicAliases: Boolean ): MarketplaceCategory """Look up a single Marketplace listing""" marketplaceListing( """ Select the listing that matches this slug. It's the short name of the listing used in its URL. """ slug: String! ): MarketplaceListing """Look up Marketplace listings""" marketplaceListings( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int """Select only listings with the given category.""" categorySlug: String """Also check topic aliases for the category slug""" useTopicAliases: Boolean """ Select listings to which user has admin access. If omitted, listings visible to the viewer are returned. """ viewerCanAdmin: Boolean """Select listings that can be administered by the specified user.""" adminId: ID """Select listings for products owned by the specified organization.""" organizationId: ID """ Select listings visible to the viewer even if they are not approved. If omitted or false, only approved listings will be returned. """ allStates: Boolean """ Select the listings with these slugs, if they are visible to the viewer. """ slugs: [String] """ Select only listings where the primary category matches the given category slug. """ primaryCategoryOnly: Boolean = false """Select only listings that offer a free trial.""" withFreeTrialsOnly: Boolean = false ): MarketplaceListingConnection! """Return information about the GitHub instance""" meta: GitHubMetadata! """Fetches an object given its ID.""" node( """ID of the object.""" id: ID! ): Node """Lookup nodes by a list of IDs.""" nodes( """The list of node IDs.""" ids: [ID!]! ): [Node]! """Lookup a organization by login.""" organization( """The organization's login.""" login: String! ): Organization """The client's rate limit information.""" rateLimit( """If true, calculate the cost for the query without evaluating it""" dryRun: Boolean = false ): RateLimit """ Hack to workaround https://github.com/facebook/relay/issues/112 re-exposing the root query object """ relay: Query! """Lookup a given repository by the owner and repository name.""" repository( """The login field of a user or organization""" owner: String! """The name of the repository""" name: String! ): Repository """ Lookup a repository owner (ie. either a User or an Organization) by login. """ repositoryOwner( """The username to lookup the owner by.""" login: String! ): RepositoryOwner """Lookup resource by a URL.""" resource( """The URL.""" url: URI! ): UniformResourceLocatable """Perform a search across resources.""" search( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int """The search string to look for.""" query: String! """The types of search items to search within.""" type: SearchType! ): SearchResultItemConnection! """GitHub Security Advisories""" securityAdvisories( """Ordering options for the returned topics.""" orderBy: SecurityAdvisoryOrder """Filter advisories by identifier, e.g. GHSA or CVE.""" identifier: SecurityAdvisoryIdentifierFilter """Filter advisories to those published since a time in the past.""" publishedSince: DateTime """Filter advisories to those updated since a time in the past.""" updatedSince: DateTime """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): SecurityAdvisoryConnection! """Fetch a Security Advisory by its GHSA ID""" securityAdvisory( """GitHub Security Advisory ID.""" ghsaId: String! ): SecurityAdvisory """Software Vulnerabilities documented by GitHub Security Advisories""" securityVulnerabilities( """Ordering options for the returned topics.""" orderBy: SecurityVulnerabilityOrder """An ecosystem to filter vulnerabilities by.""" ecosystem: SecurityAdvisoryEcosystem """A package name to filter vulnerabilities by.""" package: String """A list of severities to filter vulnerabilities by.""" severities: [SecurityAdvisorySeverity!] """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): SecurityVulnerabilityConnection! """Look up a topic by name.""" topic( """The topic's name.""" name: String! ): Topic """Lookup a user by login.""" user( """The user's login.""" login: String! ): User """The currently authenticated user.""" viewer: User! } """Represents the client's rate limit.""" type RateLimit { """The point cost for the current query counting against the rate limit.""" cost: Int! """ The maximum number of points the client is permitted to consume in a 60 minute window. """ limit: Int! """The maximum number of nodes this query may return""" nodeCount: Int! """The number of points remaining in the current rate limit window.""" remaining: Int! """ The time at which the current rate limit window resets in UTC epoch seconds. """ resetAt: DateTime! } """Represents a subject that can be reacted on.""" interface Reactable { """Identifies the primary key from the database.""" databaseId: Int id: ID! """A list of reactions grouped by content left on the subject.""" reactionGroups: [ReactionGroup!] """A list of Reactions left on the Issue.""" reactions( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int """Allows filtering Reactions by emoji.""" content: ReactionContent """Allows specifying the order in which reactions are returned.""" orderBy: ReactionOrder ): ReactionConnection! """Can user react to this subject""" viewerCanReact: Boolean! } """The connection type for User.""" type ReactingUserConnection { """A list of edges.""" edges: [ReactingUserEdge] """A list of nodes.""" nodes: [User] """Information to aid in pagination.""" pageInfo: PageInfo! """Identifies the total count of items in the connection.""" totalCount: Int! } """Represents a user that's made a reaction.""" type ReactingUserEdge { """A cursor for use in pagination.""" cursor: String! node: User! """The moment when the user made the reaction.""" reactedAt: DateTime! } """An emoji reaction to a particular piece of content.""" type Reaction implements Node { """Identifies the emoji reaction.""" content: ReactionContent! """Identifies the date and time when the object was created.""" createdAt: DateTime! """Identifies the primary key from the database.""" databaseId: Int id: ID! """The reactable piece of content""" reactable: Reactable! """Identifies the user who created this reaction.""" user: User } """A list of reactions that have been left on the subject.""" type ReactionConnection { """A list of edges.""" edges: [ReactionEdge] """A list of nodes.""" nodes: [Reaction] """Information to aid in pagination.""" pageInfo: PageInfo! """Identifies the total count of items in the connection.""" totalCount: Int! """ Whether or not the authenticated user has left a reaction on the subject. """ viewerHasReacted: Boolean! } """Emojis that can be attached to Issues, Pull Requests and Comments.""" enum ReactionContent { """Represents the 👍 emoji.""" THUMBS_UP """Represents the 👎 emoji.""" THUMBS_DOWN """Represents the 😄 emoji.""" LAUGH """Represents the 🎉 emoji.""" HOORAY """Represents the 😕 emoji.""" CONFUSED """Represents the ❤️ emoji.""" HEART """Represents the 🚀 emoji.""" ROCKET """Represents the 👀 emoji.""" EYES } """An edge in a connection.""" type ReactionEdge { """A cursor for use in pagination.""" cursor: String! """The item at the end of the edge.""" node: Reaction } """A group of emoji reactions to a particular piece of content.""" type ReactionGroup { """Identifies the emoji reaction.""" content: ReactionContent! """Identifies when the reaction was created.""" createdAt: DateTime """The subject that was reacted to.""" subject: Reactable! """ Users who have reacted to the reaction subject with the emotion represented by this reaction group """ users( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): ReactingUserConnection! """ Whether or not the authenticated user has left a reaction on the subject. """ viewerHasReacted: Boolean! } """Ways in which lists of reactions can be ordered upon return.""" input ReactionOrder { """The field in which to order reactions by.""" field: ReactionOrderField! """The direction in which to order reactions by the specified field.""" direction: OrderDirection! } """A list of fields that reactions can be ordered by.""" enum ReactionOrderField { """Allows ordering a list of reactions by when they were created.""" CREATED_AT } """Represents a Git reference.""" type Ref implements Node { """A list of pull requests with this ref as the head ref.""" associatedPullRequests( """A list of states to filter the pull requests by.""" states: [PullRequestState!] """A list of label names to filter the pull requests by.""" labels: [String!] """The head ref name to filter the pull requests by.""" headRefName: String """The base ref name to filter the pull requests by.""" baseRefName: String """Ordering options for pull requests returned from the connection.""" orderBy: IssueOrder """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): PullRequestConnection! id: ID! """The ref name.""" name: String! """The ref's prefix, such as `refs/heads/` or `refs/tags/`.""" prefix: String! """The repository the ref belongs to.""" repository: Repository! """The object the ref points to.""" target: GitObject! } """The connection type for Ref.""" type RefConnection { """A list of edges.""" edges: [RefEdge] """A list of nodes.""" nodes: [Ref] """Information to aid in pagination.""" pageInfo: PageInfo! """Identifies the total count of items in the connection.""" totalCount: Int! } """An edge in a connection.""" type RefEdge { """A cursor for use in pagination.""" cursor: String! """The item at the end of the edge.""" node: Ref } """Represents a 'referenced' event on a given `ReferencedSubject`.""" type ReferencedEvent implements Node { """Identifies the actor who performed the event.""" actor: Actor """Identifies the commit associated with the 'referenced' event.""" commit: Commit """Identifies the repository associated with the 'referenced' event.""" commitRepository: Repository! """Identifies the date and time when the object was created.""" createdAt: DateTime! id: ID! """Reference originated in a different repository.""" isCrossRepository: Boolean! """ Checks if the commit message itself references the subject. Can be false in the case of a commit comment reference. """ isDirectReference: Boolean! """Object referenced by event.""" subject: ReferencedSubject! } """Any referencable object""" union ReferencedSubject = Issue | PullRequest """Ways in which lists of git refs can be ordered upon return.""" input RefOrder { """The field in which to order refs by.""" field: RefOrderField! """The direction in which to order refs by the specified field.""" direction: OrderDirection! } """Properties by which ref connections can be ordered.""" enum RefOrderField { """Order refs by underlying commit date if the ref prefix is refs/tags/""" TAG_COMMIT_DATE """Order refs by their alphanumeric name""" ALPHABETICAL } """Represents an owner of a registry package.""" interface RegistryPackageOwner { id: ID! } """Represents an interface to search packages on an object.""" interface RegistryPackageSearch { id: ID! } """A release contains the content for a release.""" type Release implements Node & UniformResourceLocatable { """The author of the release""" author: User """Identifies the date and time when the object was created.""" createdAt: DateTime! """Identifies the description of the release.""" description: String id: ID! """Whether or not the release is a draft""" isDraft: Boolean! """Whether or not the release is a prerelease""" isPrerelease: Boolean! """Identifies the title of the release.""" name: String """Identifies the date and time when the release was created.""" publishedAt: DateTime """List of releases assets which are dependent on this release.""" releaseAssets( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int """A list of names to filter the assets by.""" name: String ): ReleaseAssetConnection! """The HTTP path for this issue""" resourcePath: URI! """The Git tag the release points to""" tag: Ref """The name of the release's Git tag""" tagName: String! """Identifies the date and time when the object was last updated.""" updatedAt: DateTime! """The HTTP URL for this issue""" url: URI! } """A release asset contains the content for a release asset.""" type ReleaseAsset implements Node { """The asset's content-type""" contentType: String! """Identifies the date and time when the object was created.""" createdAt: DateTime! """The number of times this asset was downloaded""" downloadCount: Int! """ Identifies the URL where you can download the release asset via the browser. """ downloadUrl: URI! id: ID! """Identifies the title of the release asset.""" name: String! """Release that the asset is associated with""" release: Release """The size (in bytes) of the asset""" size: Int! """Identifies the date and time when the object was last updated.""" updatedAt: DateTime! """The user that performed the upload""" uploadedBy: User! """Identifies the URL of the release asset.""" url: URI! } """The connection type for ReleaseAsset.""" type ReleaseAssetConnection { """A list of edges.""" edges: [ReleaseAssetEdge] """A list of nodes.""" nodes: [ReleaseAsset] """Information to aid in pagination.""" pageInfo: PageInfo! """Identifies the total count of items in the connection.""" totalCount: Int! } """An edge in a connection.""" type ReleaseAssetEdge { """A cursor for use in pagination.""" cursor: String! """The item at the end of the edge.""" node: ReleaseAsset } """The connection type for Release.""" type ReleaseConnection { """A list of edges.""" edges: [ReleaseEdge] """A list of nodes.""" nodes: [Release] """Information to aid in pagination.""" pageInfo: PageInfo! """Identifies the total count of items in the connection.""" totalCount: Int! } """An edge in a connection.""" type ReleaseEdge { """A cursor for use in pagination.""" cursor: String! """The item at the end of the edge.""" node: Release } """Ways in which lists of releases can be ordered upon return.""" input ReleaseOrder { """The field in which to order releases by.""" field: ReleaseOrderField! """The direction in which to order releases by the specified field.""" direction: OrderDirection! } """Properties by which release connections can be ordered.""" enum ReleaseOrderField { """Order releases by creation time""" CREATED_AT """Order releases alphabetically by name""" NAME } """Autogenerated input type of RemoveAssigneesFromAssignable""" input RemoveAssigneesFromAssignableInput { """The id of the assignable object to remove assignees from.""" assignableId: ID! """The id of users to remove as assignees.""" assigneeIds: [ID!]! """A unique identifier for the client performing the mutation.""" clientMutationId: String } """Autogenerated return type of RemoveAssigneesFromAssignable""" type RemoveAssigneesFromAssignablePayload { """The item that was unassigned.""" assignable: Assignable """A unique identifier for the client performing the mutation.""" clientMutationId: String } """ Represents a 'removed_from_project' event on a given issue or pull request. """ type RemovedFromProjectEvent implements Node { """Identifies the actor who performed the event.""" actor: Actor """Identifies the date and time when the object was created.""" createdAt: DateTime! """Identifies the primary key from the database.""" databaseId: Int id: ID! } """Autogenerated input type of RemoveLabelsFromLabelable""" input RemoveLabelsFromLabelableInput { """The id of the Labelable to remove labels from.""" labelableId: ID! """The ids of labels to remove.""" labelIds: [ID!]! """A unique identifier for the client performing the mutation.""" clientMutationId: String } """Autogenerated return type of RemoveLabelsFromLabelable""" type RemoveLabelsFromLabelablePayload { """A unique identifier for the client performing the mutation.""" clientMutationId: String """The Labelable the labels were removed from.""" labelable: Labelable } """Autogenerated input type of RemoveOutsideCollaborator""" input RemoveOutsideCollaboratorInput { """The ID of the outside collaborator to remove.""" userId: ID! """The ID of the organization to remove the outside collaborator from.""" organizationId: ID! """A unique identifier for the client performing the mutation.""" clientMutationId: String } """Autogenerated return type of RemoveOutsideCollaborator""" type RemoveOutsideCollaboratorPayload { """A unique identifier for the client performing the mutation.""" clientMutationId: String """The user that was removed as an outside collaborator.""" removedUser: User } """Autogenerated input type of RemoveReaction""" input RemoveReactionInput { """The Node ID of the subject to modify.""" subjectId: ID! """The name of the emoji reaction to remove.""" content: ReactionContent! """A unique identifier for the client performing the mutation.""" clientMutationId: String } """Autogenerated return type of RemoveReaction""" type RemoveReactionPayload { """A unique identifier for the client performing the mutation.""" clientMutationId: String """The reaction object.""" reaction: Reaction """The reactable subject.""" subject: Reactable } """Autogenerated input type of RemoveStar""" input RemoveStarInput { """The Starrable ID to unstar.""" starrableId: ID! """A unique identifier for the client performing the mutation.""" clientMutationId: String } """Autogenerated return type of RemoveStar""" type RemoveStarPayload { """A unique identifier for the client performing the mutation.""" clientMutationId: String """The starrable.""" starrable: Starrable } """Represents a 'renamed' event on a given issue or pull request""" type RenamedTitleEvent implements Node { """Identifies the actor who performed the event.""" actor: Actor """Identifies the date and time when the object was created.""" createdAt: DateTime! """Identifies the current title of the issue or pull request.""" currentTitle: String! id: ID! """Identifies the previous title of the issue or pull request.""" previousTitle: String! """Subject that was renamed.""" subject: RenamedTitleSubject! } """An object which has a renamable title""" union RenamedTitleSubject = Issue | PullRequest """Represents a 'reopened' event on any `Closable`.""" type ReopenedEvent implements Node { """Identifies the actor who performed the event.""" actor: Actor """Object that was reopened.""" closable: Closable! """Identifies the date and time when the object was created.""" createdAt: DateTime! id: ID! } """Autogenerated input type of ReopenIssue""" input ReopenIssueInput { """ID of the issue to be opened.""" issueId: ID! """A unique identifier for the client performing the mutation.""" clientMutationId: String } """Autogenerated return type of ReopenIssue""" type ReopenIssuePayload { """A unique identifier for the client performing the mutation.""" clientMutationId: String """The issue that was opened.""" issue: Issue } """Autogenerated input type of ReopenPullRequest""" input ReopenPullRequestInput { """ID of the pull request to be reopened.""" pullRequestId: ID! """A unique identifier for the client performing the mutation.""" clientMutationId: String } """Autogenerated return type of ReopenPullRequest""" type ReopenPullRequestPayload { """A unique identifier for the client performing the mutation.""" clientMutationId: String """The pull request that was reopened.""" pullRequest: PullRequest } """The reasons a piece of content can be reported or minimized.""" enum ReportedContentClassifiers { """A spammy piece of content""" SPAM """An abusive or harassing piece of content""" ABUSE """An irrelevant piece of content""" OFF_TOPIC """An outdated piece of content""" OUTDATED """The content has been resolved""" RESOLVED } """A repository contains the content for a project.""" type Repository implements Node & ProjectOwner & RegistryPackageOwner & Subscribable & Starrable & UniformResourceLocatable & RepositoryInfo { """A list of users that can be assigned to issues in this repository.""" assignableUsers( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): UserConnection! """A list of branch protection rules for this repository.""" branchProtectionRules( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): BranchProtectionRuleConnection! """Returns the code of conduct for this repository""" codeOfConduct: CodeOfConduct """A list of collaborators associated with the repository.""" collaborators( """Collaborators affiliation level with a repository.""" affiliation: CollaboratorAffiliation """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): RepositoryCollaboratorConnection """A list of commit comments associated with the repository.""" commitComments( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): CommitCommentConnection! """Identifies the date and time when the object was created.""" createdAt: DateTime! """Identifies the primary key from the database.""" databaseId: Int """The Ref associated with the repository's default branch.""" defaultBranchRef: Ref """A list of deploy keys that are on this repository.""" deployKeys( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): DeployKeyConnection! """Deployments associated with the repository""" deployments( """Environments to list deployments for""" environments: [String!] """Ordering options for deployments returned from the connection.""" orderBy: DeploymentOrder """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): DeploymentConnection! """The description of the repository.""" description: String """The description of the repository rendered to HTML.""" descriptionHTML: HTML! """The number of kilobytes this repository occupies on disk.""" diskUsage: Int """ Returns how many forks there are of this repository in the whole network. """ forkCount: Int! """A list of direct forked repositories.""" forks( """If non-null, filters repositories according to privacy""" privacy: RepositoryPrivacy """Ordering options for repositories returned from the connection""" orderBy: RepositoryOrder """ Array of viewer's affiliation options for repositories returned from the connection. For example, OWNER will include only repositories that the current viewer owns. """ affiliations: [RepositoryAffiliation] """ Array of owner's affiliation options for repositories returned from the connection. For example, OWNER will include only repositories that the organization or user being viewed owns. """ ownerAffiliations: [RepositoryAffiliation] """ If non-null, filters repositories according to whether they have been locked """ isLocked: Boolean """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): RepositoryConnection! """Indicates if the repository has issues feature enabled.""" hasIssuesEnabled: Boolean! """Indicates if the repository has wiki feature enabled.""" hasWikiEnabled: Boolean! """The repository's URL.""" homepageUrl: URI id: ID! """Indicates if the repository is unmaintained.""" isArchived: Boolean! """Returns whether or not this repository disabled.""" isDisabled: Boolean! """Identifies if the repository is a fork.""" isFork: Boolean! """Indicates if the repository has been locked or not.""" isLocked: Boolean! """Identifies if the repository is a mirror.""" isMirror: Boolean! """Identifies if the repository is private.""" isPrivate: Boolean! """Returns a single issue from the current repository by number.""" issue( """The number for the issue to be returned.""" number: Int! ): Issue """ Returns a single issue-like object from the current repository by number. """ issueOrPullRequest( """The number for the issue to be returned.""" number: Int! ): IssueOrPullRequest """A list of issues that have been opened in the repository.""" issues( """Ordering options for issues returned from the connection.""" orderBy: IssueOrder """A list of label names to filter the pull requests by.""" labels: [String!] """A list of states to filter the issues by.""" states: [IssueState!] """Filtering options for issues returned from the connection.""" filterBy: IssueFilters """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): IssueConnection! """Returns a single label by name""" label( """Label name""" name: String! ): Label """A list of labels associated with the repository.""" labels( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int """If provided, searches labels by name and description.""" query: String ): LabelConnection """ A list containing a breakdown of the language composition of the repository. """ languages( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int """Order for connection""" orderBy: LanguageOrder ): LanguageConnection """The license associated with the repository""" licenseInfo: License """The reason the repository has been locked.""" lockReason: RepositoryLockReason """ A list of Users that can be mentioned in the context of the repository. """ mentionableUsers( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): UserConnection! """Whether or not PRs are merged with a merge commit on this repository.""" mergeCommitAllowed: Boolean! """Returns a single milestone from the current repository by number.""" milestone( """The number for the milestone to be returned.""" number: Int! ): Milestone """A list of milestones associated with the repository.""" milestones( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int """Filter by the state of the milestones.""" states: [MilestoneState!] """Ordering options for milestones.""" orderBy: MilestoneOrder ): MilestoneConnection """The repository's original mirror URL.""" mirrorUrl: URI """The name of the repository.""" name: String! """The repository's name with owner.""" nameWithOwner: String! """A Git object in the repository""" object( """The Git object ID""" oid: GitObjectID """A Git revision expression suitable for rev-parse""" expression: String ): GitObject """The User owner of the repository.""" owner: RepositoryOwner! """The repository parent, if this is a fork.""" parent: Repository """The primary language of the repository's code.""" primaryLanguage: Language """Find project by number.""" project( """The project number to find.""" number: Int! ): Project """A list of projects under the owner.""" projects( """Ordering options for projects returned from the connection""" orderBy: ProjectOrder """Query to search projects by, currently only searching by name.""" search: String """A list of states to filter the projects by.""" states: [ProjectState!] """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): ProjectConnection! """The HTTP path listing the repository's projects""" projectsResourcePath: URI! """The HTTP URL listing the repository's projects""" projectsUrl: URI! """Returns a single pull request from the current repository by number.""" pullRequest( """The number for the pull request to be returned.""" number: Int! ): PullRequest """A list of pull requests that have been opened in the repository.""" pullRequests( """A list of states to filter the pull requests by.""" states: [PullRequestState!] """A list of label names to filter the pull requests by.""" labels: [String!] """The head ref name to filter the pull requests by.""" headRefName: String """The base ref name to filter the pull requests by.""" baseRefName: String """Ordering options for pull requests returned from the connection.""" orderBy: IssueOrder """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): PullRequestConnection! """Identifies when the repository was last pushed to.""" pushedAt: DateTime """Whether or not rebase-merging is enabled on this repository.""" rebaseMergeAllowed: Boolean! """Fetch a given ref from the repository""" ref( """ The ref to retrieve. Fully qualified matches are checked in order (`refs/heads/master`) before falling back onto checks for short name matches (`master`). """ qualifiedName: String! ): Ref """Fetch a list of refs from the repository""" refs( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int """A ref name prefix like `refs/heads/`, `refs/tags/`, etc.""" refPrefix: String! """DEPRECATED: use orderBy. The ordering direction.""" direction: OrderDirection """Ordering options for refs returned from the connection.""" orderBy: RefOrder ): RefConnection """Lookup a single release given various criteria.""" release( """The name of the Tag the Release was created from""" tagName: String! ): Release """List of releases which are dependent on this repository.""" releases( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int """Order for connection""" orderBy: ReleaseOrder ): ReleaseConnection! """A list of applied repository-topic associations for this repository.""" repositoryTopics( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): RepositoryTopicConnection! """The HTTP path for this repository""" resourcePath: URI! """ A description of the repository, rendered to HTML without any links in it. """ shortDescriptionHTML( """How many characters to return.""" limit: Int = 200 ): HTML! """Whether or not squash-merging is enabled on this repository.""" squashMergeAllowed: Boolean! """The SSH URL to clone this repository""" sshUrl: GitSSHRemote! """A list of users who have starred this starrable.""" stargazers( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int """Order for connection""" orderBy: StarOrder ): StargazerConnection! """Identifies the date and time when the object was last updated.""" updatedAt: DateTime! """The HTTP URL for this repository""" url: URI! """Indicates whether the viewer has admin permissions on this repository.""" viewerCanAdminister: Boolean! """Can the current viewer create new projects on this owner.""" viewerCanCreateProjects: Boolean! """ Check if the viewer is able to change their subscription status for the repository. """ viewerCanSubscribe: Boolean! """Indicates whether the viewer can update the topics of this repository.""" viewerCanUpdateTopics: Boolean! """ Returns a boolean indicating whether the viewing user has starred this starrable. """ viewerHasStarred: Boolean! """ The users permission level on the repository. Will return null if authenticated as an GitHub App. """ viewerPermission: RepositoryPermission """ Identifies if the viewer is watching, not watching, or ignoring the subscribable entity. """ viewerSubscription: SubscriptionState """A list of users watching the repository.""" watchers( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): UserConnection! } """The affiliation of a user to a repository""" enum RepositoryAffiliation { """Repositories that are owned by the authenticated user.""" OWNER """Repositories that the user has been added to as a collaborator.""" COLLABORATOR """ Repositories that the user has access to through being a member of an organization. This includes every repository on every team that the user is on. """ ORGANIZATION_MEMBER } """The affiliation type between collaborator and repository.""" enum RepositoryCollaboratorAffiliation { """All collaborators of the repository.""" ALL """All outside collaborators of an organization-owned repository.""" OUTSIDE } """The connection type for User.""" type RepositoryCollaboratorConnection { """A list of edges.""" edges: [RepositoryCollaboratorEdge] """A list of nodes.""" nodes: [User] """Information to aid in pagination.""" pageInfo: PageInfo! """Identifies the total count of items in the connection.""" totalCount: Int! } """Represents a user who is a collaborator of a repository.""" type RepositoryCollaboratorEdge { """A cursor for use in pagination.""" cursor: String! node: User! """The permission the user has on the repository.""" permission: RepositoryPermission! """A list of sources for the user's access to the repository.""" permissionSources: [PermissionSource!] } """A list of repositories owned by the subject.""" type RepositoryConnection { """A list of edges.""" edges: [RepositoryEdge] """A list of nodes.""" nodes: [Repository] """Information to aid in pagination.""" pageInfo: PageInfo! """Identifies the total count of items in the connection.""" totalCount: Int! """The total size in kilobytes of all repositories in the connection.""" totalDiskUsage: Int! } """The reason a repository is listed as 'contributed'.""" enum RepositoryContributionType { """Created a commit""" COMMIT """Created an issue""" ISSUE """Created a pull request""" PULL_REQUEST """Created the repository""" REPOSITORY """Reviewed a pull request""" PULL_REQUEST_REVIEW } """An edge in a connection.""" type RepositoryEdge { """A cursor for use in pagination.""" cursor: String! """The item at the end of the edge.""" node: Repository } """A subset of repository info.""" interface RepositoryInfo { """Identifies the date and time when the object was created.""" createdAt: DateTime! """The description of the repository.""" description: String """The description of the repository rendered to HTML.""" descriptionHTML: HTML! """ Returns how many forks there are of this repository in the whole network. """ forkCount: Int! """Indicates if the repository has issues feature enabled.""" hasIssuesEnabled: Boolean! """Indicates if the repository has wiki feature enabled.""" hasWikiEnabled: Boolean! """The repository's URL.""" homepageUrl: URI """Indicates if the repository is unmaintained.""" isArchived: Boolean! """Identifies if the repository is a fork.""" isFork: Boolean! """Indicates if the repository has been locked or not.""" isLocked: Boolean! """Identifies if the repository is a mirror.""" isMirror: Boolean! """Identifies if the repository is private.""" isPrivate: Boolean! """The license associated with the repository""" licenseInfo: License """The reason the repository has been locked.""" lockReason: RepositoryLockReason """The repository's original mirror URL.""" mirrorUrl: URI """The name of the repository.""" name: String! """The repository's name with owner.""" nameWithOwner: String! """The User owner of the repository.""" owner: RepositoryOwner! """Identifies when the repository was last pushed to.""" pushedAt: DateTime """The HTTP path for this repository""" resourcePath: URI! """ A description of the repository, rendered to HTML without any links in it. """ shortDescriptionHTML( """How many characters to return.""" limit: Int = 200 ): HTML! """Identifies the date and time when the object was last updated.""" updatedAt: DateTime! """The HTTP URL for this repository""" url: URI! } """An invitation for a user to be added to a repository.""" type RepositoryInvitation implements Node { id: ID! """The user who received the invitation.""" invitee: User! """The user who created the invitation.""" inviter: User! """The permission granted on this repository by this invitation.""" permission: RepositoryPermission! """The Repository the user is invited to.""" repository: RepositoryInfo } """An edge in a connection.""" type RepositoryInvitationEdge { """A cursor for use in pagination.""" cursor: String! """The item at the end of the edge.""" node: RepositoryInvitation } """The possible reasons a given repository could be in a locked state.""" enum RepositoryLockReason { """The repository is locked due to a move.""" MOVING """The repository is locked due to a billing related reason.""" BILLING """The repository is locked due to a rename.""" RENAME """The repository is locked due to a migration.""" MIGRATING } """Represents a object that belongs to a repository.""" interface RepositoryNode { """The repository associated with this node.""" repository: Repository! } """Ordering options for repository connections""" input RepositoryOrder { """The field to order repositories by.""" field: RepositoryOrderField! """The ordering direction.""" direction: OrderDirection! } """Properties by which repository connections can be ordered.""" enum RepositoryOrderField { """Order repositories by creation time""" CREATED_AT """Order repositories by update time""" UPDATED_AT """Order repositories by push time""" PUSHED_AT """Order repositories by name""" NAME """Order repositories by number of stargazers""" STARGAZERS } """Represents an owner of a Repository.""" interface RepositoryOwner { """A URL pointing to the owner's public avatar.""" avatarUrl( """The size of the resulting square image.""" size: Int ): URI! id: ID! """The username used to login.""" login: String! """A list of repositories this user has pinned to their profile""" pinnedRepositories( """If non-null, filters repositories according to privacy""" privacy: RepositoryPrivacy """Ordering options for repositories returned from the connection""" orderBy: RepositoryOrder """ Array of viewer's affiliation options for repositories returned from the connection. For example, OWNER will include only repositories that the current viewer owns. """ affiliations: [RepositoryAffiliation] """ Array of owner's affiliation options for repositories returned from the connection. For example, OWNER will include only repositories that the organization or user being viewed owns. """ ownerAffiliations: [RepositoryAffiliation] """ If non-null, filters repositories according to whether they have been locked """ isLocked: Boolean """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): RepositoryConnection! @deprecated(reason: "pinnedRepositories will be removed Use ProfileOwner.pinnedItems instead. Removal on 2019-07-01 UTC.") """A list of repositories that the user owns.""" repositories( """If non-null, filters repositories according to privacy""" privacy: RepositoryPrivacy """Ordering options for repositories returned from the connection""" orderBy: RepositoryOrder """ Array of viewer's affiliation options for repositories returned from the connection. For example, OWNER will include only repositories that the current viewer owns. """ affiliations: [RepositoryAffiliation] """ Array of owner's affiliation options for repositories returned from the connection. For example, OWNER will include only repositories that the organization or user being viewed owns. """ ownerAffiliations: [RepositoryAffiliation] """ If non-null, filters repositories according to whether they have been locked """ isLocked: Boolean """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int """ If non-null, filters repositories according to whether they are forks of another repository """ isFork: Boolean ): RepositoryConnection! """Find Repository.""" repository( """Name of Repository to find.""" name: String! ): Repository """The HTTP URL for the owner.""" resourcePath: URI! """The HTTP URL for the owner.""" url: URI! } """The access level to a repository""" enum RepositoryPermission { """Can read, clone, push, and add collaborators""" ADMIN """Can read, clone and push""" WRITE """Can read and clone""" READ } """The privacy of a repository""" enum RepositoryPrivacy { """Public""" PUBLIC """Private""" PRIVATE } """A repository-topic connects a repository to a topic.""" type RepositoryTopic implements Node & UniformResourceLocatable { id: ID! """The HTTP path for this repository-topic.""" resourcePath: URI! """The topic.""" topic: Topic! """The HTTP URL for this repository-topic.""" url: URI! } """The connection type for RepositoryTopic.""" type RepositoryTopicConnection { """A list of edges.""" edges: [RepositoryTopicEdge] """A list of nodes.""" nodes: [RepositoryTopic] """Information to aid in pagination.""" pageInfo: PageInfo! """Identifies the total count of items in the connection.""" totalCount: Int! } """An edge in a connection.""" type RepositoryTopicEdge { """A cursor for use in pagination.""" cursor: String! """The item at the end of the edge.""" node: RepositoryTopic } """Types that can be requested reviewers.""" union RequestedReviewer = User | Team | Mannequin """Autogenerated input type of RequestReviews""" input RequestReviewsInput { """The Node ID of the pull request to modify.""" pullRequestId: ID! """The Node IDs of the user to request.""" userIds: [ID!] """The Node IDs of the team to request.""" teamIds: [ID!] """Add users to the set rather than replace.""" union: Boolean """A unique identifier for the client performing the mutation.""" clientMutationId: String } """Autogenerated return type of RequestReviews""" type RequestReviewsPayload { """A unique identifier for the client performing the mutation.""" clientMutationId: String """The pull request that is getting requests.""" pullRequest: PullRequest """The edge from the pull request to the requested reviewers.""" requestedReviewersEdge: UserEdge } """Autogenerated input type of ResolveReviewThread""" input ResolveReviewThreadInput { """The ID of the thread to resolve""" threadId: ID! """A unique identifier for the client performing the mutation.""" clientMutationId: String } """Autogenerated return type of ResolveReviewThread""" type ResolveReviewThreadPayload { """A unique identifier for the client performing the mutation.""" clientMutationId: String """The thread to resolve.""" thread: PullRequestReviewThread } """Represents a private contribution a user made on GitHub.""" type RestrictedContribution implements Contribution { """ Whether this contribution is associated with a record you do not have access to. For example, your own 'first issue' contribution may have been made on a repository you can no longer access. """ isRestricted: Boolean! """When this contribution was made.""" occurredAt: DateTime! """The HTTP path for this contribution.""" resourcePath: URI! """The HTTP URL for this contribution.""" url: URI! """ The user who made this contribution. """ user: User! } """ A team or user who has the ability to dismiss a review on a protected branch. """ type ReviewDismissalAllowance implements Node { """The actor that can dismiss.""" actor: ReviewDismissalAllowanceActor """ Identifies the branch protection rule associated with the allowed user or team. """ branchProtectionRule: BranchProtectionRule id: ID! } """Types that can be an actor.""" union ReviewDismissalAllowanceActor = User | Team """The connection type for ReviewDismissalAllowance.""" type ReviewDismissalAllowanceConnection { """A list of edges.""" edges: [ReviewDismissalAllowanceEdge] """A list of nodes.""" nodes: [ReviewDismissalAllowance] """Information to aid in pagination.""" pageInfo: PageInfo! """Identifies the total count of items in the connection.""" totalCount: Int! } """An edge in a connection.""" type ReviewDismissalAllowanceEdge { """A cursor for use in pagination.""" cursor: String! """The item at the end of the edge.""" node: ReviewDismissalAllowance } """ Represents a 'review_dismissed' event on a given issue or pull request. """ type ReviewDismissedEvent implements Node & UniformResourceLocatable { """Identifies the actor who performed the event.""" actor: Actor """Identifies the date and time when the object was created.""" createdAt: DateTime! """Identifies the primary key from the database.""" databaseId: Int """ Identifies the optional message associated with the 'review_dismissed' event. """ dismissalMessage: String """ Identifies the optional message associated with the event, rendered to HTML. """ dismissalMessageHTML: String id: ID! """Identifies the message associated with the 'review_dismissed' event.""" message: String! @deprecated(reason: "`message` is being removed because it not nullable, whereas the underlying field is optional. Use `dismissalMessage` instead. Removal on 2019-07-01 UTC.") """The message associated with the event, rendered to HTML.""" messageHtml: HTML! @deprecated(reason: "`messageHtml` is being removed because it not nullable, whereas the underlying field is optional. Use `dismissalMessageHTML` instead. Removal on 2019-07-01 UTC.") """ Identifies the previous state of the review with the 'review_dismissed' event. """ previousReviewState: PullRequestReviewState! """PullRequest referenced by event.""" pullRequest: PullRequest! """Identifies the commit which caused the review to become stale.""" pullRequestCommit: PullRequestCommit """The HTTP path for this review dismissed event.""" resourcePath: URI! """Identifies the review associated with the 'review_dismissed' event.""" review: PullRequestReview """The HTTP URL for this review dismissed event.""" url: URI! } """A request for a user to review a pull request.""" type ReviewRequest implements Node { """Identifies the primary key from the database.""" databaseId: Int id: ID! """Identifies the pull request associated with this review request.""" pullRequest: PullRequest! """The reviewer that is requested.""" requestedReviewer: RequestedReviewer } """The connection type for ReviewRequest.""" type ReviewRequestConnection { """A list of edges.""" edges: [ReviewRequestEdge] """A list of nodes.""" nodes: [ReviewRequest] """Information to aid in pagination.""" pageInfo: PageInfo! """Identifies the total count of items in the connection.""" totalCount: Int! } """Represents an 'review_requested' event on a given pull request.""" type ReviewRequestedEvent implements Node { """Identifies the actor who performed the event.""" actor: Actor """Identifies the date and time when the object was created.""" createdAt: DateTime! id: ID! """PullRequest referenced by event.""" pullRequest: PullRequest! """Identifies the reviewer whose review was requested.""" requestedReviewer: RequestedReviewer } """An edge in a connection.""" type ReviewRequestEdge { """A cursor for use in pagination.""" cursor: String! """The item at the end of the edge.""" node: ReviewRequest } """Represents an 'review_request_removed' event on a given pull request.""" type ReviewRequestRemovedEvent implements Node { """Identifies the actor who performed the event.""" actor: Actor """Identifies the date and time when the object was created.""" createdAt: DateTime! id: ID! """PullRequest referenced by event.""" pullRequest: PullRequest! """Identifies the reviewer whose review request was removed.""" requestedReviewer: RequestedReviewer } """The results of a search.""" union SearchResultItem = Issue | PullRequest | Repository | User | Organization | MarketplaceListing """A list of results that matched against a search query.""" type SearchResultItemConnection { """The number of pieces of code that matched the search query.""" codeCount: Int! """A list of edges.""" edges: [SearchResultItemEdge] """The number of issues that matched the search query.""" issueCount: Int! """A list of nodes.""" nodes: [SearchResultItem] """Information to aid in pagination.""" pageInfo: PageInfo! """The number of repositories that matched the search query.""" repositoryCount: Int! """The number of users that matched the search query.""" userCount: Int! """The number of wiki pages that matched the search query.""" wikiCount: Int! } """An edge in a connection.""" type SearchResultItemEdge { """A cursor for use in pagination.""" cursor: String! """The item at the end of the edge.""" node: SearchResultItem """Text matches on the result found.""" textMatches: [TextMatch] } """Represents the individual results of a search.""" enum SearchType { """Returns results matching issues in repositories.""" ISSUE """Returns results matching repositories.""" REPOSITORY """Returns results matching users and organizations on GitHub.""" USER } """A GitHub Security Advisory""" type SecurityAdvisory implements Node { """Identifies the primary key from the database.""" databaseId: Int """This is a long plaintext description of the advisory""" description: String! """The GitHub Security Advisory ID""" ghsaId: String! id: ID! """A list of identifiers for this advisory""" identifiers: [SecurityAdvisoryIdentifier!]! """The organization that originated the advisory""" origin: String! """When the advisory was published""" publishedAt: DateTime! """A list of references for this advisory""" references: [SecurityAdvisoryReference!]! """The severity of the advisory""" severity: SecurityAdvisorySeverity! """A short plaintext summary of the advisory""" summary: String! """When the advisory was last updated""" updatedAt: DateTime! """Vulnerabilities associated with this Advisory""" vulnerabilities( """Ordering options for the returned topics.""" orderBy: SecurityVulnerabilityOrder """An ecosystem to filter vulnerabilities by.""" ecosystem: SecurityAdvisoryEcosystem """A package name to filter vulnerabilities by.""" package: String """A list of severities to filter vulnerabilities by.""" severities: [SecurityAdvisorySeverity!] """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): SecurityVulnerabilityConnection! """When the advisory was withdrawn, if it has been withdrawn""" withdrawnAt: DateTime } """The connection type for SecurityAdvisory.""" type SecurityAdvisoryConnection { """A list of edges.""" edges: [SecurityAdvisoryEdge] """A list of nodes.""" nodes: [SecurityAdvisory] """Information to aid in pagination.""" pageInfo: PageInfo! """Identifies the total count of items in the connection.""" totalCount: Int! } """The possible ecosystems of a security vulnerability's package.""" enum SecurityAdvisoryEcosystem { """Ruby gems hosted at RubyGems.org""" RUBYGEMS """JavaScript packages hosted at npmjs.com""" NPM """Python packages hosted at PyPI.org""" PIP """Java artifacts hosted at the Maven central repository""" MAVEN """.NET packages hosted at the NuGet Gallery""" NUGET } """An edge in a connection.""" type SecurityAdvisoryEdge { """A cursor for use in pagination.""" cursor: String! """The item at the end of the edge.""" node: SecurityAdvisory } """A GitHub Security Advisory Identifier""" type SecurityAdvisoryIdentifier { """The identifier type, e.g. GHSA, CVE""" type: String! """The identifier""" value: String! } """An advisory identifier to filter results on.""" input SecurityAdvisoryIdentifierFilter { """The identifier type.""" type: SecurityAdvisoryIdentifierType! """The identifier string. Supports exact or partial matching.""" value: String! } """Identifier formats available for advisories.""" enum SecurityAdvisoryIdentifierType { """Common Vulnerabilities and Exposures Identifier.""" CVE """GitHub Security Advisory ID.""" GHSA } """Ordering options for security advisory connections""" input SecurityAdvisoryOrder { """The field to order security advisories by.""" field: SecurityAdvisoryOrderField! """The ordering direction.""" direction: OrderDirection! } """Properties by which security advisory connections can be ordered.""" enum SecurityAdvisoryOrderField { """Order advisories by publication time""" PUBLISHED_AT """Order advisories by update time""" UPDATED_AT } """An individual package""" type SecurityAdvisoryPackage { """The ecosystem the package belongs to, e.g. RUBYGEMS, NPM""" ecosystem: SecurityAdvisoryEcosystem! """The package name""" name: String! } """An individual package version""" type SecurityAdvisoryPackageVersion { """The package name or version""" identifier: String! } """A GitHub Security Advisory Reference""" type SecurityAdvisoryReference { """A publicly accessible reference""" url: URI! } """Severity of the vulnerability.""" enum SecurityAdvisorySeverity { """Low.""" LOW """Moderate.""" MODERATE """High.""" HIGH """Critical.""" CRITICAL } """An individual vulnerability within an Advisory""" type SecurityVulnerability { """The Advisory associated with this Vulnerability""" advisory: SecurityAdvisory! """The first version containing a fix for the vulnerability""" firstPatchedVersion: SecurityAdvisoryPackageVersion """A description of the vulnerable package""" package: SecurityAdvisoryPackage! """The severity of the vulnerability within this package""" severity: SecurityAdvisorySeverity! """When the vulnerability was last updated""" updatedAt: DateTime! """ A string that describes the vulnerable package versions. This string follows a basic syntax with a few forms. + `= 0.2.0` denotes a single vulnerable version. + `<= 1.0.8` denotes a version range up to and including the specified version + `< 0.1.11` denotes a version range up to, but excluding, the specified version + `>= 4.3.0, < 4.3.5` denotes a version range with a known minimum and maximum version. + `>= 0.0.1` denotes a version range with a known minimum, but no known maximum """ vulnerableVersionRange: String! } """The connection type for SecurityVulnerability.""" type SecurityVulnerabilityConnection { """A list of edges.""" edges: [SecurityVulnerabilityEdge] """A list of nodes.""" nodes: [SecurityVulnerability] """Information to aid in pagination.""" pageInfo: PageInfo! """Identifies the total count of items in the connection.""" totalCount: Int! } """An edge in a connection.""" type SecurityVulnerabilityEdge { """A cursor for use in pagination.""" cursor: String! """The item at the end of the edge.""" node: SecurityVulnerability } """Ordering options for security vulnerability connections""" input SecurityVulnerabilityOrder { """The field to order security vulnerabilities by.""" field: SecurityVulnerabilityOrderField! """The ordering direction.""" direction: OrderDirection! } """Properties by which security vulnerability connections can be ordered.""" enum SecurityVulnerabilityOrderField { """Order vulnerability by update time""" UPDATED_AT } """Represents an S/MIME signature on a Commit or Tag.""" type SmimeSignature implements GitSignature { """Email used to sign this object.""" email: String! """True if the signature is valid and verified by GitHub.""" isValid: Boolean! """ Payload for GPG signing object. Raw ODB object without the signature header. """ payload: String! """ASCII-armored signature header from object.""" signature: String! """GitHub user corresponding to the email signing this commit.""" signer: User """ The state of this signature. `VALID` if signature is valid and verified by GitHub, otherwise represents reason why signature is considered invalid. """ state: GitSignatureState! """True if the signature was made with GitHub's signing key.""" wasSignedByGitHub: Boolean! } """The connection type for User.""" type StargazerConnection { """A list of edges.""" edges: [StargazerEdge] """A list of nodes.""" nodes: [User] """Information to aid in pagination.""" pageInfo: PageInfo! """Identifies the total count of items in the connection.""" totalCount: Int! } """Represents a user that's starred a repository.""" type StargazerEdge { """A cursor for use in pagination.""" cursor: String! node: User! """Identifies when the item was starred.""" starredAt: DateTime! } """Ways in which star connections can be ordered.""" input StarOrder { """The field in which to order nodes by.""" field: StarOrderField! """The direction in which to order nodes.""" direction: OrderDirection! } """Properties by which star connections can be ordered.""" enum StarOrderField { """Allows ordering a list of stars by when they were created.""" STARRED_AT } """Things that can be starred.""" interface Starrable { id: ID! """A list of users who have starred this starrable.""" stargazers( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int """Order for connection""" orderBy: StarOrder ): StargazerConnection! """ Returns a boolean indicating whether the viewing user has starred this starrable. """ viewerHasStarred: Boolean! } """The connection type for Repository.""" type StarredRepositoryConnection { """A list of edges.""" edges: [StarredRepositoryEdge] """A list of nodes.""" nodes: [Repository] """Information to aid in pagination.""" pageInfo: PageInfo! """Identifies the total count of items in the connection.""" totalCount: Int! } """Represents a starred repository.""" type StarredRepositoryEdge { """A cursor for use in pagination.""" cursor: String! node: Repository! """Identifies when the item was starred.""" starredAt: DateTime! } """Represents a commit status.""" type Status implements Node { """The commit this status is attached to.""" commit: Commit """Looks up an individual status context by context name.""" context( """The context name.""" name: String! ): StatusContext """The individual status contexts for this commit.""" contexts: [StatusContext!]! id: ID! """The combined commit status.""" state: StatusState! } """Represents an individual commit status context""" type StatusContext implements Node { """This commit this status context is attached to.""" commit: Commit """The name of this status context.""" context: String! """Identifies the date and time when the object was created.""" createdAt: DateTime! """The actor who created this status context.""" creator: Actor """The description for this status context.""" description: String id: ID! """The state of this status context.""" state: StatusState! """The URL for this status context.""" targetUrl: URI } """The possible commit status states.""" enum StatusState { """Status is expected.""" EXPECTED """Status is errored.""" ERROR """Status is failing.""" FAILURE """Status is pending.""" PENDING """Status is successful.""" SUCCESS } """Autogenerated input type of SubmitPullRequestReview""" input SubmitPullRequestReviewInput { """The Pull Request Review ID to submit.""" pullRequestReviewId: ID! """The event to send to the Pull Request Review.""" event: PullRequestReviewEvent! """The text field to set on the Pull Request Review.""" body: String """A unique identifier for the client performing the mutation.""" clientMutationId: String } """Autogenerated return type of SubmitPullRequestReview""" type SubmitPullRequestReviewPayload { """A unique identifier for the client performing the mutation.""" clientMutationId: String """The submitted pull request review.""" pullRequestReview: PullRequestReview } """Entities that can be subscribed to for web and email notifications.""" interface Subscribable { id: ID! """ Check if the viewer is able to change their subscription status for the repository. """ viewerCanSubscribe: Boolean! """ Identifies if the viewer is watching, not watching, or ignoring the subscribable entity. """ viewerSubscription: SubscriptionState } """Represents a 'subscribed' event on a given `Subscribable`.""" type SubscribedEvent implements Node { """Identifies the actor who performed the event.""" actor: Actor """Identifies the date and time when the object was created.""" createdAt: DateTime! id: ID! """Object referenced by event.""" subscribable: Subscribable! } """The possible states of a subscription.""" enum SubscriptionState { """The User is only notified when participating or @mentioned.""" UNSUBSCRIBED """The User is notified of all conversations.""" SUBSCRIBED """The User is never notified.""" IGNORED } """ A suggestion to review a pull request based on a user's commit history and review comments. """ type SuggestedReviewer { """Is this suggestion based on past commits?""" isAuthor: Boolean! """Is this suggestion based on past review comments?""" isCommenter: Boolean! """Identifies the user suggested to review the pull request.""" reviewer: User! } """Represents a Git tag.""" type Tag implements Node & GitObject { """An abbreviated version of the Git object ID""" abbreviatedOid: String! """The HTTP path for this Git object""" commitResourcePath: URI! """The HTTP URL for this Git object""" commitUrl: URI! id: ID! """The Git tag message.""" message: String """The Git tag name.""" name: String! """The Git object ID""" oid: GitObjectID! """The Repository the Git object belongs to""" repository: Repository! """Details about the tag author.""" tagger: GitActor """The Git object the tag points to.""" target: GitObject! } """A team of users in an organization.""" type Team implements Node & Subscribable & MemberStatusable { """A list of teams that are ancestors of this team.""" ancestors( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): TeamConnection! """A URL pointing to the team's avatar.""" avatarUrl( """The size in pixels of the resulting square image.""" size: Int = 400 ): URI """List of child teams belonging to this team""" childTeams( """Order for connection""" orderBy: TeamOrder """User logins to filter by""" userLogins: [String!] """Whether to list immediate child teams or all descendant child teams.""" immediateOnly: Boolean = true """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): TeamConnection! """The slug corresponding to the organization and team.""" combinedSlug: String! """Identifies the date and time when the object was created.""" createdAt: DateTime! """The description of the team.""" description: String """The HTTP path for editing this team""" editTeamResourcePath: URI! """The HTTP URL for editing this team""" editTeamUrl: URI! id: ID! """A list of pending invitations for users to this team""" invitations( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): OrganizationInvitationConnection """ Get the status messages members of this entity have set that are either public or visible only to the organization. """ memberStatuses( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int """Ordering options for user statuses returned from the connection.""" orderBy: UserStatusOrder ): UserStatusConnection! """A list of users who are members of this team.""" members( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int """The search string to look for.""" query: String """Filter by membership type""" membership: TeamMembershipType = ALL """Filter by team member role""" role: TeamMemberRole """Order for the connection.""" orderBy: TeamMemberOrder ): TeamMemberConnection! """The HTTP path for the team' members""" membersResourcePath: URI! """The HTTP URL for the team' members""" membersUrl: URI! """The name of the team.""" name: String! """The HTTP path creating a new team""" newTeamResourcePath: URI! """The HTTP URL creating a new team""" newTeamUrl: URI! """The organization that owns this team.""" organization: Organization! """The parent team of the team.""" parentTeam: Team """The level of privacy the team has.""" privacy: TeamPrivacy! """A list of repositories this team has access to.""" repositories( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int """The search string to look for.""" query: String """Order for the connection.""" orderBy: TeamRepositoryOrder ): TeamRepositoryConnection! """The HTTP path for this team's repositories""" repositoriesResourcePath: URI! """The HTTP URL for this team's repositories""" repositoriesUrl: URI! """The HTTP path for this team""" resourcePath: URI! """The slug corresponding to the team.""" slug: String! """The HTTP path for this team's teams""" teamsResourcePath: URI! """The HTTP URL for this team's teams""" teamsUrl: URI! """Identifies the date and time when the object was last updated.""" updatedAt: DateTime! """The HTTP URL for this team""" url: URI! """Team is adminable by the viewer.""" viewerCanAdminister: Boolean! """ Check if the viewer is able to change their subscription status for the repository. """ viewerCanSubscribe: Boolean! """ Identifies if the viewer is watching, not watching, or ignoring the subscribable entity. """ viewerSubscription: SubscriptionState } """The connection type for Team.""" type TeamConnection { """A list of edges.""" edges: [TeamEdge] """A list of nodes.""" nodes: [Team] """Information to aid in pagination.""" pageInfo: PageInfo! """Identifies the total count of items in the connection.""" totalCount: Int! } """An edge in a connection.""" type TeamEdge { """A cursor for use in pagination.""" cursor: String! """The item at the end of the edge.""" node: Team } """The connection type for User.""" type TeamMemberConnection { """A list of edges.""" edges: [TeamMemberEdge] """A list of nodes.""" nodes: [User] """Information to aid in pagination.""" pageInfo: PageInfo! """Identifies the total count of items in the connection.""" totalCount: Int! } """Represents a user who is a member of a team.""" type TeamMemberEdge { """A cursor for use in pagination.""" cursor: String! """The HTTP path to the organization's member access page.""" memberAccessResourcePath: URI! """The HTTP URL to the organization's member access page.""" memberAccessUrl: URI! node: User! """The role the member has on the team.""" role: TeamMemberRole! } """Ordering options for team member connections""" input TeamMemberOrder { """The field to order team members by.""" field: TeamMemberOrderField! """The ordering direction.""" direction: OrderDirection! } """Properties by which team member connections can be ordered.""" enum TeamMemberOrderField { """Order team members by login""" LOGIN """Order team members by creation time""" CREATED_AT } """The possible team member roles; either 'maintainer' or 'member'.""" enum TeamMemberRole { """A team maintainer has permission to add and remove team members.""" MAINTAINER """A team member has no administrative permissions on the team.""" MEMBER } """ Defines which types of team members are included in the returned list. Can be one of IMMEDIATE, CHILD_TEAM or ALL. """ enum TeamMembershipType { """Includes only immediate members of the team.""" IMMEDIATE """Includes only child team members for the team.""" CHILD_TEAM """Includes immediate and child team members for the team.""" ALL } """Ways in which team connections can be ordered.""" input TeamOrder { """The field in which to order nodes by.""" field: TeamOrderField! """The direction in which to order nodes.""" direction: OrderDirection! } """Properties by which team connections can be ordered.""" enum TeamOrderField { """Allows ordering a list of teams by name.""" NAME } """The possible team privacy values.""" enum TeamPrivacy { """A secret team can only be seen by its members.""" SECRET """ A visible team can be seen and @mentioned by every member of the organization. """ VISIBLE } """The connection type for Repository.""" type TeamRepositoryConnection { """A list of edges.""" edges: [TeamRepositoryEdge] """A list of nodes.""" nodes: [Repository] """Information to aid in pagination.""" pageInfo: PageInfo! """Identifies the total count of items in the connection.""" totalCount: Int! } """Represents a team repository.""" type TeamRepositoryEdge { """A cursor for use in pagination.""" cursor: String! node: Repository! """The permission level the team has on the repository""" permission: RepositoryPermission! } """Ordering options for team repository connections""" input TeamRepositoryOrder { """The field to order repositories by.""" field: TeamRepositoryOrderField! """The ordering direction.""" direction: OrderDirection! } """Properties by which team repository connections can be ordered.""" enum TeamRepositoryOrderField { """Order repositories by creation time""" CREATED_AT """Order repositories by update time""" UPDATED_AT """Order repositories by push time""" PUSHED_AT """Order repositories by name""" NAME """Order repositories by permission""" PERMISSION """Order repositories by number of stargazers""" STARGAZERS } """The role of a user on a team.""" enum TeamRole { """User has admin rights on the team.""" ADMIN """User is a member of the team.""" MEMBER } """A text match within a search result.""" type TextMatch { """The specific text fragment within the property matched on.""" fragment: String! """Highlights within the matched fragment.""" highlights: [TextMatchHighlight!]! """The property matched on.""" property: String! } """Represents a single highlight in a search result match.""" type TextMatchHighlight { """The indice in the fragment where the matched text begins.""" beginIndice: Int! """The indice in the fragment where the matched text ends.""" endIndice: Int! """The text matched.""" text: String! } """A topic aggregates entities that are related to a subject.""" type Topic implements Node & Starrable { id: ID! """The topic's name.""" name: String! """ A list of related topics, including aliases of this topic, sorted with the most relevant first. Returns up to 10 Topics. """ relatedTopics( """How many topics to return.""" first: Int = 3 ): [Topic!]! """A list of users who have starred this starrable.""" stargazers( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int """Order for connection""" orderBy: StarOrder ): StargazerConnection! """ Returns a boolean indicating whether the viewing user has starred this starrable. """ viewerHasStarred: Boolean! } """The connection type for Topic.""" type TopicConnection { """A list of edges.""" edges: [TopicEdge] """A list of nodes.""" nodes: [Topic] """Information to aid in pagination.""" pageInfo: PageInfo! """Identifies the total count of items in the connection.""" totalCount: Int! } """An edge in a connection.""" type TopicEdge { """A cursor for use in pagination.""" cursor: String! """The item at the end of the edge.""" node: Topic } """Reason that the suggested topic is declined.""" enum TopicSuggestionDeclineReason { """The suggested topic is not relevant to the repository.""" NOT_RELEVANT """ The suggested topic is too specific for the repository (e.g. #ruby-on-rails-version-4-2-1). """ TOO_SPECIFIC """The viewer does not like the suggested topic.""" PERSONAL_PREFERENCE """The suggested topic is too general for the repository.""" TOO_GENERAL } """Represents a 'transferred' event on a given issue or pull request.""" type TransferredEvent implements Node { """Identifies the actor who performed the event.""" actor: Actor """Identifies the date and time when the object was created.""" createdAt: DateTime! """The repository this came from""" fromRepository: Repository id: ID! """Identifies the issue associated with the event.""" issue: Issue! } """Represents a Git tree.""" type Tree implements Node & GitObject { """An abbreviated version of the Git object ID""" abbreviatedOid: String! """The HTTP path for this Git object""" commitResourcePath: URI! """The HTTP URL for this Git object""" commitUrl: URI! """A list of tree entries.""" entries: [TreeEntry!] id: ID! """The Git object ID""" oid: GitObjectID! """The Repository the Git object belongs to""" repository: Repository! } """Represents a Git tree entry.""" type TreeEntry { """Entry file mode.""" mode: Int! """Entry file name.""" name: String! """Entry file object.""" object: GitObject """Entry file Git object ID.""" oid: GitObjectID! """The Repository the tree entry belongs to""" repository: Repository! """Entry file type.""" type: String! } """Represents an 'unassigned' event on any assignable object.""" type UnassignedEvent implements Node { """Identifies the actor who performed the event.""" actor: Actor """Identifies the assignable associated with the event.""" assignable: Assignable! """Identifies the date and time when the object was created.""" createdAt: DateTime! id: ID! """Identifies the subject (user) who was unassigned.""" user: User } """Represents a type that can be retrieved by a URL.""" interface UniformResourceLocatable { """The HTML path to this resource.""" resourcePath: URI! """The URL to this resource.""" url: URI! } """Represents an unknown signature on a Commit or Tag.""" type UnknownSignature implements GitSignature { """Email used to sign this object.""" email: String! """True if the signature is valid and verified by GitHub.""" isValid: Boolean! """ Payload for GPG signing object. Raw ODB object without the signature header. """ payload: String! """ASCII-armored signature header from object.""" signature: String! """GitHub user corresponding to the email signing this commit.""" signer: User """ The state of this signature. `VALID` if signature is valid and verified by GitHub, otherwise represents reason why signature is considered invalid. """ state: GitSignatureState! """True if the signature was made with GitHub's signing key.""" wasSignedByGitHub: Boolean! } """Represents an 'unlabeled' event on a given issue or pull request.""" type UnlabeledEvent implements Node { """Identifies the actor who performed the event.""" actor: Actor """Identifies the date and time when the object was created.""" createdAt: DateTime! id: ID! """Identifies the label associated with the 'unlabeled' event.""" label: Label! """Identifies the `Labelable` associated with the event.""" labelable: Labelable! } """Represents an 'unlocked' event on a given issue or pull request.""" type UnlockedEvent implements Node { """Identifies the actor who performed the event.""" actor: Actor """Identifies the date and time when the object was created.""" createdAt: DateTime! id: ID! """Object that was unlocked.""" lockable: Lockable! } """Autogenerated input type of UnlockLockable""" input UnlockLockableInput { """ID of the issue or pull request to be unlocked.""" lockableId: ID! """A unique identifier for the client performing the mutation.""" clientMutationId: String } """Autogenerated return type of UnlockLockable""" type UnlockLockablePayload { """A unique identifier for the client performing the mutation.""" clientMutationId: String """The item that was unlocked.""" unlockedRecord: Lockable } """Autogenerated input type of UnmarkIssueAsDuplicate""" input UnmarkIssueAsDuplicateInput { """ID of the issue or pull request currently marked as a duplicate.""" duplicateId: ID! """ ID of the issue or pull request currently considered canonical/authoritative/original. """ canonicalId: ID! """A unique identifier for the client performing the mutation.""" clientMutationId: String } """Autogenerated return type of UnmarkIssueAsDuplicate""" type UnmarkIssueAsDuplicatePayload { """A unique identifier for the client performing the mutation.""" clientMutationId: String """The issue or pull request that was marked as a duplicate.""" duplicate: IssueOrPullRequest } """Autogenerated input type of UnminimizeComment""" input UnminimizeCommentInput { """The Node ID of the subject to modify.""" subjectId: ID! """A unique identifier for the client performing the mutation.""" clientMutationId: String } """Autogenerated input type of UnpinIssue""" input UnpinIssueInput { """The ID of the issue to be unpinned""" issueId: ID! """A unique identifier for the client performing the mutation.""" clientMutationId: String } """Represents an 'unpinned' event on a given issue or pull request.""" type UnpinnedEvent implements Node { """Identifies the actor who performed the event.""" actor: Actor """Identifies the date and time when the object was created.""" createdAt: DateTime! id: ID! """Identifies the issue associated with the event.""" issue: Issue! } """Autogenerated input type of UnresolveReviewThread""" input UnresolveReviewThreadInput { """The ID of the thread to unresolve""" threadId: ID! """A unique identifier for the client performing the mutation.""" clientMutationId: String } """Autogenerated return type of UnresolveReviewThread""" type UnresolveReviewThreadPayload { """A unique identifier for the client performing the mutation.""" clientMutationId: String """The thread to resolve.""" thread: PullRequestReviewThread } """Represents an 'unsubscribed' event on a given `Subscribable`.""" type UnsubscribedEvent implements Node { """Identifies the actor who performed the event.""" actor: Actor """Identifies the date and time when the object was created.""" createdAt: DateTime! id: ID! """Object referenced by event.""" subscribable: Subscribable! } """Entities that can be updated.""" interface Updatable { """Check if the current viewer can update this object.""" viewerCanUpdate: Boolean! } """Comments that can be updated.""" interface UpdatableComment { """Reasons why the current viewer can not update this comment.""" viewerCannotUpdateReasons: [CommentCannotUpdateReason!]! } """Autogenerated input type of UpdateBranchProtectionRule""" input UpdateBranchProtectionRuleInput { """The global relay id of the branch protection rule to be updated.""" branchProtectionRuleId: ID! """The glob-like pattern used to determine matching branches.""" pattern: String """Are approving reviews required to update matching branches.""" requiresApprovingReviews: Boolean """Number of approving reviews required to update matching branches.""" requiredApprovingReviewCount: Int """Are commits required to be signed.""" requiresCommitSignatures: Boolean """Can admins overwrite branch protection.""" isAdminEnforced: Boolean """Are status checks required to update matching branches.""" requiresStatusChecks: Boolean """Are branches required to be up to date before merging.""" requiresStrictStatusChecks: Boolean """Are reviews from code owners required to update matching branches.""" requiresCodeOwnerReviews: Boolean """ Will new commits pushed to matching branches dismiss pull request review approvals. """ dismissesStaleReviews: Boolean """Is dismissal of pull request reviews restricted.""" restrictsReviewDismissals: Boolean """ A list of User or Team IDs allowed to dismiss reviews on pull requests targeting matching branches. """ reviewDismissalActorIds: [ID!] """Is pushing to matching branches restricted.""" restrictsPushes: Boolean """A list of User or Team IDs allowed to push to matching branches.""" pushActorIds: [ID!] """ List of required status check contexts that must pass for commits to be accepted to matching branches. """ requiredStatusCheckContexts: [String!] """A unique identifier for the client performing the mutation.""" clientMutationId: String } """Autogenerated return type of UpdateBranchProtectionRule""" type UpdateBranchProtectionRulePayload { """The newly created BranchProtectionRule.""" branchProtectionRule: BranchProtectionRule """A unique identifier for the client performing the mutation.""" clientMutationId: String } """Autogenerated input type of UpdateIssueComment""" input UpdateIssueCommentInput { """The ID of the IssueComment to modify.""" id: ID! """The updated text of the comment.""" body: String! """A unique identifier for the client performing the mutation.""" clientMutationId: String } """Autogenerated return type of UpdateIssueComment""" type UpdateIssueCommentPayload { """A unique identifier for the client performing the mutation.""" clientMutationId: String """The updated comment.""" issueComment: IssueComment } """Autogenerated input type of UpdateIssue""" input UpdateIssueInput { """The ID of the Issue to modify.""" id: ID! """The title for the issue.""" title: String """The body for the issue description.""" body: String """An array of Node IDs of users for this issue.""" assigneeIds: [ID!] """The Node ID of the milestone for this issue.""" milestoneId: ID """An array of Node IDs of labels for this issue.""" labelIds: [ID!] """The desired issue state.""" state: IssueState """An array of Node IDs for projects associated with this issue.""" projectIds: [ID!] """A unique identifier for the client performing the mutation.""" clientMutationId: String } """Autogenerated return type of UpdateIssue""" type UpdateIssuePayload { """A unique identifier for the client performing the mutation.""" clientMutationId: String """The issue.""" issue: Issue } """Autogenerated input type of UpdateProjectCard""" input UpdateProjectCardInput { """The ProjectCard ID to update.""" projectCardId: ID! """Whether or not the ProjectCard should be archived""" isArchived: Boolean """The note of ProjectCard.""" note: String """A unique identifier for the client performing the mutation.""" clientMutationId: String } """Autogenerated return type of UpdateProjectCard""" type UpdateProjectCardPayload { """A unique identifier for the client performing the mutation.""" clientMutationId: String """The updated ProjectCard.""" projectCard: ProjectCard } """Autogenerated input type of UpdateProjectColumn""" input UpdateProjectColumnInput { """The ProjectColumn ID to update.""" projectColumnId: ID! """The name of project column.""" name: String! """A unique identifier for the client performing the mutation.""" clientMutationId: String } """Autogenerated return type of UpdateProjectColumn""" type UpdateProjectColumnPayload { """A unique identifier for the client performing the mutation.""" clientMutationId: String """The updated project column.""" projectColumn: ProjectColumn } """Autogenerated input type of UpdateProject""" input UpdateProjectInput { """The Project ID to update.""" projectId: ID! """The name of project.""" name: String """The description of project.""" body: String """Whether the project is open or closed.""" state: ProjectState """Whether the project is public or not.""" public: Boolean """A unique identifier for the client performing the mutation.""" clientMutationId: String } """Autogenerated return type of UpdateProject""" type UpdateProjectPayload { """A unique identifier for the client performing the mutation.""" clientMutationId: String """The updated project.""" project: Project } """Autogenerated input type of UpdatePullRequest""" input UpdatePullRequestInput { """The Node ID of the pull request.""" pullRequestId: ID! """ The name of the branch you want your changes pulled into. This should be an existing branch on the current repository. """ baseRefName: String """The title of the pull request.""" title: String """The contents of the pull request.""" body: String """Indicates whether maintainers can modify the pull request.""" maintainerCanModify: Boolean """A unique identifier for the client performing the mutation.""" clientMutationId: String } """Autogenerated return type of UpdatePullRequest""" type UpdatePullRequestPayload { """A unique identifier for the client performing the mutation.""" clientMutationId: String """The updated pull request.""" pullRequest: PullRequest } """Autogenerated input type of UpdatePullRequestReviewComment""" input UpdatePullRequestReviewCommentInput { """The Node ID of the comment to modify.""" pullRequestReviewCommentId: ID! """The text of the comment.""" body: String! """A unique identifier for the client performing the mutation.""" clientMutationId: String } """Autogenerated return type of UpdatePullRequestReviewComment""" type UpdatePullRequestReviewCommentPayload { """A unique identifier for the client performing the mutation.""" clientMutationId: String """The updated comment.""" pullRequestReviewComment: PullRequestReviewComment } """Autogenerated input type of UpdatePullRequestReview""" input UpdatePullRequestReviewInput { """The Node ID of the pull request review to modify.""" pullRequestReviewId: ID! """The contents of the pull request review body.""" body: String! """A unique identifier for the client performing the mutation.""" clientMutationId: String } """Autogenerated return type of UpdatePullRequestReview""" type UpdatePullRequestReviewPayload { """A unique identifier for the client performing the mutation.""" clientMutationId: String """The updated pull request review.""" pullRequestReview: PullRequestReview } """Autogenerated input type of UpdateSubscription""" input UpdateSubscriptionInput { """The Node ID of the subscribable object to modify.""" subscribableId: ID! """The new state of the subscription.""" state: SubscriptionState! """A unique identifier for the client performing the mutation.""" clientMutationId: String } """Autogenerated return type of UpdateSubscription""" type UpdateSubscriptionPayload { """A unique identifier for the client performing the mutation.""" clientMutationId: String """The input subscribable entity.""" subscribable: Subscribable } """Autogenerated input type of UpdateTopics""" input UpdateTopicsInput { """The Node ID of the repository.""" repositoryId: ID! """An array of topic names.""" topicNames: [String!]! """A unique identifier for the client performing the mutation.""" clientMutationId: String } """Autogenerated return type of UpdateTopics""" type UpdateTopicsPayload { """A unique identifier for the client performing the mutation.""" clientMutationId: String """Names of the provided topics that are not valid.""" invalidTopicNames: [String!] """The updated repository.""" repository: Repository } """An RFC 3986, RFC 3987, and RFC 6570 (level 4) compliant URI string.""" scalar URI """ A user is an individual's account on GitHub that owns repositories and can make new content. """ type User implements Node & Actor & RegistryPackageOwner & RegistryPackageSearch & ProjectOwner & RepositoryOwner & UniformResourceLocatable & ProfileOwner { """ Determine if this repository owner has any items that can be pinned to their profile. """ anyPinnableItems( """Filter to only a particular kind of pinnable item.""" type: PinnableItemType ): Boolean! """A URL pointing to the user's public avatar.""" avatarUrl( """The size of the resulting square image.""" size: Int ): URI! """The user's public profile bio.""" bio: String """The user's public profile bio as HTML.""" bioHTML: HTML! """A list of commit comments made by this user.""" commitComments( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): CommitCommentConnection! """The user's public profile company.""" company: String """The user's public profile company as HTML.""" companyHTML: HTML! """ The collection of contributions this user has made to different repositories. """ contributionsCollection( """The ID of the organization used to filter contributions.""" organizationID: ID """ Only contributions made at this time or later will be counted. If omitted, defaults to a year ago. """ from: DateTime """ Only contributions made before and up to and including this time will be counted. If omitted, defaults to the current time. """ to: DateTime ): ContributionsCollection! """Identifies the date and time when the object was created.""" createdAt: DateTime! """Identifies the primary key from the database.""" databaseId: Int """The user's publicly visible profile email.""" email: String! """A list of users the given user is followed by.""" followers( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): FollowerConnection! """A list of users the given user is following.""" following( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): FollowingConnection! """Find gist by repo name.""" gist( """The gist name to find.""" name: String! ): Gist """A list of gist comments made by this user.""" gistComments( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): GistCommentConnection! """A list of the Gists the user has created.""" gists( """Filters Gists according to privacy.""" privacy: GistPrivacy """Ordering options for gists returned from the connection""" orderBy: GistOrder """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): GistConnection! id: ID! """ Whether or not this user is a participant in the GitHub Security Bug Bounty. """ isBountyHunter: Boolean! """ Whether or not this user is a participant in the GitHub Campus Experts Program. """ isCampusExpert: Boolean! """Whether or not this user is a GitHub Developer Program member.""" isDeveloperProgramMember: Boolean! """Whether or not this user is a GitHub employee.""" isEmployee: Boolean! """Whether or not the user has marked themselves as for hire.""" isHireable: Boolean! """Whether or not this user is a site administrator.""" isSiteAdmin: Boolean! """Whether or not this user is the viewing user.""" isViewer: Boolean! """A list of issue comments made by this user.""" issueComments( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): IssueCommentConnection! """A list of issues associated with this user.""" issues( """Ordering options for issues returned from the connection.""" orderBy: IssueOrder """A list of label names to filter the pull requests by.""" labels: [String!] """A list of states to filter the issues by.""" states: [IssueState!] """Filtering options for issues returned from the connection.""" filterBy: IssueFilters """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): IssueConnection! """ Showcases a selection of repositories and gists that the profile owner has either curated or that have been selected automatically based on popularity. """ itemShowcase: ProfileItemShowcase! """The user's public profile location.""" location: String """The username used to login.""" login: String! """The user's public profile name.""" name: String """Find an organization by its login that the user belongs to.""" organization( """The login of the organization to find.""" login: String! ): Organization """A list of organizations the user belongs to.""" organizations( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): OrganizationConnection! """ A list of repositories and gists this profile owner can pin to their profile. """ pinnableItems( """Filter the types of pinnable items that are returned.""" types: [PinnableItemType!] """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): PinnableItemConnection! """ A list of repositories and gists this profile owner has pinned to their profile """ pinnedItems( """Filter the types of pinned items that are returned.""" types: [PinnableItemType!] """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): PinnableItemConnection! """ Returns how many more items this profile owner can pin to their profile. """ pinnedItemsRemaining: Int! """A list of repositories this user has pinned to their profile""" pinnedRepositories( """If non-null, filters repositories according to privacy""" privacy: RepositoryPrivacy """Ordering options for repositories returned from the connection""" orderBy: RepositoryOrder """ Array of viewer's affiliation options for repositories returned from the connection. For example, OWNER will include only repositories that the current viewer owns. """ affiliations: [RepositoryAffiliation] """ Array of owner's affiliation options for repositories returned from the connection. For example, OWNER will include only repositories that the organization or user being viewed owns. """ ownerAffiliations: [RepositoryAffiliation] """ If non-null, filters repositories according to whether they have been locked """ isLocked: Boolean """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): RepositoryConnection! @deprecated(reason: "pinnedRepositories will be removed Use ProfileOwner.pinnedItems instead. Removal on 2019-07-01 UTC.") """Find project by number.""" project( """The project number to find.""" number: Int! ): Project """A list of projects under the owner.""" projects( """Ordering options for projects returned from the connection""" orderBy: ProjectOrder """Query to search projects by, currently only searching by name.""" search: String """A list of states to filter the projects by.""" states: [ProjectState!] """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): ProjectConnection! """The HTTP path listing user's projects""" projectsResourcePath: URI! """The HTTP URL listing user's projects""" projectsUrl: URI! """A list of public keys associated with this user.""" publicKeys( """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): PublicKeyConnection! """A list of pull requests associated with this user.""" pullRequests( """A list of states to filter the pull requests by.""" states: [PullRequestState!] """A list of label names to filter the pull requests by.""" labels: [String!] """The head ref name to filter the pull requests by.""" headRefName: String """The base ref name to filter the pull requests by.""" baseRefName: String """Ordering options for pull requests returned from the connection.""" orderBy: IssueOrder """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): PullRequestConnection! """A list of repositories that the user owns.""" repositories( """If non-null, filters repositories according to privacy""" privacy: RepositoryPrivacy """Ordering options for repositories returned from the connection""" orderBy: RepositoryOrder """ Array of viewer's affiliation options for repositories returned from the connection. For example, OWNER will include only repositories that the current viewer owns. """ affiliations: [RepositoryAffiliation] """ Array of owner's affiliation options for repositories returned from the connection. For example, OWNER will include only repositories that the organization or user being viewed owns. """ ownerAffiliations: [RepositoryAffiliation] """ If non-null, filters repositories according to whether they have been locked """ isLocked: Boolean """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int """ If non-null, filters repositories according to whether they are forks of another repository """ isFork: Boolean ): RepositoryConnection! """A list of repositories that the user recently contributed to.""" repositoriesContributedTo( """If non-null, filters repositories according to privacy""" privacy: RepositoryPrivacy """Ordering options for repositories returned from the connection""" orderBy: RepositoryOrder """ If non-null, filters repositories according to whether they have been locked """ isLocked: Boolean """If true, include user repositories""" includeUserRepositories: Boolean """ If non-null, include only the specified types of contributions. The GitHub.com UI uses [COMMIT, ISSUE, PULL_REQUEST, REPOSITORY] """ contributionTypes: [RepositoryContributionType] """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): RepositoryConnection! """Find Repository.""" repository( """Name of Repository to find.""" name: String! ): Repository """The HTTP path for this user""" resourcePath: URI! """Repositories the user has starred.""" starredRepositories( """ Filters starred repositories to only return repositories owned by the viewer. """ ownedByViewer: Boolean """Order for connection""" orderBy: StarOrder """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): StarredRepositoryConnection! """The user's description of what they're currently doing.""" status: UserStatus """Identifies the date and time when the object was last updated.""" updatedAt: DateTime! """The HTTP URL for this user""" url: URI! """Can the viewer pin repositories and gists to the profile?""" viewerCanChangePinnedItems: Boolean! """Can the current viewer create new projects on this owner.""" viewerCanCreateProjects: Boolean! """Whether or not the viewer is able to follow the user.""" viewerCanFollow: Boolean! """Whether or not this user is followed by the viewer.""" viewerIsFollowing: Boolean! """A list of repositories the given user is watching.""" watching( """If non-null, filters repositories according to privacy""" privacy: RepositoryPrivacy """Ordering options for repositories returned from the connection""" orderBy: RepositoryOrder """Affiliation options for repositories returned from the connection""" affiliations: [RepositoryAffiliation] """ Array of owner's affiliation options for repositories returned from the connection. For example, OWNER will include only repositories that the organization or user being viewed owns. """ ownerAffiliations: [RepositoryAffiliation] """ If non-null, filters repositories according to whether they have been locked """ isLocked: Boolean """Returns the elements in the list that come after the specified cursor.""" after: String """ Returns the elements in the list that come before the specified cursor. """ before: String """Returns the first _n_ elements from the list.""" first: Int """Returns the last _n_ elements from the list.""" last: Int ): RepositoryConnection! """A URL pointing to the user's public website/blog.""" websiteUrl: URI } """The possible durations that a user can be blocked for.""" enum UserBlockDuration { """The user was blocked for 1 day""" ONE_DAY """The user was blocked for 3 days""" THREE_DAYS """The user was blocked for 7 days""" ONE_WEEK """The user was blocked for 30 days""" ONE_MONTH """The user was blocked permanently""" PERMANENT } """Represents a 'user_blocked' event on a given user.""" type UserBlockedEvent implements Node { """Identifies the actor who performed the event.""" actor: Actor """Number of days that the user was blocked for.""" blockDuration: UserBlockDuration! """Identifies the date and time when the object was created.""" createdAt: DateTime! id: ID! """The user who was blocked.""" subject: User } """The connection type for User.""" type UserConnection { """A list of edges.""" edges: [UserEdge] """A list of nodes.""" nodes: [User] """Information to aid in pagination.""" pageInfo: PageInfo! """Identifies the total count of items in the connection.""" totalCount: Int! } """An edit on user content""" type UserContentEdit implements Node { """Identifies the date and time when the object was created.""" createdAt: DateTime! """Identifies the date and time when the object was deleted.""" deletedAt: DateTime """The actor who deleted this content""" deletedBy: Actor """A summary of the changes for this edit""" diff: String """When this content was edited""" editedAt: DateTime! """The actor who edited this content""" editor: Actor id: ID! """Identifies the date and time when the object was last updated.""" updatedAt: DateTime! } """A list of edits to content.""" type UserContentEditConnection { """A list of edges.""" edges: [UserContentEditEdge] """A list of nodes.""" nodes: [UserContentEdit] """Information to aid in pagination.""" pageInfo: PageInfo! """Identifies the total count of items in the connection.""" totalCount: Int! } """An edge in a connection.""" type UserContentEditEdge { """A cursor for use in pagination.""" cursor: String! """The item at the end of the edge.""" node: UserContentEdit } """Represents a user.""" type UserEdge { """A cursor for use in pagination.""" cursor: String! """The item at the end of the edge.""" node: User } """The user's description of what they're currently doing.""" type UserStatus implements Node { """Identifies the date and time when the object was created.""" createdAt: DateTime! """An emoji summarizing the user's status.""" emoji: String """ID of the object.""" id: ID! """ Whether this status indicates the user is not fully available on GitHub. """ indicatesLimitedAvailability: Boolean! """A brief message describing what the user is doing.""" message: String """ The organization whose members can see this status. If null, this status is publicly visible. """ organization: Organization """Identifies the date and time when the object was last updated.""" updatedAt: DateTime! """The user who has this status.""" user: User! } """The connection type for UserStatus.""" type UserStatusConnection { """A list of edges.""" edges: [UserStatusEdge] """A list of nodes.""" nodes: [UserStatus] """Information to aid in pagination.""" pageInfo: PageInfo! """Identifies the total count of items in the connection.""" totalCount: Int! } """An edge in a connection.""" type UserStatusEdge { """A cursor for use in pagination.""" cursor: String! """The item at the end of the edge.""" node: UserStatus } """Ordering options for user status connections.""" input UserStatusOrder { """The field to order user statuses by.""" field: UserStatusOrderField! """The ordering direction.""" direction: OrderDirection! } """Properties by which user status connections can be ordered.""" enum UserStatusOrderField { """Order user statuses by when they were updated.""" UPDATED_AT } """A valid x509 certificate string""" scalar X509Certificate graphql-core-3.2.6/tests/fixtures/github_schema.json000066400000000000000000067567671474546154300226750ustar00rootroot00000000000000{ "data": { "__schema": { "queryType": { "name": "Query" }, "mutationType": { "name": "Mutation" }, "subscriptionType": null, "types": [ { "kind": "SCALAR", "name": "Boolean", "description": "Represents `true` or `false` values.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "SCALAR", "name": "String", "description": "Represents textual data as UTF-8 character sequences. This type is most often used by GraphQL to represent free-form human-readable text.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "Query", "description": "The query root of GitHub's GraphQL interface.", "fields": [ { "name": "codeOfConduct", "description": "Look up a code of conduct by its key", "args": [ { "name": "key", "description": "The code of conduct's key", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "CodeOfConduct", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "codesOfConduct", "description": "Look up a code of conduct by its key", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "CodeOfConduct", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "license", "description": "Look up an open source license by its key", "args": [ { "name": "key", "description": "The license's downcased SPDX ID", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "License", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "licenses", "description": "Return a list of known open source licenses", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "License", "ofType": null } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "marketplaceCategories", "description": "Get alphabetically sorted list of Marketplace categories", "args": [ { "name": "includeCategories", "description": "Return only the specified categories.", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } } }, "defaultValue": null }, { "name": "excludeEmpty", "description": "Exclude categories with no listings.", "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": null }, { "name": "excludeSubcategories", "description": "Returns top level categories only, excluding any subcategories.", "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "MarketplaceCategory", "ofType": null } } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "marketplaceCategory", "description": "Look up a Marketplace category by its slug.", "args": [ { "name": "slug", "description": "The URL slug of the category.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "defaultValue": null }, { "name": "useTopicAliases", "description": "Also check topic aliases for the category slug", "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "MarketplaceCategory", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "marketplaceListing", "description": "Look up a single Marketplace listing", "args": [ { "name": "slug", "description": "Select the listing that matches this slug. It's the short name of the listing used in its URL.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "MarketplaceListing", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "marketplaceListings", "description": "Look up Marketplace listings", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "categorySlug", "description": "Select only listings with the given category.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "useTopicAliases", "description": "Also check topic aliases for the category slug", "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": null }, { "name": "viewerCanAdmin", "description": "Select listings to which user has admin access. If omitted, listings visible to the\nviewer are returned.\n", "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": null }, { "name": "adminId", "description": "Select listings that can be administered by the specified user.", "type": { "kind": "SCALAR", "name": "ID", "ofType": null }, "defaultValue": null }, { "name": "organizationId", "description": "Select listings for products owned by the specified organization.", "type": { "kind": "SCALAR", "name": "ID", "ofType": null }, "defaultValue": null }, { "name": "allStates", "description": "Select listings visible to the viewer even if they are not approved. If omitted or\nfalse, only approved listings will be returned.\n", "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": null }, { "name": "slugs", "description": "Select the listings with these slugs, if they are visible to the viewer.", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "defaultValue": null }, { "name": "primaryCategoryOnly", "description": "Select only listings where the primary category matches the given category slug.", "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": "false" }, { "name": "withFreeTrialsOnly", "description": "Select only listings that offer a free trial.", "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": "false" } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "MarketplaceListingConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "meta", "description": "Return information about the GitHub instance", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "GitHubMetadata", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "node", "description": "Fetches an object given its ID.", "args": [ { "name": "id", "description": "ID of the object.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "INTERFACE", "name": "Node", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "nodes", "description": "Lookup nodes by a list of IDs.", "args": [ { "name": "ids", "description": "The list of node IDs.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } } } }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "LIST", "name": null, "ofType": { "kind": "INTERFACE", "name": "Node", "ofType": null } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "organization", "description": "Lookup a organization by login.", "args": [ { "name": "login", "description": "The organization's login.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "Organization", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "rateLimit", "description": "The client's rate limit information.", "args": [ { "name": "dryRun", "description": "If true, calculate the cost for the query without evaluating it", "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": "false" } ], "type": { "kind": "OBJECT", "name": "RateLimit", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "relay", "description": "Hack to workaround https://github.com/facebook/relay/issues/112 re-exposing the root query object", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "Query", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "repository", "description": "Lookup a given repository by the owner and repository name.", "args": [ { "name": "owner", "description": "The login field of a user or organization", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "defaultValue": null }, { "name": "name", "description": "The name of the repository", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "Repository", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "repositoryOwner", "description": "Lookup a repository owner (ie. either a User or an Organization) by login.", "args": [ { "name": "login", "description": "The username to lookup the owner by.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "INTERFACE", "name": "RepositoryOwner", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "resource", "description": "Lookup resource by a URL.", "args": [ { "name": "url", "description": "The URL.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "INTERFACE", "name": "UniformResourceLocatable", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "search", "description": "Perform a search across resources.", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "query", "description": "The search string to look for.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "defaultValue": null }, { "name": "type", "description": "The types of search items to search within.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "SearchType", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "SearchResultItemConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "securityAdvisories", "description": "GitHub Security Advisories", "args": [ { "name": "orderBy", "description": "Ordering options for the returned topics.", "type": { "kind": "INPUT_OBJECT", "name": "SecurityAdvisoryOrder", "ofType": null }, "defaultValue": "{field:\"UPDATED_AT\",direction:\"DESC\"}" }, { "name": "identifier", "description": "Filter advisories by identifier, e.g. GHSA or CVE.", "type": { "kind": "INPUT_OBJECT", "name": "SecurityAdvisoryIdentifierFilter", "ofType": null }, "defaultValue": null }, { "name": "publishedSince", "description": "Filter advisories to those published since a time in the past.", "type": { "kind": "SCALAR", "name": "DateTime", "ofType": null }, "defaultValue": null }, { "name": "updatedSince", "description": "Filter advisories to those updated since a time in the past.", "type": { "kind": "SCALAR", "name": "DateTime", "ofType": null }, "defaultValue": null }, { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "SecurityAdvisoryConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "securityAdvisory", "description": "Fetch a Security Advisory by its GHSA ID", "args": [ { "name": "ghsaId", "description": "GitHub Security Advisory ID.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "SecurityAdvisory", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "securityVulnerabilities", "description": "Software Vulnerabilities documented by GitHub Security Advisories", "args": [ { "name": "orderBy", "description": "Ordering options for the returned topics.", "type": { "kind": "INPUT_OBJECT", "name": "SecurityVulnerabilityOrder", "ofType": null }, "defaultValue": "{field:\"UPDATED_AT\",direction:\"DESC\"}" }, { "name": "ecosystem", "description": "An ecosystem to filter vulnerabilities by.", "type": { "kind": "ENUM", "name": "SecurityAdvisoryEcosystem", "ofType": null }, "defaultValue": null }, { "name": "package", "description": "A package name to filter vulnerabilities by.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "severities", "description": "A list of severities to filter vulnerabilities by.", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "SecurityAdvisorySeverity", "ofType": null } } }, "defaultValue": null }, { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "SecurityVulnerabilityConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "topic", "description": "Look up a topic by name.", "args": [ { "name": "name", "description": "The topic's name.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "Topic", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "user", "description": "Lookup a user by login.", "args": [ { "name": "login", "description": "The user's login.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "User", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewer", "description": "The currently authenticated user.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "User", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "INTERFACE", "name": "Node", "description": "An object with an ID.", "fields": [ { "name": "id", "description": "ID of the object.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": [ { "kind": "OBJECT", "name": "AddedToProjectEvent", "ofType": null }, { "kind": "OBJECT", "name": "App", "ofType": null }, { "kind": "OBJECT", "name": "AssignedEvent", "ofType": null }, { "kind": "OBJECT", "name": "BaseRefChangedEvent", "ofType": null }, { "kind": "OBJECT", "name": "BaseRefForcePushedEvent", "ofType": null }, { "kind": "OBJECT", "name": "Blob", "ofType": null }, { "kind": "OBJECT", "name": "Bot", "ofType": null }, { "kind": "OBJECT", "name": "BranchProtectionRule", "ofType": null }, { "kind": "OBJECT", "name": "ClosedEvent", "ofType": null }, { "kind": "OBJECT", "name": "CodeOfConduct", "ofType": null }, { "kind": "OBJECT", "name": "CommentDeletedEvent", "ofType": null }, { "kind": "OBJECT", "name": "Commit", "ofType": null }, { "kind": "OBJECT", "name": "CommitComment", "ofType": null }, { "kind": "OBJECT", "name": "CommitCommentThread", "ofType": null }, { "kind": "OBJECT", "name": "ConvertedNoteToIssueEvent", "ofType": null }, { "kind": "OBJECT", "name": "CrossReferencedEvent", "ofType": null }, { "kind": "OBJECT", "name": "DemilestonedEvent", "ofType": null }, { "kind": "OBJECT", "name": "DeployKey", "ofType": null }, { "kind": "OBJECT", "name": "DeployedEvent", "ofType": null }, { "kind": "OBJECT", "name": "Deployment", "ofType": null }, { "kind": "OBJECT", "name": "DeploymentEnvironmentChangedEvent", "ofType": null }, { "kind": "OBJECT", "name": "DeploymentStatus", "ofType": null }, { "kind": "OBJECT", "name": "ExternalIdentity", "ofType": null }, { "kind": "OBJECT", "name": "Gist", "ofType": null }, { "kind": "OBJECT", "name": "GistComment", "ofType": null }, { "kind": "OBJECT", "name": "HeadRefDeletedEvent", "ofType": null }, { "kind": "OBJECT", "name": "HeadRefForcePushedEvent", "ofType": null }, { "kind": "OBJECT", "name": "HeadRefRestoredEvent", "ofType": null }, { "kind": "OBJECT", "name": "Issue", "ofType": null }, { "kind": "OBJECT", "name": "IssueComment", "ofType": null }, { "kind": "OBJECT", "name": "Label", "ofType": null }, { "kind": "OBJECT", "name": "LabeledEvent", "ofType": null }, { "kind": "OBJECT", "name": "Language", "ofType": null }, { "kind": "OBJECT", "name": "License", "ofType": null }, { "kind": "OBJECT", "name": "LockedEvent", "ofType": null }, { "kind": "OBJECT", "name": "Mannequin", "ofType": null }, { "kind": "OBJECT", "name": "MarketplaceCategory", "ofType": null }, { "kind": "OBJECT", "name": "MarketplaceListing", "ofType": null }, { "kind": "OBJECT", "name": "MentionedEvent", "ofType": null }, { "kind": "OBJECT", "name": "MergedEvent", "ofType": null }, { "kind": "OBJECT", "name": "Milestone", "ofType": null }, { "kind": "OBJECT", "name": "MilestonedEvent", "ofType": null }, { "kind": "OBJECT", "name": "MovedColumnsInProjectEvent", "ofType": null }, { "kind": "OBJECT", "name": "Organization", "ofType": null }, { "kind": "OBJECT", "name": "OrganizationIdentityProvider", "ofType": null }, { "kind": "OBJECT", "name": "OrganizationInvitation", "ofType": null }, { "kind": "OBJECT", "name": "PinnedEvent", "ofType": null }, { "kind": "OBJECT", "name": "Project", "ofType": null }, { "kind": "OBJECT", "name": "ProjectCard", "ofType": null }, { "kind": "OBJECT", "name": "ProjectColumn", "ofType": null }, { "kind": "OBJECT", "name": "PublicKey", "ofType": null }, { "kind": "OBJECT", "name": "PullRequest", "ofType": null }, { "kind": "OBJECT", "name": "PullRequestCommit", "ofType": null }, { "kind": "OBJECT", "name": "PullRequestCommitCommentThread", "ofType": null }, { "kind": "OBJECT", "name": "PullRequestReview", "ofType": null }, { "kind": "OBJECT", "name": "PullRequestReviewComment", "ofType": null }, { "kind": "OBJECT", "name": "PullRequestReviewThread", "ofType": null }, { "kind": "OBJECT", "name": "PushAllowance", "ofType": null }, { "kind": "OBJECT", "name": "Reaction", "ofType": null }, { "kind": "OBJECT", "name": "Ref", "ofType": null }, { "kind": "OBJECT", "name": "ReferencedEvent", "ofType": null }, { "kind": "OBJECT", "name": "Release", "ofType": null }, { "kind": "OBJECT", "name": "ReleaseAsset", "ofType": null }, { "kind": "OBJECT", "name": "RemovedFromProjectEvent", "ofType": null }, { "kind": "OBJECT", "name": "RenamedTitleEvent", "ofType": null }, { "kind": "OBJECT", "name": "ReopenedEvent", "ofType": null }, { "kind": "OBJECT", "name": "Repository", "ofType": null }, { "kind": "OBJECT", "name": "RepositoryInvitation", "ofType": null }, { "kind": "OBJECT", "name": "RepositoryTopic", "ofType": null }, { "kind": "OBJECT", "name": "ReviewDismissalAllowance", "ofType": null }, { "kind": "OBJECT", "name": "ReviewDismissedEvent", "ofType": null }, { "kind": "OBJECT", "name": "ReviewRequest", "ofType": null }, { "kind": "OBJECT", "name": "ReviewRequestRemovedEvent", "ofType": null }, { "kind": "OBJECT", "name": "ReviewRequestedEvent", "ofType": null }, { "kind": "OBJECT", "name": "SecurityAdvisory", "ofType": null }, { "kind": "OBJECT", "name": "Status", "ofType": null }, { "kind": "OBJECT", "name": "StatusContext", "ofType": null }, { "kind": "OBJECT", "name": "SubscribedEvent", "ofType": null }, { "kind": "OBJECT", "name": "Tag", "ofType": null }, { "kind": "OBJECT", "name": "Team", "ofType": null }, { "kind": "OBJECT", "name": "Topic", "ofType": null }, { "kind": "OBJECT", "name": "TransferredEvent", "ofType": null }, { "kind": "OBJECT", "name": "Tree", "ofType": null }, { "kind": "OBJECT", "name": "UnassignedEvent", "ofType": null }, { "kind": "OBJECT", "name": "UnlabeledEvent", "ofType": null }, { "kind": "OBJECT", "name": "UnlockedEvent", "ofType": null }, { "kind": "OBJECT", "name": "UnpinnedEvent", "ofType": null }, { "kind": "OBJECT", "name": "UnsubscribedEvent", "ofType": null }, { "kind": "OBJECT", "name": "User", "ofType": null }, { "kind": "OBJECT", "name": "UserBlockedEvent", "ofType": null }, { "kind": "OBJECT", "name": "UserContentEdit", "ofType": null }, { "kind": "OBJECT", "name": "UserStatus", "ofType": null } ] }, { "kind": "SCALAR", "name": "ID", "description": "Represents a unique identifier that is Base64 obfuscated. It is often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as `\"VXNlci0xMA==\"`) or integer (such as `4`) input value will be accepted as an ID.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "INTERFACE", "name": "UniformResourceLocatable", "description": "Represents a type that can be retrieved by a URL.", "fields": [ { "name": "resourcePath", "description": "The HTML path to this resource.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "url", "description": "The URL to this resource.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": [ { "kind": "OBJECT", "name": "Bot", "ofType": null }, { "kind": "OBJECT", "name": "ClosedEvent", "ofType": null }, { "kind": "OBJECT", "name": "Commit", "ofType": null }, { "kind": "OBJECT", "name": "CrossReferencedEvent", "ofType": null }, { "kind": "OBJECT", "name": "Issue", "ofType": null }, { "kind": "OBJECT", "name": "Mannequin", "ofType": null }, { "kind": "OBJECT", "name": "MergedEvent", "ofType": null }, { "kind": "OBJECT", "name": "Milestone", "ofType": null }, { "kind": "OBJECT", "name": "Organization", "ofType": null }, { "kind": "OBJECT", "name": "PullRequest", "ofType": null }, { "kind": "OBJECT", "name": "PullRequestCommit", "ofType": null }, { "kind": "OBJECT", "name": "Release", "ofType": null }, { "kind": "OBJECT", "name": "Repository", "ofType": null }, { "kind": "OBJECT", "name": "RepositoryTopic", "ofType": null }, { "kind": "OBJECT", "name": "ReviewDismissedEvent", "ofType": null }, { "kind": "OBJECT", "name": "User", "ofType": null } ] }, { "kind": "SCALAR", "name": "URI", "description": "An RFC 3986, RFC 3987, and RFC 6570 (level 4) compliant URI string.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "User", "description": "A user is an individual's account on GitHub that owns repositories and can make new content.", "fields": [ { "name": "anyPinnableItems", "description": "Determine if this repository owner has any items that can be pinned to their profile.", "args": [ { "name": "type", "description": "Filter to only a particular kind of pinnable item.", "type": { "kind": "ENUM", "name": "PinnableItemType", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "avatarUrl", "description": "A URL pointing to the user's public avatar.", "args": [ { "name": "size", "description": "The size of the resulting square image.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "bio", "description": "The user's public profile bio.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "bioHTML", "description": "The user's public profile bio as HTML.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "HTML", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "commitComments", "description": "A list of commit comments made by this user.", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "CommitCommentConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "company", "description": "The user's public profile company.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "companyHTML", "description": "The user's public profile company as HTML.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "HTML", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "contributionsCollection", "description": "The collection of contributions this user has made to different repositories.", "args": [ { "name": "organizationID", "description": "The ID of the organization used to filter contributions.", "type": { "kind": "SCALAR", "name": "ID", "ofType": null }, "defaultValue": null }, { "name": "from", "description": "Only contributions made at this time or later will be counted. If omitted, defaults to a year ago.", "type": { "kind": "SCALAR", "name": "DateTime", "ofType": null }, "defaultValue": null }, { "name": "to", "description": "Only contributions made before and up to and including this time will be counted. If omitted, defaults to the current time.", "type": { "kind": "SCALAR", "name": "DateTime", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "ContributionsCollection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "createdAt", "description": "Identifies the date and time when the object was created.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "databaseId", "description": "Identifies the primary key from the database.", "args": [], "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "email", "description": "The user's publicly visible profile email.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "followers", "description": "A list of users the given user is followed by.", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "FollowerConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "following", "description": "A list of users the given user is following.", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "FollowingConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "gist", "description": "Find gist by repo name.", "args": [ { "name": "name", "description": "The gist name to find.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "Gist", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "gistComments", "description": "A list of gist comments made by this user.", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "GistCommentConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "gists", "description": "A list of the Gists the user has created.", "args": [ { "name": "privacy", "description": "Filters Gists according to privacy.", "type": { "kind": "ENUM", "name": "GistPrivacy", "ofType": null }, "defaultValue": null }, { "name": "orderBy", "description": "Ordering options for gists returned from the connection", "type": { "kind": "INPUT_OBJECT", "name": "GistOrder", "ofType": null }, "defaultValue": null }, { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "GistConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "isBountyHunter", "description": "Whether or not this user is a participant in the GitHub Security Bug Bounty.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "isCampusExpert", "description": "Whether or not this user is a participant in the GitHub Campus Experts Program.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "isDeveloperProgramMember", "description": "Whether or not this user is a GitHub Developer Program member.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "isEmployee", "description": "Whether or not this user is a GitHub employee.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "isHireable", "description": "Whether or not the user has marked themselves as for hire.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "isSiteAdmin", "description": "Whether or not this user is a site administrator.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "isViewer", "description": "Whether or not this user is the viewing user.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "issueComments", "description": "A list of issue comments made by this user.", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "IssueCommentConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "issues", "description": "A list of issues associated with this user.", "args": [ { "name": "orderBy", "description": "Ordering options for issues returned from the connection.", "type": { "kind": "INPUT_OBJECT", "name": "IssueOrder", "ofType": null }, "defaultValue": null }, { "name": "labels", "description": "A list of label names to filter the pull requests by.", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } } }, "defaultValue": null }, { "name": "states", "description": "A list of states to filter the issues by.", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "IssueState", "ofType": null } } }, "defaultValue": null }, { "name": "filterBy", "description": "Filtering options for issues returned from the connection.", "type": { "kind": "INPUT_OBJECT", "name": "IssueFilters", "ofType": null }, "defaultValue": null }, { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "IssueConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "itemShowcase", "description": "Showcases a selection of repositories and gists that the profile owner has either curated or that have been selected automatically based on popularity.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "ProfileItemShowcase", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "location", "description": "The user's public profile location.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "login", "description": "The username used to login.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "name", "description": "The user's public profile name.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "organization", "description": "Find an organization by its login that the user belongs to.", "args": [ { "name": "login", "description": "The login of the organization to find.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "Organization", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "organizations", "description": "A list of organizations the user belongs to.", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "OrganizationConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pinnableItems", "description": "A list of repositories and gists this profile owner can pin to their profile.", "args": [ { "name": "types", "description": "Filter the types of pinnable items that are returned.", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "PinnableItemType", "ofType": null } } }, "defaultValue": null }, { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PinnableItemConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pinnedItems", "description": "A list of repositories and gists this profile owner has pinned to their profile", "args": [ { "name": "types", "description": "Filter the types of pinned items that are returned.", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "PinnableItemType", "ofType": null } } }, "defaultValue": null }, { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PinnableItemConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pinnedItemsRemaining", "description": "Returns how many more items this profile owner can pin to their profile.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pinnedRepositories", "description": "A list of repositories this user has pinned to their profile", "args": [ { "name": "privacy", "description": "If non-null, filters repositories according to privacy", "type": { "kind": "ENUM", "name": "RepositoryPrivacy", "ofType": null }, "defaultValue": null }, { "name": "orderBy", "description": "Ordering options for repositories returned from the connection", "type": { "kind": "INPUT_OBJECT", "name": "RepositoryOrder", "ofType": null }, "defaultValue": null }, { "name": "affiliations", "description": "Array of viewer's affiliation options for repositories returned from the connection. For example, OWNER will include only repositories that the current viewer owns.", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "ENUM", "name": "RepositoryAffiliation", "ofType": null } }, "defaultValue": "[\"OWNER\", \"COLLABORATOR\"]" }, { "name": "ownerAffiliations", "description": "Array of owner's affiliation options for repositories returned from the connection. For example, OWNER will include only repositories that the organization or user being viewed owns.", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "ENUM", "name": "RepositoryAffiliation", "ofType": null } }, "defaultValue": "[\"OWNER\", \"COLLABORATOR\"]" }, { "name": "isLocked", "description": "If non-null, filters repositories according to whether they have been locked", "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": null }, { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "RepositoryConnection", "ofType": null } }, "isDeprecated": true, "deprecationReason": "pinnedRepositories will be removed Use ProfileOwner.pinnedItems instead. Removal on 2019-07-01 UTC." }, { "name": "project", "description": "Find project by number.", "args": [ { "name": "number", "description": "The project number to find.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "Project", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "projects", "description": "A list of projects under the owner.", "args": [ { "name": "orderBy", "description": "Ordering options for projects returned from the connection", "type": { "kind": "INPUT_OBJECT", "name": "ProjectOrder", "ofType": null }, "defaultValue": null }, { "name": "search", "description": "Query to search projects by, currently only searching by name.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "states", "description": "A list of states to filter the projects by.", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "ProjectState", "ofType": null } } }, "defaultValue": null }, { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "ProjectConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "projectsResourcePath", "description": "The HTTP path listing user's projects", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "projectsUrl", "description": "The HTTP URL listing user's projects", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "publicKeys", "description": "A list of public keys associated with this user.", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PublicKeyConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pullRequests", "description": "A list of pull requests associated with this user.", "args": [ { "name": "states", "description": "A list of states to filter the pull requests by.", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "PullRequestState", "ofType": null } } }, "defaultValue": null }, { "name": "labels", "description": "A list of label names to filter the pull requests by.", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } } }, "defaultValue": null }, { "name": "headRefName", "description": "The head ref name to filter the pull requests by.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "baseRefName", "description": "The base ref name to filter the pull requests by.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "orderBy", "description": "Ordering options for pull requests returned from the connection.", "type": { "kind": "INPUT_OBJECT", "name": "IssueOrder", "ofType": null }, "defaultValue": null }, { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PullRequestConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "repositories", "description": "A list of repositories that the user owns.", "args": [ { "name": "privacy", "description": "If non-null, filters repositories according to privacy", "type": { "kind": "ENUM", "name": "RepositoryPrivacy", "ofType": null }, "defaultValue": null }, { "name": "orderBy", "description": "Ordering options for repositories returned from the connection", "type": { "kind": "INPUT_OBJECT", "name": "RepositoryOrder", "ofType": null }, "defaultValue": null }, { "name": "affiliations", "description": "Array of viewer's affiliation options for repositories returned from the connection. For example, OWNER will include only repositories that the current viewer owns.", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "ENUM", "name": "RepositoryAffiliation", "ofType": null } }, "defaultValue": "[\"OWNER\", \"COLLABORATOR\"]" }, { "name": "ownerAffiliations", "description": "Array of owner's affiliation options for repositories returned from the connection. For example, OWNER will include only repositories that the organization or user being viewed owns.", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "ENUM", "name": "RepositoryAffiliation", "ofType": null } }, "defaultValue": "[\"OWNER\", \"COLLABORATOR\"]" }, { "name": "isLocked", "description": "If non-null, filters repositories according to whether they have been locked", "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": null }, { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "isFork", "description": "If non-null, filters repositories according to whether they are forks of another repository", "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "RepositoryConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "repositoriesContributedTo", "description": "A list of repositories that the user recently contributed to.", "args": [ { "name": "privacy", "description": "If non-null, filters repositories according to privacy", "type": { "kind": "ENUM", "name": "RepositoryPrivacy", "ofType": null }, "defaultValue": null }, { "name": "orderBy", "description": "Ordering options for repositories returned from the connection", "type": { "kind": "INPUT_OBJECT", "name": "RepositoryOrder", "ofType": null }, "defaultValue": null }, { "name": "isLocked", "description": "If non-null, filters repositories according to whether they have been locked", "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": null }, { "name": "includeUserRepositories", "description": "If true, include user repositories", "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": null }, { "name": "contributionTypes", "description": "If non-null, include only the specified types of contributions. The GitHub.com UI uses [COMMIT, ISSUE, PULL_REQUEST, REPOSITORY]", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "ENUM", "name": "RepositoryContributionType", "ofType": null } }, "defaultValue": null }, { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "RepositoryConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "repository", "description": "Find Repository.", "args": [ { "name": "name", "description": "Name of Repository to find.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "Repository", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "resourcePath", "description": "The HTTP path for this user", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "starredRepositories", "description": "Repositories the user has starred.", "args": [ { "name": "ownedByViewer", "description": "Filters starred repositories to only return repositories owned by the viewer.", "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": null }, { "name": "orderBy", "description": "Order for connection", "type": { "kind": "INPUT_OBJECT", "name": "StarOrder", "ofType": null }, "defaultValue": null }, { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "StarredRepositoryConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "status", "description": "The user's description of what they're currently doing.", "args": [], "type": { "kind": "OBJECT", "name": "UserStatus", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "updatedAt", "description": "Identifies the date and time when the object was last updated.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "url", "description": "The HTTP URL for this user", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerCanChangePinnedItems", "description": "Can the viewer pin repositories and gists to the profile?", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerCanCreateProjects", "description": "Can the current viewer create new projects on this owner.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerCanFollow", "description": "Whether or not the viewer is able to follow the user.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerIsFollowing", "description": "Whether or not this user is followed by the viewer.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "watching", "description": "A list of repositories the given user is watching.", "args": [ { "name": "privacy", "description": "If non-null, filters repositories according to privacy", "type": { "kind": "ENUM", "name": "RepositoryPrivacy", "ofType": null }, "defaultValue": null }, { "name": "orderBy", "description": "Ordering options for repositories returned from the connection", "type": { "kind": "INPUT_OBJECT", "name": "RepositoryOrder", "ofType": null }, "defaultValue": null }, { "name": "affiliations", "description": "Affiliation options for repositories returned from the connection", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "ENUM", "name": "RepositoryAffiliation", "ofType": null } }, "defaultValue": "[\"OWNER\", \"COLLABORATOR\", \"ORGANIZATION_MEMBER\"]" }, { "name": "ownerAffiliations", "description": "Array of owner's affiliation options for repositories returned from the connection. For example, OWNER will include only repositories that the organization or user being viewed owns.", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "ENUM", "name": "RepositoryAffiliation", "ofType": null } }, "defaultValue": "[\"OWNER\", \"COLLABORATOR\"]" }, { "name": "isLocked", "description": "If non-null, filters repositories according to whether they have been locked", "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": null }, { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "RepositoryConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "websiteUrl", "description": "A URL pointing to the user's public website/blog.", "args": [], "type": { "kind": "SCALAR", "name": "URI", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null }, { "kind": "INTERFACE", "name": "Actor", "ofType": null }, { "kind": "INTERFACE", "name": "RegistryPackageOwner", "ofType": null }, { "kind": "INTERFACE", "name": "RegistryPackageSearch", "ofType": null }, { "kind": "INTERFACE", "name": "ProjectOwner", "ofType": null }, { "kind": "INTERFACE", "name": "RepositoryOwner", "ofType": null }, { "kind": "INTERFACE", "name": "UniformResourceLocatable", "ofType": null }, { "kind": "INTERFACE", "name": "ProfileOwner", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "INTERFACE", "name": "Actor", "description": "Represents an object which can take actions on GitHub. Typically a User or Bot.", "fields": [ { "name": "avatarUrl", "description": "A URL pointing to the actor's public avatar.", "args": [ { "name": "size", "description": "The size of the resulting square image.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "login", "description": "The username of the actor.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "resourcePath", "description": "The HTTP path for this actor.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "url", "description": "The HTTP URL for this actor.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": [ { "kind": "OBJECT", "name": "Bot", "ofType": null }, { "kind": "OBJECT", "name": "Mannequin", "ofType": null }, { "kind": "OBJECT", "name": "Organization", "ofType": null }, { "kind": "OBJECT", "name": "User", "ofType": null } ] }, { "kind": "SCALAR", "name": "Int", "description": "Represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "PageInfo", "description": "Information about pagination in a connection.", "fields": [ { "name": "endCursor", "description": "When paginating forwards, the cursor to continue.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "hasNextPage", "description": "When paginating forwards, are there more items?", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "hasPreviousPage", "description": "When paginating backwards, are there more items?", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "startCursor", "description": "When paginating backwards, the cursor to continue.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "SCALAR", "name": "DateTime", "description": "An ISO-8601 encoded UTC date string.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "INTERFACE", "name": "RegistryPackageOwner", "description": "Represents an owner of a registry package.", "fields": [ { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": [ { "kind": "OBJECT", "name": "Organization", "ofType": null }, { "kind": "OBJECT", "name": "Repository", "ofType": null }, { "kind": "OBJECT", "name": "User", "ofType": null } ] }, { "kind": "OBJECT", "name": "Repository", "description": "A repository contains the content for a project.", "fields": [ { "name": "assignableUsers", "description": "A list of users that can be assigned to issues in this repository.", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "UserConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "branchProtectionRules", "description": "A list of branch protection rules for this repository.", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "BranchProtectionRuleConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "codeOfConduct", "description": "Returns the code of conduct for this repository", "args": [], "type": { "kind": "OBJECT", "name": "CodeOfConduct", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "collaborators", "description": "A list of collaborators associated with the repository.", "args": [ { "name": "affiliation", "description": "Collaborators affiliation level with a repository.", "type": { "kind": "ENUM", "name": "CollaboratorAffiliation", "ofType": null }, "defaultValue": null }, { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "RepositoryCollaboratorConnection", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "commitComments", "description": "A list of commit comments associated with the repository.", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "CommitCommentConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "createdAt", "description": "Identifies the date and time when the object was created.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "databaseId", "description": "Identifies the primary key from the database.", "args": [], "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "defaultBranchRef", "description": "The Ref associated with the repository's default branch.", "args": [], "type": { "kind": "OBJECT", "name": "Ref", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "deployKeys", "description": "A list of deploy keys that are on this repository.", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "DeployKeyConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "deployments", "description": "Deployments associated with the repository", "args": [ { "name": "environments", "description": "Environments to list deployments for", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } } }, "defaultValue": null }, { "name": "orderBy", "description": "Ordering options for deployments returned from the connection.", "type": { "kind": "INPUT_OBJECT", "name": "DeploymentOrder", "ofType": null }, "defaultValue": "{field:\"CREATED_AT\",direction:\"ASC\"}" }, { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "DeploymentConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "description", "description": "The description of the repository.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "descriptionHTML", "description": "The description of the repository rendered to HTML.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "HTML", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "diskUsage", "description": "The number of kilobytes this repository occupies on disk.", "args": [], "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "forkCount", "description": "Returns how many forks there are of this repository in the whole network.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "forks", "description": "A list of direct forked repositories.", "args": [ { "name": "privacy", "description": "If non-null, filters repositories according to privacy", "type": { "kind": "ENUM", "name": "RepositoryPrivacy", "ofType": null }, "defaultValue": null }, { "name": "orderBy", "description": "Ordering options for repositories returned from the connection", "type": { "kind": "INPUT_OBJECT", "name": "RepositoryOrder", "ofType": null }, "defaultValue": null }, { "name": "affiliations", "description": "Array of viewer's affiliation options for repositories returned from the connection. For example, OWNER will include only repositories that the current viewer owns.", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "ENUM", "name": "RepositoryAffiliation", "ofType": null } }, "defaultValue": "[\"OWNER\", \"COLLABORATOR\"]" }, { "name": "ownerAffiliations", "description": "Array of owner's affiliation options for repositories returned from the connection. For example, OWNER will include only repositories that the organization or user being viewed owns.", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "ENUM", "name": "RepositoryAffiliation", "ofType": null } }, "defaultValue": "[\"OWNER\", \"COLLABORATOR\"]" }, { "name": "isLocked", "description": "If non-null, filters repositories according to whether they have been locked", "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": null }, { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "RepositoryConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "hasIssuesEnabled", "description": "Indicates if the repository has issues feature enabled.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "hasWikiEnabled", "description": "Indicates if the repository has wiki feature enabled.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "homepageUrl", "description": "The repository's URL.", "args": [], "type": { "kind": "SCALAR", "name": "URI", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "isArchived", "description": "Indicates if the repository is unmaintained.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "isDisabled", "description": "Returns whether or not this repository disabled.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "isFork", "description": "Identifies if the repository is a fork.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "isLocked", "description": "Indicates if the repository has been locked or not.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "isMirror", "description": "Identifies if the repository is a mirror.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "isPrivate", "description": "Identifies if the repository is private.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "issue", "description": "Returns a single issue from the current repository by number.", "args": [ { "name": "number", "description": "The number for the issue to be returned.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "Issue", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "issueOrPullRequest", "description": "Returns a single issue-like object from the current repository by number.", "args": [ { "name": "number", "description": "The number for the issue to be returned.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "UNION", "name": "IssueOrPullRequest", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "issues", "description": "A list of issues that have been opened in the repository.", "args": [ { "name": "orderBy", "description": "Ordering options for issues returned from the connection.", "type": { "kind": "INPUT_OBJECT", "name": "IssueOrder", "ofType": null }, "defaultValue": null }, { "name": "labels", "description": "A list of label names to filter the pull requests by.", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } } }, "defaultValue": null }, { "name": "states", "description": "A list of states to filter the issues by.", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "IssueState", "ofType": null } } }, "defaultValue": null }, { "name": "filterBy", "description": "Filtering options for issues returned from the connection.", "type": { "kind": "INPUT_OBJECT", "name": "IssueFilters", "ofType": null }, "defaultValue": null }, { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "IssueConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "label", "description": "Returns a single label by name", "args": [ { "name": "name", "description": "Label name", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "Label", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "labels", "description": "A list of labels associated with the repository.", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "query", "description": "If provided, searches labels by name and description.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "LabelConnection", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "languages", "description": "A list containing a breakdown of the language composition of the repository.", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "orderBy", "description": "Order for connection", "type": { "kind": "INPUT_OBJECT", "name": "LanguageOrder", "ofType": null }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "LanguageConnection", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "licenseInfo", "description": "The license associated with the repository", "args": [], "type": { "kind": "OBJECT", "name": "License", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "lockReason", "description": "The reason the repository has been locked.", "args": [], "type": { "kind": "ENUM", "name": "RepositoryLockReason", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "mentionableUsers", "description": "A list of Users that can be mentioned in the context of the repository.", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "UserConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "mergeCommitAllowed", "description": "Whether or not PRs are merged with a merge commit on this repository.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "milestone", "description": "Returns a single milestone from the current repository by number.", "args": [ { "name": "number", "description": "The number for the milestone to be returned.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "Milestone", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "milestones", "description": "A list of milestones associated with the repository.", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "states", "description": "Filter by the state of the milestones.", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "MilestoneState", "ofType": null } } }, "defaultValue": null }, { "name": "orderBy", "description": "Ordering options for milestones.", "type": { "kind": "INPUT_OBJECT", "name": "MilestoneOrder", "ofType": null }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "MilestoneConnection", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "mirrorUrl", "description": "The repository's original mirror URL.", "args": [], "type": { "kind": "SCALAR", "name": "URI", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "name", "description": "The name of the repository.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "nameWithOwner", "description": "The repository's name with owner.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "object", "description": "A Git object in the repository", "args": [ { "name": "oid", "description": "The Git object ID", "type": { "kind": "SCALAR", "name": "GitObjectID", "ofType": null }, "defaultValue": null }, { "name": "expression", "description": "A Git revision expression suitable for rev-parse", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null } ], "type": { "kind": "INTERFACE", "name": "GitObject", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "owner", "description": "The User owner of the repository.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INTERFACE", "name": "RepositoryOwner", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "parent", "description": "The repository parent, if this is a fork.", "args": [], "type": { "kind": "OBJECT", "name": "Repository", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "primaryLanguage", "description": "The primary language of the repository's code.", "args": [], "type": { "kind": "OBJECT", "name": "Language", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "project", "description": "Find project by number.", "args": [ { "name": "number", "description": "The project number to find.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "Project", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "projects", "description": "A list of projects under the owner.", "args": [ { "name": "orderBy", "description": "Ordering options for projects returned from the connection", "type": { "kind": "INPUT_OBJECT", "name": "ProjectOrder", "ofType": null }, "defaultValue": null }, { "name": "search", "description": "Query to search projects by, currently only searching by name.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "states", "description": "A list of states to filter the projects by.", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "ProjectState", "ofType": null } } }, "defaultValue": null }, { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "ProjectConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "projectsResourcePath", "description": "The HTTP path listing the repository's projects", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "projectsUrl", "description": "The HTTP URL listing the repository's projects", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pullRequest", "description": "Returns a single pull request from the current repository by number.", "args": [ { "name": "number", "description": "The number for the pull request to be returned.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "PullRequest", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "pullRequests", "description": "A list of pull requests that have been opened in the repository.", "args": [ { "name": "states", "description": "A list of states to filter the pull requests by.", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "PullRequestState", "ofType": null } } }, "defaultValue": null }, { "name": "labels", "description": "A list of label names to filter the pull requests by.", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } } }, "defaultValue": null }, { "name": "headRefName", "description": "The head ref name to filter the pull requests by.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "baseRefName", "description": "The base ref name to filter the pull requests by.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "orderBy", "description": "Ordering options for pull requests returned from the connection.", "type": { "kind": "INPUT_OBJECT", "name": "IssueOrder", "ofType": null }, "defaultValue": null }, { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PullRequestConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pushedAt", "description": "Identifies when the repository was last pushed to.", "args": [], "type": { "kind": "SCALAR", "name": "DateTime", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "rebaseMergeAllowed", "description": "Whether or not rebase-merging is enabled on this repository.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "ref", "description": "Fetch a given ref from the repository", "args": [ { "name": "qualifiedName", "description": "The ref to retrieve. Fully qualified matches are checked in order (`refs/heads/master`) before falling back onto checks for short name matches (`master`).", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "Ref", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "refs", "description": "Fetch a list of refs from the repository", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "refPrefix", "description": "A ref name prefix like `refs/heads/`, `refs/tags/`, etc.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "defaultValue": null }, { "name": "direction", "description": "DEPRECATED: use orderBy. The ordering direction.", "type": { "kind": "ENUM", "name": "OrderDirection", "ofType": null }, "defaultValue": null }, { "name": "orderBy", "description": "Ordering options for refs returned from the connection.", "type": { "kind": "INPUT_OBJECT", "name": "RefOrder", "ofType": null }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "RefConnection", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "release", "description": "Lookup a single release given various criteria.", "args": [ { "name": "tagName", "description": "The name of the Tag the Release was created from", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "Release", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "releases", "description": "List of releases which are dependent on this repository.", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "orderBy", "description": "Order for connection", "type": { "kind": "INPUT_OBJECT", "name": "ReleaseOrder", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "ReleaseConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "repositoryTopics", "description": "A list of applied repository-topic associations for this repository.", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "RepositoryTopicConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "resourcePath", "description": "The HTTP path for this repository", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "shortDescriptionHTML", "description": "A description of the repository, rendered to HTML without any links in it.", "args": [ { "name": "limit", "description": "How many characters to return.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": "200" } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "HTML", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "squashMergeAllowed", "description": "Whether or not squash-merging is enabled on this repository.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "sshUrl", "description": "The SSH URL to clone this repository", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "GitSSHRemote", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "stargazers", "description": "A list of users who have starred this starrable.", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "orderBy", "description": "Order for connection", "type": { "kind": "INPUT_OBJECT", "name": "StarOrder", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "StargazerConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "updatedAt", "description": "Identifies the date and time when the object was last updated.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "url", "description": "The HTTP URL for this repository", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerCanAdminister", "description": "Indicates whether the viewer has admin permissions on this repository.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerCanCreateProjects", "description": "Can the current viewer create new projects on this owner.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerCanSubscribe", "description": "Check if the viewer is able to change their subscription status for the repository.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerCanUpdateTopics", "description": "Indicates whether the viewer can update the topics of this repository.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerHasStarred", "description": "Returns a boolean indicating whether the viewing user has starred this starrable.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerPermission", "description": "The users permission level on the repository. Will return null if authenticated as an GitHub App.", "args": [], "type": { "kind": "ENUM", "name": "RepositoryPermission", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerSubscription", "description": "Identifies if the viewer is watching, not watching, or ignoring the subscribable entity.", "args": [], "type": { "kind": "ENUM", "name": "SubscriptionState", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "watchers", "description": "A list of users watching the repository.", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "UserConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null }, { "kind": "INTERFACE", "name": "ProjectOwner", "ofType": null }, { "kind": "INTERFACE", "name": "RegistryPackageOwner", "ofType": null }, { "kind": "INTERFACE", "name": "Subscribable", "ofType": null }, { "kind": "INTERFACE", "name": "Starrable", "ofType": null }, { "kind": "INTERFACE", "name": "UniformResourceLocatable", "ofType": null }, { "kind": "INTERFACE", "name": "RepositoryInfo", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "INTERFACE", "name": "ProjectOwner", "description": "Represents an owner of a Project.", "fields": [ { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "project", "description": "Find project by number.", "args": [ { "name": "number", "description": "The project number to find.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "Project", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "projects", "description": "A list of projects under the owner.", "args": [ { "name": "orderBy", "description": "Ordering options for projects returned from the connection", "type": { "kind": "INPUT_OBJECT", "name": "ProjectOrder", "ofType": null }, "defaultValue": null }, { "name": "search", "description": "Query to search projects by, currently only searching by name.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "states", "description": "A list of states to filter the projects by.", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "ProjectState", "ofType": null } } }, "defaultValue": null }, { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "ProjectConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "projectsResourcePath", "description": "The HTTP path listing owners projects", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "projectsUrl", "description": "The HTTP URL listing owners projects", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerCanCreateProjects", "description": "Can the current viewer create new projects on this owner.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": [ { "kind": "OBJECT", "name": "Organization", "ofType": null }, { "kind": "OBJECT", "name": "Repository", "ofType": null }, { "kind": "OBJECT", "name": "User", "ofType": null } ] }, { "kind": "OBJECT", "name": "Project", "description": "Projects manage issues, pull requests and notes within a project owner.", "fields": [ { "name": "body", "description": "The project's description body.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "bodyHTML", "description": "The projects description body rendered to HTML.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "HTML", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "closed", "description": "`true` if the object is closed (definition of closed may depend on type)", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "closedAt", "description": "Identifies the date and time when the object was closed.", "args": [], "type": { "kind": "SCALAR", "name": "DateTime", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "columns", "description": "List of columns in the project", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "ProjectColumnConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "createdAt", "description": "Identifies the date and time when the object was created.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "creator", "description": "The actor who originally created the project.", "args": [], "type": { "kind": "INTERFACE", "name": "Actor", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "databaseId", "description": "Identifies the primary key from the database.", "args": [], "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "name", "description": "The project's name.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "number", "description": "The project's number.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "owner", "description": "The project's owner. Currently limited to repositories, organizations, and users.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INTERFACE", "name": "ProjectOwner", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pendingCards", "description": "List of pending cards in this project", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "archivedStates", "description": "A list of archived states to filter the cards by", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "ENUM", "name": "ProjectCardArchivedState", "ofType": null } }, "defaultValue": "[\"ARCHIVED\", \"NOT_ARCHIVED\"]" } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "ProjectCardConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "resourcePath", "description": "The HTTP path for this project", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "state", "description": "Whether the project is open or closed.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "ProjectState", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "updatedAt", "description": "Identifies the date and time when the object was last updated.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "url", "description": "The HTTP URL for this project", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerCanUpdate", "description": "Check if the current viewer can update this object.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null }, { "kind": "INTERFACE", "name": "Closable", "ofType": null }, { "kind": "INTERFACE", "name": "Updatable", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "INTERFACE", "name": "Closable", "description": "An object that can be closed", "fields": [ { "name": "closed", "description": "`true` if the object is closed (definition of closed may depend on type)", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "closedAt", "description": "Identifies the date and time when the object was closed.", "args": [], "type": { "kind": "SCALAR", "name": "DateTime", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": [ { "kind": "OBJECT", "name": "Issue", "ofType": null }, { "kind": "OBJECT", "name": "Milestone", "ofType": null }, { "kind": "OBJECT", "name": "Project", "ofType": null }, { "kind": "OBJECT", "name": "PullRequest", "ofType": null } ] }, { "kind": "INTERFACE", "name": "Updatable", "description": "Entities that can be updated.", "fields": [ { "name": "viewerCanUpdate", "description": "Check if the current viewer can update this object.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": [ { "kind": "OBJECT", "name": "CommitComment", "ofType": null }, { "kind": "OBJECT", "name": "GistComment", "ofType": null }, { "kind": "OBJECT", "name": "Issue", "ofType": null }, { "kind": "OBJECT", "name": "IssueComment", "ofType": null }, { "kind": "OBJECT", "name": "Project", "ofType": null }, { "kind": "OBJECT", "name": "PullRequest", "ofType": null }, { "kind": "OBJECT", "name": "PullRequestReview", "ofType": null }, { "kind": "OBJECT", "name": "PullRequestReviewComment", "ofType": null } ] }, { "kind": "ENUM", "name": "ProjectState", "description": "State of the project; either 'open' or 'closed'", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "OPEN", "description": "The project is open.", "isDeprecated": false, "deprecationReason": null }, { "name": "CLOSED", "description": "The project is closed.", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null }, { "kind": "SCALAR", "name": "HTML", "description": "A string containing HTML code.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "ProjectColumnConnection", "description": "The connection type for ProjectColumn.", "fields": [ { "name": "edges", "description": "A list of edges.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "ProjectColumnEdge", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "nodes", "description": "A list of nodes.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "ProjectColumn", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pageInfo", "description": "Information to aid in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PageInfo", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "totalCount", "description": "Identifies the total count of items in the connection.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "ProjectColumnEdge", "description": "An edge in a connection.", "fields": [ { "name": "cursor", "description": "A cursor for use in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "node", "description": "The item at the end of the edge.", "args": [], "type": { "kind": "OBJECT", "name": "ProjectColumn", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "ProjectColumn", "description": "A column inside a project.", "fields": [ { "name": "cards", "description": "List of cards in the column", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "archivedStates", "description": "A list of archived states to filter the cards by", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "ENUM", "name": "ProjectCardArchivedState", "ofType": null } }, "defaultValue": "[\"ARCHIVED\", \"NOT_ARCHIVED\"]" } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "ProjectCardConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "createdAt", "description": "Identifies the date and time when the object was created.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "databaseId", "description": "Identifies the primary key from the database.", "args": [], "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "name", "description": "The project column's name.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "project", "description": "The project that contains this column.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "Project", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "purpose", "description": "The semantic purpose of the column", "args": [], "type": { "kind": "ENUM", "name": "ProjectColumnPurpose", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "resourcePath", "description": "The HTTP path for this project column", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "updatedAt", "description": "Identifies the date and time when the object was last updated.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "url", "description": "The HTTP URL for this project column", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "ENUM", "name": "ProjectColumnPurpose", "description": "The semantic purpose of the column - todo, in progress, or done.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "TODO", "description": "The column contains cards still to be worked on", "isDeprecated": false, "deprecationReason": null }, { "name": "IN_PROGRESS", "description": "The column contains cards which are currently being worked on", "isDeprecated": false, "deprecationReason": null }, { "name": "DONE", "description": "The column contains cards which are complete", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null }, { "kind": "OBJECT", "name": "ProjectCardConnection", "description": "The connection type for ProjectCard.", "fields": [ { "name": "edges", "description": "A list of edges.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "ProjectCardEdge", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "nodes", "description": "A list of nodes.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "ProjectCard", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pageInfo", "description": "Information to aid in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PageInfo", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "totalCount", "description": "Identifies the total count of items in the connection.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "ProjectCardEdge", "description": "An edge in a connection.", "fields": [ { "name": "cursor", "description": "A cursor for use in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "node", "description": "The item at the end of the edge.", "args": [], "type": { "kind": "OBJECT", "name": "ProjectCard", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "ProjectCard", "description": "A card in a project.", "fields": [ { "name": "column", "description": "The project column this card is associated under. A card may only belong to one\nproject column at a time. The column field will be null if the card is created\nin a pending state and has yet to be associated with a column. Once cards are\nassociated with a column, they will not become pending in the future.\n", "args": [], "type": { "kind": "OBJECT", "name": "ProjectColumn", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "content", "description": "The card content item", "args": [], "type": { "kind": "UNION", "name": "ProjectCardItem", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "createdAt", "description": "Identifies the date and time when the object was created.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "creator", "description": "The actor who created this card", "args": [], "type": { "kind": "INTERFACE", "name": "Actor", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "databaseId", "description": "Identifies the primary key from the database.", "args": [], "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "isArchived", "description": "Whether the card is archived", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "note", "description": "The card note", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "project", "description": "The project that contains this card.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "Project", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "resourcePath", "description": "The HTTP path for this card", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "state", "description": "The state of ProjectCard", "args": [], "type": { "kind": "ENUM", "name": "ProjectCardState", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "updatedAt", "description": "Identifies the date and time when the object was last updated.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "url", "description": "The HTTP URL for this card", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "ENUM", "name": "ProjectCardState", "description": "Various content states of a ProjectCard", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "CONTENT_ONLY", "description": "The card has content only.", "isDeprecated": false, "deprecationReason": null }, { "name": "NOTE_ONLY", "description": "The card has a note only.", "isDeprecated": false, "deprecationReason": null }, { "name": "REDACTED", "description": "The card is redacted.", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null }, { "kind": "UNION", "name": "ProjectCardItem", "description": "Types that can be inside Project Cards.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": [ { "kind": "OBJECT", "name": "Issue", "ofType": null }, { "kind": "OBJECT", "name": "PullRequest", "ofType": null } ] }, { "kind": "OBJECT", "name": "Issue", "description": "An Issue is a place to discuss ideas, enhancements, tasks, and bugs for a project.", "fields": [ { "name": "activeLockReason", "description": "Reason that the conversation was locked.", "args": [], "type": { "kind": "ENUM", "name": "LockReason", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "assignees", "description": "A list of Users assigned to this object.", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "UserConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "author", "description": "The actor who authored the comment.", "args": [], "type": { "kind": "INTERFACE", "name": "Actor", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "authorAssociation", "description": "Author's association with the subject of the comment.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "CommentAuthorAssociation", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "body", "description": "Identifies the body of the issue.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "bodyHTML", "description": "Identifies the body of the issue rendered to HTML.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "HTML", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "bodyText", "description": "Identifies the body of the issue rendered to text.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "closed", "description": "`true` if the object is closed (definition of closed may depend on type)", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "closedAt", "description": "Identifies the date and time when the object was closed.", "args": [], "type": { "kind": "SCALAR", "name": "DateTime", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "comments", "description": "A list of comments associated with the Issue.", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "IssueCommentConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "createdAt", "description": "Identifies the date and time when the object was created.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "createdViaEmail", "description": "Check if this comment was created via an email reply.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "databaseId", "description": "Identifies the primary key from the database.", "args": [], "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "editor", "description": "The actor who edited the comment.", "args": [], "type": { "kind": "INTERFACE", "name": "Actor", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "includesCreatedEdit", "description": "Check if this comment was edited and includes an edit with the creation data", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "labels", "description": "A list of labels associated with the object.", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "LabelConnection", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "lastEditedAt", "description": "The moment the editor made the last edit", "args": [], "type": { "kind": "SCALAR", "name": "DateTime", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "locked", "description": "`true` if the object is locked", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "milestone", "description": "Identifies the milestone associated with the issue.", "args": [], "type": { "kind": "OBJECT", "name": "Milestone", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "number", "description": "Identifies the issue number.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "participants", "description": "A list of Users that are participating in the Issue conversation.", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "UserConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "projectCards", "description": "List of project cards associated with this issue.", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "archivedStates", "description": "A list of archived states to filter the cards by", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "ENUM", "name": "ProjectCardArchivedState", "ofType": null } }, "defaultValue": "[\"ARCHIVED\", \"NOT_ARCHIVED\"]" } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "ProjectCardConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "publishedAt", "description": "Identifies when the comment was published at.", "args": [], "type": { "kind": "SCALAR", "name": "DateTime", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "reactionGroups", "description": "A list of reactions grouped by content left on the subject.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "ReactionGroup", "ofType": null } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "reactions", "description": "A list of Reactions left on the Issue.", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "content", "description": "Allows filtering Reactions by emoji.", "type": { "kind": "ENUM", "name": "ReactionContent", "ofType": null }, "defaultValue": null }, { "name": "orderBy", "description": "Allows specifying the order in which reactions are returned.", "type": { "kind": "INPUT_OBJECT", "name": "ReactionOrder", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "ReactionConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "repository", "description": "The repository associated with this node.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "Repository", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "resourcePath", "description": "The HTTP path for this issue", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "state", "description": "Identifies the state of the issue.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "IssueState", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "timeline", "description": "A list of events, comments, commits, etc. associated with the issue.", "args": [ { "name": "since", "description": "Allows filtering timeline events by a `since` timestamp.", "type": { "kind": "SCALAR", "name": "DateTime", "ofType": null }, "defaultValue": null }, { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "IssueTimelineConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "timelineItems", "description": "A list of events, comments, commits, etc. associated with the issue.", "args": [ { "name": "since", "description": "Filter timeline items by a `since` timestamp.", "type": { "kind": "SCALAR", "name": "DateTime", "ofType": null }, "defaultValue": null }, { "name": "skip", "description": "Skips the first _n_ elements in the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "itemTypes", "description": "Filter timeline items by type.", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "IssueTimelineItemsItemType", "ofType": null } } }, "defaultValue": null }, { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "IssueTimelineItemsConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "title", "description": "Identifies the issue title.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "updatedAt", "description": "Identifies the date and time when the object was last updated.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "url", "description": "The HTTP URL for this issue", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "userContentEdits", "description": "A list of edits to this content.", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "UserContentEditConnection", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerCanReact", "description": "Can user react to this subject", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerCanSubscribe", "description": "Check if the viewer is able to change their subscription status for the repository.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerCanUpdate", "description": "Check if the current viewer can update this object.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerCannotUpdateReasons", "description": "Reasons why the current viewer can not update this comment.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "CommentCannotUpdateReason", "ofType": null } } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerDidAuthor", "description": "Did the viewer author this comment.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerSubscription", "description": "Identifies if the viewer is watching, not watching, or ignoring the subscribable entity.", "args": [], "type": { "kind": "ENUM", "name": "SubscriptionState", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null }, { "kind": "INTERFACE", "name": "Assignable", "ofType": null }, { "kind": "INTERFACE", "name": "Closable", "ofType": null }, { "kind": "INTERFACE", "name": "Comment", "ofType": null }, { "kind": "INTERFACE", "name": "Updatable", "ofType": null }, { "kind": "INTERFACE", "name": "UpdatableComment", "ofType": null }, { "kind": "INTERFACE", "name": "Labelable", "ofType": null }, { "kind": "INTERFACE", "name": "Lockable", "ofType": null }, { "kind": "INTERFACE", "name": "Reactable", "ofType": null }, { "kind": "INTERFACE", "name": "RepositoryNode", "ofType": null }, { "kind": "INTERFACE", "name": "Subscribable", "ofType": null }, { "kind": "INTERFACE", "name": "UniformResourceLocatable", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "INTERFACE", "name": "Assignable", "description": "An object that can have users assigned to it.", "fields": [ { "name": "assignees", "description": "A list of Users assigned to this object.", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "UserConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": [ { "kind": "OBJECT", "name": "Issue", "ofType": null }, { "kind": "OBJECT", "name": "PullRequest", "ofType": null } ] }, { "kind": "OBJECT", "name": "UserConnection", "description": "The connection type for User.", "fields": [ { "name": "edges", "description": "A list of edges.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "UserEdge", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "nodes", "description": "A list of nodes.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "User", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pageInfo", "description": "Information to aid in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PageInfo", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "totalCount", "description": "Identifies the total count of items in the connection.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "UserEdge", "description": "Represents a user.", "fields": [ { "name": "cursor", "description": "A cursor for use in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "node", "description": "The item at the end of the edge.", "args": [], "type": { "kind": "OBJECT", "name": "User", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "INTERFACE", "name": "Comment", "description": "Represents a comment.", "fields": [ { "name": "author", "description": "The actor who authored the comment.", "args": [], "type": { "kind": "INTERFACE", "name": "Actor", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "authorAssociation", "description": "Author's association with the subject of the comment.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "CommentAuthorAssociation", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "body", "description": "The body as Markdown.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "bodyHTML", "description": "The body rendered to HTML.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "HTML", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "bodyText", "description": "The body rendered to text.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "createdAt", "description": "Identifies the date and time when the object was created.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "createdViaEmail", "description": "Check if this comment was created via an email reply.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "editor", "description": "The actor who edited the comment.", "args": [], "type": { "kind": "INTERFACE", "name": "Actor", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "includesCreatedEdit", "description": "Check if this comment was edited and includes an edit with the creation data", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "lastEditedAt", "description": "The moment the editor made the last edit", "args": [], "type": { "kind": "SCALAR", "name": "DateTime", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "publishedAt", "description": "Identifies when the comment was published at.", "args": [], "type": { "kind": "SCALAR", "name": "DateTime", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "updatedAt", "description": "Identifies the date and time when the object was last updated.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "userContentEdits", "description": "A list of edits to this content.", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "UserContentEditConnection", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerDidAuthor", "description": "Did the viewer author this comment.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": [ { "kind": "OBJECT", "name": "CommitComment", "ofType": null }, { "kind": "OBJECT", "name": "GistComment", "ofType": null }, { "kind": "OBJECT", "name": "Issue", "ofType": null }, { "kind": "OBJECT", "name": "IssueComment", "ofType": null }, { "kind": "OBJECT", "name": "PullRequest", "ofType": null }, { "kind": "OBJECT", "name": "PullRequestReview", "ofType": null }, { "kind": "OBJECT", "name": "PullRequestReviewComment", "ofType": null } ] }, { "kind": "OBJECT", "name": "UserContentEditConnection", "description": "A list of edits to content.", "fields": [ { "name": "edges", "description": "A list of edges.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "UserContentEditEdge", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "nodes", "description": "A list of nodes.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "UserContentEdit", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pageInfo", "description": "Information to aid in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PageInfo", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "totalCount", "description": "Identifies the total count of items in the connection.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "UserContentEditEdge", "description": "An edge in a connection.", "fields": [ { "name": "cursor", "description": "A cursor for use in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "node", "description": "The item at the end of the edge.", "args": [], "type": { "kind": "OBJECT", "name": "UserContentEdit", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "UserContentEdit", "description": "An edit on user content", "fields": [ { "name": "createdAt", "description": "Identifies the date and time when the object was created.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "deletedAt", "description": "Identifies the date and time when the object was deleted.", "args": [], "type": { "kind": "SCALAR", "name": "DateTime", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "deletedBy", "description": "The actor who deleted this content", "args": [], "type": { "kind": "INTERFACE", "name": "Actor", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "diff", "description": "A summary of the changes for this edit", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "editedAt", "description": "When this content was edited", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "editor", "description": "The actor who edited this content", "args": [], "type": { "kind": "INTERFACE", "name": "Actor", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "updatedAt", "description": "Identifies the date and time when the object was last updated.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "ENUM", "name": "CommentAuthorAssociation", "description": "A comment author association with repository.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "MEMBER", "description": "Author is a member of the organization that owns the repository.", "isDeprecated": false, "deprecationReason": null }, { "name": "OWNER", "description": "Author is the owner of the repository.", "isDeprecated": false, "deprecationReason": null }, { "name": "COLLABORATOR", "description": "Author has been invited to collaborate on the repository.", "isDeprecated": false, "deprecationReason": null }, { "name": "CONTRIBUTOR", "description": "Author has previously committed to the repository.", "isDeprecated": false, "deprecationReason": null }, { "name": "FIRST_TIME_CONTRIBUTOR", "description": "Author has not previously committed to the repository.", "isDeprecated": false, "deprecationReason": null }, { "name": "FIRST_TIMER", "description": "Author has not previously committed to GitHub.", "isDeprecated": false, "deprecationReason": null }, { "name": "NONE", "description": "Author has no association with the repository.", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null }, { "kind": "INTERFACE", "name": "UpdatableComment", "description": "Comments that can be updated.", "fields": [ { "name": "viewerCannotUpdateReasons", "description": "Reasons why the current viewer can not update this comment.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "CommentCannotUpdateReason", "ofType": null } } } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": [ { "kind": "OBJECT", "name": "CommitComment", "ofType": null }, { "kind": "OBJECT", "name": "GistComment", "ofType": null }, { "kind": "OBJECT", "name": "Issue", "ofType": null }, { "kind": "OBJECT", "name": "IssueComment", "ofType": null }, { "kind": "OBJECT", "name": "PullRequest", "ofType": null }, { "kind": "OBJECT", "name": "PullRequestReview", "ofType": null }, { "kind": "OBJECT", "name": "PullRequestReviewComment", "ofType": null } ] }, { "kind": "ENUM", "name": "CommentCannotUpdateReason", "description": "The possible errors that will prevent a user from updating a comment.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "INSUFFICIENT_ACCESS", "description": "You must be the author or have write access to this repository to update this comment.", "isDeprecated": false, "deprecationReason": null }, { "name": "LOCKED", "description": "Unable to create comment because issue is locked.", "isDeprecated": false, "deprecationReason": null }, { "name": "LOGIN_REQUIRED", "description": "You must be logged in to update this comment.", "isDeprecated": false, "deprecationReason": null }, { "name": "MAINTENANCE", "description": "Repository is under maintenance.", "isDeprecated": false, "deprecationReason": null }, { "name": "VERIFIED_EMAIL_REQUIRED", "description": "At least one email address must be verified to update this comment.", "isDeprecated": false, "deprecationReason": null }, { "name": "DENIED", "description": "You cannot update this comment", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null }, { "kind": "INTERFACE", "name": "Labelable", "description": "An object that can have labels assigned to it.", "fields": [ { "name": "labels", "description": "A list of labels associated with the object.", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "LabelConnection", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": [ { "kind": "OBJECT", "name": "Issue", "ofType": null }, { "kind": "OBJECT", "name": "PullRequest", "ofType": null } ] }, { "kind": "OBJECT", "name": "LabelConnection", "description": "The connection type for Label.", "fields": [ { "name": "edges", "description": "A list of edges.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "LabelEdge", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "nodes", "description": "A list of nodes.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "Label", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pageInfo", "description": "Information to aid in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PageInfo", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "totalCount", "description": "Identifies the total count of items in the connection.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "LabelEdge", "description": "An edge in a connection.", "fields": [ { "name": "cursor", "description": "A cursor for use in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "node", "description": "The item at the end of the edge.", "args": [], "type": { "kind": "OBJECT", "name": "Label", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "Label", "description": "A label for categorizing Issues or Milestones with a given Repository.", "fields": [ { "name": "color", "description": "Identifies the label color.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "createdAt", "description": "Identifies the date and time when the label was created.", "args": [], "type": { "kind": "SCALAR", "name": "DateTime", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "description", "description": "A brief description of this label.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "isDefault", "description": "Indicates whether or not this is a default label.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "issues", "description": "A list of issues associated with this label.", "args": [ { "name": "orderBy", "description": "Ordering options for issues returned from the connection.", "type": { "kind": "INPUT_OBJECT", "name": "IssueOrder", "ofType": null }, "defaultValue": null }, { "name": "labels", "description": "A list of label names to filter the pull requests by.", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } } }, "defaultValue": null }, { "name": "states", "description": "A list of states to filter the issues by.", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "IssueState", "ofType": null } } }, "defaultValue": null }, { "name": "filterBy", "description": "Filtering options for issues returned from the connection.", "type": { "kind": "INPUT_OBJECT", "name": "IssueFilters", "ofType": null }, "defaultValue": null }, { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "IssueConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "name", "description": "Identifies the label name.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pullRequests", "description": "A list of pull requests associated with this label.", "args": [ { "name": "states", "description": "A list of states to filter the pull requests by.", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "PullRequestState", "ofType": null } } }, "defaultValue": null }, { "name": "labels", "description": "A list of label names to filter the pull requests by.", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } } }, "defaultValue": null }, { "name": "headRefName", "description": "The head ref name to filter the pull requests by.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "baseRefName", "description": "The base ref name to filter the pull requests by.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "orderBy", "description": "Ordering options for pull requests returned from the connection.", "type": { "kind": "INPUT_OBJECT", "name": "IssueOrder", "ofType": null }, "defaultValue": null }, { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PullRequestConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "repository", "description": "The repository associated with this label.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "Repository", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "resourcePath", "description": "The HTTP path for this label.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "updatedAt", "description": "Identifies the date and time when the label was last updated.", "args": [], "type": { "kind": "SCALAR", "name": "DateTime", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "url", "description": "The HTTP URL for this label.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "IssueConnection", "description": "The connection type for Issue.", "fields": [ { "name": "edges", "description": "A list of edges.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "IssueEdge", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "nodes", "description": "A list of nodes.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "Issue", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pageInfo", "description": "Information to aid in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PageInfo", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "totalCount", "description": "Identifies the total count of items in the connection.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "IssueEdge", "description": "An edge in a connection.", "fields": [ { "name": "cursor", "description": "A cursor for use in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "node", "description": "The item at the end of the edge.", "args": [], "type": { "kind": "OBJECT", "name": "Issue", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "IssueOrder", "description": "Ways in which lists of issues can be ordered upon return.", "fields": null, "inputFields": [ { "name": "field", "description": "The field in which to order issues by.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "IssueOrderField", "ofType": null } }, "defaultValue": null }, { "name": "direction", "description": "The direction in which to order issues by the specified field.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "OrderDirection", "ofType": null } }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "ENUM", "name": "IssueOrderField", "description": "Properties by which issue connections can be ordered.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "CREATED_AT", "description": "Order issues by creation time", "isDeprecated": false, "deprecationReason": null }, { "name": "UPDATED_AT", "description": "Order issues by update time", "isDeprecated": false, "deprecationReason": null }, { "name": "COMMENTS", "description": "Order issues by comment count", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null }, { "kind": "ENUM", "name": "OrderDirection", "description": "Possible directions in which to order a list of items when provided an `orderBy` argument.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "ASC", "description": "Specifies an ascending order for a given `orderBy` argument.", "isDeprecated": false, "deprecationReason": null }, { "name": "DESC", "description": "Specifies a descending order for a given `orderBy` argument.", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null }, { "kind": "ENUM", "name": "IssueState", "description": "The possible states of an issue.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "OPEN", "description": "An issue that is still open", "isDeprecated": false, "deprecationReason": null }, { "name": "CLOSED", "description": "An issue that has been closed", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "IssueFilters", "description": "Ways in which to filter lists of issues.", "fields": null, "inputFields": [ { "name": "assignee", "description": "List issues assigned to given name. Pass in `null` for issues with no assigned user, and `*` for issues assigned to any user.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "createdBy", "description": "List issues created by given name.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "labels", "description": "List issues where the list of label names exist on the issue.", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } } }, "defaultValue": null }, { "name": "mentioned", "description": "List issues where the given name is mentioned in the issue.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "milestone", "description": "List issues by given milestone argument. If an string representation of an integer is passed, it should refer to a milestone by its number field. Pass in `null` for issues with no milestone, and `*` for issues that are assigned to any milestone.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "since", "description": "List issues that have been updated at or after the given date.", "type": { "kind": "SCALAR", "name": "DateTime", "ofType": null }, "defaultValue": null }, { "name": "states", "description": "List issues filtered by the list of states given.", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "IssueState", "ofType": null } } }, "defaultValue": null }, { "name": "viewerSubscribed", "description": "List issues subscribed to by viewer.", "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": "false" } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "PullRequestConnection", "description": "The connection type for PullRequest.", "fields": [ { "name": "edges", "description": "A list of edges.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "PullRequestEdge", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "nodes", "description": "A list of nodes.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "PullRequest", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pageInfo", "description": "Information to aid in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PageInfo", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "totalCount", "description": "Identifies the total count of items in the connection.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "PullRequestEdge", "description": "An edge in a connection.", "fields": [ { "name": "cursor", "description": "A cursor for use in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "node", "description": "The item at the end of the edge.", "args": [], "type": { "kind": "OBJECT", "name": "PullRequest", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "PullRequest", "description": "A repository pull request.", "fields": [ { "name": "activeLockReason", "description": "Reason that the conversation was locked.", "args": [], "type": { "kind": "ENUM", "name": "LockReason", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "additions", "description": "The number of additions in this pull request.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "assignees", "description": "A list of Users assigned to this object.", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "UserConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "author", "description": "The actor who authored the comment.", "args": [], "type": { "kind": "INTERFACE", "name": "Actor", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "authorAssociation", "description": "Author's association with the subject of the comment.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "CommentAuthorAssociation", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "baseRef", "description": "Identifies the base Ref associated with the pull request.", "args": [], "type": { "kind": "OBJECT", "name": "Ref", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "baseRefName", "description": "Identifies the name of the base Ref associated with the pull request, even if the ref has been deleted.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "baseRefOid", "description": "Identifies the oid of the base ref associated with the pull request, even if the ref has been deleted.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "GitObjectID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "baseRepository", "description": "The repository associated with this pull request's base Ref.", "args": [], "type": { "kind": "OBJECT", "name": "Repository", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "body", "description": "The body as Markdown.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "bodyHTML", "description": "The body rendered to HTML.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "HTML", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "bodyText", "description": "The body rendered to text.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "changedFiles", "description": "The number of changed files in this pull request.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "closed", "description": "`true` if the pull request is closed", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "closedAt", "description": "Identifies the date and time when the object was closed.", "args": [], "type": { "kind": "SCALAR", "name": "DateTime", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "comments", "description": "A list of comments associated with the pull request.", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "IssueCommentConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "commits", "description": "A list of commits present in this pull request's head branch not present in the base branch.", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PullRequestCommitConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "createdAt", "description": "Identifies the date and time when the object was created.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "createdViaEmail", "description": "Check if this comment was created via an email reply.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "databaseId", "description": "Identifies the primary key from the database.", "args": [], "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "deletions", "description": "The number of deletions in this pull request.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "editor", "description": "The actor who edited this pull request's body.", "args": [], "type": { "kind": "INTERFACE", "name": "Actor", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "files", "description": "Lists the files changed within this pull request.", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "PullRequestChangedFileConnection", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "headRef", "description": "Identifies the head Ref associated with the pull request.", "args": [], "type": { "kind": "OBJECT", "name": "Ref", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "headRefName", "description": "Identifies the name of the head Ref associated with the pull request, even if the ref has been deleted.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "headRefOid", "description": "Identifies the oid of the head ref associated with the pull request, even if the ref has been deleted.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "GitObjectID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "headRepository", "description": "The repository associated with this pull request's head Ref.", "args": [], "type": { "kind": "OBJECT", "name": "Repository", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "headRepositoryOwner", "description": "The owner of the repository associated with this pull request's head Ref.", "args": [], "type": { "kind": "INTERFACE", "name": "RepositoryOwner", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "includesCreatedEdit", "description": "Check if this comment was edited and includes an edit with the creation data", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "isCrossRepository", "description": "The head and base repositories are different.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "labels", "description": "A list of labels associated with the object.", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "LabelConnection", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "lastEditedAt", "description": "The moment the editor made the last edit", "args": [], "type": { "kind": "SCALAR", "name": "DateTime", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "locked", "description": "`true` if the pull request is locked", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "maintainerCanModify", "description": "Indicates whether maintainers can modify the pull request.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "mergeCommit", "description": "The commit that was created when this pull request was merged.", "args": [], "type": { "kind": "OBJECT", "name": "Commit", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "mergeable", "description": "Whether or not the pull request can be merged based on the existence of merge conflicts.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "MergeableState", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "merged", "description": "Whether or not the pull request was merged.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "mergedAt", "description": "The date and time that the pull request was merged.", "args": [], "type": { "kind": "SCALAR", "name": "DateTime", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "mergedBy", "description": "The actor who merged the pull request.", "args": [], "type": { "kind": "INTERFACE", "name": "Actor", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "milestone", "description": "Identifies the milestone associated with the pull request.", "args": [], "type": { "kind": "OBJECT", "name": "Milestone", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "number", "description": "Identifies the pull request number.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "participants", "description": "A list of Users that are participating in the Pull Request conversation.", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "UserConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "permalink", "description": "The permalink to the pull request.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "potentialMergeCommit", "description": "The commit that GitHub automatically generated to test if this pull request could be merged. This field will not return a value if the pull request is merged, or if the test merge commit is still being generated. See the `mergeable` field for more details on the mergeability of the pull request.", "args": [], "type": { "kind": "OBJECT", "name": "Commit", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "projectCards", "description": "List of project cards associated with this pull request.", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "archivedStates", "description": "A list of archived states to filter the cards by", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "ENUM", "name": "ProjectCardArchivedState", "ofType": null } }, "defaultValue": "[\"ARCHIVED\", \"NOT_ARCHIVED\"]" } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "ProjectCardConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "publishedAt", "description": "Identifies when the comment was published at.", "args": [], "type": { "kind": "SCALAR", "name": "DateTime", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "reactionGroups", "description": "A list of reactions grouped by content left on the subject.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "ReactionGroup", "ofType": null } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "reactions", "description": "A list of Reactions left on the Issue.", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "content", "description": "Allows filtering Reactions by emoji.", "type": { "kind": "ENUM", "name": "ReactionContent", "ofType": null }, "defaultValue": null }, { "name": "orderBy", "description": "Allows specifying the order in which reactions are returned.", "type": { "kind": "INPUT_OBJECT", "name": "ReactionOrder", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "ReactionConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "repository", "description": "The repository associated with this node.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "Repository", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "resourcePath", "description": "The HTTP path for this pull request.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "revertResourcePath", "description": "The HTTP path for reverting this pull request.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "revertUrl", "description": "The HTTP URL for reverting this pull request.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "reviewRequests", "description": "A list of review requests associated with the pull request.", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "ReviewRequestConnection", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "reviewThreads", "description": "The list of all review threads for this pull request.", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PullRequestReviewThreadConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "reviews", "description": "A list of reviews associated with the pull request.", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "states", "description": "A list of states to filter the reviews.", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "PullRequestReviewState", "ofType": null } } }, "defaultValue": null }, { "name": "author", "description": "Filter by author of the review.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "PullRequestReviewConnection", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "state", "description": "Identifies the state of the pull request.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "PullRequestState", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "suggestedReviewers", "description": "A list of reviewer suggestions based on commit history and past review comments.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "SuggestedReviewer", "ofType": null } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "timeline", "description": "A list of events, comments, commits, etc. associated with the pull request.", "args": [ { "name": "since", "description": "Allows filtering timeline events by a `since` timestamp.", "type": { "kind": "SCALAR", "name": "DateTime", "ofType": null }, "defaultValue": null }, { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PullRequestTimelineConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "timelineItems", "description": "A list of events, comments, commits, etc. associated with the pull request.", "args": [ { "name": "since", "description": "Filter timeline items by a `since` timestamp.", "type": { "kind": "SCALAR", "name": "DateTime", "ofType": null }, "defaultValue": null }, { "name": "skip", "description": "Skips the first _n_ elements in the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "itemTypes", "description": "Filter timeline items by type.", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "PullRequestTimelineItemsItemType", "ofType": null } } }, "defaultValue": null }, { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PullRequestTimelineItemsConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "title", "description": "Identifies the pull request title.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "updatedAt", "description": "Identifies the date and time when the object was last updated.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "url", "description": "The HTTP URL for this pull request.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "userContentEdits", "description": "A list of edits to this content.", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "UserContentEditConnection", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerCanApplySuggestion", "description": "Whether or not the viewer can apply suggestion.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerCanReact", "description": "Can user react to this subject", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerCanSubscribe", "description": "Check if the viewer is able to change their subscription status for the repository.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerCanUpdate", "description": "Check if the current viewer can update this object.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerCannotUpdateReasons", "description": "Reasons why the current viewer can not update this comment.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "CommentCannotUpdateReason", "ofType": null } } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerDidAuthor", "description": "Did the viewer author this comment.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerSubscription", "description": "Identifies if the viewer is watching, not watching, or ignoring the subscribable entity.", "args": [], "type": { "kind": "ENUM", "name": "SubscriptionState", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null }, { "kind": "INTERFACE", "name": "Assignable", "ofType": null }, { "kind": "INTERFACE", "name": "Closable", "ofType": null }, { "kind": "INTERFACE", "name": "Comment", "ofType": null }, { "kind": "INTERFACE", "name": "Updatable", "ofType": null }, { "kind": "INTERFACE", "name": "UpdatableComment", "ofType": null }, { "kind": "INTERFACE", "name": "Labelable", "ofType": null }, { "kind": "INTERFACE", "name": "Lockable", "ofType": null }, { "kind": "INTERFACE", "name": "Reactable", "ofType": null }, { "kind": "INTERFACE", "name": "RepositoryNode", "ofType": null }, { "kind": "INTERFACE", "name": "Subscribable", "ofType": null }, { "kind": "INTERFACE", "name": "UniformResourceLocatable", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "INTERFACE", "name": "Lockable", "description": "An object that can be locked.", "fields": [ { "name": "activeLockReason", "description": "Reason that the conversation was locked.", "args": [], "type": { "kind": "ENUM", "name": "LockReason", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "locked", "description": "`true` if the object is locked", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": [ { "kind": "OBJECT", "name": "Issue", "ofType": null }, { "kind": "OBJECT", "name": "PullRequest", "ofType": null } ] }, { "kind": "ENUM", "name": "LockReason", "description": "The possible reasons that an issue or pull request was locked.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "OFF_TOPIC", "description": "The issue or pull request was locked because the conversation was off-topic.", "isDeprecated": false, "deprecationReason": null }, { "name": "TOO_HEATED", "description": "The issue or pull request was locked because the conversation was too heated.", "isDeprecated": false, "deprecationReason": null }, { "name": "RESOLVED", "description": "The issue or pull request was locked because the conversation was resolved.", "isDeprecated": false, "deprecationReason": null }, { "name": "SPAM", "description": "The issue or pull request was locked because the conversation was spam.", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null }, { "kind": "OBJECT", "name": "App", "description": "A GitHub App.", "fields": [ { "name": "createdAt", "description": "Identifies the date and time when the object was created.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "databaseId", "description": "Identifies the primary key from the database.", "args": [], "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "description", "description": "The description of the app.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "logoBackgroundColor", "description": "The hex color code, without the leading '#', for the logo background.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "logoUrl", "description": "A URL pointing to the app's logo.", "args": [ { "name": "size", "description": "The size of the resulting image.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "name", "description": "The name of the app.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "slug", "description": "A slug based on the name of the app for use in URLs.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "updatedAt", "description": "Identifies the date and time when the object was last updated.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "url", "description": "The URL to the app's homepage.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "MarketplaceListing", "description": "A listing in the GitHub integration marketplace.", "fields": [ { "name": "app", "description": "The GitHub App this listing represents.", "args": [], "type": { "kind": "OBJECT", "name": "App", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "companyUrl", "description": "URL to the listing owner's company site.", "args": [], "type": { "kind": "SCALAR", "name": "URI", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "configurationResourcePath", "description": "The HTTP path for configuring access to the listing's integration or OAuth app", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "configurationUrl", "description": "The HTTP URL for configuring access to the listing's integration or OAuth app", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "documentationUrl", "description": "URL to the listing's documentation.", "args": [], "type": { "kind": "SCALAR", "name": "URI", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "extendedDescription", "description": "The listing's detailed description.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "extendedDescriptionHTML", "description": "The listing's detailed description rendered to HTML.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "HTML", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "fullDescription", "description": "The listing's introductory description.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "fullDescriptionHTML", "description": "The listing's introductory description rendered to HTML.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "HTML", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "hasApprovalBeenRequested", "description": "Whether this listing has been submitted for review from GitHub for approval to be displayed in the Marketplace.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": true, "deprecationReason": "`hasApprovalBeenRequested` will be removed. Use `isVerificationPendingFromDraft` instead. Removal on 2019-10-01 UTC." }, { "name": "hasPublishedFreeTrialPlans", "description": "Does this listing have any plans with a free trial?", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "hasTermsOfService", "description": "Does this listing have a terms of service link?", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "howItWorks", "description": "A technical description of how this app works with GitHub.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "howItWorksHTML", "description": "The listing's technical description rendered to HTML.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "HTML", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "installationUrl", "description": "URL to install the product to the viewer's account or organization.", "args": [], "type": { "kind": "SCALAR", "name": "URI", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "installedForViewer", "description": "Whether this listing's app has been installed for the current viewer", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "isApproved", "description": "Whether this listing has been approved for display in the Marketplace.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": true, "deprecationReason": "`isApproved` will be removed. Use `isPublic` instead. Removal on 2019-10-01 UTC." }, { "name": "isArchived", "description": "Whether this listing has been removed from the Marketplace.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "isDelisted", "description": "Whether this listing has been removed from the Marketplace.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": true, "deprecationReason": "`isDelisted` will be removed. Use `isArchived` instead. Removal on 2019-10-01 UTC." }, { "name": "isDraft", "description": "Whether this listing is still an editable draft that has not been submitted for review and is not publicly visible in the Marketplace.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "isPaid", "description": "Whether the product this listing represents is available as part of a paid plan.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "isPublic", "description": "Whether this listing has been approved for display in the Marketplace.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "isRejected", "description": "Whether this listing has been rejected by GitHub for display in the Marketplace.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "isUnverified", "description": "Whether this listing has been approved for unverified display in the Marketplace.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "isUnverifiedPending", "description": "Whether this draft listing has been submitted for review for approval to be unverified in the Marketplace.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "isVerificationPendingFromDraft", "description": "Whether this draft listing has been submitted for review from GitHub for approval to be verified in the Marketplace.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "isVerificationPendingFromUnverified", "description": "Whether this unverified listing has been submitted for review from GitHub for approval to be verified in the Marketplace.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "isVerified", "description": "Whether this listing has been approved for verified display in the Marketplace.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "logoBackgroundColor", "description": "The hex color code, without the leading '#', for the logo background.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "logoUrl", "description": "URL for the listing's logo image.", "args": [ { "name": "size", "description": "The size in pixels of the resulting square image.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": "400" } ], "type": { "kind": "SCALAR", "name": "URI", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "name", "description": "The listing's full name.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "normalizedShortDescription", "description": "The listing's very short description without a trailing period or ampersands.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pricingUrl", "description": "URL to the listing's detailed pricing.", "args": [], "type": { "kind": "SCALAR", "name": "URI", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "primaryCategory", "description": "The category that best describes the listing.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "MarketplaceCategory", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "privacyPolicyUrl", "description": "URL to the listing's privacy policy, may return an empty string for listings that do not require a privacy policy URL.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "resourcePath", "description": "The HTTP path for the Marketplace listing.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "screenshotUrls", "description": "The URLs for the listing's screenshots.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "LIST", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "secondaryCategory", "description": "An alternate category that describes the listing.", "args": [], "type": { "kind": "OBJECT", "name": "MarketplaceCategory", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "shortDescription", "description": "The listing's very short description.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "slug", "description": "The short name of the listing used in its URL.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "statusUrl", "description": "URL to the listing's status page.", "args": [], "type": { "kind": "SCALAR", "name": "URI", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "supportEmail", "description": "An email address for support for this listing's app.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "supportUrl", "description": "Either a URL or an email address for support for this listing's app, may return an empty string for listings that do not require a support URL.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "termsOfServiceUrl", "description": "URL to the listing's terms of service.", "args": [], "type": { "kind": "SCALAR", "name": "URI", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "url", "description": "The HTTP URL for the Marketplace listing.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerCanAddPlans", "description": "Can the current viewer add plans for this Marketplace listing.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerCanApprove", "description": "Can the current viewer approve this Marketplace listing.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerCanDelist", "description": "Can the current viewer delist this Marketplace listing.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerCanEdit", "description": "Can the current viewer edit this Marketplace listing.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerCanEditCategories", "description": "Can the current viewer edit the primary and secondary category of this\nMarketplace listing.\n", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerCanEditPlans", "description": "Can the current viewer edit the plans for this Marketplace listing.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerCanRedraft", "description": "Can the current viewer return this Marketplace listing to draft state\nso it becomes editable again.\n", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerCanReject", "description": "Can the current viewer reject this Marketplace listing by returning it to\nan editable draft state or rejecting it entirely.\n", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerCanRequestApproval", "description": "Can the current viewer request this listing be reviewed for display in\nthe Marketplace as verified.\n", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerHasPurchased", "description": "Indicates whether the current user has an active subscription to this Marketplace listing.\n", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerHasPurchasedForAllOrganizations", "description": "Indicates if the current user has purchased a subscription to this Marketplace listing\nfor all of the organizations the user owns.\n", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerIsListingAdmin", "description": "Does the current viewer role allow them to administer this Marketplace listing.\n", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "Organization", "description": "An account on GitHub, with one or more owners, that has repositories, members and teams.", "fields": [ { "name": "anyPinnableItems", "description": "Determine if this repository owner has any items that can be pinned to their profile.", "args": [ { "name": "type", "description": "Filter to only a particular kind of pinnable item.", "type": { "kind": "ENUM", "name": "PinnableItemType", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "avatarUrl", "description": "A URL pointing to the organization's public avatar.", "args": [ { "name": "size", "description": "The size of the resulting square image.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "databaseId", "description": "Identifies the primary key from the database.", "args": [], "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "description", "description": "The organization's public profile description.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "email", "description": "The organization's public email.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "isVerified", "description": "Whether the organization has verified its profile email and website.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "itemShowcase", "description": "Showcases a selection of repositories and gists that the profile owner has either curated or that have been selected automatically based on popularity.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "ProfileItemShowcase", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "location", "description": "The organization's public profile location.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "login", "description": "The organization's login name.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "memberStatuses", "description": "Get the status messages members of this entity have set that are either public or visible only to the organization.", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "orderBy", "description": "Ordering options for user statuses returned from the connection.", "type": { "kind": "INPUT_OBJECT", "name": "UserStatusOrder", "ofType": null }, "defaultValue": "{field:\"UPDATED_AT\",direction:\"DESC\"}" } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "UserStatusConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "membersWithRole", "description": "A list of users who are members of this organization.", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "OrganizationMemberConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "name", "description": "The organization's public profile name.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "newTeamResourcePath", "description": "The HTTP path creating a new team", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "newTeamUrl", "description": "The HTTP URL creating a new team", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "organizationBillingEmail", "description": "The billing email for the organization.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "pendingMembers", "description": "A list of users who have been invited to join this organization.", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "UserConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pinnableItems", "description": "A list of repositories and gists this profile owner can pin to their profile.", "args": [ { "name": "types", "description": "Filter the types of pinnable items that are returned.", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "PinnableItemType", "ofType": null } } }, "defaultValue": null }, { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PinnableItemConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pinnedItems", "description": "A list of repositories and gists this profile owner has pinned to their profile", "args": [ { "name": "types", "description": "Filter the types of pinned items that are returned.", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "PinnableItemType", "ofType": null } } }, "defaultValue": null }, { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PinnableItemConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pinnedItemsRemaining", "description": "Returns how many more items this profile owner can pin to their profile.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pinnedRepositories", "description": "A list of repositories this user has pinned to their profile", "args": [ { "name": "privacy", "description": "If non-null, filters repositories according to privacy", "type": { "kind": "ENUM", "name": "RepositoryPrivacy", "ofType": null }, "defaultValue": null }, { "name": "orderBy", "description": "Ordering options for repositories returned from the connection", "type": { "kind": "INPUT_OBJECT", "name": "RepositoryOrder", "ofType": null }, "defaultValue": null }, { "name": "affiliations", "description": "Array of viewer's affiliation options for repositories returned from the connection. For example, OWNER will include only repositories that the current viewer owns.", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "ENUM", "name": "RepositoryAffiliation", "ofType": null } }, "defaultValue": "[\"OWNER\", \"COLLABORATOR\"]" }, { "name": "ownerAffiliations", "description": "Array of owner's affiliation options for repositories returned from the connection. For example, OWNER will include only repositories that the organization or user being viewed owns.", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "ENUM", "name": "RepositoryAffiliation", "ofType": null } }, "defaultValue": "[\"OWNER\", \"COLLABORATOR\"]" }, { "name": "isLocked", "description": "If non-null, filters repositories according to whether they have been locked", "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": null }, { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "RepositoryConnection", "ofType": null } }, "isDeprecated": true, "deprecationReason": "pinnedRepositories will be removed Use ProfileOwner.pinnedItems instead. Removal on 2019-07-01 UTC." }, { "name": "project", "description": "Find project by number.", "args": [ { "name": "number", "description": "The project number to find.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "Project", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "projects", "description": "A list of projects under the owner.", "args": [ { "name": "orderBy", "description": "Ordering options for projects returned from the connection", "type": { "kind": "INPUT_OBJECT", "name": "ProjectOrder", "ofType": null }, "defaultValue": null }, { "name": "search", "description": "Query to search projects by, currently only searching by name.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "states", "description": "A list of states to filter the projects by.", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "ProjectState", "ofType": null } } }, "defaultValue": null }, { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "ProjectConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "projectsResourcePath", "description": "The HTTP path listing organization's projects", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "projectsUrl", "description": "The HTTP URL listing organization's projects", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "repositories", "description": "A list of repositories that the user owns.", "args": [ { "name": "privacy", "description": "If non-null, filters repositories according to privacy", "type": { "kind": "ENUM", "name": "RepositoryPrivacy", "ofType": null }, "defaultValue": null }, { "name": "orderBy", "description": "Ordering options for repositories returned from the connection", "type": { "kind": "INPUT_OBJECT", "name": "RepositoryOrder", "ofType": null }, "defaultValue": null }, { "name": "affiliations", "description": "Array of viewer's affiliation options for repositories returned from the connection. For example, OWNER will include only repositories that the current viewer owns.", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "ENUM", "name": "RepositoryAffiliation", "ofType": null } }, "defaultValue": "[\"OWNER\", \"COLLABORATOR\"]" }, { "name": "ownerAffiliations", "description": "Array of owner's affiliation options for repositories returned from the connection. For example, OWNER will include only repositories that the organization or user being viewed owns.", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "ENUM", "name": "RepositoryAffiliation", "ofType": null } }, "defaultValue": "[\"OWNER\", \"COLLABORATOR\"]" }, { "name": "isLocked", "description": "If non-null, filters repositories according to whether they have been locked", "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": null }, { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "isFork", "description": "If non-null, filters repositories according to whether they are forks of another repository", "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "RepositoryConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "repository", "description": "Find Repository.", "args": [ { "name": "name", "description": "Name of Repository to find.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "Repository", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "requiresTwoFactorAuthentication", "description": "When true the organization requires all members, billing managers, and outside collaborators to enable two-factor authentication.", "args": [], "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "resourcePath", "description": "The HTTP path for this organization.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "samlIdentityProvider", "description": "The Organization's SAML identity providers", "args": [], "type": { "kind": "OBJECT", "name": "OrganizationIdentityProvider", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "team", "description": "Find an organization's team by its slug.", "args": [ { "name": "slug", "description": "The name or slug of the team to find.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "Team", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "teams", "description": "A list of teams in this organization.", "args": [ { "name": "privacy", "description": "If non-null, filters teams according to privacy", "type": { "kind": "ENUM", "name": "TeamPrivacy", "ofType": null }, "defaultValue": null }, { "name": "role", "description": "If non-null, filters teams according to whether the viewer is an admin or member on team", "type": { "kind": "ENUM", "name": "TeamRole", "ofType": null }, "defaultValue": null }, { "name": "query", "description": "If non-null, filters teams with query on team name and team slug", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "userLogins", "description": "User logins to filter by", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } } }, "defaultValue": null }, { "name": "orderBy", "description": "Ordering options for teams returned from the connection", "type": { "kind": "INPUT_OBJECT", "name": "TeamOrder", "ofType": null }, "defaultValue": null }, { "name": "ldapMapped", "description": "If true, filters teams that are mapped to an LDAP Group (Enterprise only)", "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": null }, { "name": "rootTeamsOnly", "description": "If true, restrict to only root teams", "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": "false" }, { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "TeamConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "teamsResourcePath", "description": "The HTTP path listing organization's teams", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "teamsUrl", "description": "The HTTP URL listing organization's teams", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "url", "description": "The HTTP URL for this organization.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerCanAdminister", "description": "Organization is adminable by the viewer.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerCanChangePinnedItems", "description": "Can the viewer pin repositories and gists to the profile?", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerCanCreateProjects", "description": "Can the current viewer create new projects on this owner.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerCanCreateRepositories", "description": "Viewer can create repositories on this organization", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerCanCreateTeams", "description": "Viewer can create teams on this organization.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerIsAMember", "description": "Viewer is an active member of this organization.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "websiteUrl", "description": "The organization's public profile URL.", "args": [], "type": { "kind": "SCALAR", "name": "URI", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null }, { "kind": "INTERFACE", "name": "Actor", "ofType": null }, { "kind": "INTERFACE", "name": "RegistryPackageOwner", "ofType": null }, { "kind": "INTERFACE", "name": "RegistryPackageSearch", "ofType": null }, { "kind": "INTERFACE", "name": "ProjectOwner", "ofType": null }, { "kind": "INTERFACE", "name": "RepositoryOwner", "ofType": null }, { "kind": "INTERFACE", "name": "UniformResourceLocatable", "ofType": null }, { "kind": "INTERFACE", "name": "MemberStatusable", "ofType": null }, { "kind": "INTERFACE", "name": "ProfileOwner", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "INTERFACE", "name": "RegistryPackageSearch", "description": "Represents an interface to search packages on an object.", "fields": [ { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": [ { "kind": "OBJECT", "name": "Organization", "ofType": null }, { "kind": "OBJECT", "name": "User", "ofType": null } ] }, { "kind": "INTERFACE", "name": "RepositoryOwner", "description": "Represents an owner of a Repository.", "fields": [ { "name": "avatarUrl", "description": "A URL pointing to the owner's public avatar.", "args": [ { "name": "size", "description": "The size of the resulting square image.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "login", "description": "The username used to login.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pinnedRepositories", "description": "A list of repositories this user has pinned to their profile", "args": [ { "name": "privacy", "description": "If non-null, filters repositories according to privacy", "type": { "kind": "ENUM", "name": "RepositoryPrivacy", "ofType": null }, "defaultValue": null }, { "name": "orderBy", "description": "Ordering options for repositories returned from the connection", "type": { "kind": "INPUT_OBJECT", "name": "RepositoryOrder", "ofType": null }, "defaultValue": null }, { "name": "affiliations", "description": "Array of viewer's affiliation options for repositories returned from the connection. For example, OWNER will include only repositories that the current viewer owns.", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "ENUM", "name": "RepositoryAffiliation", "ofType": null } }, "defaultValue": "[\"OWNER\", \"COLLABORATOR\"]" }, { "name": "ownerAffiliations", "description": "Array of owner's affiliation options for repositories returned from the connection. For example, OWNER will include only repositories that the organization or user being viewed owns.", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "ENUM", "name": "RepositoryAffiliation", "ofType": null } }, "defaultValue": "[\"OWNER\", \"COLLABORATOR\"]" }, { "name": "isLocked", "description": "If non-null, filters repositories according to whether they have been locked", "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": null }, { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "RepositoryConnection", "ofType": null } }, "isDeprecated": true, "deprecationReason": "pinnedRepositories will be removed Use ProfileOwner.pinnedItems instead. Removal on 2019-07-01 UTC." }, { "name": "repositories", "description": "A list of repositories that the user owns.", "args": [ { "name": "privacy", "description": "If non-null, filters repositories according to privacy", "type": { "kind": "ENUM", "name": "RepositoryPrivacy", "ofType": null }, "defaultValue": null }, { "name": "orderBy", "description": "Ordering options for repositories returned from the connection", "type": { "kind": "INPUT_OBJECT", "name": "RepositoryOrder", "ofType": null }, "defaultValue": null }, { "name": "affiliations", "description": "Array of viewer's affiliation options for repositories returned from the connection. For example, OWNER will include only repositories that the current viewer owns.", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "ENUM", "name": "RepositoryAffiliation", "ofType": null } }, "defaultValue": "[\"OWNER\", \"COLLABORATOR\"]" }, { "name": "ownerAffiliations", "description": "Array of owner's affiliation options for repositories returned from the connection. For example, OWNER will include only repositories that the organization or user being viewed owns.", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "ENUM", "name": "RepositoryAffiliation", "ofType": null } }, "defaultValue": "[\"OWNER\", \"COLLABORATOR\"]" }, { "name": "isLocked", "description": "If non-null, filters repositories according to whether they have been locked", "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": null }, { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "isFork", "description": "If non-null, filters repositories according to whether they are forks of another repository", "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "RepositoryConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "repository", "description": "Find Repository.", "args": [ { "name": "name", "description": "Name of Repository to find.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "Repository", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "resourcePath", "description": "The HTTP URL for the owner.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "url", "description": "The HTTP URL for the owner.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": [ { "kind": "OBJECT", "name": "Organization", "ofType": null }, { "kind": "OBJECT", "name": "User", "ofType": null } ] }, { "kind": "OBJECT", "name": "RepositoryConnection", "description": "A list of repositories owned by the subject.", "fields": [ { "name": "edges", "description": "A list of edges.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "RepositoryEdge", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "nodes", "description": "A list of nodes.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "Repository", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pageInfo", "description": "Information to aid in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PageInfo", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "totalCount", "description": "Identifies the total count of items in the connection.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "totalDiskUsage", "description": "The total size in kilobytes of all repositories in the connection.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "RepositoryEdge", "description": "An edge in a connection.", "fields": [ { "name": "cursor", "description": "A cursor for use in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "node", "description": "The item at the end of the edge.", "args": [], "type": { "kind": "OBJECT", "name": "Repository", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "ENUM", "name": "RepositoryPrivacy", "description": "The privacy of a repository", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "PUBLIC", "description": "Public", "isDeprecated": false, "deprecationReason": null }, { "name": "PRIVATE", "description": "Private", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "RepositoryOrder", "description": "Ordering options for repository connections", "fields": null, "inputFields": [ { "name": "field", "description": "The field to order repositories by.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "RepositoryOrderField", "ofType": null } }, "defaultValue": null }, { "name": "direction", "description": "The ordering direction.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "OrderDirection", "ofType": null } }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "ENUM", "name": "RepositoryOrderField", "description": "Properties by which repository connections can be ordered.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "CREATED_AT", "description": "Order repositories by creation time", "isDeprecated": false, "deprecationReason": null }, { "name": "UPDATED_AT", "description": "Order repositories by update time", "isDeprecated": false, "deprecationReason": null }, { "name": "PUSHED_AT", "description": "Order repositories by push time", "isDeprecated": false, "deprecationReason": null }, { "name": "NAME", "description": "Order repositories by name", "isDeprecated": false, "deprecationReason": null }, { "name": "STARGAZERS", "description": "Order repositories by number of stargazers", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null }, { "kind": "ENUM", "name": "RepositoryAffiliation", "description": "The affiliation of a user to a repository", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "OWNER", "description": "Repositories that are owned by the authenticated user.", "isDeprecated": false, "deprecationReason": null }, { "name": "COLLABORATOR", "description": "Repositories that the user has been added to as a collaborator.", "isDeprecated": false, "deprecationReason": null }, { "name": "ORGANIZATION_MEMBER", "description": "Repositories that the user has access to through being a member of an organization. This includes every repository on every team that the user is on.", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null }, { "kind": "SCALAR", "name": "Float", "description": "Represents signed double-precision fractional values as specified by [IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point).", "fields": null, "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "INTERFACE", "name": "MemberStatusable", "description": "Entities that have members who can set status messages.", "fields": [ { "name": "memberStatuses", "description": "Get the status messages members of this entity have set that are either public or visible only to the organization.", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "orderBy", "description": "Ordering options for user statuses returned from the connection.", "type": { "kind": "INPUT_OBJECT", "name": "UserStatusOrder", "ofType": null }, "defaultValue": "{field:\"UPDATED_AT\",direction:\"DESC\"}" } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "UserStatusConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": [ { "kind": "OBJECT", "name": "Organization", "ofType": null }, { "kind": "OBJECT", "name": "Team", "ofType": null } ] }, { "kind": "OBJECT", "name": "UserStatusConnection", "description": "The connection type for UserStatus.", "fields": [ { "name": "edges", "description": "A list of edges.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "UserStatusEdge", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "nodes", "description": "A list of nodes.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "UserStatus", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pageInfo", "description": "Information to aid in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PageInfo", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "totalCount", "description": "Identifies the total count of items in the connection.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "UserStatusEdge", "description": "An edge in a connection.", "fields": [ { "name": "cursor", "description": "A cursor for use in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "node", "description": "The item at the end of the edge.", "args": [], "type": { "kind": "OBJECT", "name": "UserStatus", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "UserStatus", "description": "The user's description of what they're currently doing.", "fields": [ { "name": "createdAt", "description": "Identifies the date and time when the object was created.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "emoji", "description": "An emoji summarizing the user's status.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": "ID of the object.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "indicatesLimitedAvailability", "description": "Whether this status indicates the user is not fully available on GitHub.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "message", "description": "A brief message describing what the user is doing.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "organization", "description": "The organization whose members can see this status. If null, this status is publicly visible.", "args": [], "type": { "kind": "OBJECT", "name": "Organization", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "updatedAt", "description": "Identifies the date and time when the object was last updated.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "user", "description": "The user who has this status.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "User", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "UserStatusOrder", "description": "Ordering options for user status connections.", "fields": null, "inputFields": [ { "name": "field", "description": "The field to order user statuses by.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "UserStatusOrderField", "ofType": null } }, "defaultValue": null }, { "name": "direction", "description": "The ordering direction.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "OrderDirection", "ofType": null } }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "ENUM", "name": "UserStatusOrderField", "description": "Properties by which user status connections can be ordered.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "UPDATED_AT", "description": "Order user statuses by when they were updated.", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null }, { "kind": "INTERFACE", "name": "ProfileOwner", "description": "Represents any entity on GitHub that has a profile page.", "fields": [ { "name": "anyPinnableItems", "description": "Determine if this repository owner has any items that can be pinned to their profile.", "args": [ { "name": "type", "description": "Filter to only a particular kind of pinnable item.", "type": { "kind": "ENUM", "name": "PinnableItemType", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "email", "description": "The public profile email.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "itemShowcase", "description": "Showcases a selection of repositories and gists that the profile owner has either curated or that have been selected automatically based on popularity.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "ProfileItemShowcase", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "location", "description": "The public profile location.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "login", "description": "The username used to login.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "name", "description": "The public profile name.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "pinnableItems", "description": "A list of repositories and gists this profile owner can pin to their profile.", "args": [ { "name": "types", "description": "Filter the types of pinnable items that are returned.", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "PinnableItemType", "ofType": null } } }, "defaultValue": null }, { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PinnableItemConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pinnedItems", "description": "A list of repositories and gists this profile owner has pinned to their profile", "args": [ { "name": "types", "description": "Filter the types of pinned items that are returned.", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "PinnableItemType", "ofType": null } } }, "defaultValue": null }, { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PinnableItemConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pinnedItemsRemaining", "description": "Returns how many more items this profile owner can pin to their profile.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerCanChangePinnedItems", "description": "Can the viewer pin repositories and gists to the profile?", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "websiteUrl", "description": "The public profile website URL.", "args": [], "type": { "kind": "SCALAR", "name": "URI", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": [ { "kind": "OBJECT", "name": "Organization", "ofType": null }, { "kind": "OBJECT", "name": "User", "ofType": null } ] }, { "kind": "OBJECT", "name": "ProfileItemShowcase", "description": "A curatable list of repositories relating to a repository owner, which defaults to showing the most popular repositories they own.", "fields": [ { "name": "hasPinnedItems", "description": "Whether or not the owner has pinned any repositories or gists.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "items", "description": "The repositories and gists in the showcase. If the profile owner has any pinned items, those will be returned. Otherwise, the profile owner's popular repositories will be returned.", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PinnableItemConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "PinnableItemConnection", "description": "The connection type for PinnableItem.", "fields": [ { "name": "edges", "description": "A list of edges.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "PinnableItemEdge", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "nodes", "description": "A list of nodes.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "UNION", "name": "PinnableItem", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pageInfo", "description": "Information to aid in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PageInfo", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "totalCount", "description": "Identifies the total count of items in the connection.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "PinnableItemEdge", "description": "An edge in a connection.", "fields": [ { "name": "cursor", "description": "A cursor for use in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "node", "description": "The item at the end of the edge.", "args": [], "type": { "kind": "UNION", "name": "PinnableItem", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "UNION", "name": "PinnableItem", "description": "Types that can be pinned to a profile page.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": [ { "kind": "OBJECT", "name": "Gist", "ofType": null }, { "kind": "OBJECT", "name": "Repository", "ofType": null } ] }, { "kind": "OBJECT", "name": "Gist", "description": "A Gist.", "fields": [ { "name": "comments", "description": "A list of comments associated with the gist", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "GistCommentConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "createdAt", "description": "Identifies the date and time when the object was created.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "description", "description": "The gist description.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "files", "description": "The files in this gist.", "args": [ { "name": "limit", "description": "The maximum number of files to return.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": "10" } ], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "GistFile", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "isFork", "description": "Identifies if the gist is a fork.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "isPublic", "description": "Whether the gist is public or not.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "name", "description": "The gist name.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "owner", "description": "The gist owner.", "args": [], "type": { "kind": "INTERFACE", "name": "RepositoryOwner", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "pushedAt", "description": "Identifies when the gist was last pushed to.", "args": [], "type": { "kind": "SCALAR", "name": "DateTime", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "stargazers", "description": "A list of users who have starred this starrable.", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "orderBy", "description": "Order for connection", "type": { "kind": "INPUT_OBJECT", "name": "StarOrder", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "StargazerConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "updatedAt", "description": "Identifies the date and time when the object was last updated.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerHasStarred", "description": "Returns a boolean indicating whether the viewing user has starred this starrable.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null }, { "kind": "INTERFACE", "name": "Starrable", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "INTERFACE", "name": "Starrable", "description": "Things that can be starred.", "fields": [ { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "stargazers", "description": "A list of users who have starred this starrable.", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "orderBy", "description": "Order for connection", "type": { "kind": "INPUT_OBJECT", "name": "StarOrder", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "StargazerConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerHasStarred", "description": "Returns a boolean indicating whether the viewing user has starred this starrable.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": [ { "kind": "OBJECT", "name": "Gist", "ofType": null }, { "kind": "OBJECT", "name": "Repository", "ofType": null }, { "kind": "OBJECT", "name": "Topic", "ofType": null } ] }, { "kind": "OBJECT", "name": "StargazerConnection", "description": "The connection type for User.", "fields": [ { "name": "edges", "description": "A list of edges.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "StargazerEdge", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "nodes", "description": "A list of nodes.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "User", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pageInfo", "description": "Information to aid in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PageInfo", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "totalCount", "description": "Identifies the total count of items in the connection.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "StargazerEdge", "description": "Represents a user that's starred a repository.", "fields": [ { "name": "cursor", "description": "A cursor for use in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "node", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "User", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "starredAt", "description": "Identifies when the item was starred.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "StarOrder", "description": "Ways in which star connections can be ordered.", "fields": null, "inputFields": [ { "name": "field", "description": "The field in which to order nodes by.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "StarOrderField", "ofType": null } }, "defaultValue": null }, { "name": "direction", "description": "The direction in which to order nodes.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "OrderDirection", "ofType": null } }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "ENUM", "name": "StarOrderField", "description": "Properties by which star connections can be ordered.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "STARRED_AT", "description": "Allows ordering a list of stars by when they were created.", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null }, { "kind": "OBJECT", "name": "GistCommentConnection", "description": "The connection type for GistComment.", "fields": [ { "name": "edges", "description": "A list of edges.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "GistCommentEdge", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "nodes", "description": "A list of nodes.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "GistComment", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pageInfo", "description": "Information to aid in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PageInfo", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "totalCount", "description": "Identifies the total count of items in the connection.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "GistCommentEdge", "description": "An edge in a connection.", "fields": [ { "name": "cursor", "description": "A cursor for use in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "node", "description": "The item at the end of the edge.", "args": [], "type": { "kind": "OBJECT", "name": "GistComment", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "GistComment", "description": "Represents a comment on an Gist.", "fields": [ { "name": "author", "description": "The actor who authored the comment.", "args": [], "type": { "kind": "INTERFACE", "name": "Actor", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "authorAssociation", "description": "Author's association with the gist.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "CommentAuthorAssociation", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "body", "description": "Identifies the comment body.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "bodyHTML", "description": "The comment body rendered to HTML.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "HTML", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "bodyText", "description": "The body rendered to text.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "createdAt", "description": "Identifies the date and time when the object was created.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "createdViaEmail", "description": "Check if this comment was created via an email reply.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "databaseId", "description": "Identifies the primary key from the database.", "args": [], "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "editor", "description": "The actor who edited the comment.", "args": [], "type": { "kind": "INTERFACE", "name": "Actor", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "gist", "description": "The associated gist.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "Gist", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "includesCreatedEdit", "description": "Check if this comment was edited and includes an edit with the creation data", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "isMinimized", "description": "Returns whether or not a comment has been minimized.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "lastEditedAt", "description": "The moment the editor made the last edit", "args": [], "type": { "kind": "SCALAR", "name": "DateTime", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "minimizedReason", "description": "Returns why the comment was minimized.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "publishedAt", "description": "Identifies when the comment was published at.", "args": [], "type": { "kind": "SCALAR", "name": "DateTime", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "updatedAt", "description": "Identifies the date and time when the object was last updated.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "userContentEdits", "description": "A list of edits to this content.", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "UserContentEditConnection", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerCanDelete", "description": "Check if the current viewer can delete this object.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerCanMinimize", "description": "Check if the current viewer can minimize this object.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerCanUpdate", "description": "Check if the current viewer can update this object.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerCannotUpdateReasons", "description": "Reasons why the current viewer can not update this comment.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "CommentCannotUpdateReason", "ofType": null } } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerDidAuthor", "description": "Did the viewer author this comment.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null }, { "kind": "INTERFACE", "name": "Comment", "ofType": null }, { "kind": "INTERFACE", "name": "Deletable", "ofType": null }, { "kind": "INTERFACE", "name": "Updatable", "ofType": null }, { "kind": "INTERFACE", "name": "UpdatableComment", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "INTERFACE", "name": "Deletable", "description": "Entities that can be deleted.", "fields": [ { "name": "viewerCanDelete", "description": "Check if the current viewer can delete this object.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": [ { "kind": "OBJECT", "name": "CommitComment", "ofType": null }, { "kind": "OBJECT", "name": "GistComment", "ofType": null }, { "kind": "OBJECT", "name": "IssueComment", "ofType": null }, { "kind": "OBJECT", "name": "PullRequestReview", "ofType": null }, { "kind": "OBJECT", "name": "PullRequestReviewComment", "ofType": null } ] }, { "kind": "OBJECT", "name": "GistFile", "description": "A file in a gist.", "fields": [ { "name": "encodedName", "description": "The file name encoded to remove characters that are invalid in URL paths.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "encoding", "description": "The gist file encoding.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "extension", "description": "The file extension from the file name.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "isImage", "description": "Indicates if this file is an image.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "isTruncated", "description": "Whether the file's contents were truncated.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "language", "description": "The programming language this file is written in.", "args": [], "type": { "kind": "OBJECT", "name": "Language", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "name", "description": "The gist file name.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "size", "description": "The gist file size in bytes.", "args": [], "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "text", "description": "UTF8 text data or null if the file is binary", "args": [ { "name": "truncate", "description": "Optionally truncate the returned file to this length.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "Language", "description": "Represents a given language found in repositories.", "fields": [ { "name": "color", "description": "The color defined for the current language.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "name", "description": "The name of the current language.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "ENUM", "name": "PinnableItemType", "description": "Represents items that can be pinned to a profile page or dashboard.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "REPOSITORY", "description": "A repository.", "isDeprecated": false, "deprecationReason": null }, { "name": "GIST", "description": "A gist.", "isDeprecated": false, "deprecationReason": null }, { "name": "ISSUE", "description": "An issue.", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null }, { "kind": "OBJECT", "name": "ProjectConnection", "description": "A list of projects associated with the owner.", "fields": [ { "name": "edges", "description": "A list of edges.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "ProjectEdge", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "nodes", "description": "A list of nodes.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "Project", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pageInfo", "description": "Information to aid in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PageInfo", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "totalCount", "description": "Identifies the total count of items in the connection.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "ProjectEdge", "description": "An edge in a connection.", "fields": [ { "name": "cursor", "description": "A cursor for use in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "node", "description": "The item at the end of the edge.", "args": [], "type": { "kind": "OBJECT", "name": "Project", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "ProjectOrder", "description": "Ways in which lists of projects can be ordered upon return.", "fields": null, "inputFields": [ { "name": "field", "description": "The field in which to order projects by.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "ProjectOrderField", "ofType": null } }, "defaultValue": null }, { "name": "direction", "description": "The direction in which to order projects by the specified field.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "OrderDirection", "ofType": null } }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "ENUM", "name": "ProjectOrderField", "description": "Properties by which project connections can be ordered.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "CREATED_AT", "description": "Order projects by creation time", "isDeprecated": false, "deprecationReason": null }, { "name": "UPDATED_AT", "description": "Order projects by update time", "isDeprecated": false, "deprecationReason": null }, { "name": "NAME", "description": "Order projects by name", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null }, { "kind": "OBJECT", "name": "Bot", "description": "A special type of user which takes actions on behalf of GitHub Apps.", "fields": [ { "name": "avatarUrl", "description": "A URL pointing to the GitHub App's public avatar.", "args": [ { "name": "size", "description": "The size of the resulting square image.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "createdAt", "description": "Identifies the date and time when the object was created.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "databaseId", "description": "Identifies the primary key from the database.", "args": [], "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "login", "description": "The username of the actor.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "resourcePath", "description": "The HTTP path for this bot", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "updatedAt", "description": "Identifies the date and time when the object was last updated.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "url", "description": "The HTTP URL for this bot", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null }, { "kind": "INTERFACE", "name": "Actor", "ofType": null }, { "kind": "INTERFACE", "name": "UniformResourceLocatable", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "IssueComment", "description": "Represents a comment on an Issue.", "fields": [ { "name": "author", "description": "The actor who authored the comment.", "args": [], "type": { "kind": "INTERFACE", "name": "Actor", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "authorAssociation", "description": "Author's association with the subject of the comment.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "CommentAuthorAssociation", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "body", "description": "The body as Markdown.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "bodyHTML", "description": "The body rendered to HTML.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "HTML", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "bodyText", "description": "The body rendered to text.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "createdAt", "description": "Identifies the date and time when the object was created.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "createdViaEmail", "description": "Check if this comment was created via an email reply.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "databaseId", "description": "Identifies the primary key from the database.", "args": [], "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "editor", "description": "The actor who edited the comment.", "args": [], "type": { "kind": "INTERFACE", "name": "Actor", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "includesCreatedEdit", "description": "Check if this comment was edited and includes an edit with the creation data", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "isMinimized", "description": "Returns whether or not a comment has been minimized.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "issue", "description": "Identifies the issue associated with the comment.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "Issue", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "lastEditedAt", "description": "The moment the editor made the last edit", "args": [], "type": { "kind": "SCALAR", "name": "DateTime", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "minimizedReason", "description": "Returns why the comment was minimized.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "publishedAt", "description": "Identifies when the comment was published at.", "args": [], "type": { "kind": "SCALAR", "name": "DateTime", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "pullRequest", "description": "Returns the pull request associated with the comment, if this comment was made on a\npull request.\n", "args": [], "type": { "kind": "OBJECT", "name": "PullRequest", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "reactionGroups", "description": "A list of reactions grouped by content left on the subject.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "ReactionGroup", "ofType": null } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "reactions", "description": "A list of Reactions left on the Issue.", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "content", "description": "Allows filtering Reactions by emoji.", "type": { "kind": "ENUM", "name": "ReactionContent", "ofType": null }, "defaultValue": null }, { "name": "orderBy", "description": "Allows specifying the order in which reactions are returned.", "type": { "kind": "INPUT_OBJECT", "name": "ReactionOrder", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "ReactionConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "repository", "description": "The repository associated with this node.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "Repository", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "resourcePath", "description": "The HTTP path for this issue comment", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "updatedAt", "description": "Identifies the date and time when the object was last updated.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "url", "description": "The HTTP URL for this issue comment", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "userContentEdits", "description": "A list of edits to this content.", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "UserContentEditConnection", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerCanDelete", "description": "Check if the current viewer can delete this object.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerCanMinimize", "description": "Check if the current viewer can minimize this object.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerCanReact", "description": "Can user react to this subject", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerCanUpdate", "description": "Check if the current viewer can update this object.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerCannotUpdateReasons", "description": "Reasons why the current viewer can not update this comment.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "CommentCannotUpdateReason", "ofType": null } } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerDidAuthor", "description": "Did the viewer author this comment.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null }, { "kind": "INTERFACE", "name": "Comment", "ofType": null }, { "kind": "INTERFACE", "name": "Deletable", "ofType": null }, { "kind": "INTERFACE", "name": "Updatable", "ofType": null }, { "kind": "INTERFACE", "name": "UpdatableComment", "ofType": null }, { "kind": "INTERFACE", "name": "Reactable", "ofType": null }, { "kind": "INTERFACE", "name": "RepositoryNode", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "INTERFACE", "name": "Reactable", "description": "Represents a subject that can be reacted on.", "fields": [ { "name": "databaseId", "description": "Identifies the primary key from the database.", "args": [], "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "reactionGroups", "description": "A list of reactions grouped by content left on the subject.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "ReactionGroup", "ofType": null } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "reactions", "description": "A list of Reactions left on the Issue.", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "content", "description": "Allows filtering Reactions by emoji.", "type": { "kind": "ENUM", "name": "ReactionContent", "ofType": null }, "defaultValue": null }, { "name": "orderBy", "description": "Allows specifying the order in which reactions are returned.", "type": { "kind": "INPUT_OBJECT", "name": "ReactionOrder", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "ReactionConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerCanReact", "description": "Can user react to this subject", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": [ { "kind": "OBJECT", "name": "CommitComment", "ofType": null }, { "kind": "OBJECT", "name": "Issue", "ofType": null }, { "kind": "OBJECT", "name": "IssueComment", "ofType": null }, { "kind": "OBJECT", "name": "PullRequest", "ofType": null }, { "kind": "OBJECT", "name": "PullRequestReview", "ofType": null }, { "kind": "OBJECT", "name": "PullRequestReviewComment", "ofType": null } ] }, { "kind": "OBJECT", "name": "ReactionGroup", "description": "A group of emoji reactions to a particular piece of content.", "fields": [ { "name": "content", "description": "Identifies the emoji reaction.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "ReactionContent", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "createdAt", "description": "Identifies when the reaction was created.", "args": [], "type": { "kind": "SCALAR", "name": "DateTime", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "subject", "description": "The subject that was reacted to.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INTERFACE", "name": "Reactable", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "users", "description": "Users who have reacted to the reaction subject with the emotion represented by this reaction group", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "ReactingUserConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerHasReacted", "description": "Whether or not the authenticated user has left a reaction on the subject.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "ENUM", "name": "ReactionContent", "description": "Emojis that can be attached to Issues, Pull Requests and Comments.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "THUMBS_UP", "description": "Represents the 👍 emoji.", "isDeprecated": false, "deprecationReason": null }, { "name": "THUMBS_DOWN", "description": "Represents the 👎 emoji.", "isDeprecated": false, "deprecationReason": null }, { "name": "LAUGH", "description": "Represents the 😄 emoji.", "isDeprecated": false, "deprecationReason": null }, { "name": "HOORAY", "description": "Represents the 🎉 emoji.", "isDeprecated": false, "deprecationReason": null }, { "name": "CONFUSED", "description": "Represents the 😕 emoji.", "isDeprecated": false, "deprecationReason": null }, { "name": "HEART", "description": "Represents the ❤️ emoji.", "isDeprecated": false, "deprecationReason": null }, { "name": "ROCKET", "description": "Represents the 🚀 emoji.", "isDeprecated": false, "deprecationReason": null }, { "name": "EYES", "description": "Represents the 👀 emoji.", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null }, { "kind": "OBJECT", "name": "ReactingUserConnection", "description": "The connection type for User.", "fields": [ { "name": "edges", "description": "A list of edges.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "ReactingUserEdge", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "nodes", "description": "A list of nodes.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "User", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pageInfo", "description": "Information to aid in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PageInfo", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "totalCount", "description": "Identifies the total count of items in the connection.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "ReactingUserEdge", "description": "Represents a user that's made a reaction.", "fields": [ { "name": "cursor", "description": "A cursor for use in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "node", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "User", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "reactedAt", "description": "The moment when the user made the reaction.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "ReactionConnection", "description": "A list of reactions that have been left on the subject.", "fields": [ { "name": "edges", "description": "A list of edges.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "ReactionEdge", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "nodes", "description": "A list of nodes.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "Reaction", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pageInfo", "description": "Information to aid in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PageInfo", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "totalCount", "description": "Identifies the total count of items in the connection.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerHasReacted", "description": "Whether or not the authenticated user has left a reaction on the subject.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "ReactionEdge", "description": "An edge in a connection.", "fields": [ { "name": "cursor", "description": "A cursor for use in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "node", "description": "The item at the end of the edge.", "args": [], "type": { "kind": "OBJECT", "name": "Reaction", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "Reaction", "description": "An emoji reaction to a particular piece of content.", "fields": [ { "name": "content", "description": "Identifies the emoji reaction.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "ReactionContent", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "createdAt", "description": "Identifies the date and time when the object was created.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "databaseId", "description": "Identifies the primary key from the database.", "args": [], "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "reactable", "description": "The reactable piece of content", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INTERFACE", "name": "Reactable", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "user", "description": "Identifies the user who created this reaction.", "args": [], "type": { "kind": "OBJECT", "name": "User", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "ReactionOrder", "description": "Ways in which lists of reactions can be ordered upon return.", "fields": null, "inputFields": [ { "name": "field", "description": "The field in which to order reactions by.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "ReactionOrderField", "ofType": null } }, "defaultValue": null }, { "name": "direction", "description": "The direction in which to order reactions by the specified field.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "OrderDirection", "ofType": null } }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "ENUM", "name": "ReactionOrderField", "description": "A list of fields that reactions can be ordered by.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "CREATED_AT", "description": "Allows ordering a list of reactions by when they were created.", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null }, { "kind": "INTERFACE", "name": "RepositoryInfo", "description": "A subset of repository info.", "fields": [ { "name": "createdAt", "description": "Identifies the date and time when the object was created.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "description", "description": "The description of the repository.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "descriptionHTML", "description": "The description of the repository rendered to HTML.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "HTML", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "forkCount", "description": "Returns how many forks there are of this repository in the whole network.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "hasIssuesEnabled", "description": "Indicates if the repository has issues feature enabled.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "hasWikiEnabled", "description": "Indicates if the repository has wiki feature enabled.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "homepageUrl", "description": "The repository's URL.", "args": [], "type": { "kind": "SCALAR", "name": "URI", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "isArchived", "description": "Indicates if the repository is unmaintained.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "isFork", "description": "Identifies if the repository is a fork.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "isLocked", "description": "Indicates if the repository has been locked or not.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "isMirror", "description": "Identifies if the repository is a mirror.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "isPrivate", "description": "Identifies if the repository is private.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "licenseInfo", "description": "The license associated with the repository", "args": [], "type": { "kind": "OBJECT", "name": "License", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "lockReason", "description": "The reason the repository has been locked.", "args": [], "type": { "kind": "ENUM", "name": "RepositoryLockReason", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "mirrorUrl", "description": "The repository's original mirror URL.", "args": [], "type": { "kind": "SCALAR", "name": "URI", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "name", "description": "The name of the repository.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "nameWithOwner", "description": "The repository's name with owner.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "owner", "description": "The User owner of the repository.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INTERFACE", "name": "RepositoryOwner", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pushedAt", "description": "Identifies when the repository was last pushed to.", "args": [], "type": { "kind": "SCALAR", "name": "DateTime", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "resourcePath", "description": "The HTTP path for this repository", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "shortDescriptionHTML", "description": "A description of the repository, rendered to HTML without any links in it.", "args": [ { "name": "limit", "description": "How many characters to return.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": "200" } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "HTML", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "updatedAt", "description": "Identifies the date and time when the object was last updated.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "url", "description": "The HTTP URL for this repository", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": [ { "kind": "OBJECT", "name": "Repository", "ofType": null } ] }, { "kind": "ENUM", "name": "RepositoryLockReason", "description": "The possible reasons a given repository could be in a locked state.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "MOVING", "description": "The repository is locked due to a move.", "isDeprecated": false, "deprecationReason": null }, { "name": "BILLING", "description": "The repository is locked due to a billing related reason.", "isDeprecated": false, "deprecationReason": null }, { "name": "RENAME", "description": "The repository is locked due to a rename.", "isDeprecated": false, "deprecationReason": null }, { "name": "MIGRATING", "description": "The repository is locked due to a migration.", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null }, { "kind": "OBJECT", "name": "License", "description": "A repository's open source license", "fields": [ { "name": "body", "description": "The full text of the license", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "conditions", "description": "The conditions set by the license", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "LicenseRule", "ofType": null } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "description", "description": "A human-readable description of the license", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "featured", "description": "Whether the license should be featured", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "hidden", "description": "Whether the license should be displayed in license pickers", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "implementation", "description": "Instructions on how to implement the license", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "key", "description": "The lowercased SPDX ID of the license", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "limitations", "description": "The limitations set by the license", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "LicenseRule", "ofType": null } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "name", "description": "The license full name specified by ", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "nickname", "description": "Customary short name if applicable (e.g, GPLv3)", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "permissions", "description": "The permissions set by the license", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "LicenseRule", "ofType": null } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pseudoLicense", "description": "Whether the license is a pseudo-license placeholder (e.g., other, no-license)", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "spdxId", "description": "Short identifier specified by ", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "url", "description": "URL to the license on ", "args": [], "type": { "kind": "SCALAR", "name": "URI", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "LicenseRule", "description": "Describes a License's conditions, permissions, and limitations", "fields": [ { "name": "description", "description": "A description of the rule", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "key", "description": "The machine-readable rule key", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "label", "description": "The human-readable rule label", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "RepositoryTopicConnection", "description": "The connection type for RepositoryTopic.", "fields": [ { "name": "edges", "description": "A list of edges.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "RepositoryTopicEdge", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "nodes", "description": "A list of nodes.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "RepositoryTopic", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pageInfo", "description": "Information to aid in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PageInfo", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "totalCount", "description": "Identifies the total count of items in the connection.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "RepositoryTopicEdge", "description": "An edge in a connection.", "fields": [ { "name": "cursor", "description": "A cursor for use in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "node", "description": "The item at the end of the edge.", "args": [], "type": { "kind": "OBJECT", "name": "RepositoryTopic", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "RepositoryTopic", "description": "A repository-topic connects a repository to a topic.", "fields": [ { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "resourcePath", "description": "The HTTP path for this repository-topic.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "topic", "description": "The topic.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "Topic", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "url", "description": "The HTTP URL for this repository-topic.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null }, { "kind": "INTERFACE", "name": "UniformResourceLocatable", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "Topic", "description": "A topic aggregates entities that are related to a subject.", "fields": [ { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "name", "description": "The topic's name.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "relatedTopics", "description": "A list of related topics, including aliases of this topic, sorted with the most relevant\nfirst. Returns up to 10 Topics.\n", "args": [ { "name": "first", "description": "How many topics to return.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": "3" } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "Topic", "ofType": null } } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "stargazers", "description": "A list of users who have starred this starrable.", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "orderBy", "description": "Order for connection", "type": { "kind": "INPUT_OBJECT", "name": "StarOrder", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "StargazerConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerHasStarred", "description": "Returns a boolean indicating whether the viewing user has starred this starrable.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null }, { "kind": "INTERFACE", "name": "Starrable", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "Release", "description": "A release contains the content for a release.", "fields": [ { "name": "author", "description": "The author of the release", "args": [], "type": { "kind": "OBJECT", "name": "User", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "createdAt", "description": "Identifies the date and time when the object was created.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "description", "description": "Identifies the description of the release.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "isDraft", "description": "Whether or not the release is a draft", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "isPrerelease", "description": "Whether or not the release is a prerelease", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "name", "description": "Identifies the title of the release.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "publishedAt", "description": "Identifies the date and time when the release was created.", "args": [], "type": { "kind": "SCALAR", "name": "DateTime", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "releaseAssets", "description": "List of releases assets which are dependent on this release.", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "name", "description": "A list of names to filter the assets by.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "ReleaseAssetConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "resourcePath", "description": "The HTTP path for this issue", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "tag", "description": "The Git tag the release points to", "args": [], "type": { "kind": "OBJECT", "name": "Ref", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "tagName", "description": "The name of the release's Git tag", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "updatedAt", "description": "Identifies the date and time when the object was last updated.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "url", "description": "The HTTP URL for this issue", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null }, { "kind": "INTERFACE", "name": "UniformResourceLocatable", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "Ref", "description": "Represents a Git reference.", "fields": [ { "name": "associatedPullRequests", "description": "A list of pull requests with this ref as the head ref.", "args": [ { "name": "states", "description": "A list of states to filter the pull requests by.", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "PullRequestState", "ofType": null } } }, "defaultValue": null }, { "name": "labels", "description": "A list of label names to filter the pull requests by.", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } } }, "defaultValue": null }, { "name": "headRefName", "description": "The head ref name to filter the pull requests by.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "baseRefName", "description": "The base ref name to filter the pull requests by.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "orderBy", "description": "Ordering options for pull requests returned from the connection.", "type": { "kind": "INPUT_OBJECT", "name": "IssueOrder", "ofType": null }, "defaultValue": null }, { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PullRequestConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "name", "description": "The ref name.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "prefix", "description": "The ref's prefix, such as `refs/heads/` or `refs/tags/`.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "repository", "description": "The repository the ref belongs to.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "Repository", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "target", "description": "The object the ref points to.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INTERFACE", "name": "GitObject", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "INTERFACE", "name": "GitObject", "description": "Represents a Git object.", "fields": [ { "name": "abbreviatedOid", "description": "An abbreviated version of the Git object ID", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "commitResourcePath", "description": "The HTTP path for this Git object", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "commitUrl", "description": "The HTTP URL for this Git object", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "oid", "description": "The Git object ID", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "GitObjectID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "repository", "description": "The Repository the Git object belongs to", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "Repository", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": [ { "kind": "OBJECT", "name": "Blob", "ofType": null }, { "kind": "OBJECT", "name": "Commit", "ofType": null }, { "kind": "OBJECT", "name": "Tag", "ofType": null }, { "kind": "OBJECT", "name": "Tree", "ofType": null } ] }, { "kind": "SCALAR", "name": "GitObjectID", "description": "A Git object ID.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "INTERFACE", "name": "RepositoryNode", "description": "Represents a object that belongs to a repository.", "fields": [ { "name": "repository", "description": "The repository associated with this node.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "Repository", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": [ { "kind": "OBJECT", "name": "CommitComment", "ofType": null }, { "kind": "OBJECT", "name": "CommitCommentThread", "ofType": null }, { "kind": "OBJECT", "name": "Issue", "ofType": null }, { "kind": "OBJECT", "name": "IssueComment", "ofType": null }, { "kind": "OBJECT", "name": "PullRequest", "ofType": null }, { "kind": "OBJECT", "name": "PullRequestCommitCommentThread", "ofType": null }, { "kind": "OBJECT", "name": "PullRequestReview", "ofType": null }, { "kind": "OBJECT", "name": "PullRequestReviewComment", "ofType": null } ] }, { "kind": "OBJECT", "name": "Blob", "description": "Represents a Git blob.", "fields": [ { "name": "abbreviatedOid", "description": "An abbreviated version of the Git object ID", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "byteSize", "description": "Byte size of Blob object", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "commitResourcePath", "description": "The HTTP path for this Git object", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "commitUrl", "description": "The HTTP URL for this Git object", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "isBinary", "description": "Indicates whether the Blob is binary or text", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "isTruncated", "description": "Indicates whether the contents is truncated", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "oid", "description": "The Git object ID", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "GitObjectID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "repository", "description": "The Repository the Git object belongs to", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "Repository", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "text", "description": "UTF8 text data or null if the Blob is binary", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null }, { "kind": "INTERFACE", "name": "GitObject", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "Commit", "description": "Represents a Git commit.", "fields": [ { "name": "abbreviatedOid", "description": "An abbreviated version of the Git object ID", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "additions", "description": "The number of additions in this commit.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "associatedPullRequests", "description": "The pull requests associated with a commit", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "orderBy", "description": "Ordering options for pull requests.", "type": { "kind": "INPUT_OBJECT", "name": "PullRequestOrder", "ofType": null }, "defaultValue": "{field:\"CREATED_AT\",direction:\"ASC\"}" } ], "type": { "kind": "OBJECT", "name": "PullRequestConnection", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "author", "description": "Authorship details of the commit.", "args": [], "type": { "kind": "OBJECT", "name": "GitActor", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "authoredByCommitter", "description": "Check if the committer and the author match.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "authoredDate", "description": "The datetime when this commit was authored.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "blame", "description": "Fetches `git blame` information.", "args": [ { "name": "path", "description": "The file whose Git blame information you want.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "Blame", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "changedFiles", "description": "The number of changed files in this commit.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "comments", "description": "Comments made on the commit.", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "CommitCommentConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "commitResourcePath", "description": "The HTTP path for this Git object", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "commitUrl", "description": "The HTTP URL for this Git object", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "committedDate", "description": "The datetime when this commit was committed.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "committedViaWeb", "description": "Check if commited via GitHub web UI.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "committer", "description": "Committership details of the commit.", "args": [], "type": { "kind": "OBJECT", "name": "GitActor", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "deletions", "description": "The number of deletions in this commit.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "deployments", "description": "The deployments associated with a commit.", "args": [ { "name": "environments", "description": "Environments to list deployments for", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } } }, "defaultValue": null }, { "name": "orderBy", "description": "Ordering options for deployments returned from the connection.", "type": { "kind": "INPUT_OBJECT", "name": "DeploymentOrder", "ofType": null }, "defaultValue": "{field:\"CREATED_AT\",direction:\"ASC\"}" }, { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "DeploymentConnection", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "history", "description": "The linear commit history starting from (and including) this commit, in the same order as `git log`.", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "path", "description": "If non-null, filters history to only show commits touching files under this path.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "author", "description": "If non-null, filters history to only show commits with matching authorship.", "type": { "kind": "INPUT_OBJECT", "name": "CommitAuthor", "ofType": null }, "defaultValue": null }, { "name": "since", "description": "Allows specifying a beginning time or date for fetching commits.", "type": { "kind": "SCALAR", "name": "GitTimestamp", "ofType": null }, "defaultValue": null }, { "name": "until", "description": "Allows specifying an ending time or date for fetching commits.", "type": { "kind": "SCALAR", "name": "GitTimestamp", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "CommitHistoryConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "message", "description": "The Git commit message", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "messageBody", "description": "The Git commit message body", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "messageBodyHTML", "description": "The commit message body rendered to HTML.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "HTML", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "messageHeadline", "description": "The Git commit message headline", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "messageHeadlineHTML", "description": "The commit message headline rendered to HTML.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "HTML", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "oid", "description": "The Git object ID", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "GitObjectID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "parents", "description": "The parents of a commit.", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "CommitConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pushedDate", "description": "The datetime when this commit was pushed.", "args": [], "type": { "kind": "SCALAR", "name": "DateTime", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "repository", "description": "The Repository this commit belongs to", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "Repository", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "resourcePath", "description": "The HTTP path for this commit", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "signature", "description": "Commit signing information, if present.", "args": [], "type": { "kind": "INTERFACE", "name": "GitSignature", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "status", "description": "Status information for this commit", "args": [], "type": { "kind": "OBJECT", "name": "Status", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "tarballUrl", "description": "Returns a URL to download a tarball archive for a repository.\nNote: For private repositories, these links are temporary and expire after five minutes.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "tree", "description": "Commit's root Tree", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "Tree", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "treeResourcePath", "description": "The HTTP path for the tree of this commit", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "treeUrl", "description": "The HTTP URL for the tree of this commit", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "url", "description": "The HTTP URL for this commit", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerCanSubscribe", "description": "Check if the viewer is able to change their subscription status for the repository.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerSubscription", "description": "Identifies if the viewer is watching, not watching, or ignoring the subscribable entity.", "args": [], "type": { "kind": "ENUM", "name": "SubscriptionState", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "zipballUrl", "description": "Returns a URL to download a zipball archive for a repository.\nNote: For private repositories, these links are temporary and expire after five minutes.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null }, { "kind": "INTERFACE", "name": "GitObject", "ofType": null }, { "kind": "INTERFACE", "name": "Subscribable", "ofType": null }, { "kind": "INTERFACE", "name": "UniformResourceLocatable", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "INTERFACE", "name": "Subscribable", "description": "Entities that can be subscribed to for web and email notifications.", "fields": [ { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerCanSubscribe", "description": "Check if the viewer is able to change their subscription status for the repository.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerSubscription", "description": "Identifies if the viewer is watching, not watching, or ignoring the subscribable entity.", "args": [], "type": { "kind": "ENUM", "name": "SubscriptionState", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": [ { "kind": "OBJECT", "name": "Commit", "ofType": null }, { "kind": "OBJECT", "name": "Issue", "ofType": null }, { "kind": "OBJECT", "name": "PullRequest", "ofType": null }, { "kind": "OBJECT", "name": "Repository", "ofType": null }, { "kind": "OBJECT", "name": "Team", "ofType": null } ] }, { "kind": "ENUM", "name": "SubscriptionState", "description": "The possible states of a subscription.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "UNSUBSCRIBED", "description": "The User is only notified when participating or @mentioned.", "isDeprecated": false, "deprecationReason": null }, { "name": "SUBSCRIBED", "description": "The User is notified of all conversations.", "isDeprecated": false, "deprecationReason": null }, { "name": "IGNORED", "description": "The User is never notified.", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null }, { "kind": "OBJECT", "name": "Tree", "description": "Represents a Git tree.", "fields": [ { "name": "abbreviatedOid", "description": "An abbreviated version of the Git object ID", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "commitResourcePath", "description": "The HTTP path for this Git object", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "commitUrl", "description": "The HTTP URL for this Git object", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "entries", "description": "A list of tree entries.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "TreeEntry", "ofType": null } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "oid", "description": "The Git object ID", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "GitObjectID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "repository", "description": "The Repository the Git object belongs to", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "Repository", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null }, { "kind": "INTERFACE", "name": "GitObject", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "TreeEntry", "description": "Represents a Git tree entry.", "fields": [ { "name": "mode", "description": "Entry file mode.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "name", "description": "Entry file name.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "object", "description": "Entry file object.", "args": [], "type": { "kind": "INTERFACE", "name": "GitObject", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "oid", "description": "Entry file Git object ID.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "GitObjectID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "repository", "description": "The Repository the tree entry belongs to", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "Repository", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "type", "description": "Entry file type.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "GitActor", "description": "Represents an actor in a Git commit (ie. an author or committer).", "fields": [ { "name": "avatarUrl", "description": "A URL pointing to the author's public avatar.", "args": [ { "name": "size", "description": "The size of the resulting square image.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "date", "description": "The timestamp of the Git action (authoring or committing).", "args": [], "type": { "kind": "SCALAR", "name": "GitTimestamp", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "email", "description": "The email in the Git commit.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "name", "description": "The name in the Git commit.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "user", "description": "The GitHub user corresponding to the email field. Null if no such user exists.", "args": [], "type": { "kind": "OBJECT", "name": "User", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "SCALAR", "name": "GitTimestamp", "description": "An ISO-8601 encoded date string. Unlike the DateTime type, GitTimestamp is not converted in UTC.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "CommitConnection", "description": "The connection type for Commit.", "fields": [ { "name": "edges", "description": "A list of edges.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "CommitEdge", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "nodes", "description": "A list of nodes.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "Commit", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pageInfo", "description": "Information to aid in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PageInfo", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "totalCount", "description": "Identifies the total count of items in the connection.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "CommitEdge", "description": "An edge in a connection.", "fields": [ { "name": "cursor", "description": "A cursor for use in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "node", "description": "The item at the end of the edge.", "args": [], "type": { "kind": "OBJECT", "name": "Commit", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "CommitHistoryConnection", "description": "The connection type for Commit.", "fields": [ { "name": "edges", "description": "A list of edges.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "CommitEdge", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "nodes", "description": "A list of nodes.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "Commit", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pageInfo", "description": "Information to aid in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PageInfo", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "totalCount", "description": "Identifies the total count of items in the connection.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "CommitAuthor", "description": "Specifies an author for filtering Git commits.", "fields": null, "inputFields": [ { "name": "id", "description": "ID of a User to filter by. If non-null, only commits authored by this user will be returned. This field takes precedence over emails.", "type": { "kind": "SCALAR", "name": "ID", "ofType": null }, "defaultValue": null }, { "name": "emails", "description": "Email addresses to filter by. Commits authored by any of the specified email addresses will be returned.", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } } }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "CommitCommentConnection", "description": "The connection type for CommitComment.", "fields": [ { "name": "edges", "description": "A list of edges.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "CommitCommentEdge", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "nodes", "description": "A list of nodes.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "CommitComment", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pageInfo", "description": "Information to aid in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PageInfo", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "totalCount", "description": "Identifies the total count of items in the connection.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "CommitCommentEdge", "description": "An edge in a connection.", "fields": [ { "name": "cursor", "description": "A cursor for use in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "node", "description": "The item at the end of the edge.", "args": [], "type": { "kind": "OBJECT", "name": "CommitComment", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "CommitComment", "description": "Represents a comment on a given Commit.", "fields": [ { "name": "author", "description": "The actor who authored the comment.", "args": [], "type": { "kind": "INTERFACE", "name": "Actor", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "authorAssociation", "description": "Author's association with the subject of the comment.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "CommentAuthorAssociation", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "body", "description": "Identifies the comment body.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "bodyHTML", "description": "Identifies the comment body rendered to HTML.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "HTML", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "bodyText", "description": "The body rendered to text.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "commit", "description": "Identifies the commit associated with the comment, if the commit exists.", "args": [], "type": { "kind": "OBJECT", "name": "Commit", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "createdAt", "description": "Identifies the date and time when the object was created.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "createdViaEmail", "description": "Check if this comment was created via an email reply.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "databaseId", "description": "Identifies the primary key from the database.", "args": [], "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "editor", "description": "The actor who edited the comment.", "args": [], "type": { "kind": "INTERFACE", "name": "Actor", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "includesCreatedEdit", "description": "Check if this comment was edited and includes an edit with the creation data", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "isMinimized", "description": "Returns whether or not a comment has been minimized.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "lastEditedAt", "description": "The moment the editor made the last edit", "args": [], "type": { "kind": "SCALAR", "name": "DateTime", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "minimizedReason", "description": "Returns why the comment was minimized.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "path", "description": "Identifies the file path associated with the comment.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "position", "description": "Identifies the line position associated with the comment.", "args": [], "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "publishedAt", "description": "Identifies when the comment was published at.", "args": [], "type": { "kind": "SCALAR", "name": "DateTime", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "reactionGroups", "description": "A list of reactions grouped by content left on the subject.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "ReactionGroup", "ofType": null } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "reactions", "description": "A list of Reactions left on the Issue.", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "content", "description": "Allows filtering Reactions by emoji.", "type": { "kind": "ENUM", "name": "ReactionContent", "ofType": null }, "defaultValue": null }, { "name": "orderBy", "description": "Allows specifying the order in which reactions are returned.", "type": { "kind": "INPUT_OBJECT", "name": "ReactionOrder", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "ReactionConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "repository", "description": "The repository associated with this node.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "Repository", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "resourcePath", "description": "The HTTP path permalink for this commit comment.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "updatedAt", "description": "Identifies the date and time when the object was last updated.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "url", "description": "The HTTP URL permalink for this commit comment.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "userContentEdits", "description": "A list of edits to this content.", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "UserContentEditConnection", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerCanDelete", "description": "Check if the current viewer can delete this object.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerCanMinimize", "description": "Check if the current viewer can minimize this object.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerCanReact", "description": "Can user react to this subject", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerCanUpdate", "description": "Check if the current viewer can update this object.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerCannotUpdateReasons", "description": "Reasons why the current viewer can not update this comment.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "CommentCannotUpdateReason", "ofType": null } } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerDidAuthor", "description": "Did the viewer author this comment.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null }, { "kind": "INTERFACE", "name": "Comment", "ofType": null }, { "kind": "INTERFACE", "name": "Deletable", "ofType": null }, { "kind": "INTERFACE", "name": "Updatable", "ofType": null }, { "kind": "INTERFACE", "name": "UpdatableComment", "ofType": null }, { "kind": "INTERFACE", "name": "Reactable", "ofType": null }, { "kind": "INTERFACE", "name": "RepositoryNode", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "INTERFACE", "name": "GitSignature", "description": "Information about a signature (GPG or S/MIME) on a Commit or Tag.", "fields": [ { "name": "email", "description": "Email used to sign this object.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "isValid", "description": "True if the signature is valid and verified by GitHub.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "payload", "description": "Payload for GPG signing object. Raw ODB object without the signature header.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "signature", "description": "ASCII-armored signature header from object.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "signer", "description": "GitHub user corresponding to the email signing this commit.", "args": [], "type": { "kind": "OBJECT", "name": "User", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "state", "description": "The state of this signature. `VALID` if signature is valid and verified by GitHub, otherwise represents reason why signature is considered invalid.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "GitSignatureState", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "wasSignedByGitHub", "description": "True if the signature was made with GitHub's signing key.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": [ { "kind": "OBJECT", "name": "GpgSignature", "ofType": null }, { "kind": "OBJECT", "name": "SmimeSignature", "ofType": null }, { "kind": "OBJECT", "name": "UnknownSignature", "ofType": null } ] }, { "kind": "ENUM", "name": "GitSignatureState", "description": "The state of a Git signature.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "VALID", "description": "Valid signature and verified by GitHub", "isDeprecated": false, "deprecationReason": null }, { "name": "INVALID", "description": "Invalid signature", "isDeprecated": false, "deprecationReason": null }, { "name": "MALFORMED_SIG", "description": "Malformed signature", "isDeprecated": false, "deprecationReason": null }, { "name": "UNKNOWN_KEY", "description": "Key used for signing not known to GitHub", "isDeprecated": false, "deprecationReason": null }, { "name": "BAD_EMAIL", "description": "Invalid email used for signing", "isDeprecated": false, "deprecationReason": null }, { "name": "UNVERIFIED_EMAIL", "description": "Email used for signing unverified on GitHub", "isDeprecated": false, "deprecationReason": null }, { "name": "NO_USER", "description": "Email used for signing not known to GitHub", "isDeprecated": false, "deprecationReason": null }, { "name": "UNKNOWN_SIG_TYPE", "description": "Unknown signature type", "isDeprecated": false, "deprecationReason": null }, { "name": "UNSIGNED", "description": "Unsigned", "isDeprecated": false, "deprecationReason": null }, { "name": "GPGVERIFY_UNAVAILABLE", "description": "Internal error - the GPG verification service is unavailable at the moment", "isDeprecated": false, "deprecationReason": null }, { "name": "GPGVERIFY_ERROR", "description": "Internal error - the GPG verification service misbehaved", "isDeprecated": false, "deprecationReason": null }, { "name": "NOT_SIGNING_KEY", "description": "The usage flags for the key that signed this don't allow signing", "isDeprecated": false, "deprecationReason": null }, { "name": "EXPIRED_KEY", "description": "Signing key expired", "isDeprecated": false, "deprecationReason": null }, { "name": "OCSP_PENDING", "description": "Valid signature, pending certificate revocation checking", "isDeprecated": false, "deprecationReason": null }, { "name": "OCSP_ERROR", "description": "Valid siganture, though certificate revocation check failed", "isDeprecated": false, "deprecationReason": null }, { "name": "BAD_CERT", "description": "The signing certificate or its chain could not be verified", "isDeprecated": false, "deprecationReason": null }, { "name": "OCSP_REVOKED", "description": "One or more certificates in chain has been revoked", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null }, { "kind": "OBJECT", "name": "Status", "description": "Represents a commit status.", "fields": [ { "name": "commit", "description": "The commit this status is attached to.", "args": [], "type": { "kind": "OBJECT", "name": "Commit", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "context", "description": "Looks up an individual status context by context name.", "args": [ { "name": "name", "description": "The context name.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "StatusContext", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "contexts", "description": "The individual status contexts for this commit.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "StatusContext", "ofType": null } } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "state", "description": "The combined commit status.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "StatusState", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "ENUM", "name": "StatusState", "description": "The possible commit status states.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "EXPECTED", "description": "Status is expected.", "isDeprecated": false, "deprecationReason": null }, { "name": "ERROR", "description": "Status is errored.", "isDeprecated": false, "deprecationReason": null }, { "name": "FAILURE", "description": "Status is failing.", "isDeprecated": false, "deprecationReason": null }, { "name": "PENDING", "description": "Status is pending.", "isDeprecated": false, "deprecationReason": null }, { "name": "SUCCESS", "description": "Status is successful.", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null }, { "kind": "OBJECT", "name": "StatusContext", "description": "Represents an individual commit status context", "fields": [ { "name": "commit", "description": "This commit this status context is attached to.", "args": [], "type": { "kind": "OBJECT", "name": "Commit", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "context", "description": "The name of this status context.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "createdAt", "description": "Identifies the date and time when the object was created.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "creator", "description": "The actor who created this status context.", "args": [], "type": { "kind": "INTERFACE", "name": "Actor", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "description", "description": "The description for this status context.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "state", "description": "The state of this status context.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "StatusState", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "targetUrl", "description": "The URL for this status context.", "args": [], "type": { "kind": "SCALAR", "name": "URI", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "ENUM", "name": "PullRequestState", "description": "The possible states of a pull request.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "OPEN", "description": "A pull request that is still open.", "isDeprecated": false, "deprecationReason": null }, { "name": "CLOSED", "description": "A pull request that has been closed without being merged.", "isDeprecated": false, "deprecationReason": null }, { "name": "MERGED", "description": "A pull request that has been closed by being merged.", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null }, { "kind": "OBJECT", "name": "Blame", "description": "Represents a Git blame.", "fields": [ { "name": "ranges", "description": "The list of ranges from a Git blame.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "BlameRange", "ofType": null } } } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "BlameRange", "description": "Represents a range of information from a Git blame.", "fields": [ { "name": "age", "description": "Identifies the recency of the change, from 1 (new) to 10 (old). This is calculated as a 2-quantile and determines the length of distance between the median age of all the changes in the file and the recency of the current range's change.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "commit", "description": "Identifies the line author", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "Commit", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "endingLine", "description": "The ending line for the range", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "startingLine", "description": "The starting line for the range", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "DeploymentConnection", "description": "The connection type for Deployment.", "fields": [ { "name": "edges", "description": "A list of edges.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "DeploymentEdge", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "nodes", "description": "A list of nodes.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "Deployment", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pageInfo", "description": "Information to aid in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PageInfo", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "totalCount", "description": "Identifies the total count of items in the connection.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "DeploymentEdge", "description": "An edge in a connection.", "fields": [ { "name": "cursor", "description": "A cursor for use in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "node", "description": "The item at the end of the edge.", "args": [], "type": { "kind": "OBJECT", "name": "Deployment", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "Deployment", "description": "Represents triggered deployment instance.", "fields": [ { "name": "commit", "description": "Identifies the commit sha of the deployment.", "args": [], "type": { "kind": "OBJECT", "name": "Commit", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "commitOid", "description": "Identifies the oid of the deployment commit, even if the commit has been deleted.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "createdAt", "description": "Identifies the date and time when the object was created.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "creator", "description": "Identifies the actor who triggered the deployment.", "args": [], "type": { "kind": "INTERFACE", "name": "Actor", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "databaseId", "description": "Identifies the primary key from the database.", "args": [], "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "description", "description": "The deployment description.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "environment", "description": "The environment to which this deployment was made.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "latestStatus", "description": "The latest status of this deployment.", "args": [], "type": { "kind": "OBJECT", "name": "DeploymentStatus", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "payload", "description": "Extra information that a deployment system might need.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "ref", "description": "Identifies the Ref of the deployment, if the deployment was created by ref.", "args": [], "type": { "kind": "OBJECT", "name": "Ref", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "repository", "description": "Identifies the repository associated with the deployment.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "Repository", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "state", "description": "The current state of the deployment.", "args": [], "type": { "kind": "ENUM", "name": "DeploymentState", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "statuses", "description": "A list of statuses associated with the deployment.", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "DeploymentStatusConnection", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "task", "description": "The deployment task.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "updatedAt", "description": "Identifies the date and time when the object was last updated.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "DeploymentStatusConnection", "description": "The connection type for DeploymentStatus.", "fields": [ { "name": "edges", "description": "A list of edges.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "DeploymentStatusEdge", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "nodes", "description": "A list of nodes.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "DeploymentStatus", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pageInfo", "description": "Information to aid in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PageInfo", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "totalCount", "description": "Identifies the total count of items in the connection.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "DeploymentStatusEdge", "description": "An edge in a connection.", "fields": [ { "name": "cursor", "description": "A cursor for use in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "node", "description": "The item at the end of the edge.", "args": [], "type": { "kind": "OBJECT", "name": "DeploymentStatus", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "DeploymentStatus", "description": "Describes the status of a given deployment attempt.", "fields": [ { "name": "createdAt", "description": "Identifies the date and time when the object was created.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "creator", "description": "Identifies the actor who triggered the deployment.", "args": [], "type": { "kind": "INTERFACE", "name": "Actor", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "deployment", "description": "Identifies the deployment associated with status.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "Deployment", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "description", "description": "Identifies the description of the deployment.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "environmentUrl", "description": "Identifies the environment URL of the deployment.", "args": [], "type": { "kind": "SCALAR", "name": "URI", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "logUrl", "description": "Identifies the log URL of the deployment.", "args": [], "type": { "kind": "SCALAR", "name": "URI", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "state", "description": "Identifies the current state of the deployment.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "DeploymentStatusState", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "updatedAt", "description": "Identifies the date and time when the object was last updated.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "ENUM", "name": "DeploymentStatusState", "description": "The possible states for a deployment status.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "PENDING", "description": "The deployment is pending.", "isDeprecated": false, "deprecationReason": null }, { "name": "SUCCESS", "description": "The deployment was successful.", "isDeprecated": false, "deprecationReason": null }, { "name": "FAILURE", "description": "The deployment has failed.", "isDeprecated": false, "deprecationReason": null }, { "name": "INACTIVE", "description": "The deployment is inactive.", "isDeprecated": false, "deprecationReason": null }, { "name": "ERROR", "description": "The deployment experienced an error.", "isDeprecated": false, "deprecationReason": null }, { "name": "QUEUED", "description": "The deployment is queued", "isDeprecated": false, "deprecationReason": null }, { "name": "IN_PROGRESS", "description": "The deployment is in progress.", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null }, { "kind": "ENUM", "name": "DeploymentState", "description": "The possible states in which a deployment can be.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "ABANDONED", "description": "The pending deployment was not updated after 30 minutes.", "isDeprecated": false, "deprecationReason": null }, { "name": "ACTIVE", "description": "The deployment is currently active.", "isDeprecated": false, "deprecationReason": null }, { "name": "DESTROYED", "description": "An inactive transient deployment.", "isDeprecated": false, "deprecationReason": null }, { "name": "ERROR", "description": "The deployment experienced an error.", "isDeprecated": false, "deprecationReason": null }, { "name": "FAILURE", "description": "The deployment has failed.", "isDeprecated": false, "deprecationReason": null }, { "name": "INACTIVE", "description": "The deployment is inactive.", "isDeprecated": false, "deprecationReason": null }, { "name": "PENDING", "description": "The deployment is pending.", "isDeprecated": false, "deprecationReason": null }, { "name": "QUEUED", "description": "The deployment has queued", "isDeprecated": false, "deprecationReason": null }, { "name": "IN_PROGRESS", "description": "The deployment is in progress.", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "DeploymentOrder", "description": "Ordering options for deployment connections", "fields": null, "inputFields": [ { "name": "field", "description": "The field to order deployments by.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "DeploymentOrderField", "ofType": null } }, "defaultValue": null }, { "name": "direction", "description": "The ordering direction.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "OrderDirection", "ofType": null } }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "ENUM", "name": "DeploymentOrderField", "description": "Properties by which deployment connections can be ordered.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "CREATED_AT", "description": "Order collection by creation time", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "PullRequestOrder", "description": "Ways in which lists of issues can be ordered upon return.", "fields": null, "inputFields": [ { "name": "field", "description": "The field in which to order pull requests by.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "PullRequestOrderField", "ofType": null } }, "defaultValue": null }, { "name": "direction", "description": "The direction in which to order pull requests by the specified field.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "OrderDirection", "ofType": null } }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "ENUM", "name": "PullRequestOrderField", "description": "Properties by which pull_requests connections can be ordered.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "CREATED_AT", "description": "Order pull_requests by creation time", "isDeprecated": false, "deprecationReason": null }, { "name": "UPDATED_AT", "description": "Order pull_requests by update time", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null }, { "kind": "OBJECT", "name": "ReleaseAssetConnection", "description": "The connection type for ReleaseAsset.", "fields": [ { "name": "edges", "description": "A list of edges.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "ReleaseAssetEdge", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "nodes", "description": "A list of nodes.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "ReleaseAsset", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pageInfo", "description": "Information to aid in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PageInfo", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "totalCount", "description": "Identifies the total count of items in the connection.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "ReleaseAssetEdge", "description": "An edge in a connection.", "fields": [ { "name": "cursor", "description": "A cursor for use in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "node", "description": "The item at the end of the edge.", "args": [], "type": { "kind": "OBJECT", "name": "ReleaseAsset", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "ReleaseAsset", "description": "A release asset contains the content for a release asset.", "fields": [ { "name": "contentType", "description": "The asset's content-type", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "createdAt", "description": "Identifies the date and time when the object was created.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "downloadCount", "description": "The number of times this asset was downloaded", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "downloadUrl", "description": "Identifies the URL where you can download the release asset via the browser.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "name", "description": "Identifies the title of the release asset.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "release", "description": "Release that the asset is associated with", "args": [], "type": { "kind": "OBJECT", "name": "Release", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "size", "description": "The size (in bytes) of the asset", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "updatedAt", "description": "Identifies the date and time when the object was last updated.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "uploadedBy", "description": "The user that performed the upload", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "User", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "url", "description": "Identifies the URL of the release asset.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "MarketplaceCategory", "description": "A public description of a Marketplace category.", "fields": [ { "name": "description", "description": "The category's description.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "howItWorks", "description": "The technical description of how apps listed in this category work with GitHub.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "name", "description": "The category's name.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "primaryListingCount", "description": "How many Marketplace listings have this as their primary category.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "resourcePath", "description": "The HTTP path for this Marketplace category.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "secondaryListingCount", "description": "How many Marketplace listings have this as their secondary category.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "slug", "description": "The short name of the category used in its URL.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "url", "description": "The HTTP URL for this Marketplace category.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "MarketplaceListingConnection", "description": "Look up Marketplace Listings", "fields": [ { "name": "edges", "description": "A list of edges.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "MarketplaceListingEdge", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "nodes", "description": "A list of nodes.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "MarketplaceListing", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pageInfo", "description": "Information to aid in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PageInfo", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "totalCount", "description": "Identifies the total count of items in the connection.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "MarketplaceListingEdge", "description": "An edge in a connection.", "fields": [ { "name": "cursor", "description": "A cursor for use in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "node", "description": "The item at the end of the edge.", "args": [], "type": { "kind": "OBJECT", "name": "MarketplaceListing", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "ReleaseConnection", "description": "The connection type for Release.", "fields": [ { "name": "edges", "description": "A list of edges.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "ReleaseEdge", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "nodes", "description": "A list of nodes.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "Release", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pageInfo", "description": "Information to aid in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PageInfo", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "totalCount", "description": "Identifies the total count of items in the connection.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "ReleaseEdge", "description": "An edge in a connection.", "fields": [ { "name": "cursor", "description": "A cursor for use in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "node", "description": "The item at the end of the edge.", "args": [], "type": { "kind": "OBJECT", "name": "Release", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "ReleaseOrder", "description": "Ways in which lists of releases can be ordered upon return.", "fields": null, "inputFields": [ { "name": "field", "description": "The field in which to order releases by.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "ReleaseOrderField", "ofType": null } }, "defaultValue": null }, { "name": "direction", "description": "The direction in which to order releases by the specified field.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "OrderDirection", "ofType": null } }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "ENUM", "name": "ReleaseOrderField", "description": "Properties by which release connections can be ordered.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "CREATED_AT", "description": "Order releases by creation time", "isDeprecated": false, "deprecationReason": null }, { "name": "NAME", "description": "Order releases alphabetically by name", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null }, { "kind": "ENUM", "name": "IssuePubSubTopic", "description": "The possible PubSub channels for an issue.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "UPDATED", "description": "The channel ID for observing issue updates.", "isDeprecated": false, "deprecationReason": null }, { "name": "MARKASREAD", "description": "The channel ID for marking an issue as read.", "isDeprecated": false, "deprecationReason": null }, { "name": "TIMELINE", "description": "The channel ID for updating items on the issue timeline.", "isDeprecated": false, "deprecationReason": null }, { "name": "STATE", "description": "The channel ID for observing issue state updates.", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null }, { "kind": "OBJECT", "name": "OrganizationConnection", "description": "The connection type for Organization.", "fields": [ { "name": "edges", "description": "A list of edges.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "OrganizationEdge", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "nodes", "description": "A list of nodes.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "Organization", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pageInfo", "description": "Information to aid in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PageInfo", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "totalCount", "description": "Identifies the total count of items in the connection.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "OrganizationEdge", "description": "An edge in a connection.", "fields": [ { "name": "cursor", "description": "A cursor for use in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "node", "description": "The item at the end of the edge.", "args": [], "type": { "kind": "OBJECT", "name": "Organization", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "OrganizationInvitation", "description": "An Invitation for a user to an organization.", "fields": [ { "name": "createdAt", "description": "Identifies the date and time when the object was created.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "email", "description": "The email address of the user invited to the organization.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "invitationType", "description": "The type of invitation that was sent (e.g. email, user).", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "OrganizationInvitationType", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "invitee", "description": "The user who was invited to the organization.", "args": [], "type": { "kind": "OBJECT", "name": "User", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "inviter", "description": "The user who created the invitation.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "User", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "organization", "description": "The organization the invite is for", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "Organization", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "role", "description": "The user's pending role in the organization (e.g. member, owner).", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "OrganizationInvitationRole", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "ENUM", "name": "OrganizationInvitationType", "description": "The possible organization invitation types.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "USER", "description": "The invitation was to an existing user.", "isDeprecated": false, "deprecationReason": null }, { "name": "EMAIL", "description": "The invitation was to an email address.", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null }, { "kind": "ENUM", "name": "OrganizationInvitationRole", "description": "The possible organization invitation roles.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "DIRECT_MEMBER", "description": "The user is invited to be a direct member of the organization.", "isDeprecated": false, "deprecationReason": null }, { "name": "ADMIN", "description": "The user is invited to be an admin of the organization.", "isDeprecated": false, "deprecationReason": null }, { "name": "BILLING_MANAGER", "description": "The user is invited to be a billing manager of the organization.", "isDeprecated": false, "deprecationReason": null }, { "name": "REINSTATE", "description": "The user's previous role will be reinstated.", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null }, { "kind": "OBJECT", "name": "TeamConnection", "description": "The connection type for Team.", "fields": [ { "name": "edges", "description": "A list of edges.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "TeamEdge", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "nodes", "description": "A list of nodes.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "Team", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pageInfo", "description": "Information to aid in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PageInfo", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "totalCount", "description": "Identifies the total count of items in the connection.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "TeamEdge", "description": "An edge in a connection.", "fields": [ { "name": "cursor", "description": "A cursor for use in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "node", "description": "The item at the end of the edge.", "args": [], "type": { "kind": "OBJECT", "name": "Team", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "Team", "description": "A team of users in an organization.", "fields": [ { "name": "ancestors", "description": "A list of teams that are ancestors of this team.", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "TeamConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "avatarUrl", "description": "A URL pointing to the team's avatar.", "args": [ { "name": "size", "description": "The size in pixels of the resulting square image.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": "400" } ], "type": { "kind": "SCALAR", "name": "URI", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "childTeams", "description": "List of child teams belonging to this team", "args": [ { "name": "orderBy", "description": "Order for connection", "type": { "kind": "INPUT_OBJECT", "name": "TeamOrder", "ofType": null }, "defaultValue": null }, { "name": "userLogins", "description": "User logins to filter by", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } } }, "defaultValue": null }, { "name": "immediateOnly", "description": "Whether to list immediate child teams or all descendant child teams.", "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": "true" }, { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "TeamConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "combinedSlug", "description": "The slug corresponding to the organization and team.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "createdAt", "description": "Identifies the date and time when the object was created.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "description", "description": "The description of the team.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "editTeamResourcePath", "description": "The HTTP path for editing this team", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "editTeamUrl", "description": "The HTTP URL for editing this team", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "invitations", "description": "A list of pending invitations for users to this team", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "OrganizationInvitationConnection", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "memberStatuses", "description": "Get the status messages members of this entity have set that are either public or visible only to the organization.", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "orderBy", "description": "Ordering options for user statuses returned from the connection.", "type": { "kind": "INPUT_OBJECT", "name": "UserStatusOrder", "ofType": null }, "defaultValue": "{field:\"UPDATED_AT\",direction:\"DESC\"}" } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "UserStatusConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "members", "description": "A list of users who are members of this team.", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "query", "description": "The search string to look for.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "membership", "description": "Filter by membership type", "type": { "kind": "ENUM", "name": "TeamMembershipType", "ofType": null }, "defaultValue": "ALL" }, { "name": "role", "description": "Filter by team member role", "type": { "kind": "ENUM", "name": "TeamMemberRole", "ofType": null }, "defaultValue": null }, { "name": "orderBy", "description": "Order for the connection.", "type": { "kind": "INPUT_OBJECT", "name": "TeamMemberOrder", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "TeamMemberConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "membersResourcePath", "description": "The HTTP path for the team' members", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "membersUrl", "description": "The HTTP URL for the team' members", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "name", "description": "The name of the team.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "newTeamResourcePath", "description": "The HTTP path creating a new team", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "newTeamUrl", "description": "The HTTP URL creating a new team", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "organization", "description": "The organization that owns this team.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "Organization", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "parentTeam", "description": "The parent team of the team.", "args": [], "type": { "kind": "OBJECT", "name": "Team", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "privacy", "description": "The level of privacy the team has.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "TeamPrivacy", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "repositories", "description": "A list of repositories this team has access to.", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "query", "description": "The search string to look for.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "orderBy", "description": "Order for the connection.", "type": { "kind": "INPUT_OBJECT", "name": "TeamRepositoryOrder", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "TeamRepositoryConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "repositoriesResourcePath", "description": "The HTTP path for this team's repositories", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "repositoriesUrl", "description": "The HTTP URL for this team's repositories", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "resourcePath", "description": "The HTTP path for this team", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "slug", "description": "The slug corresponding to the team.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "teamsResourcePath", "description": "The HTTP path for this team's teams", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "teamsUrl", "description": "The HTTP URL for this team's teams", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "updatedAt", "description": "Identifies the date and time when the object was last updated.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "url", "description": "The HTTP URL for this team", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerCanAdminister", "description": "Team is adminable by the viewer.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerCanSubscribe", "description": "Check if the viewer is able to change their subscription status for the repository.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerSubscription", "description": "Identifies if the viewer is watching, not watching, or ignoring the subscribable entity.", "args": [], "type": { "kind": "ENUM", "name": "SubscriptionState", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null }, { "kind": "INTERFACE", "name": "Subscribable", "ofType": null }, { "kind": "INTERFACE", "name": "MemberStatusable", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "ENUM", "name": "TeamPrivacy", "description": "The possible team privacy values.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "SECRET", "description": "A secret team can only be seen by its members.", "isDeprecated": false, "deprecationReason": null }, { "name": "VISIBLE", "description": "A visible team can be seen and @mentioned by every member of the organization.", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null }, { "kind": "OBJECT", "name": "TeamMemberConnection", "description": "The connection type for User.", "fields": [ { "name": "edges", "description": "A list of edges.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "TeamMemberEdge", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "nodes", "description": "A list of nodes.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "User", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pageInfo", "description": "Information to aid in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PageInfo", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "totalCount", "description": "Identifies the total count of items in the connection.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "TeamMemberEdge", "description": "Represents a user who is a member of a team.", "fields": [ { "name": "cursor", "description": "A cursor for use in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "memberAccessResourcePath", "description": "The HTTP path to the organization's member access page.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "memberAccessUrl", "description": "The HTTP URL to the organization's member access page.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "node", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "User", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "role", "description": "The role the member has on the team.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "TeamMemberRole", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "ENUM", "name": "TeamMemberRole", "description": "The possible team member roles; either 'maintainer' or 'member'.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "MAINTAINER", "description": "A team maintainer has permission to add and remove team members.", "isDeprecated": false, "deprecationReason": null }, { "name": "MEMBER", "description": "A team member has no administrative permissions on the team.", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null }, { "kind": "ENUM", "name": "TeamMembershipType", "description": "Defines which types of team members are included in the returned list. Can be one of IMMEDIATE, CHILD_TEAM or ALL.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "IMMEDIATE", "description": "Includes only immediate members of the team.", "isDeprecated": false, "deprecationReason": null }, { "name": "CHILD_TEAM", "description": "Includes only child team members for the team.", "isDeprecated": false, "deprecationReason": null }, { "name": "ALL", "description": "Includes immediate and child team members for the team.", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "TeamMemberOrder", "description": "Ordering options for team member connections", "fields": null, "inputFields": [ { "name": "field", "description": "The field to order team members by.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "TeamMemberOrderField", "ofType": null } }, "defaultValue": null }, { "name": "direction", "description": "The ordering direction.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "OrderDirection", "ofType": null } }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "ENUM", "name": "TeamMemberOrderField", "description": "Properties by which team member connections can be ordered.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "LOGIN", "description": "Order team members by login", "isDeprecated": false, "deprecationReason": null }, { "name": "CREATED_AT", "description": "Order team members by creation time", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null }, { "kind": "OBJECT", "name": "TeamRepositoryConnection", "description": "The connection type for Repository.", "fields": [ { "name": "edges", "description": "A list of edges.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "TeamRepositoryEdge", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "nodes", "description": "A list of nodes.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "Repository", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pageInfo", "description": "Information to aid in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PageInfo", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "totalCount", "description": "Identifies the total count of items in the connection.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "TeamRepositoryEdge", "description": "Represents a team repository.", "fields": [ { "name": "cursor", "description": "A cursor for use in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "node", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "Repository", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "permission", "description": "The permission level the team has on the repository", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "RepositoryPermission", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "ENUM", "name": "RepositoryPermission", "description": "The access level to a repository", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "ADMIN", "description": "Can read, clone, push, and add collaborators", "isDeprecated": false, "deprecationReason": null }, { "name": "WRITE", "description": "Can read, clone and push", "isDeprecated": false, "deprecationReason": null }, { "name": "READ", "description": "Can read and clone", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "TeamRepositoryOrder", "description": "Ordering options for team repository connections", "fields": null, "inputFields": [ { "name": "field", "description": "The field to order repositories by.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "TeamRepositoryOrderField", "ofType": null } }, "defaultValue": null }, { "name": "direction", "description": "The ordering direction.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "OrderDirection", "ofType": null } }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "ENUM", "name": "TeamRepositoryOrderField", "description": "Properties by which team repository connections can be ordered.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "CREATED_AT", "description": "Order repositories by creation time", "isDeprecated": false, "deprecationReason": null }, { "name": "UPDATED_AT", "description": "Order repositories by update time", "isDeprecated": false, "deprecationReason": null }, { "name": "PUSHED_AT", "description": "Order repositories by push time", "isDeprecated": false, "deprecationReason": null }, { "name": "NAME", "description": "Order repositories by name", "isDeprecated": false, "deprecationReason": null }, { "name": "PERMISSION", "description": "Order repositories by permission", "isDeprecated": false, "deprecationReason": null }, { "name": "STARGAZERS", "description": "Order repositories by number of stargazers", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null }, { "kind": "OBJECT", "name": "OrganizationInvitationConnection", "description": "The connection type for OrganizationInvitation.", "fields": [ { "name": "edges", "description": "A list of edges.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "OrganizationInvitationEdge", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "nodes", "description": "A list of nodes.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "OrganizationInvitation", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pageInfo", "description": "Information to aid in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PageInfo", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "totalCount", "description": "Identifies the total count of items in the connection.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "OrganizationInvitationEdge", "description": "An edge in a connection.", "fields": [ { "name": "cursor", "description": "A cursor for use in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "node", "description": "The item at the end of the edge.", "args": [], "type": { "kind": "OBJECT", "name": "OrganizationInvitation", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "TeamOrder", "description": "Ways in which team connections can be ordered.", "fields": null, "inputFields": [ { "name": "field", "description": "The field in which to order nodes by.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "TeamOrderField", "ofType": null } }, "defaultValue": null }, { "name": "direction", "description": "The direction in which to order nodes.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "OrderDirection", "ofType": null } }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "ENUM", "name": "TeamOrderField", "description": "Properties by which team connections can be ordered.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "NAME", "description": "Allows ordering a list of teams by name.", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null }, { "kind": "ENUM", "name": "DefaultRepositoryPermissionField", "description": "The possible default permissions for repositories.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "NONE", "description": "No access", "isDeprecated": false, "deprecationReason": null }, { "name": "READ", "description": "Can read repos by default", "isDeprecated": false, "deprecationReason": null }, { "name": "WRITE", "description": "Can read and write repos by default", "isDeprecated": false, "deprecationReason": null }, { "name": "ADMIN", "description": "Can read, write, and administrate repos by default", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null }, { "kind": "OBJECT", "name": "ExternalIdentityConnection", "description": "The connection type for ExternalIdentity.", "fields": [ { "name": "edges", "description": "A list of edges.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "ExternalIdentityEdge", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "nodes", "description": "A list of nodes.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "ExternalIdentity", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pageInfo", "description": "Information to aid in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PageInfo", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "totalCount", "description": "Identifies the total count of items in the connection.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "ExternalIdentityEdge", "description": "An edge in a connection.", "fields": [ { "name": "cursor", "description": "A cursor for use in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "node", "description": "The item at the end of the edge.", "args": [], "type": { "kind": "OBJECT", "name": "ExternalIdentity", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "ExternalIdentity", "description": "An external identity provisioned by SAML SSO or SCIM.", "fields": [ { "name": "guid", "description": "The GUID for this identity", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "organizationInvitation", "description": "Organization invitation for this SCIM-provisioned external identity", "args": [], "type": { "kind": "OBJECT", "name": "OrganizationInvitation", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "samlIdentity", "description": "SAML Identity attributes", "args": [], "type": { "kind": "OBJECT", "name": "ExternalIdentitySamlAttributes", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "scimIdentity", "description": "SCIM Identity attributes", "args": [], "type": { "kind": "OBJECT", "name": "ExternalIdentityScimAttributes", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "user", "description": "User linked to this external identity. Will be NULL if this identity has not been claimed by an organization member.", "args": [], "type": { "kind": "OBJECT", "name": "User", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "ExternalIdentitySamlAttributes", "description": "SAML attributes for the External Identity", "fields": [ { "name": "nameId", "description": "The NameID of the SAML identity", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "ExternalIdentityScimAttributes", "description": "SCIM attributes for the External Identity", "fields": [ { "name": "username", "description": "The userName of the SCIM identity", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "PublicKey", "description": "A user's public key.", "fields": [ { "name": "accessedAt", "description": "The last time this authorization was used to perform an action", "args": [], "type": { "kind": "SCALAR", "name": "DateTime", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "createdAt", "description": "Identifies the date and time when the object was created.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "fingerprint", "description": "The fingerprint for this PublicKey", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "isReadOnly", "description": "Whether this PublicKey is read-only or not", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "key", "description": "The public key string", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "updatedAt", "description": "Identifies the date and time when the object was last updated.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "SCALAR", "name": "X509Certificate", "description": "A valid x509 certificate string", "fields": null, "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "ENUM", "name": "IdentityProviderConfigurationState", "description": "The possible states in which authentication can be configured with an identity provider.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "ENFORCED", "description": "Authentication with an identity provider is configured and enforced.", "isDeprecated": false, "deprecationReason": null }, { "name": "CONFIGURED", "description": "Authentication with an identity provider is configured but not enforced.", "isDeprecated": false, "deprecationReason": null }, { "name": "UNCONFIGURED", "description": "Authentication with an identity provider is not configured.", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null }, { "kind": "SCALAR", "name": "Date", "description": "An ISO-8601 encoded date string.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "OrganizationIdentityProvider", "description": "An Identity Provider configured to provision SAML and SCIM identities for Organizations", "fields": [ { "name": "digestMethod", "description": "The digest algorithm used to sign SAML requests for the Identity Provider.", "args": [], "type": { "kind": "SCALAR", "name": "URI", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "externalIdentities", "description": "External Identities provisioned by this Identity Provider", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "ExternalIdentityConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "idpCertificate", "description": "The x509 certificate used by the Identity Provder to sign assertions and responses.", "args": [], "type": { "kind": "SCALAR", "name": "X509Certificate", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "issuer", "description": "The Issuer Entity ID for the SAML Identity Provider", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "organization", "description": "Organization this Identity Provider belongs to", "args": [], "type": { "kind": "OBJECT", "name": "Organization", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "signatureMethod", "description": "The signature algorithm used to sign SAML requests for the Identity Provider.", "args": [], "type": { "kind": "SCALAR", "name": "URI", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "ssoUrl", "description": "The URL endpoint for the Identity Provider's SAML SSO.", "args": [], "type": { "kind": "SCALAR", "name": "URI", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "OrganizationMemberConnection", "description": "The connection type for User.", "fields": [ { "name": "edges", "description": "A list of edges.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "OrganizationMemberEdge", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "nodes", "description": "A list of nodes.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "User", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pageInfo", "description": "Information to aid in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PageInfo", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "totalCount", "description": "Identifies the total count of items in the connection.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "OrganizationMemberEdge", "description": "Represents a user within an organization.", "fields": [ { "name": "cursor", "description": "A cursor for use in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "hasTwoFactorEnabled", "description": "Whether the organization member has two factor enabled or not. Returns null if information is not available to viewer.", "args": [], "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "node", "description": "The item at the end of the edge.", "args": [], "type": { "kind": "OBJECT", "name": "User", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "role", "description": "The role this user has in the organization.", "args": [], "type": { "kind": "ENUM", "name": "OrganizationMemberRole", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "ENUM", "name": "OrganizationMemberRole", "description": "The possible roles within an organization for its members.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "MEMBER", "description": "The user is a member of the organization.", "isDeprecated": false, "deprecationReason": null }, { "name": "ADMIN", "description": "The user is an administrator of the organization.", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null }, { "kind": "ENUM", "name": "TeamRole", "description": "The role of a user on a team.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "ADMIN", "description": "User has admin rights on the team.", "isDeprecated": false, "deprecationReason": null }, { "name": "MEMBER", "description": "User is a member of the team.", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null }, { "kind": "OBJECT", "name": "GistConnection", "description": "The connection type for Gist.", "fields": [ { "name": "edges", "description": "A list of edges.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "GistEdge", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "nodes", "description": "A list of nodes.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "Gist", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pageInfo", "description": "Information to aid in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PageInfo", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "totalCount", "description": "Identifies the total count of items in the connection.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "GistEdge", "description": "An edge in a connection.", "fields": [ { "name": "cursor", "description": "A cursor for use in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "node", "description": "The item at the end of the edge.", "args": [], "type": { "kind": "OBJECT", "name": "Gist", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "ENUM", "name": "GistPrivacy", "description": "The privacy of a Gist", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "PUBLIC", "description": "Public", "isDeprecated": false, "deprecationReason": null }, { "name": "SECRET", "description": "Secret", "isDeprecated": false, "deprecationReason": null }, { "name": "ALL", "description": "Gists that are public and secret", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "GistOrder", "description": "Ordering options for gist connections", "fields": null, "inputFields": [ { "name": "field", "description": "The field to order repositories by.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "GistOrderField", "ofType": null } }, "defaultValue": null }, { "name": "direction", "description": "The ordering direction.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "OrderDirection", "ofType": null } }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "ENUM", "name": "GistOrderField", "description": "Properties by which gist connections can be ordered.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "CREATED_AT", "description": "Order gists by creation time", "isDeprecated": false, "deprecationReason": null }, { "name": "UPDATED_AT", "description": "Order gists by update time", "isDeprecated": false, "deprecationReason": null }, { "name": "PUSHED_AT", "description": "Order gists by push time", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null }, { "kind": "OBJECT", "name": "RepositoryInvitationEdge", "description": "An edge in a connection.", "fields": [ { "name": "cursor", "description": "A cursor for use in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "node", "description": "The item at the end of the edge.", "args": [], "type": { "kind": "OBJECT", "name": "RepositoryInvitation", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "RepositoryInvitation", "description": "An invitation for a user to be added to a repository.", "fields": [ { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "invitee", "description": "The user who received the invitation.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "User", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "inviter", "description": "The user who created the invitation.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "User", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "permission", "description": "The permission granted on this repository by this invitation.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "RepositoryPermission", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "repository", "description": "The Repository the user is invited to.", "args": [], "type": { "kind": "INTERFACE", "name": "RepositoryInfo", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "Mannequin", "description": "A placeholder user for attribution of imported data on GitHub.", "fields": [ { "name": "avatarUrl", "description": "A URL pointing to the GitHub App's public avatar.", "args": [ { "name": "size", "description": "The size of the resulting square image.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "createdAt", "description": "Identifies the date and time when the object was created.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "databaseId", "description": "Identifies the primary key from the database.", "args": [], "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "login", "description": "The username of the actor.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "resourcePath", "description": "The HTML path to this resource.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "updatedAt", "description": "Identifies the date and time when the object was last updated.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "url", "description": "The URL to this resource.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null }, { "kind": "INTERFACE", "name": "Actor", "ofType": null }, { "kind": "INTERFACE", "name": "UniformResourceLocatable", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "LanguageConnection", "description": "A list of languages associated with the parent.", "fields": [ { "name": "edges", "description": "A list of edges.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "LanguageEdge", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "nodes", "description": "A list of nodes.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "Language", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pageInfo", "description": "Information to aid in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PageInfo", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "totalCount", "description": "Identifies the total count of items in the connection.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "totalSize", "description": "The total size in bytes of files written in that language.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "LanguageEdge", "description": "Represents the language of a repository.", "fields": [ { "name": "cursor", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "node", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "Language", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "size", "description": "The number of bytes of code written in the language.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "Milestone", "description": "Represents a Milestone object on a given repository.", "fields": [ { "name": "closed", "description": "`true` if the object is closed (definition of closed may depend on type)", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "closedAt", "description": "Identifies the date and time when the object was closed.", "args": [], "type": { "kind": "SCALAR", "name": "DateTime", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "createdAt", "description": "Identifies the date and time when the object was created.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "creator", "description": "Identifies the actor who created the milestone.", "args": [], "type": { "kind": "INTERFACE", "name": "Actor", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "description", "description": "Identifies the description of the milestone.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "dueOn", "description": "Identifies the due date of the milestone.", "args": [], "type": { "kind": "SCALAR", "name": "DateTime", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "issues", "description": "A list of issues associated with the milestone.", "args": [ { "name": "orderBy", "description": "Ordering options for issues returned from the connection.", "type": { "kind": "INPUT_OBJECT", "name": "IssueOrder", "ofType": null }, "defaultValue": null }, { "name": "labels", "description": "A list of label names to filter the pull requests by.", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } } }, "defaultValue": null }, { "name": "states", "description": "A list of states to filter the issues by.", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "IssueState", "ofType": null } } }, "defaultValue": null }, { "name": "filterBy", "description": "Filtering options for issues returned from the connection.", "type": { "kind": "INPUT_OBJECT", "name": "IssueFilters", "ofType": null }, "defaultValue": null }, { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "IssueConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "number", "description": "Identifies the number of the milestone.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pullRequests", "description": "A list of pull requests associated with the milestone.", "args": [ { "name": "states", "description": "A list of states to filter the pull requests by.", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "PullRequestState", "ofType": null } } }, "defaultValue": null }, { "name": "labels", "description": "A list of label names to filter the pull requests by.", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } } }, "defaultValue": null }, { "name": "headRefName", "description": "The head ref name to filter the pull requests by.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "baseRefName", "description": "The base ref name to filter the pull requests by.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "orderBy", "description": "Ordering options for pull requests returned from the connection.", "type": { "kind": "INPUT_OBJECT", "name": "IssueOrder", "ofType": null }, "defaultValue": null }, { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PullRequestConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "repository", "description": "The repository associated with this milestone.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "Repository", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "resourcePath", "description": "The HTTP path for this milestone", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "state", "description": "Identifies the state of the milestone.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "MilestoneState", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "title", "description": "Identifies the title of the milestone.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "updatedAt", "description": "Identifies the date and time when the object was last updated.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "url", "description": "The HTTP URL for this milestone", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null }, { "kind": "INTERFACE", "name": "Closable", "ofType": null }, { "kind": "INTERFACE", "name": "UniformResourceLocatable", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "ENUM", "name": "MilestoneState", "description": "The possible states of a milestone.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "OPEN", "description": "A milestone that is still open.", "isDeprecated": false, "deprecationReason": null }, { "name": "CLOSED", "description": "A milestone that has been closed.", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null }, { "kind": "OBJECT", "name": "PullRequestChangedFileConnection", "description": "The connection type for PullRequestChangedFile.", "fields": [ { "name": "edges", "description": "A list of edges.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "PullRequestChangedFileEdge", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "nodes", "description": "A list of nodes.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "PullRequestChangedFile", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pageInfo", "description": "Information to aid in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PageInfo", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "totalCount", "description": "Identifies the total count of items in the connection.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "PullRequestChangedFileEdge", "description": "An edge in a connection.", "fields": [ { "name": "cursor", "description": "A cursor for use in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "node", "description": "The item at the end of the edge.", "args": [], "type": { "kind": "OBJECT", "name": "PullRequestChangedFile", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "PullRequestChangedFile", "description": "A file changed in a pull request.", "fields": [ { "name": "additions", "description": "The number of additions to the file.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "deletions", "description": "The number of deletions to the file.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "path", "description": "The path of the file.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "ENUM", "name": "MergeableState", "description": "Whether or not a PullRequest can be merged.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "MERGEABLE", "description": "The pull request can be merged.", "isDeprecated": false, "deprecationReason": null }, { "name": "CONFLICTING", "description": "The pull request cannot be merged due to merge conflicts.", "isDeprecated": false, "deprecationReason": null }, { "name": "UNKNOWN", "description": "The mergeability of the pull request is still being calculated.", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null }, { "kind": "OBJECT", "name": "PullRequestReviewComment", "description": "A review comment associated with a given repository pull request.", "fields": [ { "name": "author", "description": "The actor who authored the comment.", "args": [], "type": { "kind": "INTERFACE", "name": "Actor", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "authorAssociation", "description": "Author's association with the subject of the comment.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "CommentAuthorAssociation", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "body", "description": "The comment body of this review comment.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "bodyHTML", "description": "The comment body of this review comment rendered to HTML.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "HTML", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "bodyText", "description": "The comment body of this review comment rendered as plain text.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "commit", "description": "Identifies the commit associated with the comment.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "Commit", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "createdAt", "description": "Identifies when the comment was created.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "createdViaEmail", "description": "Check if this comment was created via an email reply.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "databaseId", "description": "Identifies the primary key from the database.", "args": [], "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "diffHunk", "description": "The diff hunk to which the comment applies.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "draftedAt", "description": "Identifies when the comment was created in a draft state.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "editor", "description": "The actor who edited the comment.", "args": [], "type": { "kind": "INTERFACE", "name": "Actor", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "includesCreatedEdit", "description": "Check if this comment was edited and includes an edit with the creation data", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "isMinimized", "description": "Returns whether or not a comment has been minimized.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "lastEditedAt", "description": "The moment the editor made the last edit", "args": [], "type": { "kind": "SCALAR", "name": "DateTime", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "minimizedReason", "description": "Returns why the comment was minimized.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "originalCommit", "description": "Identifies the original commit associated with the comment.", "args": [], "type": { "kind": "OBJECT", "name": "Commit", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "originalPosition", "description": "The original line index in the diff to which the comment applies.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "outdated", "description": "Identifies when the comment body is outdated", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "path", "description": "The path to which the comment applies.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "position", "description": "The line index in the diff to which the comment applies.", "args": [], "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "publishedAt", "description": "Identifies when the comment was published at.", "args": [], "type": { "kind": "SCALAR", "name": "DateTime", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "pullRequest", "description": "The pull request associated with this review comment.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PullRequest", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pullRequestReview", "description": "The pull request review associated with this review comment.", "args": [], "type": { "kind": "OBJECT", "name": "PullRequestReview", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "reactionGroups", "description": "A list of reactions grouped by content left on the subject.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "ReactionGroup", "ofType": null } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "reactions", "description": "A list of Reactions left on the Issue.", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "content", "description": "Allows filtering Reactions by emoji.", "type": { "kind": "ENUM", "name": "ReactionContent", "ofType": null }, "defaultValue": null }, { "name": "orderBy", "description": "Allows specifying the order in which reactions are returned.", "type": { "kind": "INPUT_OBJECT", "name": "ReactionOrder", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "ReactionConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "replyTo", "description": "The comment this is a reply to.", "args": [], "type": { "kind": "OBJECT", "name": "PullRequestReviewComment", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "repository", "description": "The repository associated with this node.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "Repository", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "resourcePath", "description": "The HTTP path permalink for this review comment.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "state", "description": "Identifies the state of the comment.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "PullRequestReviewCommentState", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "updatedAt", "description": "Identifies when the comment was last updated.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "url", "description": "The HTTP URL permalink for this review comment.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "userContentEdits", "description": "A list of edits to this content.", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "UserContentEditConnection", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerCanDelete", "description": "Check if the current viewer can delete this object.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerCanMinimize", "description": "Check if the current viewer can minimize this object.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerCanReact", "description": "Can user react to this subject", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerCanUpdate", "description": "Check if the current viewer can update this object.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerCannotUpdateReasons", "description": "Reasons why the current viewer can not update this comment.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "CommentCannotUpdateReason", "ofType": null } } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerDidAuthor", "description": "Did the viewer author this comment.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null }, { "kind": "INTERFACE", "name": "Comment", "ofType": null }, { "kind": "INTERFACE", "name": "Deletable", "ofType": null }, { "kind": "INTERFACE", "name": "Updatable", "ofType": null }, { "kind": "INTERFACE", "name": "UpdatableComment", "ofType": null }, { "kind": "INTERFACE", "name": "Reactable", "ofType": null }, { "kind": "INTERFACE", "name": "RepositoryNode", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "PullRequestReview", "description": "A review object for a given pull request.", "fields": [ { "name": "author", "description": "The actor who authored the comment.", "args": [], "type": { "kind": "INTERFACE", "name": "Actor", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "authorAssociation", "description": "Author's association with the subject of the comment.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "CommentAuthorAssociation", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "body", "description": "Identifies the pull request review body.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "bodyHTML", "description": "The body of this review rendered to HTML.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "HTML", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "bodyText", "description": "The body of this review rendered as plain text.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "comments", "description": "A list of review comments for the current pull request review.", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PullRequestReviewCommentConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "commit", "description": "Identifies the commit associated with this pull request review.", "args": [], "type": { "kind": "OBJECT", "name": "Commit", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "createdAt", "description": "Identifies the date and time when the object was created.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "createdViaEmail", "description": "Check if this comment was created via an email reply.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "databaseId", "description": "Identifies the primary key from the database.", "args": [], "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "editor", "description": "The actor who edited the comment.", "args": [], "type": { "kind": "INTERFACE", "name": "Actor", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "includesCreatedEdit", "description": "Check if this comment was edited and includes an edit with the creation data", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "lastEditedAt", "description": "The moment the editor made the last edit", "args": [], "type": { "kind": "SCALAR", "name": "DateTime", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "onBehalfOf", "description": "A list of teams that this review was made on behalf of.", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "TeamConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "publishedAt", "description": "Identifies when the comment was published at.", "args": [], "type": { "kind": "SCALAR", "name": "DateTime", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "pullRequest", "description": "Identifies the pull request associated with this pull request review.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PullRequest", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "reactionGroups", "description": "A list of reactions grouped by content left on the subject.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "ReactionGroup", "ofType": null } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "reactions", "description": "A list of Reactions left on the Issue.", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "content", "description": "Allows filtering Reactions by emoji.", "type": { "kind": "ENUM", "name": "ReactionContent", "ofType": null }, "defaultValue": null }, { "name": "orderBy", "description": "Allows specifying the order in which reactions are returned.", "type": { "kind": "INPUT_OBJECT", "name": "ReactionOrder", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "ReactionConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "repository", "description": "The repository associated with this node.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "Repository", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "resourcePath", "description": "The HTTP path permalink for this PullRequestReview.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "state", "description": "Identifies the current state of the pull request review.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "PullRequestReviewState", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "submittedAt", "description": "Identifies when the Pull Request Review was submitted", "args": [], "type": { "kind": "SCALAR", "name": "DateTime", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "updatedAt", "description": "Identifies the date and time when the object was last updated.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "url", "description": "The HTTP URL permalink for this PullRequestReview.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "userContentEdits", "description": "A list of edits to this content.", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "UserContentEditConnection", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerCanDelete", "description": "Check if the current viewer can delete this object.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerCanReact", "description": "Can user react to this subject", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerCanUpdate", "description": "Check if the current viewer can update this object.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerCannotUpdateReasons", "description": "Reasons why the current viewer can not update this comment.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "CommentCannotUpdateReason", "ofType": null } } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerDidAuthor", "description": "Did the viewer author this comment.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null }, { "kind": "INTERFACE", "name": "Comment", "ofType": null }, { "kind": "INTERFACE", "name": "Deletable", "ofType": null }, { "kind": "INTERFACE", "name": "Updatable", "ofType": null }, { "kind": "INTERFACE", "name": "UpdatableComment", "ofType": null }, { "kind": "INTERFACE", "name": "Reactable", "ofType": null }, { "kind": "INTERFACE", "name": "RepositoryNode", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "ENUM", "name": "PullRequestReviewState", "description": "The possible states of a pull request review.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "PENDING", "description": "A review that has not yet been submitted.", "isDeprecated": false, "deprecationReason": null }, { "name": "COMMENTED", "description": "An informational review.", "isDeprecated": false, "deprecationReason": null }, { "name": "APPROVED", "description": "A review allowing the pull request to merge.", "isDeprecated": false, "deprecationReason": null }, { "name": "CHANGES_REQUESTED", "description": "A review blocking the pull request from merging.", "isDeprecated": false, "deprecationReason": null }, { "name": "DISMISSED", "description": "A review that has been dismissed.", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null }, { "kind": "OBJECT", "name": "PullRequestReviewCommentConnection", "description": "The connection type for PullRequestReviewComment.", "fields": [ { "name": "edges", "description": "A list of edges.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "PullRequestReviewCommentEdge", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "nodes", "description": "A list of nodes.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "PullRequestReviewComment", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pageInfo", "description": "Information to aid in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PageInfo", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "totalCount", "description": "Identifies the total count of items in the connection.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "PullRequestReviewCommentEdge", "description": "An edge in a connection.", "fields": [ { "name": "cursor", "description": "A cursor for use in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "node", "description": "The item at the end of the edge.", "args": [], "type": { "kind": "OBJECT", "name": "PullRequestReviewComment", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "PullRequestReviewThread", "description": "A threaded list of comments for a given pull request.", "fields": [ { "name": "comments", "description": "A list of pull request comments associated with the thread.", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PullRequestReviewCommentConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "isResolved", "description": "Whether this thread has been resolved", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pullRequest", "description": "Identifies the pull request associated with this thread.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PullRequest", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "repository", "description": "Identifies the repository associated with this thread.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "Repository", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "resolvedBy", "description": "The user who resolved this thread", "args": [], "type": { "kind": "OBJECT", "name": "User", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerCanResolve", "description": "Whether or not the viewer can resolve this thread", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "viewerCanUnresolve", "description": "Whether or not the viewer can unresolve this thread", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "PullRequestCommit", "description": "Represents a Git commit part of a pull request.", "fields": [ { "name": "commit", "description": "The Git commit object", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "Commit", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pullRequest", "description": "The pull request this commit belongs to", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PullRequest", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "resourcePath", "description": "The HTTP path for this pull request commit", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "url", "description": "The HTTP URL for this pull request commit", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null }, { "kind": "INTERFACE", "name": "UniformResourceLocatable", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "PullRequestReviewThreadConnection", "description": "Review comment threads for a pull request review.", "fields": [ { "name": "edges", "description": "A list of edges.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "PullRequestReviewThreadEdge", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "nodes", "description": "A list of nodes.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "PullRequestReviewThread", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pageInfo", "description": "Information to aid in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PageInfo", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "totalCount", "description": "Identifies the total count of items in the connection.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "PullRequestReviewThreadEdge", "description": "An edge in a connection.", "fields": [ { "name": "cursor", "description": "A cursor for use in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "node", "description": "The item at the end of the edge.", "args": [], "type": { "kind": "OBJECT", "name": "PullRequestReviewThread", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "ENUM", "name": "PullRequestReviewCommentState", "description": "The possible states of a pull request review comment.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "PENDING", "description": "A comment that is part of a pending review", "isDeprecated": false, "deprecationReason": null }, { "name": "SUBMITTED", "description": "A comment that is part of a submitted review", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null }, { "kind": "ENUM", "name": "PullRequestPubSubTopic", "description": "The possible PubSub channels for a pull request.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "UPDATED", "description": "The channel ID for observing pull request updates.", "isDeprecated": false, "deprecationReason": null }, { "name": "MARKASREAD", "description": "The channel ID for marking an pull request as read.", "isDeprecated": false, "deprecationReason": null }, { "name": "HEAD_REF", "description": "The channel ID for observing head ref updates.", "isDeprecated": false, "deprecationReason": null }, { "name": "TIMELINE", "description": "The channel ID for updating items on the pull request timeline.", "isDeprecated": false, "deprecationReason": null }, { "name": "STATE", "description": "The channel ID for observing pull request state updates.", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null }, { "kind": "OBJECT", "name": "IssueCommentConnection", "description": "The connection type for IssueComment.", "fields": [ { "name": "edges", "description": "A list of edges.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "IssueCommentEdge", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "nodes", "description": "A list of nodes.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "IssueComment", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pageInfo", "description": "Information to aid in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PageInfo", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "totalCount", "description": "Identifies the total count of items in the connection.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "IssueCommentEdge", "description": "An edge in a connection.", "fields": [ { "name": "cursor", "description": "A cursor for use in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "node", "description": "The item at the end of the edge.", "args": [], "type": { "kind": "OBJECT", "name": "IssueComment", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "PullRequestReviewConnection", "description": "The connection type for PullRequestReview.", "fields": [ { "name": "edges", "description": "A list of edges.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "PullRequestReviewEdge", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "nodes", "description": "A list of nodes.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "PullRequestReview", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pageInfo", "description": "Information to aid in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PageInfo", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "totalCount", "description": "Identifies the total count of items in the connection.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "PullRequestReviewEdge", "description": "An edge in a connection.", "fields": [ { "name": "cursor", "description": "A cursor for use in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "node", "description": "The item at the end of the edge.", "args": [], "type": { "kind": "OBJECT", "name": "PullRequestReview", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "PullRequestCommitConnection", "description": "The connection type for PullRequestCommit.", "fields": [ { "name": "edges", "description": "A list of edges.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "PullRequestCommitEdge", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "nodes", "description": "A list of nodes.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "PullRequestCommit", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pageInfo", "description": "Information to aid in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PageInfo", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "totalCount", "description": "Identifies the total count of items in the connection.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "PullRequestCommitEdge", "description": "An edge in a connection.", "fields": [ { "name": "cursor", "description": "A cursor for use in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "node", "description": "The item at the end of the edge.", "args": [], "type": { "kind": "OBJECT", "name": "PullRequestCommit", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "ReviewRequestConnection", "description": "The connection type for ReviewRequest.", "fields": [ { "name": "edges", "description": "A list of edges.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "ReviewRequestEdge", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "nodes", "description": "A list of nodes.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "ReviewRequest", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pageInfo", "description": "Information to aid in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PageInfo", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "totalCount", "description": "Identifies the total count of items in the connection.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "ReviewRequestEdge", "description": "An edge in a connection.", "fields": [ { "name": "cursor", "description": "A cursor for use in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "node", "description": "The item at the end of the edge.", "args": [], "type": { "kind": "OBJECT", "name": "ReviewRequest", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "ReviewRequest", "description": "A request for a user to review a pull request.", "fields": [ { "name": "databaseId", "description": "Identifies the primary key from the database.", "args": [], "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pullRequest", "description": "Identifies the pull request associated with this review request.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PullRequest", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "requestedReviewer", "description": "The reviewer that is requested.", "args": [], "type": { "kind": "UNION", "name": "RequestedReviewer", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "UNION", "name": "RequestedReviewer", "description": "Types that can be requested reviewers.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": [ { "kind": "OBJECT", "name": "User", "ofType": null }, { "kind": "OBJECT", "name": "Team", "ofType": null }, { "kind": "OBJECT", "name": "Mannequin", "ofType": null } ] }, { "kind": "OBJECT", "name": "PullRequestTimelineConnection", "description": "The connection type for PullRequestTimelineItem.", "fields": [ { "name": "edges", "description": "A list of edges.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "PullRequestTimelineItemEdge", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "nodes", "description": "A list of nodes.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "UNION", "name": "PullRequestTimelineItem", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pageInfo", "description": "Information to aid in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PageInfo", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "totalCount", "description": "Identifies the total count of items in the connection.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "PullRequestTimelineItemEdge", "description": "An edge in a connection.", "fields": [ { "name": "cursor", "description": "A cursor for use in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "node", "description": "The item at the end of the edge.", "args": [], "type": { "kind": "UNION", "name": "PullRequestTimelineItem", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "UNION", "name": "PullRequestTimelineItem", "description": "An item in an pull request timeline", "fields": null, "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": [ { "kind": "OBJECT", "name": "Commit", "ofType": null }, { "kind": "OBJECT", "name": "CommitCommentThread", "ofType": null }, { "kind": "OBJECT", "name": "PullRequestReview", "ofType": null }, { "kind": "OBJECT", "name": "PullRequestReviewThread", "ofType": null }, { "kind": "OBJECT", "name": "PullRequestReviewComment", "ofType": null }, { "kind": "OBJECT", "name": "IssueComment", "ofType": null }, { "kind": "OBJECT", "name": "ClosedEvent", "ofType": null }, { "kind": "OBJECT", "name": "ReopenedEvent", "ofType": null }, { "kind": "OBJECT", "name": "SubscribedEvent", "ofType": null }, { "kind": "OBJECT", "name": "UnsubscribedEvent", "ofType": null }, { "kind": "OBJECT", "name": "MergedEvent", "ofType": null }, { "kind": "OBJECT", "name": "ReferencedEvent", "ofType": null }, { "kind": "OBJECT", "name": "CrossReferencedEvent", "ofType": null }, { "kind": "OBJECT", "name": "AssignedEvent", "ofType": null }, { "kind": "OBJECT", "name": "UnassignedEvent", "ofType": null }, { "kind": "OBJECT", "name": "LabeledEvent", "ofType": null }, { "kind": "OBJECT", "name": "UnlabeledEvent", "ofType": null }, { "kind": "OBJECT", "name": "MilestonedEvent", "ofType": null }, { "kind": "OBJECT", "name": "DemilestonedEvent", "ofType": null }, { "kind": "OBJECT", "name": "RenamedTitleEvent", "ofType": null }, { "kind": "OBJECT", "name": "LockedEvent", "ofType": null }, { "kind": "OBJECT", "name": "UnlockedEvent", "ofType": null }, { "kind": "OBJECT", "name": "DeployedEvent", "ofType": null }, { "kind": "OBJECT", "name": "DeploymentEnvironmentChangedEvent", "ofType": null }, { "kind": "OBJECT", "name": "HeadRefDeletedEvent", "ofType": null }, { "kind": "OBJECT", "name": "HeadRefRestoredEvent", "ofType": null }, { "kind": "OBJECT", "name": "HeadRefForcePushedEvent", "ofType": null }, { "kind": "OBJECT", "name": "BaseRefForcePushedEvent", "ofType": null }, { "kind": "OBJECT", "name": "ReviewRequestedEvent", "ofType": null }, { "kind": "OBJECT", "name": "ReviewRequestRemovedEvent", "ofType": null }, { "kind": "OBJECT", "name": "ReviewDismissedEvent", "ofType": null }, { "kind": "OBJECT", "name": "UserBlockedEvent", "ofType": null } ] }, { "kind": "OBJECT", "name": "CommitCommentThread", "description": "A thread of comments on a commit.", "fields": [ { "name": "comments", "description": "The comments that exist in this thread.", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "CommitCommentConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "commit", "description": "The commit the comments were made on.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "Commit", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "path", "description": "The file the comments were made on.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "position", "description": "The position in the diff for the commit that the comment was made on.", "args": [], "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "repository", "description": "The repository associated with this node.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "Repository", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null }, { "kind": "INTERFACE", "name": "RepositoryNode", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "ClosedEvent", "description": "Represents a 'closed' event on any `Closable`.", "fields": [ { "name": "actor", "description": "Identifies the actor who performed the event.", "args": [], "type": { "kind": "INTERFACE", "name": "Actor", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "closable", "description": "Object that was closed.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INTERFACE", "name": "Closable", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "closer", "description": "Object which triggered the creation of this event.", "args": [], "type": { "kind": "UNION", "name": "Closer", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "createdAt", "description": "Identifies the date and time when the object was created.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "resourcePath", "description": "The HTTP path for this closed event.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "url", "description": "The HTTP URL for this closed event.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null }, { "kind": "INTERFACE", "name": "UniformResourceLocatable", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "UNION", "name": "Closer", "description": "The object which triggered a `ClosedEvent`.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": [ { "kind": "OBJECT", "name": "Commit", "ofType": null }, { "kind": "OBJECT", "name": "PullRequest", "ofType": null } ] }, { "kind": "OBJECT", "name": "ReopenedEvent", "description": "Represents a 'reopened' event on any `Closable`.", "fields": [ { "name": "actor", "description": "Identifies the actor who performed the event.", "args": [], "type": { "kind": "INTERFACE", "name": "Actor", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "closable", "description": "Object that was reopened.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INTERFACE", "name": "Closable", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "createdAt", "description": "Identifies the date and time when the object was created.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "SubscribedEvent", "description": "Represents a 'subscribed' event on a given `Subscribable`.", "fields": [ { "name": "actor", "description": "Identifies the actor who performed the event.", "args": [], "type": { "kind": "INTERFACE", "name": "Actor", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "createdAt", "description": "Identifies the date and time when the object was created.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "subscribable", "description": "Object referenced by event.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INTERFACE", "name": "Subscribable", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "UnsubscribedEvent", "description": "Represents an 'unsubscribed' event on a given `Subscribable`.", "fields": [ { "name": "actor", "description": "Identifies the actor who performed the event.", "args": [], "type": { "kind": "INTERFACE", "name": "Actor", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "createdAt", "description": "Identifies the date and time when the object was created.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "subscribable", "description": "Object referenced by event.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INTERFACE", "name": "Subscribable", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "MergedEvent", "description": "Represents a 'merged' event on a given pull request.", "fields": [ { "name": "actor", "description": "Identifies the actor who performed the event.", "args": [], "type": { "kind": "INTERFACE", "name": "Actor", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "commit", "description": "Identifies the commit associated with the `merge` event.", "args": [], "type": { "kind": "OBJECT", "name": "Commit", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "createdAt", "description": "Identifies the date and time when the object was created.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "mergeRef", "description": "Identifies the Ref associated with the `merge` event.", "args": [], "type": { "kind": "OBJECT", "name": "Ref", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "mergeRefName", "description": "Identifies the name of the Ref associated with the `merge` event.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pullRequest", "description": "PullRequest referenced by event.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PullRequest", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "resourcePath", "description": "The HTTP path for this merged event.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "url", "description": "The HTTP URL for this merged event.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null }, { "kind": "INTERFACE", "name": "UniformResourceLocatable", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "ReferencedEvent", "description": "Represents a 'referenced' event on a given `ReferencedSubject`.", "fields": [ { "name": "actor", "description": "Identifies the actor who performed the event.", "args": [], "type": { "kind": "INTERFACE", "name": "Actor", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "commit", "description": "Identifies the commit associated with the 'referenced' event.", "args": [], "type": { "kind": "OBJECT", "name": "Commit", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "commitRepository", "description": "Identifies the repository associated with the 'referenced' event.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "Repository", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "createdAt", "description": "Identifies the date and time when the object was created.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "isCrossRepository", "description": "Reference originated in a different repository.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "isDirectReference", "description": "Checks if the commit message itself references the subject. Can be false in the case of a commit comment reference.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "subject", "description": "Object referenced by event.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "UNION", "name": "ReferencedSubject", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "UNION", "name": "ReferencedSubject", "description": "Any referencable object", "fields": null, "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": [ { "kind": "OBJECT", "name": "Issue", "ofType": null }, { "kind": "OBJECT", "name": "PullRequest", "ofType": null } ] }, { "kind": "OBJECT", "name": "CrossReferencedEvent", "description": "Represents a mention made by one issue or pull request to another.", "fields": [ { "name": "actor", "description": "Identifies the actor who performed the event.", "args": [], "type": { "kind": "INTERFACE", "name": "Actor", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "createdAt", "description": "Identifies the date and time when the object was created.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "isCrossRepository", "description": "Reference originated in a different repository.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "referencedAt", "description": "Identifies when the reference was made.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "resourcePath", "description": "The HTTP path for this pull request.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "source", "description": "Issue or pull request that made the reference.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "UNION", "name": "ReferencedSubject", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "target", "description": "Issue or pull request to which the reference was made.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "UNION", "name": "ReferencedSubject", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "url", "description": "The HTTP URL for this pull request.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "willCloseTarget", "description": "Checks if the target will be closed when the source is merged.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null }, { "kind": "INTERFACE", "name": "UniformResourceLocatable", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "AssignedEvent", "description": "Represents an 'assigned' event on any assignable object.", "fields": [ { "name": "actor", "description": "Identifies the actor who performed the event.", "args": [], "type": { "kind": "INTERFACE", "name": "Actor", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "assignable", "description": "Identifies the assignable associated with the event.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INTERFACE", "name": "Assignable", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "createdAt", "description": "Identifies the date and time when the object was created.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "user", "description": "Identifies the user who was assigned.", "args": [], "type": { "kind": "OBJECT", "name": "User", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "UnassignedEvent", "description": "Represents an 'unassigned' event on any assignable object.", "fields": [ { "name": "actor", "description": "Identifies the actor who performed the event.", "args": [], "type": { "kind": "INTERFACE", "name": "Actor", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "assignable", "description": "Identifies the assignable associated with the event.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INTERFACE", "name": "Assignable", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "createdAt", "description": "Identifies the date and time when the object was created.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "user", "description": "Identifies the subject (user) who was unassigned.", "args": [], "type": { "kind": "OBJECT", "name": "User", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "LabeledEvent", "description": "Represents a 'labeled' event on a given issue or pull request.", "fields": [ { "name": "actor", "description": "Identifies the actor who performed the event.", "args": [], "type": { "kind": "INTERFACE", "name": "Actor", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "createdAt", "description": "Identifies the date and time when the object was created.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "label", "description": "Identifies the label associated with the 'labeled' event.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "Label", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "labelable", "description": "Identifies the `Labelable` associated with the event.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INTERFACE", "name": "Labelable", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "UnlabeledEvent", "description": "Represents an 'unlabeled' event on a given issue or pull request.", "fields": [ { "name": "actor", "description": "Identifies the actor who performed the event.", "args": [], "type": { "kind": "INTERFACE", "name": "Actor", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "createdAt", "description": "Identifies the date and time when the object was created.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "label", "description": "Identifies the label associated with the 'unlabeled' event.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "Label", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "labelable", "description": "Identifies the `Labelable` associated with the event.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INTERFACE", "name": "Labelable", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "MilestonedEvent", "description": "Represents a 'milestoned' event on a given issue or pull request.", "fields": [ { "name": "actor", "description": "Identifies the actor who performed the event.", "args": [], "type": { "kind": "INTERFACE", "name": "Actor", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "createdAt", "description": "Identifies the date and time when the object was created.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "milestoneTitle", "description": "Identifies the milestone title associated with the 'milestoned' event.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "subject", "description": "Object referenced by event.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "UNION", "name": "MilestoneItem", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "UNION", "name": "MilestoneItem", "description": "Types that can be inside a Milestone.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": [ { "kind": "OBJECT", "name": "Issue", "ofType": null }, { "kind": "OBJECT", "name": "PullRequest", "ofType": null } ] }, { "kind": "OBJECT", "name": "DemilestonedEvent", "description": "Represents a 'demilestoned' event on a given issue or pull request.", "fields": [ { "name": "actor", "description": "Identifies the actor who performed the event.", "args": [], "type": { "kind": "INTERFACE", "name": "Actor", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "createdAt", "description": "Identifies the date and time when the object was created.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "milestoneTitle", "description": "Identifies the milestone title associated with the 'demilestoned' event.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "subject", "description": "Object referenced by event.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "UNION", "name": "MilestoneItem", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "RenamedTitleEvent", "description": "Represents a 'renamed' event on a given issue or pull request", "fields": [ { "name": "actor", "description": "Identifies the actor who performed the event.", "args": [], "type": { "kind": "INTERFACE", "name": "Actor", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "createdAt", "description": "Identifies the date and time when the object was created.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "currentTitle", "description": "Identifies the current title of the issue or pull request.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "previousTitle", "description": "Identifies the previous title of the issue or pull request.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "subject", "description": "Subject that was renamed.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "UNION", "name": "RenamedTitleSubject", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "UNION", "name": "RenamedTitleSubject", "description": "An object which has a renamable title", "fields": null, "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": [ { "kind": "OBJECT", "name": "Issue", "ofType": null }, { "kind": "OBJECT", "name": "PullRequest", "ofType": null } ] }, { "kind": "OBJECT", "name": "LockedEvent", "description": "Represents a 'locked' event on a given issue or pull request.", "fields": [ { "name": "actor", "description": "Identifies the actor who performed the event.", "args": [], "type": { "kind": "INTERFACE", "name": "Actor", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "createdAt", "description": "Identifies the date and time when the object was created.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "lockReason", "description": "Reason that the conversation was locked (optional).", "args": [], "type": { "kind": "ENUM", "name": "LockReason", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "lockable", "description": "Object that was locked.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INTERFACE", "name": "Lockable", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "UnlockedEvent", "description": "Represents an 'unlocked' event on a given issue or pull request.", "fields": [ { "name": "actor", "description": "Identifies the actor who performed the event.", "args": [], "type": { "kind": "INTERFACE", "name": "Actor", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "createdAt", "description": "Identifies the date and time when the object was created.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "lockable", "description": "Object that was unlocked.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INTERFACE", "name": "Lockable", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "DeployedEvent", "description": "Represents a 'deployed' event on a given pull request.", "fields": [ { "name": "actor", "description": "Identifies the actor who performed the event.", "args": [], "type": { "kind": "INTERFACE", "name": "Actor", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "createdAt", "description": "Identifies the date and time when the object was created.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "databaseId", "description": "Identifies the primary key from the database.", "args": [], "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "deployment", "description": "The deployment associated with the 'deployed' event.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "Deployment", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pullRequest", "description": "PullRequest referenced by event.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PullRequest", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "ref", "description": "The ref associated with the 'deployed' event.", "args": [], "type": { "kind": "OBJECT", "name": "Ref", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "DeploymentEnvironmentChangedEvent", "description": "Represents a 'deployment_environment_changed' event on a given pull request.", "fields": [ { "name": "actor", "description": "Identifies the actor who performed the event.", "args": [], "type": { "kind": "INTERFACE", "name": "Actor", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "createdAt", "description": "Identifies the date and time when the object was created.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "deploymentStatus", "description": "The deployment status that updated the deployment environment.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "DeploymentStatus", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pullRequest", "description": "PullRequest referenced by event.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PullRequest", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "HeadRefDeletedEvent", "description": "Represents a 'head_ref_deleted' event on a given pull request.", "fields": [ { "name": "actor", "description": "Identifies the actor who performed the event.", "args": [], "type": { "kind": "INTERFACE", "name": "Actor", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "createdAt", "description": "Identifies the date and time when the object was created.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "headRef", "description": "Identifies the Ref associated with the `head_ref_deleted` event.", "args": [], "type": { "kind": "OBJECT", "name": "Ref", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "headRefName", "description": "Identifies the name of the Ref associated with the `head_ref_deleted` event.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pullRequest", "description": "PullRequest referenced by event.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PullRequest", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "HeadRefRestoredEvent", "description": "Represents a 'head_ref_restored' event on a given pull request.", "fields": [ { "name": "actor", "description": "Identifies the actor who performed the event.", "args": [], "type": { "kind": "INTERFACE", "name": "Actor", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "createdAt", "description": "Identifies the date and time when the object was created.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pullRequest", "description": "PullRequest referenced by event.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PullRequest", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "HeadRefForcePushedEvent", "description": "Represents a 'head_ref_force_pushed' event on a given pull request.", "fields": [ { "name": "actor", "description": "Identifies the actor who performed the event.", "args": [], "type": { "kind": "INTERFACE", "name": "Actor", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "afterCommit", "description": "Identifies the after commit SHA for the 'head_ref_force_pushed' event.", "args": [], "type": { "kind": "OBJECT", "name": "Commit", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "beforeCommit", "description": "Identifies the before commit SHA for the 'head_ref_force_pushed' event.", "args": [], "type": { "kind": "OBJECT", "name": "Commit", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "createdAt", "description": "Identifies the date and time when the object was created.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pullRequest", "description": "PullRequest referenced by event.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PullRequest", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "ref", "description": "Identifies the fully qualified ref name for the 'head_ref_force_pushed' event.", "args": [], "type": { "kind": "OBJECT", "name": "Ref", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "BaseRefForcePushedEvent", "description": "Represents a 'base_ref_force_pushed' event on a given pull request.", "fields": [ { "name": "actor", "description": "Identifies the actor who performed the event.", "args": [], "type": { "kind": "INTERFACE", "name": "Actor", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "afterCommit", "description": "Identifies the after commit SHA for the 'base_ref_force_pushed' event.", "args": [], "type": { "kind": "OBJECT", "name": "Commit", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "beforeCommit", "description": "Identifies the before commit SHA for the 'base_ref_force_pushed' event.", "args": [], "type": { "kind": "OBJECT", "name": "Commit", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "createdAt", "description": "Identifies the date and time when the object was created.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pullRequest", "description": "PullRequest referenced by event.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PullRequest", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "ref", "description": "Identifies the fully qualified ref name for the 'base_ref_force_pushed' event.", "args": [], "type": { "kind": "OBJECT", "name": "Ref", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "ReviewRequestedEvent", "description": "Represents an 'review_requested' event on a given pull request.", "fields": [ { "name": "actor", "description": "Identifies the actor who performed the event.", "args": [], "type": { "kind": "INTERFACE", "name": "Actor", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "createdAt", "description": "Identifies the date and time when the object was created.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pullRequest", "description": "PullRequest referenced by event.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PullRequest", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "requestedReviewer", "description": "Identifies the reviewer whose review was requested.", "args": [], "type": { "kind": "UNION", "name": "RequestedReviewer", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "ReviewRequestRemovedEvent", "description": "Represents an 'review_request_removed' event on a given pull request.", "fields": [ { "name": "actor", "description": "Identifies the actor who performed the event.", "args": [], "type": { "kind": "INTERFACE", "name": "Actor", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "createdAt", "description": "Identifies the date and time when the object was created.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pullRequest", "description": "PullRequest referenced by event.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PullRequest", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "requestedReviewer", "description": "Identifies the reviewer whose review request was removed.", "args": [], "type": { "kind": "UNION", "name": "RequestedReviewer", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "ReviewDismissedEvent", "description": "Represents a 'review_dismissed' event on a given issue or pull request.", "fields": [ { "name": "actor", "description": "Identifies the actor who performed the event.", "args": [], "type": { "kind": "INTERFACE", "name": "Actor", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "createdAt", "description": "Identifies the date and time when the object was created.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "databaseId", "description": "Identifies the primary key from the database.", "args": [], "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "dismissalMessage", "description": "Identifies the optional message associated with the 'review_dismissed' event.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "dismissalMessageHTML", "description": "Identifies the optional message associated with the event, rendered to HTML.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "message", "description": "Identifies the message associated with the 'review_dismissed' event.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": true, "deprecationReason": "`message` is being removed because it not nullable, whereas the underlying field is optional. Use `dismissalMessage` instead. Removal on 2019-07-01 UTC." }, { "name": "messageHtml", "description": "The message associated with the event, rendered to HTML.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "HTML", "ofType": null } }, "isDeprecated": true, "deprecationReason": "`messageHtml` is being removed because it not nullable, whereas the underlying field is optional. Use `dismissalMessageHTML` instead. Removal on 2019-07-01 UTC." }, { "name": "previousReviewState", "description": "Identifies the previous state of the review with the 'review_dismissed' event.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "PullRequestReviewState", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pullRequest", "description": "PullRequest referenced by event.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PullRequest", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pullRequestCommit", "description": "Identifies the commit which caused the review to become stale.", "args": [], "type": { "kind": "OBJECT", "name": "PullRequestCommit", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "resourcePath", "description": "The HTTP path for this review dismissed event.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "review", "description": "Identifies the review associated with the 'review_dismissed' event.", "args": [], "type": { "kind": "OBJECT", "name": "PullRequestReview", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "url", "description": "The HTTP URL for this review dismissed event.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null }, { "kind": "INTERFACE", "name": "UniformResourceLocatable", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "UserBlockedEvent", "description": "Represents a 'user_blocked' event on a given user.", "fields": [ { "name": "actor", "description": "Identifies the actor who performed the event.", "args": [], "type": { "kind": "INTERFACE", "name": "Actor", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "blockDuration", "description": "Number of days that the user was blocked for.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "UserBlockDuration", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "createdAt", "description": "Identifies the date and time when the object was created.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "subject", "description": "The user who was blocked.", "args": [], "type": { "kind": "OBJECT", "name": "User", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "ENUM", "name": "UserBlockDuration", "description": "The possible durations that a user can be blocked for.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "ONE_DAY", "description": "The user was blocked for 1 day", "isDeprecated": false, "deprecationReason": null }, { "name": "THREE_DAYS", "description": "The user was blocked for 3 days", "isDeprecated": false, "deprecationReason": null }, { "name": "ONE_WEEK", "description": "The user was blocked for 7 days", "isDeprecated": false, "deprecationReason": null }, { "name": "ONE_MONTH", "description": "The user was blocked for 30 days", "isDeprecated": false, "deprecationReason": null }, { "name": "PERMANENT", "description": "The user was blocked permanently", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null }, { "kind": "OBJECT", "name": "PullRequestTimelineItemsConnection", "description": "The connection type for PullRequestTimelineItems.", "fields": [ { "name": "edges", "description": "A list of edges.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "PullRequestTimelineItemsEdge", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "filteredCount", "description": "Identifies the count of items after applying `before` and `after` filters.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "nodes", "description": "A list of nodes.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "UNION", "name": "PullRequestTimelineItems", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pageCount", "description": "Identifies the count of items after applying `before`/`after` filters and `first`/`last`/`skip` slicing.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pageInfo", "description": "Information to aid in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PageInfo", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "totalCount", "description": "Identifies the total count of items in the connection.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "updatedAt", "description": "Identifies the date and time when the timeline was last updated.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "PullRequestTimelineItemsEdge", "description": "An edge in a connection.", "fields": [ { "name": "cursor", "description": "A cursor for use in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "node", "description": "The item at the end of the edge.", "args": [], "type": { "kind": "UNION", "name": "PullRequestTimelineItems", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "UNION", "name": "PullRequestTimelineItems", "description": "An item in a pull request timeline", "fields": null, "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": [ { "kind": "OBJECT", "name": "PullRequestCommit", "ofType": null }, { "kind": "OBJECT", "name": "PullRequestCommitCommentThread", "ofType": null }, { "kind": "OBJECT", "name": "PullRequestReview", "ofType": null }, { "kind": "OBJECT", "name": "PullRequestReviewThread", "ofType": null }, { "kind": "OBJECT", "name": "PullRequestRevisionMarker", "ofType": null }, { "kind": "OBJECT", "name": "BaseRefChangedEvent", "ofType": null }, { "kind": "OBJECT", "name": "BaseRefForcePushedEvent", "ofType": null }, { "kind": "OBJECT", "name": "DeployedEvent", "ofType": null }, { "kind": "OBJECT", "name": "DeploymentEnvironmentChangedEvent", "ofType": null }, { "kind": "OBJECT", "name": "HeadRefDeletedEvent", "ofType": null }, { "kind": "OBJECT", "name": "HeadRefForcePushedEvent", "ofType": null }, { "kind": "OBJECT", "name": "HeadRefRestoredEvent", "ofType": null }, { "kind": "OBJECT", "name": "MergedEvent", "ofType": null }, { "kind": "OBJECT", "name": "ReviewDismissedEvent", "ofType": null }, { "kind": "OBJECT", "name": "ReviewRequestedEvent", "ofType": null }, { "kind": "OBJECT", "name": "ReviewRequestRemovedEvent", "ofType": null }, { "kind": "OBJECT", "name": "IssueComment", "ofType": null }, { "kind": "OBJECT", "name": "CrossReferencedEvent", "ofType": null }, { "kind": "OBJECT", "name": "AddedToProjectEvent", "ofType": null }, { "kind": "OBJECT", "name": "AssignedEvent", "ofType": null }, { "kind": "OBJECT", "name": "ClosedEvent", "ofType": null }, { "kind": "OBJECT", "name": "CommentDeletedEvent", "ofType": null }, { "kind": "OBJECT", "name": "ConvertedNoteToIssueEvent", "ofType": null }, { "kind": "OBJECT", "name": "DemilestonedEvent", "ofType": null }, { "kind": "OBJECT", "name": "LabeledEvent", "ofType": null }, { "kind": "OBJECT", "name": "LockedEvent", "ofType": null }, { "kind": "OBJECT", "name": "MentionedEvent", "ofType": null }, { "kind": "OBJECT", "name": "MilestonedEvent", "ofType": null }, { "kind": "OBJECT", "name": "MovedColumnsInProjectEvent", "ofType": null }, { "kind": "OBJECT", "name": "PinnedEvent", "ofType": null }, { "kind": "OBJECT", "name": "ReferencedEvent", "ofType": null }, { "kind": "OBJECT", "name": "RemovedFromProjectEvent", "ofType": null }, { "kind": "OBJECT", "name": "RenamedTitleEvent", "ofType": null }, { "kind": "OBJECT", "name": "ReopenedEvent", "ofType": null }, { "kind": "OBJECT", "name": "SubscribedEvent", "ofType": null }, { "kind": "OBJECT", "name": "TransferredEvent", "ofType": null }, { "kind": "OBJECT", "name": "UnassignedEvent", "ofType": null }, { "kind": "OBJECT", "name": "UnlabeledEvent", "ofType": null }, { "kind": "OBJECT", "name": "UnlockedEvent", "ofType": null }, { "kind": "OBJECT", "name": "UserBlockedEvent", "ofType": null }, { "kind": "OBJECT", "name": "UnpinnedEvent", "ofType": null }, { "kind": "OBJECT", "name": "UnsubscribedEvent", "ofType": null } ] }, { "kind": "OBJECT", "name": "PullRequestCommitCommentThread", "description": "Represents a commit comment thread part of a pull request.", "fields": [ { "name": "comments", "description": "The comments that exist in this thread.", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "CommitCommentConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "commit", "description": "The commit the comments were made on.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "Commit", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "path", "description": "The file the comments were made on.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "position", "description": "The position in the diff for the commit that the comment was made on.", "args": [], "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "pullRequest", "description": "The pull request this commit comment thread belongs to", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PullRequest", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "repository", "description": "The repository associated with this node.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "Repository", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null }, { "kind": "INTERFACE", "name": "RepositoryNode", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "PullRequestRevisionMarker", "description": "Represents the latest point in the pull request timeline for which the viewer has seen the pull request's commits.", "fields": [ { "name": "createdAt", "description": "Identifies the date and time when the object was created.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "lastSeenCommit", "description": "The last commit the viewer has seen.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "Commit", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pullRequest", "description": "The pull request to which the marker belongs.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PullRequest", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "BaseRefChangedEvent", "description": "Represents a 'base_ref_changed' event on a given issue or pull request.", "fields": [ { "name": "actor", "description": "Identifies the actor who performed the event.", "args": [], "type": { "kind": "INTERFACE", "name": "Actor", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "createdAt", "description": "Identifies the date and time when the object was created.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "databaseId", "description": "Identifies the primary key from the database.", "args": [], "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "AddedToProjectEvent", "description": "Represents a 'added_to_project' event on a given issue or pull request.", "fields": [ { "name": "actor", "description": "Identifies the actor who performed the event.", "args": [], "type": { "kind": "INTERFACE", "name": "Actor", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "createdAt", "description": "Identifies the date and time when the object was created.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "databaseId", "description": "Identifies the primary key from the database.", "args": [], "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "CommentDeletedEvent", "description": "Represents a 'comment_deleted' event on a given issue or pull request.", "fields": [ { "name": "actor", "description": "Identifies the actor who performed the event.", "args": [], "type": { "kind": "INTERFACE", "name": "Actor", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "createdAt", "description": "Identifies the date and time when the object was created.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "databaseId", "description": "Identifies the primary key from the database.", "args": [], "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "ConvertedNoteToIssueEvent", "description": "Represents a 'converted_note_to_issue' event on a given issue or pull request.", "fields": [ { "name": "actor", "description": "Identifies the actor who performed the event.", "args": [], "type": { "kind": "INTERFACE", "name": "Actor", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "createdAt", "description": "Identifies the date and time when the object was created.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "databaseId", "description": "Identifies the primary key from the database.", "args": [], "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "UNION", "name": "IssueOrPullRequest", "description": "Used for return value of Repository.issueOrPullRequest.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": [ { "kind": "OBJECT", "name": "Issue", "ofType": null }, { "kind": "OBJECT", "name": "PullRequest", "ofType": null } ] }, { "kind": "OBJECT", "name": "MentionedEvent", "description": "Represents a 'mentioned' event on a given issue or pull request.", "fields": [ { "name": "actor", "description": "Identifies the actor who performed the event.", "args": [], "type": { "kind": "INTERFACE", "name": "Actor", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "createdAt", "description": "Identifies the date and time when the object was created.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "databaseId", "description": "Identifies the primary key from the database.", "args": [], "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "MovedColumnsInProjectEvent", "description": "Represents a 'moved_columns_in_project' event on a given issue or pull request.", "fields": [ { "name": "actor", "description": "Identifies the actor who performed the event.", "args": [], "type": { "kind": "INTERFACE", "name": "Actor", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "createdAt", "description": "Identifies the date and time when the object was created.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "databaseId", "description": "Identifies the primary key from the database.", "args": [], "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "PinnedEvent", "description": "Represents a 'pinned' event on a given issue or pull request.", "fields": [ { "name": "actor", "description": "Identifies the actor who performed the event.", "args": [], "type": { "kind": "INTERFACE", "name": "Actor", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "createdAt", "description": "Identifies the date and time when the object was created.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "issue", "description": "Identifies the issue associated with the event.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "Issue", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "RemovedFromProjectEvent", "description": "Represents a 'removed_from_project' event on a given issue or pull request.", "fields": [ { "name": "actor", "description": "Identifies the actor who performed the event.", "args": [], "type": { "kind": "INTERFACE", "name": "Actor", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "createdAt", "description": "Identifies the date and time when the object was created.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "databaseId", "description": "Identifies the primary key from the database.", "args": [], "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "TransferredEvent", "description": "Represents a 'transferred' event on a given issue or pull request.", "fields": [ { "name": "actor", "description": "Identifies the actor who performed the event.", "args": [], "type": { "kind": "INTERFACE", "name": "Actor", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "createdAt", "description": "Identifies the date and time when the object was created.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "fromRepository", "description": "The repository this came from", "args": [], "type": { "kind": "OBJECT", "name": "Repository", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "issue", "description": "Identifies the issue associated with the event.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "Issue", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "UnpinnedEvent", "description": "Represents an 'unpinned' event on a given issue or pull request.", "fields": [ { "name": "actor", "description": "Identifies the actor who performed the event.", "args": [], "type": { "kind": "INTERFACE", "name": "Actor", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "createdAt", "description": "Identifies the date and time when the object was created.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "issue", "description": "Identifies the issue associated with the event.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "Issue", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "ENUM", "name": "PullRequestTimelineItemsItemType", "description": "The possible item types found in a timeline.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "PULL_REQUEST_COMMIT", "description": "Represents a Git commit part of a pull request.", "isDeprecated": false, "deprecationReason": null }, { "name": "PULL_REQUEST_COMMIT_COMMENT_THREAD", "description": "Represents a commit comment thread part of a pull request.", "isDeprecated": false, "deprecationReason": null }, { "name": "PULL_REQUEST_REVIEW", "description": "A review object for a given pull request.", "isDeprecated": false, "deprecationReason": null }, { "name": "PULL_REQUEST_REVIEW_THREAD", "description": "A threaded list of comments for a given pull request.", "isDeprecated": false, "deprecationReason": null }, { "name": "PULL_REQUEST_REVISION_MARKER", "description": "Represents the latest point in the pull request timeline for which the viewer has seen the pull request's commits.", "isDeprecated": false, "deprecationReason": null }, { "name": "BASE_REF_CHANGED_EVENT", "description": "Represents a 'base_ref_changed' event on a given issue or pull request.", "isDeprecated": false, "deprecationReason": null }, { "name": "BASE_REF_FORCE_PUSHED_EVENT", "description": "Represents a 'base_ref_force_pushed' event on a given pull request.", "isDeprecated": false, "deprecationReason": null }, { "name": "DEPLOYED_EVENT", "description": "Represents a 'deployed' event on a given pull request.", "isDeprecated": false, "deprecationReason": null }, { "name": "DEPLOYMENT_ENVIRONMENT_CHANGED_EVENT", "description": "Represents a 'deployment_environment_changed' event on a given pull request.", "isDeprecated": false, "deprecationReason": null }, { "name": "HEAD_REF_DELETED_EVENT", "description": "Represents a 'head_ref_deleted' event on a given pull request.", "isDeprecated": false, "deprecationReason": null }, { "name": "HEAD_REF_FORCE_PUSHED_EVENT", "description": "Represents a 'head_ref_force_pushed' event on a given pull request.", "isDeprecated": false, "deprecationReason": null }, { "name": "HEAD_REF_RESTORED_EVENT", "description": "Represents a 'head_ref_restored' event on a given pull request.", "isDeprecated": false, "deprecationReason": null }, { "name": "MERGED_EVENT", "description": "Represents a 'merged' event on a given pull request.", "isDeprecated": false, "deprecationReason": null }, { "name": "REVIEW_DISMISSED_EVENT", "description": "Represents a 'review_dismissed' event on a given issue or pull request.", "isDeprecated": false, "deprecationReason": null }, { "name": "REVIEW_REQUESTED_EVENT", "description": "Represents an 'review_requested' event on a given pull request.", "isDeprecated": false, "deprecationReason": null }, { "name": "REVIEW_REQUEST_REMOVED_EVENT", "description": "Represents an 'review_request_removed' event on a given pull request.", "isDeprecated": false, "deprecationReason": null }, { "name": "ISSUE_COMMENT", "description": "Represents a comment on an Issue.", "isDeprecated": false, "deprecationReason": null }, { "name": "CROSS_REFERENCED_EVENT", "description": "Represents a mention made by one issue or pull request to another.", "isDeprecated": false, "deprecationReason": null }, { "name": "ADDED_TO_PROJECT_EVENT", "description": "Represents a 'added_to_project' event on a given issue or pull request.", "isDeprecated": false, "deprecationReason": null }, { "name": "ASSIGNED_EVENT", "description": "Represents an 'assigned' event on any assignable object.", "isDeprecated": false, "deprecationReason": null }, { "name": "CLOSED_EVENT", "description": "Represents a 'closed' event on any `Closable`.", "isDeprecated": false, "deprecationReason": null }, { "name": "COMMENT_DELETED_EVENT", "description": "Represents a 'comment_deleted' event on a given issue or pull request.", "isDeprecated": false, "deprecationReason": null }, { "name": "CONVERTED_NOTE_TO_ISSUE_EVENT", "description": "Represents a 'converted_note_to_issue' event on a given issue or pull request.", "isDeprecated": false, "deprecationReason": null }, { "name": "DEMILESTONED_EVENT", "description": "Represents a 'demilestoned' event on a given issue or pull request.", "isDeprecated": false, "deprecationReason": null }, { "name": "LABELED_EVENT", "description": "Represents a 'labeled' event on a given issue or pull request.", "isDeprecated": false, "deprecationReason": null }, { "name": "LOCKED_EVENT", "description": "Represents a 'locked' event on a given issue or pull request.", "isDeprecated": false, "deprecationReason": null }, { "name": "MENTIONED_EVENT", "description": "Represents a 'mentioned' event on a given issue or pull request.", "isDeprecated": false, "deprecationReason": null }, { "name": "MILESTONED_EVENT", "description": "Represents a 'milestoned' event on a given issue or pull request.", "isDeprecated": false, "deprecationReason": null }, { "name": "MOVED_COLUMNS_IN_PROJECT_EVENT", "description": "Represents a 'moved_columns_in_project' event on a given issue or pull request.", "isDeprecated": false, "deprecationReason": null }, { "name": "PINNED_EVENT", "description": "Represents a 'pinned' event on a given issue or pull request.", "isDeprecated": false, "deprecationReason": null }, { "name": "REFERENCED_EVENT", "description": "Represents a 'referenced' event on a given `ReferencedSubject`.", "isDeprecated": false, "deprecationReason": null }, { "name": "REMOVED_FROM_PROJECT_EVENT", "description": "Represents a 'removed_from_project' event on a given issue or pull request.", "isDeprecated": false, "deprecationReason": null }, { "name": "RENAMED_TITLE_EVENT", "description": "Represents a 'renamed' event on a given issue or pull request", "isDeprecated": false, "deprecationReason": null }, { "name": "REOPENED_EVENT", "description": "Represents a 'reopened' event on any `Closable`.", "isDeprecated": false, "deprecationReason": null }, { "name": "SUBSCRIBED_EVENT", "description": "Represents a 'subscribed' event on a given `Subscribable`.", "isDeprecated": false, "deprecationReason": null }, { "name": "TRANSFERRED_EVENT", "description": "Represents a 'transferred' event on a given issue or pull request.", "isDeprecated": false, "deprecationReason": null }, { "name": "UNASSIGNED_EVENT", "description": "Represents an 'unassigned' event on any assignable object.", "isDeprecated": false, "deprecationReason": null }, { "name": "UNLABELED_EVENT", "description": "Represents an 'unlabeled' event on a given issue or pull request.", "isDeprecated": false, "deprecationReason": null }, { "name": "UNLOCKED_EVENT", "description": "Represents an 'unlocked' event on a given issue or pull request.", "isDeprecated": false, "deprecationReason": null }, { "name": "USER_BLOCKED_EVENT", "description": "Represents a 'user_blocked' event on a given user.", "isDeprecated": false, "deprecationReason": null }, { "name": "UNPINNED_EVENT", "description": "Represents an 'unpinned' event on a given issue or pull request.", "isDeprecated": false, "deprecationReason": null }, { "name": "UNSUBSCRIBED_EVENT", "description": "Represents an 'unsubscribed' event on a given `Subscribable`.", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null }, { "kind": "OBJECT", "name": "SuggestedReviewer", "description": "A suggestion to review a pull request based on a user's commit history and review comments.", "fields": [ { "name": "isAuthor", "description": "Is this suggestion based on past commits?", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "isCommenter", "description": "Is this suggestion based on past review comments?", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "reviewer", "description": "Identifies the user suggested to review the pull request.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "User", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "ENUM", "name": "ProjectCardArchivedState", "description": "The possible archived states of a project card.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "ARCHIVED", "description": "A project card that is archived", "isDeprecated": false, "deprecationReason": null }, { "name": "NOT_ARCHIVED", "description": "A project card that is not archived", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null }, { "kind": "OBJECT", "name": "IssueTimelineConnection", "description": "The connection type for IssueTimelineItem.", "fields": [ { "name": "edges", "description": "A list of edges.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "IssueTimelineItemEdge", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "nodes", "description": "A list of nodes.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "UNION", "name": "IssueTimelineItem", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pageInfo", "description": "Information to aid in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PageInfo", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "totalCount", "description": "Identifies the total count of items in the connection.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "IssueTimelineItemEdge", "description": "An edge in a connection.", "fields": [ { "name": "cursor", "description": "A cursor for use in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "node", "description": "The item at the end of the edge.", "args": [], "type": { "kind": "UNION", "name": "IssueTimelineItem", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "UNION", "name": "IssueTimelineItem", "description": "An item in an issue timeline", "fields": null, "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": [ { "kind": "OBJECT", "name": "Commit", "ofType": null }, { "kind": "OBJECT", "name": "IssueComment", "ofType": null }, { "kind": "OBJECT", "name": "CrossReferencedEvent", "ofType": null }, { "kind": "OBJECT", "name": "ClosedEvent", "ofType": null }, { "kind": "OBJECT", "name": "ReopenedEvent", "ofType": null }, { "kind": "OBJECT", "name": "SubscribedEvent", "ofType": null }, { "kind": "OBJECT", "name": "UnsubscribedEvent", "ofType": null }, { "kind": "OBJECT", "name": "ReferencedEvent", "ofType": null }, { "kind": "OBJECT", "name": "AssignedEvent", "ofType": null }, { "kind": "OBJECT", "name": "UnassignedEvent", "ofType": null }, { "kind": "OBJECT", "name": "LabeledEvent", "ofType": null }, { "kind": "OBJECT", "name": "UnlabeledEvent", "ofType": null }, { "kind": "OBJECT", "name": "UserBlockedEvent", "ofType": null }, { "kind": "OBJECT", "name": "MilestonedEvent", "ofType": null }, { "kind": "OBJECT", "name": "DemilestonedEvent", "ofType": null }, { "kind": "OBJECT", "name": "RenamedTitleEvent", "ofType": null }, { "kind": "OBJECT", "name": "LockedEvent", "ofType": null }, { "kind": "OBJECT", "name": "UnlockedEvent", "ofType": null }, { "kind": "OBJECT", "name": "TransferredEvent", "ofType": null } ] }, { "kind": "OBJECT", "name": "IssueTimelineItemsConnection", "description": "The connection type for IssueTimelineItems.", "fields": [ { "name": "edges", "description": "A list of edges.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "IssueTimelineItemsEdge", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "filteredCount", "description": "Identifies the count of items after applying `before` and `after` filters.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "nodes", "description": "A list of nodes.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "UNION", "name": "IssueTimelineItems", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pageCount", "description": "Identifies the count of items after applying `before`/`after` filters and `first`/`last`/`skip` slicing.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pageInfo", "description": "Information to aid in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PageInfo", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "totalCount", "description": "Identifies the total count of items in the connection.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "updatedAt", "description": "Identifies the date and time when the timeline was last updated.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "IssueTimelineItemsEdge", "description": "An edge in a connection.", "fields": [ { "name": "cursor", "description": "A cursor for use in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "node", "description": "The item at the end of the edge.", "args": [], "type": { "kind": "UNION", "name": "IssueTimelineItems", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "UNION", "name": "IssueTimelineItems", "description": "An item in an issue timeline", "fields": null, "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": [ { "kind": "OBJECT", "name": "IssueComment", "ofType": null }, { "kind": "OBJECT", "name": "CrossReferencedEvent", "ofType": null }, { "kind": "OBJECT", "name": "AddedToProjectEvent", "ofType": null }, { "kind": "OBJECT", "name": "AssignedEvent", "ofType": null }, { "kind": "OBJECT", "name": "ClosedEvent", "ofType": null }, { "kind": "OBJECT", "name": "CommentDeletedEvent", "ofType": null }, { "kind": "OBJECT", "name": "ConvertedNoteToIssueEvent", "ofType": null }, { "kind": "OBJECT", "name": "DemilestonedEvent", "ofType": null }, { "kind": "OBJECT", "name": "LabeledEvent", "ofType": null }, { "kind": "OBJECT", "name": "LockedEvent", "ofType": null }, { "kind": "OBJECT", "name": "MentionedEvent", "ofType": null }, { "kind": "OBJECT", "name": "MilestonedEvent", "ofType": null }, { "kind": "OBJECT", "name": "MovedColumnsInProjectEvent", "ofType": null }, { "kind": "OBJECT", "name": "PinnedEvent", "ofType": null }, { "kind": "OBJECT", "name": "ReferencedEvent", "ofType": null }, { "kind": "OBJECT", "name": "RemovedFromProjectEvent", "ofType": null }, { "kind": "OBJECT", "name": "RenamedTitleEvent", "ofType": null }, { "kind": "OBJECT", "name": "ReopenedEvent", "ofType": null }, { "kind": "OBJECT", "name": "SubscribedEvent", "ofType": null }, { "kind": "OBJECT", "name": "TransferredEvent", "ofType": null }, { "kind": "OBJECT", "name": "UnassignedEvent", "ofType": null }, { "kind": "OBJECT", "name": "UnlabeledEvent", "ofType": null }, { "kind": "OBJECT", "name": "UnlockedEvent", "ofType": null }, { "kind": "OBJECT", "name": "UserBlockedEvent", "ofType": null }, { "kind": "OBJECT", "name": "UnpinnedEvent", "ofType": null }, { "kind": "OBJECT", "name": "UnsubscribedEvent", "ofType": null } ] }, { "kind": "ENUM", "name": "IssueTimelineItemsItemType", "description": "The possible item types found in a timeline.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "ISSUE_COMMENT", "description": "Represents a comment on an Issue.", "isDeprecated": false, "deprecationReason": null }, { "name": "CROSS_REFERENCED_EVENT", "description": "Represents a mention made by one issue or pull request to another.", "isDeprecated": false, "deprecationReason": null }, { "name": "ADDED_TO_PROJECT_EVENT", "description": "Represents a 'added_to_project' event on a given issue or pull request.", "isDeprecated": false, "deprecationReason": null }, { "name": "ASSIGNED_EVENT", "description": "Represents an 'assigned' event on any assignable object.", "isDeprecated": false, "deprecationReason": null }, { "name": "CLOSED_EVENT", "description": "Represents a 'closed' event on any `Closable`.", "isDeprecated": false, "deprecationReason": null }, { "name": "COMMENT_DELETED_EVENT", "description": "Represents a 'comment_deleted' event on a given issue or pull request.", "isDeprecated": false, "deprecationReason": null }, { "name": "CONVERTED_NOTE_TO_ISSUE_EVENT", "description": "Represents a 'converted_note_to_issue' event on a given issue or pull request.", "isDeprecated": false, "deprecationReason": null }, { "name": "DEMILESTONED_EVENT", "description": "Represents a 'demilestoned' event on a given issue or pull request.", "isDeprecated": false, "deprecationReason": null }, { "name": "LABELED_EVENT", "description": "Represents a 'labeled' event on a given issue or pull request.", "isDeprecated": false, "deprecationReason": null }, { "name": "LOCKED_EVENT", "description": "Represents a 'locked' event on a given issue or pull request.", "isDeprecated": false, "deprecationReason": null }, { "name": "MENTIONED_EVENT", "description": "Represents a 'mentioned' event on a given issue or pull request.", "isDeprecated": false, "deprecationReason": null }, { "name": "MILESTONED_EVENT", "description": "Represents a 'milestoned' event on a given issue or pull request.", "isDeprecated": false, "deprecationReason": null }, { "name": "MOVED_COLUMNS_IN_PROJECT_EVENT", "description": "Represents a 'moved_columns_in_project' event on a given issue or pull request.", "isDeprecated": false, "deprecationReason": null }, { "name": "PINNED_EVENT", "description": "Represents a 'pinned' event on a given issue or pull request.", "isDeprecated": false, "deprecationReason": null }, { "name": "REFERENCED_EVENT", "description": "Represents a 'referenced' event on a given `ReferencedSubject`.", "isDeprecated": false, "deprecationReason": null }, { "name": "REMOVED_FROM_PROJECT_EVENT", "description": "Represents a 'removed_from_project' event on a given issue or pull request.", "isDeprecated": false, "deprecationReason": null }, { "name": "RENAMED_TITLE_EVENT", "description": "Represents a 'renamed' event on a given issue or pull request", "isDeprecated": false, "deprecationReason": null }, { "name": "REOPENED_EVENT", "description": "Represents a 'reopened' event on any `Closable`.", "isDeprecated": false, "deprecationReason": null }, { "name": "SUBSCRIBED_EVENT", "description": "Represents a 'subscribed' event on a given `Subscribable`.", "isDeprecated": false, "deprecationReason": null }, { "name": "TRANSFERRED_EVENT", "description": "Represents a 'transferred' event on a given issue or pull request.", "isDeprecated": false, "deprecationReason": null }, { "name": "UNASSIGNED_EVENT", "description": "Represents an 'unassigned' event on any assignable object.", "isDeprecated": false, "deprecationReason": null }, { "name": "UNLABELED_EVENT", "description": "Represents an 'unlabeled' event on a given issue or pull request.", "isDeprecated": false, "deprecationReason": null }, { "name": "UNLOCKED_EVENT", "description": "Represents an 'unlocked' event on a given issue or pull request.", "isDeprecated": false, "deprecationReason": null }, { "name": "USER_BLOCKED_EVENT", "description": "Represents a 'user_blocked' event on a given user.", "isDeprecated": false, "deprecationReason": null }, { "name": "UNPINNED_EVENT", "description": "Represents an 'unpinned' event on a given issue or pull request.", "isDeprecated": false, "deprecationReason": null }, { "name": "UNSUBSCRIBED_EVENT", "description": "Represents an 'unsubscribed' event on a given `Subscribable`.", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null }, { "kind": "ENUM", "name": "CollaboratorAffiliation", "description": "Collaborators affiliation level with a subject.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "OUTSIDE", "description": "All outside collaborators of an organization-owned subject.", "isDeprecated": false, "deprecationReason": null }, { "name": "DIRECT", "description": "All collaborators with permissions to an organization-owned subject, regardless of organization membership status.", "isDeprecated": false, "deprecationReason": null }, { "name": "ALL", "description": "All collaborators the authenticated user can see.", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null }, { "kind": "OBJECT", "name": "DeployKeyConnection", "description": "The connection type for DeployKey.", "fields": [ { "name": "edges", "description": "A list of edges.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "DeployKeyEdge", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "nodes", "description": "A list of nodes.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "DeployKey", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pageInfo", "description": "Information to aid in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PageInfo", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "totalCount", "description": "Identifies the total count of items in the connection.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "DeployKeyEdge", "description": "An edge in a connection.", "fields": [ { "name": "cursor", "description": "A cursor for use in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "node", "description": "The item at the end of the edge.", "args": [], "type": { "kind": "OBJECT", "name": "DeployKey", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "DeployKey", "description": "A repository deploy key.", "fields": [ { "name": "createdAt", "description": "Identifies the date and time when the object was created.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "key", "description": "The deploy key.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "readOnly", "description": "Whether or not the deploy key is read only.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "title", "description": "The deploy key title.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "verified", "description": "Whether or not the deploy key has been verified.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "ENUM", "name": "RepositoryCollaboratorAffiliation", "description": "The affiliation type between collaborator and repository.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "ALL", "description": "All collaborators of the repository.", "isDeprecated": false, "deprecationReason": null }, { "name": "OUTSIDE", "description": "All outside collaborators of an organization-owned repository.", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null }, { "kind": "OBJECT", "name": "BranchProtectionRuleConnection", "description": "The connection type for BranchProtectionRule.", "fields": [ { "name": "edges", "description": "A list of edges.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "BranchProtectionRuleEdge", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "nodes", "description": "A list of nodes.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "BranchProtectionRule", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pageInfo", "description": "Information to aid in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PageInfo", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "totalCount", "description": "Identifies the total count of items in the connection.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "BranchProtectionRuleEdge", "description": "An edge in a connection.", "fields": [ { "name": "cursor", "description": "A cursor for use in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "node", "description": "The item at the end of the edge.", "args": [], "type": { "kind": "OBJECT", "name": "BranchProtectionRule", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "BranchProtectionRule", "description": "A branch protection rule.", "fields": [ { "name": "branchProtectionRuleConflicts", "description": "A list of conflicts matching branches protection rule and other branch protection rules", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "BranchProtectionRuleConflictConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "creator", "description": "The actor who created this branch protection rule.", "args": [], "type": { "kind": "INTERFACE", "name": "Actor", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "databaseId", "description": "Identifies the primary key from the database.", "args": [], "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "dismissesStaleReviews", "description": "Will new commits pushed to matching branches dismiss pull request review approvals.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "isAdminEnforced", "description": "Can admins overwrite branch protection.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "matchingRefs", "description": "Repository refs that are protected by this rule", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "RefConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pattern", "description": "Identifies the protection rule pattern.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pushAllowances", "description": "A list push allowances for this branch protection rule.", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PushAllowanceConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "repository", "description": "The repository associated with this branch protection rule.", "args": [], "type": { "kind": "OBJECT", "name": "Repository", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "requiredApprovingReviewCount", "description": "Number of approving reviews required to update matching branches.", "args": [], "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "requiredStatusCheckContexts", "description": "List of required status check contexts that must pass for commits to be accepted to matching branches.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "requiresApprovingReviews", "description": "Are approving reviews required to update matching branches.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "requiresCommitSignatures", "description": "Are commits required to be signed.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "requiresStatusChecks", "description": "Are status checks required to update matching branches.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "requiresStrictStatusChecks", "description": "Are branches required to be up to date before merging.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "restrictsPushes", "description": "Is pushing to matching branches restricted.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "restrictsReviewDismissals", "description": "Is dismissal of pull request reviews restricted.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "reviewDismissalAllowances", "description": "A list review dismissal allowances for this branch protection rule.", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "ReviewDismissalAllowanceConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "ReviewDismissalAllowanceConnection", "description": "The connection type for ReviewDismissalAllowance.", "fields": [ { "name": "edges", "description": "A list of edges.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "ReviewDismissalAllowanceEdge", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "nodes", "description": "A list of nodes.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "ReviewDismissalAllowance", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pageInfo", "description": "Information to aid in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PageInfo", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "totalCount", "description": "Identifies the total count of items in the connection.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "ReviewDismissalAllowanceEdge", "description": "An edge in a connection.", "fields": [ { "name": "cursor", "description": "A cursor for use in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "node", "description": "The item at the end of the edge.", "args": [], "type": { "kind": "OBJECT", "name": "ReviewDismissalAllowance", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "ReviewDismissalAllowance", "description": "A team or user who has the ability to dismiss a review on a protected branch.", "fields": [ { "name": "actor", "description": "The actor that can dismiss.", "args": [], "type": { "kind": "UNION", "name": "ReviewDismissalAllowanceActor", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "branchProtectionRule", "description": "Identifies the branch protection rule associated with the allowed user or team.", "args": [], "type": { "kind": "OBJECT", "name": "BranchProtectionRule", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "UNION", "name": "ReviewDismissalAllowanceActor", "description": "Types that can be an actor.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": [ { "kind": "OBJECT", "name": "User", "ofType": null }, { "kind": "OBJECT", "name": "Team", "ofType": null } ] }, { "kind": "OBJECT", "name": "PushAllowanceConnection", "description": "The connection type for PushAllowance.", "fields": [ { "name": "edges", "description": "A list of edges.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "PushAllowanceEdge", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "nodes", "description": "A list of nodes.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "PushAllowance", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pageInfo", "description": "Information to aid in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PageInfo", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "totalCount", "description": "Identifies the total count of items in the connection.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "PushAllowanceEdge", "description": "An edge in a connection.", "fields": [ { "name": "cursor", "description": "A cursor for use in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "node", "description": "The item at the end of the edge.", "args": [], "type": { "kind": "OBJECT", "name": "PushAllowance", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "PushAllowance", "description": "A team or user who has the ability to push to a protected branch.", "fields": [ { "name": "actor", "description": "The actor that can push.", "args": [], "type": { "kind": "UNION", "name": "PushAllowanceActor", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "branchProtectionRule", "description": "Identifies the branch protection rule associated with the allowed user or team.", "args": [], "type": { "kind": "OBJECT", "name": "BranchProtectionRule", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "UNION", "name": "PushAllowanceActor", "description": "Types that can be an actor.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": [ { "kind": "OBJECT", "name": "User", "ofType": null }, { "kind": "OBJECT", "name": "Team", "ofType": null } ] }, { "kind": "OBJECT", "name": "RefConnection", "description": "The connection type for Ref.", "fields": [ { "name": "edges", "description": "A list of edges.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "RefEdge", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "nodes", "description": "A list of nodes.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "Ref", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pageInfo", "description": "Information to aid in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PageInfo", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "totalCount", "description": "Identifies the total count of items in the connection.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "RefEdge", "description": "An edge in a connection.", "fields": [ { "name": "cursor", "description": "A cursor for use in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "node", "description": "The item at the end of the edge.", "args": [], "type": { "kind": "OBJECT", "name": "Ref", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "BranchProtectionRuleConflictConnection", "description": "The connection type for BranchProtectionRuleConflict.", "fields": [ { "name": "edges", "description": "A list of edges.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "BranchProtectionRuleConflictEdge", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "nodes", "description": "A list of nodes.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "BranchProtectionRuleConflict", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pageInfo", "description": "Information to aid in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PageInfo", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "totalCount", "description": "Identifies the total count of items in the connection.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "BranchProtectionRuleConflictEdge", "description": "An edge in a connection.", "fields": [ { "name": "cursor", "description": "A cursor for use in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "node", "description": "The item at the end of the edge.", "args": [], "type": { "kind": "OBJECT", "name": "BranchProtectionRuleConflict", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "BranchProtectionRuleConflict", "description": "A conflict between two branch protection rules.", "fields": [ { "name": "branchProtectionRule", "description": "Identifies the branch protection rule.", "args": [], "type": { "kind": "OBJECT", "name": "BranchProtectionRule", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "conflictingBranchProtectionRule", "description": "Identifies the conflicting branch protection rule.", "args": [], "type": { "kind": "OBJECT", "name": "BranchProtectionRule", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "ref", "description": "Identifies the branch ref that has conflicting rules", "args": [], "type": { "kind": "OBJECT", "name": "Ref", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "MilestoneConnection", "description": "The connection type for Milestone.", "fields": [ { "name": "edges", "description": "A list of edges.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "MilestoneEdge", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "nodes", "description": "A list of nodes.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "Milestone", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pageInfo", "description": "Information to aid in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PageInfo", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "totalCount", "description": "Identifies the total count of items in the connection.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "MilestoneEdge", "description": "An edge in a connection.", "fields": [ { "name": "cursor", "description": "A cursor for use in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "node", "description": "The item at the end of the edge.", "args": [], "type": { "kind": "OBJECT", "name": "Milestone", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "MilestoneOrder", "description": "Ordering options for milestone connections.", "fields": null, "inputFields": [ { "name": "field", "description": "The field to order milestones by.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "MilestoneOrderField", "ofType": null } }, "defaultValue": null }, { "name": "direction", "description": "The ordering direction.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "OrderDirection", "ofType": null } }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "ENUM", "name": "MilestoneOrderField", "description": "Properties by which milestone connections can be ordered.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "DUE_DATE", "description": "Order milestones by when they are due.", "isDeprecated": false, "deprecationReason": null }, { "name": "CREATED_AT", "description": "Order milestones by when they were created.", "isDeprecated": false, "deprecationReason": null }, { "name": "UPDATED_AT", "description": "Order milestones by when they were last updated.", "isDeprecated": false, "deprecationReason": null }, { "name": "NUMBER", "description": "Order milestones by their number.", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null }, { "kind": "OBJECT", "name": "CodeOfConduct", "description": "The Code of Conduct for a repository", "fields": [ { "name": "body", "description": "The body of the Code of Conduct", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "key", "description": "The key for the Code of Conduct", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "name", "description": "The formal name of the Code of Conduct", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "resourcePath", "description": "The HTTP path for this Code of Conduct", "args": [], "type": { "kind": "SCALAR", "name": "URI", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "url", "description": "The HTTP URL for this Code of Conduct", "args": [], "type": { "kind": "SCALAR", "name": "URI", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "RepositoryCollaboratorConnection", "description": "The connection type for User.", "fields": [ { "name": "edges", "description": "A list of edges.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "RepositoryCollaboratorEdge", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "nodes", "description": "A list of nodes.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "User", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pageInfo", "description": "Information to aid in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PageInfo", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "totalCount", "description": "Identifies the total count of items in the connection.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "RepositoryCollaboratorEdge", "description": "Represents a user who is a collaborator of a repository.", "fields": [ { "name": "cursor", "description": "A cursor for use in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "node", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "User", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "permission", "description": "The permission the user has on the repository.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "RepositoryPermission", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "permissionSources", "description": "A list of sources for the user's access to the repository.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PermissionSource", "ofType": null } } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "PermissionSource", "description": "A level of permission and source for a user's access to a repository.", "fields": [ { "name": "organization", "description": "The organization the repository belongs to.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "Organization", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "permission", "description": "The level of access this source has granted to the user.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "DefaultRepositoryPermissionField", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "source", "description": "The source of this permission.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "UNION", "name": "PermissionGranter", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "UNION", "name": "PermissionGranter", "description": "Types that can grant permissions on a repository to a user", "fields": null, "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": [ { "kind": "OBJECT", "name": "Organization", "ofType": null }, { "kind": "OBJECT", "name": "Repository", "ofType": null }, { "kind": "OBJECT", "name": "Team", "ofType": null } ] }, { "kind": "INPUT_OBJECT", "name": "LanguageOrder", "description": "Ordering options for language connections.", "fields": null, "inputFields": [ { "name": "field", "description": "The field to order languages by.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "LanguageOrderField", "ofType": null } }, "defaultValue": null }, { "name": "direction", "description": "The ordering direction.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "OrderDirection", "ofType": null } }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "ENUM", "name": "LanguageOrderField", "description": "Properties by which language connections can be ordered.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "SIZE", "description": "Order languages by the size of all files containing the language", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "RefOrder", "description": "Ways in which lists of git refs can be ordered upon return.", "fields": null, "inputFields": [ { "name": "field", "description": "The field in which to order refs by.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "RefOrderField", "ofType": null } }, "defaultValue": null }, { "name": "direction", "description": "The direction in which to order refs by the specified field.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "OrderDirection", "ofType": null } }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "ENUM", "name": "RefOrderField", "description": "Properties by which ref connections can be ordered.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "TAG_COMMIT_DATE", "description": "Order refs by underlying commit date if the ref prefix is refs/tags/", "isDeprecated": false, "deprecationReason": null }, { "name": "ALPHABETICAL", "description": "Order refs by their alphanumeric name", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null }, { "kind": "OBJECT", "name": "SecurityAdvisory", "description": "A GitHub Security Advisory", "fields": [ { "name": "databaseId", "description": "Identifies the primary key from the database.", "args": [], "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "description", "description": "This is a long plaintext description of the advisory", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "ghsaId", "description": "The GitHub Security Advisory ID", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "identifiers", "description": "A list of identifiers for this advisory", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "SecurityAdvisoryIdentifier", "ofType": null } } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "origin", "description": "The organization that originated the advisory", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "publishedAt", "description": "When the advisory was published", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "references", "description": "A list of references for this advisory", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "SecurityAdvisoryReference", "ofType": null } } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "severity", "description": "The severity of the advisory", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "SecurityAdvisorySeverity", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "summary", "description": "A short plaintext summary of the advisory", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "updatedAt", "description": "When the advisory was last updated", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "vulnerabilities", "description": "Vulnerabilities associated with this Advisory", "args": [ { "name": "orderBy", "description": "Ordering options for the returned topics.", "type": { "kind": "INPUT_OBJECT", "name": "SecurityVulnerabilityOrder", "ofType": null }, "defaultValue": "{field:\"UPDATED_AT\",direction:\"DESC\"}" }, { "name": "ecosystem", "description": "An ecosystem to filter vulnerabilities by.", "type": { "kind": "ENUM", "name": "SecurityAdvisoryEcosystem", "ofType": null }, "defaultValue": null }, { "name": "package", "description": "A package name to filter vulnerabilities by.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "severities", "description": "A list of severities to filter vulnerabilities by.", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "SecurityAdvisorySeverity", "ofType": null } } }, "defaultValue": null }, { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "SecurityVulnerabilityConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "withdrawnAt", "description": "When the advisory was withdrawn, if it has been withdrawn", "args": [], "type": { "kind": "SCALAR", "name": "DateTime", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "ENUM", "name": "SecurityAdvisorySeverity", "description": "Severity of the vulnerability.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "LOW", "description": "Low.", "isDeprecated": false, "deprecationReason": null }, { "name": "MODERATE", "description": "Moderate.", "isDeprecated": false, "deprecationReason": null }, { "name": "HIGH", "description": "High.", "isDeprecated": false, "deprecationReason": null }, { "name": "CRITICAL", "description": "Critical.", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null }, { "kind": "OBJECT", "name": "SecurityAdvisoryIdentifier", "description": "A GitHub Security Advisory Identifier", "fields": [ { "name": "type", "description": "The identifier type, e.g. GHSA, CVE", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "value", "description": "The identifier", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "SecurityAdvisoryReference", "description": "A GitHub Security Advisory Reference", "fields": [ { "name": "url", "description": "A publicly accessible reference", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "SecurityVulnerabilityConnection", "description": "The connection type for SecurityVulnerability.", "fields": [ { "name": "edges", "description": "A list of edges.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "SecurityVulnerabilityEdge", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "nodes", "description": "A list of nodes.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "SecurityVulnerability", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pageInfo", "description": "Information to aid in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PageInfo", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "totalCount", "description": "Identifies the total count of items in the connection.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "SecurityVulnerabilityEdge", "description": "An edge in a connection.", "fields": [ { "name": "cursor", "description": "A cursor for use in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "node", "description": "The item at the end of the edge.", "args": [], "type": { "kind": "OBJECT", "name": "SecurityVulnerability", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "SecurityVulnerability", "description": "An individual vulnerability within an Advisory", "fields": [ { "name": "advisory", "description": "The Advisory associated with this Vulnerability", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "SecurityAdvisory", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "firstPatchedVersion", "description": "The first version containing a fix for the vulnerability", "args": [], "type": { "kind": "OBJECT", "name": "SecurityAdvisoryPackageVersion", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "package", "description": "A description of the vulnerable package", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "SecurityAdvisoryPackage", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "severity", "description": "The severity of the vulnerability within this package", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "SecurityAdvisorySeverity", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "updatedAt", "description": "When the vulnerability was last updated", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "vulnerableVersionRange", "description": "A string that describes the vulnerable package versions.\nThis string follows a basic syntax with a few forms.\n+ `= 0.2.0` denotes a single vulnerable version.\n+ `<= 1.0.8` denotes a version range up to and including the specified version\n+ `< 0.1.11` denotes a version range up to, but excluding, the specified version\n+ `>= 4.3.0, < 4.3.5` denotes a version range with a known minimum and maximum version.\n+ `>= 0.0.1` denotes a version range with a known minimum, but no known maximum\n", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "SecurityAdvisoryPackage", "description": "An individual package", "fields": [ { "name": "ecosystem", "description": "The ecosystem the package belongs to, e.g. RUBYGEMS, NPM", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "SecurityAdvisoryEcosystem", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "name", "description": "The package name", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "ENUM", "name": "SecurityAdvisoryEcosystem", "description": "The possible ecosystems of a security vulnerability's package.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "RUBYGEMS", "description": "Ruby gems hosted at RubyGems.org", "isDeprecated": false, "deprecationReason": null }, { "name": "NPM", "description": "JavaScript packages hosted at npmjs.com", "isDeprecated": false, "deprecationReason": null }, { "name": "PIP", "description": "Python packages hosted at PyPI.org", "isDeprecated": false, "deprecationReason": null }, { "name": "MAVEN", "description": "Java artifacts hosted at the Maven central repository", "isDeprecated": false, "deprecationReason": null }, { "name": "NUGET", "description": ".NET packages hosted at the NuGet Gallery", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null }, { "kind": "OBJECT", "name": "SecurityAdvisoryPackageVersion", "description": "An individual package version", "fields": [ { "name": "identifier", "description": "The package name or version", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "SecurityVulnerabilityOrder", "description": "Ordering options for security vulnerability connections", "fields": null, "inputFields": [ { "name": "field", "description": "The field to order security vulnerabilities by.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "SecurityVulnerabilityOrderField", "ofType": null } }, "defaultValue": null }, { "name": "direction", "description": "The ordering direction.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "OrderDirection", "ofType": null } }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "ENUM", "name": "SecurityVulnerabilityOrderField", "description": "Properties by which security vulnerability connections can be ordered.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "UPDATED_AT", "description": "Order vulnerability by update time", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null }, { "kind": "SCALAR", "name": "GitSSHRemote", "description": "Git SSH string", "fields": null, "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "TopicConnection", "description": "The connection type for Topic.", "fields": [ { "name": "edges", "description": "A list of edges.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "TopicEdge", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "nodes", "description": "A list of nodes.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "Topic", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pageInfo", "description": "Information to aid in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PageInfo", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "totalCount", "description": "Identifies the total count of items in the connection.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "TopicEdge", "description": "An edge in a connection.", "fields": [ { "name": "cursor", "description": "A cursor for use in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "node", "description": "The item at the end of the edge.", "args": [], "type": { "kind": "OBJECT", "name": "Topic", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "ContributionsCollection", "description": "A contributions collection aggregates contributions such as opened issues and commits created by a user.", "fields": [ { "name": "commitContributionsByRepository", "description": "Commit contributions made by the user, grouped by repository.", "args": [ { "name": "maxRepositories", "description": "How many repositories should be included.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": "25" } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "CommitContributionsByRepository", "ofType": null } } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "contributionCalendar", "description": "A calendar of this user's contributions on GitHub.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "ContributionCalendar", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "contributionYears", "description": "The years the user has been making contributions with the most recent year first.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "doesEndInCurrentMonth", "description": "Determine if this collection's time span ends in the current month.\n", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "earliestRestrictedContributionDate", "description": "The date of the first restricted contribution the user made in this time period. Can only be non-null when the user has enabled private contribution counts.", "args": [], "type": { "kind": "SCALAR", "name": "Date", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "endedAt", "description": "The ending date and time of this collection.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "firstIssueContribution", "description": "The first issue the user opened on GitHub. This will be null if that issue was opened outside the collection's time range and ignoreTimeRange is false. If the issue is not visible but the user has opted to show private contributions, a RestrictedContribution will be returned.", "args": [ { "name": "ignoreTimeRange", "description": "If true, the first issue will be returned even if it was opened outside of the collection's time range.\n\n**Upcoming Change on 2019-07-01 UTC**\n**Description:** `ignoreTimeRange` will be removed. Use a `ContributionsCollection` starting sufficiently far back\n**Reason:** ignore_time_range will be removed\n", "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": "false" } ], "type": { "kind": "UNION", "name": "CreatedIssueOrRestrictedContribution", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "firstPullRequestContribution", "description": "The first pull request the user opened on GitHub. This will be null if that pull request was opened outside the collection's time range and ignoreTimeRange is not true. If the pull request is not visible but the user has opted to show private contributions, a RestrictedContribution will be returned.", "args": [ { "name": "ignoreTimeRange", "description": "If true, the first pull request will be returned even if it was opened outside of the collection's time range.\n\n**Upcoming Change on 2019-07-01 UTC**\n**Description:** `ignoreTimeRange` will be removed. Use a `ContributionsCollection` starting sufficiently far back\n**Reason:** ignore_time_range will be removed\n", "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": "false" } ], "type": { "kind": "UNION", "name": "CreatedPullRequestOrRestrictedContribution", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "firstRepositoryContribution", "description": "The first repository the user created on GitHub. This will be null if that first repository was created outside the collection's time range and ignoreTimeRange is false. If the repository is not visible, then a RestrictedContribution is returned.", "args": [ { "name": "ignoreTimeRange", "description": "If true, the first repository will be returned even if it was opened outside of the collection's time range.\n\n**Upcoming Change on 2019-07-01 UTC**\n**Description:** `ignoreTimeRange` will be removed. Use a `ContributionsCollection` starting sufficiently far back\n**Reason:** ignore_time_range will be removed\n", "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": "false" } ], "type": { "kind": "UNION", "name": "CreatedRepositoryOrRestrictedContribution", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "hasActivityInThePast", "description": "Does the user have any more activity in the timeline that occurred prior to the collection's time range?", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "hasAnyContributions", "description": "Determine if there are any contributions in this collection.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "hasAnyRestrictedContributions", "description": "Determine if the user made any contributions in this time frame whose details are not visible because they were made in a private repository. Can only be true if the user enabled private contribution counts.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "isSingleDay", "description": "Whether or not the collector's time span is all within the same day.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "issueContributions", "description": "A list of issues the user opened.", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "excludeFirst", "description": "Should the user's first issue ever be excluded from the result.", "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": "false" }, { "name": "excludePopular", "description": "Should the user's most commented issue be excluded from the result.", "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": "false" }, { "name": "orderBy", "description": "Ordering options for contributions returned from the connection.", "type": { "kind": "INPUT_OBJECT", "name": "ContributionOrder", "ofType": null }, "defaultValue": "{field:\"OCCURRED_AT\",direction:\"DESC\"}" } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "CreatedIssueContributionConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "issueContributionsByRepository", "description": "Issue contributions made by the user, grouped by repository.", "args": [ { "name": "maxRepositories", "description": "How many repositories should be included.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": "25" }, { "name": "excludeFirst", "description": "Should the user's first issue ever be excluded from the result.", "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": "false" }, { "name": "excludePopular", "description": "Should the user's most commented issue be excluded from the result.", "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": "false" } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "IssueContributionsByRepository", "ofType": null } } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "joinedGitHubContribution", "description": "When the user signed up for GitHub. This will be null if that sign up date falls outside the collection's time range and ignoreTimeRange is false.", "args": [ { "name": "ignoreTimeRange", "description": "If true, the contribution will be returned even if the user signed up outside of the collection's time range.\n\n**Upcoming Change on 2019-07-01 UTC**\n**Description:** `ignoreTimeRange` will be removed. Use a `ContributionsCollection` starting sufficiently far back\n**Reason:** ignore_time_range will be removed\n", "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": "false" } ], "type": { "kind": "OBJECT", "name": "JoinedGitHubContribution", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "latestRestrictedContributionDate", "description": "The date of the most recent restricted contribution the user made in this time period. Can only be non-null when the user has enabled private contribution counts.", "args": [], "type": { "kind": "SCALAR", "name": "Date", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "mostRecentCollectionWithActivity", "description": "When this collection's time range does not include any activity from the user, use this\nto get a different collection from an earlier time range that does have activity.\n", "args": [], "type": { "kind": "OBJECT", "name": "ContributionsCollection", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "mostRecentCollectionWithoutActivity", "description": "Returns a different contributions collection from an earlier time range than this one\nthat does not have any contributions.\n", "args": [], "type": { "kind": "OBJECT", "name": "ContributionsCollection", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "popularIssueContribution", "description": "The issue the user opened on GitHub that received the most comments in the specified\ntime frame.\n", "args": [], "type": { "kind": "OBJECT", "name": "CreatedIssueContribution", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "popularPullRequestContribution", "description": "The pull request the user opened on GitHub that received the most comments in the\nspecified time frame.\n", "args": [], "type": { "kind": "OBJECT", "name": "CreatedPullRequestContribution", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "pullRequestContributions", "description": "Pull request contributions made by the user.", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "excludeFirst", "description": "Should the user's first pull request ever be excluded from the result.", "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": "false" }, { "name": "excludePopular", "description": "Should the user's most commented pull request be excluded from the result.", "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": "false" }, { "name": "orderBy", "description": "Ordering options for contributions returned from the connection.", "type": { "kind": "INPUT_OBJECT", "name": "ContributionOrder", "ofType": null }, "defaultValue": "{field:\"OCCURRED_AT\",direction:\"DESC\"}" } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "CreatedPullRequestContributionConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pullRequestContributionsByRepository", "description": "Pull request contributions made by the user, grouped by repository.", "args": [ { "name": "maxRepositories", "description": "How many repositories should be included.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": "25" }, { "name": "excludeFirst", "description": "Should the user's first pull request ever be excluded from the result.", "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": "false" }, { "name": "excludePopular", "description": "Should the user's most commented pull request be excluded from the result.", "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": "false" } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PullRequestContributionsByRepository", "ofType": null } } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pullRequestReviewContributions", "description": "Pull request review contributions made by the user.", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "orderBy", "description": "Ordering options for contributions returned from the connection.", "type": { "kind": "INPUT_OBJECT", "name": "ContributionOrder", "ofType": null }, "defaultValue": "{field:\"OCCURRED_AT\",direction:\"DESC\"}" } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "CreatedPullRequestReviewContributionConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pullRequestReviewContributionsByRepository", "description": "Pull request review contributions made by the user, grouped by repository.", "args": [ { "name": "maxRepositories", "description": "How many repositories should be included.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": "25" } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PullRequestReviewContributionsByRepository", "ofType": null } } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "repositoryContributions", "description": "A list of repositories owned by the user that the user created in this time range.", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "excludeFirst", "description": "Should the user's first repository ever be excluded from the result.", "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": "false" }, { "name": "orderBy", "description": "Ordering options for contributions returned from the connection.", "type": { "kind": "INPUT_OBJECT", "name": "ContributionOrder", "ofType": null }, "defaultValue": "{field:\"OCCURRED_AT\",direction:\"DESC\"}" } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "CreatedRepositoryContributionConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "restrictedContributionsCount", "description": "A count of contributions made by the user that the viewer cannot access. Only non-zero when the user has chosen to share their private contribution counts.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "startedAt", "description": "The beginning date and time of this collection.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "totalCommitContributions", "description": "How many commits were made by the user in this time span.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "totalIssueContributions", "description": "How many issues the user opened.", "args": [ { "name": "excludeFirst", "description": "Should the user's first issue ever be excluded from this count.", "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": "false" }, { "name": "excludePopular", "description": "Should the user's most commented issue be excluded from this count.", "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": "false" } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "totalPullRequestContributions", "description": "How many pull requests the user opened.", "args": [ { "name": "excludeFirst", "description": "Should the user's first pull request ever be excluded from this count.", "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": "false" }, { "name": "excludePopular", "description": "Should the user's most commented pull request be excluded from this count.", "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": "false" } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "totalPullRequestReviewContributions", "description": "How many pull request reviews the user left.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "totalRepositoriesWithContributedCommits", "description": "How many different repositories the user committed to.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "totalRepositoriesWithContributedIssues", "description": "How many different repositories the user opened issues in.", "args": [ { "name": "excludeFirst", "description": "Should the user's first issue ever be excluded from this count.", "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": "false" }, { "name": "excludePopular", "description": "Should the user's most commented issue be excluded from this count.", "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": "false" } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "totalRepositoriesWithContributedPullRequestReviews", "description": "How many different repositories the user left pull request reviews in.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "totalRepositoriesWithContributedPullRequests", "description": "How many different repositories the user opened pull requests in.", "args": [ { "name": "excludeFirst", "description": "Should the user's first pull request ever be excluded from this count.", "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": "false" }, { "name": "excludePopular", "description": "Should the user's most commented pull request be excluded from this count.", "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": "false" } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "totalRepositoryContributions", "description": "How many repositories the user created.", "args": [ { "name": "excludeFirst", "description": "Should the user's first repository ever be excluded from this count.", "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": "false" } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "user", "description": "The user who made the contributions in this collection.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "User", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "CreatedIssueContributionConnection", "description": "The connection type for CreatedIssueContribution.", "fields": [ { "name": "edges", "description": "A list of edges.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "CreatedIssueContributionEdge", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "nodes", "description": "A list of nodes.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "CreatedIssueContribution", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pageInfo", "description": "Information to aid in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PageInfo", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "totalCount", "description": "Identifies the total count of items in the connection.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "CreatedIssueContributionEdge", "description": "An edge in a connection.", "fields": [ { "name": "cursor", "description": "A cursor for use in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "node", "description": "The item at the end of the edge.", "args": [], "type": { "kind": "OBJECT", "name": "CreatedIssueContribution", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "CreatedIssueContribution", "description": "Represents the contribution a user made on GitHub by opening an issue.", "fields": [ { "name": "isRestricted", "description": "Whether this contribution is associated with a record you do not have access to. For\nexample, your own 'first issue' contribution may have been made on a repository you can no\nlonger access.\n", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "issue", "description": "The issue that was opened.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "Issue", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "occurredAt", "description": "When this contribution was made.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "resourcePath", "description": "The HTTP path for this contribution.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "url", "description": "The HTTP URL for this contribution.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "user", "description": "The user who made this contribution.\n", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "User", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Contribution", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "INTERFACE", "name": "Contribution", "description": "Represents a contribution a user made on GitHub, such as opening an issue.", "fields": [ { "name": "isRestricted", "description": "Whether this contribution is associated with a record you do not have access to. For\nexample, your own 'first issue' contribution may have been made on a repository you can no\nlonger access.\n", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "occurredAt", "description": "When this contribution was made.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "resourcePath", "description": "The HTTP path for this contribution.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "url", "description": "The HTTP URL for this contribution.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "user", "description": "The user who made this contribution.\n", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "User", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": [ { "kind": "OBJECT", "name": "CreatedCommitContribution", "ofType": null }, { "kind": "OBJECT", "name": "CreatedIssueContribution", "ofType": null }, { "kind": "OBJECT", "name": "CreatedPullRequestContribution", "ofType": null }, { "kind": "OBJECT", "name": "CreatedPullRequestReviewContribution", "ofType": null }, { "kind": "OBJECT", "name": "CreatedRepositoryContribution", "ofType": null }, { "kind": "OBJECT", "name": "JoinedGitHubContribution", "ofType": null }, { "kind": "OBJECT", "name": "RestrictedContribution", "ofType": null } ] }, { "kind": "INPUT_OBJECT", "name": "ContributionOrder", "description": "Ordering options for contribution connections.", "fields": null, "inputFields": [ { "name": "field", "description": "The field by which to order contributions.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "ContributionOrderField", "ofType": null } }, "defaultValue": null }, { "name": "direction", "description": "The ordering direction.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "OrderDirection", "ofType": null } }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "ENUM", "name": "ContributionOrderField", "description": "Properties by which contribution connections can be ordered.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "OCCURRED_AT", "description": "Order contributions by when they were made.", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null }, { "kind": "OBJECT", "name": "CreatedRepositoryContributionConnection", "description": "The connection type for CreatedRepositoryContribution.", "fields": [ { "name": "edges", "description": "A list of edges.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "CreatedRepositoryContributionEdge", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "nodes", "description": "A list of nodes.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "CreatedRepositoryContribution", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pageInfo", "description": "Information to aid in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PageInfo", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "totalCount", "description": "Identifies the total count of items in the connection.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "CreatedRepositoryContributionEdge", "description": "An edge in a connection.", "fields": [ { "name": "cursor", "description": "A cursor for use in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "node", "description": "The item at the end of the edge.", "args": [], "type": { "kind": "OBJECT", "name": "CreatedRepositoryContribution", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "CreatedRepositoryContribution", "description": "Represents the contribution a user made on GitHub by creating a repository.", "fields": [ { "name": "isRestricted", "description": "Whether this contribution is associated with a record you do not have access to. For\nexample, your own 'first issue' contribution may have been made on a repository you can no\nlonger access.\n", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "occurredAt", "description": "When this contribution was made.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "repository", "description": "The repository that was created.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "Repository", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "resourcePath", "description": "The HTTP path for this contribution.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "url", "description": "The HTTP URL for this contribution.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "user", "description": "The user who made this contribution.\n", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "User", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Contribution", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "JoinedGitHubContribution", "description": "Represents a user signing up for a GitHub account.", "fields": [ { "name": "isRestricted", "description": "Whether this contribution is associated with a record you do not have access to. For\nexample, your own 'first issue' contribution may have been made on a repository you can no\nlonger access.\n", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "occurredAt", "description": "When this contribution was made.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "resourcePath", "description": "The HTTP path for this contribution.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "url", "description": "The HTTP URL for this contribution.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "user", "description": "The user who made this contribution.\n", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "User", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Contribution", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "UNION", "name": "CreatedRepositoryOrRestrictedContribution", "description": "Represents either a repository the viewer can access or a restricted contribution.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": [ { "kind": "OBJECT", "name": "CreatedRepositoryContribution", "ofType": null }, { "kind": "OBJECT", "name": "RestrictedContribution", "ofType": null } ] }, { "kind": "OBJECT", "name": "RestrictedContribution", "description": "Represents a private contribution a user made on GitHub.", "fields": [ { "name": "isRestricted", "description": "Whether this contribution is associated with a record you do not have access to. For\nexample, your own 'first issue' contribution may have been made on a repository you can no\nlonger access.\n", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "occurredAt", "description": "When this contribution was made.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "resourcePath", "description": "The HTTP path for this contribution.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "url", "description": "The HTTP URL for this contribution.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "user", "description": "The user who made this contribution.\n", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "User", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Contribution", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "UNION", "name": "CreatedIssueOrRestrictedContribution", "description": "Represents either a issue the viewer can access or a restricted contribution.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": [ { "kind": "OBJECT", "name": "CreatedIssueContribution", "ofType": null }, { "kind": "OBJECT", "name": "RestrictedContribution", "ofType": null } ] }, { "kind": "UNION", "name": "CreatedPullRequestOrRestrictedContribution", "description": "Represents either a pull request the viewer can access or a restricted contribution.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": [ { "kind": "OBJECT", "name": "CreatedPullRequestContribution", "ofType": null }, { "kind": "OBJECT", "name": "RestrictedContribution", "ofType": null } ] }, { "kind": "OBJECT", "name": "CreatedPullRequestContribution", "description": "Represents the contribution a user made on GitHub by opening a pull request.", "fields": [ { "name": "isRestricted", "description": "Whether this contribution is associated with a record you do not have access to. For\nexample, your own 'first issue' contribution may have been made on a repository you can no\nlonger access.\n", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "occurredAt", "description": "When this contribution was made.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pullRequest", "description": "The pull request that was opened.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PullRequest", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "resourcePath", "description": "The HTTP path for this contribution.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "url", "description": "The HTTP URL for this contribution.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "user", "description": "The user who made this contribution.\n", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "User", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Contribution", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "ContributionCalendar", "description": "A calendar of contributions made on GitHub by a user.", "fields": [ { "name": "colors", "description": "A list of hex color codes used in this calendar. The darker the color, the more contributions it represents.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "isHalloween", "description": "Determine if the color set was chosen because it's currently Halloween.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "months", "description": "A list of the months of contributions in this calendar.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "ContributionCalendarMonth", "ofType": null } } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "totalContributions", "description": "The count of total contributions in the calendar.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "weeks", "description": "A list of the weeks of contributions in this calendar.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "ContributionCalendarWeek", "ofType": null } } } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "ContributionCalendarWeek", "description": "A week of contributions in a user's contribution graph.", "fields": [ { "name": "contributionDays", "description": "The days of contributions in this week.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "ContributionCalendarDay", "ofType": null } } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "firstDay", "description": "The date of the earliest square in this week.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Date", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "ContributionCalendarDay", "description": "Represents a single day of contributions on GitHub by a user.", "fields": [ { "name": "color", "description": "The hex color code that represents how many contributions were made on this day compared to others in the calendar.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "contributionCount", "description": "How many contributions were made by the user on this day.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "date", "description": "The day this square represents.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Date", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "weekday", "description": "A number representing which day of the week this square represents, e.g., 1 is Monday.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "ContributionCalendarMonth", "description": "A month of contributions in a user's contribution graph.", "fields": [ { "name": "firstDay", "description": "The date of the first day of this month.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Date", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "name", "description": "The name of the month.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "totalWeeks", "description": "How many weeks started in this month.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "year", "description": "The year the month occurred in.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "CreatedPullRequestReviewContributionConnection", "description": "The connection type for CreatedPullRequestReviewContribution.", "fields": [ { "name": "edges", "description": "A list of edges.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "CreatedPullRequestReviewContributionEdge", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "nodes", "description": "A list of nodes.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "CreatedPullRequestReviewContribution", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pageInfo", "description": "Information to aid in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PageInfo", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "totalCount", "description": "Identifies the total count of items in the connection.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "CreatedPullRequestReviewContributionEdge", "description": "An edge in a connection.", "fields": [ { "name": "cursor", "description": "A cursor for use in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "node", "description": "The item at the end of the edge.", "args": [], "type": { "kind": "OBJECT", "name": "CreatedPullRequestReviewContribution", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "CreatedPullRequestReviewContribution", "description": "Represents the contribution a user made by leaving a review on a pull request.", "fields": [ { "name": "isRestricted", "description": "Whether this contribution is associated with a record you do not have access to. For\nexample, your own 'first issue' contribution may have been made on a repository you can no\nlonger access.\n", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "occurredAt", "description": "When this contribution was made.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pullRequest", "description": "The pull request the user reviewed.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PullRequest", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pullRequestReview", "description": "The review the user left on the pull request.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PullRequestReview", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "repository", "description": "The repository containing the pull request that the user reviewed.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "Repository", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "resourcePath", "description": "The HTTP path for this contribution.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "url", "description": "The HTTP URL for this contribution.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "user", "description": "The user who made this contribution.\n", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "User", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Contribution", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "PullRequestReviewContributionsByRepository", "description": "This aggregates pull request reviews made by a user within one repository.", "fields": [ { "name": "contributions", "description": "The pull request review contributions.", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "orderBy", "description": "Ordering options for contributions returned from the connection.", "type": { "kind": "INPUT_OBJECT", "name": "ContributionOrder", "ofType": null }, "defaultValue": "{field:\"OCCURRED_AT\",direction:\"DESC\"}" } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "CreatedPullRequestReviewContributionConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "repository", "description": "The repository in which the pull request reviews were made.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "Repository", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "CommitContributionsByRepository", "description": "This aggregates commits made by a user within one repository.", "fields": [ { "name": "contributions", "description": "The commit contributions, each representing a day.", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "orderBy", "description": "Ordering options for commit contributions returned from the connection.", "type": { "kind": "INPUT_OBJECT", "name": "CommitContributionOrder", "ofType": null }, "defaultValue": "{field:\"OCCURRED_AT\",direction:\"DESC\"}" } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "CreatedCommitContributionConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "repository", "description": "The repository in which the commits were made.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "Repository", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "resourcePath", "description": "The HTTP path for the user's commits to the repository in this time range.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "url", "description": "The HTTP URL for the user's commits to the repository in this time range.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "CreatedCommitContributionConnection", "description": "The connection type for CreatedCommitContribution.", "fields": [ { "name": "edges", "description": "A list of edges.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "CreatedCommitContributionEdge", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "nodes", "description": "A list of nodes.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "CreatedCommitContribution", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pageInfo", "description": "Information to aid in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PageInfo", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "totalCount", "description": "Identifies the total count of commits across days and repositories in the connection.\n", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "CreatedCommitContributionEdge", "description": "An edge in a connection.", "fields": [ { "name": "cursor", "description": "A cursor for use in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "node", "description": "The item at the end of the edge.", "args": [], "type": { "kind": "OBJECT", "name": "CreatedCommitContribution", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "CreatedCommitContribution", "description": "Represents the contribution a user made by committing to a repository.", "fields": [ { "name": "commitCount", "description": "How many commits were made on this day to this repository by the user.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "isRestricted", "description": "Whether this contribution is associated with a record you do not have access to. For\nexample, your own 'first issue' contribution may have been made on a repository you can no\nlonger access.\n", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "occurredAt", "description": "When this contribution was made.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "repository", "description": "The repository the user made a commit in.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "Repository", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "resourcePath", "description": "The HTTP path for this contribution.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "url", "description": "The HTTP URL for this contribution.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "user", "description": "The user who made this contribution.\n", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "User", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Contribution", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "CommitContributionOrder", "description": "Ordering options for commit contribution connections.", "fields": null, "inputFields": [ { "name": "field", "description": "The field by which to order commit contributions.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "CommitContributionOrderField", "ofType": null } }, "defaultValue": null }, { "name": "direction", "description": "The ordering direction.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "OrderDirection", "ofType": null } }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "ENUM", "name": "CommitContributionOrderField", "description": "Properties by which commit contribution connections can be ordered.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "OCCURRED_AT", "description": "Order commit contributions by when they were made.", "isDeprecated": false, "deprecationReason": null }, { "name": "COMMIT_COUNT", "description": "Order commit contributions by how many commits they represent.", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null }, { "kind": "OBJECT", "name": "CreatedPullRequestContributionConnection", "description": "The connection type for CreatedPullRequestContribution.", "fields": [ { "name": "edges", "description": "A list of edges.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "CreatedPullRequestContributionEdge", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "nodes", "description": "A list of nodes.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "CreatedPullRequestContribution", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pageInfo", "description": "Information to aid in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PageInfo", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "totalCount", "description": "Identifies the total count of items in the connection.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "CreatedPullRequestContributionEdge", "description": "An edge in a connection.", "fields": [ { "name": "cursor", "description": "A cursor for use in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "node", "description": "The item at the end of the edge.", "args": [], "type": { "kind": "OBJECT", "name": "CreatedPullRequestContribution", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "PullRequestContributionsByRepository", "description": "This aggregates pull requests opened by a user within one repository.", "fields": [ { "name": "contributions", "description": "The pull request contributions.", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "orderBy", "description": "Ordering options for contributions returned from the connection.", "type": { "kind": "INPUT_OBJECT", "name": "ContributionOrder", "ofType": null }, "defaultValue": "{field:\"OCCURRED_AT\",direction:\"DESC\"}" } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "CreatedPullRequestContributionConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "repository", "description": "The repository in which the pull requests were opened.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "Repository", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "IssueContributionsByRepository", "description": "This aggregates issues opened by a user within one repository.", "fields": [ { "name": "contributions", "description": "The issue contributions.", "args": [ { "name": "after", "description": "Returns the elements in the list that come after the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "before", "description": "Returns the elements in the list that come before the specified cursor.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "first", "description": "Returns the first _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "last", "description": "Returns the last _n_ elements from the list.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "orderBy", "description": "Ordering options for contributions returned from the connection.", "type": { "kind": "INPUT_OBJECT", "name": "ContributionOrder", "ofType": null }, "defaultValue": "{field:\"OCCURRED_AT\",direction:\"DESC\"}" } ], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "CreatedIssueContributionConnection", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "repository", "description": "The repository in which the issues were opened.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "Repository", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "ENUM", "name": "RepositoryContributionType", "description": "The reason a repository is listed as 'contributed'.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "COMMIT", "description": "Created a commit", "isDeprecated": false, "deprecationReason": null }, { "name": "ISSUE", "description": "Created an issue", "isDeprecated": false, "deprecationReason": null }, { "name": "PULL_REQUEST", "description": "Created a pull request", "isDeprecated": false, "deprecationReason": null }, { "name": "REPOSITORY", "description": "Created the repository", "isDeprecated": false, "deprecationReason": null }, { "name": "PULL_REQUEST_REVIEW", "description": "Reviewed a pull request", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null }, { "kind": "OBJECT", "name": "PublicKeyConnection", "description": "The connection type for PublicKey.", "fields": [ { "name": "edges", "description": "A list of edges.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "PublicKeyEdge", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "nodes", "description": "A list of nodes.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "PublicKey", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pageInfo", "description": "Information to aid in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PageInfo", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "totalCount", "description": "Identifies the total count of items in the connection.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "PublicKeyEdge", "description": "An edge in a connection.", "fields": [ { "name": "cursor", "description": "A cursor for use in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "node", "description": "The item at the end of the edge.", "args": [], "type": { "kind": "OBJECT", "name": "PublicKey", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "FollowingConnection", "description": "The connection type for User.", "fields": [ { "name": "edges", "description": "A list of edges.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "UserEdge", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "nodes", "description": "A list of nodes.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "User", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pageInfo", "description": "Information to aid in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PageInfo", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "totalCount", "description": "Identifies the total count of items in the connection.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "FollowerConnection", "description": "The connection type for User.", "fields": [ { "name": "edges", "description": "A list of edges.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "UserEdge", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "nodes", "description": "A list of nodes.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "User", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pageInfo", "description": "Information to aid in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PageInfo", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "totalCount", "description": "Identifies the total count of items in the connection.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "StarredRepositoryConnection", "description": "The connection type for Repository.", "fields": [ { "name": "edges", "description": "A list of edges.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "StarredRepositoryEdge", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "nodes", "description": "A list of nodes.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "Repository", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pageInfo", "description": "Information to aid in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PageInfo", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "totalCount", "description": "Identifies the total count of items in the connection.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "StarredRepositoryEdge", "description": "Represents a starred repository.", "fields": [ { "name": "cursor", "description": "A cursor for use in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "node", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "Repository", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "starredAt", "description": "Identifies when the item was starred.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "AppEdge", "description": "An edge in a connection.", "fields": [ { "name": "cursor", "description": "A cursor for use in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "node", "description": "The item at the end of the edge.", "args": [], "type": { "kind": "OBJECT", "name": "App", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "RateLimit", "description": "Represents the client's rate limit.", "fields": [ { "name": "cost", "description": "The point cost for the current query counting against the rate limit.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "limit", "description": "The maximum number of points the client is permitted to consume in a 60 minute window.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "nodeCount", "description": "The maximum number of nodes this query may return", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "remaining", "description": "The number of points remaining in the current rate limit window.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "resetAt", "description": "The time at which the current rate limit window resets in UTC epoch seconds.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "SearchResultItemConnection", "description": "A list of results that matched against a search query.", "fields": [ { "name": "codeCount", "description": "The number of pieces of code that matched the search query.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "edges", "description": "A list of edges.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "SearchResultItemEdge", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "issueCount", "description": "The number of issues that matched the search query.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "nodes", "description": "A list of nodes.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "UNION", "name": "SearchResultItem", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pageInfo", "description": "Information to aid in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PageInfo", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "repositoryCount", "description": "The number of repositories that matched the search query.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "userCount", "description": "The number of users that matched the search query.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "wikiCount", "description": "The number of wiki pages that matched the search query.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "SearchResultItemEdge", "description": "An edge in a connection.", "fields": [ { "name": "cursor", "description": "A cursor for use in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "node", "description": "The item at the end of the edge.", "args": [], "type": { "kind": "UNION", "name": "SearchResultItem", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "textMatches", "description": "Text matches on the result found.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "TextMatch", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "UNION", "name": "SearchResultItem", "description": "The results of a search.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": [ { "kind": "OBJECT", "name": "Issue", "ofType": null }, { "kind": "OBJECT", "name": "PullRequest", "ofType": null }, { "kind": "OBJECT", "name": "Repository", "ofType": null }, { "kind": "OBJECT", "name": "User", "ofType": null }, { "kind": "OBJECT", "name": "Organization", "ofType": null }, { "kind": "OBJECT", "name": "MarketplaceListing", "ofType": null } ] }, { "kind": "OBJECT", "name": "TextMatch", "description": "A text match within a search result.", "fields": [ { "name": "fragment", "description": "The specific text fragment within the property matched on.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "highlights", "description": "Highlights within the matched fragment.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "TextMatchHighlight", "ofType": null } } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "property", "description": "The property matched on.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "TextMatchHighlight", "description": "Represents a single highlight in a search result match.", "fields": [ { "name": "beginIndice", "description": "The indice in the fragment where the matched text begins.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "endIndice", "description": "The indice in the fragment where the matched text ends.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "text", "description": "The text matched.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "ENUM", "name": "SearchType", "description": "Represents the individual results of a search.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "ISSUE", "description": "Returns results matching issues in repositories.", "isDeprecated": false, "deprecationReason": null }, { "name": "REPOSITORY", "description": "Returns results matching repositories.", "isDeprecated": false, "deprecationReason": null }, { "name": "USER", "description": "Returns results matching users and organizations on GitHub.", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null }, { "kind": "UNION", "name": "CollectionItemContent", "description": "Types that can be inside Collection Items.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": null, "possibleTypes": [ { "kind": "OBJECT", "name": "Repository", "ofType": null }, { "kind": "OBJECT", "name": "Organization", "ofType": null }, { "kind": "OBJECT", "name": "User", "ofType": null } ] }, { "kind": "OBJECT", "name": "GitHubMetadata", "description": "Represents information about the GitHub instance.", "fields": [ { "name": "gitHubServicesSha", "description": "Returns a String that's a SHA of `github-services`", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "GitObjectID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "gitIpAddresses", "description": "IP addresses that users connect to for git operations", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "hookIpAddresses", "description": "IP addresses that service hooks are sent from", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "importerIpAddresses", "description": "IP addresses that the importer connects from", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "isPasswordAuthenticationVerifiable", "description": "Whether or not users are verified", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pagesIpAddresses", "description": "IP addresses for GitHub Pages' A records", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "SecurityAdvisoryConnection", "description": "The connection type for SecurityAdvisory.", "fields": [ { "name": "edges", "description": "A list of edges.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "SecurityAdvisoryEdge", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "nodes", "description": "A list of nodes.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "OBJECT", "name": "SecurityAdvisory", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "pageInfo", "description": "Information to aid in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "PageInfo", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "totalCount", "description": "Identifies the total count of items in the connection.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "SecurityAdvisoryEdge", "description": "An edge in a connection.", "fields": [ { "name": "cursor", "description": "A cursor for use in pagination.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "node", "description": "The item at the end of the edge.", "args": [], "type": { "kind": "OBJECT", "name": "SecurityAdvisory", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "SecurityAdvisoryOrder", "description": "Ordering options for security advisory connections", "fields": null, "inputFields": [ { "name": "field", "description": "The field to order security advisories by.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "SecurityAdvisoryOrderField", "ofType": null } }, "defaultValue": null }, { "name": "direction", "description": "The ordering direction.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "OrderDirection", "ofType": null } }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "ENUM", "name": "SecurityAdvisoryOrderField", "description": "Properties by which security advisory connections can be ordered.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "PUBLISHED_AT", "description": "Order advisories by publication time", "isDeprecated": false, "deprecationReason": null }, { "name": "UPDATED_AT", "description": "Order advisories by update time", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "SecurityAdvisoryIdentifierFilter", "description": "An advisory identifier to filter results on.", "fields": null, "inputFields": [ { "name": "type", "description": "The identifier type.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "SecurityAdvisoryIdentifierType", "ofType": null } }, "defaultValue": null }, { "name": "value", "description": "The identifier string. Supports exact or partial matching.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "ENUM", "name": "SecurityAdvisoryIdentifierType", "description": "Identifier formats available for advisories.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "CVE", "description": "Common Vulnerabilities and Exposures Identifier.", "isDeprecated": false, "deprecationReason": null }, { "name": "GHSA", "description": "GitHub Security Advisory ID.", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null }, { "kind": "OBJECT", "name": "Mutation", "description": "The root query for implementing GraphQL mutations.", "fields": [ { "name": "acceptTopicSuggestion", "description": "Applies a suggested topic to the repository.", "args": [ { "name": "input", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INPUT_OBJECT", "name": "AcceptTopicSuggestionInput", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "AcceptTopicSuggestionPayload", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "addAssigneesToAssignable", "description": "Adds assignees to an assignable object.", "args": [ { "name": "input", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INPUT_OBJECT", "name": "AddAssigneesToAssignableInput", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "AddAssigneesToAssignablePayload", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "addComment", "description": "Adds a comment to an Issue or Pull Request.", "args": [ { "name": "input", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INPUT_OBJECT", "name": "AddCommentInput", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "AddCommentPayload", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "addLabelsToLabelable", "description": "Adds labels to a labelable object.", "args": [ { "name": "input", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INPUT_OBJECT", "name": "AddLabelsToLabelableInput", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "AddLabelsToLabelablePayload", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "addProjectCard", "description": "Adds a card to a ProjectColumn. Either `contentId` or `note` must be provided but **not** both.", "args": [ { "name": "input", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INPUT_OBJECT", "name": "AddProjectCardInput", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "AddProjectCardPayload", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "addProjectColumn", "description": "Adds a column to a Project.", "args": [ { "name": "input", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INPUT_OBJECT", "name": "AddProjectColumnInput", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "AddProjectColumnPayload", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "addPullRequestReview", "description": "Adds a review to a Pull Request.", "args": [ { "name": "input", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INPUT_OBJECT", "name": "AddPullRequestReviewInput", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "AddPullRequestReviewPayload", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "addPullRequestReviewComment", "description": "Adds a comment to a review.", "args": [ { "name": "input", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INPUT_OBJECT", "name": "AddPullRequestReviewCommentInput", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "AddPullRequestReviewCommentPayload", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "addReaction", "description": "Adds a reaction to a subject.", "args": [ { "name": "input", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INPUT_OBJECT", "name": "AddReactionInput", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "AddReactionPayload", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "addStar", "description": "Adds a star to a Starrable.", "args": [ { "name": "input", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INPUT_OBJECT", "name": "AddStarInput", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "AddStarPayload", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "changeUserStatus", "description": "Update your status on GitHub.", "args": [ { "name": "input", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INPUT_OBJECT", "name": "ChangeUserStatusInput", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "ChangeUserStatusPayload", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "clearLabelsFromLabelable", "description": "Clears all labels from a labelable object.", "args": [ { "name": "input", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INPUT_OBJECT", "name": "ClearLabelsFromLabelableInput", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "ClearLabelsFromLabelablePayload", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "cloneProject", "description": "Creates a new project by cloning configuration from an existing project.", "args": [ { "name": "input", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INPUT_OBJECT", "name": "CloneProjectInput", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "CloneProjectPayload", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "closeIssue", "description": "Close an issue.", "args": [ { "name": "input", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INPUT_OBJECT", "name": "CloseIssueInput", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "CloseIssuePayload", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "closePullRequest", "description": "Close a pull request.", "args": [ { "name": "input", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INPUT_OBJECT", "name": "ClosePullRequestInput", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "ClosePullRequestPayload", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "convertProjectCardNoteToIssue", "description": "Convert a project note card to one associated with a newly created issue.", "args": [ { "name": "input", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INPUT_OBJECT", "name": "ConvertProjectCardNoteToIssueInput", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "ConvertProjectCardNoteToIssuePayload", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "createBranchProtectionRule", "description": "Create a new branch protection rule", "args": [ { "name": "input", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INPUT_OBJECT", "name": "CreateBranchProtectionRuleInput", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "CreateBranchProtectionRulePayload", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "createIssue", "description": "Creates a new issue.", "args": [ { "name": "input", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INPUT_OBJECT", "name": "CreateIssueInput", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "CreateIssuePayload", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "createProject", "description": "Creates a new project.", "args": [ { "name": "input", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INPUT_OBJECT", "name": "CreateProjectInput", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "CreateProjectPayload", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "createPullRequest", "description": "Create a new pull request", "args": [ { "name": "input", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INPUT_OBJECT", "name": "CreatePullRequestInput", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "CreatePullRequestPayload", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "declineTopicSuggestion", "description": "Rejects a suggested topic for the repository.", "args": [ { "name": "input", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INPUT_OBJECT", "name": "DeclineTopicSuggestionInput", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "DeclineTopicSuggestionPayload", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "deleteBranchProtectionRule", "description": "Delete a branch protection rule", "args": [ { "name": "input", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INPUT_OBJECT", "name": "DeleteBranchProtectionRuleInput", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "DeleteBranchProtectionRulePayload", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "deleteIssue", "description": "Deletes an Issue object.", "args": [ { "name": "input", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INPUT_OBJECT", "name": "DeleteIssueInput", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "DeleteIssuePayload", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "deleteIssueComment", "description": "Deletes an IssueComment object.", "args": [ { "name": "input", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INPUT_OBJECT", "name": "DeleteIssueCommentInput", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "DeleteIssueCommentPayload", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "deleteProject", "description": "Deletes a project.", "args": [ { "name": "input", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INPUT_OBJECT", "name": "DeleteProjectInput", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "DeleteProjectPayload", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "deleteProjectCard", "description": "Deletes a project card.", "args": [ { "name": "input", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INPUT_OBJECT", "name": "DeleteProjectCardInput", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "DeleteProjectCardPayload", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "deleteProjectColumn", "description": "Deletes a project column.", "args": [ { "name": "input", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INPUT_OBJECT", "name": "DeleteProjectColumnInput", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "DeleteProjectColumnPayload", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "deletePullRequestReview", "description": "Deletes a pull request review.", "args": [ { "name": "input", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INPUT_OBJECT", "name": "DeletePullRequestReviewInput", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "DeletePullRequestReviewPayload", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "deletePullRequestReviewComment", "description": "Deletes a pull request review comment.", "args": [ { "name": "input", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INPUT_OBJECT", "name": "DeletePullRequestReviewCommentInput", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "DeletePullRequestReviewCommentPayload", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "dismissPullRequestReview", "description": "Dismisses an approved or rejected pull request review.", "args": [ { "name": "input", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INPUT_OBJECT", "name": "DismissPullRequestReviewInput", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "DismissPullRequestReviewPayload", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "lockLockable", "description": "Lock a lockable object", "args": [ { "name": "input", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INPUT_OBJECT", "name": "LockLockableInput", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "LockLockablePayload", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "mergePullRequest", "description": "Merge a pull request.", "args": [ { "name": "input", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INPUT_OBJECT", "name": "MergePullRequestInput", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "MergePullRequestPayload", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "moveProjectCard", "description": "Moves a project card to another place.", "args": [ { "name": "input", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INPUT_OBJECT", "name": "MoveProjectCardInput", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "MoveProjectCardPayload", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "moveProjectColumn", "description": "Moves a project column to another place.", "args": [ { "name": "input", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INPUT_OBJECT", "name": "MoveProjectColumnInput", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "MoveProjectColumnPayload", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "removeAssigneesFromAssignable", "description": "Removes assignees from an assignable object.", "args": [ { "name": "input", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INPUT_OBJECT", "name": "RemoveAssigneesFromAssignableInput", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "RemoveAssigneesFromAssignablePayload", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "removeLabelsFromLabelable", "description": "Removes labels from a Labelable object.", "args": [ { "name": "input", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INPUT_OBJECT", "name": "RemoveLabelsFromLabelableInput", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "RemoveLabelsFromLabelablePayload", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "removeOutsideCollaborator", "description": "Removes outside collaborator from all repositories in an organization.", "args": [ { "name": "input", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INPUT_OBJECT", "name": "RemoveOutsideCollaboratorInput", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "RemoveOutsideCollaboratorPayload", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "removeReaction", "description": "Removes a reaction from a subject.", "args": [ { "name": "input", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INPUT_OBJECT", "name": "RemoveReactionInput", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "RemoveReactionPayload", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "removeStar", "description": "Removes a star from a Starrable.", "args": [ { "name": "input", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INPUT_OBJECT", "name": "RemoveStarInput", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "RemoveStarPayload", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "reopenIssue", "description": "Reopen a issue.", "args": [ { "name": "input", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INPUT_OBJECT", "name": "ReopenIssueInput", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "ReopenIssuePayload", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "reopenPullRequest", "description": "Reopen a pull request.", "args": [ { "name": "input", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INPUT_OBJECT", "name": "ReopenPullRequestInput", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "ReopenPullRequestPayload", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "requestReviews", "description": "Set review requests on a pull request.", "args": [ { "name": "input", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INPUT_OBJECT", "name": "RequestReviewsInput", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "RequestReviewsPayload", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "resolveReviewThread", "description": "Marks a review thread as resolved.", "args": [ { "name": "input", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INPUT_OBJECT", "name": "ResolveReviewThreadInput", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "ResolveReviewThreadPayload", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "submitPullRequestReview", "description": "Submits a pending pull request review.", "args": [ { "name": "input", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INPUT_OBJECT", "name": "SubmitPullRequestReviewInput", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "SubmitPullRequestReviewPayload", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "unlockLockable", "description": "Unlock a lockable object", "args": [ { "name": "input", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INPUT_OBJECT", "name": "UnlockLockableInput", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "UnlockLockablePayload", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "unmarkIssueAsDuplicate", "description": "Unmark an issue as a duplicate of another issue.", "args": [ { "name": "input", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INPUT_OBJECT", "name": "UnmarkIssueAsDuplicateInput", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "UnmarkIssueAsDuplicatePayload", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "unresolveReviewThread", "description": "Marks a review thread as unresolved.", "args": [ { "name": "input", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INPUT_OBJECT", "name": "UnresolveReviewThreadInput", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "UnresolveReviewThreadPayload", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "updateBranchProtectionRule", "description": "Create a new branch protection rule", "args": [ { "name": "input", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INPUT_OBJECT", "name": "UpdateBranchProtectionRuleInput", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "UpdateBranchProtectionRulePayload", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "updateIssue", "description": "Updates an Issue.", "args": [ { "name": "input", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INPUT_OBJECT", "name": "UpdateIssueInput", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "UpdateIssuePayload", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "updateIssueComment", "description": "Updates an IssueComment object.", "args": [ { "name": "input", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INPUT_OBJECT", "name": "UpdateIssueCommentInput", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "UpdateIssueCommentPayload", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "updateProject", "description": "Updates an existing project.", "args": [ { "name": "input", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INPUT_OBJECT", "name": "UpdateProjectInput", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "UpdateProjectPayload", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "updateProjectCard", "description": "Updates an existing project card.", "args": [ { "name": "input", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INPUT_OBJECT", "name": "UpdateProjectCardInput", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "UpdateProjectCardPayload", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "updateProjectColumn", "description": "Updates an existing project column.", "args": [ { "name": "input", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INPUT_OBJECT", "name": "UpdateProjectColumnInput", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "UpdateProjectColumnPayload", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "updatePullRequest", "description": "Update a pull request", "args": [ { "name": "input", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INPUT_OBJECT", "name": "UpdatePullRequestInput", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "UpdatePullRequestPayload", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "updatePullRequestReview", "description": "Updates the body of a pull request review.", "args": [ { "name": "input", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INPUT_OBJECT", "name": "UpdatePullRequestReviewInput", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "UpdatePullRequestReviewPayload", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "updatePullRequestReviewComment", "description": "Updates a pull request review comment.", "args": [ { "name": "input", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INPUT_OBJECT", "name": "UpdatePullRequestReviewCommentInput", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "UpdatePullRequestReviewCommentPayload", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "updateSubscription", "description": "Updates the state for subscribable subjects.", "args": [ { "name": "input", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INPUT_OBJECT", "name": "UpdateSubscriptionInput", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "UpdateSubscriptionPayload", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "updateTopics", "description": "Replaces the repository's topics with the given topics.", "args": [ { "name": "input", "description": null, "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INPUT_OBJECT", "name": "UpdateTopicsInput", "ofType": null } }, "defaultValue": null } ], "type": { "kind": "OBJECT", "name": "UpdateTopicsPayload", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "AddReactionPayload", "description": "Autogenerated return type of AddReaction", "fields": [ { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "reaction", "description": "The reaction object.", "args": [], "type": { "kind": "OBJECT", "name": "Reaction", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "subject", "description": "The reactable subject.", "args": [], "type": { "kind": "INTERFACE", "name": "Reactable", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "AddReactionInput", "description": "Autogenerated input type of AddReaction", "fields": null, "inputFields": [ { "name": "subjectId", "description": "The Node ID of the subject to modify.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null }, { "name": "content", "description": "The name of the emoji to react with.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "ReactionContent", "ofType": null } }, "defaultValue": null }, { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "RemoveReactionPayload", "description": "Autogenerated return type of RemoveReaction", "fields": [ { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "reaction", "description": "The reaction object.", "args": [], "type": { "kind": "OBJECT", "name": "Reaction", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "subject", "description": "The reactable subject.", "args": [], "type": { "kind": "INTERFACE", "name": "Reactable", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "RemoveReactionInput", "description": "Autogenerated input type of RemoveReaction", "fields": null, "inputFields": [ { "name": "subjectId", "description": "The Node ID of the subject to modify.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null }, { "name": "content", "description": "The name of the emoji reaction to remove.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "ReactionContent", "ofType": null } }, "defaultValue": null }, { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "UpdateSubscriptionPayload", "description": "Autogenerated return type of UpdateSubscription", "fields": [ { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "subscribable", "description": "The input subscribable entity.", "args": [], "type": { "kind": "INTERFACE", "name": "Subscribable", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "UpdateSubscriptionInput", "description": "Autogenerated input type of UpdateSubscription", "fields": null, "inputFields": [ { "name": "subscribableId", "description": "The Node ID of the subscribable object to modify.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null }, { "name": "state", "description": "The new state of the subscription.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "SubscriptionState", "ofType": null } }, "defaultValue": null }, { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "AddCommentPayload", "description": "Autogenerated return type of AddComment", "fields": [ { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "commentEdge", "description": "The edge from the subject's comment connection.", "args": [], "type": { "kind": "OBJECT", "name": "IssueCommentEdge", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "subject", "description": "The subject", "args": [], "type": { "kind": "INTERFACE", "name": "Node", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "timelineEdge", "description": "The edge from the subject's timeline connection.", "args": [], "type": { "kind": "OBJECT", "name": "IssueTimelineItemEdge", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "AddCommentInput", "description": "Autogenerated input type of AddComment", "fields": null, "inputFields": [ { "name": "subjectId", "description": "The Node ID of the subject to modify.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null }, { "name": "body", "description": "The contents of the comment.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "defaultValue": null }, { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "MinimizeCommentInput", "description": "Autogenerated input type of MinimizeComment", "fields": null, "inputFields": [ { "name": "subjectId", "description": "The Node ID of the subject to modify.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null }, { "name": "classifier", "description": "The classification of comment", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "ReportedContentClassifiers", "ofType": null } }, "defaultValue": null }, { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "ENUM", "name": "ReportedContentClassifiers", "description": "The reasons a piece of content can be reported or minimized.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "SPAM", "description": "A spammy piece of content", "isDeprecated": false, "deprecationReason": null }, { "name": "ABUSE", "description": "An abusive or harassing piece of content", "isDeprecated": false, "deprecationReason": null }, { "name": "OFF_TOPIC", "description": "An irrelevant piece of content", "isDeprecated": false, "deprecationReason": null }, { "name": "OUTDATED", "description": "An outdated piece of content", "isDeprecated": false, "deprecationReason": null }, { "name": "RESOLVED", "description": "The content has been resolved", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "UnminimizeCommentInput", "description": "Autogenerated input type of UnminimizeComment", "fields": null, "inputFields": [ { "name": "subjectId", "description": "The Node ID of the subject to modify.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null }, { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "UpdateIssueCommentPayload", "description": "Autogenerated return type of UpdateIssueComment", "fields": [ { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "issueComment", "description": "The updated comment.", "args": [], "type": { "kind": "OBJECT", "name": "IssueComment", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "UpdateIssueCommentInput", "description": "Autogenerated input type of UpdateIssueComment", "fields": null, "inputFields": [ { "name": "id", "description": "The ID of the IssueComment to modify.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null }, { "name": "body", "description": "The updated text of the comment.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "defaultValue": null }, { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "CreateProjectPayload", "description": "Autogenerated return type of CreateProject", "fields": [ { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "project", "description": "The new project.", "args": [], "type": { "kind": "OBJECT", "name": "Project", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "CreateProjectInput", "description": "Autogenerated input type of CreateProject", "fields": null, "inputFields": [ { "name": "ownerId", "description": "The owner ID to create the project under.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null }, { "name": "name", "description": "The name of project.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "defaultValue": null }, { "name": "body", "description": "The description of project.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "UpdateProjectPayload", "description": "Autogenerated return type of UpdateProject", "fields": [ { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "project", "description": "The updated project.", "args": [], "type": { "kind": "OBJECT", "name": "Project", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "UpdateProjectInput", "description": "Autogenerated input type of UpdateProject", "fields": null, "inputFields": [ { "name": "projectId", "description": "The Project ID to update.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null }, { "name": "name", "description": "The name of project.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "body", "description": "The description of project.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "state", "description": "Whether the project is open or closed.", "type": { "kind": "ENUM", "name": "ProjectState", "ofType": null }, "defaultValue": null }, { "name": "public", "description": "Whether the project is public or not.", "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": null }, { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "DeleteProjectPayload", "description": "Autogenerated return type of DeleteProject", "fields": [ { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "owner", "description": "The repository or organization the project was removed from.", "args": [], "type": { "kind": "INTERFACE", "name": "ProjectOwner", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "DeleteProjectInput", "description": "Autogenerated input type of DeleteProject", "fields": null, "inputFields": [ { "name": "projectId", "description": "The Project ID to update.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null }, { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "CloneProjectPayload", "description": "Autogenerated return type of CloneProject", "fields": [ { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "jobStatusId", "description": "The id of the JobStatus for populating cloned fields.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "project", "description": "The new cloned project.", "args": [], "type": { "kind": "OBJECT", "name": "Project", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "CloneProjectInput", "description": "Autogenerated input type of CloneProject", "fields": null, "inputFields": [ { "name": "targetOwnerId", "description": "The owner ID to create the project under.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null }, { "name": "sourceId", "description": "The source project to clone.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null }, { "name": "includeWorkflows", "description": "Whether or not to clone the source project's workflows.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "defaultValue": null }, { "name": "name", "description": "The name of the project.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "defaultValue": null }, { "name": "body", "description": "The description of the project.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "public", "description": "The visibility of the project, defaults to false (private).", "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": null }, { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "ImportProjectInput", "description": "Autogenerated input type of ImportProject", "fields": null, "inputFields": [ { "name": "ownerName", "description": "The name of the Organization or User to create the Project under.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "defaultValue": null }, { "name": "name", "description": "The name of Project.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "defaultValue": null }, { "name": "body", "description": "The description of Project.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "public", "description": "Whether the Project is public or not.", "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": "false" }, { "name": "columnImports", "description": "A list of columns containing issues and pull requests.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INPUT_OBJECT", "name": "ProjectColumnImport", "ofType": null } } } }, "defaultValue": null }, { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "ProjectColumnImport", "description": "A project column and a list of its issues and PRs.", "fields": null, "inputFields": [ { "name": "columnName", "description": "The name of the column.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "defaultValue": null }, { "name": "position", "description": "The position of the column, starting from 0.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "defaultValue": null }, { "name": "issues", "description": "A list of issues and pull requests in the column.", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INPUT_OBJECT", "name": "ProjectCardImport", "ofType": null } } }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "ProjectCardImport", "description": "An issue or PR and its owning repository to be used in a project card.", "fields": null, "inputFields": [ { "name": "repository", "description": "Repository name with owner (owner/repository).", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "defaultValue": null }, { "name": "number", "description": "The issue or pull request number.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "AddProjectColumnPayload", "description": "Autogenerated return type of AddProjectColumn", "fields": [ { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "columnEdge", "description": "The edge from the project's column connection.", "args": [], "type": { "kind": "OBJECT", "name": "ProjectColumnEdge", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "project", "description": "The project", "args": [], "type": { "kind": "OBJECT", "name": "Project", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "AddProjectColumnInput", "description": "Autogenerated input type of AddProjectColumn", "fields": null, "inputFields": [ { "name": "projectId", "description": "The Node ID of the project.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null }, { "name": "name", "description": "The name of the column.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "defaultValue": null }, { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "MoveProjectColumnPayload", "description": "Autogenerated return type of MoveProjectColumn", "fields": [ { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "columnEdge", "description": "The new edge of the moved column.", "args": [], "type": { "kind": "OBJECT", "name": "ProjectColumnEdge", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "MoveProjectColumnInput", "description": "Autogenerated input type of MoveProjectColumn", "fields": null, "inputFields": [ { "name": "columnId", "description": "The id of the column to move.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null }, { "name": "afterColumnId", "description": "Place the new column after the column with this id. Pass null to place it at the front.", "type": { "kind": "SCALAR", "name": "ID", "ofType": null }, "defaultValue": null }, { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "UpdateProjectColumnPayload", "description": "Autogenerated return type of UpdateProjectColumn", "fields": [ { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "projectColumn", "description": "The updated project column.", "args": [], "type": { "kind": "OBJECT", "name": "ProjectColumn", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "UpdateProjectColumnInput", "description": "Autogenerated input type of UpdateProjectColumn", "fields": null, "inputFields": [ { "name": "projectColumnId", "description": "The ProjectColumn ID to update.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null }, { "name": "name", "description": "The name of project column.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "defaultValue": null }, { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "DeleteProjectColumnPayload", "description": "Autogenerated return type of DeleteProjectColumn", "fields": [ { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "deletedColumnId", "description": "The deleted column ID.", "args": [], "type": { "kind": "SCALAR", "name": "ID", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "project", "description": "The project the deleted column was in.", "args": [], "type": { "kind": "OBJECT", "name": "Project", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "DeleteProjectColumnInput", "description": "Autogenerated input type of DeleteProjectColumn", "fields": null, "inputFields": [ { "name": "columnId", "description": "The id of the column to delete.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null }, { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "AddProjectCardPayload", "description": "Autogenerated return type of AddProjectCard", "fields": [ { "name": "cardEdge", "description": "The edge from the ProjectColumn's card connection.", "args": [], "type": { "kind": "OBJECT", "name": "ProjectCardEdge", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "projectColumn", "description": "The ProjectColumn", "args": [], "type": { "kind": "OBJECT", "name": "ProjectColumn", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "AddProjectCardInput", "description": "Autogenerated input type of AddProjectCard", "fields": null, "inputFields": [ { "name": "projectColumnId", "description": "The Node ID of the ProjectColumn.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null }, { "name": "contentId", "description": "The content of the card. Must be a member of the ProjectCardItem union", "type": { "kind": "SCALAR", "name": "ID", "ofType": null }, "defaultValue": null }, { "name": "note", "description": "The note on the card.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "UpdateProjectCardPayload", "description": "Autogenerated return type of UpdateProjectCard", "fields": [ { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "projectCard", "description": "The updated ProjectCard.", "args": [], "type": { "kind": "OBJECT", "name": "ProjectCard", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "UpdateProjectCardInput", "description": "Autogenerated input type of UpdateProjectCard", "fields": null, "inputFields": [ { "name": "projectCardId", "description": "The ProjectCard ID to update.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null }, { "name": "isArchived", "description": "Whether or not the ProjectCard should be archived", "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": null }, { "name": "note", "description": "The note of ProjectCard.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "MoveProjectCardPayload", "description": "Autogenerated return type of MoveProjectCard", "fields": [ { "name": "cardEdge", "description": "The new edge of the moved card.", "args": [], "type": { "kind": "OBJECT", "name": "ProjectCardEdge", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "MoveProjectCardInput", "description": "Autogenerated input type of MoveProjectCard", "fields": null, "inputFields": [ { "name": "cardId", "description": "The id of the card to move.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null }, { "name": "columnId", "description": "The id of the column to move it into.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null }, { "name": "afterCardId", "description": "Place the new card after the card with this id. Pass null to place it at the top.", "type": { "kind": "SCALAR", "name": "ID", "ofType": null }, "defaultValue": null }, { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "DeleteProjectCardPayload", "description": "Autogenerated return type of DeleteProjectCard", "fields": [ { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "column", "description": "The column the deleted card was in.", "args": [], "type": { "kind": "OBJECT", "name": "ProjectColumn", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "deletedCardId", "description": "The deleted card ID.", "args": [], "type": { "kind": "SCALAR", "name": "ID", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "DeleteProjectCardInput", "description": "Autogenerated input type of DeleteProjectCard", "fields": null, "inputFields": [ { "name": "cardId", "description": "The id of the card to delete.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null }, { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "ConvertProjectCardNoteToIssuePayload", "description": "Autogenerated return type of ConvertProjectCardNoteToIssue", "fields": [ { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "projectCard", "description": "The updated ProjectCard.", "args": [], "type": { "kind": "OBJECT", "name": "ProjectCard", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "ConvertProjectCardNoteToIssueInput", "description": "Autogenerated input type of ConvertProjectCardNoteToIssue", "fields": null, "inputFields": [ { "name": "projectCardId", "description": "The ProjectCard ID to convert.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null }, { "name": "repositoryId", "description": "The ID of the repository to create the issue in.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null }, { "name": "title", "description": "The title of the newly created issue. Defaults to the card's note text.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "body", "description": "The body of the newly created issue.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "UnmarkIssueAsDuplicatePayload", "description": "Autogenerated return type of UnmarkIssueAsDuplicate", "fields": [ { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "duplicate", "description": "The issue or pull request that was marked as a duplicate.", "args": [], "type": { "kind": "UNION", "name": "IssueOrPullRequest", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "UnmarkIssueAsDuplicateInput", "description": "Autogenerated input type of UnmarkIssueAsDuplicate", "fields": null, "inputFields": [ { "name": "duplicateId", "description": "ID of the issue or pull request currently marked as a duplicate.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null }, { "name": "canonicalId", "description": "ID of the issue or pull request currently considered canonical/authoritative/original.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null }, { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "LockLockablePayload", "description": "Autogenerated return type of LockLockable", "fields": [ { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "lockedRecord", "description": "The item that was locked.", "args": [], "type": { "kind": "INTERFACE", "name": "Lockable", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "LockLockableInput", "description": "Autogenerated input type of LockLockable", "fields": null, "inputFields": [ { "name": "lockableId", "description": "ID of the issue or pull request to be locked.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null }, { "name": "lockReason", "description": "A reason for why the issue or pull request will be locked.", "type": { "kind": "ENUM", "name": "LockReason", "ofType": null }, "defaultValue": null }, { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "UnlockLockablePayload", "description": "Autogenerated return type of UnlockLockable", "fields": [ { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "unlockedRecord", "description": "The item that was unlocked.", "args": [], "type": { "kind": "INTERFACE", "name": "Lockable", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "UnlockLockableInput", "description": "Autogenerated input type of UnlockLockable", "fields": null, "inputFields": [ { "name": "lockableId", "description": "ID of the issue or pull request to be unlocked.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null }, { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "AddAssigneesToAssignablePayload", "description": "Autogenerated return type of AddAssigneesToAssignable", "fields": [ { "name": "assignable", "description": "The item that was assigned.", "args": [], "type": { "kind": "INTERFACE", "name": "Assignable", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "AddAssigneesToAssignableInput", "description": "Autogenerated input type of AddAssigneesToAssignable", "fields": null, "inputFields": [ { "name": "assignableId", "description": "The id of the assignable object to add assignees to.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null }, { "name": "assigneeIds", "description": "The id of users to add as assignees.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } } } }, "defaultValue": null }, { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "RemoveAssigneesFromAssignablePayload", "description": "Autogenerated return type of RemoveAssigneesFromAssignable", "fields": [ { "name": "assignable", "description": "The item that was unassigned.", "args": [], "type": { "kind": "INTERFACE", "name": "Assignable", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "RemoveAssigneesFromAssignableInput", "description": "Autogenerated input type of RemoveAssigneesFromAssignable", "fields": null, "inputFields": [ { "name": "assignableId", "description": "The id of the assignable object to remove assignees from.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null }, { "name": "assigneeIds", "description": "The id of users to remove as assignees.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } } } }, "defaultValue": null }, { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "AddLabelsToLabelablePayload", "description": "Autogenerated return type of AddLabelsToLabelable", "fields": [ { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "labelable", "description": "The item that was labeled.", "args": [], "type": { "kind": "INTERFACE", "name": "Labelable", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "AddLabelsToLabelableInput", "description": "Autogenerated input type of AddLabelsToLabelable", "fields": null, "inputFields": [ { "name": "labelableId", "description": "The id of the labelable object to add labels to.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null }, { "name": "labelIds", "description": "The ids of the labels to add.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } } } }, "defaultValue": null }, { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "CreateIssuePayload", "description": "Autogenerated return type of CreateIssue", "fields": [ { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "issue", "description": "The new issue.", "args": [], "type": { "kind": "OBJECT", "name": "Issue", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "CreateIssueInput", "description": "Autogenerated input type of CreateIssue", "fields": null, "inputFields": [ { "name": "repositoryId", "description": "The Node ID of the repository.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null }, { "name": "title", "description": "The title for the issue.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "defaultValue": null }, { "name": "body", "description": "The body for the issue description.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "assigneeIds", "description": "The Node ID for the user assignee for this issue.", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } } }, "defaultValue": null }, { "name": "milestoneId", "description": "The Node ID of the milestone for this issue.", "type": { "kind": "SCALAR", "name": "ID", "ofType": null }, "defaultValue": null }, { "name": "labelIds", "description": "An array of Node IDs of labels for this issue.", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } } }, "defaultValue": null }, { "name": "projectIds", "description": "An array of Node IDs for projects associated with this issue.", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } } }, "defaultValue": null }, { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "ClearLabelsFromLabelablePayload", "description": "Autogenerated return type of ClearLabelsFromLabelable", "fields": [ { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "labelable", "description": "The item that was unlabeled.", "args": [], "type": { "kind": "INTERFACE", "name": "Labelable", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "ClearLabelsFromLabelableInput", "description": "Autogenerated input type of ClearLabelsFromLabelable", "fields": null, "inputFields": [ { "name": "labelableId", "description": "The id of the labelable object to clear the labels from.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null }, { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "RemoveLabelsFromLabelablePayload", "description": "Autogenerated return type of RemoveLabelsFromLabelable", "fields": [ { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "labelable", "description": "The Labelable the labels were removed from.", "args": [], "type": { "kind": "INTERFACE", "name": "Labelable", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "RemoveLabelsFromLabelableInput", "description": "Autogenerated input type of RemoveLabelsFromLabelable", "fields": null, "inputFields": [ { "name": "labelableId", "description": "The id of the Labelable to remove labels from.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null }, { "name": "labelIds", "description": "The ids of labels to remove.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } } } }, "defaultValue": null }, { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "CloseIssuePayload", "description": "Autogenerated return type of CloseIssue", "fields": [ { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "issue", "description": "The issue that was closed.", "args": [], "type": { "kind": "OBJECT", "name": "Issue", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "CloseIssueInput", "description": "Autogenerated input type of CloseIssue", "fields": null, "inputFields": [ { "name": "issueId", "description": "ID of the issue to be closed.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null }, { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "ReopenIssuePayload", "description": "Autogenerated return type of ReopenIssue", "fields": [ { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "issue", "description": "The issue that was opened.", "args": [], "type": { "kind": "OBJECT", "name": "Issue", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "ReopenIssueInput", "description": "Autogenerated input type of ReopenIssue", "fields": null, "inputFields": [ { "name": "issueId", "description": "ID of the issue to be opened.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null }, { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "DeleteIssueCommentPayload", "description": "Autogenerated return type of DeleteIssueComment", "fields": [ { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "DeleteIssueCommentInput", "description": "Autogenerated input type of DeleteIssueComment", "fields": null, "inputFields": [ { "name": "id", "description": "The ID of the comment to delete.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null }, { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "UpdateIssuePayload", "description": "Autogenerated return type of UpdateIssue", "fields": [ { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "issue", "description": "The issue.", "args": [], "type": { "kind": "OBJECT", "name": "Issue", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "UpdateIssueInput", "description": "Autogenerated input type of UpdateIssue", "fields": null, "inputFields": [ { "name": "id", "description": "The ID of the Issue to modify.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null }, { "name": "title", "description": "The title for the issue.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "body", "description": "The body for the issue description.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "assigneeIds", "description": "An array of Node IDs of users for this issue.", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } } }, "defaultValue": null }, { "name": "milestoneId", "description": "The Node ID of the milestone for this issue.", "type": { "kind": "SCALAR", "name": "ID", "ofType": null }, "defaultValue": null }, { "name": "labelIds", "description": "An array of Node IDs of labels for this issue.", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } } }, "defaultValue": null }, { "name": "state", "description": "The desired issue state.", "type": { "kind": "ENUM", "name": "IssueState", "ofType": null }, "defaultValue": null }, { "name": "projectIds", "description": "An array of Node IDs for projects associated with this issue.", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } } }, "defaultValue": null }, { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "DeleteIssuePayload", "description": "Autogenerated return type of DeleteIssue", "fields": [ { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "repository", "description": "The repository the issue belonged to", "args": [], "type": { "kind": "OBJECT", "name": "Repository", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "DeleteIssueInput", "description": "Autogenerated input type of DeleteIssue", "fields": null, "inputFields": [ { "name": "issueId", "description": "The ID of the issue to delete.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null }, { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "PinIssueInput", "description": "Autogenerated input type of PinIssue", "fields": null, "inputFields": [ { "name": "issueId", "description": "The ID of the issue to be pinned", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null }, { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "UnpinIssueInput", "description": "Autogenerated input type of UnpinIssue", "fields": null, "inputFields": [ { "name": "issueId", "description": "The ID of the issue to be unpinned", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null }, { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "CreatePullRequestPayload", "description": "Autogenerated return type of CreatePullRequest", "fields": [ { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "pullRequest", "description": "The new pull request.", "args": [], "type": { "kind": "OBJECT", "name": "PullRequest", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "CreatePullRequestInput", "description": "Autogenerated input type of CreatePullRequest", "fields": null, "inputFields": [ { "name": "repositoryId", "description": "The Node ID of the repository.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null }, { "name": "baseRefName", "description": "The name of the branch you want your changes pulled into. This should be an existing branch\non the current repository. You cannot update the base branch on a pull request to point\nto another repository.\n", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "defaultValue": null }, { "name": "headRefName", "description": "The name of the branch where your changes are implemented. For cross-repository pull requests\nin the same network, namespace `head_ref_name` with a user like this: `username:branch`.\n", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "defaultValue": null }, { "name": "title", "description": "The title of the pull request.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "defaultValue": null }, { "name": "body", "description": "The contents of the pull request.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "maintainerCanModify", "description": "Indicates whether maintainers can modify the pull request.", "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": "true" }, { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "UpdatePullRequestPayload", "description": "Autogenerated return type of UpdatePullRequest", "fields": [ { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "pullRequest", "description": "The updated pull request.", "args": [], "type": { "kind": "OBJECT", "name": "PullRequest", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "UpdatePullRequestInput", "description": "Autogenerated input type of UpdatePullRequest", "fields": null, "inputFields": [ { "name": "pullRequestId", "description": "The Node ID of the pull request.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null }, { "name": "baseRefName", "description": "The name of the branch you want your changes pulled into. This should be an existing branch\non the current repository.\n", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "title", "description": "The title of the pull request.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "body", "description": "The contents of the pull request.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "maintainerCanModify", "description": "Indicates whether maintainers can modify the pull request.", "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": null }, { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "ClosePullRequestPayload", "description": "Autogenerated return type of ClosePullRequest", "fields": [ { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "pullRequest", "description": "The pull request that was closed.", "args": [], "type": { "kind": "OBJECT", "name": "PullRequest", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "ClosePullRequestInput", "description": "Autogenerated input type of ClosePullRequest", "fields": null, "inputFields": [ { "name": "pullRequestId", "description": "ID of the pull request to be closed.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null }, { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "ReopenPullRequestPayload", "description": "Autogenerated return type of ReopenPullRequest", "fields": [ { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "pullRequest", "description": "The pull request that was reopened.", "args": [], "type": { "kind": "OBJECT", "name": "PullRequest", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "ReopenPullRequestInput", "description": "Autogenerated input type of ReopenPullRequest", "fields": null, "inputFields": [ { "name": "pullRequestId", "description": "ID of the pull request to be reopened.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null }, { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "MergePullRequestPayload", "description": "Autogenerated return type of MergePullRequest", "fields": [ { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "pullRequest", "description": "The pull request that was merged.", "args": [], "type": { "kind": "OBJECT", "name": "PullRequest", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "MergePullRequestInput", "description": "Autogenerated input type of MergePullRequest", "fields": null, "inputFields": [ { "name": "pullRequestId", "description": "ID of the pull request to be merged.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null }, { "name": "commitHeadline", "description": "Commit headline to use for the merge commit; if omitted, a default message will be used.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "commitBody", "description": "Commit body to use for the merge commit; if omitted, a default message will be used", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "expectedHeadOid", "description": "OID that the pull request head ref must match to allow merge; if omitted, no check is performed.", "type": { "kind": "SCALAR", "name": "GitObjectID", "ofType": null }, "defaultValue": null }, { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "DeletePullRequestReviewCommentPayload", "description": "Autogenerated return type of DeletePullRequestReviewComment", "fields": [ { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "pullRequestReview", "description": "The pull request review the deleted comment belonged to.", "args": [], "type": { "kind": "OBJECT", "name": "PullRequestReview", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "DeletePullRequestReviewCommentInput", "description": "Autogenerated input type of DeletePullRequestReviewComment", "fields": null, "inputFields": [ { "name": "id", "description": "The ID of the comment to delete.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null }, { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "AddPullRequestReviewPayload", "description": "Autogenerated return type of AddPullRequestReview", "fields": [ { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "pullRequestReview", "description": "The newly created pull request review.", "args": [], "type": { "kind": "OBJECT", "name": "PullRequestReview", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "reviewEdge", "description": "The edge from the pull request's review connection.", "args": [], "type": { "kind": "OBJECT", "name": "PullRequestReviewEdge", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "AddPullRequestReviewInput", "description": "Autogenerated input type of AddPullRequestReview", "fields": null, "inputFields": [ { "name": "pullRequestId", "description": "The Node ID of the pull request to modify.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null }, { "name": "commitOID", "description": "The commit OID the review pertains to.", "type": { "kind": "SCALAR", "name": "GitObjectID", "ofType": null }, "defaultValue": null }, { "name": "body", "description": "The contents of the review body comment.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "event", "description": "The event to perform on the pull request review.", "type": { "kind": "ENUM", "name": "PullRequestReviewEvent", "ofType": null }, "defaultValue": null }, { "name": "comments", "description": "The review line comments.", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "INPUT_OBJECT", "name": "DraftPullRequestReviewComment", "ofType": null } }, "defaultValue": null }, { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "ENUM", "name": "PullRequestReviewEvent", "description": "The possible events to perform on a pull request review.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "COMMENT", "description": "Submit general feedback without explicit approval.", "isDeprecated": false, "deprecationReason": null }, { "name": "APPROVE", "description": "Submit feedback and approve merging these changes.", "isDeprecated": false, "deprecationReason": null }, { "name": "REQUEST_CHANGES", "description": "Submit feedback that must be addressed before merging.", "isDeprecated": false, "deprecationReason": null }, { "name": "DISMISS", "description": "Dismiss review so it now longer effects merging.", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "DraftPullRequestReviewComment", "description": "Specifies a review comment to be left with a Pull Request Review.", "fields": null, "inputFields": [ { "name": "path", "description": "Path to the file being commented on.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "defaultValue": null }, { "name": "position", "description": "Position in the file to leave a comment on.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "defaultValue": null }, { "name": "body", "description": "Body of the comment to leave.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "SubmitPullRequestReviewPayload", "description": "Autogenerated return type of SubmitPullRequestReview", "fields": [ { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "pullRequestReview", "description": "The submitted pull request review.", "args": [], "type": { "kind": "OBJECT", "name": "PullRequestReview", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "SubmitPullRequestReviewInput", "description": "Autogenerated input type of SubmitPullRequestReview", "fields": null, "inputFields": [ { "name": "pullRequestReviewId", "description": "The Pull Request Review ID to submit.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null }, { "name": "event", "description": "The event to send to the Pull Request Review.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "PullRequestReviewEvent", "ofType": null } }, "defaultValue": null }, { "name": "body", "description": "The text field to set on the Pull Request Review.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "UpdatePullRequestReviewPayload", "description": "Autogenerated return type of UpdatePullRequestReview", "fields": [ { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "pullRequestReview", "description": "The updated pull request review.", "args": [], "type": { "kind": "OBJECT", "name": "PullRequestReview", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "UpdatePullRequestReviewInput", "description": "Autogenerated input type of UpdatePullRequestReview", "fields": null, "inputFields": [ { "name": "pullRequestReviewId", "description": "The Node ID of the pull request review to modify.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null }, { "name": "body", "description": "The contents of the pull request review body.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "defaultValue": null }, { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "DismissPullRequestReviewPayload", "description": "Autogenerated return type of DismissPullRequestReview", "fields": [ { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "pullRequestReview", "description": "The dismissed pull request review.", "args": [], "type": { "kind": "OBJECT", "name": "PullRequestReview", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "DismissPullRequestReviewInput", "description": "Autogenerated input type of DismissPullRequestReview", "fields": null, "inputFields": [ { "name": "pullRequestReviewId", "description": "The Node ID of the pull request review to modify.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null }, { "name": "message", "description": "The contents of the pull request review dismissal message.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "defaultValue": null }, { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "DeletePullRequestReviewPayload", "description": "Autogenerated return type of DeletePullRequestReview", "fields": [ { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "pullRequestReview", "description": "The deleted pull request review.", "args": [], "type": { "kind": "OBJECT", "name": "PullRequestReview", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "DeletePullRequestReviewInput", "description": "Autogenerated input type of DeletePullRequestReview", "fields": null, "inputFields": [ { "name": "pullRequestReviewId", "description": "The Node ID of the pull request review to delete.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null }, { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "ResolveReviewThreadPayload", "description": "Autogenerated return type of ResolveReviewThread", "fields": [ { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "thread", "description": "The thread to resolve.", "args": [], "type": { "kind": "OBJECT", "name": "PullRequestReviewThread", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "ResolveReviewThreadInput", "description": "Autogenerated input type of ResolveReviewThread", "fields": null, "inputFields": [ { "name": "threadId", "description": "The ID of the thread to resolve", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null }, { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "UnresolveReviewThreadPayload", "description": "Autogenerated return type of UnresolveReviewThread", "fields": [ { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "thread", "description": "The thread to resolve.", "args": [], "type": { "kind": "OBJECT", "name": "PullRequestReviewThread", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "UnresolveReviewThreadInput", "description": "Autogenerated input type of UnresolveReviewThread", "fields": null, "inputFields": [ { "name": "threadId", "description": "The ID of the thread to unresolve", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null }, { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "AddPullRequestReviewCommentPayload", "description": "Autogenerated return type of AddPullRequestReviewComment", "fields": [ { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "comment", "description": "The newly created comment.", "args": [], "type": { "kind": "OBJECT", "name": "PullRequestReviewComment", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "commentEdge", "description": "The edge from the review's comment connection.", "args": [], "type": { "kind": "OBJECT", "name": "PullRequestReviewCommentEdge", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "AddPullRequestReviewCommentInput", "description": "Autogenerated input type of AddPullRequestReviewComment", "fields": null, "inputFields": [ { "name": "pullRequestReviewId", "description": "The Node ID of the review to modify.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null }, { "name": "commitOID", "description": "The SHA of the commit to comment on.", "type": { "kind": "SCALAR", "name": "GitObjectID", "ofType": null }, "defaultValue": null }, { "name": "body", "description": "The text of the comment.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "defaultValue": null }, { "name": "path", "description": "The relative path of the file to comment on.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "position", "description": "The line index in the diff to comment on.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "inReplyTo", "description": "The comment id to reply to.", "type": { "kind": "SCALAR", "name": "ID", "ofType": null }, "defaultValue": null }, { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "UpdatePullRequestReviewCommentPayload", "description": "Autogenerated return type of UpdatePullRequestReviewComment", "fields": [ { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "pullRequestReviewComment", "description": "The updated comment.", "args": [], "type": { "kind": "OBJECT", "name": "PullRequestReviewComment", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "UpdatePullRequestReviewCommentInput", "description": "Autogenerated input type of UpdatePullRequestReviewComment", "fields": null, "inputFields": [ { "name": "pullRequestReviewCommentId", "description": "The Node ID of the comment to modify.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null }, { "name": "body", "description": "The text of the comment.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "defaultValue": null }, { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "RemoveOutsideCollaboratorPayload", "description": "Autogenerated return type of RemoveOutsideCollaborator", "fields": [ { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "removedUser", "description": "The user that was removed as an outside collaborator.", "args": [], "type": { "kind": "OBJECT", "name": "User", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "RemoveOutsideCollaboratorInput", "description": "Autogenerated input type of RemoveOutsideCollaborator", "fields": null, "inputFields": [ { "name": "userId", "description": "The ID of the outside collaborator to remove.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null }, { "name": "organizationId", "description": "The ID of the organization to remove the outside collaborator from.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null }, { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "RequestReviewsPayload", "description": "Autogenerated return type of RequestReviews", "fields": [ { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "pullRequest", "description": "The pull request that is getting requests.", "args": [], "type": { "kind": "OBJECT", "name": "PullRequest", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "requestedReviewersEdge", "description": "The edge from the pull request to the requested reviewers.", "args": [], "type": { "kind": "OBJECT", "name": "UserEdge", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "RequestReviewsInput", "description": "Autogenerated input type of RequestReviews", "fields": null, "inputFields": [ { "name": "pullRequestId", "description": "The Node ID of the pull request to modify.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null }, { "name": "userIds", "description": "The Node IDs of the user to request.", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } } }, "defaultValue": null }, { "name": "teamIds", "description": "The Node IDs of the team to request.", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } } }, "defaultValue": null }, { "name": "union", "description": "Add users to the set rather than replace.", "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": null }, { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "AddStarPayload", "description": "Autogenerated return type of AddStar", "fields": [ { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "starrable", "description": "The starrable.", "args": [], "type": { "kind": "INTERFACE", "name": "Starrable", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "AddStarInput", "description": "Autogenerated input type of AddStar", "fields": null, "inputFields": [ { "name": "starrableId", "description": "The Starrable ID to star.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null }, { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "RemoveStarPayload", "description": "Autogenerated return type of RemoveStar", "fields": [ { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "starrable", "description": "The starrable.", "args": [], "type": { "kind": "INTERFACE", "name": "Starrable", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "RemoveStarInput", "description": "Autogenerated input type of RemoveStar", "fields": null, "inputFields": [ { "name": "starrableId", "description": "The Starrable ID to unstar.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null }, { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "AcceptTopicSuggestionPayload", "description": "Autogenerated return type of AcceptTopicSuggestion", "fields": [ { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "topic", "description": "The accepted topic.", "args": [], "type": { "kind": "OBJECT", "name": "Topic", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "AcceptTopicSuggestionInput", "description": "Autogenerated input type of AcceptTopicSuggestion", "fields": null, "inputFields": [ { "name": "repositoryId", "description": "The Node ID of the repository.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null }, { "name": "name", "description": "The name of the suggested topic.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "defaultValue": null }, { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "DeclineTopicSuggestionPayload", "description": "Autogenerated return type of DeclineTopicSuggestion", "fields": [ { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "topic", "description": "The declined topic.", "args": [], "type": { "kind": "OBJECT", "name": "Topic", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "DeclineTopicSuggestionInput", "description": "Autogenerated input type of DeclineTopicSuggestion", "fields": null, "inputFields": [ { "name": "repositoryId", "description": "The Node ID of the repository.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null }, { "name": "name", "description": "The name of the suggested topic.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "defaultValue": null }, { "name": "reason", "description": "The reason why the suggested topic is declined.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "TopicSuggestionDeclineReason", "ofType": null } }, "defaultValue": null }, { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "ENUM", "name": "TopicSuggestionDeclineReason", "description": "Reason that the suggested topic is declined.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "NOT_RELEVANT", "description": "The suggested topic is not relevant to the repository.", "isDeprecated": false, "deprecationReason": null }, { "name": "TOO_SPECIFIC", "description": "The suggested topic is too specific for the repository (e.g. #ruby-on-rails-version-4-2-1).", "isDeprecated": false, "deprecationReason": null }, { "name": "PERSONAL_PREFERENCE", "description": "The viewer does not like the suggested topic.", "isDeprecated": false, "deprecationReason": null }, { "name": "TOO_GENERAL", "description": "The suggested topic is too general for the repository.", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null }, { "kind": "OBJECT", "name": "UpdateTopicsPayload", "description": "Autogenerated return type of UpdateTopics", "fields": [ { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "invalidTopicNames", "description": "Names of the provided topics that are not valid.", "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "repository", "description": "The updated repository.", "args": [], "type": { "kind": "OBJECT", "name": "Repository", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "UpdateTopicsInput", "description": "Autogenerated input type of UpdateTopics", "fields": null, "inputFields": [ { "name": "repositoryId", "description": "The Node ID of the repository.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null }, { "name": "topicNames", "description": "An array of topic names.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } } } }, "defaultValue": null }, { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "CreateBranchProtectionRulePayload", "description": "Autogenerated return type of CreateBranchProtectionRule", "fields": [ { "name": "branchProtectionRule", "description": "The newly created BranchProtectionRule.", "args": [], "type": { "kind": "OBJECT", "name": "BranchProtectionRule", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "CreateBranchProtectionRuleInput", "description": "Autogenerated input type of CreateBranchProtectionRule", "fields": null, "inputFields": [ { "name": "repositoryId", "description": "The global relay id of the repository in which a new branch protection rule should be created in.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null }, { "name": "pattern", "description": "The glob-like pattern used to determine matching branches.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "defaultValue": null }, { "name": "requiresApprovingReviews", "description": "Are approving reviews required to update matching branches.", "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": null }, { "name": "requiredApprovingReviewCount", "description": "Number of approving reviews required to update matching branches.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "requiresCommitSignatures", "description": "Are commits required to be signed.", "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": null }, { "name": "isAdminEnforced", "description": "Can admins overwrite branch protection.", "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": null }, { "name": "requiresStatusChecks", "description": "Are status checks required to update matching branches.", "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": null }, { "name": "requiresStrictStatusChecks", "description": "Are branches required to be up to date before merging.", "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": null }, { "name": "requiresCodeOwnerReviews", "description": "Are reviews from code owners required to update matching branches.", "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": null }, { "name": "dismissesStaleReviews", "description": "Will new commits pushed to matching branches dismiss pull request review approvals.", "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": null }, { "name": "restrictsReviewDismissals", "description": "Is dismissal of pull request reviews restricted.", "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": null }, { "name": "reviewDismissalActorIds", "description": "A list of User or Team IDs allowed to dismiss reviews on pull requests targeting matching branches.", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } } }, "defaultValue": null }, { "name": "restrictsPushes", "description": "Is pushing to matching branches restricted.", "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": null }, { "name": "pushActorIds", "description": "A list of User or Team IDs allowed to push to matching branches.", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } } }, "defaultValue": null }, { "name": "requiredStatusCheckContexts", "description": "List of required status check contexts that must pass for commits to be accepted to matching branches.", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } } }, "defaultValue": null }, { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "UpdateBranchProtectionRulePayload", "description": "Autogenerated return type of UpdateBranchProtectionRule", "fields": [ { "name": "branchProtectionRule", "description": "The newly created BranchProtectionRule.", "args": [], "type": { "kind": "OBJECT", "name": "BranchProtectionRule", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "UpdateBranchProtectionRuleInput", "description": "Autogenerated input type of UpdateBranchProtectionRule", "fields": null, "inputFields": [ { "name": "branchProtectionRuleId", "description": "The global relay id of the branch protection rule to be updated.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null }, { "name": "pattern", "description": "The glob-like pattern used to determine matching branches.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "requiresApprovingReviews", "description": "Are approving reviews required to update matching branches.", "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": null }, { "name": "requiredApprovingReviewCount", "description": "Number of approving reviews required to update matching branches.", "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, "defaultValue": null }, { "name": "requiresCommitSignatures", "description": "Are commits required to be signed.", "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": null }, { "name": "isAdminEnforced", "description": "Can admins overwrite branch protection.", "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": null }, { "name": "requiresStatusChecks", "description": "Are status checks required to update matching branches.", "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": null }, { "name": "requiresStrictStatusChecks", "description": "Are branches required to be up to date before merging.", "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": null }, { "name": "requiresCodeOwnerReviews", "description": "Are reviews from code owners required to update matching branches.", "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": null }, { "name": "dismissesStaleReviews", "description": "Will new commits pushed to matching branches dismiss pull request review approvals.", "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": null }, { "name": "restrictsReviewDismissals", "description": "Is dismissal of pull request reviews restricted.", "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": null }, { "name": "reviewDismissalActorIds", "description": "A list of User or Team IDs allowed to dismiss reviews on pull requests targeting matching branches.", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } } }, "defaultValue": null }, { "name": "restrictsPushes", "description": "Is pushing to matching branches restricted.", "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": null }, { "name": "pushActorIds", "description": "A list of User or Team IDs allowed to push to matching branches.", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } } }, "defaultValue": null }, { "name": "requiredStatusCheckContexts", "description": "List of required status check contexts that must pass for commits to be accepted to matching branches.", "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } } }, "defaultValue": null }, { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "DeleteBranchProtectionRulePayload", "description": "Autogenerated return type of DeleteBranchProtectionRule", "fields": [ { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "DeleteBranchProtectionRuleInput", "description": "Autogenerated input type of DeleteBranchProtectionRule", "fields": null, "inputFields": [ { "name": "branchProtectionRuleId", "description": "The global relay id of the branch protection rule to be deleted.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null }, { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "ChangeUserStatusPayload", "description": "Autogenerated return type of ChangeUserStatus", "fields": [ { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "status", "description": "Your updated status.", "args": [], "type": { "kind": "OBJECT", "name": "UserStatus", "ofType": null }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "ChangeUserStatusInput", "description": "Autogenerated input type of ChangeUserStatus", "fields": null, "inputFields": [ { "name": "emoji", "description": "The emoji to represent your status. Can either be a native Unicode emoji or an emoji name with colons, e.g., :grinning:.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "message", "description": "A short description of your current status.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null }, { "name": "organizationId", "description": "The ID of the organization whose members will be allowed to see the status. If omitted, the status will be publicly visible.", "type": { "kind": "SCALAR", "name": "ID", "ofType": null }, "defaultValue": null }, { "name": "limitedAvailability", "description": "Whether this status should indicate you are not fully available on GitHub, e.g., you are away.", "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": "false" }, { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "ContentAttachment", "description": "A content attachment", "fields": [ { "name": "body", "description": "The body text of the content attachment. This parameter supports markdown.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "contentReference", "description": "The content reference that the content attachment is attached to.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "ContentReference", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "databaseId", "description": "Identifies the primary key from the database.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "title", "description": "The title of the content attachment.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "ContentReference", "description": "A content reference", "fields": [ { "name": "databaseId", "description": "Identifies the primary key from the database.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "reference", "description": "The reference of the content reference.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "INPUT_OBJECT", "name": "CreateContentAttachmentInput", "description": "Autogenerated input type of CreateContentAttachment", "fields": null, "inputFields": [ { "name": "contentReferenceId", "description": "The node ID of the content_reference.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "defaultValue": null }, { "name": "title", "description": "The title of the content attachment.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "defaultValue": null }, { "name": "body", "description": "The body of the content attachment, which may contain markdown.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "defaultValue": null }, { "name": "clientMutationId", "description": "A unique identifier for the client performing the mutation.", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": null } ], "interfaces": null, "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "__Schema", "description": "A GraphQL Schema defines the capabilities of a GraphQL server. It exposes all available types and directives on the server, as well as the entry points for query, mutation, and subscription operations.", "fields": [ { "name": "directives", "description": "A list of all directives supported by this server.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "__Directive", "ofType": null } } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "mutationType", "description": "If this server supports mutation, the type that mutation operations will be rooted at.", "args": [], "type": { "kind": "OBJECT", "name": "__Type", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "queryType", "description": "The type that query operations will be rooted at.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "__Type", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "subscriptionType", "description": "If this server support subscription, the type that subscription operations will be rooted at.", "args": [], "type": { "kind": "OBJECT", "name": "__Type", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "types", "description": "A list of all types supported by this server.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "__Type", "ofType": null } } } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "__Type", "description": "The fundamental unit of any GraphQL Schema is the type. There are many kinds of types in GraphQL as represented by the `__TypeKind` enum.\n\nDepending on the kind of a type, certain fields describe information about that type. Scalar types provide no information beyond a name and description, while Enum types provide their values. Object and Interface types provide the fields they describe. Abstract types, Union and Interface, provide the Object types possible at runtime. List and NonNull types compose other types.", "fields": [ { "name": "description", "description": null, "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "enumValues", "description": null, "args": [ { "name": "includeDeprecated", "description": null, "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": "false" } ], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "__EnumValue", "ofType": null } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "fields", "description": null, "args": [ { "name": "includeDeprecated", "description": null, "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, "defaultValue": "false" } ], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "__Field", "ofType": null } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "inputFields", "description": null, "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "__InputValue", "ofType": null } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "interfaces", "description": null, "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "__Type", "ofType": null } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "kind", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "__TypeKind", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "name", "description": null, "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "ofType", "description": null, "args": [], "type": { "kind": "OBJECT", "name": "__Type", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "possibleTypes", "description": null, "args": [], "type": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "__Type", "ofType": null } } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "__Field", "description": "Object and Interface types are described by a list of Fields, each of which has a name, potentially a list of arguments, and a return type.", "fields": [ { "name": "args", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "__InputValue", "ofType": null } } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "deprecationReason", "description": null, "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "description", "description": null, "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "isDeprecated", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "name", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "type", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "__Type", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "__Directive", "description": "A Directive provides a way to describe alternate runtime execution and type validation behavior in a GraphQL document.\n\nIn some cases, you need to provide options to alter GraphQL's execution behavior in ways field arguments will not suffice, such as conditionally including or skipping a field. Directives provide this by describing additional information to the executor.", "fields": [ { "name": "args", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "__InputValue", "ofType": null } } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "description", "description": null, "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "locations", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "LIST", "name": null, "ofType": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "__DirectiveLocation", "ofType": null } } } }, "isDeprecated": false, "deprecationReason": null }, { "name": "name", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "onField", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": true, "deprecationReason": "Use `locations`." }, { "name": "onFragment", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": true, "deprecationReason": "Use `locations`." }, { "name": "onOperation", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": true, "deprecationReason": "Use `locations`." } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "__EnumValue", "description": "One possible value for a given Enum. Enum values are unique values, not a placeholder for a string or numeric value. However an Enum value is returned in a JSON response as a string.", "fields": [ { "name": "deprecationReason", "description": null, "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "description", "description": null, "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "isDeprecated", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "name", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "__InputValue", "description": "Arguments provided to Fields or Directives and the input fields of an InputObject are represented as Input Values which describe their type and optionally a default value.", "fields": [ { "name": "defaultValue", "description": "A GraphQL-formatted string representing the default value for this input value.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "description", "description": null, "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "name", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "type", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "__Type", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [], "enumValues": null, "possibleTypes": null }, { "kind": "ENUM", "name": "__TypeKind", "description": "An enum describing what kind of type a given `__Type` is.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "SCALAR", "description": "Indicates this type is a scalar.", "isDeprecated": false, "deprecationReason": null }, { "name": "OBJECT", "description": "Indicates this type is an object. `fields` and `interfaces` are valid fields.", "isDeprecated": false, "deprecationReason": null }, { "name": "INTERFACE", "description": "Indicates this type is an interface. `fields` and `possibleTypes` are valid fields.", "isDeprecated": false, "deprecationReason": null }, { "name": "UNION", "description": "Indicates this type is a union. `possibleTypes` is a valid field.", "isDeprecated": false, "deprecationReason": null }, { "name": "ENUM", "description": "Indicates this type is an enum. `enumValues` is a valid field.", "isDeprecated": false, "deprecationReason": null }, { "name": "INPUT_OBJECT", "description": "Indicates this type is an input object. `inputFields` is a valid field.", "isDeprecated": false, "deprecationReason": null }, { "name": "LIST", "description": "Indicates this type is a list. `ofType` is a valid field.", "isDeprecated": false, "deprecationReason": null }, { "name": "NON_NULL", "description": "Indicates this type is a non-null. `ofType` is a valid field.", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null }, { "kind": "ENUM", "name": "__DirectiveLocation", "description": "A Directive can be adjacent to many parts of the GraphQL language, a __DirectiveLocation describes one such possible adjacencies.", "fields": null, "inputFields": null, "interfaces": null, "enumValues": [ { "name": "QUERY", "description": "Location adjacent to a query operation.", "isDeprecated": false, "deprecationReason": null }, { "name": "MUTATION", "description": "Location adjacent to a mutation operation.", "isDeprecated": false, "deprecationReason": null }, { "name": "SUBSCRIPTION", "description": "Location adjacent to a subscription operation.", "isDeprecated": false, "deprecationReason": null }, { "name": "FIELD", "description": "Location adjacent to a field.", "isDeprecated": false, "deprecationReason": null }, { "name": "FRAGMENT_DEFINITION", "description": "Location adjacent to a fragment definition.", "isDeprecated": false, "deprecationReason": null }, { "name": "FRAGMENT_SPREAD", "description": "Location adjacent to a fragment spread.", "isDeprecated": false, "deprecationReason": null }, { "name": "INLINE_FRAGMENT", "description": "Location adjacent to an inline fragment.", "isDeprecated": false, "deprecationReason": null }, { "name": "SCHEMA", "description": "Location adjacent to a schema definition.", "isDeprecated": false, "deprecationReason": null }, { "name": "SCALAR", "description": "Location adjacent to a scalar definition.", "isDeprecated": false, "deprecationReason": null }, { "name": "OBJECT", "description": "Location adjacent to an object type definition.", "isDeprecated": false, "deprecationReason": null }, { "name": "FIELD_DEFINITION", "description": "Location adjacent to a field definition.", "isDeprecated": false, "deprecationReason": null }, { "name": "ARGUMENT_DEFINITION", "description": "Location adjacent to an argument definition.", "isDeprecated": false, "deprecationReason": null }, { "name": "INTERFACE", "description": "Location adjacent to an interface definition.", "isDeprecated": false, "deprecationReason": null }, { "name": "UNION", "description": "Location adjacent to a union definition.", "isDeprecated": false, "deprecationReason": null }, { "name": "ENUM", "description": "Location adjacent to an enum definition.", "isDeprecated": false, "deprecationReason": null }, { "name": "ENUM_VALUE", "description": "Location adjacent to an enum value definition.", "isDeprecated": false, "deprecationReason": null }, { "name": "INPUT_OBJECT", "description": "Location adjacent to an input object type definition.", "isDeprecated": false, "deprecationReason": null }, { "name": "INPUT_FIELD_DEFINITION", "description": "Location adjacent to an input object field definition.", "isDeprecated": false, "deprecationReason": null } ], "possibleTypes": null }, { "kind": "OBJECT", "name": "GpgSignature", "description": "Represents a GPG signature on a Commit or Tag.", "fields": [ { "name": "email", "description": "Email used to sign this object.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "isValid", "description": "True if the signature is valid and verified by GitHub.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "keyId", "description": "Hex-encoded ID of the key that signed this object.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "payload", "description": "Payload for GPG signing object. Raw ODB object without the signature header.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "signature", "description": "ASCII-armored signature header from object.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "signer", "description": "GitHub user corresponding to the email signing this commit.", "args": [], "type": { "kind": "OBJECT", "name": "User", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "state", "description": "The state of this signature. `VALID` if signature is valid and verified by GitHub, otherwise represents reason why signature is considered invalid.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "GitSignatureState", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "wasSignedByGitHub", "description": "True if the signature was made with GitHub's signing key.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "GitSignature", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "SmimeSignature", "description": "Represents an S/MIME signature on a Commit or Tag.", "fields": [ { "name": "email", "description": "Email used to sign this object.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "isValid", "description": "True if the signature is valid and verified by GitHub.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "payload", "description": "Payload for GPG signing object. Raw ODB object without the signature header.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "signature", "description": "ASCII-armored signature header from object.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "signer", "description": "GitHub user corresponding to the email signing this commit.", "args": [], "type": { "kind": "OBJECT", "name": "User", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "state", "description": "The state of this signature. `VALID` if signature is valid and verified by GitHub, otherwise represents reason why signature is considered invalid.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "GitSignatureState", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "wasSignedByGitHub", "description": "True if the signature was made with GitHub's signing key.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "GitSignature", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "Tag", "description": "Represents a Git tag.", "fields": [ { "name": "abbreviatedOid", "description": "An abbreviated version of the Git object ID", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "commitResourcePath", "description": "The HTTP path for this Git object", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "commitUrl", "description": "The HTTP URL for this Git object", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "URI", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "id", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "message", "description": "The Git tag message.", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "name", "description": "The Git tag name.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "oid", "description": "The Git object ID", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "GitObjectID", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "repository", "description": "The Repository the Git object belongs to", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "OBJECT", "name": "Repository", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "tagger", "description": "Details about the tag author.", "args": [], "type": { "kind": "OBJECT", "name": "GitActor", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "target", "description": "The Git object the tag points to.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "INTERFACE", "name": "GitObject", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "Node", "ofType": null }, { "kind": "INTERFACE", "name": "GitObject", "ofType": null } ], "enumValues": null, "possibleTypes": null }, { "kind": "OBJECT", "name": "UnknownSignature", "description": "Represents an unknown signature on a Commit or Tag.", "fields": [ { "name": "email", "description": "Email used to sign this object.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "isValid", "description": "True if the signature is valid and verified by GitHub.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "payload", "description": "Payload for GPG signing object. Raw ODB object without the signature header.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "signature", "description": "ASCII-armored signature header from object.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "signer", "description": "GitHub user corresponding to the email signing this commit.", "args": [], "type": { "kind": "OBJECT", "name": "User", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { "name": "state", "description": "The state of this signature. `VALID` if signature is valid and verified by GitHub, otherwise represents reason why signature is considered invalid.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "ENUM", "name": "GitSignatureState", "ofType": null } }, "isDeprecated": false, "deprecationReason": null }, { "name": "wasSignedByGitHub", "description": "True if the signature was made with GitHub's signing key.", "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "isDeprecated": false, "deprecationReason": null } ], "inputFields": null, "interfaces": [ { "kind": "INTERFACE", "name": "GitSignature", "ofType": null } ], "enumValues": null, "possibleTypes": null } ], "directives": [ { "name": "include", "description": "Directs the executor to include this field or fragment only when the `if` argument is true.", "locations": ["FIELD", "FRAGMENT_SPREAD", "INLINE_FRAGMENT"], "args": [ { "name": "if", "description": "Included when true.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "defaultValue": null } ] }, { "name": "skip", "description": "Directs the executor to skip this field or fragment when the `if` argument is true.", "locations": ["FIELD", "FRAGMENT_SPREAD", "INLINE_FRAGMENT"], "args": [ { "name": "if", "description": "Skipped when true.", "type": { "kind": "NON_NULL", "name": null, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } }, "defaultValue": null } ] }, { "name": "deprecated", "description": "Marks an element of a GraphQL schema as no longer supported.", "locations": ["FIELD_DEFINITION", "ENUM_VALUE"], "args": [ { "name": "reason", "description": "Explains why this element was deprecated, usually also including a suggestion for how to access supported similar data. Formatted in [Markdown](https://daringfireball.net/projects/markdown/).", "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "defaultValue": "\"No longer supported\"" } ] } ] } } } graphql-core-3.2.6/tests/fixtures/kitchen_sink.graphql000066400000000000000000000017421474546154300231730ustar00rootroot00000000000000query queryName($foo: ComplexType, $site: Site = MOBILE) @onQuery { whoever123is: node(id: [123, 456]) { id , ... on User @onInlineFragment { field2 { id , alias: field1(first:10, after:$foo,) @include(if: $foo) { id, ...frag @onFragmentSpread } } } ... @skip(unless: $foo) { id } ... { id } } } mutation likeStory @onMutation { like(story: 123) @onField { story { id @onField } } } subscription StoryLikeSubscription( $input: StoryLikeSubscribeInput @onVariableDefinition ) @onSubscription { storyLikeSubscribe(input: $input) { story { likers { count } likeSentence { text } } } } fragment frag on Friend @onFragmentDefinition { foo(size: $size, bar: $b, obj: {key: "value", block: """ block string uses \""" """}) } { unnamed(truthy: true, falsy: false, nullish: null), query } query { __typename } graphql-core-3.2.6/tests/fixtures/schema_kitchen_sink.graphql000066400000000000000000000054741474546154300245210ustar00rootroot00000000000000"""This is a description of the schema as a whole.""" schema { query: QueryType mutation: MutationType } """ This is a description of the `Foo` type. """ type Foo implements Bar & Baz & Two { "Description of the `one` field." one: Type """ This is a description of the `two` field. """ two( """ This is a description of the `argument` argument. """ argument: InputType! ): Type """This is a description of the `three` field.""" three(argument: InputType, other: String): Int four(argument: String = "string"): String five(argument: [String] = ["string", "string"]): String six(argument: InputType = {key: "value"}): Type seven(argument: Int = null): Type } type AnnotatedObject @onObject(arg: "value") { annotatedField(arg: Type = "default" @onArgumentDefinition): Type @onField } type UndefinedType extend type Foo { seven(argument: [String]): Type } extend type Foo @onType interface Bar { one: Type four(argument: String = "string"): String } interface AnnotatedInterface @onInterface { annotatedField(arg: Type @onArgumentDefinition): Type @onField } interface UndefinedInterface extend interface Bar implements Two { two(argument: InputType!): Type } extend interface Bar @onInterface interface Baz implements Bar & Two { one: Type two(argument: InputType!): Type four(argument: String = "string"): String } union Feed = | Story | Article | Advert union AnnotatedUnion @onUnion = A | B union AnnotatedUnionTwo @onUnion = | A | B union UndefinedUnion extend union Feed = Photo | Video extend union Feed @onUnion scalar CustomScalar scalar AnnotatedScalar @onScalar extend scalar CustomScalar @onScalar enum Site { """ This is a description of the `DESKTOP` value """ DESKTOP """This is a description of the `MOBILE` value""" MOBILE "This is a description of the `WEB` value" WEB } enum AnnotatedEnum @onEnum { ANNOTATED_VALUE @onEnumValue OTHER_VALUE } enum UndefinedEnum extend enum Site { VR } extend enum Site @onEnum input InputType { key: String! answer: Int = 42 } input AnnotatedInput @onInputObject { annotatedField: Type @onInputFieldDefinition } input UndefinedInput extend input InputType { other: Float = 1.23e4 @onInputFieldDefinition } extend input InputType @onInputObject """ This is a description of the `@skip` directive """ directive @skip( """This is a description of the `if` argument""" if: Boolean! @onArgumentDefinition ) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT directive @include(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT directive @include2(if: Boolean!) on | FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT directive @myRepeatableDir(name: String!) repeatable on | OBJECT | INTERFACE extend schema @onSchema extend schema @onSchema { subscription: SubscriptionType } graphql-core-3.2.6/tests/language/000077500000000000000000000000001474546154300170505ustar00rootroot00000000000000graphql-core-3.2.6/tests/language/__init__.py000066400000000000000000000000411474546154300211540ustar00rootroot00000000000000"""Tests for graphql.language""" graphql-core-3.2.6/tests/language/test_ast.py000066400000000000000000000212661474546154300212570ustar00rootroot00000000000000from copy import copy, deepcopy import weakref from graphql.language import Location, Node, Source, Token, TokenKind from graphql.pyutils import inspect class SampleTestNode(Node): __slots__ = "alpha", "beta" alpha: int beta: int def describe_token_class(): def initializes(): token = Token( kind=TokenKind.NAME, start=11, end=12, line=1, column=3, value="n", ) assert token.kind == TokenKind.NAME assert token.start == 11 assert token.end == 12 assert token.line == 1 assert token.column == 3 assert token.prev is None assert token.value == "n" def can_stringify(): token = Token(TokenKind.NAME, 1, 2, 1, 2, value="test") assert str(token) == "Name 'test'" assert token.desc == str(token) def has_representation_with_line_and_column(): token = Token(TokenKind.NAME, 1, 2, 1, 2, value="test") assert repr(token) == "" assert inspect(token) == repr(token) def can_check_equality(): token1 = Token(TokenKind.NAME, 1, 2, 1, 2, value="test") token2 = Token(TokenKind.NAME, 1, 2, 1, 2, value="test") assert token2 == token1 assert not token2 != token1 token3 = Token(TokenKind.NAME, 1, 2, 1, 2, value="text") assert token3 != token1 token4 = Token(TokenKind.NAME, 1, 4, 1, 2, value="test") assert token4 != token1 token5 = Token(TokenKind.NAME, 1, 2, 1, 4, value="test") assert token5 != token1 def can_compare_with_string(): token = Token(TokenKind.NAME, 1, 2, 1, 2, value="test") assert token == "Name 'test'" assert token != "Name 'foo'" def does_not_equal_incompatible_object(): token = Token(TokenKind.NAME, 1, 2, 1, 2, value="test") assert token != {"Name": "test"} def can_hash(): token1 = Token(TokenKind.NAME, 1, 2, 1, 2, value="hash") token2 = Token(TokenKind.NAME, 1, 2, 1, 2, value="hash") assert token2 == token1 assert hash(token2) == hash(token1) token3 = Token(TokenKind.NAME, 1, 2, 1, 2, value="bash") assert token3 != token1 assert hash(token3) != hash(token1) def can_copy(): token1 = Token(TokenKind.NAME, 1, 2, 1, 2, value="copy") token2 = copy(token1) assert token2 == token1 assert token2 is not token1 def describe_location_class(): token1 = Token(TokenKind.NAME, 1, 2, 1, 2) token2 = Token(TokenKind.NAME, 2, 3, 1, 3) source = Source("source") def initializes(): loc = Location(token1, token2, source) assert loc.start == token1.start assert loc.end == token2.end assert loc.start_token is token1 assert loc.end_token is token2 assert loc.source is source def can_stringify_with_start_and_end(): loc = Location(token1, token2, source) assert str(loc) == "1:3" def has_representation_with_start_and_end(): loc = Location(token1, token2, source) assert repr(loc) == "" assert inspect(loc) == repr(loc) def can_check_equality(): loc1 = Location(token1, token2, source) loc2 = Location(token1, token2, source) assert loc2 == loc1 loc3 = Location(token1, token1, source) assert loc3 != loc1 loc4 = Location(token2, token2, source) assert loc4 != loc1 assert loc4 != loc3 def can_check_equality_with_tuple_or_list(): loc = Location(token1, token2, source) assert loc == (1, 3) assert loc == [1, 3] assert not loc != (1, 3) assert not loc != [1, 3] assert loc != (1, 2) assert loc != [2, 3] def does_not_equal_incompatible_object(): loc = Location(token1, token2, source) assert not loc == (1, 2, 3) assert loc != (1, 2, 3) assert not loc == {1: 2} assert loc != {1: 2} def can_hash(): loc1 = Location(token1, token2, source) loc2 = Location(token1, token2, source) assert loc2 == loc1 assert hash(loc2) == hash(loc1) loc3 = Location(token1, token1, source) assert loc3 != loc1 assert hash(loc3) != hash(loc1) loc4 = Location(token2, token2, source) assert loc4 != loc1 assert hash(loc4) != hash(loc1) assert hash(loc4) != hash(loc3) def describe_node_class(): def initializes_with_keywords(): node = SampleTestNode(alpha=1, beta=2, loc=0) assert node.alpha == 1 assert node.beta == 2 assert node.loc == 0 node = SampleTestNode(alpha=1, loc=None) assert node.loc is None assert node.alpha == 1 assert node.beta is None node = SampleTestNode(alpha=1, beta=2, gamma=3) assert node.alpha == 1 assert node.beta == 2 assert not hasattr(node, "gamma") def has_representation_with_loc(): node = SampleTestNode(alpha=1, beta=2) assert repr(node) == "SampleTestNode" node = SampleTestNode(alpha=1, beta=2, loc=3) assert repr(node) == "SampleTestNode at 3" def can_check_equality(): node = SampleTestNode(alpha=1, beta=2) node2 = SampleTestNode(alpha=1, beta=2) assert node2 == node assert not node2 != node node2 = SampleTestNode(alpha=1, beta=1) assert node2 != node node3 = Node(alpha=1, beta=2) assert node3 != node def can_hash(): node = SampleTestNode(alpha=1, beta=2) node2 = SampleTestNode(alpha=1, beta=2) assert node == node2 assert node2 is not node assert hash(node2) == hash(node) node3 = SampleTestNode(alpha=1, beta=3) assert node3 != node assert hash(node3) != hash(node) def caches_are_hashed(): node = SampleTestNode(alpha=1) assert not hasattr(node, "_hash") hash1 = hash(node) assert hasattr(node, "_hash") assert hash1 == getattr(node, "_hash") node.alpha = 2 assert not hasattr(node, "_hash") hash2 = hash(node) assert hash2 != hash1 assert hasattr(node, "_hash") assert hash2 == getattr(node, "_hash") def can_create_weak_reference(): node = SampleTestNode(alpha=1, beta=2) ref = weakref.ref(node) assert ref() is node def can_create_custom_attribute(): node = SampleTestNode(alpha=1, beta=2) node.gamma = 3 assert node.gamma == 3 # type: ignore def can_create_shallow_copy(): node = SampleTestNode(alpha=1, beta=2) node2 = copy(node) assert node2 is not node assert node2 == node def shallow_copy_is_really_shallow(): node = SampleTestNode(alpha=1, beta=2) node2 = SampleTestNode(alpha=node, beta=node) node3 = copy(node2) assert node3 is not node2 assert node3 == node2 assert node3.alpha is node2.alpha assert node3.beta is node2.beta def can_create_deep_copy(): alpha = SampleTestNode(alpha=1, beta=2) beta = SampleTestNode(alpha=3, beta=4) node = SampleTestNode(alpha=alpha, beta=beta) node2 = deepcopy(node) assert node2 is not node assert node2 == node assert node2.alpha == alpha assert node2.alpha is not alpha assert node2.alpha == alpha assert node2.beta is not beta def provides_snake_cased_kind_as_class_attribute(): assert SampleTestNode.kind == "sample_test" def provides_proper_kind_if_class_does_not_end_with_node(): class Foo(Node): pass assert Foo.kind == "foo" def provides_keys_as_class_attribute(): assert SampleTestNode.keys == ("loc", "alpha", "beta") def can_can_convert_to_dict(): node = SampleTestNode(alpha=1, beta=2) res = node.to_dict() assert node.to_dict(locations=True) == res assert res == {"kind": "sample_test", "alpha": 1, "beta": 2} assert list(res) == ["kind", "alpha", "beta"] def can_can_convert_to_dict_with_locations(): token = Token( kind=TokenKind.NAME, start=1, end=3, line=1, column=1, value="foo", ) loc = Location(token, token, Source("foo")) node = SampleTestNode(alpha=1, beta=2, loc=loc) res = node.to_dict(locations=True) assert res == { "kind": "sample_test", "alpha": 1, "beta": 2, "loc": {"start": 1, "end": 3}, } assert list(res) == ["kind", "alpha", "beta", "loc"] assert list(res["loc"]) == ["start", "end"] graphql-core-3.2.6/tests/language/test_block_string.py000066400000000000000000000156001474546154300231430ustar00rootroot00000000000000from typing import cast, Collection, Optional from graphql.language.block_string import ( is_printable_as_block_string, dedent_block_string_lines, print_block_string, ) def join_lines(*args: str) -> str: return "\n".join(args) def describe_dedent_block_string_lines(): def _assert_dedent(lines: Collection[str], expected: Collection[str]) -> None: assert dedent_block_string_lines(lines) == expected def handles_empty_string(): _assert_dedent([""], []) def does_not_dedent_first_line(): _assert_dedent([" a"], [" a"]) _assert_dedent([" a", " b"], [" a", "b"]) def removes_minimal_indentation_length(): _assert_dedent(["", " a", " b"], ["a", " b"]) _assert_dedent(["", " a", " b"], [" a", "b"]) _assert_dedent(["", " a", " b", "c"], [" a", " b", "c"]) def dedent_both_tab_and_space_as_single_character(): _assert_dedent(["", "\ta", " b"], ["a", " b"]) _assert_dedent(["", "\t a", " b"], ["a", " b"]) _assert_dedent(["", " \t a", " b"], ["a", " b"]) def removes_uniform_indentation_from_a_string(): lines = ["", " Hello,", " World!", "", " Yours,", " GraphQL."] _assert_dedent(lines, ["Hello,", " World!", "", "Yours,", " GraphQL."]) def removes_empty_leading_and_trailing_lines(): lines = [ "", "", " Hello,", " World!", "", " Yours,", " GraphQL.", "", "", ] _assert_dedent(lines, ["Hello,", " World!", "", "Yours,", " GraphQL."]) def removes_blank_leading_and_trailing_lines(): lines = [ " ", " ", " Hello,", " World!", "", " Yours,", " GraphQL.", " ", " ", ] _assert_dedent(lines, ["Hello,", " World!", "", "Yours,", " GraphQL."]) def retains_indentation_from_first_line(): lines = [" Hello,", " World!", "", " Yours,", " GraphQL."] _assert_dedent(lines, [" Hello,", " World!", "", "Yours,", " GraphQL."]) def does_not_alter_trailing_spaces(): lines = [ " ", " Hello, ", " World! ", " ", " Yours, ", " GraphQL. ", " ", ] _assert_dedent( lines, [ "Hello, ", " World! ", " ", "Yours, ", " GraphQL. ", ], ) def describe_is_printable_as_block_string(): def _assert_printable(s: str) -> None: assert is_printable_as_block_string(s) is True, s def _assert_non_printable(s: str) -> None: assert is_printable_as_block_string(s) is False, s def accepts_valid_strings(): _assert_printable("") _assert_printable(" a") _assert_printable('\t"\n"') _assert_non_printable('\t"\n \n\t"') def rejects_strings_with_only_whitespace(): _assert_non_printable(" ") _assert_non_printable("\t") _assert_non_printable("\t ") _assert_non_printable(" \t") def rejects_strings_with_non_printable_characters(): _assert_non_printable("\x00") _assert_non_printable("a\x00b") def rejects_strings_with_only_empty_lines(): _assert_non_printable("\n") _assert_non_printable("\n\n") _assert_non_printable("\n\n\n") _assert_non_printable(" \n \n") _assert_non_printable("\t\n\t\t\n") def rejects_strings_with_carriage_return(): _assert_non_printable("\r") _assert_non_printable("\n\r") _assert_non_printable("\r\n") _assert_non_printable("a\rb") def rejects_strings_with_leading_empty_lines(): _assert_non_printable("\na") _assert_non_printable(" \na") _assert_non_printable("\t\na") _assert_non_printable("\n\na") def rejects_strings_with_trailing_empty_lines(): _assert_non_printable("a\n") _assert_non_printable("a\n ") _assert_non_printable("a\n\t") _assert_non_printable("a\n\n") def can_check_lazy_stings(): class LazyString: def __init__(self, string: str) -> None: self.string = string def __str__(self) -> str: return self.string _assert_printable(cast(str, LazyString(""))) _assert_non_printable(cast(str, LazyString(" "))) def describe_print_block_string(): def _assert_block_string( s: str, readable: str, minimize: Optional[str] = None ) -> None: assert print_block_string(s) == readable assert print_block_string(s, minimize=True) == minimize or readable def does_not_escape_characters(): s = '" \\ / \b \f \n \r \t' _assert_block_string(s, f'"""\n{s}\n"""', f'"""\n{s}"""') def by_default_print_block_strings_as_single_line(): s = "one liner" _assert_block_string(s, '"""one liner"""') def by_default_print_block_strings_ending_with_triple_quotation_as_multi_line(): s = 'triple quotation """' _assert_block_string( s, '"""\ntriple quotation \\"""\n"""', '"""triple quotation \\""""""' ) def correctly_prints_single_line_with_leading_space(): s = " space-led string" _assert_block_string(s, '""" space-led string"""') def correctly_prints_single_line_with_leading_space_and_trailing_quotation(): s = ' space-led value "quoted string"' _assert_block_string(s, '""" space-led value "quoted string"\n"""') def correctly_prints_single_line_with_trailing_backslash(): s = "backslash \\" _assert_block_string(s, '"""\nbackslash \\\n"""', '"""\nbackslash \\\n"""') def correctly_prints_multi_line_with_internal_indent(): s = "no indent\n with indent" _assert_block_string( s, '"""\nno indent\n with indent\n"""', '"""\nno indent\n with indent"""' ) def correctly_prints_string_with_a_first_line_indentation(): s = join_lines(" first ", " line ", "indentation", " string") _assert_block_string( s, join_lines( '"""', " first ", " line ", "indentation", " string", '"""' ), join_lines( '""" first ', " line ", "indentation", ' string"""', ), ) def correctly_prints_lazy_stings(): class LazyString: def __str__(self) -> str: return "lazy" _assert_block_string(cast(str, LazyString()), '"""lazy"""') graphql-core-3.2.6/tests/language/test_block_string_fuzz.py000066400000000000000000000033661474546154300242270ustar00rootroot00000000000000from pytest import mark from graphql.language import Source, Lexer, TokenKind from graphql.language.block_string import ( print_block_string, is_printable_as_block_string, ) from ..utils import dedent, gen_fuzz_strings def lex_value(s: str) -> str: lexer = Lexer(Source(s)) value = lexer.advance().value assert isinstance(value, str) assert lexer.advance().kind == TokenKind.EOF, "Expected EOF" return value def assert_printable_block_string(test_value: str, minimize: bool = False) -> None: block_string = print_block_string(test_value, minimize=minimize) printed_value = lex_value(block_string) assert test_value == printed_value, dedent( f""" Expected lexValue({block_string!r}) to equal {test_value!r} but got {printed_value!r} """ ) def assert_non_printable_block_string(test_value: str) -> None: block_string = print_block_string(test_value) printed_value = lex_value(block_string) assert test_value != printed_value, dedent( f""" Expected lexValue({block_string!r}) to not equal {test_value!r} """ ) def describe_print_block_string(): @mark.slow @mark.timeout(20) def correctly_print_random_strings(): # Testing with length >7 is taking exponentially more time. However, it is # highly recommended testing with increased limit if you make any change. for fuzz_str in gen_fuzz_strings(allowed_chars='\n\t "a\\', max_length=7): if not is_printable_as_block_string(fuzz_str): assert_non_printable_block_string(fuzz_str) continue assert_printable_block_string(fuzz_str) assert_printable_block_string(fuzz_str, minimize=True) graphql-core-3.2.6/tests/language/test_character_classes.py000066400000000000000000000045331474546154300241370ustar00rootroot00000000000000from string import ascii_letters as letters, digits, punctuation from graphql.language.character_classes import ( is_digit, is_letter, is_name_start, is_name_continue, ) non_ascii = "¯_±¹²³½£ºµÄäÖöØø×〇᧐〸αΑωΩ" def describe_digit(): def accepts_digits(): assert all(is_digit(char) for char in digits) def rejects_letters(): assert not any(is_digit(char) for char in letters) def rejects_underscore(): assert not is_digit("_") def rejects_punctuation(): assert not any(is_digit(char) for char in punctuation) def rejects_non_ascii(): assert not any(is_digit(char) for char in non_ascii) def rejects_empty_string(): assert not is_digit("") def describe_letter(): def accepts_letters(): assert all(is_letter(char) for char in letters) def rejects_digits(): assert not any(is_letter(char) for char in digits) def rejects_underscore(): assert not is_letter("_") def rejects_punctuation(): assert not any(is_letter(char) for char in punctuation) def rejects_non_ascii(): assert not any(is_letter(char) for char in non_ascii) def rejects_empty_string(): assert not is_letter("") def describe_name_start(): def accepts_letters(): assert all(is_name_start(char) for char in letters) def accepts_underscore(): assert is_name_start("_") def rejects_digits(): assert not any(is_name_start(char) for char in digits) def rejects_punctuation(): assert not any(is_name_start(char) for char in punctuation if char != "_") def rejects_non_ascii(): assert not any(is_name_start(char) for char in non_ascii) def rejects_empty_string(): assert not is_name_start("") def describe_name_continue(): def accepts_letters(): assert all(is_name_continue(char) for char in letters) def accepts_digits(): assert all(is_name_continue(char) for char in digits) def accepts_underscore(): assert is_name_continue("_") def rejects_punctuation(): assert not any(is_name_continue(char) for char in punctuation if char != "_") def rejects_non_ascii(): assert not any(is_name_continue(char) for char in non_ascii) def rejects_empty_string(): assert not is_name_continue("") graphql-core-3.2.6/tests/language/test_lexer.py000066400000000000000000000605101474546154300216020ustar00rootroot00000000000000from typing import List, Optional, Tuple from pytest import raises from graphql.error import GraphQLSyntaxError from graphql.language import Lexer, Source, SourceLocation, Token, TokenKind from graphql.language.lexer import is_punctuator_token_kind from graphql.pyutils import inspect from ..utils import dedent Location = Optional[Tuple[int, int]] def lex_one(s: str) -> Token: lexer = Lexer(Source(s)) return lexer.advance() def lex_second(s: str) -> Token: lexer = Lexer(Source(s)) lexer.advance() return lexer.advance() def assert_syntax_error(text: str, message: str, location: Location) -> None: with raises(GraphQLSyntaxError) as exc_info: lex_second(text) error = exc_info.value assert error.message == f"Syntax Error: {message}" assert error.description == message assert error.locations == [location] def describe_lexer(): def ignores_bom_header(): token = lex_one("\uFEFF foo") assert token == Token(TokenKind.NAME, 2, 5, 1, 3, "foo") def tracks_line_breaks(): assert lex_one("foo") == Token(TokenKind.NAME, 0, 3, 1, 1, "foo") assert lex_one("\nfoo") == Token(TokenKind.NAME, 1, 4, 2, 1, "foo") assert lex_one("\rfoo") == Token(TokenKind.NAME, 1, 4, 2, 1, "foo") assert lex_one("\r\nfoo") == Token(TokenKind.NAME, 2, 5, 2, 1, "foo") assert lex_one("\n\rfoo") == Token(TokenKind.NAME, 2, 5, 3, 1, "foo") assert lex_one("\r\r\n\nfoo") == Token(TokenKind.NAME, 4, 7, 4, 1, "foo") assert lex_one("\n\n\r\rfoo") == Token(TokenKind.NAME, 4, 7, 5, 1, "foo") def records_line_and_column(): token = lex_one("\n \r\n \r foo\n") assert token == Token(TokenKind.NAME, 8, 11, 4, 3, "foo") def can_be_stringified_or_pyutils_inspected(): token = lex_one("foo") assert token.desc == "Name 'foo'" assert str(token) == token.desc assert repr(token) == "" assert inspect(token) == repr(token) def skips_whitespace_and_comments(): token = lex_one("\n\n foo\n\n\n") assert token == Token(TokenKind.NAME, 6, 9, 3, 5, "foo") token = lex_one("\r\n\r\n foo\r\n\r\n") assert token == Token(TokenKind.NAME, 6, 9, 3, 3, "foo") token = lex_one("\r\r foo\r\r") assert token == Token(TokenKind.NAME, 4, 7, 3, 3, "foo") token = lex_one("\t\tfoo\t\t") assert token == Token(TokenKind.NAME, 2, 5, 1, 3, "foo") token = lex_one("\n #comment\n foo#comment\n") assert token == Token(TokenKind.NAME, 18, 21, 3, 5, "foo") token = lex_one(",,,foo,,,") assert token == Token(TokenKind.NAME, 3, 6, 1, 4, "foo") def errors_respect_whitespace(): with raises(GraphQLSyntaxError) as exc_info: lex_one("\n\n ~\n") assert str(exc_info.value) == dedent( """ Syntax Error: Unexpected character: '~'. GraphQL request:3:2 2 | 3 | ~ | ^ 4 | """ ) def updates_line_numbers_in_error_for_file_context(): s = "\n\n ~\n\n" source = Source(s, "foo.js", SourceLocation(11, 12)) with raises(GraphQLSyntaxError) as exc_info: Lexer(source).advance() assert str(exc_info.value) == dedent( """ Syntax Error: Unexpected character: '~'. foo.js:13:6 12 | 13 | ~ | ^ 14 | """ ) def updates_column_numbers_in_error_for_file_context(): source = Source("~", "foo.js", SourceLocation(1, 5)) with raises(GraphQLSyntaxError) as exc_info: Lexer(source).advance() assert str(exc_info.value) == dedent( """ Syntax Error: Unexpected character: '~'. foo.js:1:5 1 | ~ | ^ """ ) # noinspection PyArgumentEqualDefault def lexes_empty_string(): token = lex_one('""') assert token == Token(TokenKind.STRING, 0, 2, 1, 1, "") assert token.value == "" # noinspection PyArgumentEqualDefault def lexes_strings(): assert lex_one('""') == Token(TokenKind.STRING, 0, 2, 1, 1, "") assert lex_one('"simple"') == Token(TokenKind.STRING, 0, 8, 1, 1, "simple") assert lex_one('" white space "') == Token( TokenKind.STRING, 0, 15, 1, 1, " white space " ) assert lex_one('"quote \\""') == Token(TokenKind.STRING, 0, 10, 1, 1, 'quote "') assert lex_one('"escaped \\n\\r\\b\\t\\f"') == Token( TokenKind.STRING, 0, 20, 1, 1, "escaped \n\r\b\t\f" ) assert lex_one('"slashes \\\\ \\/"') == Token( TokenKind.STRING, 0, 15, 1, 1, "slashes \\ /" ) assert lex_one('"unescaped surrogate pair \uD83D\uDE00"') == Token( TokenKind.STRING, 0, 29, 1, 1, "unescaped surrogate pair \uD83D\uDE00" ) assert lex_one('"unescaped unicode outside BMP \U0001f600"') == Token( TokenKind.STRING, 0, 33, 1, 1, "unescaped unicode outside BMP \U0001f600" ) assert lex_one('"unescaped maximal unicode outside BMP \U0010ffff"') == Token( TokenKind.STRING, 0, 41, 1, 1, "unescaped maximal unicode outside BMP \U0010ffff", ) assert lex_one('"unicode \\u1234\\u5678\\u90AB\\uCDEF"') == Token( TokenKind.STRING, 0, 34, 1, 1, "unicode \u1234\u5678\u90AB\uCDEF" ) assert lex_one('"unicode \\u{1234}\\u{5678}\\u{90AB}\\u{CDEF}"') == Token( TokenKind.STRING, 0, 42, 1, 1, "unicode \u1234\u5678\u90AB\uCDEF" ) assert lex_one('"string with unicode escape outside BMP \\u{1F600}"') == Token( TokenKind.STRING, 0, 50, 1, 1, "string with unicode escape outside BMP \U0001F600", ) assert lex_one('"string with minimal unicode escape \\u{0}"') == Token( TokenKind.STRING, 0, 42, 1, 1, "string with minimal unicode escape \u0000" ) assert lex_one('"string with maximal unicode escape \\u{10FFFF}"') == Token( TokenKind.STRING, 0, 47, 1, 1, "string with maximal unicode escape \U0010FFFF", ) assert lex_one( '"string with maximal minimal unicode escape \\u{00000000}"' ) == Token( TokenKind.STRING, 0, 57, 1, 1, "string with maximal minimal unicode escape \u0000", ) assert lex_one( '"string with unicode surrogate pair escape \\uD83D\\uDE00"' ) == Token( TokenKind.STRING, 0, 56, 1, 1, "string with unicode surrogate pair escape \U0001f600", ) assert lex_one( '"string with unicode surrogate pair escape \\uD800\\uDC00"' ) == Token( TokenKind.STRING, 0, 56, 1, 1, "string with unicode surrogate pair escape \U00010000", ) assert lex_one( '"string with unicode surrogate pair escape \\uDBFF\\uDFFF"' ) == Token( TokenKind.STRING, 0, 56, 1, 1, "string with unicode surrogate pair escape \U0010FFFF", ) def lex_reports_useful_string_errors(): assert_syntax_error('"', "Unterminated string.", (1, 2)) assert_syntax_error('"""', "Unterminated string.", (1, 4)) assert_syntax_error('""""', "Unterminated string.", (1, 5)) assert_syntax_error('"no end quote', "Unterminated string.", (1, 14)) assert_syntax_error( "'single quotes'", "Unexpected single quote character ('), " 'did you mean to use a double quote (")?', (1, 1), ) assert_syntax_error( '"bad surrogate \uDEAD"', "Invalid character within String: U+DEAD.", (1, 16), ) assert_syntax_error( '"bad high surrogate pair \uDEAD\uDEAD"', "Invalid character within String: U+DEAD.", (1, 26), ) assert_syntax_error( '"bad low surrogate pair \uD800\uD800"', "Invalid character within String: U+D800.", (1, 25), ) assert_syntax_error('"multi\nline"', "Unterminated string.", (1, 7)) assert_syntax_error('"multi\rline"', "Unterminated string.", (1, 7)) assert_syntax_error( '"bad \\z esc"', "Invalid character escape sequence: '\\z'.", (1, 6) ) assert_syntax_error( '"bad \\x esc"', "Invalid character escape sequence: '\\x'.", (1, 6) ) assert_syntax_error( '"bad \\u1 esc"', "Invalid Unicode escape sequence: '\\u1 es'.", (1, 6) ) assert_syntax_error( '"bad \\u0XX1 esc"', "Invalid Unicode escape sequence: '\\u0XX1'.", (1, 6) ) assert_syntax_error( '"bad \\uXXXX esc"', "Invalid Unicode escape sequence: '\\uXXXX'.", (1, 6) ) assert_syntax_error( '"bad \\uFXXX esc"', "Invalid Unicode escape sequence: '\\uFXXX'.", (1, 6) ) assert_syntax_error( '"bad \\uXXXF esc"', "Invalid Unicode escape sequence: '\\uXXXF'.", (1, 6) ) assert_syntax_error( '"bad \\u{} esc"', "Invalid Unicode escape sequence: '\\u{}'.", (1, 6) ) assert_syntax_error( '"bad \\u{FXXX} esc"', "Invalid Unicode escape sequence: '\\u{FX'.", (1, 6) ) assert_syntax_error( '"bad \\u{FFFF esc"', "Invalid Unicode escape sequence: '\\u{FFFF '.", (1, 6), ) assert_syntax_error( '"bad \\u{FFFF"', "Invalid Unicode escape sequence: '\\u{FFFF\"'.", (1, 6) ) assert_syntax_error( '"too high \\u{110000} esc"', "Invalid Unicode escape sequence: '\\u{110000}'.", (1, 11), ) assert_syntax_error( '"way too high \\u{12345678} esc"', "Invalid Unicode escape sequence: '\\u{12345678}'.", (1, 15), ) assert_syntax_error( '"too long \\u{000000000} esc"', "Invalid Unicode escape sequence: '\\u{000000000'.", (1, 11), ) assert_syntax_error( '"bad surrogate \\uDEAD esc"', "Invalid Unicode escape sequence: '\\uDEAD'.", (1, 16), ) assert_syntax_error( '"bad surrogate \\u{DEAD} esc"', "Invalid Unicode escape sequence: '\\u{DEAD}'.", (1, 16), ) assert_syntax_error( '"cannot use braces for surrogate pair \\u{D83D}\\u{DE00} esc"', "Invalid Unicode escape sequence: '\\u{D83D}'.", (1, 39), ) assert_syntax_error( '"bad high surrogate pair \\uDEAD\\uDEAD esc"', "Invalid Unicode escape sequence: '\\uDEAD'.", (1, 26), ) assert_syntax_error( '"bad low surrogate pair \\uD800\\uD800 esc"', "Invalid Unicode escape sequence: '\\uD800'.", (1, 25), ) assert_syntax_error( '"cannot escape half a pair \uD83D\\uDE00 esc"', "Invalid character within String: U+D83D.", (1, 28), ) assert_syntax_error( '"cannot escape half a pair \\uD83D\uDE00 esc"', "Invalid Unicode escape sequence: '\\uD83D'.", (1, 28), ) assert_syntax_error( '"bad \\uD83D\\not an escape"', "Invalid Unicode escape sequence: '\\uD83D'.", (1, 6), ) # noinspection PyArgumentEqualDefault def lexes_block_strings(): assert lex_one('""""""') == Token(TokenKind.BLOCK_STRING, 0, 6, 1, 1, "") assert lex_one('"""simple"""') == Token( TokenKind.BLOCK_STRING, 0, 12, 1, 1, "simple" ) assert lex_one('""" white space """') == Token( TokenKind.BLOCK_STRING, 0, 19, 1, 1, " white space " ) assert lex_one('"""contains " quote"""') == Token( TokenKind.BLOCK_STRING, 0, 22, 1, 1, 'contains " quote' ) assert lex_one('"""contains \\""" triple-quote"""') == Token( TokenKind.BLOCK_STRING, 0, 32, 1, 1, 'contains """ triple-quote' ) assert lex_one('"""multi\nline"""') == Token( TokenKind.BLOCK_STRING, 0, 16, 1, 1, "multi\nline" ) assert lex_one('"""multi\rline\r\nnormalized"""') == Token( TokenKind.BLOCK_STRING, 0, 28, 1, 1, "multi\nline\nnormalized" ) assert lex_one('"""unescaped \\n\\r\\b\\t\\f\\u1234"""') == Token( TokenKind.BLOCK_STRING, 0, 32, 1, 1, "unescaped \\n\\r\\b\\t\\f\\u1234", ) assert lex_one('"""unescaped surrogate pair \uD83D\uDE00"""') == Token( TokenKind.BLOCK_STRING, 0, 33, 1, 1, "unescaped surrogate pair \uD83D\uDE00", ) assert lex_one('"""unescaped unicode outside BMP \U0001f600"""') == Token( TokenKind.BLOCK_STRING, 0, 37, 1, 1, "unescaped unicode outside BMP \U0001f600", ) assert lex_one('"""slashes \\\\ \\/"""') == Token( TokenKind.BLOCK_STRING, 0, 19, 1, 1, "slashes \\\\ \\/" ) assert lex_one( '"""\n\n spans\n multiple\n' ' lines\n\n """' ) == Token(TokenKind.BLOCK_STRING, 0, 68, 1, 1, "spans\n multiple\n lines") def advance_line_after_lexing_multiline_block_string(): assert ( lex_second( '''""" spans multiple lines \n """ second_token''' ) == Token(TokenKind.NAME, 71, 83, 8, 6, "second_token") ) def lex_reports_useful_block_string_errors(): assert_syntax_error('"""', "Unterminated string.", (1, 4)) assert_syntax_error('"""no end quote', "Unterminated string.", (1, 16)) assert_syntax_error( '"""contains invalid surrogate \uDEAD"""', "Invalid character within String: U+DEAD.", (1, 31), ) # noinspection PyArgumentEqualDefault def lexes_numbers(): assert lex_one("0") == Token(TokenKind.INT, 0, 1, 1, 1, "0") assert lex_one("1") == Token(TokenKind.INT, 0, 1, 1, 1, "1") assert lex_one("4") == Token(TokenKind.INT, 0, 1, 1, 1, "4") assert lex_one("9") == Token(TokenKind.INT, 0, 1, 1, 1, "9") assert lex_one("42") == Token(TokenKind.INT, 0, 2, 1, 1, "42") assert lex_one("4.123") == Token(TokenKind.FLOAT, 0, 5, 1, 1, "4.123") assert lex_one("-4") == Token(TokenKind.INT, 0, 2, 1, 1, "-4") assert lex_one("-42") == Token(TokenKind.INT, 0, 3, 1, 1, "-42") assert lex_one("-4.123") == Token(TokenKind.FLOAT, 0, 6, 1, 1, "-4.123") assert lex_one("0.123") == Token(TokenKind.FLOAT, 0, 5, 1, 1, "0.123") assert lex_one("123e4") == Token(TokenKind.FLOAT, 0, 5, 1, 1, "123e4") assert lex_one("123E4") == Token(TokenKind.FLOAT, 0, 5, 1, 1, "123E4") assert lex_one("123e-4") == Token(TokenKind.FLOAT, 0, 6, 1, 1, "123e-4") assert lex_one("123e+4") == Token(TokenKind.FLOAT, 0, 6, 1, 1, "123e+4") assert lex_one("-1.123e4") == Token(TokenKind.FLOAT, 0, 8, 1, 1, "-1.123e4") assert lex_one("-1.123E4") == Token(TokenKind.FLOAT, 0, 8, 1, 1, "-1.123E4") assert lex_one("-1.123e-4") == Token(TokenKind.FLOAT, 0, 9, 1, 1, "-1.123e-4") assert lex_one("-1.123e+4") == Token(TokenKind.FLOAT, 0, 9, 1, 1, "-1.123e+4") assert lex_one("-1.123e4567") == Token( TokenKind.FLOAT, 0, 11, 1, 1, "-1.123e4567" ) def lex_reports_useful_number_errors(): assert_syntax_error( "00", "Invalid number, unexpected digit after 0: '0'.", (1, 2) ) assert_syntax_error( "01", "Invalid number, unexpected digit after 0: '1'.", (1, 2) ) assert_syntax_error( "01.23", "Invalid number, unexpected digit after 0: '1'.", (1, 2) ) assert_syntax_error("+1", "Unexpected character: '+'.", (1, 1)) assert_syntax_error( "1.", "Invalid number, expected digit but got: .", (1, 3) ) assert_syntax_error( "1e", "Invalid number, expected digit but got: .", (1, 3) ) assert_syntax_error( "1E", "Invalid number, expected digit but got: .", (1, 3) ) assert_syntax_error( "1.e1", "Invalid number, expected digit but got: 'e'.", (1, 3) ) assert_syntax_error(".123", "Unexpected character: '.'.", (1, 1)) assert_syntax_error( "1.A", "Invalid number, expected digit but got: 'A'.", (1, 3) ) assert_syntax_error( "-A", "Invalid number, expected digit but got: 'A'.", (1, 2) ) assert_syntax_error( "1.0e", "Invalid number, expected digit but got: .", (1, 5) ) assert_syntax_error( "1.0eA", "Invalid number, expected digit but got: 'A'.", (1, 5) ) assert_syntax_error( '1.0e"', "Invalid number, expected digit but got: '\"'.", (1, 5) ) assert_syntax_error( "1.2e3e", "Invalid number, expected digit but got: 'e'.", (1, 6) ) assert_syntax_error( "1.2e3.4", "Invalid number, expected digit but got: '.'.", (1, 6) ) assert_syntax_error( "1.23.4", "Invalid number, expected digit but got: '.'.", (1, 5) ) def lex_does_not_allow_name_start_after_a_number(): assert_syntax_error( "0xF1", "Invalid number, expected digit but got: 'x'.", (1, 2) ) assert_syntax_error( "0b10", "Invalid number, expected digit but got: 'b'.", (1, 2) ) assert_syntax_error( "123abc", "Invalid number, expected digit but got: 'a'.", (1, 4) ) assert_syntax_error( "1_234", "Invalid number, expected digit but got: '_'.", (1, 2) ) assert_syntax_error("1\xdf", "Unexpected character: U+00DF.", (1, 2)) assert_syntax_error( "1.23f", "Invalid number, expected digit but got: 'f'.", (1, 5) ) assert_syntax_error( "1.234_5", "Invalid number, expected digit but got: '_'.", (1, 6) ) # noinspection PyArgumentEqualDefault def lexes_punctuation(): assert lex_one("!") == Token(TokenKind.BANG, 0, 1, 1, 1, None) assert lex_one("$") == Token(TokenKind.DOLLAR, 0, 1, 1, 1, None) assert lex_one("(") == Token(TokenKind.PAREN_L, 0, 1, 1, 1, None) assert lex_one(")") == Token(TokenKind.PAREN_R, 0, 1, 1, 1, None) assert lex_one("...") == Token(TokenKind.SPREAD, 0, 3, 1, 1, None) assert lex_one(":") == Token(TokenKind.COLON, 0, 1, 1, 1, None) assert lex_one("=") == Token(TokenKind.EQUALS, 0, 1, 1, 1, None) assert lex_one("@") == Token(TokenKind.AT, 0, 1, 1, 1, None) assert lex_one("[") == Token(TokenKind.BRACKET_L, 0, 1, 1, 1, None) assert lex_one("]") == Token(TokenKind.BRACKET_R, 0, 1, 1, 1, None) assert lex_one("{") == Token(TokenKind.BRACE_L, 0, 1, 1, 1, None) assert lex_one("}") == Token(TokenKind.BRACE_R, 0, 1, 1, 1, None) assert lex_one("|") == Token(TokenKind.PIPE, 0, 1, 1, 1, None) def lex_reports_useful_unknown_character_error(): assert_syntax_error("..", "Unexpected character: '.'.", (1, 1)) assert_syntax_error("~", "Unexpected character: '~'.", (1, 1)) assert_syntax_error("\x00", "Unexpected character: U+0000.", (1, 1)) assert_syntax_error("\b", "Unexpected character: U+0008.", (1, 1)) assert_syntax_error("\xAA", "Unexpected character: U+00AA.", (1, 1)) assert_syntax_error("\u0AAA", "Unexpected character: U+0AAA.", (1, 1)) assert_syntax_error("\u203B", "Unexpected character: U+203B.", (1, 1)) assert_syntax_error("\U0001f600", "Unexpected character: U+1F600.", (1, 1)) assert_syntax_error("\uD83D\uDE00", "Unexpected character: U+1F600.", (1, 1)) assert_syntax_error("\uD800\uDC00", "Unexpected character: U+10000.", (1, 1)) assert_syntax_error("\uDBFF\uDFFF", "Unexpected character: U+10FFFF.", (1, 1)) assert_syntax_error("\uD800", "Invalid character: U+D800.", (1, 1)) assert_syntax_error("\uDBFF", "Invalid character: U+DBFF.", (1, 1)) assert_syntax_error("\uDEAD", "Invalid character: U+DEAD.", (1, 1)) # noinspection PyArgumentEqualDefault def lex_reports_useful_information_for_dashes_in_names(): source = Source("a-b") lexer = Lexer(source) first_token = lexer.advance() assert first_token == Token(TokenKind.NAME, 0, 1, 1, 1, "a") with raises(GraphQLSyntaxError) as exc_info: lexer.advance() error = exc_info.value assert error.message == ( "Syntax Error: Invalid number, expected digit but got: 'b'." ) assert error.locations == [(1, 3)] def produces_double_linked_list_of_tokens_including_comments(): source = Source( """ { #comment field } """ ) lexer = Lexer(source) start_token = lexer.token while True: end_token = lexer.advance() if end_token.kind == TokenKind.EOF: break assert end_token.kind != TokenKind.COMMENT assert start_token.prev is None assert end_token.next is None tokens: List[Token] = [] tok: Optional[Token] = start_token while tok: assert not tokens or tok.prev == tokens[-1] tokens.append(tok) tok = tok.next assert [tok.kind for tok in tokens] == [ TokenKind.SOF, TokenKind.BRACE_L, TokenKind.COMMENT, TokenKind.NAME, TokenKind.BRACE_R, TokenKind.EOF, ] def lexes_comments(): assert lex_one("# Comment").prev == Token( TokenKind.COMMENT, 0, 9, 1, 1, " Comment" ) assert lex_one("# Comment\nAnother line").prev == Token( TokenKind.COMMENT, 0, 9, 1, 1, " Comment" ) assert lex_one("# Comment\r\nAnother line").prev == Token( TokenKind.COMMENT, 0, 9, 1, 1, " Comment" ) assert lex_one("# Comment \U0001f600").prev == Token( TokenKind.COMMENT, 0, 11, 1, 1, " Comment \U0001f600" ) assert lex_one("# Comment \uD83D\uDE00").prev == Token( TokenKind.COMMENT, 0, 12, 1, 1, " Comment \uD83D\uDE00" ) assert_syntax_error( "# Invalid surrogate \uDEAD", "Invalid character: U+DEAD.", (1, 21) ) def describe_is_punctuator_token_kind(): def _is_punctuator_token(text: str) -> bool: return is_punctuator_token_kind(lex_one(text).kind) def returns_true_for_punctuator_tokens(): assert _is_punctuator_token("!") is True assert _is_punctuator_token("$") is True assert _is_punctuator_token("&") is True assert _is_punctuator_token("(") is True assert _is_punctuator_token(")") is True assert _is_punctuator_token("...") is True assert _is_punctuator_token(":") is True assert _is_punctuator_token("=") is True assert _is_punctuator_token("@") is True assert _is_punctuator_token("[") is True assert _is_punctuator_token("]") is True assert _is_punctuator_token("{") is True assert _is_punctuator_token("|") is True assert _is_punctuator_token("}") is True def returns_false_for_non_punctuator_tokens(): assert _is_punctuator_token("") is False assert _is_punctuator_token("name") is False assert _is_punctuator_token("1") is False assert _is_punctuator_token("3.14") is False assert _is_punctuator_token('"str"') is False assert _is_punctuator_token('"""str"""') is False graphql-core-3.2.6/tests/language/test_location.py000066400000000000000000000032531474546154300222740ustar00rootroot00000000000000from graphql import SourceLocation def describe_source_location(): def can_be_formatted(): location = SourceLocation(1, 2) assert location.formatted == {"line": 1, "column": 2} def can_compare_with_other_source_location(): location = SourceLocation(1, 2) same_location = SourceLocation(1, 2) assert location == same_location assert not location != same_location different_location = SourceLocation(1, 1) assert not location == different_location assert location != different_location different_location = SourceLocation(2, 2) assert not location == different_location assert location != different_location def can_compare_with_location_tuple(): location = SourceLocation(1, 2) same_location = (1, 2) assert location == same_location assert not location != same_location different_location = (1, 1) assert not location == different_location assert location != different_location different_location = (2, 2) assert not location == different_location assert location != different_location def can_compare_with_formatted_location(): location = SourceLocation(1, 2) same_location = location.formatted assert location == same_location assert not location != same_location different_location = SourceLocation(1, 1).formatted assert not location == different_location assert location != different_location different_location = SourceLocation(2, 2).formatted assert not location == different_location assert location != different_location graphql-core-3.2.6/tests/language/test_parser.py000066400000000000000000000503741474546154300217660ustar00rootroot00000000000000from typing import cast, Optional, Tuple from pytest import raises from graphql.error import GraphQLSyntaxError from graphql.language import ( ArgumentNode, DefinitionNode, DocumentNode, FieldNode, IntValueNode, ListTypeNode, ListValueNode, NameNode, NamedTypeNode, NonNullTypeNode, NullValueNode, ObjectFieldNode, ObjectValueNode, OperationDefinitionNode, OperationType, SelectionSetNode, StringValueNode, ValueNode, VariableNode, Token, TokenKind, parse, parse_type, parse_value, parse_const_value, Source, ) from graphql.pyutils import inspect from ..fixtures import kitchen_sink_query # noqa: F401 from ..utils import dedent Location = Optional[Tuple[int, int]] def assert_syntax_error(text: str, message: str, location: Location) -> None: with raises(GraphQLSyntaxError) as exc_info: parse(text) error = exc_info.value assert error.message == f"Syntax Error: {message}" assert error.description == message assert error.locations == [location] def describe_parser(): def parse_provides_useful_errors(): with raises(GraphQLSyntaxError) as exc_info: parse("{") error = exc_info.value assert error.message == "Syntax Error: Expected Name, found ." assert error.positions == [1] assert error.locations == [(1, 2)] assert str(error) == dedent( """ Syntax Error: Expected Name, found . GraphQL request:1:2 1 | { | ^ """ ) assert_syntax_error( "\n { ...MissingOn }\n fragment MissingOn Type", "Expected 'on', found Name 'Type'.", (3, 26), ) assert_syntax_error("{ field: {} }", "Expected Name, found '{'.", (1, 10)) assert_syntax_error( "notAnOperation Foo { field }", "Unexpected Name 'notAnOperation'.", (1, 1) ) assert_syntax_error("...", "Unexpected '...'.", (1, 1)) assert_syntax_error('{ ""', "Expected Name, found String ''.", (1, 3)) def parse_provides_useful_error_when_using_source(): with raises(GraphQLSyntaxError) as exc_info: parse(Source("query", "MyQuery.graphql")) error = exc_info.value assert str(error) == dedent( """ Syntax Error: Expected '{', found . MyQuery.graphql:1:6 1 | query | ^ """ ) def limits_maximum_number_of_tokens(): assert parse("{ foo }", max_tokens=3) with raises( GraphQLSyntaxError, match="Syntax Error: Document contains more than 2 tokens." " Parsing aborted.", ): assert parse("{ foo }", max_tokens=2) assert parse('{ foo(bar: "baz") }', max_tokens=8) with raises( GraphQLSyntaxError, match="Syntax Error: Document contains more than 7 tokens." " Parsing aborted.", ): assert parse('{ foo(bar: "baz") }', max_tokens=7) def parses_variable_inline_values(): parse("{ field(complex: { a: { b: [ $var ] } }) }") def parses_constant_default_values(): assert_syntax_error( "query Foo($x: Complex = { a: { b: [ $var ] } }) { field }", "Unexpected variable '$var' in constant value.", (1, 37), ) def parses_variable_definition_directives(): parse("query Foo($x: Boolean = false @bar) { field }") def does_not_accept_fragments_named_on(): assert_syntax_error( "fragment on on on { on }", "Unexpected Name 'on'.", (1, 10) ) def does_not_accept_fragments_spread_of_on(): assert_syntax_error("{ ...on }", "Expected Name, found '}'.", (1, 9)) def does_not_allow_true_false_or_null_as_enum_value(): assert_syntax_error( "enum Test { VALID, true }", "Name 'true' is reserved and cannot be used for an enum value.", (1, 20), ) assert_syntax_error( "enum Test { VALID, false }", "Name 'false' is reserved and cannot be used for an enum value.", (1, 20), ) assert_syntax_error( "enum Test { VALID, null }", "Name 'null' is reserved and cannot be used for an enum value.", (1, 20), ) def parses_multi_byte_characters(): # Note: \u0A0A could be naively interpreted as two line-feed chars. doc = parse( """ # This comment has a \u0A0A multi-byte character. { field(arg: "Has a \u0A0A multi-byte character.") } """ ) definitions = doc.definitions assert isinstance(definitions, tuple) assert len(definitions) == 1 selection_set = cast(OperationDefinitionNode, definitions[0]).selection_set selections = selection_set.selections assert isinstance(selections, tuple) assert len(selections) == 1 arguments = cast(FieldNode, selections[0]).arguments assert isinstance(arguments, tuple) assert len(arguments) == 1 value = arguments[0].value assert isinstance(value, StringValueNode) assert value.value == "Has a \u0A0A multi-byte character." # noinspection PyShadowingNames def parses_kitchen_sink(kitchen_sink_query): # noqa: F811 parse(kitchen_sink_query) def allows_non_keywords_anywhere_a_name_is_allowed(): non_keywords = ( "on", "fragment", "query", "mutation", "subscription", "true", "false", ) for keyword in non_keywords: # You can't define or reference a fragment named `on`. fragment_name = "a" if keyword == "on" else keyword document = f""" query {keyword} {{ ... {fragment_name} ... on {keyword} {{ field }} }} fragment {fragment_name} on Type {{ {keyword}({keyword}: ${keyword}) @{keyword}({keyword}: {keyword}) }} """ parse(document) def parses_anonymous_mutation_operations(): parse( """ mutation { mutationField } """ ) def parses_anonymous_subscription_operations(): parse( """ subscription { subscriptionField } """ ) def parses_named_mutation_operations(): parse( """ mutation Foo { mutationField } """ ) def parses_named_subscription_operations(): parse( """ subscription Foo { subscriptionField } """ ) def creates_ast(): doc = parse( dedent( """ { node(id: 4) { id, name } } """ ) ) assert isinstance(doc, DocumentNode) assert doc.loc == (0, 40) definitions = doc.definitions assert isinstance(definitions, tuple) assert len(definitions) == 1 definition = cast(OperationDefinitionNode, definitions[0]) assert isinstance(definition, DefinitionNode) assert definition.loc == (0, 40) assert definition.operation == OperationType.QUERY assert definition.name is None assert definition.variable_definitions == () assert definition.directives == () selection_set: Optional[SelectionSetNode] = definition.selection_set assert isinstance(selection_set, SelectionSetNode) assert selection_set.loc == (0, 40) selections = selection_set.selections assert isinstance(selections, tuple) assert len(selections) == 1 field = selections[0] assert isinstance(field, FieldNode) assert field.loc == (4, 38) assert field.alias is None name = field.name assert isinstance(name, NameNode) assert name.loc == (4, 8) assert name.value == "node" arguments = field.arguments assert isinstance(arguments, tuple) assert len(arguments) == 1 argument = arguments[0] assert isinstance(argument, ArgumentNode) name = argument.name assert isinstance(name, NameNode) assert name.loc == (9, 11) assert name.value == "id" value = argument.value assert isinstance(value, ValueNode) assert isinstance(value, IntValueNode) assert value.loc == (13, 14) assert value.value == "4" assert argument.loc == (9, 14) assert field.directives == () selection_set = field.selection_set assert isinstance(selection_set, SelectionSetNode) selections = selection_set.selections assert isinstance(selections, tuple) assert len(selections) == 2 field = selections[0] assert isinstance(field, FieldNode) assert field.loc == (22, 24) assert field.alias is None name = field.name assert isinstance(name, NameNode) assert name.loc == (22, 24) assert name.value == "id" assert field.arguments == () assert field.directives == () assert field.selection_set is None field = selections[0] assert isinstance(field, FieldNode) assert field.loc == (22, 24) assert field.alias is None name = field.name assert isinstance(name, NameNode) assert name.loc == (22, 24) assert name.value == "id" assert field.arguments == () assert field.directives == () assert field.selection_set is None field = selections[1] assert isinstance(field, FieldNode) assert field.loc == (30, 34) assert field.alias is None name = field.name assert isinstance(name, NameNode) assert name.loc == (30, 34) assert name.value == "name" assert field.arguments == () assert field.directives == () assert field.selection_set is None def creates_ast_from_nameless_query_without_variables(): doc = parse( dedent( """ query { node { id } } """ ) ) assert isinstance(doc, DocumentNode) assert doc.loc == (0, 29) definitions = doc.definitions assert isinstance(definitions, tuple) assert len(definitions) == 1 definition = definitions[0] assert isinstance(definition, OperationDefinitionNode) assert definition.loc == (0, 29) assert definition.operation == OperationType.QUERY assert definition.name is None assert definition.variable_definitions == () assert definition.directives == () selection_set: Optional[SelectionSetNode] = definition.selection_set assert isinstance(selection_set, SelectionSetNode) assert selection_set.loc == (6, 29) selections = selection_set.selections assert isinstance(selections, tuple) assert len(selections) == 1 field = selections[0] assert isinstance(field, FieldNode) assert field.loc == (10, 27) assert field.alias is None name = field.name assert isinstance(name, NameNode) assert name.loc == (10, 14) assert name.value == "node" assert field.arguments == () assert field.directives == () selection_set = field.selection_set assert isinstance(selection_set, SelectionSetNode) assert selection_set.loc == (15, 27) selections = selection_set.selections assert isinstance(selections, tuple) assert len(selections) == 1 field = selections[0] assert isinstance(field, FieldNode) assert field.loc == (21, 23) assert field.alias is None name = field.name assert isinstance(name, NameNode) assert name.loc == (21, 23) assert name.value == "id" assert field.arguments == () assert field.directives == () assert field.selection_set is None def allows_parsing_without_source_location_information(): result = parse("{ id }", no_location=True) assert result.loc is None def legacy_allows_parsing_fragment_defined_variables(): document = "fragment a($v: Boolean = false) on t { f(v: $v) }" parse(document, allow_legacy_fragment_variables=True) with raises(GraphQLSyntaxError): parse(document) def contains_location_information_that_only_stringifies_start_end(): result = parse("{ id }") assert str(result.loc) == "0:6" assert repr(result.loc) == "" assert inspect(result.loc) == repr(result.loc) def contains_references_to_source(): source = Source("{ id }") result = parse(source) assert result.loc and result.loc.source is source def contains_references_to_start_and_end_tokens(): result = parse("{ id }") start_token = result.loc and result.loc.start_token assert isinstance(start_token, Token) assert start_token.kind == TokenKind.SOF end_token = result.loc and result.loc.end_token assert isinstance(end_token, Token) assert end_token.kind == TokenKind.EOF def allows_comments_everywhere_in_the_source(): # make sure first and last line can be comment result = parse( """# top comment { field # field comment } # bottom comment""" ) top_comment = result.loc and result.loc.start_token.next assert top_comment and top_comment.kind is TokenKind.COMMENT assert top_comment.value == " top comment" field_comment = top_comment.next.next.next # type: ignore assert field_comment and field_comment.kind is TokenKind.COMMENT assert field_comment.value == " field comment" bottom_comment = field_comment.next.next # type: ignore assert bottom_comment and bottom_comment.kind is TokenKind.COMMENT assert bottom_comment.value == " bottom comment" def describe_parse_value(): def parses_null_value(): result = parse_value("null") assert isinstance(result, NullValueNode) assert result.loc == (0, 4) def parses_empty_strings(): result = parse_value('""') assert isinstance(result, StringValueNode) assert result.value == "" assert result.loc == (0, 2) def parses_list_values(): result = parse_value('[123 "abc"]') assert isinstance(result, ListValueNode) assert result.loc == (0, 11) values = result.values assert isinstance(values, tuple) assert len(values) == 2 value = values[0] assert isinstance(value, IntValueNode) assert value.loc == (1, 4) assert value.value == "123" value = values[1] assert isinstance(value, StringValueNode) assert value.loc == (5, 10) assert value.value == "abc" def parses_block_strings(): result = parse_value('["""long""" "short"]') assert isinstance(result, ListValueNode) assert result.loc == (0, 20) values = result.values assert isinstance(values, tuple) assert len(values) == 2 value = values[0] assert isinstance(value, StringValueNode) assert value.loc == (1, 11) assert value.value == "long" assert value.block is True value = values[1] assert isinstance(value, StringValueNode) assert value.loc == (12, 19) assert value.value == "short" assert value.block is False def allows_variables(): result = parse_value("{ field: $var }") assert isinstance(result, ObjectValueNode) assert result.loc == (0, 15) fields = result.fields assert len(fields) == 1 field = fields[0] assert isinstance(field, ObjectFieldNode) assert field.loc == (2, 13) name = field.name assert isinstance(name, NameNode) assert name.loc == (2, 7) assert name.value == "field" value = field.value assert isinstance(value, VariableNode) assert value.loc == (9, 13) name = value.name assert isinstance(name, NameNode) assert name.loc == (10, 13) assert name.value == "var" def correct_message_for_incomplete_variable(): with raises(GraphQLSyntaxError) as exc_info: parse_value("$") assert exc_info.value == { "message": "Syntax Error: Expected Name, found .", "locations": [(1, 2)], } def correct_message_for_unexpected_token(): with raises(GraphQLSyntaxError) as exc_info: parse_value(":") assert exc_info.value == { "message": "Syntax Error: Unexpected ':'.", "locations": [(1, 1)], } def describe_parse_const_value(): def parses_values(): result = parse_const_value('[123 "abc"]') assert isinstance(result, ListValueNode) assert result.loc == (0, 11) values = result.values assert len(values) == 2 value = values[0] assert isinstance(value, IntValueNode) assert value.loc == (1, 4) assert value.value == "123" value = values[1] assert isinstance(value, StringValueNode) assert value.loc == (5, 10) assert value.value == "abc" assert value.block is False def does_not_allow_variables(): with raises(GraphQLSyntaxError) as exc_info: parse_const_value("{ field: $var }") assert exc_info.value == { "message": "Syntax Error: Unexpected variable '$var' in constant value.", "locations": [(1, 10)], } def correct_message_for_unexpected_token(): with raises(GraphQLSyntaxError) as exc_info: parse_const_value("$$") assert exc_info.value == { "message": "Syntax Error: Unexpected '$'.", "locations": [(1, 1)], } def describe_parse_type(): def parses_well_known_types(): result = parse_type("String") assert isinstance(result, NamedTypeNode) assert result.loc == (0, 6) name = result.name assert isinstance(name, NameNode) assert name.loc == (0, 6) assert name.value == "String" def parses_custom_types(): result = parse_type("MyType") assert isinstance(result, NamedTypeNode) assert result.loc == (0, 6) name = result.name assert isinstance(name, NameNode) assert name.loc == (0, 6) assert name.value == "MyType" def parses_list_types(): result = parse_type("[MyType]") assert isinstance(result, ListTypeNode) assert result.loc == (0, 8) type_ = result.type assert isinstance(type_, NamedTypeNode) assert type_.loc == (1, 7) name = type_.name assert isinstance(name, NameNode) assert name.loc == (1, 7) assert name.value == "MyType" def parses_non_null_types(): result = parse_type("MyType!") assert isinstance(result, NonNullTypeNode) assert result.loc == (0, 7) type_ = result.type assert isinstance(type_, NamedTypeNode) assert type_.loc == (0, 6) name = type_.name assert isinstance(name, NameNode) assert name.loc == (0, 6) assert name.value == "MyType" def parses_nested_types(): result = parse_type("[MyType!]") assert isinstance(result, ListTypeNode) assert result.loc == (0, 9) type_ = result.type assert isinstance(type_, NonNullTypeNode) assert type_.loc == (1, 8) type_ = type_.type assert isinstance(type_, NamedTypeNode) assert type_.loc == (1, 7) name = type_.name assert isinstance(name, NameNode) assert name.loc == (1, 7) assert name.value == "MyType" graphql-core-3.2.6/tests/language/test_predicates.py000066400000000000000000000117701474546154300226120ustar00rootroot00000000000000from operator import attrgetter from typing import Callable from graphql.language import ( ast, Node, parse_value, is_definition_node, is_executable_definition_node, is_selection_node, is_value_node, is_const_value_node, is_type_node, is_type_system_definition_node, is_type_definition_node, is_type_system_extension_node, is_type_extension_node, ) all_ast_nodes = sorted( [ node_type() for node_type in vars(ast).values() if type(node_type) is type and issubclass(node_type, Node) and not node_type.__name__.startswith("Const") ], key=attrgetter("kind"), ) def filter_nodes(predicate: Callable[[Node], bool]): return [node.kind for node in all_ast_nodes if predicate(node)] def describe_ast_node_predicates(): def check_definition_node(): assert filter_nodes(is_definition_node) == [ "definition", "directive_definition", "enum_type_definition", "enum_type_extension", "enum_value_definition", "executable_definition", "field_definition", "fragment_definition", "input_object_type_definition", "input_object_type_extension", "input_value_definition", "interface_type_definition", "interface_type_extension", "object_type_definition", "object_type_extension", "operation_definition", "scalar_type_definition", "scalar_type_extension", "schema_definition", "type_definition", "type_extension", "type_system_definition", "union_type_definition", "union_type_extension", ] def check_executable_definition_node(): assert filter_nodes(is_executable_definition_node) == [ "executable_definition", "fragment_definition", "operation_definition", ] def check_selection_node(): assert filter_nodes(is_selection_node) == [ "field", "fragment_spread", "inline_fragment", "selection", ] def check_value_node(): assert filter_nodes(is_value_node) == [ "boolean_value", "enum_value", "float_value", "int_value", "list_value", "null_value", "object_value", "string_value", "value", "variable", ] def check_const_value_node(): assert is_const_value_node(parse_value('"value"')) is True assert is_const_value_node(parse_value("$var")) is False assert is_const_value_node(parse_value('{ field: "value" }')) is True assert is_const_value_node(parse_value("{ field: $var }")) is False assert is_const_value_node(parse_value('[ "value" ]')) is True assert is_const_value_node(parse_value("[ $var ]")) is False def check_type_node(): assert filter_nodes(is_type_node) == [ "list_type", "named_type", "non_null_type", "type", ] def check_type_system_definition_node(): assert filter_nodes(is_type_system_definition_node) == [ "directive_definition", "enum_type_definition", "enum_type_extension", "input_object_type_definition", "input_object_type_extension", "interface_type_definition", "interface_type_extension", "object_type_definition", "object_type_extension", "scalar_type_definition", "scalar_type_extension", "schema_definition", "type_definition", "type_extension", "type_system_definition", "union_type_definition", "union_type_extension", ] def check_type_definition_node(): assert filter_nodes(is_type_definition_node) == [ "enum_type_definition", "input_object_type_definition", "interface_type_definition", "object_type_definition", "scalar_type_definition", "type_definition", "union_type_definition", ] def check_type_system_extension_node(): assert filter_nodes(is_type_system_extension_node) == [ "enum_type_extension", "input_object_type_extension", "interface_type_extension", "object_type_extension", "scalar_type_extension", "schema_extension", "type_extension", "union_type_extension", ] def check_type_extension_node(): assert filter_nodes(is_type_extension_node) == [ "enum_type_extension", "input_object_type_extension", "interface_type_extension", "object_type_extension", "scalar_type_extension", "type_extension", "union_type_extension", ] graphql-core-3.2.6/tests/language/test_print_string.py000066400000000000000000000046051474546154300232100ustar00rootroot00000000000000from graphql.language.print_string import print_string def describe_print_string(): def prints_a_simple_string(): assert print_string("hello world") == '"hello world"' def escapes_quotes(): assert print_string('"hello world"') == '"\\"hello world\\""' def escapes_backslashes(): assert print_string("escape: \\") == '"escape: \\\\"' def escapes_well_known_control_chars(): assert print_string("\b\f\n\r\t") == '"\\b\\f\\n\\r\\t"' def escapes_zero_byte(): assert print_string("\x00") == '"\\u0000"' def does_not_escape_space(): assert print_string(" ") == '" "' def does_not_escape_non_ascii_character(): assert print_string("\u21BB") == '"\u21BB"' def does_not_escape_supplementary_character(): assert print_string("\U0001f600") == '"\U0001f600"' def escapes_all_control_chars(): assert print_string( "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F" "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F" "\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2A\x2B\x2C\x2D\x2E\x2F" "\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3A\x3B\x3C\x3D\x3E\x3F" "\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4A\x4B\x4C\x4D\x4E\x4F" "\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5A\x5B\x5C\x5D\x5E\x5F" "\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6A\x6B\x6C\x6D\x6E\x6F" "\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7A\x7B\x7C\x7D\x7E\x7F" "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8A\x8B\x8C\x8D\x8E\x8F" "\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9A\x9B\x9C\x9D\x9E\x9F" ) == ( '"\\u0000\\u0001\\u0002\\u0003\\u0004\\u0005\\u0006\\u0007' "\\b\\t\\n\\u000B\\f\\r\\u000E\\u000F" "\\u0010\\u0011\\u0012\\u0013\\u0014\\u0015\\u0016\\u0017" "\\u0018\\u0019\\u001A\\u001B\\u001C\\u001D\\u001E\\u001F" " !\\\"#$%&'()*+,-./0123456789:;<=>?" "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\\\]^_" "`abcdefghijklmnopqrstuvwxyz{|}~\\u007F" "\\u0080\\u0081\\u0082\\u0083\\u0084\\u0085\\u0086\\u0087" "\\u0088\\u0089\\u008A\\u008B\\u008C\\u008D\\u008E\\u008F" "\\u0090\\u0091\\u0092\\u0093\\u0094\\u0095\\u0096\\u0097" '\\u0098\\u0099\\u009A\\u009B\\u009C\\u009D\\u009E\\u009F"' ) graphql-core-3.2.6/tests/language/test_printer.py000066400000000000000000000143731474546154300221540ustar00rootroot00000000000000from copy import deepcopy from pytest import raises from graphql.language import FieldNode, NameNode, parse, print_ast from ..fixtures import kitchen_sink_query # noqa: F401 from ..utils import dedent def describe_printer_query_document(): def prints_minimal_ast(): ast = FieldNode(name=NameNode(value="foo")) assert print_ast(ast) == "foo" def produces_helpful_error_messages(): bad_ast = {"random": "Data"} with raises(TypeError) as exc_info: # noinspection PyTypeChecker print_ast(bad_ast) # type: ignore assert str(exc_info.value) == "Not an AST Node: {'random': 'Data'}." corrupt_ast = FieldNode(name="random data") with raises(TypeError) as exc_info: print_ast(corrupt_ast) assert str(exc_info.value) == "Invalid AST Node: 'random data'." def correctly_prints_query_operation_without_name(): query_ast_shorthanded = parse("query { id, name }") assert print_ast(query_ast_shorthanded) == "{\n id\n name\n}" def correctly_prints_mutation_operation_without_name(): mutation_ast = parse("mutation { id, name }") assert print_ast(mutation_ast) == "mutation {\n id\n name\n}" def correctly_prints_query_operation_with_artifacts(): query_ast_with_artifacts = parse( "query ($foo: TestType) @testDirective { id, name }" ) assert print_ast(query_ast_with_artifacts) == dedent( """ query ($foo: TestType) @testDirective { id name } """ ) def correctly_prints_mutation_operation_with_artifacts(): mutation_ast_with_artifacts = parse( "mutation ($foo: TestType) @testDirective { id, name }" ) assert print_ast(mutation_ast_with_artifacts) == dedent( """ mutation ($foo: TestType) @testDirective { id name } """ ) def prints_query_with_variable_directives(): query_ast_with_variable_directive = parse( "query ($foo: TestType = {a: 123}" " @testDirective(if: true) @test) { id }" ) assert print_ast(query_ast_with_variable_directive) == dedent( """ query ($foo: TestType = {a: 123} @testDirective(if: true) @test) { id } """ ) def keeps_arguments_on_one_line_if_line_has_80_chars_or_less(): printed = print_ast(parse("{trip(wheelchair:false arriveBy:false){dateTime}}")) assert printed == dedent( """ { trip(wheelchair: false, arriveBy: false) { dateTime } } """ ) def puts_arguments_on_multiple_lines_if_line_has_more_than_80_chars(): printed = print_ast( parse( "{trip(wheelchair:false arriveBy:false includePlannedCancellations:true" " transitDistanceReluctance:2000){dateTime}}" ) ) assert printed == dedent( """ { trip( wheelchair: false arriveBy: false includePlannedCancellations: true transitDistanceReluctance: 2000 ) { dateTime } } """ ) def legacy_prints_fragment_with_variable_directives(): query_ast_with_variable_directive = parse( "fragment Foo($foo: TestType @test) on TestType @testDirective { id }", allow_legacy_fragment_variables=True, ) assert print_ast(query_ast_with_variable_directive) == dedent( """ fragment Foo($foo: TestType @test) on TestType @testDirective { id } """ ) def legacy_correctly_prints_fragment_defined_variables(): source = """ fragment Foo($a: ComplexType, $b: Boolean = false) on TestType { id } """ fragment_with_variable = parse(source, allow_legacy_fragment_variables=True) assert print_ast(fragment_with_variable) == dedent(source) def prints_kitchen_sink_without_altering_ast(kitchen_sink_query): # noqa: F811 ast = parse(kitchen_sink_query, no_location=True) ast_before_print_call = deepcopy(ast) printed = print_ast(ast) printed_ast = parse(printed, no_location=True) assert printed_ast == ast assert deepcopy(ast) == ast_before_print_call assert printed == dedent( r''' query queryName($foo: ComplexType, $site: Site = MOBILE) @onQuery { whoever123is: node(id: [123, 456]) { id ... on User @onInlineFragment { field2 { id alias: field1(first: 10, after: $foo) @include(if: $foo) { id ...frag @onFragmentSpread } } } ... @skip(unless: $foo) { id } ... { id } } } mutation likeStory @onMutation { like(story: 123) @onField { story { id @onField } } } subscription StoryLikeSubscription($input: StoryLikeSubscribeInput @onVariableDefinition) @onSubscription { storyLikeSubscribe(input: $input) { story { likers { count } likeSentence { text } } } } fragment frag on Friend @onFragmentDefinition { foo( size: $size bar: $b obj: {key: "value", block: """ block string uses \""" """} ) } { unnamed(truthy: true, falsy: false, nullish: null) query } { __typename } ''' # noqa: E501 ) graphql-core-3.2.6/tests/language/test_schema_parser.py000066400000000000000000000710631474546154300233040ustar00rootroot00000000000000from textwrap import dedent from typing import List, Optional, Tuple from pytest import raises from graphql.error import GraphQLSyntaxError from graphql.language import ( ArgumentNode, BooleanValueNode, DirectiveDefinitionNode, DirectiveNode, DocumentNode, EnumTypeDefinitionNode, EnumValueDefinitionNode, FieldDefinitionNode, InputObjectTypeDefinitionNode, InputValueDefinitionNode, InterfaceTypeDefinitionNode, InterfaceTypeExtensionNode, ListTypeNode, NameNode, NamedTypeNode, NonNullTypeNode, ObjectTypeDefinitionNode, ObjectTypeExtensionNode, OperationType, OperationTypeDefinitionNode, ScalarTypeDefinitionNode, SchemaDefinitionNode, SchemaExtensionNode, StringValueNode, TypeNode, UnionTypeDefinitionNode, ValueNode, parse, ) from ..fixtures import kitchen_sink_sdl # noqa: F401 Location = Optional[Tuple[int, int]] def assert_syntax_error(text: str, message: str, location: Location) -> None: with raises(GraphQLSyntaxError) as exc_info: parse(text) error = exc_info.value assert error.message == f"Syntax Error: {message}" assert error.description == message assert error.locations == [location] def assert_definitions(body: str, loc: Location, num=1): doc = parse(body) assert isinstance(doc, DocumentNode) assert doc.loc == loc definitions = doc.definitions assert isinstance(definitions, tuple) assert len(definitions) == num return definitions[0] if num == 1 else definitions def type_node(name: str, loc: Location): return NamedTypeNode(name=name_node(name, loc), loc=loc) def name_node(name: str, loc: Location): return NameNode(value=name, loc=loc) def field_node(name: NameNode, type_: TypeNode, loc: Location): return field_node_with_args(name, type_, [], loc) def field_node_with_args(name: NameNode, type_: TypeNode, args: List, loc: Location): return FieldDefinitionNode( name=name, arguments=args, type=type_, directives=[], loc=loc, description=None ) def non_null_type(type_: TypeNode, loc: Location): return NonNullTypeNode(type=type_, loc=loc) def enum_value_node(name: str, loc: Location): return EnumValueDefinitionNode( name=name_node(name, loc), directives=[], loc=loc, description=None ) def input_value_node( name: NameNode, type_: TypeNode, default_value: Optional[ValueNode], loc: Location ): return InputValueDefinitionNode( name=name, type=type_, default_value=default_value, directives=[], loc=loc, description=None, ) def boolean_value_node(value: bool, loc: Location): return BooleanValueNode(value=value, loc=loc) def string_value_node(value: str, block: Optional[bool], loc: Location): return StringValueNode(value=value, block=block, loc=loc) def list_type_node(type_: TypeNode, loc: Location): return ListTypeNode(type=type_, loc=loc) def schema_extension_node( directives: List[DirectiveNode], operation_types: List[OperationTypeDefinitionNode], loc: Location, ): return SchemaExtensionNode( directives=directives, operation_types=operation_types, loc=loc ) def operation_type_definition(operation: OperationType, type_: TypeNode, loc: Location): return OperationTypeDefinitionNode(operation=operation, type=type_, loc=loc) def directive_node(name: NameNode, arguments: List[ArgumentNode], loc: Location): return DirectiveNode(name=name, arguments=arguments, loc=loc) def describe_schema_parser(): def simple_type(): body = dedent( """ type Hello { world: String } """ ) definition = assert_definitions(body, (0, 32)) assert isinstance(definition, ObjectTypeDefinitionNode) assert definition.name == name_node("Hello", (6, 11)) assert definition.description is None assert definition.interfaces == () assert definition.directives == () assert definition.fields == ( field_node( name_node("world", (16, 21)), type_node("String", (23, 29)), (16, 29) ), ) assert definition.loc == (1, 31) def parses_type_with_description_string(): body = dedent( """ "Description" type Hello { world: String } """ ) definition = assert_definitions(body, (0, 46)) assert isinstance(definition, ObjectTypeDefinitionNode) assert definition.name == name_node("Hello", (20, 25)) description = definition.description assert description == string_value_node("Description", False, (1, 14)) def parses_type_with_description_multi_line_string(): body = dedent( ''' """ Description """ # Even with comments between them type Hello { world: String }''' ) definition = assert_definitions(body, (0, 85)) assert isinstance(definition, ObjectTypeDefinitionNode) assert definition.name == name_node("Hello", (60, 65)) description = definition.description assert description == string_value_node("Description", True, (1, 20)) def parses_schema_with_description_string(): body = dedent( """ "Description" schema { query: Foo } """ ) definition = assert_definitions(body, (0, 39)) assert isinstance(definition, SchemaDefinitionNode) description = definition.description assert description == string_value_node("Description", False, (1, 14)) def description_followed_by_something_other_than_type_system_definition_throws(): assert_syntax_error('"Description" 1', "Unexpected Int '1'.", (1, 15)) def simple_extension(): body = dedent( """ extend type Hello { world: String } """ ) extension = assert_definitions(body, (0, 39)) assert isinstance(extension, ObjectTypeExtensionNode) assert extension.name == name_node("Hello", (13, 18)) assert extension.interfaces == () assert extension.directives == () assert extension.fields == ( field_node( name_node("world", (23, 28)), type_node("String", (30, 36)), (23, 36) ), ) assert extension.loc == (1, 38) def object_extension_without_fields(): body = "extend type Hello implements Greeting" extension = assert_definitions(body, (0, 37)) assert isinstance(extension, ObjectTypeExtensionNode) assert extension.name == name_node("Hello", (12, 17)) assert extension.interfaces == (type_node("Greeting", (29, 37)),) assert extension.directives == () assert extension.fields == () assert extension.loc == (0, 37) def interface_extension_without_fields(): body = "extend interface Hello implements Greeting" extension = assert_definitions(body, (0, 42)) assert isinstance(extension, InterfaceTypeExtensionNode) assert extension.name == name_node("Hello", (17, 22)) assert extension.interfaces == (type_node("Greeting", (34, 42)),) assert extension.directives == () assert extension.fields == () assert extension.loc == (0, 42) def object_extension_without_fields_followed_by_extension(): body = ( "\n extend type Hello implements Greeting\n\n" " extend type Hello implements SecondGreeting\n " ) extensions = assert_definitions(body, (0, 100), 2) extension = extensions[0] assert isinstance(extension, ObjectTypeExtensionNode) assert extension.name == name_node("Hello", (19, 24)) assert extension.interfaces == (type_node("Greeting", (36, 44)),) assert extension.directives == () assert extension.fields == () assert extension.loc == (7, 44) extension = extensions[1] assert isinstance(extension, ObjectTypeExtensionNode) assert extension.name == name_node("Hello", (64, 69)) assert extension.interfaces == (type_node("SecondGreeting", (81, 95)),) assert extension.directives == () assert extension.fields == () assert extension.loc == (52, 95) def extension_without_anything_throws(): assert_syntax_error("extend scalar Hello", "Unexpected .", (1, 20)) assert_syntax_error("extend type Hello", "Unexpected .", (1, 18)) assert_syntax_error("extend interface Hello", "Unexpected .", (1, 23)) assert_syntax_error("extend union Hello", "Unexpected .", (1, 19)) assert_syntax_error("extend enum Hello", "Unexpected .", (1, 18)) assert_syntax_error("extend input Hello", "Unexpected .", (1, 19)) def interface_extension_without_fields_followed_by_extension(): body = ( "\n extend interface Hello implements Greeting\n\n" " extend interface Hello implements SecondGreeting\n " ) extensions = assert_definitions(body, (0, 110), 2) extension = extensions[0] assert isinstance(extension, InterfaceTypeExtensionNode) assert extension.name == name_node("Hello", (24, 29)) assert extension.interfaces == (type_node("Greeting", (41, 49)),) assert extension.directives == () assert extension.fields == () assert extension.loc == (7, 49) extension = extensions[1] assert isinstance(extension, InterfaceTypeExtensionNode) assert extension.name == name_node("Hello", (74, 79)) assert extension.interfaces == (type_node("SecondGreeting", (91, 105)),) assert extension.directives == () assert extension.fields == () assert extension.loc == (57, 105) def object_extension_do_not_include_descriptions(): assert_syntax_error( """ "Description" extend type Hello { world: String }""", "Unexpected description," " descriptions are supported only on type definitions.", (2, 13), ) assert_syntax_error( """ extend "Description" type Hello { world: String }""", "Unexpected String 'Description'.", (2, 20), ) def interface_extension_do_not_include_descriptions(): assert_syntax_error( """ "Description" extend interface Hello { world: String }""", "Unexpected description," " descriptions are supported only on type definitions.", (2, 13), ) assert_syntax_error( """ extend "Description" interface Hello { world: String }""", "Unexpected String 'Description'.", (2, 20), ) def schema_extension(): body = """ extend schema { mutation: Mutation }""" doc = parse(body) assert isinstance(doc, DocumentNode) assert doc.loc == (0, 75) assert doc.definitions == ( schema_extension_node( [], [ operation_type_definition( OperationType.MUTATION, type_node("Mutation", (53, 61)), (43, 61), ) ], (13, 75), ), ) def schema_extension_with_only_directives(): body = "extend schema @directive" doc = parse(body) assert isinstance(doc, DocumentNode) assert doc.loc == (0, 24) assert doc.definitions == ( schema_extension_node( [directive_node(name_node("directive", (15, 24)), [], (14, 24))], [], (0, 24), ), ) def schema_extension_without_anything_throws(): assert_syntax_error("extend schema", "Unexpected .", (1, 14)) def schema_extension_with_invalid_operation_type_throws(): assert_syntax_error( "extend schema { unknown: SomeType }", "Unexpected Name 'unknown'.", (1, 17) ) def simple_non_null_type(): body = dedent( """ type Hello { world: String! } """ ) definition = assert_definitions(body, (0, 33)) assert isinstance(definition, ObjectTypeDefinitionNode) assert definition.name == name_node("Hello", (6, 11)) assert definition.description is None assert definition.interfaces == () assert definition.directives == () assert definition.fields == ( field_node( name_node("world", (16, 21)), non_null_type(type_node("String", (23, 29)), (23, 30)), (16, 30), ), ) assert definition.loc == (1, 32) def simple_interface_inheriting_interface(): body = "interface Hello implements World { field: String }" definition = assert_definitions(body, (0, 50)) assert isinstance(definition, InterfaceTypeDefinitionNode) assert definition.name == name_node("Hello", (10, 15)) assert definition.description is None assert definition.interfaces == (type_node("World", (27, 32)),) assert definition.directives == () assert definition.fields == ( field_node( name_node("field", (35, 40)), type_node("String", (42, 48)), (35, 48) ), ) assert definition.loc == (0, 50) def simple_type_inheriting_interface(): body = "type Hello implements World { field: String }" definition = assert_definitions(body, (0, 45)) assert isinstance(definition, ObjectTypeDefinitionNode) assert definition.name == name_node("Hello", (5, 10)) assert definition.description is None assert definition.interfaces == (type_node("World", (22, 27)),) assert definition.directives == () assert definition.fields == ( field_node( name_node("field", (30, 35)), type_node("String", (37, 43)), (30, 43) ), ) assert definition.loc == (0, 45) def simple_type_inheriting_multiple_interfaces(): body = "type Hello implements Wo & rld { field: String }" definition = assert_definitions(body, (0, 48)) assert isinstance(definition, ObjectTypeDefinitionNode) assert definition.name == name_node("Hello", (5, 10)) assert definition.description is None assert definition.interfaces == ( type_node("Wo", (22, 24)), type_node("rld", (27, 30)), ) assert definition.directives == () assert definition.fields == ( field_node( name_node("field", (33, 38)), type_node("String", (40, 46)), (33, 46) ), ) assert definition.loc == (0, 48) def simple_interface_inheriting_multiple_interfaces(): body = "interface Hello implements Wo & rld { field: String }" definition = assert_definitions(body, (0, 53)) assert isinstance(definition, InterfaceTypeDefinitionNode) assert definition.name == name_node("Hello", (10, 15)) assert definition.description is None assert definition.interfaces == ( type_node("Wo", (27, 29)), type_node("rld", (32, 35)), ) assert definition.directives == () assert definition.fields == ( field_node( name_node("field", (38, 43)), type_node("String", (45, 51)), (38, 51) ), ) assert definition.loc == (0, 53) def simple_type_inheriting_multiple_interfaces_with_leading_ampersand(): body = "type Hello implements & Wo & rld { field: String }" definition = assert_definitions(body, (0, 50)) assert isinstance(definition, ObjectTypeDefinitionNode) assert definition.name == name_node("Hello", (5, 10)) assert definition.description is None assert definition.interfaces == ( type_node("Wo", (24, 26)), type_node("rld", (29, 32)), ) assert definition.directives == () assert definition.fields == ( field_node( name_node("field", (35, 40)), type_node("String", (42, 48)), (35, 48) ), ) assert definition.loc == (0, 50) def simple_interface_inheriting_multiple_interfaces_with_leading_ampersand(): body = "interface Hello implements & Wo & rld { field: String }" definition = assert_definitions(body, (0, 55)) assert isinstance(definition, InterfaceTypeDefinitionNode) assert definition.name == name_node("Hello", (10, 15)) assert definition.description is None assert definition.interfaces == ( type_node("Wo", (29, 31)), type_node("rld", (34, 37)), ) assert definition.directives == () assert definition.fields == ( field_node( name_node("field", (40, 45)), type_node("String", (47, 53)), (40, 53) ), ) assert definition.loc == (0, 55) def single_value_enum(): body = "enum Hello { WORLD }" definition = assert_definitions(body, (0, 20)) assert isinstance(definition, EnumTypeDefinitionNode) assert definition.name == name_node("Hello", (5, 10)) assert definition.description is None assert definition.directives == () assert definition.values == (enum_value_node("WORLD", (13, 18)),) assert definition.loc == (0, 20) def double_value_enum(): body = "enum Hello { WO, RLD }" definition = assert_definitions(body, (0, 22)) assert isinstance(definition, EnumTypeDefinitionNode) assert definition.name == name_node("Hello", (5, 10)) assert definition.description is None assert definition.directives == () assert definition.values == ( enum_value_node("WO", (13, 15)), enum_value_node("RLD", (17, 20)), ) assert definition.loc == (0, 22) def simple_interface(): body = dedent( """ interface Hello { world: String } """ ) definition = assert_definitions(body, (0, 37)) assert isinstance(definition, InterfaceTypeDefinitionNode) assert definition.name == name_node("Hello", (11, 16)) assert definition.description is None assert definition.interfaces == () assert definition.directives == () assert definition.fields == ( field_node( name_node("world", (21, 26)), type_node("String", (28, 34)), (21, 34) ), ) assert definition.loc == (1, 36) def simple_field_with_arg(): body = dedent( """ type Hello { world(flag: Boolean): String } """ ) definition = assert_definitions(body, (0, 47)) assert isinstance(definition, ObjectTypeDefinitionNode) assert definition.name == name_node("Hello", (6, 11)) assert definition.description is None assert definition.interfaces == () assert definition.directives == () assert definition.fields == ( field_node_with_args( name_node("world", (16, 21)), type_node("String", (38, 44)), [ input_value_node( name_node("flag", (22, 26)), type_node("Boolean", (28, 35)), None, (22, 35), ) ], (16, 44), ), ) assert definition.loc == (1, 46) def simple_field_with_arg_with_default_value(): body = dedent( """ type Hello { world(flag: Boolean = true): String } """ ) definition = assert_definitions(body, (0, 54)) assert isinstance(definition, ObjectTypeDefinitionNode) assert definition.name == name_node("Hello", (6, 11)) assert definition.description is None assert definition.interfaces == () assert definition.directives == () assert definition.fields == ( field_node_with_args( name_node("world", (16, 21)), type_node("String", (45, 51)), [ input_value_node( name_node("flag", (22, 26)), type_node("Boolean", (28, 35)), boolean_value_node(True, (38, 42)), (22, 42), ) ], (16, 51), ), ) assert definition.loc == (1, 53) def simple_field_with_list_arg(): body = dedent( """ type Hello { world(things: [String]): String } """ ) definition = assert_definitions(body, (0, 50)) assert isinstance(definition, ObjectTypeDefinitionNode) assert definition.name == name_node("Hello", (6, 11)) assert definition.description is None assert definition.interfaces == () assert definition.directives == () assert definition.fields == ( field_node_with_args( name_node("world", (16, 21)), type_node("String", (41, 47)), [ input_value_node( name_node("things", (22, 28)), list_type_node(type_node("String", (31, 37)), (30, 38)), None, (22, 38), ) ], (16, 47), ), ) assert definition.loc == (1, 49) def simple_field_with_two_args(): body = dedent( """ type Hello { world(argOne: Boolean, argTwo: Int): String } """ ) definition = assert_definitions(body, (0, 62)) assert isinstance(definition, ObjectTypeDefinitionNode) assert definition.name == name_node("Hello", (6, 11)) assert definition.description is None assert definition.interfaces == () assert definition.directives == () assert definition.fields == ( field_node_with_args( name_node("world", (16, 21)), type_node("String", (53, 59)), [ input_value_node( name_node("argOne", (22, 28)), type_node("Boolean", (30, 37)), None, (22, 37), ), input_value_node( name_node("argTwo", (39, 45)), type_node("Int", (47, 50)), None, (39, 50), ), ], (16, 59), ), ) assert definition.loc == (1, 61) def simple_union(): body = "union Hello = World" definition = assert_definitions(body, (0, 19)) assert isinstance(definition, UnionTypeDefinitionNode) assert definition.name == name_node("Hello", (6, 11)) assert definition.description is None assert definition.directives == () assert definition.types == (type_node("World", (14, 19)),) assert definition.loc == (0, 19) def union_with_two_types(): body = "union Hello = Wo | Rld" definition = assert_definitions(body, (0, 22)) assert isinstance(definition, UnionTypeDefinitionNode) assert definition.name == name_node("Hello", (6, 11)) assert definition.description is None assert definition.directives == () assert definition.types == ( type_node("Wo", (14, 16)), type_node("Rld", (19, 22)), ) assert definition.loc == (0, 22) def union_with_two_types_and_leading_pipe(): body = "union Hello = | Wo | Rld" definition = assert_definitions(body, (0, 24)) assert isinstance(definition, UnionTypeDefinitionNode) assert definition.name == name_node("Hello", (6, 11)) assert definition.directives == () assert definition.types == ( type_node("Wo", (16, 18)), type_node("Rld", (21, 24)), ) assert definition.loc == (0, 24) def union_fails_with_no_types(): assert_syntax_error("union Hello = |", "Expected Name, found .", (1, 16)) def union_fails_with_leading_double_pipe(): assert_syntax_error( "union Hello = || Wo | Rld", "Expected Name, found '|'.", (1, 16) ) def union_fails_with_double_pipe(): assert_syntax_error( "union Hello = Wo || Rld", "Expected Name, found '|'.", (1, 19) ) def union_fails_with_trailing_pipe(): assert_syntax_error( "union Hello = | Wo | Rld |", "Expected Name, found .", (1, 27) ) def scalar(): body = "scalar Hello" definition = assert_definitions(body, (0, 12)) assert isinstance(definition, ScalarTypeDefinitionNode) assert definition.name == name_node("Hello", (7, 12)) assert definition.description is None assert definition.directives == () assert definition.loc == (0, 12) def simple_input_object(): body = "\ninput Hello {\n world: String\n}" definition = assert_definitions(body, (0, 32)) assert isinstance(definition, InputObjectTypeDefinitionNode) assert definition.name == name_node("Hello", (7, 12)) assert definition.description is None assert definition.directives == () assert definition.fields == ( input_value_node( name_node("world", (17, 22)), type_node("String", (24, 30)), None, (17, 30), ), ) assert definition.loc == (1, 32) def simple_input_object_with_args_should_fail(): assert_syntax_error( "\ninput Hello {\n world(foo : Int): String\n}", "Expected ':', found '('.", (3, 8), ) def directive_definition(): body = "directive @foo on OBJECT | INTERFACE" definition = assert_definitions(body, (0, 36)) assert isinstance(definition, DirectiveDefinitionNode) assert definition.name == name_node("foo", (11, 14)) assert definition.description is None assert definition.arguments == () assert definition.repeatable is False assert definition.locations == ( name_node("OBJECT", (18, 24)), name_node("INTERFACE", (27, 36)), ) def repeatable_directive_definition(): body = "directive @foo repeatable on OBJECT | INTERFACE" definition = assert_definitions(body, (0, 47)) assert isinstance(definition, DirectiveDefinitionNode) assert definition.name == name_node("foo", (11, 14)) assert definition.description is None assert definition.arguments == () assert definition.repeatable is True assert definition.locations == ( name_node("OBJECT", (29, 35)), name_node("INTERFACE", (38, 47)), ) def directive_with_incorrect_locations(): assert_syntax_error( "\ndirective @foo on FIELD | INCORRECT_LOCATION", "Unexpected Name 'INCORRECT_LOCATION'.", (2, 27), ) def parses_kitchen_sink_schema(kitchen_sink_sdl): # noqa: F811 assert parse(kitchen_sink_sdl) def can_pickle_and_unpickle_kitchen_sink_schema_ast(kitchen_sink_sdl): # noqa: F811 import pickle # create a schema AST from the kitchen sink SDL doc = parse(kitchen_sink_sdl) # check that the schema AST can be pickled # (particularly, there should be no recursion error) dumped = pickle.dumps(doc) # check that the pickle size is reasonable assert len(dumped) < 50 * len(kitchen_sink_sdl) loaded = pickle.loads(dumped) # check that the un-pickled schema AST is still the same assert loaded == doc # check that pickling again creates the same result dumped_again = pickle.dumps(doc) assert dumped_again == dumped graphql-core-3.2.6/tests/language/test_schema_printer.py000066400000000000000000000121261474546154300234660ustar00rootroot00000000000000from copy import deepcopy from pytest import raises from graphql.language import ScalarTypeDefinitionNode, NameNode, print_ast, parse from ..fixtures import kitchen_sink_sdl # noqa: F401 from ..utils import dedent def describe_printer_sdl_document(): def prints_minimal_ast(): node = ScalarTypeDefinitionNode(name=NameNode(value="foo")) assert print_ast(node) == "scalar foo" def produces_helpful_error_messages(): bad_ast = {"random": "Data"} with raises(TypeError) as exc_info: # noinspection PyTypeChecker print_ast(bad_ast) # type: ignore msg = str(exc_info.value) assert msg == "Not an AST Node: {'random': 'Data'}." # noinspection PyShadowingNames def prints_kitchen_sink_without_altering_ast(kitchen_sink_sdl): # noqa: F811 ast = parse(kitchen_sink_sdl, no_location=True) ast_before_print_call = deepcopy(ast) printed = print_ast(ast) printed_ast = parse(printed, no_location=True) assert printed_ast == ast assert deepcopy(ast) == ast_before_print_call assert printed == dedent( ''' """This is a description of the schema as a whole.""" schema { query: QueryType mutation: MutationType } """ This is a description of the `Foo` type. """ type Foo implements Bar & Baz & Two { "Description of the `one` field." one: Type """This is a description of the `two` field.""" two( """This is a description of the `argument` argument.""" argument: InputType! ): Type """This is a description of the `three` field.""" three(argument: InputType, other: String): Int four(argument: String = "string"): String five(argument: [String] = ["string", "string"]): String six(argument: InputType = {key: "value"}): Type seven(argument: Int = null): Type } type AnnotatedObject @onObject(arg: "value") { annotatedField(arg: Type = "default" @onArgumentDefinition): Type @onField } type UndefinedType extend type Foo { seven(argument: [String]): Type } extend type Foo @onType interface Bar { one: Type four(argument: String = "string"): String } interface AnnotatedInterface @onInterface { annotatedField(arg: Type @onArgumentDefinition): Type @onField } interface UndefinedInterface extend interface Bar implements Two { two(argument: InputType!): Type } extend interface Bar @onInterface interface Baz implements Bar & Two { one: Type two(argument: InputType!): Type four(argument: String = "string"): String } union Feed = Story | Article | Advert union AnnotatedUnion @onUnion = A | B union AnnotatedUnionTwo @onUnion = A | B union UndefinedUnion extend union Feed = Photo | Video extend union Feed @onUnion scalar CustomScalar scalar AnnotatedScalar @onScalar extend scalar CustomScalar @onScalar enum Site { """This is a description of the `DESKTOP` value""" DESKTOP """This is a description of the `MOBILE` value""" MOBILE "This is a description of the `WEB` value" WEB } enum AnnotatedEnum @onEnum { ANNOTATED_VALUE @onEnumValue OTHER_VALUE } enum UndefinedEnum extend enum Site { VR } extend enum Site @onEnum input InputType { key: String! answer: Int = 42 } input AnnotatedInput @onInputObject { annotatedField: Type @onInputFieldDefinition } input UndefinedInput extend input InputType { other: Float = 1.23e4 @onInputFieldDefinition } extend input InputType @onInputObject """This is a description of the `@skip` directive""" directive @skip( """This is a description of the `if` argument""" if: Boolean! @onArgumentDefinition ) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT directive @include(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT directive @include2(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT directive @myRepeatableDir(name: String!) repeatable on OBJECT | INTERFACE extend schema @onSchema extend schema @onSchema { subscription: SubscriptionType } ''' # noqa: E501 ) graphql-core-3.2.6/tests/language/test_source.py000066400000000000000000000070131474546154300217620ustar00rootroot00000000000000import weakref from typing import cast, Tuple from pytest import raises from graphql.language import Source, SourceLocation from ..utils import dedent def describe_source(): def accepts_body_and_name(): source = Source("foo", "bar") assert source.body == "foo" assert source.name == "bar" def accepts_location_offset(): location_offset = SourceLocation(2, 3) source = Source("", "", location_offset) assert source.location_offset is location_offset def accepts_tuple_as_location_offset(): # noinspection PyTypeChecker source = Source("", "", (2, 3)) # type: ignore assert isinstance(source.location_offset, SourceLocation) assert source.location_offset == (2, 3) def uses_default_arguments(): source = Source("") assert source.name == "GraphQL request" assert isinstance(source.location_offset, SourceLocation) assert source.location_offset == (1, 1) def can_get_location(): body = dedent( """ line 1 line 2 line 3 """ ) source = Source(body) assert source.body == body location = source.get_location(body.find("2")) assert isinstance(location, SourceLocation) assert location == (2, 6) def can_be_stringified(): source = Source("") assert str(source) == "" source = Source("", "Custom source name") assert str(source) == "" def can_be_compared(): source = Source("foo") assert source == source assert not source != source assert source == "foo" assert not source != "foo" same_source = Source("foo") assert source == same_source assert not source != same_source different_source = Source("bar") assert not source == different_source assert source != different_source assert not source == "bar" assert source != "bar" def can_create_weak_reference(): source = Source("foo") ref = weakref.ref(source) assert ref() is source def can_create_custom_attribute(): node = Source("foo") node.custom = "bar" # type: ignore assert node.custom == "bar" # type: ignore def rejects_invalid_location_offset(): def create_source(location_offset: Tuple[int, int]) -> Source: return Source("", "", cast(SourceLocation, location_offset)) with raises(TypeError): create_source(None) # type: ignore with raises(TypeError): create_source(1) # type: ignore with raises(TypeError): create_source((1,)) # type: ignore with raises(TypeError): create_source((1, 2, 3)) # type: ignore with raises( ValueError, match="line in location_offset is 1-indexed and must be positive\\.", ): create_source((0, 1)) with raises( ValueError, match="line in location_offset is 1-indexed and must be positive\\.", ): create_source((-1, 1)) with raises( ValueError, match="column in location_offset is 1-indexed and must be positive\\.", ): create_source((1, 0)) with raises( ValueError, match="column in location_offset is 1-indexed and must be positive\\.", ): create_source((1, -1)) graphql-core-3.2.6/tests/language/test_visitor.py000066400000000000000000001721431474546154300221700ustar00rootroot00000000000000from copy import copy from functools import partial from typing import cast, List, Optional from pytest import mark, raises from graphql.language import ( Node, FieldNode, NameNode, SelectionNode, SelectionSetNode, parse, visit, BREAK, REMOVE, SKIP, ParallelVisitor, Visitor, VisitorKeyMap, ) from ..fixtures import kitchen_sink_query # noqa: F401 def check_visitor_fn_args(ast, node, key, parent, path, ancestors, is_edited=False): assert isinstance(node, Node) is_root = key is None if is_root: if not is_edited: assert node is ast assert parent is None assert path == [] assert ancestors == [] return assert isinstance(key, (int, str)) if isinstance(key, int): assert isinstance(parent, tuple) assert 0 <= key <= len(parent) else: assert isinstance(parent, Node) assert hasattr(parent, key) assert isinstance(path, list) assert path[-1] == key assert isinstance(ancestors, list) assert len(ancestors) == len(path) - 1 if not is_edited: current_node = ast for i, ancestor in enumerate(ancestors): assert ancestor is current_node k = path[i] assert isinstance(k, (int, str)) if isinstance(k, int): assert isinstance(current_node, tuple) assert 0 <= k <= len(current_node) current_node = current_node[k] else: assert isinstance(current_node, Node) assert hasattr(current_node, k) current_node = getattr(current_node, k) assert current_node is not None assert parent is current_node if isinstance(key, int): assert parent[key] is node else: assert getattr(parent, key) is node check_visitor_fn_args_edited = partial(check_visitor_fn_args, is_edited=True) def get_value(node): return getattr(node, "value", None) def describe_visitor(): def visit_with_invalid_node(): with raises(TypeError) as exc_info: # noinspection PyTypeChecker visit("invalid", Visitor()) # type: ignore assert str(exc_info.value) == "Not an AST Node: 'invalid'." def visit_with_invalid_visitor(): ast = parse("{ a }", no_location=True) class TestVisitor: def enter(self, *_args): pass with raises(TypeError) as exc_info: # noinspection PyTypeChecker visit(ast, TestVisitor()) # type: ignore assert str(exc_info.value) == "Not an AST Visitor: ." def visitors_support_all_method_variants(): class TestVisitorWithInstanceMethods(Visitor): def enter(self, node, *args): assert isinstance(self, TestVisitorWithInstanceMethods) assert isinstance(node, Node) assert len(args) == 4 visited.append(f"enter:{node.kind}") pass def leave(self, node, *args): assert isinstance(self, TestVisitorWithInstanceMethods) assert isinstance(node, Node) assert len(args) == 4 visited.append(f"leave:{node.kind}") pass def enter_field(self, node, *args): assert isinstance(self, TestVisitorWithInstanceMethods) assert isinstance(node, Node) assert len(args) == 4 visited.append(f"enter_field:{node.kind}") pass def leave_field(self, node, *args): assert isinstance(self, TestVisitorWithInstanceMethods) assert isinstance(node, Node) assert len(args) == 4 visited.append(f"leave_field:{node.kind}") pass class TestVisitorWithClassMethods(Visitor): @classmethod def enter(cls, node, *args): assert cls is TestVisitorWithClassMethods assert isinstance(node, Node) assert len(args) == 4 visited.append(f"enter:{node.kind}") pass @classmethod def leave(cls, node, *args): assert cls is TestVisitorWithClassMethods assert isinstance(node, Node) assert len(args) == 4 visited.append(f"leave:{node.kind}") pass @classmethod def enter_field(cls, node, *args): assert cls is TestVisitorWithClassMethods assert isinstance(node, Node) assert len(args) == 4 visited.append(f"enter_field:{node.kind}") pass @classmethod def leave_field(cls, node, *args): assert cls is TestVisitorWithClassMethods assert isinstance(node, Node) assert len(args) == 4 visited.append(f"leave_field:{node.kind}") pass class TestVisitorWithStaticMethods(Visitor): @staticmethod def enter(node, *args): assert isinstance(node, Node) assert len(args) == 4 visited.append(f"enter:{node.kind}") pass @staticmethod def leave(node, *args): assert isinstance(node, Node) assert len(args) == 4 visited.append(f"leave:{node.kind}") pass @staticmethod def enter_field(node, *args): assert isinstance(node, Node) assert len(args) == 4 visited.append(f"enter_field:{node.kind}") pass @staticmethod def leave_field(node, *args): assert isinstance(node, Node) assert len(args) == 4 visited.append(f"leave_field:{node.kind}") pass for visitor_class in ( TestVisitorWithInstanceMethods, TestVisitorWithClassMethods, TestVisitorWithStaticMethods, ): ast = parse("{ a }") visited: List[str] = [] visit(ast, visitor_class()) assert visited == [ "enter:document", "enter:operation_definition", "enter:selection_set", "enter_field:field", "enter:name", "leave:name", "leave_field:field", "leave:selection_set", "leave:operation_definition", "leave:document", ] def has_get_enter_leave_for_kind_method(): class TestVisitor(Visitor): @staticmethod def enter(*args): pass @staticmethod def enter_document(*args): pass @staticmethod def leave(*args): pass @staticmethod def leave_document(*args): pass visitor = TestVisitor() assert visitor.get_enter_leave_for_kind("document") == ( visitor.enter_document, visitor.leave_document, ) assert visitor.get_enter_leave_for_kind("field") == ( visitor.enter, visitor.leave, ) # also test deprecated method assert visitor.get_visit_fn("document") == visitor.enter_document assert visitor.get_visit_fn("field") == visitor.enter assert visitor.get_visit_fn("document", True) == visitor.leave_document assert visitor.get_visit_fn("field", True) == visitor.leave def validates_path_argument(): ast = parse("{ a }", no_location=True) visited = [] class TestVisitor(Visitor): @staticmethod def enter(*args): check_visitor_fn_args(ast, *args) visited.append(["enter", *args[3]]) @staticmethod def leave(*args): check_visitor_fn_args(ast, *args) visited.append(["leave", *args[3]]) visit(ast, TestVisitor()) assert visited == [ ["enter"], ["enter", "definitions", 0], ["enter", "definitions", 0, "selection_set"], ["enter", "definitions", 0, "selection_set", "selections", 0], ["enter", "definitions", 0, "selection_set", "selections", 0, "name"], ["leave", "definitions", 0, "selection_set", "selections", 0, "name"], ["leave", "definitions", 0, "selection_set", "selections", 0], ["leave", "definitions", 0, "selection_set"], ["leave", "definitions", 0], ["leave"], ] def validates_ancestors_argument(): ast = parse("{ a }", no_location=True) visited_nodes = [] class TestVisitor(Visitor): @staticmethod def enter(node, key, parent, _path, ancestors): in_array = isinstance(key, int) if in_array: visited_nodes.append(parent) visited_nodes.append(node) expected_ancestors = visited_nodes[0:-2] assert ancestors == expected_ancestors @staticmethod def leave(_node, key, _parent, _path, ancestors): expected_ancestors = visited_nodes[0:-2] assert ancestors == expected_ancestors in_array = isinstance(key, int) if in_array: visited_nodes.pop() visited_nodes.pop() visit(ast, TestVisitor()) def allows_visiting_only_specified_nodes(): ast = parse("{ a }", no_location=True) visited = [] class TestVisitor(Visitor): selection_set = None @staticmethod def enter_field(node, *_args): visited.append(["enter", node.kind]) @staticmethod def leave_field(node, *_args): visited.append(["leave", node.kind]) visit(ast, TestVisitor()) assert visited == [["enter", "field"], ["leave", "field"]] def allows_editing_a_node_both_on_enter_and_on_leave(): ast = parse("{ a, b, c { a, b, c } }", no_location=True) visited = [] class TestVisitor(Visitor): selection_set = None def enter_operation_definition(self, *args): check_visitor_fn_args(ast, *args) node = copy(args[0]) assert len(node.selection_set.selections) == 3 self.selection_set = node.selection_set node.selection_set = SelectionSetNode(selections=[]) visited.append("enter") return node def leave_operation_definition(self, *args): check_visitor_fn_args_edited(ast, *args) node = copy(args[0]) assert not node.selection_set.selections node.selection_set = self.selection_set visited.append("leave") return node edited_ast = visit(ast, TestVisitor()) assert edited_ast == ast assert visited == ["enter", "leave"] @mark.parametrize("remove_action", (REMOVE, Ellipsis), ids=("REMOVE", "Ellipsis")) def allows_for_editing_on_enter(remove_action): ast = parse("{ a, b, c { a, b, c } }", no_location=True) class TestVisitor(Visitor): @staticmethod def enter(*args): check_visitor_fn_args(ast, *args) node = args[0] if isinstance(node, FieldNode) and node.name.value == "b": return remove_action edited_ast = visit(ast, TestVisitor()) assert ast == parse("{ a, b, c { a, b, c } }", no_location=True) assert edited_ast == parse("{ a, c { a, c } }", no_location=True) @mark.parametrize("remove_action", (REMOVE, Ellipsis), ids=("REMOVE", "Ellipsis")) def allows_for_editing_on_leave(remove_action): ast = parse("{ a, b, c { a, b, c } }", no_location=True) class TestVisitor(Visitor): @staticmethod def leave(*args): check_visitor_fn_args_edited(ast, *args) node = args[0] if isinstance(node, FieldNode) and node.name.value == "b": return remove_action edited_ast = visit(ast, TestVisitor()) assert ast == parse("{ a, b, c { a, b, c } }", no_location=True) assert edited_ast == parse("{ a, c { a, c } }", no_location=True) @mark.parametrize("skip_action", (SKIP, False), ids=("SKIP", "False")) def ignores_false_returned_on_leave(skip_action): ast = parse("{ a, b, c { a, b, c } }", no_location=True) class TestVisitor(Visitor): @staticmethod def leave(*args): return skip_action returned_ast = visit(ast, TestVisitor()) assert returned_ast == parse("{ a, b, c { a, b, c } }", no_location=True) def visits_edited_node(): ast = parse("{ a { x } }", no_location=True) added_field = FieldNode(name=NameNode(value="__typename")) class TestVisitor(Visitor): did_visit_added_field = False def enter(self, *args): check_visitor_fn_args_edited(ast, *args) node = args[0] if isinstance(node, FieldNode) and node.name.value == "a": node = copy(node) assert node.selection_set node.selection_set.selections = ( added_field, ) + node.selection_set.selections return node if node == added_field: self.did_visit_added_field = True visitor = TestVisitor() visit(ast, visitor) assert visitor.did_visit_added_field @mark.parametrize("skip_action", (SKIP, False), ids=("SKIP", "False")) def allows_skipping_a_sub_tree(skip_action): ast = parse("{ a, b { x }, c }", no_location=True) visited = [] class TestVisitor(Visitor): @staticmethod def enter(*args): check_visitor_fn_args(ast, *args) node = args[0] kind, value = node.kind, get_value(node) visited.append(["enter", kind, value]) if kind == "field" and node.name.value == "b": return skip_action @staticmethod def leave(*args): check_visitor_fn_args(ast, *args) node = args[0] kind, value = node.kind, get_value(node) visited.append(["leave", kind, value]) visit(ast, TestVisitor()) assert visited == [ ["enter", "document", None], ["enter", "operation_definition", None], ["enter", "selection_set", None], ["enter", "field", None], ["enter", "name", "a"], ["leave", "name", "a"], ["leave", "field", None], ["enter", "field", None], ["enter", "field", None], ["enter", "name", "c"], ["leave", "name", "c"], ["leave", "field", None], ["leave", "selection_set", None], ["leave", "operation_definition", None], ["leave", "document", None], ] @mark.parametrize("break_action", (BREAK, True), ids=("BREAK", "True")) def allows_early_exit_while_visiting(break_action): ast = parse("{ a, b { x }, c }", no_location=True) visited = [] class TestVisitor(Visitor): @staticmethod def enter(*args): check_visitor_fn_args(ast, *args) node = args[0] kind, value = node.kind, get_value(node) visited.append(["enter", kind, value]) if kind == "name" and node.value == "x": return break_action @staticmethod def leave(*args): check_visitor_fn_args(ast, *args) node = args[0] kind, value = node.kind, get_value(node) visited.append(["leave", kind, value]) visit(ast, TestVisitor()) assert visited == [ ["enter", "document", None], ["enter", "operation_definition", None], ["enter", "selection_set", None], ["enter", "field", None], ["enter", "name", "a"], ["leave", "name", "a"], ["leave", "field", None], ["enter", "field", None], ["enter", "name", "b"], ["leave", "name", "b"], ["enter", "selection_set", None], ["enter", "field", None], ["enter", "name", "x"], ] @mark.parametrize("break_action", (BREAK, True), ids=("BREAK", "True")) def allows_early_exit_while_leaving(break_action): ast = parse("{ a, b { x }, c }", no_location=True) visited = [] class TestVisitor(Visitor): @staticmethod def enter(*args): check_visitor_fn_args(ast, *args) node = args[0] kind, value = node.kind, get_value(node) visited.append(["enter", kind, value]) @staticmethod def leave(*args): check_visitor_fn_args(ast, *args) node = args[0] kind, value = node.kind, get_value(node) visited.append(["leave", kind, value]) if kind == "name" and node.value == "x": return break_action visit(ast, TestVisitor()) assert visited == [ ["enter", "document", None], ["enter", "operation_definition", None], ["enter", "selection_set", None], ["enter", "field", None], ["enter", "name", "a"], ["leave", "name", "a"], ["leave", "field", None], ["enter", "field", None], ["enter", "name", "b"], ["leave", "name", "b"], ["enter", "selection_set", None], ["enter", "field", None], ["enter", "name", "x"], ["leave", "name", "x"], ] def allows_a_named_functions_visitor_api(): ast = parse("{ a, b { x }, c }", no_location=True) visited = [] class TestVisitor(Visitor): @staticmethod def enter_name(*args): check_visitor_fn_args(ast, *args) node = args[0] kind, value = node.kind, get_value(node) visited.append(["enter", kind, value]) @staticmethod def enter_selection_set(*args): check_visitor_fn_args(ast, *args) node = args[0] kind, value = node.kind, get_value(node) visited.append(["enter", kind, value]) @staticmethod def leave_selection_set(*args): check_visitor_fn_args(ast, *args) node = args[0] kind, value = node.kind, get_value(node) visited.append(["leave", kind, value]) visit(ast, TestVisitor()) assert visited == [ ["enter", "selection_set", None], ["enter", "name", "a"], ["enter", "name", "b"], ["enter", "selection_set", None], ["enter", "name", "x"], ["leave", "selection_set", None], ["enter", "name", "c"], ["leave", "selection_set", None], ] def visit_nodes_with_custom_kinds_but_does_not_traverse_deeper(): # GraphQL.js removed support for unknown node types, # but it is easy for us to add and support custom node types, # so we keep allowing this and test this feature here. custom_ast = parse("{ a }") class CustomFieldNode(SelectionNode): __slots__ = "name", "selection_set" name: NameNode selection_set: Optional[SelectionSetNode] custom_selection_set = cast(FieldNode, custom_ast.definitions[0]).selection_set assert custom_selection_set is not None custom_selection_set.selections = custom_selection_set.selections + ( CustomFieldNode( name=NameNode(value="NameNodeToBeSkipped"), selection_set=SelectionSetNode( selections=CustomFieldNode( name=NameNode(value="NameNodeToBeSkipped") ) ), ), ) visited = [] class TestVisitor(Visitor): @staticmethod def enter(node, *_args): visited.append(["enter", node.kind, get_value(node)]) @staticmethod def leave(node, *_args): visited.append(["leave", node.kind, get_value(node)]) visit(custom_ast, TestVisitor()) assert visited == [ ["enter", "document", None], ["enter", "operation_definition", None], ["enter", "selection_set", None], ["enter", "field", None], ["enter", "name", "a"], ["leave", "name", "a"], ["leave", "field", None], ["enter", "custom_field", None], ["leave", "custom_field", None], ["leave", "selection_set", None], ["leave", "operation_definition", None], ["leave", "document", None], ] def visits_only_the_specified_kind_in_visitor_key_map(): visited = [] visitor_key_map: VisitorKeyMap = { "document": ("definitions",), "operation_definition": ("name",), } class TestVisitor(Visitor): @staticmethod def enter(node, *_args): visited.append(["enter", node.kind, get_value(node)]) @staticmethod def leave(node, *_args): visited.append(["leave", node.kind, get_value(node)]) example_document_ast = parse( """ query ExampleOperation { someField } """ ) visit(example_document_ast, TestVisitor(), visitor_key_map) assert visited == [ ["enter", "document", None], ["enter", "operation_definition", None], ["enter", "name", "ExampleOperation"], ["leave", "name", "ExampleOperation"], ["leave", "operation_definition", None], ["leave", "document", None], ] def cannot_define_visitor_with_unknown_ast_nodes(): with raises(TypeError) as exc_info: class VisitorWithNonExistingNode(Visitor): def enter_field(self, *_args): pass def leave_garfield(self, *_args): pass assert str(exc_info.value) == "Invalid AST node kind: garfield." with raises(TypeError) as exc_info: class VisitorWithUnspecificNode(Visitor): def enter_type_system_extension(self, *_args): pass assert str(exc_info.value) == "Invalid AST node kind: type_system_extension." def legacy_visits_variables_defined_in_fragments(): ast = parse( "fragment a($v: Boolean = false) on t { f }", no_location=True, allow_legacy_fragment_variables=True, ) visited = [] class TestVisitor(Visitor): @staticmethod def enter(*args): check_visitor_fn_args(ast, *args) node = args[0] kind, value = node.kind, get_value(node) visited.append(["enter", kind, value]) @staticmethod def leave(*args): check_visitor_fn_args(ast, *args) node = args[0] kind, value = node.kind, get_value(node) visited.append(["leave", kind, value]) visit(ast, TestVisitor()) assert visited == [ ["enter", "document", None], ["enter", "fragment_definition", None], ["enter", "name", "a"], ["leave", "name", "a"], ["enter", "variable_definition", None], ["enter", "variable", None], ["enter", "name", "v"], ["leave", "name", "v"], ["leave", "variable", None], ["enter", "named_type", None], ["enter", "name", "Boolean"], ["leave", "name", "Boolean"], ["leave", "named_type", None], ["enter", "boolean_value", False], ["leave", "boolean_value", False], ["leave", "variable_definition", None], ["enter", "named_type", None], ["enter", "name", "t"], ["leave", "name", "t"], ["leave", "named_type", None], ["enter", "selection_set", None], ["enter", "field", None], ["enter", "name", "f"], ["leave", "name", "f"], ["leave", "field", None], ["leave", "selection_set", None], ["leave", "fragment_definition", None], ["leave", "document", None], ] # noinspection PyShadowingNames def visits_kitchen_sink(kitchen_sink_query): # noqa: F811 ast = parse(kitchen_sink_query) visited: List = [] record = visited.append arg_stack: List = [] push = arg_stack.append pop = arg_stack.pop class TestVisitor(Visitor): @staticmethod def enter(*args): node, key, parent = args[:3] parent_kind = parent.kind if isinstance(parent, Node) else None record(["enter", node.kind, key, parent_kind]) check_visitor_fn_args(ast, *args) push(args[:]) @staticmethod def leave(*args): node, key, parent = args[:3] parent_kind = parent.kind if isinstance(parent, Node) else None record(["leave", node.kind, key, parent_kind]) assert pop() == args visit(ast, TestVisitor()) assert arg_stack == [] assert visited == [ ["enter", "document", None, None], ["enter", "operation_definition", 0, None], ["enter", "name", "name", "operation_definition"], ["leave", "name", "name", "operation_definition"], ["enter", "variable_definition", 0, None], ["enter", "variable", "variable", "variable_definition"], ["enter", "name", "name", "variable"], ["leave", "name", "name", "variable"], ["leave", "variable", "variable", "variable_definition"], ["enter", "named_type", "type", "variable_definition"], ["enter", "name", "name", "named_type"], ["leave", "name", "name", "named_type"], ["leave", "named_type", "type", "variable_definition"], ["leave", "variable_definition", 0, None], ["enter", "variable_definition", 1, None], ["enter", "variable", "variable", "variable_definition"], ["enter", "name", "name", "variable"], ["leave", "name", "name", "variable"], ["leave", "variable", "variable", "variable_definition"], ["enter", "named_type", "type", "variable_definition"], ["enter", "name", "name", "named_type"], ["leave", "name", "name", "named_type"], ["leave", "named_type", "type", "variable_definition"], ["enter", "enum_value", "default_value", "variable_definition"], ["leave", "enum_value", "default_value", "variable_definition"], ["leave", "variable_definition", 1, None], ["enter", "directive", 0, None], ["enter", "name", "name", "directive"], ["leave", "name", "name", "directive"], ["leave", "directive", 0, None], ["enter", "selection_set", "selection_set", "operation_definition"], ["enter", "field", 0, None], ["enter", "name", "alias", "field"], ["leave", "name", "alias", "field"], ["enter", "name", "name", "field"], ["leave", "name", "name", "field"], ["enter", "argument", 0, None], ["enter", "name", "name", "argument"], ["leave", "name", "name", "argument"], ["enter", "list_value", "value", "argument"], ["enter", "int_value", 0, None], ["leave", "int_value", 0, None], ["enter", "int_value", 1, None], ["leave", "int_value", 1, None], ["leave", "list_value", "value", "argument"], ["leave", "argument", 0, None], ["enter", "selection_set", "selection_set", "field"], ["enter", "field", 0, None], ["enter", "name", "name", "field"], ["leave", "name", "name", "field"], ["leave", "field", 0, None], ["enter", "inline_fragment", 1, None], ["enter", "named_type", "type_condition", "inline_fragment"], ["enter", "name", "name", "named_type"], ["leave", "name", "name", "named_type"], ["leave", "named_type", "type_condition", "inline_fragment"], ["enter", "directive", 0, None], ["enter", "name", "name", "directive"], ["leave", "name", "name", "directive"], ["leave", "directive", 0, None], ["enter", "selection_set", "selection_set", "inline_fragment"], ["enter", "field", 0, None], ["enter", "name", "name", "field"], ["leave", "name", "name", "field"], ["enter", "selection_set", "selection_set", "field"], ["enter", "field", 0, None], ["enter", "name", "name", "field"], ["leave", "name", "name", "field"], ["leave", "field", 0, None], ["enter", "field", 1, None], ["enter", "name", "alias", "field"], ["leave", "name", "alias", "field"], ["enter", "name", "name", "field"], ["leave", "name", "name", "field"], ["enter", "argument", 0, None], ["enter", "name", "name", "argument"], ["leave", "name", "name", "argument"], ["enter", "int_value", "value", "argument"], ["leave", "int_value", "value", "argument"], ["leave", "argument", 0, None], ["enter", "argument", 1, None], ["enter", "name", "name", "argument"], ["leave", "name", "name", "argument"], ["enter", "variable", "value", "argument"], ["enter", "name", "name", "variable"], ["leave", "name", "name", "variable"], ["leave", "variable", "value", "argument"], ["leave", "argument", 1, None], ["enter", "directive", 0, None], ["enter", "name", "name", "directive"], ["leave", "name", "name", "directive"], ["enter", "argument", 0, None], ["enter", "name", "name", "argument"], ["leave", "name", "name", "argument"], ["enter", "variable", "value", "argument"], ["enter", "name", "name", "variable"], ["leave", "name", "name", "variable"], ["leave", "variable", "value", "argument"], ["leave", "argument", 0, None], ["leave", "directive", 0, None], ["enter", "selection_set", "selection_set", "field"], ["enter", "field", 0, None], ["enter", "name", "name", "field"], ["leave", "name", "name", "field"], ["leave", "field", 0, None], ["enter", "fragment_spread", 1, None], ["enter", "name", "name", "fragment_spread"], ["leave", "name", "name", "fragment_spread"], ["enter", "directive", 0, None], ["enter", "name", "name", "directive"], ["leave", "name", "name", "directive"], ["leave", "directive", 0, None], ["leave", "fragment_spread", 1, None], ["leave", "selection_set", "selection_set", "field"], ["leave", "field", 1, None], ["leave", "selection_set", "selection_set", "field"], ["leave", "field", 0, None], ["leave", "selection_set", "selection_set", "inline_fragment"], ["leave", "inline_fragment", 1, None], ["enter", "inline_fragment", 2, None], ["enter", "directive", 0, None], ["enter", "name", "name", "directive"], ["leave", "name", "name", "directive"], ["enter", "argument", 0, None], ["enter", "name", "name", "argument"], ["leave", "name", "name", "argument"], ["enter", "variable", "value", "argument"], ["enter", "name", "name", "variable"], ["leave", "name", "name", "variable"], ["leave", "variable", "value", "argument"], ["leave", "argument", 0, None], ["leave", "directive", 0, None], ["enter", "selection_set", "selection_set", "inline_fragment"], ["enter", "field", 0, None], ["enter", "name", "name", "field"], ["leave", "name", "name", "field"], ["leave", "field", 0, None], ["leave", "selection_set", "selection_set", "inline_fragment"], ["leave", "inline_fragment", 2, None], ["enter", "inline_fragment", 3, None], ["enter", "selection_set", "selection_set", "inline_fragment"], ["enter", "field", 0, None], ["enter", "name", "name", "field"], ["leave", "name", "name", "field"], ["leave", "field", 0, None], ["leave", "selection_set", "selection_set", "inline_fragment"], ["leave", "inline_fragment", 3, None], ["leave", "selection_set", "selection_set", "field"], ["leave", "field", 0, None], ["leave", "selection_set", "selection_set", "operation_definition"], ["leave", "operation_definition", 0, None], ["enter", "operation_definition", 1, None], ["enter", "name", "name", "operation_definition"], ["leave", "name", "name", "operation_definition"], ["enter", "directive", 0, None], ["enter", "name", "name", "directive"], ["leave", "name", "name", "directive"], ["leave", "directive", 0, None], ["enter", "selection_set", "selection_set", "operation_definition"], ["enter", "field", 0, None], ["enter", "name", "name", "field"], ["leave", "name", "name", "field"], ["enter", "argument", 0, None], ["enter", "name", "name", "argument"], ["leave", "name", "name", "argument"], ["enter", "int_value", "value", "argument"], ["leave", "int_value", "value", "argument"], ["leave", "argument", 0, None], ["enter", "directive", 0, None], ["enter", "name", "name", "directive"], ["leave", "name", "name", "directive"], ["leave", "directive", 0, None], ["enter", "selection_set", "selection_set", "field"], ["enter", "field", 0, None], ["enter", "name", "name", "field"], ["leave", "name", "name", "field"], ["enter", "selection_set", "selection_set", "field"], ["enter", "field", 0, None], ["enter", "name", "name", "field"], ["leave", "name", "name", "field"], ["enter", "directive", 0, None], ["enter", "name", "name", "directive"], ["leave", "name", "name", "directive"], ["leave", "directive", 0, None], ["leave", "field", 0, None], ["leave", "selection_set", "selection_set", "field"], ["leave", "field", 0, None], ["leave", "selection_set", "selection_set", "field"], ["leave", "field", 0, None], ["leave", "selection_set", "selection_set", "operation_definition"], ["leave", "operation_definition", 1, None], ["enter", "operation_definition", 2, None], ["enter", "name", "name", "operation_definition"], ["leave", "name", "name", "operation_definition"], ["enter", "variable_definition", 0, None], ["enter", "variable", "variable", "variable_definition"], ["enter", "name", "name", "variable"], ["leave", "name", "name", "variable"], ["leave", "variable", "variable", "variable_definition"], ["enter", "named_type", "type", "variable_definition"], ["enter", "name", "name", "named_type"], ["leave", "name", "name", "named_type"], ["leave", "named_type", "type", "variable_definition"], ["enter", "directive", 0, None], ["enter", "name", "name", "directive"], ["leave", "name", "name", "directive"], ["leave", "directive", 0, None], ["leave", "variable_definition", 0, None], ["enter", "directive", 0, None], ["enter", "name", "name", "directive"], ["leave", "name", "name", "directive"], ["leave", "directive", 0, None], ["enter", "selection_set", "selection_set", "operation_definition"], ["enter", "field", 0, None], ["enter", "name", "name", "field"], ["leave", "name", "name", "field"], ["enter", "argument", 0, None], ["enter", "name", "name", "argument"], ["leave", "name", "name", "argument"], ["enter", "variable", "value", "argument"], ["enter", "name", "name", "variable"], ["leave", "name", "name", "variable"], ["leave", "variable", "value", "argument"], ["leave", "argument", 0, None], ["enter", "selection_set", "selection_set", "field"], ["enter", "field", 0, None], ["enter", "name", "name", "field"], ["leave", "name", "name", "field"], ["enter", "selection_set", "selection_set", "field"], ["enter", "field", 0, None], ["enter", "name", "name", "field"], ["leave", "name", "name", "field"], ["enter", "selection_set", "selection_set", "field"], ["enter", "field", 0, None], ["enter", "name", "name", "field"], ["leave", "name", "name", "field"], ["leave", "field", 0, None], ["leave", "selection_set", "selection_set", "field"], ["leave", "field", 0, None], ["enter", "field", 1, None], ["enter", "name", "name", "field"], ["leave", "name", "name", "field"], ["enter", "selection_set", "selection_set", "field"], ["enter", "field", 0, None], ["enter", "name", "name", "field"], ["leave", "name", "name", "field"], ["leave", "field", 0, None], ["leave", "selection_set", "selection_set", "field"], ["leave", "field", 1, None], ["leave", "selection_set", "selection_set", "field"], ["leave", "field", 0, None], ["leave", "selection_set", "selection_set", "field"], ["leave", "field", 0, None], ["leave", "selection_set", "selection_set", "operation_definition"], ["leave", "operation_definition", 2, None], ["enter", "fragment_definition", 3, None], ["enter", "name", "name", "fragment_definition"], ["leave", "name", "name", "fragment_definition"], ["enter", "named_type", "type_condition", "fragment_definition"], ["enter", "name", "name", "named_type"], ["leave", "name", "name", "named_type"], ["leave", "named_type", "type_condition", "fragment_definition"], ["enter", "directive", 0, None], ["enter", "name", "name", "directive"], ["leave", "name", "name", "directive"], ["leave", "directive", 0, None], ["enter", "selection_set", "selection_set", "fragment_definition"], ["enter", "field", 0, None], ["enter", "name", "name", "field"], ["leave", "name", "name", "field"], ["enter", "argument", 0, None], ["enter", "name", "name", "argument"], ["leave", "name", "name", "argument"], ["enter", "variable", "value", "argument"], ["enter", "name", "name", "variable"], ["leave", "name", "name", "variable"], ["leave", "variable", "value", "argument"], ["leave", "argument", 0, None], ["enter", "argument", 1, None], ["enter", "name", "name", "argument"], ["leave", "name", "name", "argument"], ["enter", "variable", "value", "argument"], ["enter", "name", "name", "variable"], ["leave", "name", "name", "variable"], ["leave", "variable", "value", "argument"], ["leave", "argument", 1, None], ["enter", "argument", 2, None], ["enter", "name", "name", "argument"], ["leave", "name", "name", "argument"], ["enter", "object_value", "value", "argument"], ["enter", "object_field", 0, None], ["enter", "name", "name", "object_field"], ["leave", "name", "name", "object_field"], ["enter", "string_value", "value", "object_field"], ["leave", "string_value", "value", "object_field"], ["leave", "object_field", 0, None], ["enter", "object_field", 1, None], ["enter", "name", "name", "object_field"], ["leave", "name", "name", "object_field"], ["enter", "string_value", "value", "object_field"], ["leave", "string_value", "value", "object_field"], ["leave", "object_field", 1, None], ["leave", "object_value", "value", "argument"], ["leave", "argument", 2, None], ["leave", "field", 0, None], ["leave", "selection_set", "selection_set", "fragment_definition"], ["leave", "fragment_definition", 3, None], ["enter", "operation_definition", 4, None], ["enter", "selection_set", "selection_set", "operation_definition"], ["enter", "field", 0, None], ["enter", "name", "name", "field"], ["leave", "name", "name", "field"], ["enter", "argument", 0, None], ["enter", "name", "name", "argument"], ["leave", "name", "name", "argument"], ["enter", "boolean_value", "value", "argument"], ["leave", "boolean_value", "value", "argument"], ["leave", "argument", 0, None], ["enter", "argument", 1, None], ["enter", "name", "name", "argument"], ["leave", "name", "name", "argument"], ["enter", "boolean_value", "value", "argument"], ["leave", "boolean_value", "value", "argument"], ["leave", "argument", 1, None], ["enter", "argument", 2, None], ["enter", "name", "name", "argument"], ["leave", "name", "name", "argument"], ["enter", "null_value", "value", "argument"], ["leave", "null_value", "value", "argument"], ["leave", "argument", 2, None], ["leave", "field", 0, None], ["enter", "field", 1, None], ["enter", "name", "name", "field"], ["leave", "name", "name", "field"], ["leave", "field", 1, None], ["leave", "selection_set", "selection_set", "operation_definition"], ["leave", "operation_definition", 4, None], ["enter", "operation_definition", 5, None], ["enter", "selection_set", "selection_set", "operation_definition"], ["enter", "field", 0, None], ["enter", "name", "name", "field"], ["leave", "name", "name", "field"], ["leave", "field", 0, None], ["leave", "selection_set", "selection_set", "operation_definition"], ["leave", "operation_definition", 5, None], ["leave", "document", None, None], ] def describe_visit_in_parallel(): @mark.parametrize("skip_action", (SKIP, False), ids=("SKIP", "False")) def allows_skipping_a_sub_tree(skip_action): # Note: nearly identical to the above test but using ParallelVisitor ast = parse("{ a, b { x }, c }") visited = [] class TestVisitor(Visitor): @staticmethod def enter(*args): check_visitor_fn_args(ast, *args) node = args[0] kind, value = node.kind, get_value(node) visited.append(["enter", kind, value]) if kind == "field" and node.name.value == "b": return skip_action @staticmethod def leave(*args): check_visitor_fn_args(ast, *args) node = args[0] kind, value = node.kind, get_value(node) visited.append(["leave", kind, value]) visit(ast, ParallelVisitor([TestVisitor()])) assert visited == [ ["enter", "document", None], ["enter", "operation_definition", None], ["enter", "selection_set", None], ["enter", "field", None], ["enter", "name", "a"], ["leave", "name", "a"], ["leave", "field", None], ["enter", "field", None], ["enter", "field", None], ["enter", "name", "c"], ["leave", "name", "c"], ["leave", "field", None], ["leave", "selection_set", None], ["leave", "operation_definition", None], ["leave", "document", None], ] @mark.parametrize("skip_action", (SKIP, False), ids=("SKIP", "False")) def allows_skipping_different_sub_trees(skip_action): ast = parse("{ a { x }, b { y} }") visited = [] class TestVisitor(Visitor): def __init__(self, name): super().__init__() self.name = name def enter(self, *args): check_visitor_fn_args(ast, *args) node = args[0] kind, value = node.kind, get_value(node) name = self.name visited.append([f"no-{name}", "enter", kind, value]) if kind == "field" and node.name.value == name: return skip_action def leave(self, *args): check_visitor_fn_args(ast, *args) node = args[0] kind, value = node.kind, get_value(node) name = self.name visited.append([f"no-{name}", "leave", kind, value]) visit(ast, ParallelVisitor([TestVisitor("a"), TestVisitor("b")])) assert visited == [ ["no-a", "enter", "document", None], ["no-b", "enter", "document", None], ["no-a", "enter", "operation_definition", None], ["no-b", "enter", "operation_definition", None], ["no-a", "enter", "selection_set", None], ["no-b", "enter", "selection_set", None], ["no-a", "enter", "field", None], ["no-b", "enter", "field", None], ["no-b", "enter", "name", "a"], ["no-b", "leave", "name", "a"], ["no-b", "enter", "selection_set", None], ["no-b", "enter", "field", None], ["no-b", "enter", "name", "x"], ["no-b", "leave", "name", "x"], ["no-b", "leave", "field", None], ["no-b", "leave", "selection_set", None], ["no-b", "leave", "field", None], ["no-a", "enter", "field", None], ["no-b", "enter", "field", None], ["no-a", "enter", "name", "b"], ["no-a", "leave", "name", "b"], ["no-a", "enter", "selection_set", None], ["no-a", "enter", "field", None], ["no-a", "enter", "name", "y"], ["no-a", "leave", "name", "y"], ["no-a", "leave", "field", None], ["no-a", "leave", "selection_set", None], ["no-a", "leave", "field", None], ["no-a", "leave", "selection_set", None], ["no-b", "leave", "selection_set", None], ["no-a", "leave", "operation_definition", None], ["no-b", "leave", "operation_definition", None], ["no-a", "leave", "document", None], ["no-b", "leave", "document", None], ] @mark.parametrize("break_action", (BREAK, True), ids=("BREAK", "True")) def allows_early_exit_while_visiting(break_action): # Note: nearly identical to the above test but using ParallelVisitor. ast = parse("{ a, b { x }, c }") visited = [] class TestVisitor(Visitor): @staticmethod def enter(*args): check_visitor_fn_args(ast, *args) node = args[0] kind, value = node.kind, get_value(node) visited.append(["enter", kind, value]) if kind == "name" and node.value == "x": return break_action @staticmethod def leave(*args): check_visitor_fn_args(ast, *args) node = args[0] kind, value = node.kind, get_value(node) visited.append(["leave", kind, value]) visit(ast, ParallelVisitor([TestVisitor()])) assert visited == [ ["enter", "document", None], ["enter", "operation_definition", None], ["enter", "selection_set", None], ["enter", "field", None], ["enter", "name", "a"], ["leave", "name", "a"], ["leave", "field", None], ["enter", "field", None], ["enter", "name", "b"], ["leave", "name", "b"], ["enter", "selection_set", None], ["enter", "field", None], ["enter", "name", "x"], ] @mark.parametrize("break_action", (BREAK, True), ids=("BREAK", "True")) def allows_early_exit_from_different_points(break_action): ast = parse("{ a { y }, b { x } }") visited = [] class TestVisitor(Visitor): def __init__(self, name): super().__init__() self.name = name def enter(self, *args): check_visitor_fn_args(ast, *args) node = args[0] kind, value = node.kind, get_value(node) name = self.name visited.append([f"break-{name}", "enter", kind, value]) if kind == "name" and node.value == name: return break_action def leave(self, *args): assert self.name == "b" check_visitor_fn_args(ast, *args) node = args[0] kind, value = node.kind, get_value(node) name = self.name visited.append([f"break-{name}", "leave", kind, value]) visit(ast, ParallelVisitor([TestVisitor("a"), TestVisitor("b")])) assert visited == [ ["break-a", "enter", "document", None], ["break-b", "enter", "document", None], ["break-a", "enter", "operation_definition", None], ["break-b", "enter", "operation_definition", None], ["break-a", "enter", "selection_set", None], ["break-b", "enter", "selection_set", None], ["break-a", "enter", "field", None], ["break-b", "enter", "field", None], ["break-a", "enter", "name", "a"], ["break-b", "enter", "name", "a"], ["break-b", "leave", "name", "a"], ["break-b", "enter", "selection_set", None], ["break-b", "enter", "field", None], ["break-b", "enter", "name", "y"], ["break-b", "leave", "name", "y"], ["break-b", "leave", "field", None], ["break-b", "leave", "selection_set", None], ["break-b", "leave", "field", None], ["break-b", "enter", "field", None], ["break-b", "enter", "name", "b"], ] @mark.parametrize("break_action", (BREAK, True), ids=("BREAK", "True")) def allows_early_exit_while_leaving(break_action): # Note: nearly identical to the above test but using ParallelVisitor. ast = parse("{ a, b { x }, c }") visited = [] class TestVisitor(Visitor): @staticmethod def enter(*args): check_visitor_fn_args(ast, *args) node = args[0] kind, value = node.kind, get_value(node) visited.append(["enter", kind, value]) @staticmethod def leave(*args): check_visitor_fn_args(ast, *args) node = args[0] kind, value = node.kind, get_value(node) visited.append(["leave", kind, value]) if kind == "name" and node.value == "x": return break_action visit(ast, ParallelVisitor([TestVisitor()])) assert visited == [ ["enter", "document", None], ["enter", "operation_definition", None], ["enter", "selection_set", None], ["enter", "field", None], ["enter", "name", "a"], ["leave", "name", "a"], ["leave", "field", None], ["enter", "field", None], ["enter", "name", "b"], ["leave", "name", "b"], ["enter", "selection_set", None], ["enter", "field", None], ["enter", "name", "x"], ["leave", "name", "x"], ] @mark.parametrize("break_action", (BREAK, True), ids=("BREAK", "True")) def allows_early_exit_from_leaving_different_points(break_action): ast = parse("{ a { y }, b { x } }") visited = [] class TestVisitor(Visitor): def __init__(self, name): super().__init__() self.name = name def enter(self, *args): check_visitor_fn_args(ast, *args) node = args[0] kind, value = node.kind, get_value(node) name = self.name visited.append([f"break-{name}", "enter", kind, value]) def leave(self, *args): check_visitor_fn_args(ast, *args) node = args[0] kind, value = node.kind, get_value(node) name = self.name visited.append([f"break-{name}", "leave", kind, value]) if kind == "field" and node.name.value == name: return break_action visit(ast, ParallelVisitor([TestVisitor("a"), TestVisitor("b")])) assert visited == [ ["break-a", "enter", "document", None], ["break-b", "enter", "document", None], ["break-a", "enter", "operation_definition", None], ["break-b", "enter", "operation_definition", None], ["break-a", "enter", "selection_set", None], ["break-b", "enter", "selection_set", None], ["break-a", "enter", "field", None], ["break-b", "enter", "field", None], ["break-a", "enter", "name", "a"], ["break-b", "enter", "name", "a"], ["break-a", "leave", "name", "a"], ["break-b", "leave", "name", "a"], ["break-a", "enter", "selection_set", None], ["break-b", "enter", "selection_set", None], ["break-a", "enter", "field", None], ["break-b", "enter", "field", None], ["break-a", "enter", "name", "y"], ["break-b", "enter", "name", "y"], ["break-a", "leave", "name", "y"], ["break-b", "leave", "name", "y"], ["break-a", "leave", "field", None], ["break-b", "leave", "field", None], ["break-a", "leave", "selection_set", None], ["break-b", "leave", "selection_set", None], ["break-a", "leave", "field", None], ["break-b", "leave", "field", None], ["break-b", "enter", "field", None], ["break-b", "enter", "name", "b"], ["break-b", "leave", "name", "b"], ["break-b", "enter", "selection_set", None], ["break-b", "enter", "field", None], ["break-b", "enter", "name", "x"], ["break-b", "leave", "name", "x"], ["break-b", "leave", "field", None], ["break-b", "leave", "selection_set", None], ["break-b", "leave", "field", None], ] @mark.parametrize("remove_action", (REMOVE, Ellipsis), ids=("REMOVE", "Ellipsis")) def allows_for_editing_on_enter(remove_action): ast = parse("{ a, b, c { a, b, c } }", no_location=True) visited = [] class TestVisitor1(Visitor): @staticmethod def enter(*args): check_visitor_fn_args(ast, *args) node = args[0] if node.kind == "field" and node.name.value == "b": return remove_action class TestVisitor2(Visitor): @staticmethod def enter(*args): check_visitor_fn_args(ast, *args) node = args[0] kind, value = node.kind, get_value(node) visited.append(["enter", kind, value]) @staticmethod def leave(*args): check_visitor_fn_args_edited(ast, *args) node = args[0] kind, value = node.kind, get_value(node) visited.append(["leave", kind, value]) edited_ast = visit(ast, ParallelVisitor([TestVisitor1(), TestVisitor2()])) assert ast == parse("{ a, b, c { a, b, c } }", no_location=True) assert edited_ast == parse("{ a, c { a, c } }", no_location=True) assert visited == [ ["enter", "document", None], ["enter", "operation_definition", None], ["enter", "selection_set", None], ["enter", "field", None], ["enter", "name", "a"], ["leave", "name", "a"], ["leave", "field", None], ["enter", "field", None], ["enter", "name", "c"], ["leave", "name", "c"], ["enter", "selection_set", None], ["enter", "field", None], ["enter", "name", "a"], ["leave", "name", "a"], ["leave", "field", None], ["enter", "field", None], ["enter", "name", "c"], ["leave", "name", "c"], ["leave", "field", None], ["leave", "selection_set", None], ["leave", "field", None], ["leave", "selection_set", None], ["leave", "operation_definition", None], ["leave", "document", None], ] @mark.parametrize("remove_action", (REMOVE, Ellipsis), ids=("REMOVE", "Ellipsis")) def allows_for_editing_on_leave(remove_action): ast = parse("{ a, b, c { a, b, c } }", no_location=True) visited = [] class TestVisitor1(Visitor): @staticmethod def leave(*args): check_visitor_fn_args_edited(ast, *args) node = args[0] if node.kind == "field" and node.name.value == "b": return remove_action class TestVisitor2(Visitor): @staticmethod def enter(*args): check_visitor_fn_args(ast, *args) node = args[0] kind, value = node.kind, get_value(node) visited.append(["enter", kind, value]) @staticmethod def leave(*args): check_visitor_fn_args_edited(ast, *args) node = args[0] kind, value = node.kind, get_value(node) visited.append(["leave", kind, value]) edited_ast = visit(ast, ParallelVisitor([TestVisitor1(), TestVisitor2()])) assert ast == parse("{ a, b, c { a, b, c } }", no_location=True) assert edited_ast == parse("{ a, c { a, c } }", no_location=True) assert visited == [ ["enter", "document", None], ["enter", "operation_definition", None], ["enter", "selection_set", None], ["enter", "field", None], ["enter", "name", "a"], ["leave", "name", "a"], ["leave", "field", None], ["enter", "field", None], ["enter", "name", "b"], ["leave", "name", "b"], ["enter", "field", None], ["enter", "name", "c"], ["leave", "name", "c"], ["enter", "selection_set", None], ["enter", "field", None], ["enter", "name", "a"], ["leave", "name", "a"], ["leave", "field", None], ["enter", "field", None], ["enter", "name", "b"], ["leave", "name", "b"], ["enter", "field", None], ["enter", "name", "c"], ["leave", "name", "c"], ["leave", "field", None], ["leave", "selection_set", None], ["leave", "field", None], ["leave", "selection_set", None], ["leave", "operation_definition", None], ["leave", "document", None], ] graphql-core-3.2.6/tests/pyutils/000077500000000000000000000000001474546154300167765ustar00rootroot00000000000000graphql-core-3.2.6/tests/pyutils/__init__.py000066400000000000000000000000401474546154300211010ustar00rootroot00000000000000"""Tests for graphql.pyutils""" graphql-core-3.2.6/tests/pyutils/test_cached_property.py000066400000000000000000000012711474546154300235630ustar00rootroot00000000000000from graphql.pyutils import cached_property def describe_cached_property(): def works_like_a_normal_property(): class TestClass: @cached_property def value(self): return 42 assert TestClass().value == 42 def caches_the_value(): class TestClass: evaluations = 0 @cached_property def value(self): self.__class__.evaluations += 1 return 42 obj = TestClass() assert TestClass.evaluations == 0 assert obj.value == 42 assert TestClass.evaluations == 1 assert obj.value == 42 assert TestClass.evaluations == 1 graphql-core-3.2.6/tests/pyutils/test_convert_case.py000066400000000000000000000037431474546154300230710ustar00rootroot00000000000000from graphql.pyutils import camel_to_snake, snake_to_camel def describe_camel_to_snake(): def converts_typical_names(): assert camel_to_snake("CamelCase") == "camel_case" assert ( camel_to_snake("InputObjectTypeExtensionNode") == "input_object_type_extension_node" ) assert camel_to_snake("CamelToSnake") == "camel_to_snake" def may_start_with_lowercase(): assert camel_to_snake("camelCase") == "camel_case" def works_with_acronyms(): assert camel_to_snake("SlowXMLParser") == "slow_xml_parser" assert camel_to_snake("FastGraphQLParser") == "fast_graph_ql_parser" def works_with_numbers(): assert camel_to_snake("Python3Script") == "python3_script" assert camel_to_snake("camel2snake") == "camel2snake" def keeps_already_snake(): assert camel_to_snake("snake_case") == "snake_case" def describe_snake_to_camel(): def converts_typical_names(): assert snake_to_camel("snake_case") == "SnakeCase" assert ( snake_to_camel("input_object_type_extension_node") == "InputObjectTypeExtensionNode" ) assert snake_to_camel("snake_to_camel") == "SnakeToCamel" def may_start_with_uppercase(): assert snake_to_camel("Snake_case") == "SnakeCase" def works_with_acronyms(): assert snake_to_camel("slow_xml_parser") == "SlowXmlParser" assert snake_to_camel("fast_graph_ql_parser") == "FastGraphQlParser" def works_with_numbers(): assert snake_to_camel("python3_script") == "Python3Script" assert snake_to_camel("snake2camel") == "Snake2camel" def keeps_already_camel(): assert snake_to_camel("CamelCase") == "CamelCase" def can_produce_lower_camel_case(): assert snake_to_camel("snake_case", upper=False) == "snakeCase" assert ( snake_to_camel("input_object_type_extension_node", False) == "inputObjectTypeExtensionNode" ) graphql-core-3.2.6/tests/pyutils/test_description.py000066400000000000000000000247531474546154300227450ustar00rootroot00000000000000from contextlib import contextmanager from typing import cast from graphql import graphql_sync from graphql.pyutils import ( Description, is_description, register_description, unregister_description, ) from graphql.type import ( GraphQLArgument, GraphQLDirective, GraphQLEnumValue, GraphQLField, GraphQLInputField, GraphQLNamedType, GraphQLObjectType, GraphQLSchema, GraphQLString, ) from graphql.utilities import get_introspection_query, print_schema from pytest import raises from ..utils import dedent class LazyString: def __init__(self, text: object) -> None: self.text = text def __str__(self) -> str: return str(self.text) lazy_string = cast(str, LazyString("Why am I so lazy?")) @contextmanager def registered(base: type): register_description(base) try: yield None finally: unregister_description(base) def describe_description(): def by_default_strings_are_accepted(): is_description("") is_description("text") def by_default_non_strings_are_not_accepted(): assert not is_description(None) assert not is_description(b"bytes") assert not is_description(0) assert not is_description(42) assert not is_description(("tuple",)) assert not is_description(["list"]) def after_registration_lazy_strings_are_accepted(): with registered(LazyString): assert is_description("not lazy") assert is_description(lazy_string) assert not is_description(42) def can_register_and_unregister(): try: assert Description.bases is str register_description(str) assert Description.bases is str register_description(int) assert Description.bases == (str, int) register_description(int) assert Description.bases == (str, int) register_description(float) assert Description.bases == (str, int, float) unregister_description(int) assert Description.bases == (str, float) unregister_description(float) assert Description.bases is str unregister_description(str) assert Description.bases is object register_description(str) assert Description.bases is str register_description(object) assert Description.bases is object Description.bases = (str,) unregister_description(str) assert Description.bases is object unregister_description(str) assert Description.bases is object finally: Description.bases = str def can_only_register_types(): with raises(TypeError, match="Only types can be registered\\."): # noinspection PyTypeChecker register_description("foo") # type: ignore def can_only_unregister_types(): with raises(TypeError, match="Only types can be unregistered\\."): # noinspection PyTypeChecker unregister_description("foo") # type: ignore def describe_graphql_types(): def graphql_named_type(): named_type = GraphQLNamedType(name="Foo", description="not lazy") assert named_type.name == "Foo" assert named_type.description == "not lazy" with raises(TypeError, match="Expected name to be a string\\."): GraphQLNamedType(name=lazy_string) with raises(TypeError, match="The description must be a string\\."): GraphQLNamedType(name="Foo", description=lazy_string) with registered(LazyString): named_type = GraphQLNamedType(name="Foo", description=lazy_string) assert named_type.description is lazy_string assert str(named_type.description).endswith("lazy?") with raises(TypeError, match="Expected name to be a string\\."): GraphQLNamedType(name=lazy_string) def graphql_field(): field = GraphQLField(GraphQLString, description="not lazy") assert field.description == "not lazy" field = GraphQLField(GraphQLString, deprecation_reason="not lazy") assert field.deprecation_reason == "not lazy" with raises(TypeError, match="The description must be a string\\."): GraphQLField(GraphQLString, description=lazy_string) with raises(TypeError, match="The deprecation reason must be a string\\."): GraphQLField(GraphQLString, deprecation_reason=lazy_string) with registered(LazyString): field = GraphQLField( GraphQLString, description=lazy_string, deprecation_reason=lazy_string, ) assert field.description is lazy_string assert str(field.description).endswith("lazy?") assert field.deprecation_reason is lazy_string assert str(field.deprecation_reason).endswith("lazy?") def graphql_argument(): arg = GraphQLArgument(GraphQLString, description="not lazy") assert arg.description == "not lazy" with raises(TypeError, match="Argument description must be a string\\."): GraphQLArgument(GraphQLString, description=lazy_string) with registered(LazyString): arg = GraphQLArgument(GraphQLString, description=lazy_string) assert arg.description is lazy_string assert str(arg.description).endswith("lazy?") def graphql_enum_value(): value = GraphQLEnumValue(description="not lazy") assert value.description == "not lazy" value = GraphQLEnumValue(deprecation_reason="not lazy") assert value.deprecation_reason == "not lazy" with raises( TypeError, match="The description of the enum value must be a string\\." ): GraphQLEnumValue(description=lazy_string) with raises( TypeError, match="The deprecation reason for the enum value must be a string\\.", ): GraphQLEnumValue(deprecation_reason=lazy_string) with registered(LazyString): value = GraphQLEnumValue( description=lazy_string, deprecation_reason=lazy_string ) assert value.description is lazy_string assert str(value.description).endswith("lazy?") assert value.deprecation_reason is lazy_string assert str(value.deprecation_reason).endswith("lazy?") def graphql_input_field(): field = GraphQLInputField(GraphQLString, description="not lazy") assert field.description == "not lazy" with raises(TypeError, match="Input field description must be a string\\."): GraphQLInputField(GraphQLString, description=lazy_string) with registered(LazyString): field = GraphQLInputField(GraphQLString, description=lazy_string) assert field.description is lazy_string assert str(field.description).endswith("lazy?") def graphql_directive(): directive = GraphQLDirective("Foo", [], description="not lazy") assert directive.name == "Foo" assert directive.description == "not lazy" with raises(TypeError, match="Expected name to be a string\\."): GraphQLDirective(lazy_string, []) with raises(TypeError, match="Foo description must be a string\\."): GraphQLDirective("Foo", [], description=lazy_string) with registered(LazyString): directive = GraphQLDirective("Foo", [], description=lazy_string) assert directive.description is lazy_string assert str(directive.description).endswith("lazy?") with raises(TypeError, match="Expected name to be a string\\."): GraphQLDirective(lazy_string, []) def handels_introspection(): class Lazy: def __init__(self, text: str): self.text = text self.evaluated = False def __str__(self) -> str: self.evaluated = True return self.text description = Lazy("a lazy description") deprecation_reason = Lazy("a lazy reason") with registered(Lazy): field = GraphQLField( GraphQLString, description=cast(str, description), deprecation_reason=cast(str, deprecation_reason), ) schema = GraphQLSchema(GraphQLObjectType("Query", {"lazyField": field})) query = get_introspection_query(descriptions=True) assert not description.evaluated assert not deprecation_reason.evaluated result = graphql_sync(schema, query) assert description.evaluated assert deprecation_reason.evaluated assert result.data introspected_query = result.data["__schema"]["types"][0] assert introspected_query["name"] == "Query" introspected_field = introspected_query["fields"][0] assert introspected_field["name"] == "lazyField" assert introspected_field["description"] == "a lazy description" assert introspected_field["deprecationReason"] == "a lazy reason" def handles_printing(): class Lazy: def __init__(self, text: str): self.text = text self.evaluated = False def __str__(self) -> str: self.evaluated = True return self.text description = Lazy("a lazy description") deprecation_reason = Lazy("a lazy reason") with registered(Lazy): field = GraphQLField( GraphQLString, description=cast(str, description), deprecation_reason=cast(str, deprecation_reason), ) schema = GraphQLSchema(GraphQLObjectType("Query", {"lazyField": field})) assert not description.evaluated assert not deprecation_reason.evaluated assert print_schema(schema) == dedent( ''' type Query { """a lazy description""" lazyField: String @deprecated(reason: "a lazy reason") } ''' ) assert description.evaluated assert deprecation_reason.evaluated graphql-core-3.2.6/tests/pyutils/test_did_you_mean.py000066400000000000000000000014011474546154300230370ustar00rootroot00000000000000from graphql.pyutils import did_you_mean def describe_did_you_mean(): def does_accept_an_empty_list(): assert did_you_mean([]) == "" def handles_single_suggestion(): assert did_you_mean(["A"]) == " Did you mean 'A'?" def handles_two_suggestions(): assert did_you_mean(["A", "B"]) == " Did you mean 'A' or 'B'?" def handles_multiple_suggestions(): assert did_you_mean(["A", "B", "C"]) == " Did you mean 'A', 'B', or 'C'?" def limits_to_five_suggestions(): assert ( did_you_mean(["A", "B", "C", "D", "E", "F"]) == " Did you mean 'A', 'B', 'C', 'D', or 'E'?" ) def adds_sub_message(): assert did_you_mean(["A"], "the letter") == " Did you mean the letter 'A'?" graphql-core-3.2.6/tests/pyutils/test_frozen_dict.py000066400000000000000000000054461474546154300227260ustar00rootroot00000000000000from copy import copy, deepcopy from graphql.pyutils import FrozenDict, FrozenError from pytest import raises def describe_frozen_list(): def can_read(): fd = FrozenDict({1: 2, 3: 4}) assert fd == {1: 2, 3: 4} assert list(i for i in fd) == [1, 3] assert fd.copy() == fd assert 3 in fd assert 2 not in fd assert fd[1] == 2 with raises(KeyError): # noinspection PyStatementEffect fd[2] assert len(fd) == 2 assert fd.get(1) == 2 assert fd.get(2, 5) == 5 assert list(fd.items()) == [(1, 2), (3, 4)] assert list(fd.keys()) == [1, 3] assert list(fd.values()) == [2, 4] def cannot_write(): fd = FrozenDict({1: 2, 3: 4}) with raises(FrozenError): fd[1] = 2 with raises(FrozenError): fd[4] = 5 with raises(FrozenError): del fd[1] with raises(FrozenError): del fd[3] with raises(FrozenError): fd.clear() with raises(FrozenError): fd.pop(1) with raises(FrozenError): fd.pop(4, 5) with raises(FrozenError): fd.popitem() with raises(FrozenError): fd.setdefault(1, 2) with raises(FrozenError): fd.setdefault(4, 5) with raises(FrozenError): fd.update({1: 2}) with raises(FrozenError): fd.update({4: 5}) with raises(FrozenError): fd += {4: 5} assert fd == {1: 2, 3: 4} def can_hash(): fd1 = FrozenDict({1: 2, 3: 4}) fd2 = FrozenDict({1: 2, 3: 4}) assert fd2 == fd1 assert fd2 is not fd1 assert hash(fd2) == hash(fd1) fd3 = FrozenDict({1: 2, 3: 5}) assert fd3 != fd1 assert hash(fd3) != hash(fd1) def can_copy(): fd1 = FrozenDict({1: 2, 3: 4}) fd2 = fd1.copy() assert isinstance(fd2, FrozenDict) assert fd2 == fd1 assert hash(fd2) == hash(fd1) assert fd2 is not fd1 fd3 = copy(fd1) assert isinstance(fd3, FrozenDict) assert fd3 == fd1 assert hash(fd3) == hash(fd1) assert fd3 is not fd1 def can_deep_copy(): fd11 = FrozenDict({1: 2, 3: 4}) fd12 = FrozenDict({2: 1, 4: 3}) fd1 = FrozenDict({1: fd11, 2: fd12}) assert fd1[1] is fd11 assert fd1[2] is fd12 fd2 = deepcopy(fd1) assert isinstance(fd2, FrozenDict) assert fd2 == fd1 assert hash(fd2) == hash(fd1) fd21 = fd2[1] fd22 = fd2[2] assert isinstance(fd21, FrozenDict) assert isinstance(fd22, FrozenDict) assert fd21 == fd11 assert fd21 is not fd11 assert fd22 == fd12 assert fd22 is not fd12 graphql-core-3.2.6/tests/pyutils/test_frozen_error.py000066400000000000000000000002371474546154300231250ustar00rootroot00000000000000from graphql.pyutils import FrozenError def describe_frozen_error(): def frozen_error_is_type_error(): assert issubclass(FrozenError, TypeError) graphql-core-3.2.6/tests/pyutils/test_frozen_list.py000066400000000000000000000063011474546154300227450ustar00rootroot00000000000000from copy import copy, deepcopy from pytest import raises from graphql.pyutils import FrozenError, FrozenList def describe_frozen_list(): def can_read(): fl = FrozenList([1, 2, 3]) assert fl == [1, 2, 3] assert list(i for i in fl) == fl assert fl.copy() == fl assert 2 in fl assert 4 not in fl assert fl + [4, 5] == [1, 2, 3, 4, 5] assert [4, 5] + fl == [4, 5, 1, 2, 3] assert fl * 2 == [1, 2, 3, 1, 2, 3] assert 2 * fl == [1, 2, 3, 1, 2, 3] assert fl[1] == 2 with raises(IndexError): fl[3] assert fl[1:4] == [2, 3] assert fl[::2] == [1, 3] assert len(fl) == 3 assert min(fl) == 1 assert max(fl) == 3 assert sum(fl) == 6 assert fl.index(2) == 1 with raises(ValueError): fl.index(4) assert fl.count(2) == 1 assert fl.count(4) == 0 assert list(reversed(fl)) == [3, 2, 1] assert sorted(fl) == [1, 2, 3] def cannot_write(): fl = FrozenList([1, 2, 3]) with raises(FrozenError): fl[1] = 4 with raises(FrozenError): fl[1:4] = [4] with raises(FrozenError): del fl[1] with raises(FrozenError): del fl[1:4] with raises(FrozenError): fl[1::2] = [4] with raises(FrozenError): del fl[::2] with raises(FrozenError): fl.append(4) with raises(FrozenError): fl.clear() with raises(FrozenError): fl.extend([4]) with raises(FrozenError): fl += [4] with raises(FrozenError): fl *= 2 with raises(FrozenError): fl.insert(1, 4) with raises(FrozenError): fl.pop() with raises(FrozenError): fl.remove(2) with raises(FrozenError): fl.sort() with raises(FrozenError): fl.reverse() assert fl == [1, 2, 3] def can_add_rol(): fl1 = FrozenList([1, 2]) rol2 = FrozenList([3, 4]) assert fl1 + rol2 == [1, 2, 3, 4] def can_add_tuple(): fl = FrozenList([1, 2]) assert fl + (3, 4) == [1, 2, 3, 4] def can_hash(): fl1 = FrozenList([1, 2]) fl2 = FrozenList([1, 2]) assert fl2 == fl1 assert fl2 is not fl1 assert hash(fl2) == hash(fl1) fl3 = FrozenList([1, 3]) assert fl3 != fl1 assert hash(fl3) != hash(fl1) def can_copy(): fl1 = FrozenList([1, 2]) fl2 = copy(fl1) assert isinstance(fl2, FrozenList) assert fl2 == fl1 assert hash(fl2) == hash(fl1) assert fl2 is not fl1 def can_deep_copy(): fl11 = FrozenList([1, 2]) fl12 = FrozenList([2, 1]) fl1 = FrozenList([fl11, fl12]) fl2 = deepcopy(fl1) assert isinstance(fl2, FrozenList) assert fl2 == fl1 assert hash(fl2) == hash(fl1) assert isinstance(fl2[0], FrozenList) assert isinstance(fl2[1], FrozenList) assert fl2[0] == fl1[0] assert fl2[0] is not fl1[0] assert fl2[1] == fl1[1] assert fl2[1] is not fl1[1] graphql-core-3.2.6/tests/pyutils/test_group_by.py000066400000000000000000000026201474546154300222350ustar00rootroot00000000000000from graphql.pyutils import group_by def describe_group_by(): def does_accept_an_empty_list(): def key_fn(_x: str) -> str: raise TypeError("Unexpected call of key function.") assert group_by([], key_fn) == {} def does_not_change_order(): def key_fn(_x: int) -> str: return "all" assert group_by([3, 1, 5, 4, 2, 6], key_fn) == { "all": [3, 1, 5, 4, 2, 6], } def can_group_by_odd_and_even(): def key_fn(x: int) -> str: return "odd" if x % 2 else "even" assert group_by([3, 1, 5, 4, 2, 6], key_fn) == { "odd": [3, 1, 5], "even": [4, 2, 6], } def can_group_by_string_length(): def key_fn(s: str) -> int: return len(s) assert group_by( [ "alpha", "beta", "gamma", "delta", "epsilon", "zeta", "eta", "iota", "kapp", "lambda", "my", "ny", "omikron", ], key_fn, ) == { 2: ["my", "ny"], 3: ["eta"], 4: ["beta", "zeta", "iota", "kapp"], 5: ["alpha", "gamma", "delta"], 6: ["lambda"], 7: ["epsilon", "omikron"], } graphql-core-3.2.6/tests/pyutils/test_identity_func.py000066400000000000000000000011731474546154300232550ustar00rootroot00000000000000from graphql.pyutils import identity_func, Undefined def describe_identity_func(): def returns_the_first_argument_it_receives(): assert identity_func() is Undefined assert identity_func(Undefined) is Undefined assert identity_func(None) is None obj = object() assert identity_func(obj) is obj assert identity_func(Undefined, None) is Undefined assert identity_func(None, Undefined) is None assert identity_func(None, Undefined, obj) is None assert identity_func(Undefined, None, obj) is Undefined assert identity_func(obj, None, Undefined) is obj graphql-core-3.2.6/tests/pyutils/test_inspect.py000066400000000000000000000277231474546154300220670ustar00rootroot00000000000000from math import nan, inf from contextlib import contextmanager from importlib import import_module from typing import Any, Dict, FrozenSet, List, Set, Tuple from pytest import mark from graphql.pyutils import inspect, Undefined from graphql.type import ( GraphQLDirective, GraphQLField, GraphQLInt, GraphQLList, GraphQLObjectType, GraphQLNonNull, GraphQLString, ) inspect_module = import_module(inspect.__module__) @contextmanager def increased_recursive_depth(): inspect_module.max_recursive_depth += 1 # type: ignore try: yield inspect finally: inspect_module.max_recursive_depth -= 1 # type: ignore @contextmanager def increased_str_size(): inspect_module.max_str_size *= 2 # type: ignore try: yield inspect finally: inspect_module.max_str_size //= 2 # type: ignore @contextmanager def increased_list_size(): inspect_module.max_list_size *= 2 # type: ignore try: yield inspect finally: inspect_module.max_list_size //= 2 # type: ignore def describe_inspect(): def inspect_invalid(): assert inspect(Undefined) == "Undefined" def inspect_none(): assert inspect(None) == "None" def inspect_boolean(): assert inspect(True) == "True" assert inspect(False) == "False" def inspect_string(): for s in "", "abc", "foo\tbar \u265e\0", "'", "'": assert inspect(s) == repr(s) def overly_large_string(): s = "foo" * 100 r = repr(s) assert inspect(s) == r[:118] + "..." + r[-119:] with increased_str_size(): assert inspect(s) == r def inspect_bytes(): for b in b"", b"abc", b"foo\tbar \x7f\xff\0", b"'", b"'": assert inspect(b) == repr(b) a = bytearray(b) assert inspect(a) == repr(a) def overly_many_bytes(): b = b"foo" * 100 r = repr(b) assert inspect(b) == r[:118] + "..." + r[-119:] a = bytearray(b) r = repr(a) assert inspect(a) == r[:118] + "..." + r[-119:] def inspect_numbers(): assert inspect(0) == "0" assert inspect(0.0) == "0.0" assert inspect(314) == "314" assert inspect(3.14) == "3.14" assert inspect(complex(1, 2)) == "(1+2j)" assert inspect(nan) == "nan" assert inspect(inf) == "inf" assert inspect(-inf) == "-inf" def overly_large_int(): n = int("123" * 100) r = repr(n) assert inspect(n) == r[:118] + "..." + r[-119:] with increased_str_size(): assert inspect(n) == r def inspect_function(): assert inspect(lambda: 0) == "" # pragma: no cover def test_func(): pass assert inspect(test_func) == "" def inspect_exception(): assert inspect(ValueError) == "" assert inspect(ArithmeticError(42)) == "" def inspect_class_and_method(): class TestClass: def test_method(self): pass assert inspect(TestClass) == "" assert inspect(TestClass()) == "" assert inspect(TestClass.test_method) == "" assert inspect(TestClass().test_method) == "" def inspect_unknown_object(): class MetaClass(type): __name__ = "" class TestClass(metaclass=MetaClass): pass assert inspect(TestClass()) == "" def inspect_generator(): def test_generator(): yield None # pragma: no cover assert inspect(test_generator) == "" assert inspect(test_generator()) == "" @mark.asyncio async def inspect_coroutine(): async def test_coroutine(): pass assert inspect(test_coroutine) == "" coroutine_object = test_coroutine() assert inspect(coroutine_object) == "" await coroutine_object # avoid warning def inspect_async_generator(): async def test_async_generator(): yield None # pragma: no cover assert inspect(test_async_generator) == ( "" ) assert inspect(test_async_generator()) == ( "" ) def inspect_lists(): assert inspect([]) == "[]" assert inspect([None]) == "[None]" assert inspect([[None]]) == "[[None]]" assert inspect([1, nan]) == "[1, nan]" assert inspect([["a", "b"], "c"]) == "[['a', 'b'], 'c']" def inspect_overly_large_list(): s: List[int] = list(range(20)) assert inspect(s) == "[0, 1, 2, 3, 4, ..., 16, 17, 18, 19]" with increased_list_size(): assert inspect(s) == repr(s) def inspect_overly_nested_list(): s: List[List[List]] = [[[]]] assert inspect(s) == "[[[]]]" s = [[[1, 2, 3]]] assert inspect(s) == "[[[...]]]" with increased_recursive_depth(): assert inspect(s) == repr(s) def inspect_recursive_list(): s: List[Any] = [1, 2, 3] s[1] = s assert inspect(s) == "[1, [...], 3]" def inspect_tuples(): assert inspect(()) == "()" assert inspect((None,)) == "(None,)" assert inspect(((None,),)) == "((None,),)" assert inspect((1, nan)) == "(1, nan)" assert inspect((("a", "b"), "c")) == "(('a', 'b'), 'c')" def inspect_overly_large_tuple(): s = tuple(range(20)) assert inspect(s) == "(0, 1, 2, 3, 4, ..., 16, 17, 18, 19)" with increased_list_size(): assert inspect(s) == repr(s) def inspect_overly_nested_tuple(): s: Tuple[Tuple[Tuple]] = (((),),) assert inspect(s) == "(((),),)" s = (((1, 2, 3),),) assert inspect(s) == "(((...),),)" with increased_recursive_depth(): assert inspect(s) == repr(s) def inspect_recursive_tuple(): s: List[Any] = [1, 2, 3] s[1] = s t = tuple(s) assert inspect(t) == "(1, [1, [...], 3], 3)" def mixed_lists_and_tuples(): assert inspect(["a", ("b",)]) == "['a', ('b',)]" def mixed_lists_and_tuples_with_various_objects(): class TestClass: pass assert inspect([TestClass, (TestClass,), ValueError()]) == ( "[, (,), ]" ) def inspect_dicts(): assert inspect({}) == "{}" assert inspect({"a": 1}) == "{'a': 1}" assert inspect({"a": 1, "b": 2}) == "{'a': 1, 'b': 2}" assert inspect({"list": [None, 0]}) == "{'list': [None, 0]}" assert inspect({"a": True, "b": None}) == "{'a': True, 'b': None}" def inspect_overly_large_dict(): s = dict(zip((chr(97 + i) for i in range(20)), range(20))) assert ( inspect(s) == "{'a': 0, 'b': 1, 'c': 2, 'd': 3, 'e': 4," " ..., 'q': 16, 'r': 17, 's': 18, 't': 19}" ) with increased_list_size(): assert inspect(s) == repr(s) def inspect_overly_nested_dict(): s: Dict[str, Dict[str, Dict]] = {"a": {"b": {}}} assert inspect(s) == "{'a': {'b': {}}}" s = {"a": {"b": {"c": 3}}} assert inspect(s) == "{'a': {'b': {...}}}" with increased_recursive_depth(): assert inspect(s) == repr(s) def inspect_recursive_dict(): s: Dict[int, Any] = {} s[1] = s assert inspect(s) == "{1: {...}}" def inspect_sets(): assert inspect(set()) == "set()" assert inspect({"a"}) == "{'a'}" assert inspect({"a", 1}) in ("{'a', 1}", "{1, 'a'}") # sets are unordered def inspect_overly_large_set(): s = set(range(20)) r = inspect(s) assert r.startswith("{") and r.endswith("}") assert "..., " in r and "5" not in s # sets are unordered assert len(r) == 36 with increased_list_size(): assert inspect(s) == repr(s) def inspect_overly_nested_set(): s: List[List[Set]] = [[set()]] assert inspect(s) == "[[set()]]" s = [[{1, 2, 3}]] assert inspect(s) == "[[set(...)]]" with increased_recursive_depth(): assert inspect(s) == repr(s) def inspect_frozensets(): assert inspect(frozenset()) == "frozenset()" assert inspect(frozenset(["a"])) == "frozenset({'a'})" assert inspect(frozenset(["a", 1])) in ( "frozenset({'a', 1})", "frozenset({1, 'a'})", ) # frozensets are unordered def inspect_overly_large_frozenset(): s = frozenset(range(20)) r = inspect(s) assert r.startswith("frozenset({") and r.endswith("})") assert "..., " in r and "5" not in s # frozensets are unordered assert len(r) == 47 with increased_list_size(): assert inspect(s) == repr(s) def inspect_overly_nested_frozenset(): s: FrozenSet[FrozenSet[FrozenSet]] = frozenset([frozenset([frozenset()])]) assert inspect(s) == "frozenset({frozenset({frozenset()})})" s = frozenset([frozenset([frozenset([1, 2, 3])])]) assert inspect(s) == "frozenset({frozenset({frozenset(...)})})" with increased_recursive_depth(): assert inspect(s) == repr(s) def mixed_recursive_dict_and_list(): s: Any = {1: []} s[1].append(s) assert inspect(s) == "{1: [{...}]}" s = [1, 2, 3] s[1] = {2: s} assert inspect(s) == "[1, {2: [...]}, 3]" def mixed_dicts_and_sets(): assert inspect({"a": {"b"}}) == "{'a': {'b'}}" assert inspect({1: [], 2: (), 3: set()}) == "{1: [], 2: (), 3: set()}" assert inspect([(set(),), {None: {()}}]) == "[(set(),), {None: set(...)}]" def mixed_dicts_and_sets_with_various_objects(): class TestClass: pass assert inspect({TestClass: {ValueError()}, ValueError: {TestClass()}}) == ( "{: {}," " : {}}" ) def inspect_graphql_types(): assert inspect(GraphQLInt) == "Int" assert inspect(GraphQLString) == "String" assert inspect(GraphQLNonNull(GraphQLString)) == "String!" assert inspect(GraphQLList(GraphQLString)) == "[String]" test_object_type = GraphQLObjectType( "TestObjectType", {"test": GraphQLField(GraphQLString)} ) assert inspect(test_object_type) == "TestObjectType" test_directive = GraphQLDirective("TestDirective", []) assert inspect(test_directive) == "@TestDirective" def custom_inspect(): class TestClass: @staticmethod def __inspect__(): return "" assert inspect(TestClass()) == "" def custom_inspect_that_uses_self(): class TestClass: str = "Hello World!" def __inspect__(self): return self.str assert inspect(TestClass()) == "Hello World!" def custom_inspect_that_returns_a_list(): class TestClass: @staticmethod def __inspect__(): return [1, 2, 3] assert inspect(TestClass()) == "[1, 2, 3]" def custom_inspect_that_returns_an_overly_large_string(): s = "foo" * 100 class TestClass: @staticmethod def __inspect__(): return s value = TestClass() assert inspect(value) == s[:118] + "..." + s[-119:] with increased_str_size(): assert inspect(value) == s def custom_inspect_that_is_recursive(): class TestClass: def __inspect__(self): return self assert inspect(TestClass()) == "" graphql-core-3.2.6/tests/pyutils/test_is_awaitable.py000066400000000000000000000065171474546154300230440ustar00rootroot00000000000000import asyncio import sys from inspect import isawaitable from graphql.pyutils import is_awaitable from pytest import mark def describe_is_awaitable(): def declines_the_none_value(): assert not isawaitable(None) assert not is_awaitable(None) def declines_a_boolean_value(): assert not isawaitable(True) assert not is_awaitable(True) def declines_an_int_value(): assert not is_awaitable(42) def declines_a_string_value(): assert not isawaitable("some_string") assert not is_awaitable("some_string") def declines_a_dict_value(): assert not isawaitable({}) assert not is_awaitable({}) def declines_an_object_instance(): assert not isawaitable(object()) assert not is_awaitable(object()) def declines_the_type_class(): assert not isawaitable(type) assert not is_awaitable(type) def declines_a_lambda_function(): assert not isawaitable(lambda: True) # pragma: no cover assert not is_awaitable(lambda: True) # pragma: no cover def declines_a_normal_function(): def some_function(): return True assert not isawaitable(some_function()) assert not is_awaitable(some_function) def declines_a_normal_generator_function(): def some_generator(): yield True # pragma: no cover assert not isawaitable(some_generator) assert not is_awaitable(some_generator) def declines_a_normal_generator_object(): def some_generator(): yield True # pragma: no cover assert not isawaitable(some_generator()) assert not is_awaitable(some_generator()) def declines_a_coroutine_function(): async def some_coroutine(): return True # pragma: no cover assert not isawaitable(some_coroutine) assert not is_awaitable(some_coroutine) @mark.asyncio @mark.filterwarnings("ignore:.* was never awaited:RuntimeWarning") async def recognizes_a_coroutine_object(): async def some_coroutine(): return False # pragma: no cover assert isawaitable(some_coroutine()) assert is_awaitable(some_coroutine()) @mark.filterwarnings("ignore::Warning") # Deprecation and Runtime @mark.skipif( sys.version_info >= (3, 11), reason="Generator-based coroutines not supported after Python 3.11", ) def recognizes_an_old_style_coroutine(): # pragma: no cover @asyncio.coroutine def some_old_style_coroutine(): yield False # pragma: no cover assert is_awaitable(some_old_style_coroutine()) assert is_awaitable(some_old_style_coroutine()) @mark.asyncio @mark.filterwarnings("ignore:.* was never awaited:RuntimeWarning") async def recognizes_a_future_object(): async def some_coroutine(): return False # pragma: no cover some_future = asyncio.ensure_future(some_coroutine()) assert is_awaitable(some_future) assert is_awaitable(some_future) @mark.filterwarnings("ignore:.* was never awaited:RuntimeWarning") def declines_an_async_generator(): async def some_async_generator(): yield True # pragma: no cover assert not isawaitable(some_async_generator()) assert not is_awaitable(some_async_generator()) graphql-core-3.2.6/tests/pyutils/test_is_iterable.py000066400000000000000000000207741474546154300227030ustar00rootroot00000000000000from array import array from collections import defaultdict, namedtuple from decimal import Decimal from itertools import count from graphql.pyutils import FrozenDict, FrozenList, is_collection, is_iterable def describe_is_collection(): def should_return_true_for_lists(): assert is_collection([]) is True assert is_collection([0, 1, 2]) is True assert is_collection(["A", "B", "C"]) is True def should_return_true_for_frozen_lists(): assert is_collection(FrozenList()) is True assert is_collection(FrozenList([0, 1, 2])) is True assert is_collection(FrozenList(["A", "B", "C"])) is True def should_return_true_for_tuples(): assert is_collection(()) is True assert is_collection((0, 1, 1)) is True assert is_collection(("A", "B", "C")) is True def should_return_true_for_named_tuples(): named = namedtuple("named", "A B C") assert is_collection(named(0, 1, 2)) is True def should_return_true_for_arrays(): assert is_collection(array("b")) is True assert is_collection(array("b", [0, 1, 2])) is True assert is_collection(array("i")) is True assert is_collection(array("i", [0, 1, 2])) is True def should_return_true_for_keys_view(): assert is_collection({}.keys()) is True assert is_collection({0: "A", 1: "B", 2: "C"}.keys()) is True def should_return_true_for_values_view(): assert is_collection({}.values()) is True assert is_collection({0: "A", 1: "B", 2: "C"}.values()) is True def should_return_true_for_ranges(): assert is_collection(range(10)) is True def should_return_false_for_range_function(): assert is_collection(range) is False def should_return_false_for_generator_function(): assert is_collection(count) is False def should_return_false_for_infinite_generators(): assert is_collection(count()) is False def should_return_false_for_none_object(): assert is_collection(None) is False def should_return_false_for_strings(): assert is_collection("ABC") is False assert is_collection("0") is False assert is_collection("") is False def should_return_false_for_byte_strings(): assert is_collection(b"ABC") is False assert is_collection(b"0") is False assert is_collection(b"") is False def should_return_false_for_ints(): assert is_collection(1) is False assert is_collection(-1) is False assert is_collection(0) is False def should_return_false_for_floats(): assert is_collection(1.0) is False assert is_collection(-1.0) is False assert is_collection(0.0) is False assert is_collection(float("NaN")) is False assert is_collection(float("Inf")) is False assert is_collection(float("-Inf")) is False def should_return_false_for_decimals(): assert is_collection(Decimal("1.0")) is False assert is_collection(Decimal("-1.0")) is False assert is_collection(Decimal("0.0")) is False assert is_collection(Decimal("NaN")) is False assert is_collection(Decimal("Inf")) is False assert is_collection(Decimal("-Inf")) is False def should_return_false_for_booleans(): assert is_collection(True) is False assert is_collection(False) is False def should_return_true_for_sets(): assert is_collection(set()) is True assert is_collection({0, 1, 2}) is True assert is_collection({"A", "B", "C"}) is True def should_return_false_for_dicts(): assert is_collection({}) is False assert is_collection({"__iter__": True}) is False assert is_collection({0: "A", 1: "B", 2: "C"}) is False def should_return_false_for_frozen_dicts(): assert is_collection(FrozenDict()) is False assert is_collection(FrozenDict({"__iter__": True})) is False assert is_collection(FrozenDict({0: "A", 1: "B", 2: "C"})) is False def should_return_false_for_default_dicts(): assert is_collection(defaultdict(list)) is False def should_return_false_for_simple_objects(): assert is_collection(object) is False assert is_collection(object()) is False def should_return_false_for_invalid_iterator_object(): class NoIterator: __iter__ = None assert is_collection(NoIterator) is False assert is_collection(NoIterator()) is False def describe_is_iterable(): def should_return_true_for_lists(): assert is_iterable([]) is True assert is_iterable([0, 1, 2]) is True assert is_iterable(["A", "B", "C"]) is True def should_return_true_for_frozen_lists(): assert is_iterable(FrozenList()) is True assert is_iterable(FrozenList([0, 1, 2])) is True assert is_iterable(FrozenList(["A", "B", "C"])) is True def should_return_true_for_tuples(): assert is_iterable(()) is True assert is_iterable((0, 1, 1)) is True assert is_iterable(("A", "B", "C")) is True def should_return_true_for_named_tuples(): named = namedtuple("named", "a b c") assert is_iterable(named(0, 1, 2)) is True def should_return_true_for_arrays(): assert is_iterable(array("b")) is True assert is_iterable(array("b", [0, 1, 2])) is True assert is_iterable(array("i")) is True assert is_iterable(array("i", [0, 1, 2])) is True def should_return_true_for_keys_view(): assert is_iterable({}.keys()) is True assert is_iterable({0: "A", 1: "B", 2: "C"}.keys()) is True def should_return_true_for_values_view(): assert is_iterable({}.values()) is True assert is_iterable({0: "A", 1: "B", 2: "C"}.values()) is True def should_return_true_for_ranges(): assert is_iterable(range(10)) is True def should_return_false_for_range_function(): assert is_iterable(range) is False def should_return_false_for_generator_function(): assert is_iterable(count) is False def should_return_true_for_infinite_generators(): assert is_iterable(count()) is True def should_return_false_for_none_object(): assert is_iterable(None) is False def should_return_false_for_strings(): assert is_iterable("ABC") is False assert is_iterable("0") is False assert is_iterable("") is False def should_return_false_for_byte_strings(): assert is_iterable(b"ABC") is False assert is_iterable(b"0") is False assert is_iterable(b"") is False def should_return_false_for_ints(): assert is_iterable(1) is False assert is_iterable(-1) is False assert is_iterable(0) is False def should_return_false_for_floats(): assert is_iterable(1.0) is False assert is_iterable(-1.0) is False assert is_iterable(0.0) is False assert is_iterable(float("NaN")) is False assert is_iterable(float("Inf")) is False assert is_iterable(float("-Inf")) is False def should_return_false_for_decimals(): assert is_iterable(Decimal("1.0")) is False assert is_iterable(Decimal("-1.0")) is False assert is_iterable(Decimal("0.0")) is False assert is_iterable(Decimal("NaN")) is False assert is_iterable(Decimal("Inf")) is False assert is_iterable(Decimal("-Inf")) is False def should_return_false_for_booleans(): assert is_iterable(True) is False assert is_iterable(False) is False def should_return_true_for_sets(): assert is_iterable(set()) is True assert is_iterable({0, 1, 2}) is True assert is_iterable({"A", "B", "C"}) is True def should_return_false_for_dicts(): assert is_iterable({}) is False assert is_iterable({"__iter__": True}) is False assert is_iterable({0: "A", 1: "B", 2: "C"}) is False def should_return_false_for_frozen_dicts(): assert is_iterable(FrozenDict()) is False assert is_iterable(FrozenDict({"__iter__": True})) is False assert is_iterable(FrozenDict({0: "A", 1: "B", 2: "C"})) is False def should_return_false_for_default_dicts(): assert is_iterable(defaultdict(list)) is False def should_return_false_for_simple_objects(): assert is_iterable(object) is False assert is_iterable(object()) is False def should_return_false_for_invalid_iterator_object(): class NoIterator: __iter__ = None assert is_iterable(NoIterator) is False assert is_iterable(NoIterator()) is False graphql-core-3.2.6/tests/pyutils/test_merge_kwargs.py000066400000000000000000000011351474546154300230640ustar00rootroot00000000000000from graphql.pyutils import merge_kwargs try: from typing import TypedDict except ImportError: # Python < 3.8 from typing_extensions import TypedDict class FooDict(TypedDict): foo: str bar: str baz: int def describe_merge_kwargs(): def should_merge_with_no_kwargs(): base = FooDict(foo="foo", bar="bar", baz=0) assert merge_kwargs(base) == base def should_merge_with_kwargs(): base = FooDict(foo="foo", bar="bar", baz=0) assert merge_kwargs(base, foo="moo", bar="mar", baz=1) == FooDict( foo="moo", bar="mar", baz=1 ) graphql-core-3.2.6/tests/pyutils/test_natural_compare.py000066400000000000000000000015331474546154300235650ustar00rootroot00000000000000from graphql.pyutils import natural_comparison_key key = natural_comparison_key def describe_natural_compare(): def handles_empty_strings(): assert key("") < key("a") assert key("") < key("1") def handles_strings_of_different_length(): assert key("A") < key("AA") assert key("A1") < key("A1A") def handles_numbers(): assert key("1") < key("2") assert key("2") < key("11") def handles_numbers_with_leading_zeros(): assert key("0") < key("00") assert key("02") < key("11") assert key("011") < key("200") def handles_numbers_embedded_into_names(): assert key("a0a") < key("a9a") assert key("a00a") < key("a09a") assert key("a0a1") < key("a0a9") assert key("a10a11a") < key("a10a19a") assert key("a10a11a") < key("a10a11b") graphql-core-3.2.6/tests/pyutils/test_path.py000066400000000000000000000014261474546154300213460ustar00rootroot00000000000000from graphql.pyutils import Path def describe_path(): def can_create_a_path(): first = Path(None, 1, "First") assert first.prev is None assert first.key == 1 assert first.typename == "First" def can_add_a_new_key_to_an_existing_path(): first = Path(None, 1, "First") second = first.add_key("two", "Second") assert second.prev is first assert second.key == "two" assert second.typename == "Second" def can_convert_a_path_to_a_list_of_its_keys(): root = Path(None, 0, "Root") assert root.as_list() == [0] first = root.add_key("one", "First") assert first.as_list() == [0, "one"] second = first.add_key(2, "Second") assert second.as_list() == [0, "one", 2] graphql-core-3.2.6/tests/pyutils/test_print_path_list.py000066400000000000000000000006521474546154300236150ustar00rootroot00000000000000from graphql.pyutils import print_path_list def describe_print_path_as_list(): def without_key(): assert print_path_list([]) == "" def with_one_key(): assert print_path_list(["one"]) == ".one" assert print_path_list([1]) == "[1]" def with_three_keys(): assert print_path_list([0, "one", 2]) == "[0].one[2]" assert print_path_list(["one", 2, "three"]) == ".one[2].three" graphql-core-3.2.6/tests/pyutils/test_simple_pub_sub.py000066400000000000000000000056371474546154300234320ustar00rootroot00000000000000from asyncio import sleep from inspect import isawaitable from pytest import mark, raises from graphql.pyutils import SimplePubSub def describe_simple_pub_sub(): @mark.asyncio async def subscribe_async_iterator_mock(): pubsub = SimplePubSub() iterator = pubsub.get_subscriber() # Queue up publishes assert pubsub.emit("Apple") is True assert pubsub.emit("Banana") is True # Read payloads assert await iterator.__anext__() == "Apple" assert await iterator.__anext__() == "Banana" # Read ahead i3 = await iterator.__anext__() assert isawaitable(i3) i4 = await iterator.__anext__() assert isawaitable(i4) # Publish assert pubsub.emit("Coconut") is True assert pubsub.emit("Durian") is True # Await out of order to get correct results assert await i4 == "Durian" assert await i3 == "Coconut" # Read ahead i5 = iterator.__anext__() # Terminate queue await iterator.aclose() # Publish is not caught after terminate assert pubsub.emit("Fig") is False # Find that cancelled read-ahead got a "done" result with raises(StopAsyncIteration): await i5 # And next returns empty completion value with raises(StopAsyncIteration): await iterator.__anext__() @mark.asyncio async def iterator_aclose_empties_push_queue(): pubsub = SimplePubSub() assert not pubsub.subscribers iterator = pubsub.get_subscriber() assert len(pubsub.subscribers) == 1 assert iterator.listening for value in range(3): pubsub.emit(value) await sleep(0) assert iterator.push_queue.qsize() == 3 assert iterator.pull_queue.qsize() == 0 await iterator.aclose() assert not pubsub.subscribers assert iterator.push_queue.qsize() == 0 assert iterator.pull_queue.qsize() == 0 assert not iterator.listening @mark.asyncio async def iterator_aclose_empties_pull_queue(): pubsub = SimplePubSub() assert not pubsub.subscribers iterator = pubsub.get_subscriber() assert len(pubsub.subscribers) == 1 assert iterator.listening for _n in range(3): await iterator.__anext__() assert iterator.push_queue.qsize() == 0 assert iterator.pull_queue.qsize() == 3 await iterator.aclose() assert not pubsub.subscribers assert iterator.push_queue.qsize() == 0 assert iterator.pull_queue.qsize() == 0 assert not iterator.listening @mark.asyncio async def iterator_aclose_is_idempotent(): pubsub = SimplePubSub() iterator = pubsub.get_subscriber() assert iterator.listening for n in range(3): await iterator.aclose() assert not iterator.listening graphql-core-3.2.6/tests/pyutils/test_suggestion_list.py000066400000000000000000000042561474546154300236400ustar00rootroot00000000000000from typing import List from graphql.pyutils import suggestion_list def expect_suggestions(input_: str, options: List[str], expected: List[str]) -> None: assert suggestion_list(input_, options) == expected def describe_suggestion_list(): def returns_results_when_input_is_empty(): expect_suggestions("", ["a"], ["a"]) def returns_empty_array_when_there_are_no_options(): expect_suggestions("input", [], []) def returns_options_with_small_lexical_distance(): expect_suggestions("greenish", ["green"], ["green"]) expect_suggestions("green", ["greenish"], ["greenish"]) def rejects_options_with_distance_that_exceeds_threshold(): expect_suggestions("aaaa", ["aaab"], ["aaab"]) expect_suggestions("aaaa", ["aabb"], ["aabb"]) expect_suggestions("aaaa", ["abbb"], []) expect_suggestions("ab", ["ca"], []) def returns_options_with_different_case(): expect_suggestions("verylongstring", ["VERYLONGSTRING"], ["VERYLONGSTRING"]) expect_suggestions("VERYLONGSTRING", ["verylongstring"], ["verylongstring"]) expect_suggestions("VERYLONGSTRING", ["VeryLongString"], ["VeryLongString"]) def returns_options_with_transpositions(): expect_suggestions("agr", ["arg"], ["arg"]) expect_suggestions("214365879", ["123456789"], ["123456789"]) def returns_options_sorted_based_on_lexical_distance(): expect_suggestions("abc", ["a", "ab", "abc"], ["abc", "ab", "a"]) expect_suggestions( "GraphQl", ["graphics", "SQL", "GraphQL", "quarks", "mark"], ["GraphQL", "graphics"], ) def returns_options_with_the_same_lexical_distance_sorted_naturally(): expect_suggestions("a", ["az", "ax", "ay"], ["ax", "ay", "az"]) expect_suggestions("boo", ["moo", "foo", "zoo"], ["foo", "moo", "zoo"]) expect_suggestions("abc", ["a1", "a12", "a2"], ["a1", "a2", "a12"]) def returns_options_sorted_first_by_lexical_distance_then_naturally(): expect_suggestions( "csutomer", ["store", "customer", "stomer", "some", "more"], ["customer", "stomer", "some", "store"], ) graphql-core-3.2.6/tests/pyutils/test_undefined.py000066400000000000000000000014551474546154300223550ustar00rootroot00000000000000from graphql.pyutils import Undefined def describe_invalid(): def has_repr(): assert repr(Undefined) == "Undefined" def has_str(): assert str(Undefined) == "Undefined" def is_hashable(): assert hash(Undefined) == hash(Undefined) assert hash(Undefined) != hash(None) assert hash(Undefined) != hash(False) assert hash(Undefined) != hash(True) def as_bool_is_false(): assert bool(Undefined) is False def only_equal_to_itself(): assert Undefined == Undefined assert not Undefined != Undefined none_object = None assert Undefined != none_object assert not Undefined == none_object false_object = False assert Undefined != false_object assert not Undefined == false_object graphql-core-3.2.6/tests/star_wars_data.py000066400000000000000000000073721474546154300206460ustar00rootroot00000000000000"""This defines a basic set of data for our Star Wars Schema. This data is hard coded for the sake of the demo, but you could imagine fetching this data from a backend service rather than from hardcoded JSON objects in a more complex demo. """ from typing import Awaitable, Collection, Dict, Iterator, Optional __all__ = ["get_droid", "get_friends", "get_hero", "get_human", "get_secret_backstory"] # These are classes which correspond to the schema. # They represent the shape of the data visited during field resolution. class Character: id: str name: str friends: Collection[str] appearsIn: Collection[str] # noinspection PyPep8Naming class Human(Character): type = "Human" homePlanet: str # noinspection PyShadowingBuiltins def __init__(self, id, name, friends, appearsIn, homePlanet): self.id, self.name = id, name self.friends, self.appearsIn = friends, appearsIn self.homePlanet = homePlanet # noinspection PyPep8Naming class Droid(Character): type = "Droid" primaryFunction: str # noinspection PyShadowingBuiltins def __init__(self, id, name, friends, appearsIn, primaryFunction): self.id, self.name = id, name self.friends, self.appearsIn = friends, appearsIn self.primaryFunction = primaryFunction luke = Human( id="1000", name="Luke Skywalker", friends=["1002", "1003", "2000", "2001"], appearsIn=[4, 5, 6], homePlanet="Tatooine", ) vader = Human( id="1001", name="Darth Vader", friends=["1004"], appearsIn=[4, 5, 6], homePlanet="Tatooine", ) han = Human( id="1002", name="Han Solo", friends=["1000", "1003", "2001"], appearsIn=[4, 5, 6], homePlanet=None, ) leia = Human( id="1003", name="Leia Organa", friends=["1000", "1002", "2000", "2001"], appearsIn=[4, 5, 6], homePlanet="Alderaan", ) tarkin = Human( id="1004", name="Wilhuff Tarkin", friends=["1001"], appearsIn=[4], homePlanet=None ) human_data: Dict[str, Human] = { "1000": luke, "1001": vader, "1002": han, "1003": leia, "1004": tarkin, } threepio = Droid( id="2000", name="C-3PO", friends=["1000", "1002", "1003", "2001"], appearsIn=[4, 5, 6], primaryFunction="Protocol", ) artoo = Droid( id="2001", name="R2-D2", friends=["1000", "1002", "1003"], appearsIn=[4, 5, 6], primaryFunction="Astromech", ) droid_data: Dict[str, Droid] = {"2000": threepio, "2001": artoo} # noinspection PyShadowingBuiltins async def get_character(id: str) -> Optional[Character]: """Helper function to get a character by ID.""" # We use an async function just to illustrate that GraphQL-core supports it. return human_data.get(id) or droid_data.get(id) def get_friends(character: Character) -> Iterator[Awaitable[Optional[Character]]]: """Allows us to query for a character's friends.""" # Notice that GraphQL-core accepts iterators of awaitables. return map(get_character, character.friends) def get_hero(episode: int) -> Character: """Allows us to fetch the undisputed hero of the trilogy, R2-D2.""" if episode == 5: # Luke is the hero of Episode V. return luke # Artoo is the hero otherwise. return artoo # noinspection PyShadowingBuiltins def get_human(id: str) -> Optional[Human]: """Allows us to query for the human with the given id.""" return human_data.get(id) # noinspection PyShadowingBuiltins def get_droid(id: str) -> Optional[Droid]: """Allows us to query for the droid with the given id.""" return droid_data.get(id) # noinspection PyUnusedLocal def get_secret_backstory(character: Character) -> str: """Raise an error when attempting to get the secret backstory.""" raise RuntimeError("secretBackstory is secret.") graphql-core-3.2.6/tests/star_wars_schema.py000066400000000000000000000172761474546154300212010ustar00rootroot00000000000000"""Star Wars GraphQL schema This is designed to be an end-to-end test, demonstrating the full GraphQL stack. We will create a GraphQL schema that describes the major characters in the original Star Wars trilogy. NOTE: This may contain spoilers for the original Star Wars trilogy. Using our shorthand to describe type systems, the type system for our Star Wars example is:: enum Episode { NEW_HOPE, EMPIRE, JEDI } interface Character { id: String! name: String friends: [Character] appearsIn: [Episode] } type Human implements Character { id: String! name: String friends: [Character] appearsIn: [Episode] homePlanet: String } type Droid implements Character { id: String! name: String friends: [Character] appearsIn: [Episode] primaryFunction: String } type Query { hero(episode: Episode): Character human(id: String!): Human droid(id: String!): Droid } """ from graphql.type import ( GraphQLArgument, GraphQLEnumType, GraphQLEnumValue, GraphQLField, GraphQLInterfaceType, GraphQLList, GraphQLNonNull, GraphQLObjectType, GraphQLSchema, GraphQLString, ) from tests.star_wars_data import ( get_droid, get_friends, get_hero, get_human, get_secret_backstory, ) __all__ = ["star_wars_schema"] # We begin by setting up our schema. # The original trilogy consists of three movies. # # This implements the following type system shorthand: # enum Episode { NEW_HOPE, EMPIRE, JEDI } episode_enum = GraphQLEnumType( "Episode", { "NEW_HOPE": GraphQLEnumValue(4, description="Released in 1977."), "EMPIRE": GraphQLEnumValue(5, description="Released in 1980."), "JEDI": GraphQLEnumValue(6, description="Released in 1983."), }, description="One of the films in the Star Wars Trilogy", ) # Characters in the Star Wars trilogy are either humans or droids. # # This implements the following type system shorthand: # interface Character { # id: String! # name: String # friends: [Character] # appearsIn: [Episode] # secretBackstory: String human_type: GraphQLObjectType droid_type: GraphQLObjectType character_interface: GraphQLInterfaceType = GraphQLInterfaceType( "Character", lambda: { "id": GraphQLField( GraphQLNonNull(GraphQLString), description="The id of the character." ), "name": GraphQLField(GraphQLString, description="The name of the character."), "friends": GraphQLField( GraphQLList(character_interface), description="The friends of the character," " or an empty list if they have none.", ), "appearsIn": GraphQLField( GraphQLList(episode_enum), description="Which movies they appear in." ), "secretBackstory": GraphQLField( GraphQLString, description="All secrets about their past." ), }, resolve_type=lambda character, _info, _type: { "Human": human_type.name, "Droid": droid_type.name, }[character.type], description="A character in the Star Wars Trilogy", ) # We define our human type, which implements the character interface. # # This implements the following type system shorthand: # type Human : Character { # id: String! # name: String # friends: [Character] # appearsIn: [Episode] # secretBackstory: String # } human_type = GraphQLObjectType( "Human", lambda: { "id": GraphQLField( GraphQLNonNull(GraphQLString), description="The id of the human." ), "name": GraphQLField(GraphQLString, description="The name of the human."), "friends": GraphQLField( GraphQLList(character_interface), description="The friends of the human," " or an empty list if they have none.", resolve=lambda human, _info: get_friends(human), ), "appearsIn": GraphQLField( GraphQLList(episode_enum), description="Which movies they appear in." ), "homePlanet": GraphQLField( GraphQLString, description="The home planet of the human, or null if unknown.", ), "secretBackstory": GraphQLField( GraphQLString, resolve=lambda human, _info: get_secret_backstory(human), description="Where are they from and how they came to be who they are.", ), }, interfaces=[character_interface], description="A humanoid creature in the Star Wars universe.", ) # The other type of character in Star Wars is a droid. # # This implements the following type system shorthand: # type Droid : Character { # id: String! # name: String # friends: [Character] # appearsIn: [Episode] # secretBackstory: String # primaryFunction: String # } droid_type = GraphQLObjectType( "Droid", lambda: { "id": GraphQLField( GraphQLNonNull(GraphQLString), description="The id of the droid." ), "name": GraphQLField(GraphQLString, description="The name of the droid."), "friends": GraphQLField( GraphQLList(character_interface), description="The friends of the droid," " or an empty list if they have none.", resolve=lambda droid, _info: get_friends(droid), ), "appearsIn": GraphQLField( GraphQLList(episode_enum), description="Which movies they appear in." ), "secretBackstory": GraphQLField( GraphQLString, resolve=lambda droid, _info: get_secret_backstory(droid), description="Construction date and the name of the designer.", ), "primaryFunction": GraphQLField( GraphQLString, description="The primary function of the droid." ), }, interfaces=[character_interface], description="A mechanical creature in the Star Wars universe.", ) # This is the type that will be the root of our query, and the # entry point into our schema. It gives us the ability to fetch # objects by their IDs, as well as to fetch the undisputed hero # of the Star Wars trilogy, R2-D2, directly. # # This implements the following type system shorthand: # type Query { # hero(episode: Episode): Character # human(id: String!): Human # droid(id: String!): Droid # } # noinspection PyShadowingBuiltins query_type = GraphQLObjectType( "Query", lambda: { "hero": GraphQLField( character_interface, args={ "episode": GraphQLArgument( episode_enum, description=( "If omitted, returns the hero of the whole saga." " If provided, returns the hero of that particular episode." ), ) }, resolve=lambda _source, _info, episode=None: get_hero(episode), ), "human": GraphQLField( human_type, args={ "id": GraphQLArgument( GraphQLNonNull(GraphQLString), description="id of the human" ) }, resolve=lambda _source, _info, id: get_human(id), ), "droid": GraphQLField( droid_type, args={ "id": GraphQLArgument( GraphQLNonNull(GraphQLString), description="id of the droid" ) }, resolve=lambda _source, _info, id: get_droid(id), ), }, ) # Finally, we construct our schema (whose starting query type is the query # type we defined above) and export it. star_wars_schema = GraphQLSchema(query_type, types=[human_type, droid_type]) graphql-core-3.2.6/tests/test_docs.py000066400000000000000000000323541474546154300176350ustar00rootroot00000000000000"""Test all code snippets in the documentation""" from pathlib import Path from typing import Any, Dict, List from .utils import dedent Scope = Dict[str, Any] def get_snippets(source, indent=4): """Get all code snippets from a given documentation source file.""" if not source.endswith(".rst"): # pragma: no cover source += ".rst" source_path = Path(__file__).parents[1] / "docs" / source lines = open(source_path).readlines() snippets: List[str] = [] snippet: List[str] = [] snippet_start = " " * indent for line in lines: if not line.rstrip() and snippet: snippet.append(line) elif line.startswith(snippet_start): snippet.append(line[indent:]) else: if snippet: snippets.append("".join(snippet).rstrip() + "\n") snippet = [] if snippet: snippets.append("".join(snippet).rstrip() + "\n") return snippets def expected_result(snippets): """Get and normalize expected result from snippet.""" out = snippets.pop(0) assert out.startswith("ExecutionResult(") return " ".join(out.split()).replace("( ", "(") + "\n" def expected_errors(snippets): """Get and normalize expected errors from snippet.""" out = snippets.pop(0) assert out.startswith("[GraphQLError(") return " ".join(out.split()).replace("( ", "(").replace('" "', "") def describe_introduction(): def getting_started(capsys): intro = get_snippets("intro") pip_install = intro.pop(0) assert "pip install" in pip_install and "graphql-core" in pip_install poetry_install = intro.pop(0) assert "poetry install" in poetry_install create_schema = intro.pop(0) assert "schema = GraphQLSchema(" in create_schema scope: Scope = {} exec(create_schema, scope) schema = scope.get("schema") schema_class = scope.get("GraphQLSchema") assert schema and schema_class and isinstance(schema, schema_class) query = intro.pop(0) assert "graphql_sync" in query exec(query, scope) out, err = capsys.readouterr() assert out.startswith("ExecutionResult") assert not err expected_out = intro.pop(0) assert out == expected_out def describe_usage(): sdl = get_snippets("usage/schema")[0] resolvers = get_snippets("usage/resolvers")[0] def building_a_type_schema(): schema = get_snippets("usage/schema") assert schema.pop(0) == sdl assert "enum Episode { NEWHOPE, EMPIRE, JEDI }" in sdl import_blocks = schema.pop(0) assert "from graphql import" in import_blocks assert "GraphQLObjectType" in import_blocks scope: Scope = {} exec(import_blocks, scope) assert "GraphQLObjectType" in scope build_enum = schema.pop(0) assert "episode_enum = " in build_enum exec(build_enum, scope) assert scope["episode_enum"].values["EMPIRE"].value == 5 scope2 = scope.copy() build_enum2 = schema.pop(0) assert "episode_enum = " in build_enum2 exec(build_enum2, scope2) assert scope["episode_enum"].values["EMPIRE"].value == 5 scope3 = scope.copy() build_enum3 = schema.pop(0) assert "episode_enum = " in build_enum3 exec(build_enum3, scope3) assert scope["episode_enum"].values["EMPIRE"].value == 5 build_character = schema.pop(0) assert "character_interface = " in build_character exec(resolvers, scope) exec(build_character, scope) assert "character_interface" in scope build_human_and_droid = schema.pop(0) assert "human_type = " in build_human_and_droid assert "droid_type = " in build_human_and_droid exec(build_human_and_droid, scope) assert "human_type" in scope assert "droid_type" in scope build_query_type = schema.pop(0) assert "query_type = " in build_query_type exec(build_query_type, scope) assert "query_type" in scope define_schema = schema.pop(0) assert "schema = " in define_schema exec(define_schema, scope) def implementing_resolvers(): assert "luke = dict(" in resolvers assert "def get_human(" in resolvers scope: Scope = {} exec(resolvers, scope) get_human = scope["get_human"] human = get_human(None, None, "1000") assert human["name"] == "Luke Skywalker" def executing_queries(capsys): scope: Scope = {} exec(resolvers, scope) schema = "\n".join(get_snippets("usage/schema")[1:]) exec(schema, scope) queries = get_snippets("usage/queries") async_query = queries.pop(0) assert "asyncio" in async_query and "graphql_sync" not in async_query assert "asyncio.run" in async_query try: # pragma: no cover from asyncio import run # noqa: F401 except ImportError: # Python < 3.7 assert "ExecutionResult" in expected_result(queries) else: # pragma: no cover exec(async_query, scope) out, err = capsys.readouterr() assert not err assert "R2-D2" in out assert out == expected_result(queries) sync_query = queries.pop(0) assert "graphql_sync" in sync_query and "asyncio" not in sync_query exec(sync_query, scope) out, err = capsys.readouterr() assert not err assert "Luke" in out assert out == expected_result(queries) bad_query = queries.pop(0) assert "homePlace" in bad_query exec(bad_query, scope) out, err = capsys.readouterr() assert not err assert "Cannot query" in out assert out == expected_result(queries) typename_query = queries.pop(0) assert "__typename" in typename_query exec(typename_query, scope) out, err = capsys.readouterr() assert not err assert "__typename" in out and "Human" in out assert out == expected_result(queries) backstory_query = queries.pop(0) assert "secretBackstory" in backstory_query exec(backstory_query, scope) out, err = capsys.readouterr() assert not err assert "errors" in out and "secretBackstory" in out assert out == expected_result(queries) def using_the_sdl(capsys): use_sdl = get_snippets("usage/sdl") build_schema = use_sdl.pop(0) build_schema_sdl = dedent( build_schema.partition('build_schema("""\n')[2].partition('""")')[0] ) assert build_schema_sdl == sdl.rstrip() scope: Scope = {} exec(build_schema, scope) schema = scope["schema"] assert list(schema.query_type.fields) == ["hero", "human", "droid"] exec(resolvers, scope) assert schema.query_type.fields["hero"].resolve is None attach_functions = use_sdl.pop(0) exec(attach_functions, scope) assert schema.query_type.fields["hero"].resolve is scope["get_hero"] define_enum_values = use_sdl.pop(0) define_episode_enum = get_snippets("usage/schema")[3] define_episode_enum = define_episode_enum.partition("episode_enum =")[0] assert "class EpisodeEnum" in define_episode_enum exec(define_episode_enum, scope) exec(define_enum_values, scope) assert schema.get_type("Episode").values["EMPIRE"].value == 5 query = use_sdl.pop(0) assert "graphql_sync" in query and "print(result)" in query exec(query, scope) out, err = capsys.readouterr() assert not err assert "Luke" in out and "appearsIn" in out and "EMPIRE" in out assert out == expected_result(use_sdl) def using_resolver_methods(capsys): scope: Scope = {} exec(resolvers, scope) build_schema = get_snippets("usage/sdl")[0] exec(build_schema, scope) methods = get_snippets("usage/methods") root_class = methods.pop(0) assert root_class.startswith("class Root:") assert "def human(self, info, id):" in root_class exec(root_class, scope) assert "Root" in scope query = methods.pop(0) assert "graphql_sync" in query and "Root()" in query exec(query, scope) out, err = capsys.readouterr() assert not err assert "R2-D2" in out and "primaryFunction" in out and "Astromech" in out assert out == expected_result(methods) def using_introspection(capsys): introspect = get_snippets("usage/introspection") get_query = introspect.pop(0) assert "import get_introspection_query" in get_query assert "descriptions=True" in get_query scope: Scope = {} exec(get_query, scope) query = scope["query"] assert query.lstrip().startswith("query IntrospectionQuery") assert "description" in query get_query = introspect.pop(0) assert "descriptions=False" in get_query scope2 = scope.copy() exec(get_query, scope2) query = scope2["query"] assert query.lstrip().startswith("query IntrospectionQuery") assert "description" not in query exec(resolvers, scope) create_schema = "\n".join(get_snippets("usage/schema")[1:]) exec(create_schema, scope) get_result = introspect.pop(0) assert "result = graphql_sync(" in get_result exec(get_result, scope) query_result = scope["introspection_query_result"] assert query_result.errors is None result = str(query_result.data) result = "".join(result.split()) expected_result = introspect.pop(0) result = "".join(result.split()) expected_result = "\n".join(expected_result.splitlines()[:7]) expected_result = "".join(expected_result.split()) assert result.startswith(expected_result) build_schema = introspect.pop(0) assert "schema = build_client_schema(" in build_schema scope = {"introspection_query_result": query_result} exec(build_schema, scope) schema = scope["client_schema"] assert list(schema.query_type.fields) == ["hero", "human", "droid"] print_schema = introspect.pop(0) scope = {"client_schema": schema} assert "print_schema(" in print_schema exec(print_schema, scope) out, err = capsys.readouterr() assert not err assert "enum Episode {" in out assert "id: String!" in out assert "interface Character {" in out assert "type Droid implements Character {" in out assert "type Human implements Character {" in out assert '"""A character in the Star Wars Trilogy"""' in out assert '"""A humanoid creature in the Star Wars universe."""' in out def parsing_graphql(): parser = get_snippets("usage/parser") parse_document = parser.pop(0) assert "document = parse(" in parse_document scope: Scope = {} exec(parse_document, scope) document = scope["document"] name = document.definitions[0].fields[0].name assert name.value == "me" assert str(name.loc) == "24:26" parse_document2 = parser.pop(0) assert "document = parse(" in parse_document2 assert "..., no_location=True" in parse_document2 parse_document = parse_document.replace('""")', '""", no_location=True)') scope.clear() exec(parse_document, scope) document = scope["document"] name = document.definitions[0].fields[0].name assert name.value == "me" assert name.loc is None create_document = parser.pop(0) assert "document = DocumentNode(" in create_document assert "FieldDefinitionNode(" in create_document assert "name=NameNode(value='me')," in create_document scope = {} exec(create_document, scope) assert scope["document"] == document def extending_a_schema(capsys): scope: Scope = {} exec(resolvers, scope) create_schema = "\n".join(get_snippets("usage/schema")[1:]) exec(create_schema, scope) extension = get_snippets("usage/extension") extend_schema = extension.pop(0) assert "extend_schema(" in extend_schema exec(extend_schema, scope) schema = scope["schema"] human_type = schema.get_type("Human") assert "lastName" in human_type.fields attach_resolver = extension.pop(0) exec(attach_resolver, scope) assert human_type.fields["lastName"].resolve is scope["get_last_name"] query = extension.pop(0) assert "graphql_sync(" in query exec(query, scope) out, err = capsys.readouterr() assert not err assert "lastName" in out and "Skywalker" in out assert out == expected_result(extension) def validating_queries(): scope: Scope = {} exec(resolvers, scope) create_schema = "\n".join(get_snippets("usage/schema")[1:]) exec(create_schema, scope) validator = get_snippets("usage/validator") validate = validator.pop(0) assert "errors = validate(" in validate exec(validate, scope) errors = str(scope["errors"]) assert errors == expected_errors(validator) graphql-core-3.2.6/tests/test_star_wars_introspection.py000066400000000000000000000264561474546154300237000ustar00rootroot00000000000000from typing import Any from graphql import graphql_sync from .star_wars_schema import star_wars_schema def query_star_wars(source: str) -> Any: result = graphql_sync(star_wars_schema, source) assert result.errors is None return result.data def describe_star_wars_introspection_tests(): def describe_basic_introspection(): def allows_querying_the_schema_for_types(): data = query_star_wars( """ { __schema { types { name } } } """ ) # Include all types used by StarWars schema, introspection types and # standard directives. For example, `Boolean` is used in `@skip`, # `@include` and also inside introspection types. assert data == { "__schema": { "types": [ {"name": "Human"}, {"name": "Character"}, {"name": "String"}, {"name": "Episode"}, {"name": "Droid"}, {"name": "Query"}, {"name": "Boolean"}, {"name": "__Schema"}, {"name": "__Type"}, {"name": "__TypeKind"}, {"name": "__Field"}, {"name": "__InputValue"}, {"name": "__EnumValue"}, {"name": "__Directive"}, {"name": "__DirectiveLocation"}, ] } } def allows_querying_the_schema_for_query_type(): data = query_star_wars( """ { __schema { queryType { name } } } """ ) assert data == {"__schema": {"queryType": {"name": "Query"}}} def allows_querying_the_schema_for_a_specific_type(): data = query_star_wars( """ { __type(name: "Droid") { name } } """ ) assert data == {"__type": {"name": "Droid"}} def allows_querying_the_schema_for_an_object_kind(): data = query_star_wars( """ { __type(name: "Droid") { name kind } } """ ) assert data == {"__type": {"name": "Droid", "kind": "OBJECT"}} def allows_querying_the_schema_for_an_interface_kind(): data = query_star_wars( """ { __type(name: "Character") { name kind } } """ ) assert data == {"__type": {"name": "Character", "kind": "INTERFACE"}} def allows_querying_the_schema_for_object_fields(): data = query_star_wars( """ { __type(name: "Droid") { name fields { name type { name kind } } } } """ ) assert data == { "__type": { "name": "Droid", "fields": [ {"name": "id", "type": {"name": None, "kind": "NON_NULL"}}, {"name": "name", "type": {"name": "String", "kind": "SCALAR"}}, {"name": "friends", "type": {"name": None, "kind": "LIST"}}, {"name": "appearsIn", "type": {"name": None, "kind": "LIST"}}, { "name": "secretBackstory", "type": {"name": "String", "kind": "SCALAR"}, }, { "name": "primaryFunction", "type": {"name": "String", "kind": "SCALAR"}, }, ], } } def allows_querying_the_schema_for_nested_object_fields(): data = query_star_wars( """ { __type(name: "Droid") { name fields { name type { name kind ofType { name kind } } } } } """ ) assert data == { "__type": { "name": "Droid", "fields": [ { "name": "id", "type": { "name": None, "kind": "NON_NULL", "ofType": {"name": "String", "kind": "SCALAR"}, }, }, { "name": "name", "type": { "name": "String", "kind": "SCALAR", "ofType": None, }, }, { "name": "friends", "type": { "name": None, "kind": "LIST", "ofType": {"name": "Character", "kind": "INTERFACE"}, }, }, { "name": "appearsIn", "type": { "name": None, "kind": "LIST", "ofType": {"name": "Episode", "kind": "ENUM"}, }, }, { "name": "secretBackstory", "type": { "name": "String", "kind": "SCALAR", "ofType": None, }, }, { "name": "primaryFunction", "type": { "name": "String", "kind": "SCALAR", "ofType": None, }, }, ], } } def allows_querying_the_schema_for_field_args(): data = query_star_wars( """ { __schema { queryType { fields { name args { name description type { name kind ofType { name kind } } defaultValue } } } } } """ ) assert data == { "__schema": { "queryType": { "fields": [ { "name": "hero", "args": [ { "defaultValue": None, "description": "If omitted, returns the hero of" " the whole saga. If provided, returns the hero" " of that particular episode.", "name": "episode", "type": { "kind": "ENUM", "name": "Episode", "ofType": None, }, } ], }, { "name": "human", "args": [ { "name": "id", "description": "id of the human", "type": { "kind": "NON_NULL", "name": None, "ofType": { "kind": "SCALAR", "name": "String", }, }, "defaultValue": None, } ], }, { "name": "droid", "args": [ { "name": "id", "description": "id of the droid", "type": { "kind": "NON_NULL", "name": None, "ofType": { "kind": "SCALAR", "name": "String", }, }, "defaultValue": None, } ], }, ] } } } def allows_querying_the_schema_for_documentation(): data = query_star_wars( """ { __type(name: "Droid") { name description } } """ ) assert data == { "__type": { "name": "Droid", "description": "A mechanical creature in the Star Wars universe.", } } graphql-core-3.2.6/tests/test_star_wars_query.py000066400000000000000000000332241474546154300221340ustar00rootroot00000000000000from pytest import mark from graphql import graphql, graphql_sync from .star_wars_schema import star_wars_schema as schema def describe_star_wars_query_tests(): def describe_basic_queries(): @mark.asyncio async def correctly_identifies_r2_d2_as_hero_of_the_star_wars_saga(): source = """ query HeroNameQuery { hero { name } } """ result = await graphql(schema=schema, source=source) assert result == ({"hero": {"name": "R2-D2"}}, None) @mark.asyncio async def accepts_positional_arguments_to_graphql(): source = """ query HeroNameQuery { hero { name } } """ result = await graphql(schema, source) assert result == ({"hero": {"name": "R2-D2"}}, None) sync_result = graphql_sync(schema, source) assert sync_result == result @mark.asyncio async def allows_us_to_query_for_the_id_and_friends_of_r2_d2(): source = """ query HeroNameAndFriendsQuery { hero { id name friends { name } } } """ result = await graphql(schema=schema, source=source) assert result == ( { "hero": { "id": "2001", "name": "R2-D2", "friends": [ {"name": "Luke Skywalker"}, {"name": "Han Solo"}, {"name": "Leia Organa"}, ], } }, None, ) def describe_nested_queries(): @mark.asyncio async def allows_us_to_query_for_the_friends_of_friends_of_r2_d2(): source = """ query NestedQuery { hero { name friends { name appearsIn friends { name } } } } """ result = await graphql(schema=schema, source=source) assert result == ( { "hero": { "name": "R2-D2", "friends": [ { "name": "Luke Skywalker", "appearsIn": ["NEW_HOPE", "EMPIRE", "JEDI"], "friends": [ {"name": "Han Solo"}, {"name": "Leia Organa"}, {"name": "C-3PO"}, {"name": "R2-D2"}, ], }, { "name": "Han Solo", "appearsIn": ["NEW_HOPE", "EMPIRE", "JEDI"], "friends": [ {"name": "Luke Skywalker"}, {"name": "Leia Organa"}, {"name": "R2-D2"}, ], }, { "name": "Leia Organa", "appearsIn": ["NEW_HOPE", "EMPIRE", "JEDI"], "friends": [ {"name": "Luke Skywalker"}, {"name": "Han Solo"}, {"name": "C-3PO"}, {"name": "R2-D2"}, ], }, ], } }, None, ) def describe_using_ids_and_query_parameters_to_refetch_objects(): @mark.asyncio async def allows_us_to_query_for_r2_d2_directly_using_his_id(): source = """ query { droid(id: "2001") { name } } """ result = await graphql(schema=schema, source=source) assert result == ({"droid": {"name": "R2-D2"}}, None) @mark.asyncio async def allows_us_to_query_characters_directly_using_their_id(): source = """ query FetchLukeAndC3POQuery { human(id: "1000") { name } droid(id: "2000") { name } } """ result = await graphql(schema=schema, source=source) assert result == ( {"human": {"name": "Luke Skywalker"}, "droid": {"name": "C-3PO"}}, None, ) @mark.asyncio async def allows_creating_a_generic_query_to_fetch_luke_using_his_id(): source = """ query FetchSomeIDQuery($someId: String!) { human(id: $someId) { name } } """ variable_values = {"someId": "1000"} result = await graphql( schema=schema, source=source, variable_values=variable_values ) assert result == ({"human": {"name": "Luke Skywalker"}}, None) @mark.asyncio async def allows_creating_a_generic_query_to_fetch_han_using_his_id(): source = """ query FetchSomeIDQuery($someId: String!) { human(id: $someId) { name } } """ variable_values = {"someId": "1002"} result = await graphql( schema=schema, source=source, variable_values=variable_values ) assert result == ({"human": {"name": "Han Solo"}}, None) @mark.asyncio async def generic_query_that_gets_null_back_when_passed_invalid_id(): source = """ query humanQuery($id: String!) { human(id: $id) { name } } """ variable_values = {"id": "not a valid id"} result = await graphql( schema=schema, source=source, variable_values=variable_values ) assert result == ({"human": None}, None) def describe_using_aliases_to_change_the_key_in_the_response(): @mark.asyncio async def allows_us_to_query_for_luke_changing_his_key_with_an_alias(): source = """ query FetchLukeAliased { luke: human(id: "1000") { name } } """ result = await graphql(schema=schema, source=source) assert result == ({"luke": {"name": "Luke Skywalker"}}, None) @mark.asyncio async def query_for_luke_and_leia_using_two_root_fields_and_an_alias(): source = """ query FetchLukeAndLeiaAliased { luke: human(id: "1000") { name } leia: human(id: "1003") { name } } """ result = await graphql(schema=schema, source=source) assert result == ( {"luke": {"name": "Luke Skywalker"}, "leia": {"name": "Leia Organa"}}, None, ) def describe_uses_fragments_to_express_more_complex_queries(): @mark.asyncio async def allows_us_to_query_using_duplicated_content(): source = """ query DuplicateFields { luke: human(id: "1000") { name homePlanet } leia: human(id: "1003") { name homePlanet } } """ result = await graphql(schema=schema, source=source) assert result == ( { "luke": {"name": "Luke Skywalker", "homePlanet": "Tatooine"}, "leia": {"name": "Leia Organa", "homePlanet": "Alderaan"}, }, None, ) @mark.asyncio async def allows_us_to_use_a_fragment_to_avoid_duplicating_content(): source = """ query UseFragment { luke: human(id: "1000") { ...HumanFragment } leia: human(id: "1003") { ...HumanFragment } } fragment HumanFragment on Human { name homePlanet } """ result = await graphql(schema=schema, source=source) assert result == ( { "luke": {"name": "Luke Skywalker", "homePlanet": "Tatooine"}, "leia": {"name": "Leia Organa", "homePlanet": "Alderaan"}, }, None, ) def describe_using_typename_to_find_the_type_of_an_object(): @mark.asyncio async def allows_us_to_verify_that_r2_d2_is_a_droid(): source = """ query CheckTypeOfR2 { hero { __typename name } } """ result = await graphql(schema=schema, source=source) assert result == ({"hero": {"__typename": "Droid", "name": "R2-D2"}}, None) @mark.asyncio async def allows_us_to_verify_that_luke_is_a_human(): source = """ query CheckTypeOfLuke { hero(episode: EMPIRE) { __typename name } } """ result = await graphql(schema=schema, source=source) assert result == ( {"hero": {"__typename": "Human", "name": "Luke Skywalker"}}, None, ) def describe_reporting_errors_raised_in_resolvers(): @mark.asyncio async def correctly_reports_error_on_accessing_secret_backstory(): source = """ query HeroNameQuery { hero { name secretBackstory } } """ result = await graphql(schema=schema, source=source) assert result == ( {"hero": {"name": "R2-D2", "secretBackstory": None}}, [ { "message": "secretBackstory is secret.", "locations": [(5, 21)], "path": ["hero", "secretBackstory"], } ], ) @mark.asyncio async def correctly_reports_error_on_accessing_backstory_in_a_list(): source = """ query HeroNameQuery { hero { name friends { name secretBackstory } } } """ result = await graphql(schema=schema, source=source) assert result == ( { "hero": { "name": "R2-D2", "friends": [ {"name": "Luke Skywalker", "secretBackstory": None}, {"name": "Han Solo", "secretBackstory": None}, {"name": "Leia Organa", "secretBackstory": None}, ], } }, [ { "message": "secretBackstory is secret.", "locations": [(7, 23)], "path": ["hero", "friends", 0, "secretBackstory"], }, { "message": "secretBackstory is secret.", "locations": [(7, 23)], "path": ["hero", "friends", 1, "secretBackstory"], }, { "message": "secretBackstory is secret.", "locations": [(7, 23)], "path": ["hero", "friends", 2, "secretBackstory"], }, ], ) @mark.asyncio async def correctly_reports_error_on_accessing_through_an_alias(): source = """ query HeroNameQuery { mainHero: hero { name story: secretBackstory } } """ result = await graphql(schema=schema, source=source) assert result == ( {"mainHero": {"name": "R2-D2", "story": None}}, [ { "message": "secretBackstory is secret.", "locations": [(5, 21)], "path": ["mainHero", "story"], } ], ) graphql-core-3.2.6/tests/test_star_wars_validation.py000066400000000000000000000060611474546154300231200ustar00rootroot00000000000000from typing import List from graphql.error import GraphQLError from graphql.language import parse, Source from graphql.validation import validate from .star_wars_schema import star_wars_schema def validation_errors(query: str) -> List[GraphQLError]: """Helper function to test a query and the expected response.""" source = Source(query, "StarWars.graphql") ast = parse(source) return validate(star_wars_schema, ast) def describe_star_wars_validation_tests(): def describe_basic_queries(): def validates_a_complex_but_valid_query(): query = """ query NestedQueryWithFragment { hero { ...NameAndAppearances friends { ...NameAndAppearances friends { ...NameAndAppearances } } } } fragment NameAndAppearances on Character { name appearsIn } """ assert not validation_errors(query) def notes_that_non_existent_fields_are_invalid(): query = """ query HeroSpaceshipQuery { hero { favoriteSpaceship } } """ assert validation_errors(query) def requires_fields_on_object(): query = """ query HeroNoFieldsQuery { hero } """ assert validation_errors(query) def disallows_fields_on_scalars(): query = """ query HeroFieldsOnScalarQuery { hero { name { firstCharacterOfName } } } """ assert validation_errors(query) def disallows_object_fields_on_interfaces(): query = """ query DroidFieldOnCharacter { hero { name primaryFunction } } """ assert validation_errors(query) def allows_object_fields_in_fragments(): query = """ query DroidFieldInFragment { hero { name ...DroidFields } } fragment DroidFields on Droid { primaryFunction } """ assert not validation_errors(query) def allows_object_fields_in_inline_fragments(): query = """ query DroidFieldInFragment { hero { name ...DroidFields } } fragment DroidFields on Droid { primaryFunction } """ assert not validation_errors(query) graphql-core-3.2.6/tests/test_user_registry.py000066400000000000000000000431271474546154300216130ustar00rootroot00000000000000"""User registry demo. This is an additional end-to-end test and demo for running the basic GraphQL operations on a simulated user registry database backend. """ from asyncio import sleep, wait from collections import defaultdict from enum import Enum from inspect import isawaitable from typing import Any, Dict, List, NamedTuple, Optional try: from asyncio import create_task except ImportError: # Python < 3.7 create_task = None # type: ignore from graphql import ( GraphQLArgument, GraphQLBoolean, GraphQLEnumType, GraphQLField, GraphQLID, GraphQLInputField, GraphQLInputObjectType, GraphQLInt, GraphQLNonNull, GraphQLObjectType, GraphQLSchema, GraphQLString, graphql, parse, subscribe, ) from graphql.execution.map_async_iterator import MapAsyncIterator from graphql.pyutils import SimplePubSub, SimplePubSubIterator from pytest import fixture, mark class User(NamedTuple): """A simple user object class.""" firstName: str lastName: str tweets: Optional[int] id: Optional[str] = None verified: bool = False class MutationEnum(Enum): """Mutation event type""" CREATED = "created" UPDATED = "updated" DELETED = "deleted" class UserRegistry: """Simulation of a user registry with asynchronous database backend access.""" def __init__(self, **users): self._registry: Dict[str, User] = users self._pubsub = defaultdict(SimplePubSub) async def get(self, id_: str) -> Optional[User]: """Get a user object from the registry""" await sleep(0) return self._registry.get(id_) async def create(self, **kwargs) -> User: """Create a user object in the registry""" await sleep(0) id_ = str(len(self._registry)) user = User(id=id_, **kwargs) self._registry[id_] = user self.emit_event(MutationEnum.CREATED, user) return user async def update(self, id_: str, **kwargs) -> User: """Update a user object in the registry""" await sleep(0) # noinspection PyProtectedMember user = self._registry[id_]._replace(**kwargs) self._registry[id_] = user self.emit_event(MutationEnum.UPDATED, user) return user async def delete(self, id_: str) -> User: """Delete a user object in the registry""" await sleep(0) user = self._registry.pop(id_) self.emit_event(MutationEnum.DELETED, user) return user def emit_event(self, mutation: MutationEnum, user: User) -> None: """Emit mutation events for the given object and its class""" payload = {"user": user, "mutation": mutation.value} self._pubsub[None].emit(payload) # notify all user subscriptions self._pubsub[user.id].emit(payload) # notify single user subscriptions def event_iterator(self, id_: Optional[str]) -> SimplePubSubIterator: return self._pubsub[id_].get_subscriber() mutation_type = GraphQLEnumType("MutationType", MutationEnum) user_type = GraphQLObjectType( "UserType", { "id": GraphQLField(GraphQLNonNull(GraphQLID)), "firstName": GraphQLField(GraphQLNonNull(GraphQLString)), "lastName": GraphQLField(GraphQLNonNull(GraphQLString)), "tweets": GraphQLField(GraphQLInt), "verified": GraphQLField(GraphQLNonNull(GraphQLBoolean)), }, ) user_input_type = GraphQLInputObjectType( "UserInputType", { "firstName": GraphQLInputField(GraphQLNonNull(GraphQLString)), "lastName": GraphQLInputField(GraphQLNonNull(GraphQLString)), "tweets": GraphQLInputField(GraphQLInt), "verified": GraphQLInputField(GraphQLBoolean), }, ) subscription_user_type = GraphQLObjectType( "SubscriptionUserType", {"mutation": GraphQLField(mutation_type), "user": GraphQLField(user_type)}, ) async def resolve_user(_root, info, **args): """Resolver function for fetching a user object""" return await info.context["registry"].get(args["id"]) async def resolve_create_user(_root, info, data): """Resolver function for creating a user object""" user = await info.context["registry"].create(**data) return user # noinspection PyShadowingBuiltins async def resolve_update_user(_root, info, id, data): """Resolver function for updating a user object""" user = await info.context["registry"].update(id, **data) return user # noinspection PyShadowingBuiltins async def resolve_delete_user(_root, info, id): """Resolver function for deleting a user object""" user = await info.context["registry"].get(id) await info.context["registry"].delete(user.id) return True # noinspection PyShadowingBuiltins async def subscribe_user(_root, info, id=None): """Subscribe to mutations of a specific user object or all user objects""" async_iterator = info.context["registry"].event_iterator(id) async for event in async_iterator: yield await event if isawaitable(event) else event # pragma: no cover exit # noinspection PyShadowingBuiltins,PyUnusedLocal async def resolve_subscription_user(event, info, id): """Resolver function for user subscriptions""" user = event["user"] mutation = MutationEnum(event["mutation"]).value return {"user": user, "mutation": mutation} schema = GraphQLSchema( query=GraphQLObjectType( "RootQueryType", { "User": GraphQLField( user_type, args={"id": GraphQLArgument(GraphQLID)}, resolve=resolve_user ) }, ), mutation=GraphQLObjectType( "RootMutationType", { "createUser": GraphQLField( user_type, args={"data": GraphQLArgument(GraphQLNonNull(user_input_type))}, resolve=resolve_create_user, ), "deleteUser": GraphQLField( GraphQLBoolean, args={"id": GraphQLArgument(GraphQLNonNull(GraphQLID))}, resolve=resolve_delete_user, ), "updateUser": GraphQLField( user_type, args={ "id": GraphQLArgument(GraphQLNonNull(GraphQLID)), "data": GraphQLArgument(GraphQLNonNull(user_input_type)), }, resolve=resolve_update_user, ), }, ), subscription=GraphQLObjectType( "RootSubscriptionType", { "subscribeUser": GraphQLField( subscription_user_type, args={"id": GraphQLArgument(GraphQLID)}, subscribe=subscribe_user, resolve=resolve_subscription_user, ) }, ), ) @fixture def context(): return {"registry": UserRegistry()} def describe_query(): @mark.asyncio async def query_user(context): user = await context["registry"].create( firstName="John", lastName="Doe", tweets=42, verified=True ) query = """ query ($userId: ID!) { User(id: $userId) { id, firstName, lastName, tweets, verified } } """ variables = {"userId": user.id} result = await graphql( schema, query, context_value=context, variable_values=variables ) assert not result.errors assert result.data == { "User": { "id": user.id, "firstName": user.firstName, "lastName": user.lastName, "tweets": user.tweets, "verified": user.verified, } } def describe_mutation(): @mark.asyncio async def create_user(context): received = {} def subscriber(event_name): def receive(msg): received[event_name] = msg return receive # noinspection PyProtectedMember pubsub = context["registry"]._pubsub pubsub[None].subscribers.add(subscriber("User")) pubsub["0"].subscribers.add(subscriber("User 0")) query = """ mutation ($userData: UserInputType!) { createUser(data: $userData) { id, firstName, lastName, tweets, verified } } """ user_data = dict(firstName="John", lastName="Doe", tweets=42, verified=True) variables = {"userData": user_data} result = await graphql( schema, query, context_value=context, variable_values=variables ) user = await context["registry"].get("0") assert user == User(id="0", **user_data) # type: ignore assert result.errors is None assert result.data == { "createUser": { "id": user.id, "firstName": user.firstName, "lastName": user.lastName, "tweets": user.tweets, "verified": user.verified, } } assert received == { "User": {"user": user, "mutation": MutationEnum.CREATED.value}, "User 0": {"user": user, "mutation": MutationEnum.CREATED.value}, } @mark.asyncio async def update_user(context): received = {} def subscriber(event_name): def receive(msg): received[event_name] = msg return receive # noinspection PyProtectedMember pubsub = context["registry"]._pubsub pubsub[None].subscribers.add(subscriber("User")) pubsub["0"].subscribers.add(subscriber("User 0")) user = await context["registry"].create( firstName="John", lastName="Doe", tweets=42, verified=True ) user_data = { "firstName": "Jane", "lastName": "Roe", "tweets": 210, "verified": False, } query = """ mutation ($userId: ID!, $userData: UserInputType!) { updateUser(id: $userId, data: $userData) { id, firstName, lastName, tweets, verified } }""" variables = {"userId": user.id, "userData": user_data} result = await graphql( schema, query, context_value=context, variable_values=variables ) user = await context["registry"].get("0") assert user == User(id="0", **user_data) # type: ignore assert result.errors is None assert result.data == { "updateUser": { "id": user.id, "firstName": user.firstName, "lastName": user.lastName, "tweets": user.tweets, "verified": user.verified, } } assert received == { "User": {"user": user, "mutation": MutationEnum.UPDATED.value}, "User 0": {"user": user, "mutation": MutationEnum.UPDATED.value}, } @mark.asyncio async def delete_user(context): received = {} def subscriber(name): def receive(msg): received[name] = msg return receive # noinspection PyProtectedMember pubsub = context["registry"]._pubsub pubsub[None].subscribers.add(subscriber("User")) pubsub["0"].subscribers.add(subscriber("User 0")) user = await context["registry"].create( firstName="John", lastName="Doe", tweets=42, verified=True ) query = """ mutation ($userId: ID!) { deleteUser(id: $userId) } """ variables = {"userId": user.id} result = await graphql( schema, query, context_value=context, variable_values=variables ) assert result.errors is None assert result.data == {"deleteUser": True} assert await context["registry"].get(user.id) is None assert received == { "User": {"user": user, "mutation": MutationEnum.DELETED.value}, "User 0": {"user": user, "mutation": MutationEnum.DELETED.value}, } def describe_subscription(): @mark.asyncio async def subscribe_to_user_mutations(context): query = """ subscription ($userId: ID!) { subscribeUser(id: $userId) { mutation user { id, firstName, lastName, tweets, verified } } } """ variables = {"userId": "0"} subscription_one = await subscribe( schema, parse(query), context_value=context, variable_values=variables ) assert isinstance(subscription_one, MapAsyncIterator) query = """ subscription { subscribeUser(id: null) { mutation user { id, firstName, lastName, tweets, verified } } } """ subscription_all = await subscribe(schema, parse(query), context_value=context) assert isinstance(subscription_all, MapAsyncIterator) received_one = [] received_all = [] async def mutate_users(): await sleep(0) # make sure subscribers are running await graphql( schema, """ mutation {createUser(data: { firstName: "John" lastName: "Doe" tweets: 42 verified: true}) { id } }""", context_value=context, ) await graphql( schema, """ mutation {createUser(data: { firstName: "James" lastName: "Doe" tweets: 4 verified: false}) { id } }""", context_value=context, ) await graphql( schema, """ mutation {updateUser(id: 0, data: { firstName: "Jane" lastName: "Roe" tweets: 210 verified: false}) { id } }""", context_value=context, ) await graphql( schema, """ mutation {updateUser(id: 1, data: { firstName: "Janette" lastName: "Roe" tweets: 20 verified: true}) { id } }""", context_value=context, ) await graphql( schema, """ mutation {deleteUser(id: "0")} """, context_value=context, ) await graphql( schema, """ mutation {deleteUser(id: "1")} """, context_value=context, ) async def receive_one(): async for result in subscription_one: # pragma: no cover received_one.append(result) if len(received_one) == 3: # pragma: no cover else break async def receive_all(): async for result in subscription_all: # pragma: no cover received_all.append(result) if len(received_all) == 6: # pragma: no cover else break tasks = [ create_task(task()) if create_task else task() # type: ignore for task in (mutate_users, receive_one, receive_all) ] done, pending = await wait(tasks, timeout=1) assert len(done) == len(tasks) assert not pending expected_data: List[Dict[str, Any]] = [ { "mutation": "CREATED", "user": { "id": "0", "firstName": "John", "lastName": "Doe", "tweets": 42, "verified": True, }, }, { "mutation": "CREATED", "user": { "id": "1", "firstName": "James", "lastName": "Doe", "tweets": 4, "verified": False, }, }, { "mutation": "UPDATED", "user": { "id": "0", "firstName": "Jane", "lastName": "Roe", "tweets": 210, "verified": False, }, }, { "mutation": "UPDATED", "user": { "id": "1", "firstName": "Janette", "lastName": "Roe", "tweets": 20, "verified": True, }, }, { "mutation": "DELETED", "user": { "id": "0", "firstName": "Jane", "lastName": "Roe", "tweets": 210, "verified": False, }, }, { "mutation": "DELETED", "user": { "id": "1", "firstName": "Janette", "lastName": "Roe", "tweets": 20, "verified": True, }, }, ] assert received_one == [ ({"subscribeUser": data}, None) for data in expected_data if data["user"]["id"] == "0" ] assert received_all == [ ({"subscribeUser": data}, None) for data in expected_data ] await sleep(0) graphql-core-3.2.6/tests/test_version.py000066400000000000000000000101011474546154300203540ustar00rootroot00000000000000import re import graphql from graphql.version import ( VersionInfo, version, version_info, version_js, version_info_js, ) _re_version = re.compile(r"(\d+)\.(\d+)\.(\d+)(?:(a|b|r?c)(\d+))?$") def describe_version(): def describe_version_info_class(): def create_version_info_from_fields(): v = VersionInfo(1, 2, 3, "alpha", 4) assert v.major == 1 assert v.minor == 2 assert v.micro == 3 assert v.releaselevel == "alpha" assert v.serial == 4 def create_version_info_from_str(): v = VersionInfo.from_str("1.2.3") assert v.major == 1 assert v.minor == 2 assert v.micro == 3 assert v.releaselevel == "final" assert v.serial == 0 v = VersionInfo.from_str("1.2.3a4") assert v.major == 1 assert v.minor == 2 assert v.micro == 3 assert v.releaselevel == "alpha" assert v.serial == 4 v = VersionInfo.from_str("1.2.3beta4") assert v.major == 1 assert v.minor == 2 assert v.micro == 3 assert v.releaselevel == "beta" assert v.serial == 4 v = VersionInfo.from_str("12.34.56rc789") assert v.major == 12 assert v.minor == 34 assert v.micro == 56 assert v.releaselevel == "candidate" assert v.serial == 789 def serialize_as_str(): v = VersionInfo(1, 2, 3, "final", 0) assert str(v) == "1.2.3" v = VersionInfo(1, 2, 3, "alpha", 4) assert str(v) == "1.2.3a4" v = VersionInfo(1, 2, 3, "candidate", 4) assert str(v) == "1.2.3rc4" def describe_graphql_core_version(): def base_package_has_correct_version(): assert graphql.__version__ == version assert graphql.version == version def base_package_has_correct_version_info(): assert graphql.__version_info__ is version_info assert graphql.version_info is version_info def version_has_correct_format(): assert isinstance(version, str) assert _re_version.match(version) def version_info_has_correct_fields(): assert isinstance(version_info, tuple) assert str(version_info) == version groups = _re_version.match(version).groups() # type: ignore assert version_info.major == int(groups[0]) assert version_info.minor == int(groups[1]) assert version_info.micro == int(groups[2]) if groups[3] is None: # pragma: no cover assert groups[4] is None else: # pragma: no cover assert version_info.releaselevel[:1] == groups[3].lstrip("r") assert version_info.serial == int(groups[4]) def describe_graphql_js_version(): def base_package_has_correct_version_js(): assert graphql.__version_js__ == version_js assert graphql.version_js == version_js def base_package_has_correct_version_info_js(): assert graphql.__version_info_js__ is version_info_js assert graphql.version_info_js is version_info_js def version_js_has_correct_format(): assert isinstance(version_js, str) assert _re_version.match(version_js) def version_info_js_has_correct_fields(): assert isinstance(version_info_js, tuple) assert str(version_info_js) == version_js groups = _re_version.match(version_js).groups() # type: ignore assert version_info_js.major == int(groups[0]) assert version_info_js.minor == int(groups[1]) assert version_info_js.micro == int(groups[2]) if groups[3] is None: # pragma: no cover assert groups[4] is None else: # pragma: no cover assert version_info_js.releaselevel[:1] == groups[3].lstrip("r") assert version_info_js.serial == int(groups[4]) graphql-core-3.2.6/tests/type/000077500000000000000000000000001474546154300162465ustar00rootroot00000000000000graphql-core-3.2.6/tests/type/__init__.py000066400000000000000000000000351474546154300203550ustar00rootroot00000000000000"""Tests for graphql.type""" graphql-core-3.2.6/tests/type/test_assert_name.py000066400000000000000000000053301474546154300221610ustar00rootroot00000000000000from pytest import mark, raises from graphql.error import GraphQLError from graphql.type import assert_name, assert_enum_value_name def describe_assert_name(): def pass_through_valid_name(): assert assert_name("_ValidName123") == "_ValidName123" def throws_for_non_strings(): with raises(TypeError) as exc_info: # noinspection PyTypeChecker assert_name({}) # type: ignore msg = str(exc_info.value) assert msg == "Expected name to be a string." def throws_on_empty_strings(): with raises(GraphQLError) as exc_info: assert_name("") msg = str(exc_info.value) assert msg == "Expected name to be a non-empty string." def throws_for_names_with_invalid_characters(): with raises(GraphQLError) as exc_info: assert_name(">--()-->") msg = str(exc_info.value) assert msg == "Names must only contain [_a-zA-Z0-9] but '>--()-->' does not." def throws_for_names_starting_with_invalid_characters(): with raises(GraphQLError) as exc_info: assert_name("42MeaningsOfLife") msg = str(exc_info.value) assert msg == ( "Names must start with [_a-zA-Z] but '42MeaningsOfLife' does not." ) def describe_assert_enum_value_name(): def pass_through_valid_name(): assert assert_enum_value_name("_ValidName123") == "_ValidName123" def throws_for_non_strings(): with raises(TypeError) as exc_info: # noinspection PyTypeChecker assert_enum_value_name({}) # type: ignore msg = str(exc_info.value) assert msg == "Expected name to be a string." def throws_on_empty_strings(): with raises(GraphQLError) as exc_info: assert_enum_value_name("") msg = str(exc_info.value) assert msg == "Expected name to be a non-empty string." def throws_for_names_with_invalid_characters(): with raises(GraphQLError) as exc_info: assert_enum_value_name(">--()-->") msg = str(exc_info.value) assert msg == "Names must only contain [_a-zA-Z0-9] but '>--()-->' does not." def throws_for_names_starting_with_invalid_characters(): with raises(GraphQLError) as exc_info: assert_enum_value_name("42MeaningsOfLife") msg = str(exc_info.value) assert msg == ( "Names must start with [_a-zA-Z] but '42MeaningsOfLife' does not." ) @mark.parametrize("name", ("true", "false", "null")) def throws_for_restricted_names(name): with raises(GraphQLError) as exc_info: assert_enum_value_name(name) msg = str(exc_info.value) assert msg == (f"Enum values cannot be named: {name}.") graphql-core-3.2.6/tests/type/test_custom_scalars.py000066400000000000000000000132271474546154300227060ustar00rootroot00000000000000from math import isfinite from typing import Any, Dict, NamedTuple from graphql import graphql_sync from graphql.error import GraphQLError from graphql.language import ValueNode from graphql.pyutils import inspect from graphql.type import ( GraphQLArgument, GraphQLField, GraphQLFloat, GraphQLObjectType, GraphQLScalarType, GraphQLSchema, ) from graphql.utilities import value_from_ast_untyped # this test is not (yet) part of GraphQL.js, see # https://github.com/graphql/graphql-js/issues/2657 class Money(NamedTuple): amount: float currency: str def is_finite(value: Any) -> bool: """Return true if a value is a finite number.""" return (isinstance(value, int) and not isinstance(value, bool)) or ( isinstance(value, float) and isfinite(value) ) def serialize_money(output_value: Any) -> Dict[str, float]: if not isinstance(output_value, Money): raise GraphQLError("Cannot serialize money value: " + inspect(output_value)) return output_value._asdict() def parse_money_value(input_value: Any) -> Money: if not isinstance(input_value, Money): raise GraphQLError("Cannot parse money value: " + inspect(input_value)) return input_value def parse_money_literal(value_node: ValueNode, variables=None) -> Money: money = value_from_ast_untyped(value_node, variables) if variables is not None and ( # variables are not set when checked with ValuesOfCorrectTypeRule not money or not is_finite(money.get("amount")) or not isinstance(money.get("currency"), str) ): raise GraphQLError("Cannot parse literal money value: " + inspect(money)) return Money(**money) MoneyScalar = GraphQLScalarType( name="Money", serialize=serialize_money, parse_value=parse_money_value, parse_literal=parse_money_literal, ) def resolve_balance(root, _info): return root def resolve_to_euros(_root, _info, money): amount = money.amount currency = money.currency if not amount or currency == "EUR": return amount if currency == "DM": return amount * 0.5 raise ValueError("Cannot convert to euros: " + inspect(money)) schema = GraphQLSchema( query=GraphQLObjectType( name="RootQueryType", fields={ "balance": GraphQLField(MoneyScalar, resolve=resolve_balance), "toEuros": GraphQLField( GraphQLFloat, args={"money": GraphQLArgument(MoneyScalar)}, resolve=resolve_to_euros, ), }, ) ) def describe_custom_scalar(): def serialize(): source = """ { balance } """ result = graphql_sync(schema, source, root_value=Money(42, "DM")) assert result == ({"balance": {"amount": 42, "currency": "DM"}}, None) def serialize_with_error(): source = """ { balance } """ result = graphql_sync(schema, source, root_value=21) assert result == ( {"balance": None}, [ { "message": "Cannot serialize money value: 21", "locations": [(3, 15)], "path": ["balance"], } ], ) def parse_value(): source = """ query Money($money: Money!) { toEuros(money: $money) } """ result = graphql_sync( schema, source, variable_values={"money": Money(24, "EUR")} ) assert result == ({"toEuros": 24}, None) result = graphql_sync( schema, source, variable_values={"money": Money(42, "DM")} ) assert result == ({"toEuros": 21}, None) def parse_value_with_error(): source = """ query Money($money: Money!) { toEuros(money: $money) } """ result = graphql_sync( schema, source, variable_values={"money": Money(42, "USD")} ) assert result == ( {"toEuros": None}, [ { "message": "Cannot convert to euros: (42, 'USD')", "locations": [(3, 15)], } ], ) result = graphql_sync(schema, source, variable_values={"money": 21}) assert result == ( None, [ { "message": "Variable '$money' got invalid value 21;" " Cannot parse money value: 21", "locations": [(2, 25)], } ], ) def parse_literal(): source = """ query Money($amount: Float!, $currency: String!) { toEuros(money: {amount: $amount, currency: $currency}) } """ variable_values = {"amount": 42, "currency": "DM"} result = graphql_sync(schema, source, variable_values=variable_values) assert result == ({"toEuros": 21}, None) def parse_literal_with_errors(): source = """ query Money($amount: String!, $currency: Float!) { toEuros(money: {amount: $amount, currency: $currency}) } """ variable_values = {"amount": "DM", "currency": 42} result = graphql_sync(schema, source, variable_values=variable_values) assert result == ( {"toEuros": None}, [ { "message": "Argument 'money' has invalid value" " {amount: $amount, currency: $currency}.", "locations": [(3, 30)], }, ], ) graphql-core-3.2.6/tests/type/test_definition.py000066400000000000000000002333161474546154300220170ustar00rootroot00000000000000from enum import Enum from math import isnan, nan from typing import Dict, cast from graphql.error import GraphQLError from graphql.language import ( EnumTypeDefinitionNode, EnumTypeExtensionNode, EnumValueNode, InputObjectTypeDefinitionNode, InputObjectTypeExtensionNode, InputValueDefinitionNode, InterfaceTypeDefinitionNode, InterfaceTypeExtensionNode, Node, ObjectTypeDefinitionNode, ObjectTypeExtensionNode, ScalarTypeDefinitionNode, ScalarTypeExtensionNode, StringValueNode, TypeDefinitionNode, TypeExtensionNode, UnionTypeDefinitionNode, UnionTypeExtensionNode, ValueNode, parse_value, ) from graphql.pyutils import Undefined from graphql.type import ( GraphQLArgument, GraphQLEnumType, GraphQLEnumValue, GraphQLField, GraphQLInputField, GraphQLInputObjectType, GraphQLInt, GraphQLInterfaceType, GraphQLList, GraphQLNonNull, GraphQLObjectType, GraphQLScalarType, GraphQLString, GraphQLUnionType, ) from pytest import mark, raises ScalarType = GraphQLScalarType("Scalar") ObjectType = GraphQLObjectType("Object", {}) InterfaceType = GraphQLInterfaceType("Interface", {}) UnionType = GraphQLUnionType( "Union", [ObjectType], resolve_type=lambda _obj, _info, _type: None, # pragma: no cover ) EnumType = GraphQLEnumType("Enum", {"foo": GraphQLEnumValue()}) InputObjectType = GraphQLInputObjectType("InputObject", {}) ListOfScalarsType = GraphQLList(ScalarType) NonNullScalarType = GraphQLNonNull(ScalarType) ListOfNonNullScalarsType = GraphQLList(NonNullScalarType) NonNullListOfScalars = GraphQLNonNull(ListOfScalarsType) def describe_type_system_scalars(): def defines_a_scalar_type(): scalar = GraphQLScalarType("SomeScalar") assert scalar.name == "SomeScalar" kwargs = scalar.to_kwargs() assert kwargs == { "name": "SomeScalar", "description": None, "specified_by_url": None, "serialize": None, "parse_value": None, "parse_literal": None, "extensions": {}, "ast_node": None, "extension_ast_nodes": (), } def accepts_a_scalar_type_defining_serialize(): def serialize(value): pass scalar = GraphQLScalarType("SomeScalar", serialize) assert scalar.serialize is serialize assert scalar.to_kwargs()["serialize"] is serialize def defines_a_scalar_type_with_a_description(): description = "nice scalar" scalar = GraphQLScalarType("SomeScalar", description=description) assert scalar.description is description assert scalar.to_kwargs()["description"] is description def accepts_a_scalar_type_defining_specified_by_url(): url = "https://example.com/foo_spec" scalar = GraphQLScalarType("SomeScalar", specified_by_url=url) assert scalar.specified_by_url == url assert scalar.to_kwargs()["specified_by_url"] == url def accepts_a_scalar_type_defining_parse_value_and_parse_literal(): def parse_value(_value): pass def parse_literal(_value_node, _variables): pass scalar = GraphQLScalarType( "SomeScalar", parse_value=parse_value, parse_literal=parse_literal ) assert scalar.parse_value is parse_value assert scalar.parse_literal is parse_literal kwargs = scalar.to_kwargs() assert kwargs["parse_value"] is parse_value assert kwargs["parse_literal"] is parse_literal def provides_default_methods_if_omitted(): scalar = GraphQLScalarType("Foo") assert scalar.serialize is GraphQLScalarType.serialize assert scalar.parse_value is GraphQLScalarType.parse_value assert ( scalar.parse_literal.__func__ # type: ignore is GraphQLScalarType.parse_literal ) kwargs = scalar.to_kwargs() assert kwargs["serialize"] is None assert kwargs["parse_value"] is None assert kwargs["parse_literal"] is None def use_parse_value_for_parsing_literals_if_parse_literal_omitted(): scalar = GraphQLScalarType( "Foo", parse_value=lambda value: f"parse_value: {value!r}" ) assert scalar.parse_literal(parse_value("null")) == "parse_value: None" assert ( scalar.parse_literal(parse_value('{foo: "bar"}')) == "parse_value: {'foo': 'bar'}" ) assert ( scalar.parse_literal(parse_value("{foo: { bar: $var } }"), {"var": "baz"}) == "parse_value: {'foo': {'bar': 'baz'}}" ) def accepts_a_scalar_type_with_ast_node_and_extension_ast_nodes(): ast_node = ScalarTypeDefinitionNode() extension_ast_nodes = [ScalarTypeExtensionNode()] scalar = GraphQLScalarType( "SomeScalar", ast_node=ast_node, extension_ast_nodes=extension_ast_nodes ) assert scalar.ast_node is ast_node assert scalar.extension_ast_nodes == tuple(extension_ast_nodes) def rejects_a_scalar_type_with_incorrectly_typed_name(): with raises(TypeError, match="missing .* required .* 'name'"): # noinspection PyArgumentList GraphQLScalarType() # type: ignore with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLScalarType(None) # type: ignore assert str(exc_info.value) == "Must provide name." with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLScalarType(42, {}) # type: ignore assert str(exc_info.value) == "Expected name to be a string." def rejects_a_scalar_type_with_invalid_name(): with raises(GraphQLError) as exc_info: GraphQLScalarType("") assert str(exc_info.value) == "Expected name to be a non-empty string." with raises(GraphQLError) as exc_info: GraphQLScalarType("bad-name") assert str(exc_info.value) == ( "Names must only contain [_a-zA-Z0-9] but 'bad-name' does not." ) def rejects_a_scalar_type_with_incorrectly_typed_description(): with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLScalarType("SomeScalar", description=[]) # type: ignore assert str(exc_info.value) == "The description must be a string." def rejects_a_scalar_type_defining_specified_by_url_with_an_incorrect_type(): with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLScalarType("SomeScalar", specified_by_url={}) # type: ignore assert ( str(exc_info.value) == "SomeScalar must provide 'specified_by_url' as a string, but got: {}." ) def rejects_a_scalar_type_defining_serialize_with_incorrect_type(): with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLScalarType("SomeScalar", {}) # type: ignore assert str(exc_info.value) == ( "SomeScalar must provide 'serialize' as a function." " If this custom Scalar is also used as an input type," " ensure 'parse_value' and 'parse_literal' functions" " are also provided." ) def rejects_a_scalar_type_defining_parse_literal_but_not_parse_value(): def parse_literal(_node: ValueNode, _vars=None): return Undefined # pragma: no cover with raises(TypeError) as exc_info: GraphQLScalarType("SomeScalar", parse_literal=parse_literal) assert str(exc_info.value) == ( "SomeScalar must provide both" " 'parse_value' and 'parse_literal' as functions." ) def rejects_a_scalar_type_incorrectly_defining_parse_literal_and_value(): with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLScalarType( "SomeScalar", parse_value={}, parse_literal={} # type: ignore ) assert str(exc_info.value) == ( "SomeScalar must provide both" " 'parse_value' and 'parse_literal' as functions." ) def rejects_a_scalar_type_with_an_incorrect_ast_node(): with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLScalarType("SomeScalar", ast_node=Node()) # type: ignore msg = str(exc_info.value) assert msg == "SomeScalar AST node must be a TypeDefinitionNode." with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLScalarType( "SomeScalar", ast_node=TypeDefinitionNode() # type: ignore ) msg = str(exc_info.value) assert msg == "SomeScalar AST node must be a ScalarTypeDefinitionNode." def rejects_a_scalar_type_with_incorrect_extension_ast_nodes(): with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLScalarType( "SomeScalar", extension_ast_nodes=[Node()] # type: ignore ) assert str(exc_info.value) == ( "SomeScalar extension AST nodes must be specified" " as a collection of TypeExtensionNode instances." ) with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLScalarType( "SomeScalar", extension_ast_nodes=[TypeExtensionNode()] # type: ignore ) assert str(exc_info.value) == ( "SomeScalar extension AST nodes must be specified" " as a collection of ScalarTypeExtensionNode instances." ) def describe_type_system_fields(): def defines_a_field(): field = GraphQLField(GraphQLString) assert field.type is GraphQLString kwargs = field.to_kwargs() assert kwargs == { "type_": GraphQLString, "args": None, "resolve": None, "subscribe": None, "description": None, "deprecation_reason": None, "extensions": {}, "ast_node": None, } def defines_a_field_with_args(): arg = GraphQLArgument(GraphQLInt) field = GraphQLField(GraphQLString, {"arg": arg}) assert isinstance(field.args, dict) assert list(field.args) == ["arg"] assert field.args["arg"] is arg assert field.to_kwargs()["args"] == {"arg": arg} def defines_a_field_with_input_types_as_args(): field = GraphQLField(GraphQLString, {"arg": GraphQLString}) # type: ignore assert isinstance(field.args, dict) assert list(field.args) == ["arg"] arg = field.args["arg"] assert isinstance(arg, GraphQLArgument) assert arg.type is GraphQLString def defines_a_scalar_type_with_a_description(): description = "nice field" field = GraphQLField(GraphQLString, description=description) assert field.description is description assert field.to_kwargs()["description"] is description def defines_a_scalar_type_with_a_deprecation_reason(): deprecation_reason = "field is redundant" field = GraphQLField(GraphQLString, deprecation_reason=deprecation_reason) assert field.deprecation_reason is deprecation_reason assert field.to_kwargs()["deprecation_reason"] is deprecation_reason def rejects_a_field_with_incorrect_type(): with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLField(InputObjectType) # type: ignore assert str(exc_info.value) == "Field type must be an output type." def rejects_a_field_with_incorrect_args(): with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLField(GraphQLString, args=[]) # type: ignore assert str(exc_info.value) == ( "Field args must be a dict with argument names as keys." ) with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLField(GraphQLString, args={"arg": GraphQLObjectType}) # type: ignore assert str(exc_info.value) == ( "Field args must be GraphQLArguments or input type objects." ) def rejects_a_field_with_an_incorrectly_typed_description(): with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLField(GraphQLString, description=[]) # type: ignore assert str(exc_info.value) == "The description must be a string." def rejects_a_field_with_an_incorrectly_typed_deprecation_reason(): with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLField(GraphQLString, deprecation_reason=[]) # type: ignore assert str(exc_info.value) == "The deprecation reason must be a string." def rejects_a_field_with_an_incorrect_ast_node(): with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLField(GraphQLString, ast_node=Node()) # type: ignore assert str(exc_info.value) == "Field AST node must be a FieldDefinitionNode." def describe_type_system_objects(): def defines_an_object_type(): fields = {"f": GraphQLField(ScalarType)} interfaces = (InterfaceType,) type_ = GraphQLObjectType("AnotherObjectType", fields, interfaces) assert type_.name == "AnotherObjectType" assert type_.fields == fields assert type_.fields is not fields assert type_.interfaces == interfaces assert type_.interfaces is interfaces assert type_.extensions == {} kwargs = type_.to_kwargs() assert kwargs == { "name": "AnotherObjectType", "description": None, "fields": fields, "interfaces": interfaces, "is_type_of": None, "extensions": {}, "ast_node": None, "extension_ast_nodes": (), } def does_not_mutate_passed_field_definitions(): output_fields = { "field1": GraphQLField(ScalarType), "field2": GraphQLField( ScalarType, args={"id": GraphQLArgument(ScalarType)} ), } test_object_1 = GraphQLObjectType("Test1", output_fields) test_object_2 = GraphQLObjectType("Test2", output_fields) assert test_object_1.fields == test_object_2.fields assert output_fields == { "field1": GraphQLField(ScalarType), "field2": GraphQLField( ScalarType, args={"id": GraphQLArgument(ScalarType)} ), } input_fields = { "field1": GraphQLInputField(ScalarType), "field2": GraphQLInputField(ScalarType), } test_input_object_1 = GraphQLInputObjectType("Test1", input_fields) test_input_object_2 = GraphQLInputObjectType("Test2", input_fields) assert test_input_object_1.fields == test_input_object_2.fields assert input_fields == { "field1": GraphQLInputField(ScalarType), "field2": GraphQLInputField(ScalarType), } def defines_an_object_type_with_deprecated_field(): TypeWithDeprecatedField = GraphQLObjectType( "foo", { "bar": GraphQLField(ScalarType, deprecation_reason="A terrible reason"), "baz": GraphQLField(ScalarType, deprecation_reason=""), }, ) deprecated_field = TypeWithDeprecatedField.fields["bar"] assert deprecated_field == GraphQLField( ScalarType, deprecation_reason="A terrible reason" ) assert deprecated_field.deprecation_reason == "A terrible reason" deprecated_field = TypeWithDeprecatedField.fields["baz"] assert deprecated_field == GraphQLField(ScalarType, deprecation_reason="") assert deprecated_field.deprecation_reason == "" def accepts_an_object_type_with_output_type_as_field(): # this is a shortcut syntax for simple fields obj_type = GraphQLObjectType("SomeObject", {"f": ScalarType}) # type: ignore assert list(obj_type.fields) == ["f"] field = obj_type.fields["f"] assert isinstance(field, GraphQLField) assert field.type is ScalarType assert field.args == {} assert field.deprecation_reason is None def accepts_an_object_type_with_a_field_function(): obj_type = GraphQLObjectType( "SomeObject", lambda: {"f": GraphQLField(ScalarType)} ) assert list(obj_type.fields) == ["f"] field = obj_type.fields["f"] assert isinstance(field, GraphQLField) assert field.description is None assert field.type is ScalarType assert field.args == {} assert field.resolve is None assert field.subscribe is None assert field.deprecation_reason is None assert field.extensions == {} assert field.ast_node is None def thunk_for_fields_of_object_type_is_resolved_only_once(): calls = 0 def fields(): nonlocal calls calls += 1 return {"f": GraphQLField(ScalarType)} obj_type = GraphQLObjectType("SomeObject", fields) assert "f" in obj_type.fields assert calls == 1 assert "f" in obj_type.fields assert calls == 1 def accepts_an_object_type_with_field_args(): obj_type = GraphQLObjectType( "SomeObject", {"f": GraphQLField(ScalarType, args={"arg": GraphQLArgument(ScalarType)})}, ) field = obj_type.fields["f"] assert isinstance(field, GraphQLField) assert field.description is None assert field.type is ScalarType assert isinstance(field.args, dict) assert list(field.args) == ["arg"] arg = field.args["arg"] assert isinstance(arg, GraphQLArgument) assert arg.description is None assert arg.type is ScalarType assert arg.default_value is Undefined assert arg.deprecation_reason is None assert arg.extensions == {} assert arg.ast_node is None assert field.resolve is None assert field.subscribe is None assert field.deprecation_reason is None assert field.extensions == {} assert field.ast_node is None def accepts_an_object_type_with_list_interfaces(): obj_type = GraphQLObjectType("SomeObject", {}, [InterfaceType]) assert obj_type.interfaces == (InterfaceType,) def accepts_object_type_with_interfaces_as_a_function_returning_a_list(): obj_type = GraphQLObjectType("SomeObject", {}, lambda: [InterfaceType]) assert obj_type.interfaces == (InterfaceType,) def thunk_for_interfaces_of_object_type_is_resolved_only_once(): calls = 0 def interfaces(): nonlocal calls calls += 1 return [InterfaceType] obj_type = GraphQLObjectType("SomeObject", {}, interfaces) assert obj_type.interfaces == (InterfaceType,) assert calls == 1 assert obj_type.interfaces == (InterfaceType,) assert calls == 1 def accepts_a_lambda_as_an_object_field_resolver(): obj_type = GraphQLObjectType( "SomeObject", { "f": GraphQLField( ScalarType, resolve=lambda _obj, _info: {} # pragma: no cover ) }, ) assert obj_type.fields def accepts_an_object_type_with_ast_node_and_extension_ast_nodes(): ast_node = ObjectTypeDefinitionNode() extension_ast_nodes = [ObjectTypeExtensionNode()] object_type = GraphQLObjectType( "SomeObject", {"f": GraphQLField(ScalarType)}, ast_node=ast_node, extension_ast_nodes=extension_ast_nodes, ) assert object_type.ast_node is ast_node assert object_type.extension_ast_nodes == tuple(extension_ast_nodes) def rejects_an_object_type_with_incorrectly_typed_name(): with raises(TypeError, match="missing .* required .* 'name'"): # noinspection PyArgumentList GraphQLObjectType() # type: ignore with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLObjectType(None, {}) # type: ignore assert str(exc_info.value) == "Must provide name." with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLObjectType(42, {}) # type: ignore assert str(exc_info.value) == "Expected name to be a string." def rejects_an_object_type_with_invalid_name(): with raises(GraphQLError) as exc_info: GraphQLObjectType("", {}) assert str(exc_info.value) == "Expected name to be a non-empty string." with raises(GraphQLError) as exc_info: GraphQLObjectType("bad-name", {}) assert str(exc_info.value) == ( "Names must only contain [_a-zA-Z0-9] but 'bad-name' does not." ) def rejects_an_object_type_field_with_undefined_config(): undefined_field = cast(GraphQLField, None) obj_type = GraphQLObjectType("SomeObject", {"f": undefined_field}) with raises(TypeError) as exc_info: assert not obj_type.fields msg = str(exc_info.value) assert msg == "SomeObject fields must be GraphQLField or output type objects." def rejects_an_object_type_with_incorrectly_typed_fields(): invalid_field = cast(GraphQLField, [GraphQLField(ScalarType)]) obj_type = GraphQLObjectType("SomeObject", {"f": invalid_field}) with raises(TypeError) as exc_info: assert not obj_type.fields msg = str(exc_info.value) assert msg == "SomeObject fields must be GraphQLField or output type objects." def rejects_an_object_type_with_incorrectly_named_fields(): obj_type = GraphQLObjectType( "SomeObject", {"bad-name": GraphQLField(ScalarType)} ) with raises(GraphQLError) as exc_info: assert not obj_type.fields msg = str(exc_info.value) assert msg == "Names must only contain [_a-zA-Z0-9] but 'bad-name' does not." def rejects_an_object_type_field_function_that_returns_incorrect_type(): obj_type = GraphQLObjectType( "SomeObject", lambda: [GraphQLField(ScalarType)] # type: ignore ) with raises(TypeError) as exc_info: assert not obj_type.fields assert str(exc_info.value) == ( "SomeObject fields must be specified as a mapping with field names as keys." ) def rejects_an_object_type_field_function_that_raises_an_error(): def fields(): raise RuntimeError("Oops!") obj_type = GraphQLObjectType("SomeObject", fields) with raises(TypeError) as exc_info: assert not obj_type.fields assert str(exc_info.value) == "SomeObject fields cannot be resolved. Oops!" def rejects_an_object_type_with_incorrectly_typed_field_args(): invalid_args = [{"bad_args": GraphQLArgument(ScalarType)}] with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLObjectType( "SomeObject", { "badField": GraphQLField( ScalarType, args=invalid_args # type: ignore ) }, ) msg = str(exc_info.value) assert msg == "Field args must be a dict with argument names as keys." def rejects_an_object_type_with_incorrectly_named_field_args(): obj_type = GraphQLObjectType( "SomeObject", lambda: { "badField": GraphQLField( ScalarType, args={"bad-name": GraphQLArgument(ScalarType)} ) }, ) with raises(GraphQLError) as exc_info: assert not obj_type.fields msg = str(exc_info.value) assert msg == ( "SomeObject fields cannot be resolved." " Names must only contain [_a-zA-Z0-9] but 'bad-name' does not." ) def rejects_an_object_type_with_incorrectly_typed_interfaces(): obj_type = GraphQLObjectType("SomeObject", {}, interfaces={}) with raises(TypeError) as exc_info: assert not obj_type.interfaces assert str(exc_info.value) == ( "SomeObject interfaces must be specified" " as a collection of GraphQLInterfaceType instances." ) def rejects_object_type_with_incorrectly_typed_interfaces_as_a_function(): obj_type = GraphQLObjectType("SomeObject", {}, interfaces=lambda: {}) with raises(TypeError) as exc_info: assert not obj_type.interfaces assert str(exc_info.value) == ( "SomeObject interfaces must be specified" " as a collection of GraphQLInterfaceType instances." ) def rejects_object_type_with_interfaces_as_function_that_raises_an_error(): def interfaces(): raise RuntimeError("Oops!") obj_type = GraphQLObjectType("SomeObject", {}, interfaces=interfaces) with raises(TypeError) as exc_info: assert not obj_type.interfaces assert str(exc_info.value) == "SomeObject interfaces cannot be resolved. Oops!" def rejects_an_empty_object_field_resolver(): with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLObjectType( "SomeObject", {"field": GraphQLField(ScalarType, resolve={})}, # type: ignore ) msg = str(exc_info.value) assert msg == "Field resolver must be a function if provided, but got: {}." def rejects_a_constant_scalar_value_resolver(): with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLObjectType( "SomeObject", {"field": GraphQLField(ScalarType, resolve=0)}, # type: ignore ) msg = str(exc_info.value) assert msg == "Field resolver must be a function if provided, but got: 0." def rejects_an_object_type_with_an_incorrect_type_for_is_type_of(): with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLObjectType("AnotherObject", {}, is_type_of={}) # type: ignore assert str(exc_info.value) == ( "AnotherObject must provide 'is_type_of' as a function, but got: {}." ) def rejects_an_object_type_with_an_incorrect_ast_node(): with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLObjectType("SomeObject", {}, ast_node=Node()) # type: ignore msg = str(exc_info.value) assert msg == "SomeObject AST node must be a TypeDefinitionNode." with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLObjectType( "SomeObject", {}, ast_node=TypeDefinitionNode() # type: ignore ) msg = str(exc_info.value) assert msg == "SomeObject AST node must be an ObjectTypeDefinitionNode." def rejects_an_object_type_with_incorrect_extension_ast_nodes(): with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLObjectType( "SomeObject", {}, extension_ast_nodes=[Node()] # type: ignore ) assert str(exc_info.value) == ( "SomeObject extension AST nodes must be specified" " as a collection of TypeExtensionNode instances." ) with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLObjectType( "SomeObject", {}, extension_ast_nodes=[TypeExtensionNode()], # type: ignore ) assert str(exc_info.value) == ( "SomeObject extension AST nodes must be specified" " as a collection of ObjectTypeExtensionNode instances." ) def describe_type_system_interfaces(): def defines_an_interface_type(): fields = {"f": GraphQLField(ScalarType)} interface = GraphQLInterfaceType("AnotherInterface", fields) assert interface.name == "AnotherInterface" assert interface.fields == fields assert interface.fields is not fields assert interface.resolve_type is None assert interface.extensions == {} kwargs = interface.to_kwargs() assert kwargs == { "name": "AnotherInterface", "description": None, "fields": fields, "interfaces": (), "resolve_type": None, "extensions": {}, "ast_node": None, "extension_ast_nodes": (), } def accepts_an_interface_type_defining_resolve_type(): def resolve_type(_obj, _info, _type): pass interface = GraphQLInterfaceType( "AnotherInterface", {}, resolve_type=resolve_type ) assert interface.resolve_type is resolve_type def accepts_an_interface_type_with_output_types_as_fields(): interface = GraphQLInterfaceType( "AnotherInterface", {"someField": ScalarType} # type: ignore ) fields = interface.fields assert isinstance(fields, dict) assert list(fields) == ["someField"] field = fields["someField"] assert isinstance(field, GraphQLField) assert field.type is ScalarType def accepts_an_interface_type_with_a_field_function(): fields = {"f": GraphQLField(ScalarType)} interface = GraphQLInterfaceType("AnotherInterface", lambda: fields) assert interface.fields == fields def thunk_for_fields_of_interface_type_is_resolved_only_once(): calls = 0 def fields(): nonlocal calls calls += 1 return {"f": GraphQLField(ScalarType)} interface = GraphQLInterfaceType("AnotherInterface", fields) assert "f" in interface.fields assert calls == 1 assert "f" in interface.fields assert calls == 1 def accepts_an_interface_type_with_a_list_of_interfaces(): implementing = GraphQLInterfaceType( "AnotherInterface", {}, interfaces=[InterfaceType] ) assert implementing.interfaces == (InterfaceType,) def accepts_an_interface_type_with_an_interfaces_function(): implementing = GraphQLInterfaceType( "AnotherInterface", {}, interfaces=lambda: [InterfaceType] ) assert implementing.interfaces == (InterfaceType,) def thunk_for_interfaces_of_interface_type_is_resolved_only_once(): calls = 0 def interfaces(): nonlocal calls calls += 1 return [InterfaceType] implementing = GraphQLInterfaceType( "AnotherInterface", {}, interfaces=interfaces ) assert implementing.interfaces == (InterfaceType,) assert calls == 1 assert implementing.interfaces == (InterfaceType,) assert calls == 1 def accepts_an_interface_type_with_ast_node_and_extension_ast_nodes(): ast_node = InterfaceTypeDefinitionNode() extension_ast_nodes = [InterfaceTypeExtensionNode()] interface_type = GraphQLInterfaceType( "SomeInterface", {"f": GraphQLField(ScalarType)}, ast_node=ast_node, extension_ast_nodes=extension_ast_nodes, ) assert interface_type.ast_node is ast_node assert interface_type.extension_ast_nodes == tuple(extension_ast_nodes) def rejects_an_interface_type_with_incorrectly_typed_fields(): interface = GraphQLInterfaceType("SomeInterface", []) # type: ignore with raises(TypeError) as exc_info: assert not interface.fields assert str(exc_info.value) == ( "SomeInterface fields must be specified" " as a mapping with field names as keys." ) interface = GraphQLInterfaceType( "SomeInterface", {"f": InputObjectType} # type: ignore ) with raises(TypeError) as exc_info: assert not interface.fields assert str(exc_info.value) == ( "SomeInterface fields must be GraphQLField or output type objects." ) def rejects_an_interface_type_with_unresolvable_fields(): def fields(): raise RuntimeError("Oops!") interface = GraphQLInterfaceType("SomeInterface", fields) with raises(TypeError) as exc_info: assert not interface.fields assert str(exc_info.value) == "SomeInterface fields cannot be resolved. Oops!" def rejects_an_interface_type_with_incorrectly_typed_name(): with raises(TypeError, match="missing .* required .* 'name'"): # noinspection PyArgumentList GraphQLInterfaceType() # type: ignore with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLInterfaceType(None, {}) # type: ignore assert str(exc_info.value) == "Must provide name." with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLInterfaceType(42, {}) # type: ignore assert str(exc_info.value) == "Expected name to be a string." def rejects_an_interface_type_with_invalid_name(): with raises(GraphQLError) as exc_info: GraphQLInterfaceType("", {}) assert str(exc_info.value) == "Expected name to be a non-empty string." with raises(GraphQLError) as exc_info: GraphQLInterfaceType("bad-name", {}) assert str(exc_info.value) == ( "Names must only contain [_a-zA-Z0-9] but 'bad-name' does not." ) def rejects_an_interface_type_with_incorrectly_typed_interfaces(): interface = GraphQLInterfaceType("AnotherInterface", {}, lambda: {}) with raises(TypeError) as exc_info: assert not interface.interfaces assert str(exc_info.value) == ( "AnotherInterface interfaces must be specified" " as a collection of GraphQLInterfaceType instances." ) def rejects_an_interface_type_with_unresolvable_interfaces(): def interfaces(): raise RuntimeError("Oops!") interface = GraphQLInterfaceType("AnotherInterface", {}, interfaces) with raises(TypeError) as exc_info: assert not interface.interfaces assert ( str(exc_info.value) == "AnotherInterface interfaces cannot be resolved. Oops!" ) def rejects_an_interface_type_with_an_incorrect_type_for_resolve_type(): with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLInterfaceType( "AnotherInterface", {}, resolve_type={} # type: ignore ) assert str(exc_info.value) == ( "AnotherInterface must provide 'resolve_type' as a function," " but got: {}." ) def rejects_an_interface_type_with_an_incorrect_ast_node(): with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLInterfaceType("SomeInterface", {}, ast_node=Node()) # type: ignore msg = str(exc_info.value) assert msg == "SomeInterface AST node must be a TypeDefinitionNode." with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLInterfaceType( "SomeInterface", {}, ast_node=TypeDefinitionNode() # type: ignore ) msg = str(exc_info.value) assert msg == "SomeInterface AST node must be an InterfaceTypeDefinitionNode." def rejects_an_interface_type_with_incorrect_extension_ast_nodes(): with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLInterfaceType( "SomeInterface", {}, extension_ast_nodes=[Node()] # type: ignore ) assert str(exc_info.value) == ( "SomeInterface extension AST nodes must be specified" " as a collection of TypeExtensionNode instances." ) with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLInterfaceType( "SomeInterface", {}, extension_ast_nodes=[TypeExtensionNode()], # type: ignore ) assert str(exc_info.value) == ( "SomeInterface extension AST nodes must be specified" " as a collection of InterfaceTypeExtensionNode instances." ) def describe_type_system_unions(): def accepts_a_union_type_defining_resolve_type(): assert GraphQLUnionType("SomeUnion", [ObjectType]) def accepts_a_union_type_with_list_types(): union_type = GraphQLUnionType("SomeUnion", [ObjectType]) assert union_type.types == (ObjectType,) def accepts_a_union_type_with_function_returning_a_list_of_types(): union_type = GraphQLUnionType("SomeUnion", lambda: [ObjectType]) assert union_type.types == (ObjectType,) def accepts_a_union_type_without_types(): with raises(TypeError, match="missing 1 required positional argument: 'types'"): # noinspection PyArgumentList GraphQLUnionType("SomeUnion") # type: ignore union_type = GraphQLUnionType("SomeUnion", None) # type: ignore assert union_type.types == () union_type = GraphQLUnionType("SomeUnion", []) assert union_type.types == () def accepts_a_union_type_with_ast_node_and_extension_ast_nodes(): ast_node = UnionTypeDefinitionNode() extension_ast_nodes = [UnionTypeExtensionNode()] union_type = GraphQLUnionType( "SomeUnion", [ObjectType], ast_node=ast_node, extension_ast_nodes=extension_ast_nodes, ) assert union_type.ast_node is ast_node assert union_type.extension_ast_nodes == tuple(extension_ast_nodes) def rejects_a_union_type_with_incorrectly_typed__name(): with raises(TypeError, match="missing .* required .* 'name'"): # noinspection PyArgumentList GraphQLUnionType() # type: ignore with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLUnionType(None, []) # type: ignore assert str(exc_info.value) == "Must provide name." with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLUnionType(42, []) # type: ignore assert str(exc_info.value) == "Expected name to be a string." def rejects_a_union_type_with_invalid_name(): with raises(GraphQLError) as exc_info: GraphQLUnionType("", []) assert str(exc_info.value) == "Expected name to be a non-empty string." with raises(GraphQLError) as exc_info: GraphQLUnionType("bad-name", []) assert str(exc_info.value) == ( "Names must only contain [_a-zA-Z0-9] but 'bad-name' does not." ) def rejects_a_union_type_with_an_incorrect_type_for_resolve_type(): with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLUnionType("SomeUnion", [], resolve_type={}) # type: ignore assert str(exc_info.value) == ( "SomeUnion must provide 'resolve_type' as a function, but got: {}." ) def rejects_a_union_type_with_incorrectly_typed_types(): union_type = GraphQLUnionType("SomeUnion", {"type": ObjectType}) # type: ignore with raises(TypeError) as exc_info: assert not union_type.types assert str(exc_info.value) == ( "SomeUnion types must be specified" " as a collection of GraphQLObjectType instances." ) def rejects_a_union_type_with_unresolvable_types(): def types(): raise RuntimeError("Oops!") union_type = GraphQLUnionType("SomeUnion", types) with raises(TypeError) as exc_info: assert not union_type.types assert str(exc_info.value) == "SomeUnion types cannot be resolved. Oops!" def rejects_a_union_type_with_an_incorrect_ast_node(): with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLUnionType("SomeUnion", [], ast_node=Node()) # type: ignore msg = str(exc_info.value) assert msg == "SomeUnion AST node must be a TypeDefinitionNode." with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLUnionType( "SomeUnion", [], ast_node=TypeDefinitionNode() # type: ignore ) msg = str(exc_info.value) assert msg == "SomeUnion AST node must be a UnionTypeDefinitionNode." def rejects_a_union_type_with_incorrect_extension_ast_nodes(): with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLUnionType( "SomeUnion", [], extension_ast_nodes=[Node()] # type: ignore ) assert str(exc_info.value) == ( "SomeUnion extension AST nodes must be specified" " as a collection of TypeExtensionNode instances." ) with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLUnionType( "SomeUnion", [], extension_ast_nodes=[TypeExtensionNode()], # type: ignore ) assert str(exc_info.value) == ( "SomeUnion extension AST nodes must be specified" " as a collection of UnionTypeExtensionNode instances." ) def describe_type_system_enums(): def defines_an_enum_using_a_dict(): enum_type = GraphQLEnumType("SomeEnum", {"RED": 1, "BLUE": 2}) assert enum_type.values == { "RED": GraphQLEnumValue(1), "BLUE": GraphQLEnumValue(2), } def defines_an_enum_using_an_enum_value_map(): red, blue = GraphQLEnumValue(1), GraphQLEnumValue(2) enum_type = GraphQLEnumType("SomeEnum", {"RED": red, "BLUE": blue}) assert enum_type.values == {"RED": red, "BLUE": blue} def defines_an_enum_using_a_python_enum(): Colors = Enum("Colors", "RED BLUE") enum_type = GraphQLEnumType("SomeEnum", Colors) assert enum_type.values == { "RED": GraphQLEnumValue(1), "BLUE": GraphQLEnumValue(2), } def defines_an_enum_using_values_of_a_python_enum(): Colors = Enum("Colors", "RED BLUE") enum_type = GraphQLEnumType("SomeEnum", Colors, names_as_values=False) assert enum_type.values == { "RED": GraphQLEnumValue(1), "BLUE": GraphQLEnumValue(2), } def defines_an_enum_using_names_of_a_python_enum(): Colors = Enum("Colors", "RED BLUE") enum_type = GraphQLEnumType("SomeEnum", Colors, names_as_values=True) assert enum_type.values == { "RED": GraphQLEnumValue("RED"), "BLUE": GraphQLEnumValue("BLUE"), } def defines_an_enum_using_members_of_a_python_enum(): Colors = Enum("Colors", "RED BLUE") enum_type = GraphQLEnumType("SomeEnum", Colors, names_as_values=None) assert enum_type.values == { "RED": GraphQLEnumValue(Colors.RED), "BLUE": GraphQLEnumValue(Colors.BLUE), } def defines_an_enum_type_with_a_description(): description = "nice enum" enum_type = GraphQLEnumType("SomeEnum", {}, description=description) assert enum_type.description is description assert enum_type.to_kwargs()["description"] is description def defines_an_enum_type_with_deprecated_value(): EnumTypeWithDeprecatedValue = GraphQLEnumType( name="EnumWithDeprecatedValue", values={"foo": GraphQLEnumValue(deprecation_reason="Just because")}, ) deprecated_value = EnumTypeWithDeprecatedValue.values["foo"] assert deprecated_value == GraphQLEnumValue(deprecation_reason="Just because") assert deprecated_value.deprecation_reason == "Just because" assert deprecated_value.value is None assert deprecated_value.extensions == {} assert deprecated_value.ast_node is None def defines_an_enum_type_with_a_value_of_none_and_invalid(): EnumTypeWithNullishValue = GraphQLEnumType( name="EnumWithNullishValue", values={"NULL": None, "NAN": nan, "NO_CUSTOM_VALUE": Undefined}, ) assert list(EnumTypeWithNullishValue.values) == [ "NULL", "NAN", "NO_CUSTOM_VALUE", ] null_value = EnumTypeWithNullishValue.values["NULL"] assert null_value.description is None assert null_value.value is None assert null_value.deprecation_reason is None assert null_value.extensions == {} assert null_value.ast_node is None null_value = EnumTypeWithNullishValue.values["NAN"] assert null_value.description is None assert isnan(null_value.value) assert null_value.deprecation_reason is None assert null_value.extensions == {} assert null_value.ast_node is None no_custom_value = EnumTypeWithNullishValue.values["NO_CUSTOM_VALUE"] assert no_custom_value.description is None assert no_custom_value.value is Undefined assert no_custom_value.deprecation_reason is None assert no_custom_value.extensions == {} assert no_custom_value.ast_node is None def accepts_a_well_defined_enum_type_with_empty_value_definition(): enum_type = GraphQLEnumType("SomeEnum", {"FOO": None, "BAR": None}) assert enum_type.values["FOO"].value is None assert enum_type.values["BAR"].value is None def accepts_a_well_defined_enum_type_with_internal_value_definition(): enum_type = GraphQLEnumType("SomeEnum", {"FOO": 10, "BAR": 20}) assert enum_type.values["FOO"].value == 10 assert enum_type.values["BAR"].value == 20 enum_type = GraphQLEnumType( "SomeEnum", {"FOO": GraphQLEnumValue(10), "BAR": GraphQLEnumValue(20)} ) assert enum_type.values["FOO"].value == 10 assert enum_type.values["BAR"].value == 20 def serializes_an_enum(): enum_type = GraphQLEnumType( "SomeEnum", {"FOO": "fooValue", "BAR": ["barValue"], "BAZ": None} ) assert enum_type.values["FOO"].value == "fooValue" assert enum_type.values["BAR"].value == ["barValue"] assert enum_type.values["BAZ"].value is None with raises(GraphQLError) as exc_info: enum_type.serialize(None) msg = exc_info.value.message assert msg == "Enum 'SomeEnum' cannot represent value: None" with raises(GraphQLError) as exc_info: enum_type.serialize(Undefined) msg = exc_info.value.message assert msg == "Enum 'SomeEnum' cannot represent value: Undefined" assert enum_type.serialize("fooValue") == "FOO" with raises(GraphQLError) as exc_info: enum_type.serialize("FOO") msg = exc_info.value.message assert msg == "Enum 'SomeEnum' cannot represent value: 'FOO'" assert enum_type.serialize(["barValue"]) == "BAR" with raises(GraphQLError) as exc_info: enum_type.serialize("BAR") msg = exc_info.value.message assert msg == "Enum 'SomeEnum' cannot represent value: 'BAR'" assert enum_type.serialize("BAZ") == "BAZ" with raises(GraphQLError) as exc_info: enum_type.serialize("bazValue") msg = exc_info.value.message assert msg == "Enum 'SomeEnum' cannot represent value: 'bazValue'" with raises(GraphQLError) as exc_info: enum_type.serialize(["bazValue"]) msg = exc_info.value.message assert msg == "Enum 'SomeEnum' cannot represent value: ['bazValue']" def use_first_name_for_duplicate_values(): enum_type = GraphQLEnumType("SomeEnum", {"FOO": "fooValue", "BAR": "fooValue"}) assert enum_type.values["FOO"].value == "fooValue" assert enum_type.values["BAR"].value == "fooValue" assert enum_type.serialize("fooValue") == "FOO" def parses_an_enum(): enum_type = GraphQLEnumType( "SomeEnum", {"FOO": "fooValue", "BAR": ["barValue"], "BAZ": None} ) assert enum_type.parse_value("FOO") == "fooValue" with raises(GraphQLError) as exc_info: enum_type.parse_value("fooValue") msg = exc_info.value.message assert msg == "Value 'fooValue' does not exist in 'SomeEnum' enum." assert enum_type.parse_value("BAR") == ["barValue"] with raises(GraphQLError) as exc_info: # noinspection PyTypeChecker enum_type.parse_value(["barValue"]) # type: ignore msg = exc_info.value.message assert msg == "Enum 'SomeEnum' cannot represent non-string value: ['barValue']." assert enum_type.parse_value("BAZ") is None assert enum_type.parse_literal(EnumValueNode(value="FOO")) == "fooValue" with raises(GraphQLError) as exc_info: enum_type.parse_literal(StringValueNode(value="FOO")) assert exc_info.value.message == ( "Enum 'SomeEnum' cannot represent non-enum value: \"FOO\"." " Did you mean the enum value 'FOO'?" ) with raises(GraphQLError) as exc_info: enum_type.parse_literal(EnumValueNode(value="fooValue")) msg = exc_info.value.message assert msg == "Value 'fooValue' does not exist in 'SomeEnum' enum." assert enum_type.parse_literal(EnumValueNode(value="BAR")) == ["barValue"] with raises(GraphQLError) as exc_info: enum_type.parse_literal(StringValueNode(value="BAR")) assert exc_info.value.message == ( "Enum 'SomeEnum' cannot represent non-enum value: \"BAR\"." " Did you mean the enum value 'BAR' or 'BAZ'?" ) assert enum_type.parse_literal(EnumValueNode(value="BAZ")) is None with raises(GraphQLError) as exc_info: enum_type.parse_literal(StringValueNode(value="BAZ")) assert exc_info.value.message == ( "Enum 'SomeEnum' cannot represent non-enum value: \"BAZ\"." " Did you mean the enum value 'BAZ' or 'BAR'?" ) def accepts_an_enum_type_with_ast_node_and_extension_ast_nodes(): ast_node = EnumTypeDefinitionNode() extension_ast_nodes = [EnumTypeExtensionNode()] enum_type = GraphQLEnumType( "SomeEnum", {}, ast_node=ast_node, extension_ast_nodes=extension_ast_nodes, ) assert enum_type.ast_node is ast_node assert enum_type.extension_ast_nodes == tuple(extension_ast_nodes) def rejects_an_enum_type_with_incorrectly_typed_name(): with raises(TypeError, match="missing .* required .* 'name'"): # noinspection PyArgumentList GraphQLEnumType() # type: ignore with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLEnumType(None, {}) # type: ignore assert str(exc_info.value) == "Must provide name." with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLEnumType(42, {}) # type: ignore assert str(exc_info.value) == "Expected name to be a string." def rejects_an_enum_type_with_invalid_name(): values: Dict[str, GraphQLEnumValue] = {} with raises(GraphQLError) as exc_info: GraphQLEnumType("", values) assert str(exc_info.value) == "Expected name to be a non-empty string." with raises(GraphQLError) as exc_info: GraphQLEnumType("bad-name", values) assert str(exc_info.value) == ( "Names must only contain [_a-zA-Z0-9] but 'bad-name' does not." ) def rejects_an_enum_type_with_incorrectly_named_values(): with raises(GraphQLError) as exc_info: GraphQLEnumType("SomeEnum", {"bad-name": GraphQLField(ScalarType)}) msg = str(exc_info.value) assert msg == "Names must only contain [_a-zA-Z0-9] but 'bad-name' does not." def rejects_an_enum_type_without_values(): with raises(TypeError, match="missing .* required .* 'values'"): # noinspection PyArgumentList GraphQLEnumType("SomeEnum") # type: ignore with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLEnumType("SomeEnum", values=None) # type: ignore assert str(exc_info.value) == ( "SomeEnum values must be an Enum or a mapping with value names as keys." ) def rejects_an_enum_type_with_incorrectly_typed_values(): with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLEnumType("SomeEnum", [{"FOO": 10}]) # type: ignore assert str(exc_info.value) == ( "SomeEnum values must be an Enum or a mapping with value names as keys." ) def rejects_an_enum_type_with_an_incorrectly_typed_description(): with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLEnumType("SomeEnum", {"foo": None}, description=[]) # type: ignore assert str(exc_info.value) == "The description must be a string." def rejects_an_enum_type_with_an_incorrect_ast_node(): with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLEnumType("SomeEnum", {"foo": None}, ast_node=Node()) # type: ignore msg = str(exc_info.value) assert msg == "SomeEnum AST node must be a TypeDefinitionNode." with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLEnumType( "SomeEnum", {"foo": None}, ast_node=TypeDefinitionNode() # type: ignore ) msg = str(exc_info.value) assert msg == "SomeEnum AST node must be an EnumTypeDefinitionNode." def rejects_an_enum_type_with_incorrect_extension_ast_nodes(): with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLEnumType( "SomeEnum", {"foo": None}, extension_ast_nodes=[Node()] # type: ignore ) assert str(exc_info.value) == ( "SomeEnum extension AST nodes must be specified" " as a collection of TypeExtensionNode instances." ) with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLEnumType( "SomeEnum", {"foo": None}, extension_ast_nodes=[TypeExtensionNode()], # type: ignore ) assert str(exc_info.value) == ( "SomeEnum extension AST nodes must be specified" " as a collection of EnumTypeExtensionNode instances." ) def describe_enum_values(): def accepts_an_enum_value_without_value(): enum_value = GraphQLEnumValue() assert enum_value.value is None assert enum_value.to_kwargs()["value"] is None def accepts_an_enum_value_with_a_value(): value = object() enum_value = GraphQLEnumValue(value) assert enum_value.value is value assert enum_value.to_kwargs()["value"] is value def accepts_an_enum_value_with_a_description(): description = "nice enum value" enum_value = GraphQLEnumValue(description=description) assert enum_value.description is description assert enum_value.to_kwargs()["description"] is description def accepts_an_enum_value_with_deprecation_reason(): deprecation_reason = "This has been overvalued" enum_value = GraphQLEnumValue(deprecation_reason=deprecation_reason) assert enum_value.deprecation_reason is deprecation_reason assert enum_value.to_kwargs()["deprecation_reason"] is deprecation_reason def can_compare_enum_values(): assert GraphQLEnumValue() == GraphQLEnumValue() assert GraphQLEnumValue( "value", description="description", deprecation_reason="reason" ) == GraphQLEnumValue( "value", description="description", deprecation_reason="reason" ) assert GraphQLEnumValue("value 1") != GraphQLEnumValue("value 2") assert GraphQLEnumValue(description="description 1") != GraphQLEnumValue( description="description 2" ) assert GraphQLEnumValue(deprecation_reason="reason 1") != GraphQLEnumValue( deprecation_reason="reason 2" ) def rejects_an_enum_value_with_an_incorrectly_typed_description(): with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLEnumValue(description=[]) # type: ignore msg = str(exc_info.value) assert msg == "The description of the enum value must be a string." def rejects_an_enum_value_with_an_incorrectly_typed_deprecation_reason(): with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLEnumValue(deprecation_reason=[]) # type: ignore msg = str(exc_info.value) assert msg == "The deprecation reason for the enum value must be a string." def rejects_an_enum_value_with_an_incorrect_ast_node(): with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLEnumValue(ast_node=TypeDefinitionNode()) # type: ignore msg = str(exc_info.value) assert msg == "AST node must be an EnumValueDefinitionNode." def describe_type_system_input_objects(): def accepts_an_input_object_type_with_a_description(): description = "nice input object" input_obj_type = GraphQLInputObjectType( "SomeInputObject", {}, description=description ) assert input_obj_type.description is description assert input_obj_type.to_kwargs()["description"] is description def accepts_an_input_object_type_with_an_out_type_function(): # This is an extension of GraphQL.js. input_obj_type = GraphQLInputObjectType("SomeInputObject", {}, out_type=dict) assert input_obj_type.out_type is dict assert input_obj_type.to_kwargs()["out_type"] is dict def provides_default_out_type_if_omitted(): # This is an extension of GraphQL.js. input_obj_type = GraphQLInputObjectType("SomeInputObject", {}) assert input_obj_type.out_type is GraphQLInputObjectType.out_type assert input_obj_type.to_kwargs()["out_type"] is None def accepts_an_input_object_type_with_ast_node_and_extension_ast_nodes(): ast_node = InputObjectTypeDefinitionNode() extension_ast_nodes = [InputObjectTypeExtensionNode()] input_obj_type = GraphQLInputObjectType( "SomeInputObject", {}, ast_node=ast_node, extension_ast_nodes=extension_ast_nodes, ) assert input_obj_type.ast_node is ast_node assert input_obj_type.extension_ast_nodes == tuple(extension_ast_nodes) def rejects_an_input_object_type_with_incorrect_out_type_function(): with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLInputObjectType("SomeInputObject", {}, out_type=[]) # type: ignore assert str(exc_info.value) == ( "The out type for SomeInputObject must be a function or a class." ) def rejects_an_input_object_type_with_incorrectly_typed_description(): # noinspection PyTypeChecker with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLInputObjectType( "SomeInputObject", {}, description=[] # type: ignore ) assert str(exc_info.value) == "The description must be a string." def rejects_an_input_object_type_with_an_incorrect_ast_node(): with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLInputObjectType( "SomeInputObject", {}, ast_node=Node() # type: ignore ) msg = str(exc_info.value) assert msg == "SomeInputObject AST node must be a TypeDefinitionNode." with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLInputObjectType( "SomeInputObject", {}, ast_node=TypeDefinitionNode() # type: ignore ) assert str(exc_info.value) == ( "SomeInputObject AST node must be an InputObjectTypeDefinitionNode." ) def rejects_an_input_object_type_with_incorrect_extension_ast_nodes(): with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLInputObjectType( "SomeInputObject", {}, extension_ast_nodes=[Node()] # type: ignore ) assert str(exc_info.value) == ( "SomeInputObject extension AST nodes must be specified" " as a collection of TypeExtensionNode instances." ) with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLInputObjectType( "SomeInputObject", {}, extension_ast_nodes=[TypeExtensionNode()], # type: ignore ) assert str(exc_info.value) == ( "SomeInputObject extension AST nodes must be specified" " as a collection of InputObjectTypeExtensionNode instances." ) def describe_input_objects_must_have_fields(): def accepts_an_input_object_type_with_fields(): input_obj_type = GraphQLInputObjectType( "SomeInputObject", {"f": GraphQLInputField(ScalarType)} ) assert list(input_obj_type.fields) == ["f"] input_field = input_obj_type.fields["f"] assert isinstance(input_field, GraphQLInputField) assert input_field.description is None assert input_field.type is ScalarType assert input_field.default_value is Undefined assert input_field.deprecation_reason is None assert input_field.extensions == {} assert input_field.ast_node is None assert input_field.out_name is None def accepts_an_input_object_type_with_input_type_as_field(): # this is a shortcut syntax for simple input fields input_obj_type = GraphQLInputObjectType( "SomeInputObject", {"f": ScalarType} # type: ignore ) field = input_obj_type.fields["f"] assert isinstance(field, GraphQLInputField) assert field.type is ScalarType def accepts_an_input_object_type_with_a_field_function(): input_obj_type = GraphQLInputObjectType( "SomeInputObject", lambda: {"f": GraphQLInputField(ScalarType)} ) assert list(input_obj_type.fields) == ["f"] input_field = input_obj_type.fields["f"] assert isinstance(input_field, GraphQLInputField) assert input_field.description is None assert input_field.type is ScalarType assert input_field.default_value is Undefined assert input_field.deprecation_reason is None assert input_field.extensions == {} assert input_field.ast_node is None assert input_field.out_name is None def rejects_an_input_object_type_with_incorrectly_typed_name(): with raises(TypeError, match="missing .* required .* 'name'"): # noinspection PyArgumentList GraphQLInputObjectType() # type: ignore with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLInputObjectType(None, {}) # type: ignore assert str(exc_info.value) == "Must provide name." with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLInputObjectType(42, {}) # type: ignore assert str(exc_info.value) == "Expected name to be a string." def rejects_an_input_object_type_with_invalid_name(): with raises(GraphQLError) as exc_info: GraphQLInputObjectType("", {}) assert str(exc_info.value) == "Expected name to be a non-empty string." with raises(GraphQLError) as exc_info: GraphQLInputObjectType("bad-name", {}) assert str(exc_info.value) == ( "Names must only contain [_a-zA-Z0-9] but 'bad-name' does not." ) def rejects_an_input_object_type_with_incorrect_fields(): input_obj_type = GraphQLInputObjectType( "SomeInputObject", [] # type: ignore ) with raises(TypeError) as exc_info: assert not input_obj_type.fields assert str(exc_info.value) == ( "SomeInputObject fields must be specified" " as a mapping with field names as keys." ) def rejects_an_input_object_type_with_incorrect_fields_function(): input_obj_type = GraphQLInputObjectType( "SomeInputObject", lambda: [] # type: ignore ) with raises(TypeError) as exc_info: assert not input_obj_type.fields assert str(exc_info.value) == ( "SomeInputObject fields must be specified" " as a mapping with field names as keys." ) def rejects_an_input_object_type_with_incorrectly_named_fields(): input_obj_type = GraphQLInputObjectType( "SomeInputObject", {"bad-name": GraphQLInputField(ScalarType)} ) with raises(GraphQLError) as exc_info: assert not input_obj_type.fields msg = str(exc_info.value) assert msg == ( "Names must only contain [_a-zA-Z0-9] but 'bad-name' does not." ) def rejects_an_input_object_type_with_unresolvable_fields(): def fields(): raise RuntimeError("Oops!") input_obj_type = GraphQLInputObjectType("SomeInputObject", fields) with raises(TypeError) as exc_info: assert not input_obj_type.fields assert str(exc_info.value) == ( "SomeInputObject fields cannot be resolved. Oops!" ) def describe_input_objects_fields_must_not_have_resolvers(): def rejects_an_input_object_type_with_resolvers(): def resolve(): pass with raises( TypeError, match="got an unexpected keyword argument 'resolve'" ): # noinspection PyArgumentList GraphQLInputObjectType( "SomeInputObject", { "f": GraphQLInputField( # type: ignore ScalarType, resolve=resolve, ) }, ) input_obj_type = GraphQLInputObjectType( "SomeInputObject", {"f": GraphQLField(ScalarType, resolve=resolve)}, # type: ignore ) with raises(TypeError) as exc_info: assert not input_obj_type.fields assert str(exc_info.value) == ( "SomeInputObject fields must be GraphQLInputField" " or input type objects." ) def rejects_an_input_object_type_with_resolver_constant(): with raises( TypeError, match="got an unexpected keyword argument 'resolve'" ): # noinspection PyArgumentList GraphQLInputObjectType( "SomeInputObject", {"f": GraphQLInputField(ScalarType, resolve={})}, # type: ignore ) def describe_type_system_arguments(): def accepts_an_argument_with_a_description(): description = "nice argument" argument = GraphQLArgument(GraphQLString, description=description) assert argument.description is description assert argument.to_kwargs()["description"] is description def accepts_an_argument_with_an_out_name(): # This is an extension of GraphQL.js. out_name = "python_rocks" argument = GraphQLArgument(GraphQLString, out_name=out_name) assert argument.out_name is out_name assert argument.to_kwargs()["out_name"] is out_name def provides_no_out_name_if_omitted(): # This is an extension of GraphQL.js. argument = GraphQLArgument(GraphQLString) assert argument.out_name is None assert argument.to_kwargs()["out_name"] is None def accepts_an_argument_with_an_ast_node(): ast_node = InputValueDefinitionNode() argument = GraphQLArgument(GraphQLString, ast_node=ast_node) assert argument.ast_node is ast_node assert argument.to_kwargs()["ast_node"] is ast_node def rejects_an_argument_without_type(): with raises(TypeError, match="missing 1 required positional argument"): # noinspection PyArgumentList GraphQLArgument() # type: ignore def rejects_an_argument_with_an_incorrect_type(): with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLArgument(GraphQLObjectType) # type: ignore msg = str(exc_info.value) assert msg == "Argument type must be a GraphQL input type." def rejects_an_argument_with_an_incorrectly_typed_description(): with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLArgument(GraphQLString, description=[]) # type: ignore assert str(exc_info.value) == "Argument description must be a string." def rejects_an_argument_with_an_incorrectly_typed_deprecation_reason(): with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLArgument(GraphQLString, deprecation_reason=[]) # type: ignore assert str(exc_info.value) == "Argument deprecation reason must be a string." def rejects_an_argument_with_an_incorrect_out_name(): # This is an extension of GraphQL.js. with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLArgument(GraphQLString, out_name=[]) # type: ignore assert str(exc_info.value) == "Argument out name must be a string." def rejects_an_argument_with_an_incorrect_ast_node(): with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLArgument(GraphQLString, ast_node=Node()) # type: ignore msg = str(exc_info.value) assert msg == "Argument AST node must be an InputValueDefinitionNode." def describe_type_system_input_fields(): def accepts_an_input_field_with_a_description(): description = "good input" input_field = GraphQLInputField(GraphQLString, description=description) assert input_field.description is description assert input_field.to_kwargs()["description"] is description def accepts_an_input_field_with_an_out_name(): # This is an extension of GraphQL.js. out_name = "python_rocks" input_field = GraphQLInputField(GraphQLString, out_name=out_name) assert input_field.out_name is out_name assert input_field.to_kwargs()["out_name"] is out_name def provides_no_out_name_if_omitted(): # This is an extension of GraphQL.js. input_field = GraphQLInputField(GraphQLString) assert input_field.out_name is None assert input_field.to_kwargs()["out_name"] is None def accepts_an_input_field_with_an_ast_node(): ast_node = InputValueDefinitionNode() input_field = GraphQLArgument(GraphQLString, ast_node=ast_node) assert input_field.ast_node is ast_node assert input_field.to_kwargs()["ast_node"] is ast_node def rejects_an_input_field_without_type(): with raises(TypeError, match="missing 1 required positional argument"): # noinspection PyArgumentList GraphQLInputField() # type: ignore def rejects_an_input_field_with_an_incorrect_type(): with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLInputField(GraphQLObjectType) # type: ignore msg = str(exc_info.value) assert msg == "Input field type must be a GraphQL input type." def rejects_an_input_field_with_an_incorrectly_typed_description(): with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLInputField(GraphQLString, description=[]) # type: ignore assert str(exc_info.value) == "Input field description must be a string." def rejects_an_input_field_with_an_incorrectly_typed_deprecation_reason(): with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLInputField(GraphQLString, deprecation_reason=[]) # type: ignore assert str(exc_info.value) == "Input field deprecation reason must be a string." def rejects_an_input_field_with_an_incorrect_out_name(): # This is an extension of GraphQL.js. with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLInputField(GraphQLString, out_name=[]) # type: ignore assert str(exc_info.value) == "Input field out name must be a string." def rejects_an_input_field_with_an_incorrect_ast_node(): with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLInputField(GraphQLString, ast_node=Node()) # type: ignore msg = str(exc_info.value) assert msg == "Input field AST node must be an InputValueDefinitionNode." def deprecation_reason_is_preserved_on_fields(): input_obj_type = GraphQLInputObjectType( "someInputObject", { "deprecatedField": GraphQLInputField( ScalarType, deprecation_reason="not used anymore" ) }, ) deprecated_field = input_obj_type.fields["deprecatedField"] assert ( input_obj_type.to_kwargs()["fields"]["deprecatedField"] is deprecated_field ) deprecation_reason = deprecated_field.deprecation_reason assert deprecation_reason == "not used anymore" assert deprecated_field.to_kwargs()["deprecation_reason"] is deprecation_reason def describe_type_system_list(): types = [ ScalarType, ObjectType, UnionType, InterfaceType, EnumType, InputObjectType, ListOfScalarsType, NonNullScalarType, ] @mark.parametrize("type_", types, ids=lambda type_: type_.__class__.__name__) def accepts_a_type_as_item_type_of_list(type_): assert GraphQLList(type_) not_types = [{}, dict, str, object, None] @mark.parametrize("type_", not_types, ids=lambda type_: repr(type_)) def rejects_a_non_type_as_item_type_of_list(type_): with raises(TypeError) as exc_info: GraphQLList(type_) assert str(exc_info.value) == ( f"Can only create a wrapper for a GraphQLType, but got: {type_}." ) def describe_type_system_non_null(): types = [ ScalarType, ObjectType, UnionType, InterfaceType, EnumType, InputObjectType, ListOfScalarsType, ListOfNonNullScalarsType, ] @mark.parametrize("type_", types, ids=lambda type_: type_.__class__.__name__) def accepts_a_type_as_nullable_type_of_non_null(type_): assert GraphQLNonNull(type_) not_types = [NonNullScalarType, {}, dict, str, object, None] @mark.parametrize("type_", not_types, ids=lambda type_: repr(type_)) def rejects_a_non_type_as_nullable_type_of_non_null(type_): with raises(TypeError) as exc_info: GraphQLNonNull(type_) assert ( str(exc_info.value) == ( "Can only create NonNull of a Nullable GraphQLType" f" but got: {type_}." ) if isinstance(type_, GraphQLNonNull) else f"Can only create a wrapper for a GraphQLType, but got: {type_}." ) def describe_type_system_test_utility_methods(): def stringifies_simple_types(): assert str(ScalarType) == "Scalar" assert str(ObjectType) == "Object" assert str(InterfaceType) == "Interface" assert str(UnionType) == "Union" assert str(EnumType) == "Enum" assert str(InputObjectType) == "InputObject" assert str(NonNullScalarType) == "Scalar!" assert str(ListOfScalarsType) == "[Scalar]" assert str(NonNullListOfScalars) == "[Scalar]!" assert str(ListOfNonNullScalarsType) == "[Scalar!]" assert str(GraphQLList(ListOfScalarsType)) == "[[Scalar]]" def simple_types_have_repr(): assert repr(ScalarType) == "" assert repr(ObjectType) == "" assert repr(InterfaceType) == "" assert repr(UnionType) == "" assert repr(EnumType) == "" assert repr(InputObjectType) == "" assert ( repr(ListOfNonNullScalarsType) == ">>" ) assert ( repr(GraphQLList(ListOfScalarsType)) == ">>" ) def stringifies_fields(): assert str(GraphQLField(GraphQLNonNull(GraphQLString))) == "Field: String!" assert str(GraphQLField(GraphQLList(GraphQLInt))) == "Field: [Int]" def fields_have_repr(): assert ( repr(GraphQLField(GraphQLNonNull(GraphQLString))) == ">>" ) assert ( repr(GraphQLField(GraphQLList(GraphQLInt))) == ">>" ) graphql-core-3.2.6/tests/type/test_directives.py000066400000000000000000000215631474546154300220270ustar00rootroot00000000000000from pytest import raises from graphql.error import GraphQLError from graphql.language import DirectiveLocation, DirectiveDefinitionNode, Node from graphql.type import GraphQLArgument, GraphQLDirective, GraphQLInt, GraphQLString def describe_type_system_directive(): def can_create_instance(): arg = GraphQLArgument(GraphQLString, description="arg description") node = DirectiveDefinitionNode() locations = [DirectiveLocation.SCHEMA, DirectiveLocation.OBJECT] directive = GraphQLDirective( name="test", locations=[DirectiveLocation.SCHEMA, DirectiveLocation.OBJECT], args={"arg": arg}, description="test description", is_repeatable=True, ast_node=node, ) assert directive.name == "test" assert directive.locations == tuple(locations) assert directive.args == {"arg": arg} assert directive.is_repeatable is True assert directive.description == "test description" assert directive.extensions == {} assert directive.ast_node is node def defines_a_directive_with_no_args(): locations = [DirectiveLocation.QUERY] directive = GraphQLDirective("Foo", locations=locations) assert directive.name == "Foo" assert directive.args == {} assert directive.is_repeatable is False assert directive.extensions == {} assert directive.locations == tuple(locations) def defines_a_directive_with_multiple_args(): args = { "foo": GraphQLArgument(GraphQLString), "bar": GraphQLArgument(GraphQLInt), } locations = [DirectiveLocation.QUERY] directive = GraphQLDirective("Foo", locations=locations, args=args) assert directive.name == "Foo" assert directive.args == args assert directive.is_repeatable is False assert directive.locations == tuple(locations) def defines_a_repeatable_directive(): locations = [DirectiveLocation.QUERY] directive = GraphQLDirective("Foo", is_repeatable=True, locations=locations) assert directive.name == "Foo" assert directive.args == {} assert directive.is_repeatable is True assert directive.locations == tuple(locations) def directive_accepts_input_types_as_arguments(): # noinspection PyTypeChecker directive = GraphQLDirective( name="Foo", locations=[], args={"arg": GraphQLString} # type: ignore ) arg = directive.args["arg"] assert isinstance(arg, GraphQLArgument) assert arg.type is GraphQLString def directive_accepts_strings_as_locations(): # noinspection PyTypeChecker directive = GraphQLDirective( name="Foo", locations=["SCHEMA", "OBJECT"] # type: ignore ) assert directive.locations == ( DirectiveLocation.SCHEMA, DirectiveLocation.OBJECT, ) def directive_has_str(): directive = GraphQLDirective("foo", []) assert str(directive) == "@foo" def directive_has_repr(): directive = GraphQLDirective("foo", []) assert repr(directive) == "" def can_compare_with_other_source_directive(): locations = [DirectiveLocation.QUERY] directive = GraphQLDirective("Foo", locations) assert directive == directive assert not directive != directive assert not directive == {} assert directive != {} same_directive = GraphQLDirective("Foo", locations) assert directive == same_directive assert not directive != same_directive other_directive = GraphQLDirective("Bar", locations) assert not directive == other_directive assert directive != other_directive other_locations = [DirectiveLocation.MUTATION] other_directive = GraphQLDirective("Foo", other_locations) assert not directive == other_directive assert directive != other_directive other_directive = GraphQLDirective("Foo", locations, is_repeatable=True) assert not directive == other_directive assert directive != other_directive other_directive = GraphQLDirective("Foo", locations, description="other") assert not directive == other_directive assert directive != other_directive def rejects_a_directive_with_incorrectly_typed_name(): with raises(TypeError, match="missing .* required .* 'name'"): # noinspection PyArgumentList GraphQLDirective() # type: ignore with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLDirective(None, []) # type: ignore assert str(exc_info.value) == "Must provide name." with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLDirective(42, {}) # type: ignore assert str(exc_info.value) == "Expected name to be a string." def rejects_a_directive_with_invalid_name(): with raises(GraphQLError) as exc_info: GraphQLDirective("", []) assert str(exc_info.value) == "Expected name to be a non-empty string." with raises(GraphQLError) as exc_info: GraphQLDirective("bad-name", []) assert str(exc_info.value) == ( "Names must only contain [_a-zA-Z0-9] but 'bad-name' does not." ) def rejects_a_directive_with_incorrectly_typed_args(): with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLDirective("Foo", locations=[], args=["arg"]) # type: ignore assert str(exc_info.value) == ( "Foo args must be a dict with argument names as keys." ) with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLDirective( "Foo", locations=[], args={1: GraphQLArgument(GraphQLString)}, # type: ignore ) assert str(exc_info.value) == ( "Foo args must be a dict with argument names as keys." ) with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLDirective( "Foo", locations=[], args={"arg": GraphQLDirective("Bar", [])}, # type: ignore ) assert str(exc_info.value) == ( "Foo args must be GraphQLArgument or input type objects." ) def rejects_a_directive_with_incorrectly_named_args(): with raises(GraphQLError) as exc_info: GraphQLDirective( "Foo", locations=[DirectiveLocation.QUERY], args={"bad-name": GraphQLArgument(GraphQLString)}, ) assert str(exc_info.value) == ( "Names must only contain [_a-zA-Z0-9] but 'bad-name' does not." ) def rejects_a_directive_with_incorrectly_typed_repeatable_flag(): with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLDirective("Foo", locations=[], is_repeatable=None) # type: ignore assert str(exc_info.value) == "Foo is_repeatable flag must be True or False." def rejects_a_directive_with_undefined_locations(): with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLDirective("Foo", locations=None) # type: ignore assert str(exc_info.value) == ( "Foo locations must be specified" " as a collection of DirectiveLocation enum values." ) def rejects_a_directive_with_incorrectly_typed_locations(): with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLDirective("Foo", locations="bad") # type: ignore assert ( str(exc_info.value) == "Foo locations must be specified" " as a collection of DirectiveLocation enum values." ) with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLDirective("Foo", locations=["bad"]) # type: ignore assert str(exc_info.value) == ( "Foo locations must be specified" " as a collection of DirectiveLocation enum values." ) def rejects_a_directive_with_incorrectly_typed_description(): with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLDirective( "Foo", locations=[], description={"bad": True} # type: ignore ) assert str(exc_info.value) == "Foo description must be a string." def rejects_a_directive_with_incorrectly_typed_ast_node(): with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLDirective("Foo", locations=[], ast_node=Node()) # type: ignore assert str(exc_info.value) == ( "Foo AST node must be a DirectiveDefinitionNode." ) graphql-core-3.2.6/tests/type/test_enum.py000066400000000000000000000250161474546154300206270ustar00rootroot00000000000000from datetime import datetime from enum import Enum from typing import Any, Dict, Optional from graphql import graphql_sync from graphql.type import ( GraphQLArgument, GraphQLBoolean, GraphQLEnumType, GraphQLEnumValue, GraphQLField, GraphQLInt, GraphQLObjectType, GraphQLSchema, GraphQLString, ) from graphql.utilities import introspection_from_schema ColorType = GraphQLEnumType("Color", values={"RED": 0, "GREEN": 1, "BLUE": 2}) class ColorTypeEnumValues(Enum): RED = 0 GREEN = 1 BLUE = 2 class Complex1: # noinspection PyMethodMayBeStatic some_random_object = datetime.now() class Complex2: some_random_value = 123 complex1 = Complex1() complex2 = Complex2() ComplexEnum = GraphQLEnumType("Complex", {"ONE": complex1, "TWO": complex2}) ColorType2 = GraphQLEnumType("Color", ColorTypeEnumValues) QueryType = GraphQLObjectType( "Query", { "colorEnum": GraphQLField( ColorType, args={ "fromEnum": GraphQLArgument(ColorType), "fromInt": GraphQLArgument(GraphQLInt), "fromString": GraphQLArgument(GraphQLString), }, resolve=lambda _source, info, **args: args.get("fromInt") or args.get("fromString") or args.get("fromEnum"), ), "colorInt": GraphQLField( GraphQLInt, args={ "fromEnum": GraphQLArgument(ColorType), "fromInt": GraphQLArgument(GraphQLInt), }, resolve=lambda _source, info, **args: args.get("fromEnum"), ), "complexEnum": GraphQLField( ComplexEnum, args={ # Note: default_value is provided an *internal* representation for # Enums, rather than the string name. "fromEnum": GraphQLArgument(ComplexEnum, default_value=complex1), "provideGoodValue": GraphQLArgument(GraphQLBoolean), "provideBadValue": GraphQLArgument(GraphQLBoolean), }, resolve=lambda _source, info, **args: # Note: this is one of the references of the internal values # which ComplexEnum allows. ( complex2 if args.get("provideGoodValue") # Note: similar object, but not the same *reference* as # complex2 above. Enum internal values require object equality. else Complex2() if args.get("provideBadValue") else args.get("fromEnum") ), ), }, ) MutationType = GraphQLObjectType( "Mutation", { "favoriteEnum": GraphQLField( ColorType, args={"color": GraphQLArgument(ColorType)}, resolve=lambda _source, info, color=None: color, ) }, ) SubscriptionType = GraphQLObjectType( "Subscription", { "subscribeToEnum": GraphQLField( ColorType, args={"color": GraphQLArgument(ColorType)}, resolve=lambda _source, info, color=None: color, ) }, ) schema = GraphQLSchema( query=QueryType, mutation=MutationType, subscription=SubscriptionType ) def execute_query(source: str, variable_values: Optional[Dict[str, Any]] = None): return graphql_sync(schema, source, variable_values=variable_values) def describe_type_system_enum_values(): def can_use_python_enums_instead_of_dicts(): assert ColorType2.values == ColorType.values keys = [key for key in ColorType.values] keys2 = [key for key in ColorType2.values] assert keys2 == keys values = [value.value for value in ColorType.values.values()] values2 = [value.value for value in ColorType2.values.values()] assert values2 == values def accepts_enum_literals_as_input(): result = execute_query("{ colorInt(fromEnum: GREEN) }") assert result == ({"colorInt": 1}, None) def enum_may_be_output_type(): result = execute_query("{ colorEnum(fromInt: 1) }") assert result == ({"colorEnum": "GREEN"}, None) def enum_may_be_both_input_and_output_type(): result = execute_query("{ colorEnum(fromEnum: GREEN) }") assert result == ({"colorEnum": "GREEN"}, None) def does_not_accept_string_literals(): result = execute_query('{ colorEnum(fromEnum: "GREEN") }') assert result == ( None, [ { "message": "Enum 'Color' cannot represent non-enum value:" ' "GREEN".' " Did you mean the enum value 'GREEN'?", "locations": [(1, 23)], } ], ) def does_not_accept_values_not_in_the_enum(): result = execute_query("{ colorEnum(fromEnum: GREENISH) }") assert result == ( None, [ { "message": "Value 'GREENISH' does not exist in 'Color' enum." " Did you mean the enum value 'GREEN'?", "locations": [(1, 23)], } ], ) def does_not_accept_values_with_incorrect_casing(): result = execute_query("{ colorEnum(fromEnum: green) }") assert result == ( None, [ { "message": "Value 'green' does not exist in 'Color' enum." " Did you mean the enum value 'GREEN' or 'RED'?", "locations": [(1, 23)], } ], ) def does_not_accept_incorrect_internal_value(): result = execute_query('{ colorEnum(fromString: "GREEN") }') assert result == ( {"colorEnum": None}, [ { "message": "Enum 'Color' cannot represent value: 'GREEN'", "locations": [(1, 3)], "path": ["colorEnum"], } ], ) def does_not_accept_internal_value_in_place_of_enum_literal(): result = execute_query("{ colorEnum(fromEnum: 1) }") assert result == ( None, [ { "message": "Enum 'Color' cannot represent non-enum value: 1.", "locations": [(1, 23)], } ], ) def does_not_accept_enum_literal_in_place_of_int(): result = execute_query("{ colorEnum(fromInt: GREEN) }") assert result == ( None, [ { "message": "Int cannot represent non-integer value: GREEN", "locations": [(1, 22)], } ], ) def accepts_json_string_as_enum_variable(): doc = "query ($color: Color!) { colorEnum(fromEnum: $color) }" result = execute_query(doc, {"color": "BLUE"}) assert result == ({"colorEnum": "BLUE"}, None) def accepts_enum_literals_as_input_arguments_to_mutations(): doc = "mutation ($color: Color!) { favoriteEnum(color: $color) }" result = execute_query(doc, {"color": "GREEN"}) assert result == ({"favoriteEnum": "GREEN"}, None) def accepts_enum_literals_as_input_arguments_to_subscriptions(): doc = "subscription ($color: Color!) { subscribeToEnum(color: $color) }" result = execute_query(doc, {"color": "GREEN"}) assert result == ({"subscribeToEnum": "GREEN"}, None) def does_not_accept_internal_value_as_enum_variable(): doc = "query ($color: Color!) { colorEnum(fromEnum: $color) }" result = execute_query(doc, {"color": 2}) assert result == ( None, [ { "message": "Variable '$color' got invalid value 2;" " Enum 'Color' cannot represent non-string value: 2.", "locations": [(1, 8)], } ], ) def does_not_accept_string_variables_as_enum_input(): doc = "query ($color: String!) { colorEnum(fromEnum: $color) }" result = execute_query(doc, {"color": "BLUE"}) assert result == ( None, [ { "message": "Variable '$color' of type 'String!'" " used in position expecting type 'Color'.", "locations": [(1, 8), (1, 47)], } ], ) def does_not_accept_internal_value_variable_as_enum_input(): doc = "query ($color: Int!) { colorEnum(fromEnum: $color) }" result = execute_query(doc, {"color": 2}) assert result == ( None, [ { "message": "Variable '$color' of type 'Int!'" " used in position expecting type 'Color'.", "locations": [(1, 8), (1, 44)], } ], ) def enum_value_may_have_an_internal_value_of_0(): result = execute_query( """ { colorEnum(fromEnum: RED) colorInt(fromEnum: RED) } """ ) assert result == ({"colorEnum": "RED", "colorInt": 0}, None) def enum_inputs_may_be_nullable(): result = execute_query( """ { colorEnum colorInt } """ ) assert result == ({"colorEnum": None, "colorInt": None}, None) def presents_a_values_property_for_complex_enums(): values = ComplexEnum.values assert isinstance(values, dict) assert all(isinstance(value, GraphQLEnumValue) for value in values.values()) assert {key: value.value for key, value in values.items()} == { "ONE": complex1, "TWO": complex2, } def may_be_internally_represented_with_complex_values(): result = execute_query( """ { first: complexEnum second: complexEnum(fromEnum: TWO) good: complexEnum(provideGoodValue: true) bad: complexEnum(provideBadValue: true) } """ ) assert result == ( {"first": "ONE", "second": "TWO", "good": "TWO", "bad": None}, [ { "message": "Enum 'Complex' cannot represent value:" " ", "locations": [(6, 15)], "path": ["bad"], } ], ) def can_be_introspected_without_error(): introspection_from_schema(schema) graphql-core-3.2.6/tests/type/test_extensions.py000066400000000000000000000321571474546154300220660ustar00rootroot00000000000000from typing import Any, Dict, cast from pytest import mark, param, raises from graphql.type import ( GraphQLArgument, GraphQLDirective, GraphQLEnumType, GraphQLEnumValue, GraphQLField, GraphQLInputField, GraphQLInputObjectType, GraphQLInterfaceType, GraphQLObjectType, GraphQLScalarType, GraphQLSchema, GraphQLUnionType, ) dummy_type = GraphQLScalarType("DummyScalar") bad_extensions = [param([], id="list"), param({1: "ext"}, id="non_string_key")] def bad_extensions_msg(name: str) -> str: return f"{name} extensions must be a dictionary with string keys." def describe_type_system_extensions(): def describe_graphql_scalar_type(): def without_extensions(): some_scalar = GraphQLScalarType("SomeScalar") assert some_scalar.extensions == {} assert some_scalar.to_kwargs()["extensions"] == {} def with_extensions(): scalar_extensions = {"SomeScalarExt": "scalar"} some_scalar = GraphQLScalarType("SomeScalar", extensions=scalar_extensions) assert some_scalar.extensions is scalar_extensions assert some_scalar.to_kwargs()["extensions"] is scalar_extensions @mark.parametrize("extensions", bad_extensions) def with_bad_extensions(extensions): with raises(TypeError, match=bad_extensions_msg("SomeScalar")): # noinspection PyTypeChecker GraphQLScalarType("SomeScalar", extensions=extensions) def describe_graphql_object_type(): def without_extensions(): some_object = GraphQLObjectType( "SomeObject", { "someField": GraphQLField( dummy_type, {"someArg": GraphQLArgument(dummy_type)} ) }, ) assert some_object.extensions == {} some_field = some_object.fields["someField"] assert some_field.extensions == {} some_arg = some_field.args["someArg"] assert some_arg.extensions == {} assert some_object.to_kwargs()["extensions"] == {} assert some_field.to_kwargs()["extensions"] == {} assert some_arg.to_kwargs()["extensions"] == {} def with_extensions(): object_extensions = {"SomeObjectExt": "object"} field_extensions = {"SomeFieldExt": "field"} arg_extensions = {"SomeArgExt": "arg"} some_object = GraphQLObjectType( "SomeObject", { "someField": GraphQLField( dummy_type, { "someArg": GraphQLArgument( dummy_type, extensions=arg_extensions ) }, extensions=field_extensions, ) }, extensions=object_extensions, ) assert some_object.extensions is object_extensions some_field = some_object.fields["someField"] assert some_field.extensions is field_extensions some_arg = some_field.args["someArg"] assert some_arg.extensions is arg_extensions assert some_object.to_kwargs()["extensions"] is object_extensions assert some_field.to_kwargs()["extensions"] is field_extensions assert some_arg.to_kwargs()["extensions"] is arg_extensions @mark.parametrize("extensions", bad_extensions) def with_bad_extensions(extensions): with raises(TypeError, match=bad_extensions_msg("SomeObject")): # noinspection PyTypeChecker GraphQLObjectType("SomeObject", {}, extensions=extensions) with raises(TypeError, match=bad_extensions_msg("Field")): # noinspection PyTypeChecker GraphQLField(dummy_type, extensions=extensions) with raises(TypeError, match=bad_extensions_msg("Argument")): # noinspection PyTypeChecker GraphQLArgument(dummy_type, extensions=extensions) def describe_graphql_interface_type(): def without_extensions(): some_interface = GraphQLInterfaceType( "SomeInterface", { "someField": GraphQLField( dummy_type, {"someArg": GraphQLArgument(dummy_type)} ) }, ) assert some_interface.extensions == {} some_field = some_interface.fields["someField"] assert some_field.extensions == {} some_arg = some_field.args["someArg"] assert some_arg.extensions == {} assert some_interface.to_kwargs()["extensions"] == {} assert some_field.to_kwargs()["extensions"] == {} assert some_arg.to_kwargs()["extensions"] == {} def with_extensions(): interface_extensions = {"SomeInterfaceExt": "interface"} field_extensions = {"SomeFieldExt": "field"} arg_extensions = {"SomeArgExt": "arg"} some_interface = GraphQLInterfaceType( "SomeInterface", { "someField": GraphQLField( dummy_type, { "someArg": GraphQLArgument( dummy_type, extensions=arg_extensions ) }, extensions=field_extensions, ) }, extensions=interface_extensions, ) assert some_interface.extensions is interface_extensions some_field = some_interface.fields["someField"] assert some_field.extensions is field_extensions some_arg = some_field.args["someArg"] assert some_arg.extensions is arg_extensions assert some_interface.to_kwargs()["extensions"] is interface_extensions assert some_field.to_kwargs()["extensions"] is field_extensions assert some_arg.to_kwargs()["extensions"] is arg_extensions @mark.parametrize("extensions", bad_extensions) def with_bad_extensions(extensions): with raises(TypeError, match=bad_extensions_msg("SomeInterface")): # noinspection PyTypeChecker GraphQLInterfaceType("SomeInterface", {}, extensions=extensions) def describe_graphql_union_type(): def without_extensions(): some_union = GraphQLUnionType("SomeUnion", []) assert some_union.extensions == {} assert some_union.to_kwargs()["extensions"] == {} def with_extensions(): union_extensions = {"SomeUnionExt": "union"} some_union = GraphQLUnionType("SomeUnion", [], extensions=union_extensions) assert some_union.extensions is union_extensions assert some_union.to_kwargs()["extensions"] is union_extensions @mark.parametrize("extensions", bad_extensions) def with_bad_extensions(extensions): with raises(TypeError, match=bad_extensions_msg("SomeUnion")): # noinspection PyTypeChecker GraphQLUnionType("SomeUnion", [], extensions=extensions) def describe_graphql_enum_type(): def without_extensions(): some_enum = GraphQLEnumType("SomeEnum", {"SOME_VALUE": None}) assert some_enum.extensions == {} some_value = some_enum.values["SOME_VALUE"] assert some_value.extensions == {} assert some_enum.to_kwargs()["extensions"] == {} assert some_value.to_kwargs()["extensions"] == {} def with_extensions(): enum_extensions = {"SomeEnumExt": "enum"} value_extensions = {"SomeValueExt": "value"} some_enum = GraphQLEnumType( "SomeEnum", {"SOME_VALUE": GraphQLEnumValue(extensions=value_extensions)}, extensions=enum_extensions, ) assert some_enum.extensions is enum_extensions some_value = some_enum.values["SOME_VALUE"] assert some_value.extensions is value_extensions assert some_enum.to_kwargs()["extensions"] is enum_extensions assert some_value.to_kwargs()["extensions"] is value_extensions @mark.parametrize("extensions", bad_extensions) def with_bad_extensions(extensions): with raises(TypeError, match=bad_extensions_msg("SomeEnum")): # noinspection PyTypeChecker GraphQLEnumType( "SomeEnum", cast(Dict[str, Any], {}), extensions=extensions ) with raises(TypeError, match=bad_extensions_msg("Enum value")): # noinspection PyTypeChecker GraphQLEnumValue(extensions=extensions) def describe_graphql_input_object_type(): def without_extensions(): some_input_object = GraphQLInputObjectType( "SomeInputObject", {"someInputField": GraphQLInputField(dummy_type)} ) assert some_input_object.extensions == {} some_input_field = some_input_object.fields["someInputField"] assert some_input_field.extensions == {} assert some_input_object.to_kwargs()["extensions"] == {} assert some_input_field.to_kwargs()["extensions"] == {} def with_extensions(): input_object_extensions = {"SomeInputObjectExt": "inputObject"} input_field_extensions = {"SomeInputFieldExt": "inputField"} some_input_object = GraphQLInputObjectType( "SomeInputObject", { "someInputField": GraphQLInputField( dummy_type, extensions=input_field_extensions ) }, extensions=input_object_extensions, ) assert some_input_object.extensions is input_object_extensions some_input_field = some_input_object.fields["someInputField"] assert some_input_field.extensions is input_field_extensions assert ( some_input_object.to_kwargs()["extensions"] is input_object_extensions ) assert some_input_field.to_kwargs()["extensions"] is input_field_extensions @mark.parametrize("extensions", bad_extensions) def with_bad_extensions(extensions): with raises(TypeError, match=bad_extensions_msg("SomeInputObject")): # noinspection PyTypeChecker GraphQLInputObjectType("SomeInputObject", {}, extensions=extensions) with raises(TypeError, match=bad_extensions_msg("Input field")): # noinspection PyTypeChecker GraphQLInputField(dummy_type, extensions=extensions) def describe_graphql_directive(): def without_extensions(): some_directive = GraphQLDirective( "SomeDirective", [], {"someArg": GraphQLArgument(dummy_type)} ) assert some_directive.extensions == {} some_arg = some_directive.args["someArg"] assert some_arg.extensions == {} assert some_directive.to_kwargs()["extensions"] == {} assert some_arg.to_kwargs()["extensions"] == {} def with_extensions(): directive_extensions = {"SomeDirectiveExt": "directive"} arg_extensions = {"SomeArgExt": "arg"} some_directive = GraphQLDirective( "SomeDirective", [], {"someArg": GraphQLArgument(dummy_type, extensions=arg_extensions)}, extensions=directive_extensions, ) assert some_directive.extensions is directive_extensions some_arg = some_directive.args["someArg"] assert some_arg.extensions is arg_extensions assert some_directive.to_kwargs()["extensions"] is directive_extensions assert some_arg.to_kwargs()["extensions"] is arg_extensions @mark.parametrize("extensions", bad_extensions) def with_bad_extensions(extensions): with raises(TypeError, match=bad_extensions_msg("Directive")): # noinspection PyTypeChecker GraphQLDirective("SomeDirective", [], extensions=extensions) def describe_graphql_schema(): def without_extensions(): schema = GraphQLSchema() assert schema.extensions == {} assert schema.to_kwargs()["extensions"] == {} def with_extensions(): schema_extensions = {"schemaExtension": "schema"} schema = GraphQLSchema(extensions=schema_extensions) assert schema.extensions is schema_extensions assert schema.to_kwargs()["extensions"] is schema_extensions @mark.parametrize("extensions", bad_extensions) def with_bad_extensions(extensions): with raises(TypeError, match=bad_extensions_msg("Schema")): # noinspection PyTypeChecker GraphQLSchema(extensions=extensions) graphql-core-3.2.6/tests/type/test_introspection.py000066400000000000000000001704101474546154300225620ustar00rootroot00000000000000from graphql import graphql_sync from graphql.utilities import get_introspection_query, build_schema def describe_introspection(): def executes_an_introspection_query(): schema = build_schema( """ type SomeObject { someField: String } schema { query: SomeObject } """ ) source = get_introspection_query( descriptions=False, specified_by_url=True, directive_is_repeatable=True ) result = graphql_sync(schema=schema, source=source) assert result.errors is None assert result.data == { "__schema": { "queryType": {"name": "SomeObject"}, "mutationType": None, "subscriptionType": None, "types": [ { "kind": "OBJECT", "name": "SomeObject", "specifiedByURL": None, "fields": [ { "name": "someField", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": None, }, "isDeprecated": False, "deprecationReason": None, } ], "inputFields": None, "interfaces": [], "enumValues": None, "possibleTypes": None, }, { "kind": "SCALAR", "name": "String", "specifiedByURL": None, "fields": None, "inputFields": None, "interfaces": None, "enumValues": None, "possibleTypes": None, }, { "kind": "SCALAR", "name": "Boolean", "specifiedByURL": None, "fields": None, "inputFields": None, "interfaces": None, "enumValues": None, "possibleTypes": None, }, { "kind": "OBJECT", "name": "__Schema", "specifiedByURL": None, "fields": [ { "name": "description", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": None, }, "isDeprecated": False, "deprecationReason": None, }, { "name": "types", "args": [], "type": { "kind": "NON_NULL", "name": None, "ofType": { "kind": "LIST", "name": None, "ofType": { "kind": "NON_NULL", "name": None, "ofType": { "kind": "OBJECT", "name": "__Type", "ofType": None, }, }, }, }, "isDeprecated": False, "deprecationReason": None, }, { "name": "queryType", "args": [], "type": { "kind": "NON_NULL", "name": None, "ofType": { "kind": "OBJECT", "name": "__Type", "ofType": None, }, }, "isDeprecated": False, "deprecationReason": None, }, { "name": "mutationType", "args": [], "type": { "kind": "OBJECT", "name": "__Type", "ofType": None, }, "isDeprecated": False, "deprecationReason": None, }, { "name": "subscriptionType", "args": [], "type": { "kind": "OBJECT", "name": "__Type", "ofType": None, }, "isDeprecated": False, "deprecationReason": None, }, { "name": "directives", "args": [], "type": { "kind": "NON_NULL", "name": None, "ofType": { "kind": "LIST", "name": None, "ofType": { "kind": "NON_NULL", "name": None, "ofType": { "kind": "OBJECT", "name": "__Directive", "ofType": None, }, }, }, }, "isDeprecated": False, "deprecationReason": None, }, ], "inputFields": None, "interfaces": [], "enumValues": None, "possibleTypes": None, }, { "kind": "OBJECT", "name": "__Type", "specifiedByURL": None, "fields": [ { "name": "kind", "args": [], "type": { "kind": "NON_NULL", "name": None, "ofType": { "kind": "ENUM", "name": "__TypeKind", "ofType": None, }, }, "isDeprecated": False, "deprecationReason": None, }, { "name": "name", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": None, }, "isDeprecated": False, "deprecationReason": None, }, { "name": "description", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": None, }, "isDeprecated": False, "deprecationReason": None, }, { "name": "specifiedByURL", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": None, }, "isDeprecated": False, "deprecationReason": None, }, { "name": "fields", "args": [ { "name": "includeDeprecated", "type": { "kind": "SCALAR", "name": "Boolean", "ofType": None, }, "defaultValue": "false", } ], "type": { "kind": "LIST", "name": None, "ofType": { "kind": "NON_NULL", "name": None, "ofType": { "kind": "OBJECT", "name": "__Field", "ofType": None, }, }, }, "isDeprecated": False, "deprecationReason": None, }, { "name": "interfaces", "args": [], "type": { "kind": "LIST", "name": None, "ofType": { "kind": "NON_NULL", "name": None, "ofType": { "kind": "OBJECT", "name": "__Type", "ofType": None, }, }, }, "isDeprecated": False, "deprecationReason": None, }, { "name": "possibleTypes", "args": [], "type": { "kind": "LIST", "name": None, "ofType": { "kind": "NON_NULL", "name": None, "ofType": { "kind": "OBJECT", "name": "__Type", "ofType": None, }, }, }, "isDeprecated": False, "deprecationReason": None, }, { "name": "enumValues", "args": [ { "name": "includeDeprecated", "type": { "kind": "SCALAR", "name": "Boolean", "ofType": None, }, "defaultValue": "false", } ], "type": { "kind": "LIST", "name": None, "ofType": { "kind": "NON_NULL", "name": None, "ofType": { "kind": "OBJECT", "name": "__EnumValue", "ofType": None, }, }, }, "isDeprecated": False, "deprecationReason": None, }, { "name": "inputFields", "args": [ { "name": "includeDeprecated", "type": { "kind": "SCALAR", "name": "Boolean", "ofType": None, }, "defaultValue": "false", } ], "type": { "kind": "LIST", "name": None, "ofType": { "kind": "NON_NULL", "name": None, "ofType": { "kind": "OBJECT", "name": "__InputValue", "ofType": None, }, }, }, "isDeprecated": False, "deprecationReason": None, }, { "name": "ofType", "args": [], "type": { "kind": "OBJECT", "name": "__Type", "ofType": None, }, "isDeprecated": False, "deprecationReason": None, }, ], "inputFields": None, "interfaces": [], "enumValues": None, "possibleTypes": None, }, { "kind": "ENUM", "name": "__TypeKind", "specifiedByURL": None, "fields": None, "inputFields": None, "interfaces": None, "enumValues": [ { "name": "SCALAR", "isDeprecated": False, "deprecationReason": None, }, { "name": "OBJECT", "isDeprecated": False, "deprecationReason": None, }, { "name": "INTERFACE", "isDeprecated": False, "deprecationReason": None, }, { "name": "UNION", "isDeprecated": False, "deprecationReason": None, }, { "name": "ENUM", "isDeprecated": False, "deprecationReason": None, }, { "name": "INPUT_OBJECT", "isDeprecated": False, "deprecationReason": None, }, { "name": "LIST", "isDeprecated": False, "deprecationReason": None, }, { "name": "NON_NULL", "isDeprecated": False, "deprecationReason": None, }, ], "possibleTypes": None, }, { "kind": "OBJECT", "name": "__Field", "specifiedByURL": None, "fields": [ { "name": "name", "args": [], "type": { "kind": "NON_NULL", "name": None, "ofType": { "kind": "SCALAR", "name": "String", "ofType": None, }, }, "isDeprecated": False, "deprecationReason": None, }, { "name": "description", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": None, }, "isDeprecated": False, "deprecationReason": None, }, { "name": "args", "args": [ { "name": "includeDeprecated", "type": { "kind": "SCALAR", "name": "Boolean", "ofType": None, }, "defaultValue": "false", } ], "type": { "kind": "NON_NULL", "name": None, "ofType": { "kind": "LIST", "name": None, "ofType": { "kind": "NON_NULL", "name": None, "ofType": { "kind": "OBJECT", "name": "__InputValue", "ofType": None, }, }, }, }, "isDeprecated": False, "deprecationReason": None, }, { "name": "type", "args": [], "type": { "kind": "NON_NULL", "name": None, "ofType": { "kind": "OBJECT", "name": "__Type", "ofType": None, }, }, "isDeprecated": False, "deprecationReason": None, }, { "name": "isDeprecated", "args": [], "type": { "kind": "NON_NULL", "name": None, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": None, }, }, "isDeprecated": False, "deprecationReason": None, }, { "name": "deprecationReason", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": None, }, "isDeprecated": False, "deprecationReason": None, }, ], "inputFields": None, "interfaces": [], "enumValues": None, "possibleTypes": None, }, { "kind": "OBJECT", "name": "__InputValue", "specifiedByURL": None, "fields": [ { "name": "name", "args": [], "type": { "kind": "NON_NULL", "name": None, "ofType": { "kind": "SCALAR", "name": "String", "ofType": None, }, }, "isDeprecated": False, "deprecationReason": None, }, { "name": "description", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": None, }, "isDeprecated": False, "deprecationReason": None, }, { "name": "type", "args": [], "type": { "kind": "NON_NULL", "name": None, "ofType": { "kind": "OBJECT", "name": "__Type", "ofType": None, }, }, "isDeprecated": False, "deprecationReason": None, }, { "name": "defaultValue", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": None, }, "isDeprecated": False, "deprecationReason": None, }, { "name": "isDeprecated", "args": [], "type": { "kind": "NON_NULL", "name": None, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": None, }, }, "isDeprecated": False, "deprecationReason": None, }, { "name": "deprecationReason", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": None, }, "isDeprecated": False, "deprecationReason": None, }, ], "inputFields": None, "interfaces": [], "enumValues": None, "possibleTypes": None, }, { "kind": "OBJECT", "name": "__EnumValue", "specifiedByURL": None, "fields": [ { "name": "name", "args": [], "type": { "kind": "NON_NULL", "name": None, "ofType": { "kind": "SCALAR", "name": "String", "ofType": None, }, }, "isDeprecated": False, "deprecationReason": None, }, { "name": "description", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": None, }, "isDeprecated": False, "deprecationReason": None, }, { "name": "isDeprecated", "args": [], "type": { "kind": "NON_NULL", "name": None, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": None, }, }, "isDeprecated": False, "deprecationReason": None, }, { "name": "deprecationReason", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": None, }, "isDeprecated": False, "deprecationReason": None, }, ], "inputFields": None, "interfaces": [], "enumValues": None, "possibleTypes": None, }, { "kind": "OBJECT", "name": "__Directive", "specifiedByURL": None, "fields": [ { "name": "name", "args": [], "type": { "kind": "NON_NULL", "name": None, "ofType": { "kind": "SCALAR", "name": "String", "ofType": None, }, }, "isDeprecated": False, "deprecationReason": None, }, { "name": "description", "args": [], "type": { "kind": "SCALAR", "name": "String", "ofType": None, }, "isDeprecated": False, "deprecationReason": None, }, { "name": "isRepeatable", "args": [], "type": { "kind": "NON_NULL", "name": None, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": None, }, }, "isDeprecated": False, "deprecationReason": None, }, { "name": "locations", "args": [], "type": { "kind": "NON_NULL", "name": None, "ofType": { "kind": "LIST", "name": None, "ofType": { "kind": "NON_NULL", "name": None, "ofType": { "kind": "ENUM", "name": "__DirectiveLocation", "ofType": None, }, }, }, }, "isDeprecated": False, "deprecationReason": None, }, { "name": "args", "args": [ { "name": "includeDeprecated", "type": { "kind": "SCALAR", "name": "Boolean", "ofType": None, }, "defaultValue": "false", } ], "type": { "kind": "NON_NULL", "name": None, "ofType": { "kind": "LIST", "name": None, "ofType": { "kind": "NON_NULL", "name": None, "ofType": { "kind": "OBJECT", "name": "__InputValue", "ofType": None, }, }, }, }, "isDeprecated": False, "deprecationReason": None, }, ], "inputFields": None, "interfaces": [], "enumValues": None, "possibleTypes": None, }, { "kind": "ENUM", "name": "__DirectiveLocation", "specifiedByURL": None, "fields": None, "inputFields": None, "interfaces": None, "enumValues": [ { "name": "QUERY", "isDeprecated": False, "deprecationReason": None, }, { "name": "MUTATION", "isDeprecated": False, "deprecationReason": None, }, { "name": "SUBSCRIPTION", "isDeprecated": False, "deprecationReason": None, }, { "name": "FIELD", "isDeprecated": False, "deprecationReason": None, }, { "name": "FRAGMENT_DEFINITION", "isDeprecated": False, "deprecationReason": None, }, { "name": "FRAGMENT_SPREAD", "isDeprecated": False, "deprecationReason": None, }, { "name": "INLINE_FRAGMENT", "isDeprecated": False, "deprecationReason": None, }, { "name": "VARIABLE_DEFINITION", "isDeprecated": False, "deprecationReason": None, }, { "name": "SCHEMA", "isDeprecated": False, "deprecationReason": None, }, { "name": "SCALAR", "isDeprecated": False, "deprecationReason": None, }, { "name": "OBJECT", "isDeprecated": False, "deprecationReason": None, }, { "name": "FIELD_DEFINITION", "isDeprecated": False, "deprecationReason": None, }, { "name": "ARGUMENT_DEFINITION", "isDeprecated": False, "deprecationReason": None, }, { "name": "INTERFACE", "isDeprecated": False, "deprecationReason": None, }, { "name": "UNION", "isDeprecated": False, "deprecationReason": None, }, { "name": "ENUM", "isDeprecated": False, "deprecationReason": None, }, { "name": "ENUM_VALUE", "isDeprecated": False, "deprecationReason": None, }, { "name": "INPUT_OBJECT", "isDeprecated": False, "deprecationReason": None, }, { "name": "INPUT_FIELD_DEFINITION", "isDeprecated": False, "deprecationReason": None, }, ], "possibleTypes": None, }, ], "directives": [ { "name": "include", "isRepeatable": False, "locations": ["FIELD", "FRAGMENT_SPREAD", "INLINE_FRAGMENT"], "args": [ { "defaultValue": None, "name": "if", "type": { "kind": "NON_NULL", "name": None, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": None, }, }, } ], }, { "name": "skip", "isRepeatable": False, "locations": ["FIELD", "FRAGMENT_SPREAD", "INLINE_FRAGMENT"], "args": [ { "defaultValue": None, "name": "if", "type": { "kind": "NON_NULL", "name": None, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": None, }, }, } ], }, { "name": "deprecated", "isRepeatable": False, "locations": [ "FIELD_DEFINITION", "ARGUMENT_DEFINITION", "INPUT_FIELD_DEFINITION", "ENUM_VALUE", ], "args": [ { "defaultValue": '"No longer supported"', "name": "reason", "type": { "kind": "SCALAR", "name": "String", "ofType": None, }, } ], }, { "name": "specifiedBy", "isRepeatable": False, "locations": ["SCALAR"], "args": [ { "defaultValue": None, "name": "url", "type": { "kind": "NON_NULL", "name": None, "ofType": { "kind": "SCALAR", "name": "String", "ofType": None, }, }, } ], }, ], } } def introspects_on_input_object(): schema = build_schema( """ input SomeInputObject { a: String = "tes\\t de\\fault" b: [String] c: String = null } type Query { someField(someArg: SomeInputObject): String } """ ) source = """ { __type(name: "SomeInputObject") { kind name inputFields { name type { ...TypeRef } defaultValue } } } fragment TypeRef on __Type { kind name ofType { kind name ofType { kind name ofType { kind name } } } } """ assert graphql_sync(schema=schema, source=source) == ( { "__type": { "kind": "INPUT_OBJECT", "name": "SomeInputObject", "inputFields": [ { "name": "a", "type": { "kind": "SCALAR", "name": "String", "ofType": None, }, "defaultValue": '"tes\\t de\\fault"', }, { "name": "b", "type": { "kind": "LIST", "name": None, "ofType": { "kind": "SCALAR", "name": "String", "ofType": None, }, }, "defaultValue": None, }, { "name": "c", "type": { "kind": "SCALAR", "name": "String", "ofType": None, }, "defaultValue": "null", }, ], } }, None, ) def introspects_any_default_value(): schema = build_schema( """ input InputObjectWithDefaultValues { a: String = "Emoji: \\u{1F600}" b: Complex = {x: ["abc"], y: 123} } input Complex { x: [String] y: Int } type Query { someField(someArg: InputObjectWithDefaultValues): String } """ ) source = """ { __type(name: "InputObjectWithDefaultValues") { inputFields { name defaultValue } } } """ assert graphql_sync(schema=schema, source=source) == ( { "__type": { "inputFields": [ {"name": "a", "defaultValue": '"Emoji: \U0001f600"'}, {"name": "b", "defaultValue": '{x: ["abc"], y: 123}'}, ] } }, None, ) def supports_the_type_root_field(): schema = build_schema( """ type Query { someField: String } """ ) source = """ { __type(name: "Query") { name } } """ assert graphql_sync(schema=schema, source=source) == ( {"__type": {"name": "Query"}}, None, ) def identifies_deprecated_fields(): schema = build_schema( """ type Query { nonDeprecated: String deprecated: String @deprecated(reason: "Removed in 1.0") deprecatedWithEmptyReason: String @deprecated(reason: "") } """ ) source = """ { __type(name: "Query") { fields(includeDeprecated: true) { name isDeprecated, deprecationReason } } } """ assert graphql_sync(schema=schema, source=source) == ( { "__type": { "fields": [ { "name": "nonDeprecated", "isDeprecated": False, "deprecationReason": None, }, { "name": "deprecated", "isDeprecated": True, "deprecationReason": "Removed in 1.0", }, { "name": "deprecatedWithEmptyReason", "isDeprecated": True, "deprecationReason": "", }, ], } }, None, ) def respects_the_include_deprecated_parameter_for_fields(): schema = build_schema( """ type Query { nonDeprecated: String deprecated: String @deprecated(reason: "Removed in 1.0") } """ ) source = """ { __type(name: "Query") { trueFields: fields(includeDeprecated: true) { name } falseFields: fields(includeDeprecated: false) { name } omittedFields: fields { name } } } """ assert graphql_sync(schema=schema, source=source) == ( { "__type": { "trueFields": [{"name": "nonDeprecated"}, {"name": "deprecated"}], "falseFields": [{"name": "nonDeprecated"}], "omittedFields": [{"name": "nonDeprecated"}], } }, None, ) def identifies_deprecated_args(): schema = build_schema( """ type Query { someField( nonDeprecated: String deprecated: String @deprecated(reason: "Removed in 1.0") deprecatedWithEmptyReason: String @deprecated(reason: "") ): String } """ ) source = """ { __type(name: "Query") { fields { args(includeDeprecated: true) { name isDeprecated, deprecationReason } } } } """ assert graphql_sync(schema=schema, source=source) == ( { "__type": { "fields": [ { "args": [ { "name": "nonDeprecated", "isDeprecated": False, "deprecationReason": None, }, { "name": "deprecated", "isDeprecated": True, "deprecationReason": "Removed in 1.0", }, { "name": "deprecatedWithEmptyReason", "isDeprecated": True, "deprecationReason": "", }, ], }, ], } }, None, ) def respects_the_include_deprecated_parameter_for_args(): schema = build_schema( """ type Query { someField( nonDeprecated: String deprecated: String @deprecated(reason: "Removed in 1.0") ): String } """ ) source = """ { __type(name: "Query") { fields { trueArgs: args(includeDeprecated: true) { name } falseArgs: args(includeDeprecated: false) { name } omittedArgs: args { name } } } } """ assert graphql_sync(schema=schema, source=source) == ( { "__type": { "fields": [ { "trueArgs": [ {"name": "nonDeprecated"}, {"name": "deprecated"}, ], "falseArgs": [{"name": "nonDeprecated"}], "omittedArgs": [{"name": "nonDeprecated"}], }, ], }, }, None, ) def identifies_deprecated_enum_values(): schema = build_schema( """ enum SomeEnum { NON_DEPRECATED DEPRECATED @deprecated(reason: "Removed in 1.0") ALSO_NON_DEPRECATED } type Query { someField(someArg: SomeEnum): String } """ ) source = """ { __type(name: "SomeEnum") { enumValues(includeDeprecated: true) { name isDeprecated, deprecationReason } } } """ assert graphql_sync(schema=schema, source=source) == ( { "__type": { "enumValues": [ { "name": "NON_DEPRECATED", "isDeprecated": False, "deprecationReason": None, }, { "name": "DEPRECATED", "isDeprecated": True, "deprecationReason": "Removed in 1.0", }, { "name": "ALSO_NON_DEPRECATED", "isDeprecated": False, "deprecationReason": None, }, ], } }, None, ) def respects_the_include_deprecated_parameter_for_enum_values(): schema = build_schema( """ enum SomeEnum { NON_DEPRECATED DEPRECATED @deprecated(reason: "Removed in 1.0") DEPRECATED_WITH_EMPTY_REASON @deprecated(reason: "") ALSO_NON_DEPRECATED } type Query { someField(someArg: SomeEnum): String } """ ) source = """ { __type(name: "SomeEnum") { trueValues: enumValues(includeDeprecated: true) { name } falseValues: enumValues(includeDeprecated: false) { name } omittedValues: enumValues { name } } } """ assert graphql_sync(schema=schema, source=source) == ( { "__type": { "trueValues": [ {"name": "NON_DEPRECATED"}, {"name": "DEPRECATED"}, {"name": "DEPRECATED_WITH_EMPTY_REASON"}, {"name": "ALSO_NON_DEPRECATED"}, ], "falseValues": [ {"name": "NON_DEPRECATED"}, {"name": "ALSO_NON_DEPRECATED"}, ], "omittedValues": [ {"name": "NON_DEPRECATED"}, {"name": "ALSO_NON_DEPRECATED"}, ], } }, None, ) def fails_as_expected_on_the_type_root_field_without_an_arg(): schema = build_schema( """ type Query { someField: String } """ ) source = """ { __type { name } } """ assert graphql_sync(schema=schema, source=source) == ( None, [ { "message": "Field '__type' argument 'name'" " of type 'String!' is required, but it was not provided.", "locations": [(3, 15)], } ], ) def exposes_descriptions(): schema = build_schema( ''' """Enum description""" enum SomeEnum { """Value description""" VALUE } """Object description""" type SomeObject { """Field description""" someField(arg: SomeEnum): String } """Schema description""" schema { query: SomeObject } ''' ) source = """ { Schema: __schema { description } SomeObject: __type(name: "SomeObject") { description, fields { name description } } SomeEnum: __type(name: "SomeEnum") { description enumValues { name description } } } """ assert graphql_sync(schema=schema, source=source) == ( { "Schema": { "description": "Schema description", }, "SomeEnum": { "description": "Enum description", "enumValues": [ { "name": "VALUE", "description": "Value description", }, ], }, "SomeObject": { "description": "Object description", "fields": [ { "name": "someField", "description": "Field description", }, ], }, }, None, ) def executes_introspection_query_without_calling_global_resolvers(): schema = build_schema( """ type Query { someField: String } """ ) source = get_introspection_query( specified_by_url=True, directive_is_repeatable=True, schema_description=True ) def field_resolver(_obj, info): assert False, f"Called on {info.parent_type.name}.{info.field_name}" def type_resolver(_obj, info, _abstract_type): assert False, f"Called on {info.parent_type.name}.{info.field_name}" result = graphql_sync( schema=schema, source=source, field_resolver=field_resolver, type_resolver=type_resolver, ) assert result.errors is None graphql-core-3.2.6/tests/type/test_predicate.py000066400000000000000000000515151474546154300216260ustar00rootroot00000000000000from typing import Any from pytest import raises from graphql.language import DirectiveLocation from graphql.type import ( GraphQLArgument, GraphQLDeprecatedDirective, GraphQLBoolean, GraphQLDirective, GraphQLEnumType, GraphQLFloat, GraphQLID, GraphQLIncludeDirective, GraphQLInputField, GraphQLInputObjectType, GraphQLInt, GraphQLInterfaceType, GraphQLList, GraphQLNonNull, GraphQLObjectType, GraphQLScalarType, GraphQLSkipDirective, GraphQLString, GraphQLUnionType, assert_abstract_type, assert_composite_type, assert_directive, assert_enum_type, assert_input_object_type, assert_input_type, assert_interface_type, assert_leaf_type, assert_list_type, assert_named_type, assert_non_null_type, assert_nullable_type, assert_object_type, assert_output_type, assert_scalar_type, assert_type, assert_union_type, assert_wrapping_type, get_named_type, get_nullable_type, is_abstract_type, is_composite_type, is_directive, is_enum_type, is_input_object_type, is_input_type, is_interface_type, is_leaf_type, is_list_type, is_named_type, is_required_argument, is_required_input_field, is_non_null_type, is_nullable_type, is_object_type, is_output_type, is_scalar_type, is_specified_directive, is_specified_scalar_type, is_type, is_union_type, is_wrapping_type, ) ObjectType = GraphQLObjectType("Object", {}) InterfaceType = GraphQLInterfaceType("Interface", {}) UnionType = GraphQLUnionType("Union", types=[ObjectType]) EnumType = GraphQLEnumType("Enum", values={"foo": {}}) InputObjectType = GraphQLInputObjectType("InputObject", {}) ScalarType = GraphQLScalarType("Scalar") Directive = GraphQLDirective("Directive", [DirectiveLocation.QUERY]) def describe_type_predicates(): def describe_is_type(): def returns_true_for_unwrapped_types(): assert is_type(GraphQLString) is True assert_type(GraphQLString) assert is_type(ObjectType) is True assert_type(ObjectType) def returns_true_for_wrapped_types(): assert is_type(GraphQLNonNull(GraphQLString)) is True assert_type(GraphQLNonNull(GraphQLString)) def returns_false_for_type_classes_rather_than_instance(): assert is_type(GraphQLObjectType) is False with raises(TypeError): assert_type(GraphQLObjectType) def returns_false_for_random_garbage(): assert is_type({"what": "is this"}) is False with raises(TypeError): assert_type({"what": "is this"}) def describe_is_scalar_type(): def returns_true_for_spec_defined_scalar(): assert is_scalar_type(GraphQLString) is True assert_scalar_type(GraphQLString) def returns_true_for_custom_scalar(): assert is_scalar_type(ScalarType) is True assert_scalar_type(ScalarType) def returns_false_for_scalar_class_rather_than_instance(): assert is_scalar_type(GraphQLScalarType) is False with raises(TypeError): assert_scalar_type(GraphQLScalarType) def returns_false_for_wrapped_scalar(): assert is_scalar_type(GraphQLList(ScalarType)) is False with raises(TypeError): assert_scalar_type(GraphQLList(ScalarType)) def returns_false_for_non_scalar(): assert is_scalar_type(EnumType) is False with raises(TypeError): assert_scalar_type(EnumType) assert is_scalar_type(Directive) is False with raises(TypeError): assert_scalar_type(Directive) def returns_false_for_random_garbage(): assert is_scalar_type(None) is False with raises(TypeError): assert_scalar_type(None) assert is_scalar_type({"what": "is this"}) is False with raises(TypeError): assert_scalar_type({"what": "is this"}) def describe_is_specified_scalar_type(): def returns_true_for_specified_scalars(): assert is_specified_scalar_type(GraphQLString) is True assert is_specified_scalar_type(GraphQLInt) is True assert is_specified_scalar_type(GraphQLFloat) is True assert is_specified_scalar_type(GraphQLBoolean) is True assert is_specified_scalar_type(GraphQLID) is True def describe_is_object_type(): def returns_true_for_object_type(): assert is_object_type(ObjectType) is True assert_object_type(ObjectType) def returns_false_for_wrapped_object_type(): assert is_object_type(GraphQLList(ObjectType)) is False with raises(TypeError): assert_object_type(GraphQLList(ObjectType)) def returns_false_for_non_object_type(): assert is_scalar_type(InterfaceType) is False with raises(TypeError): assert_scalar_type(InterfaceType) def describe_is_interface_type(): def returns_true_for_interface_type(): assert is_interface_type(InterfaceType) is True assert_interface_type(InterfaceType) def returns_false_for_wrapped_interface_type(): assert is_interface_type(GraphQLList(InterfaceType)) is False with raises(TypeError): assert_interface_type(GraphQLList(InterfaceType)) def returns_false_for_non_interface_type(): assert is_interface_type(ObjectType) is False with raises(TypeError): assert_interface_type(ObjectType) def describe_is_union_type(): def returns_true_for_union_type(): assert is_union_type(UnionType) is True assert_union_type(UnionType) def returns_false_for_wrapped_union_type(): assert is_union_type(GraphQLList(UnionType)) is False with raises(TypeError): assert_union_type(GraphQLList(UnionType)) def returns_false_for_non_union_type(): assert is_union_type(ObjectType) is False with raises(TypeError): assert_union_type(ObjectType) def describe_is_enum_type(): def returns_true_for_enum_type(): assert is_enum_type(EnumType) is True assert_enum_type(EnumType) def returns_false_for_wrapped_enum_type(): assert is_enum_type(GraphQLList(EnumType)) is False with raises(TypeError): assert_enum_type(GraphQLList(EnumType)) def returns_false_for_non_enum_type(): assert is_enum_type(ScalarType) is False with raises(TypeError): assert_enum_type(ScalarType) def describe_is_input_object_type(): def returns_true_for_input_object_type(): assert is_input_object_type(InputObjectType) is True assert_input_object_type(InputObjectType) def returns_false_for_wrapped_input_object_type(): assert is_input_object_type(GraphQLList(InputObjectType)) is False with raises(TypeError): assert_input_object_type(GraphQLList(InputObjectType)) def returns_false_for_non_input_object_type(): assert is_input_object_type(ObjectType) is False with raises(TypeError): assert_input_object_type(ObjectType) def describe_is_list_type(): def returns_true_for_a_list_wrapped_type(): assert is_list_type(GraphQLList(ObjectType)) is True assert_list_type(GraphQLList(ObjectType)) def returns_false_for_a_unwrapped_type(): assert is_list_type(ObjectType) is False with raises(TypeError): assert_list_type(ObjectType) def returns_false_for_a_non_list_wrapped_type(): assert is_list_type(GraphQLNonNull(GraphQLList(ObjectType))) is False with raises(TypeError): assert_list_type(GraphQLNonNull(GraphQLList(ObjectType))) def describe_is_non_null_type(): def returns_true_for_a_non_null_wrapped_type(): assert is_non_null_type(GraphQLNonNull(ObjectType)) is True assert_non_null_type(GraphQLNonNull(ObjectType)) def returns_false_for_an_unwrapped_type(): assert is_non_null_type(ObjectType) is False with raises(TypeError): assert_non_null_type(ObjectType) def returns_false_for_a_not_non_null_wrapped_type(): assert is_non_null_type(GraphQLList(GraphQLNonNull(ObjectType))) is False with raises(TypeError): assert_non_null_type(GraphQLList(GraphQLNonNull(ObjectType))) def describe_is_input_type(): def _assert_input_type(type_: Any): assert is_input_type(type_) is True assert_input_type(type_) def returns_true_for_an_input_type(): _assert_input_type(GraphQLString) _assert_input_type(EnumType) _assert_input_type(InputObjectType) def returns_true_for_a_wrapped_input_type(): _assert_input_type(GraphQLList(GraphQLString)) _assert_input_type(GraphQLList(EnumType)) _assert_input_type(GraphQLList(InputObjectType)) _assert_input_type(GraphQLNonNull(GraphQLString)) _assert_input_type(GraphQLNonNull(EnumType)) _assert_input_type(GraphQLNonNull(InputObjectType)) def _assert_non_input_type(type_: Any): assert is_input_type(type_) is False with raises(TypeError): assert_input_type(type_) def returns_false_for_an_output_type(): _assert_non_input_type(ObjectType) _assert_non_input_type(InterfaceType) _assert_non_input_type(UnionType) def returns_false_for_a_wrapped_output_type(): _assert_non_input_type(GraphQLList(ObjectType)) _assert_non_input_type(GraphQLList(InterfaceType)) _assert_non_input_type(GraphQLList(UnionType)) _assert_non_input_type(GraphQLNonNull(ObjectType)) _assert_non_input_type(GraphQLNonNull(InterfaceType)) _assert_non_input_type(GraphQLNonNull(UnionType)) def describe_is_output_type(): def _assert_output_type(type_: Any): assert is_output_type(type_) is True assert_output_type(type_) def returns_true_for_an_output_type(): _assert_output_type(GraphQLString) _assert_output_type(ObjectType) _assert_output_type(InterfaceType) _assert_output_type(UnionType) _assert_output_type(EnumType) def returns_true_for_a_wrapped_output_type(): _assert_output_type(GraphQLList(GraphQLString)) _assert_output_type(GraphQLList(ObjectType)) _assert_output_type(GraphQLList(InterfaceType)) _assert_output_type(GraphQLList(UnionType)) _assert_output_type(GraphQLList(EnumType)) _assert_output_type(GraphQLNonNull(GraphQLString)) _assert_output_type(GraphQLNonNull(ObjectType)) _assert_output_type(GraphQLNonNull(InterfaceType)) _assert_output_type(GraphQLNonNull(UnionType)) _assert_output_type(GraphQLNonNull(EnumType)) def _assert_non_output_type(type_: Any): assert is_output_type(type_) is False with raises(TypeError): assert_output_type(type_) def returns_false_for_an_input_type(): _assert_non_output_type(InputObjectType) def returns_false_for_a_wrapped_input_type(): _assert_non_output_type(GraphQLList(InputObjectType)) _assert_non_output_type(GraphQLNonNull(InputObjectType)) def describe_is_leaf_type(): def returns_true_for_scalar_and_enum_types(): assert is_leaf_type(ScalarType) is True assert_leaf_type(ScalarType) assert is_leaf_type(EnumType) is True assert_leaf_type(EnumType) def returns_false_for_wrapped_leaf_type(): assert is_leaf_type(GraphQLList(ScalarType)) is False with raises(TypeError): assert_leaf_type(GraphQLList(ScalarType)) def returns_false_for_non_leaf_type(): assert is_leaf_type(ObjectType) is False with raises(TypeError): assert_leaf_type(ObjectType) def returns_false_for_wrapped_non_leaf_type(): assert is_leaf_type(GraphQLList(ObjectType)) is False with raises(TypeError): assert_leaf_type(GraphQLList(ObjectType)) def describe_is_composite_type(): def returns_true_for_object_interface_and_union_types(): assert is_composite_type(ObjectType) is True assert_composite_type(ObjectType) assert is_composite_type(InterfaceType) is True assert_composite_type(InterfaceType) assert is_composite_type(UnionType) is True assert_composite_type(UnionType) def returns_false_for_wrapped_composite_type(): assert is_composite_type(GraphQLList(ObjectType)) is False with raises(TypeError): assert_composite_type(GraphQLList(ObjectType)) def returns_false_for_non_composite_type(): assert is_composite_type(InputObjectType) is False with raises(TypeError): assert_composite_type(InputObjectType) def returns_false_for_wrapped_non_composite_type(): assert is_composite_type(GraphQLList(InputObjectType)) is False with raises(TypeError): assert_composite_type(GraphQLList(InputObjectType)) def describe_is_abstract_type(): def returns_true_for_interface_and_union_types(): assert is_abstract_type(InterfaceType) is True assert_abstract_type(InterfaceType) assert is_abstract_type(UnionType) is True assert_abstract_type(UnionType) def returns_false_for_wrapped_abstract_type(): assert is_abstract_type(GraphQLList(InterfaceType)) is False with raises(TypeError): assert_abstract_type(GraphQLList(InterfaceType)) def returns_false_for_non_abstract_type(): assert is_abstract_type(ObjectType) is False with raises(TypeError): assert_abstract_type(ObjectType) def returns_false_for_wrapped_non_abstract_type(): assert is_abstract_type(GraphQLList(ObjectType)) is False with raises(TypeError): assert_abstract_type(GraphQLList(ObjectType)) def describe_is_wrapping_type(): def returns_true_for_list_and_non_null_types(): assert is_wrapping_type(GraphQLList(ObjectType)) is True assert_wrapping_type(GraphQLList(ObjectType)) assert is_wrapping_type(GraphQLNonNull(ObjectType)) is True assert_wrapping_type(GraphQLNonNull(ObjectType)) def returns_false_for_unwrapped_types(): assert is_wrapping_type(ObjectType) is False with raises(TypeError): assert_wrapping_type(ObjectType) def describe_is_nullable_type(): def returns_true_for_unwrapped_types(): assert is_nullable_type(ObjectType) is True assert_nullable_type(ObjectType) def returns_true_for_list_of_non_null_types(): assert is_nullable_type(GraphQLList(GraphQLNonNull(ObjectType))) is True assert_nullable_type(GraphQLList(GraphQLNonNull(ObjectType))) def returns_false_for_non_null_types(): assert is_nullable_type(GraphQLNonNull(ObjectType)) is False with raises(TypeError): assert_nullable_type(GraphQLNonNull(ObjectType)) def describe_get_nullable_type(): def returns_none_for_no_type(): assert get_nullable_type(None) is None def returns_self_for_a_nullable_type(): assert get_nullable_type(ObjectType) is ObjectType list_of_obj = GraphQLList(ObjectType) assert get_nullable_type(list_of_obj) is list_of_obj def unwraps_non_null_type(): assert get_nullable_type(GraphQLNonNull(ObjectType)) is ObjectType def describe_is_named_type(): def returns_true_for_unwrapped_types(): assert is_named_type(ObjectType) is True assert_named_type(ObjectType) def returns_false_for_list_and_non_null_types(): assert is_named_type(GraphQLList(ObjectType)) is False with raises(TypeError): assert_named_type(GraphQLList(ObjectType)) assert is_named_type(GraphQLNonNull(ObjectType)) is False with raises(TypeError): assert_named_type(GraphQLNonNull(ObjectType)) def describe_get_named_type(): def returns_none_for_no_type(): assert get_named_type(None) is None def returns_self_for_an_unwrapped_type(): assert get_named_type(ObjectType) is ObjectType def unwraps_wrapper_types(): assert get_named_type(GraphQLNonNull(ObjectType)) is ObjectType assert get_named_type(GraphQLList(ObjectType)) is ObjectType def unwraps_deeply_wrapper_types(): assert ( get_named_type(GraphQLNonNull(GraphQLList(GraphQLNonNull(ObjectType)))) is ObjectType ) def describe_is_required_argument(): def returns_true_for_required_arguments(): required_arg = GraphQLArgument(GraphQLNonNull(GraphQLString)) assert is_required_argument(required_arg) is True def returns_false_for_optional_arguments(): opt_arg1 = GraphQLArgument(GraphQLString) assert is_required_argument(opt_arg1) is False opt_arg2 = GraphQLArgument(GraphQLString, default_value=None) assert is_required_argument(opt_arg2) is False opt_arg3 = GraphQLArgument(GraphQLList(GraphQLNonNull(GraphQLString))) assert is_required_argument(opt_arg3) is False opt_arg4 = GraphQLArgument( GraphQLNonNull(GraphQLString), default_value="default" ) assert is_required_argument(opt_arg4) is False def describe_is_required_input_field(): def returns_true_for_required_input_field(): required_field = GraphQLInputField(GraphQLNonNull(GraphQLString)) assert is_required_input_field(required_field) is True def returns_false_for_optional_input_field(): opt_field1 = GraphQLInputField(GraphQLString) assert is_required_input_field(opt_field1) is False opt_field2 = GraphQLInputField(GraphQLString, default_value=None) assert is_required_input_field(opt_field2) is False opt_field3 = GraphQLInputField(GraphQLList(GraphQLNonNull(GraphQLString))) assert is_required_input_field(opt_field3) is False opt_field4 = GraphQLInputField( GraphQLNonNull(GraphQLString), default_value="default" ) assert is_required_input_field(opt_field4) is False def describe_directive_predicates(): def describe_is_directive(): def returns_true_for_spec_defined_directive(): assert is_directive(GraphQLSkipDirective) is True assert_directive(GraphQLSkipDirective) def returns_true_for_custom_directive(): assert is_directive(Directive) is True assert_directive(Directive) def returns_false_for_directive_class_rather_than_instance(): assert is_directive(GraphQLDirective) is False with raises(TypeError): assert_directive(GraphQLScalarType) def returns_false_for_non_directive(): assert is_directive(EnumType) is False with raises(TypeError): assert_directive(EnumType) assert is_directive(ScalarType) is False with raises(TypeError): assert_directive(ScalarType) def returns_false_for_random_garbage(): assert is_directive(None) is False with raises(TypeError): assert_directive(None) assert is_directive({"what": "is this"}) is False with raises(TypeError): assert_directive({"what": "is this"}) def describe_is_specified_directive(): def returns_true_for_specified_directives(): assert is_specified_directive(GraphQLIncludeDirective) is True assert is_specified_directive(GraphQLSkipDirective) is True assert is_specified_directive(GraphQLDeprecatedDirective) is True def returns_false_for_custom_directive(): assert is_specified_directive(Directive) is False graphql-core-3.2.6/tests/type/test_scalars.py000066400000000000000000000655031474546154300213200ustar00rootroot00000000000000from math import inf, nan, pi from typing import Any from pytest import raises from graphql.error import GraphQLError from graphql.language import parse_value as parse_value_to_ast from graphql.pyutils import Undefined from graphql.type import ( GraphQLInt, GraphQLFloat, GraphQLString, GraphQLBoolean, GraphQLID, ) def describe_type_system_specified_scalar_types(): def describe_graphql_int(): def parse_value(): _parse_value = GraphQLInt.parse_value def _parse_value_raises(s: Any, message: str): with raises(GraphQLError) as exc_info: _parse_value(s) assert str(exc_info.value) == message assert _parse_value(1) == 1 assert _parse_value(0) == 0 assert _parse_value(-1) == -1 _parse_value_raises( 9876504321, "Int cannot represent non 32-bit signed integer value: 9876504321", ) _parse_value_raises( -9876504321, "Int cannot represent non 32-bit signed integer value: -9876504321", ) _parse_value_raises(0.1, "Int cannot represent non-integer value: 0.1") _parse_value_raises(nan, "Int cannot represent non-integer value: nan") _parse_value_raises(inf, "Int cannot represent non-integer value: inf") _parse_value_raises( Undefined, "Int cannot represent non-integer value: Undefined" ) _parse_value_raises(None, "Int cannot represent non-integer value: None") _parse_value_raises("", "Int cannot represent non-integer value: ''") _parse_value_raises("123", "Int cannot represent non-integer value: '123'") _parse_value_raises(False, "Int cannot represent non-integer value: False") _parse_value_raises(True, "Int cannot represent non-integer value: True") _parse_value_raises([1], "Int cannot represent non-integer value: [1]") _parse_value_raises( {"value": 1}, "Int cannot represent non-integer value: {'value': 1}" ) def parse_literal(): def _parse_literal(s: str): return GraphQLInt.parse_literal(parse_value_to_ast(s)) def _parse_literal_raises(s: str, message: str): with raises(GraphQLError) as exc_info: _parse_literal(s) assert str(exc_info.value).startswith(message + "\n") assert _parse_literal("1") == 1 assert _parse_literal("0") == 0 assert _parse_literal("-1") == -1 _parse_literal_raises( "9876504321", "Int cannot represent non 32-bit signed integer value: 9876504321", ) _parse_literal_raises( "-9876504321", "Int cannot represent non 32-bit signed integer value: -9876504321", ) _parse_literal_raises("1.0", "Int cannot represent non-integer value: 1.0") _parse_literal_raises( "null", "Int cannot represent non-integer value: null" ) _parse_literal_raises( "None", "Int cannot represent non-integer value: None" ) _parse_literal_raises('""', 'Int cannot represent non-integer value: ""') _parse_literal_raises( '"123"', 'Int cannot represent non-integer value: "123"' ) _parse_literal_raises( "false", "Int cannot represent non-integer value: false" ) _parse_literal_raises( "False", "Int cannot represent non-integer value: False" ) _parse_literal_raises("[1]", "Int cannot represent non-integer value: [1]") _parse_literal_raises( "{value: 1}", "Int cannot represent non-integer value: {value: 1}" ) _parse_literal_raises( "ENUM_VALUE", "Int cannot represent non-integer value: ENUM_VALUE" ) _parse_literal_raises( "$var", "Int cannot represent non-integer value: $var" ) def serializes(): serialize = GraphQLInt.serialize assert serialize(1) == 1 assert serialize("123") == 123 assert serialize(0) == 0 assert serialize(-1) == -1 assert serialize(1e5) == 100000 assert serialize(False) == 0 assert serialize(True) == 1 assert serialize(type("Int", (int,), {})(5)) == 5 # The GraphQL specification does not allow serializing non-integer # values as Int to avoid accidental data loss. with raises(GraphQLError) as exc_info: serialize(0.1) assert str(exc_info.value) == "Int cannot represent non-integer value: 0.1" with raises(GraphQLError) as exc_info: serialize(1.1) assert str(exc_info.value) == "Int cannot represent non-integer value: 1.1" with raises(GraphQLError) as exc_info: serialize(-1.1) assert str(exc_info.value) == "Int cannot represent non-integer value: -1.1" with raises(GraphQLError) as exc_info: serialize("-1.1") assert ( str(exc_info.value) == "Int cannot represent non-integer value: '-1.1'" ) # Maybe a safe JavaScript int, but bigger than 2^32, so not # representable as a GraphQL Int with raises(GraphQLError) as exc_info: serialize(9876504321) assert str(exc_info.value) == ( "Int cannot represent non 32-bit signed integer value: 9876504321" ) with raises(GraphQLError) as exc_info: serialize(-9876504321) assert str(exc_info.value) == ( "Int cannot represent non 32-bit signed integer value: -9876504321" ) # Too big to represent as an Int in JavaScript or GraphQL with raises(GraphQLError) as exc_info: serialize(1e100) assert str(exc_info.value) == ( "Int cannot represent non 32-bit signed integer value: 1e+100" ) with raises(GraphQLError) as exc_info: serialize(-1e100) assert str(exc_info.value) == ( "Int cannot represent non 32-bit signed integer value: -1e+100" ) with raises(GraphQLError) as exc_info: serialize("one") assert ( str(exc_info.value) == "Int cannot represent non-integer value: 'one'" ) # Doesn't represent number with raises(GraphQLError) as exc_info: serialize("") assert str(exc_info.value) == "Int cannot represent non-integer value: ''" with raises(GraphQLError) as exc_info: serialize(nan) assert str(exc_info.value) == "Int cannot represent non-integer value: nan" with raises(GraphQLError) as exc_info: serialize(inf) assert str(exc_info.value) == "Int cannot represent non-integer value: inf" with raises(GraphQLError) as exc_info: serialize([5]) assert str(exc_info.value) == "Int cannot represent non-integer value: [5]" def describe_graphql_float(): def parse_value(): _parse_value = GraphQLFloat.parse_value def _parse_value_raises(s: Any, message: str): with raises(GraphQLError) as exc_info: _parse_value(s) assert str(exc_info.value) == message assert _parse_value(1) == 1 assert _parse_value(0) == 0 assert _parse_value(-1) == -1 assert _parse_value(0.1) == 0.1 assert _parse_value(pi) == pi _parse_value_raises(nan, "Float cannot represent non numeric value: nan") _parse_value_raises(inf, "Float cannot represent non numeric value: inf") _parse_value_raises("", "Float cannot represent non numeric value: ''") _parse_value_raises( "123", "Float cannot represent non numeric value: '123'" ) _parse_value_raises( "123.5", "Float cannot represent non numeric value: '123.5'" ) _parse_value_raises( False, "Float cannot represent non numeric value: False" ) _parse_value_raises(True, "Float cannot represent non numeric value: True") _parse_value_raises( [0.1], "Float cannot represent non numeric value: [0.1]" ) _parse_value_raises( {"value": 0.1}, "Float cannot represent non numeric value: {'value': 0.1}", ) def parse_literal(): def _parse_literal(s: str): return GraphQLFloat.parse_literal(parse_value_to_ast(s)) def _parse_literal_raises(s: str, message: str): with raises(GraphQLError) as exc_info: _parse_literal(s) assert str(exc_info.value).startswith(message + "\n") assert _parse_literal("1") == 1 assert _parse_literal("0") == 0 assert _parse_literal("-1") == -1 assert _parse_literal("0.1") == 0.1 assert _parse_literal(str(pi)) == pi _parse_literal_raises( "null", "Float cannot represent non numeric value: null" ) _parse_literal_raises( "None", "Float cannot represent non numeric value: None" ) _parse_literal_raises('""', 'Float cannot represent non numeric value: ""') _parse_literal_raises( '"123"', 'Float cannot represent non numeric value: "123"' ) _parse_literal_raises( '"123.5"', 'Float cannot represent non numeric value: "123.5"' ) _parse_literal_raises( "false", "Float cannot represent non numeric value: false" ) _parse_literal_raises( "False", "Float cannot represent non numeric value: False" ) _parse_literal_raises( "[0.1]", "Float cannot represent non numeric value: [0.1]" ) _parse_literal_raises( "{value: 0.1}", "Float cannot represent non numeric value: {value: 0.1}" ) _parse_literal_raises( "ENUM_VALUE", "Float cannot represent non numeric value: ENUM_VALUE" ) _parse_literal_raises( "$var", "Float cannot represent non numeric value: $var" ) def serializes(): serialize = GraphQLFloat.serialize assert serialize(1) == 1.0 assert serialize(0) == 0.0 assert serialize("123.5") == 123.5 assert serialize(-1) == -1.0 assert serialize(0.1) == 0.1 assert serialize(1.1) == 1.1 assert serialize(-1.1) == -1.1 assert serialize("-1.1") == -1.1 assert serialize(False) == 0 assert serialize(True) == 1 assert serialize(type("Float", (float,), {})(5.5)) == 5.5 with raises(GraphQLError) as exc_info: serialize(nan) assert ( str(exc_info.value) == "Float cannot represent non numeric value: nan" ) with raises(GraphQLError) as exc_info: serialize(inf) assert ( str(exc_info.value) == "Float cannot represent non numeric value: inf" ) with raises(GraphQLError) as exc_info: serialize("one") assert str(exc_info.value) == ( "Float cannot represent non numeric value: 'one'" ) with raises(GraphQLError) as exc_info: serialize("") assert str(exc_info.value) == "Float cannot represent non numeric value: ''" with raises(GraphQLError) as exc_info: serialize([5]) assert ( str(exc_info.value) == "Float cannot represent non numeric value: [5]" ) def describe_graphql_string(): def parse_value(): _parse_value = GraphQLString.parse_value def _parse_value_raises(s: Any, message: str): with raises(GraphQLError) as exc_info: _parse_value(s) assert str(exc_info.value) == message assert _parse_value("foo") == "foo" _parse_value_raises( Undefined, "String cannot represent a non string value: Undefined" ) _parse_value_raises( None, "String cannot represent a non string value: None" ) _parse_value_raises(1, "String cannot represent a non string value: 1") _parse_value_raises(nan, "String cannot represent a non string value: nan") _parse_value_raises( False, "String cannot represent a non string value: False" ) _parse_value_raises( ["foo"], "String cannot represent a non string value: ['foo']" ) _parse_value_raises( {"value": "foo"}, "String cannot represent a non string value: {'value': 'foo'}", ) def parse_literal(): def _parse_literal(s: str): return GraphQLString.parse_literal(parse_value_to_ast(s)) def _parse_literal_raises(s: str, message: str): with raises(GraphQLError) as exc_info: _parse_literal(s) assert str(exc_info.value).startswith(message + "\n") assert _parse_literal('"foo"') == "foo" assert _parse_literal('"""bar"""') == "bar" _parse_literal_raises( "null", "String cannot represent a non string value: null" ) _parse_literal_raises( "None", "String cannot represent a non string value: None" ) _parse_literal_raises("1", "String cannot represent a non string value: 1") _parse_literal_raises( "0.1", "String cannot represent a non string value: 0.1" ) _parse_literal_raises( "false", "String cannot represent a non string value: false" ) _parse_literal_raises( "False", "String cannot represent a non string value: False" ) _parse_literal_raises( '["foo"]', 'String cannot represent a non string value: ["foo"]' ) _parse_literal_raises( '{value: "foo"}', 'String cannot represent a non string value: {value: "foo"}', ) _parse_literal_raises( "ENUM_VALUE", "String cannot represent a non string value: ENUM_VALUE" ) _parse_literal_raises( "$var", "String cannot represent a non string value: $var" ) def serializes(): serialize = GraphQLString.serialize assert serialize("string") == "string" assert serialize(1) == "1" assert serialize(-1.1) == "-1.1" assert serialize(True) == "true" assert serialize(False) == "false" class StringableObjValue: def __str__(self): return "something useful" assert serialize(StringableObjValue()) == "something useful" with raises(GraphQLError) as exc_info: serialize(nan) assert str(exc_info.value) == "String cannot represent value: nan" with raises(GraphQLError) as exc_info: serialize([1]) assert str(exc_info.value) == "String cannot represent value: [1]" with raises(GraphQLError) as exc_info: serialize({}) assert str(exc_info.value) == "String cannot represent value: {}" with raises(GraphQLError) as exc_info: serialize({"value_of": "value_of string"}) assert ( str(exc_info.value) == "String cannot represent value:" " {'value_of': 'value_of string'}" ) def describe_graphql_boolean(): def parse_value(): _parse_value = GraphQLBoolean.parse_value def _parse_value_raises(s: Any, message: str): with raises(GraphQLError) as exc_info: _parse_value(s) assert str(exc_info.value) == message assert _parse_value(True) is True assert _parse_value(False) is False _parse_value_raises( Undefined, "Boolean cannot represent a non boolean value: Undefined" ) _parse_value_raises( None, "Boolean cannot represent a non boolean value: None" ) _parse_value_raises(0, "Boolean cannot represent a non boolean value: 0") _parse_value_raises(1, "Boolean cannot represent a non boolean value: 1") _parse_value_raises( nan, "Boolean cannot represent a non boolean value: nan" ) _parse_value_raises("", "Boolean cannot represent a non boolean value: ''") _parse_value_raises( "false", "Boolean cannot represent a non boolean value: 'false'" ) _parse_value_raises( "False", "Boolean cannot represent a non boolean value: 'False'" ) _parse_value_raises( [False], "Boolean cannot represent a non boolean value: [False]" ) _parse_value_raises( {"value": False}, "Boolean cannot represent a non boolean value: {'value': False}", ) def parse_literal(): def _parse_literal(s: str): return GraphQLBoolean.parse_literal(parse_value_to_ast(s)) def _parse_literal_raises(s: str, message: str): with raises(GraphQLError) as exc_info: _parse_literal(s) assert str(exc_info.value).startswith(message + "\n") assert _parse_literal("true") is True assert _parse_literal("false") is False _parse_literal_raises( "True", "Boolean cannot represent a non boolean value: True" ) _parse_literal_raises( "False", "Boolean cannot represent a non boolean value: False" ) _parse_literal_raises( "null", "Boolean cannot represent a non boolean value: null" ) _parse_literal_raises( "None", "Boolean cannot represent a non boolean value: None" ) _parse_literal_raises( "0", "Boolean cannot represent a non boolean value: 0" ) _parse_literal_raises( "1", "Boolean cannot represent a non boolean value: 1" ) _parse_literal_raises( "0.1", "Boolean cannot represent a non boolean value: 0.1" ) _parse_literal_raises( '""', 'Boolean cannot represent a non boolean value: ""' ) _parse_literal_raises( '"false"', 'Boolean cannot represent a non boolean value: "false"' ) _parse_literal_raises( '"False"', 'Boolean cannot represent a non boolean value: "False"' ) _parse_literal_raises( "[false]", "Boolean cannot represent a non boolean value: [false]" ) _parse_literal_raises( "[False]", "Boolean cannot represent a non boolean value: [False]" ) _parse_literal_raises( "{value: false}", "Boolean cannot represent a non boolean value: {value: false}", ) _parse_literal_raises( "{value: False}", "Boolean cannot represent a non boolean value: {value: False}", ) _parse_literal_raises( "ENUM_VALUE", "Boolean cannot represent a non boolean value: ENUM_VALUE" ) _parse_literal_raises( "$var", "Boolean cannot represent a non boolean value: $var" ) def serializes(): serialize = GraphQLBoolean.serialize assert serialize(1) is True assert serialize(0) is False assert serialize(True) is True assert serialize(False) is False with raises(TypeError, match="not an acceptable base type"): # you can't subclass bool in Python assert serialize(type("Boolean", (bool,), {})(True)) is True with raises(GraphQLError) as exc_info: serialize(nan) assert str(exc_info.value) == ( "Boolean cannot represent a non boolean value: nan" ) with raises(GraphQLError) as exc_info: serialize("") assert str(exc_info.value) == ( "Boolean cannot represent a non boolean value: ''" ) with raises(GraphQLError) as exc_info: serialize("True") assert str(exc_info.value) == ( "Boolean cannot represent a non boolean value: 'True'" ) with raises(GraphQLError) as exc_info: serialize([False]) assert str(exc_info.value) == ( "Boolean cannot represent a non boolean value: [False]" ) with raises(GraphQLError) as exc_info: serialize({}) assert str(exc_info.value) == ( "Boolean cannot represent a non boolean value: {}" ) def describe_graphql_id(): def parse_value(): _parse_value = GraphQLID.parse_value def _parse_value_raises(s: Any, message: str): with raises(GraphQLError) as exc_info: _parse_value(s) assert str(exc_info.value) == message assert _parse_value("") == "" assert _parse_value("1") == "1" assert _parse_value("foo") == "foo" assert _parse_value(1) == "1" assert _parse_value(0) == "0" assert _parse_value(-1) == "-1" assert _parse_value(1.0) == "1" # Maximum and minimum safe numbers in JS assert _parse_value(9007199254740991) == "9007199254740991" assert _parse_value(-9007199254740991) == "-9007199254740991" _parse_value_raises(Undefined, "ID cannot represent value: Undefined") _parse_value_raises(None, "ID cannot represent value: None") _parse_value_raises(0.1, "ID cannot represent value: 0.1") _parse_value_raises(nan, "ID cannot represent value: nan") _parse_value_raises(inf, "ID cannot represent value: inf") _parse_value_raises(False, "ID cannot represent value: False") _parse_value_raises(["1"], "ID cannot represent value: ['1']") _parse_value_raises( {"value": "1"}, "ID cannot represent value: {'value': '1'}" ) def parse_literal(): def _parse_literal(s: str): return GraphQLID.parse_literal(parse_value_to_ast(s)) def _parse_literal_raises(s: str, message: str): with raises(GraphQLError) as exc_info: _parse_literal(s) assert str(exc_info.value).startswith(message + "\n") assert _parse_literal('""') == "" assert _parse_literal('"1"') == "1" assert _parse_literal('"foo"') == "foo" assert _parse_literal('"""foo"""') == "foo" assert _parse_literal("1") == "1" assert _parse_literal("0") == "0" assert _parse_literal("-1") == "-1" # Support arbitrary long numbers even if they can't be represented in JS assert _parse_literal("90071992547409910") == "90071992547409910" assert _parse_literal("-90071992547409910") == "-90071992547409910" _parse_literal_raises( "null", "ID cannot represent a non-string and non-integer value: null" ) _parse_literal_raises( "None", "ID cannot represent a non-string and non-integer value: None" ) _parse_literal_raises( "0.1", "ID cannot represent a non-string and non-integer value: 0.1" ) _parse_literal_raises( "false", "ID cannot represent a non-string and non-integer value: false" ) _parse_literal_raises( "False", "ID cannot represent a non-string and non-integer value: False" ) _parse_literal_raises( '["1"]', 'ID cannot represent a non-string and non-integer value: ["1"]' ) _parse_literal_raises( '{value: "1"}', "ID cannot represent a non-string and non-integer value:" ' {value: "1"}', ) _parse_literal_raises( "ENUM_VALUE", "ID cannot represent a non-string and non-integer value: ENUM_VALUE", ) _parse_literal_raises( "$var", "ID cannot represent a non-string and non-integer value: $var" ) def serializes(): serialize = GraphQLID.serialize assert serialize("string") == "string" assert serialize("false") == "false" assert serialize("") == "" assert serialize(123) == "123" assert serialize(42.0) == "42" assert serialize(0) == "0" assert serialize(-1) == "-1" class ObjValue: def __init__(self, value): self._id = value def __str__(self): return str(self._id) obj_value = ObjValue(123) assert serialize(obj_value) == "123" with raises(GraphQLError) as exc_info: serialize(True) assert str(exc_info.value) == "ID cannot represent value: True" with raises(GraphQLError) as exc_info: serialize(3.14) assert str(exc_info.value) == "ID cannot represent value: 3.14" with raises(GraphQLError) as exc_info: serialize({}) assert str(exc_info.value) == "ID cannot represent value: {}" with raises(GraphQLError) as exc_info: serialize(["abc"]) assert str(exc_info.value) == "ID cannot represent value: ['abc']" graphql-core-3.2.6/tests/type/test_schema.py000066400000000000000000000377461474546154300211400ustar00rootroot00000000000000from copy import deepcopy from pytest import raises from graphql.language import ( DirectiveLocation, SchemaDefinitionNode, SchemaExtensionNode, TypeDefinitionNode, TypeExtensionNode, ) from graphql.type import ( GraphQLArgument, GraphQLBoolean, GraphQLDirective, GraphQLField, GraphQLFieldMap, GraphQLInputObjectType, GraphQLInputField, GraphQLInt, GraphQLInterfaceType, GraphQLList, GraphQLObjectType, GraphQLScalarType, GraphQLSchema, GraphQLString, GraphQLType, specified_directives, ) from graphql.utilities import build_schema, lexicographic_sort_schema, print_schema from ..utils import dedent def describe_type_system_schema(): def define_sample_schema(): BlogImage = GraphQLObjectType( "Image", { "url": GraphQLField(GraphQLString), "width": GraphQLField(GraphQLInt), "height": GraphQLField(GraphQLInt), }, ) BlogArticle: GraphQLObjectType BlogAuthor = GraphQLObjectType( "Author", lambda: { "id": GraphQLField(GraphQLString), "name": GraphQLField(GraphQLString), "pic": GraphQLField( BlogImage, args={ "width": GraphQLArgument(GraphQLInt), "height": GraphQLArgument(GraphQLInt), }, ), "recentArticle": GraphQLField(BlogArticle), }, ) BlogArticle = GraphQLObjectType( "Article", lambda: { "id": GraphQLField(GraphQLString), "isPublished": GraphQLField(GraphQLBoolean), "author": GraphQLField(BlogAuthor), "title": GraphQLField(GraphQLString), "body": GraphQLField(GraphQLString), }, ) BlogQuery = GraphQLObjectType( "Query", { "article": GraphQLField( BlogArticle, args={"id": GraphQLArgument(GraphQLString)} ), "feed": GraphQLField(GraphQLList(BlogArticle)), }, ) BlogMutation = GraphQLObjectType( "Mutation", {"writeArticle": GraphQLField(BlogArticle)} ) BlogSubscription = GraphQLObjectType( "Subscription", { "articleSubscribe": GraphQLField( args={"id": GraphQLArgument(GraphQLString)}, type_=BlogArticle ) }, ) schema = GraphQLSchema( BlogQuery, BlogMutation, BlogSubscription, description="Sample schema", ) kwargs = schema.to_kwargs() types = kwargs.pop("types") assert types == tuple(schema.type_map.values()) assert kwargs == { "query": BlogQuery, "mutation": BlogMutation, "subscription": BlogSubscription, "directives": specified_directives, "description": "Sample schema", "extensions": {}, "ast_node": None, "extension_ast_nodes": (), "assume_valid": False, } assert print_schema(schema) == dedent( ''' """Sample schema""" schema { query: Query mutation: Mutation subscription: Subscription } type Query { article(id: String): Article feed: [Article] } type Article { id: String isPublished: Boolean author: Author title: String body: String } type Author { id: String name: String pic(width: Int, height: Int): Image recentArticle: Article } type Image { url: String width: Int height: Int } type Mutation { writeArticle: Article } type Subscription { articleSubscribe(id: String): Article } ''' ) def freezes_the_specified_directives(): directives_list = [GraphQLDirective("SomeDirective", [])] schema = GraphQLSchema(directives=directives_list) assert isinstance(schema.directives, tuple) assert schema.directives == tuple(directives_list) directives_tuple = schema.directives schema = GraphQLSchema(directives=directives_tuple) assert schema.directives is directives_tuple def rejects_a_schema_with_incorrectly_typed_description(): with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLSchema(description=[]) # type: ignore assert str(exc_info.value) == "Schema description must be a string." def describe_type_map(): def includes_interface_possible_types_in_the_type_map(): SomeInterface = GraphQLInterfaceType("SomeInterface", {}) SomeSubtype = GraphQLObjectType( "SomeSubtype", {}, interfaces=[SomeInterface] ) schema = GraphQLSchema( query=GraphQLObjectType( "Query", {"iface": GraphQLField(SomeInterface)} ), types=[SomeSubtype], ) assert schema.type_map["SomeInterface"] is SomeInterface assert schema.type_map["SomeSubtype"] is SomeSubtype assert schema.is_sub_type(SomeInterface, SomeSubtype) is True def includes_interfaces_thunk_subtypes_in_the_type_map(): AnotherInterface = GraphQLInterfaceType("AnotherInterface", {}) SomeInterface = GraphQLInterfaceType( "SomeInterface", {}, interfaces=lambda: [AnotherInterface] ) SomeSubtype = GraphQLObjectType( "SomeSubtype", {}, interfaces=lambda: [SomeInterface] ) schema = GraphQLSchema( types=[SomeSubtype], ) assert schema.type_map["SomeInterface"] is SomeInterface assert schema.type_map["AnotherInterface"] is AnotherInterface assert schema.type_map["SomeSubtype"] is SomeSubtype def includes_nested_input_objects_in_the_map(): NestedInputObject = GraphQLInputObjectType("NestedInputObject", {}) SomeInputObject = GraphQLInputObjectType( "SomeInputObject", {"nested": GraphQLInputField(NestedInputObject)} ) schema = GraphQLSchema( GraphQLObjectType( "Query", { "something": GraphQLField( GraphQLString, {"input": GraphQLArgument(SomeInputObject)} ) }, ) ) assert schema.type_map["SomeInputObject"] is SomeInputObject assert schema.type_map["NestedInputObject"] is NestedInputObject def includes_input_types_only_used_in_directives(): directive = GraphQLDirective( name="dir", locations=[DirectiveLocation.OBJECT], args={ "arg": GraphQLArgument( GraphQLInputObjectType( "Foo", {"field": GraphQLInputField(GraphQLString)} ) ), "argList": GraphQLArgument( GraphQLList( GraphQLInputObjectType( "Bar", {"field": GraphQLInputField(GraphQLString)} ) ) ), }, ) schema = GraphQLSchema(directives=[directive]) assert "Foo" in schema.type_map assert "Bar" in schema.type_map def preserves_the_order_of_user_provided_types(): a_type = GraphQLObjectType( "A", {"sub": GraphQLField(GraphQLScalarType("ASub"))} ) z_type = GraphQLObjectType( "Z", {"sub": GraphQLField(GraphQLScalarType("ZSub"))} ) query_type = GraphQLObjectType( "Query", { "a": GraphQLField(a_type), "z": GraphQLField(z_type), "sub": GraphQLField(GraphQLScalarType("QuerySub")), }, ) schema = GraphQLSchema(query_type, types=[z_type, query_type, a_type]) type_names = list(schema.type_map) assert type_names == [ "Z", "ZSub", "Query", "QuerySub", "A", "ASub", "Boolean", "String", "__Schema", "__Type", "__TypeKind", "__Field", "__InputValue", "__EnumValue", "__Directive", "__DirectiveLocation", ] # Also check that this order is stable copy_schema = GraphQLSchema(**schema.to_kwargs()) assert list(copy_schema.type_map) == type_names def describe_validity(): def describe_when_not_assumed_valid(): def configures_the_schema_to_still_needing_validation(): # noinspection PyProtectedMember assert GraphQLSchema(assume_valid=False).validation_errors is None def checks_the_configuration_for_mistakes(): def query(): pass with raises(Exception): # noinspection PyTypeChecker GraphQLSchema(query) # type: ignore with raises(Exception): GraphQLSchema(types={}) with raises(Exception): GraphQLSchema(directives={}) def check_that_query_mutation_and_subscription_are_graphql_types(): directive = GraphQLDirective("foo", []) with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLSchema(query=directive) # type: ignore assert str(exc_info.value) == "Expected query to be a GraphQL type." with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLSchema(mutation=directive) # type: ignore assert str(exc_info.value) == ( "Expected mutation to be a GraphQL type." ) with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLSchema(subscription=directive) # type: ignore assert str(exc_info.value) == ( "Expected subscription to be a GraphQL type." ) def describe_a_schema_must_contain_uniquely_named_types(): def rejects_a_schema_which_redefines_a_built_in_type(): FakeString = GraphQLScalarType("String") QueryType = GraphQLObjectType( "Query", { "normal": GraphQLField(GraphQLString), "fake": GraphQLField(FakeString), }, ) with raises(TypeError) as exc_info: GraphQLSchema(QueryType) msg = str(exc_info.value) assert msg == ( "Schema must contain uniquely named types" " but contains multiple types named 'String'." ) def rejects_a_schema_when_a_provided_type_has_no_name(): query = GraphQLObjectType("Query", {"foo": GraphQLField(GraphQLString)}) types = [GraphQLType(), query, GraphQLType()] with raises(TypeError) as exc_info: GraphQLSchema(query, types=types) # type: ignore msg = str(exc_info.value) assert msg == ( "One of the provided types for building the Schema is missing a name." ) def rejects_a_schema_which_defines_an_object_twice(): types = [ GraphQLObjectType("SameName", {}), GraphQLObjectType("SameName", {}), ] with raises(TypeError) as exc_info: GraphQLSchema(types=types) msg = str(exc_info.value) assert msg == ( "Schema must contain uniquely named types" " but contains multiple types named 'SameName'." ) def rejects_a_schema_which_defines_fields_with_conflicting_types(): fields: GraphQLFieldMap = {} QueryType = GraphQLObjectType( "Query", { "a": GraphQLField(GraphQLObjectType("SameName", fields)), "b": GraphQLField(GraphQLObjectType("SameName", fields)), }, ) with raises(TypeError) as exc_info: GraphQLSchema(QueryType) msg = str(exc_info.value) assert msg == ( "Schema must contain uniquely named types" " but contains multiple types named 'SameName'." ) def describe_when_assumed_valid(): def configures_the_schema_to_have_no_errors(): # noinspection PyProtectedMember assert GraphQLSchema(assume_valid=True).validation_errors == [] def describe_ast_nodes(): def accepts_a_scalar_type_with_ast_node_and_extension_ast_nodes(): ast_node = SchemaDefinitionNode() extension_ast_nodes = [SchemaExtensionNode()] schema = GraphQLSchema( GraphQLObjectType("Query", {}), ast_node=ast_node, extension_ast_nodes=extension_ast_nodes, ) assert schema.ast_node is ast_node assert schema.extension_ast_nodes == tuple(extension_ast_nodes) def rejects_a_schema_with_an_incorrect_ast_node(): with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLSchema( GraphQLObjectType("Query", {}), ast_node=TypeDefinitionNode(), # type: ignore ) msg = str(exc_info.value) assert msg == "Schema AST node must be a SchemaDefinitionNode." def rejects_a_scalar_type_with_incorrect_extension_ast_nodes(): with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLSchema( GraphQLObjectType("Query", {}), extension_ast_nodes=[TypeExtensionNode()], # type: ignore ) assert str(exc_info.value) == ( "Schema extension AST nodes must be specified" " as a collection of SchemaExtensionNode instances." ) def can_deep_copy_a_schema(): source = """ schema { query: Farm mutation: Work } type Cow { id: ID! name: String moos: Boolean } type Pig { id: ID! name: String oink: Boolean } union Animal = Cow | Pig enum Food { CORN FRUIT } input Feed { amount: Float type: Food } type Farm { animals: [Animal!]! } type Work { feed(feed: Feed): Boolean } """ schema = build_schema(source) schema_copy = deepcopy(schema) for name in ("Cow", "Pig", "Animal", "Food", "Feed", "Farm", "Work"): assert schema.get_type(name) is not schema_copy.get_type(name) assert print_schema(lexicographic_sort_schema(schema)) == print_schema( lexicographic_sort_schema(schema_copy) ) graphql-core-3.2.6/tests/type/test_validation.py000066400000000000000000002357701474546154300220270ustar00rootroot00000000000000from operator import attrgetter from typing import Any, List, Union from pytest import mark, raises from graphql.language import parse, DirectiveLocation from graphql.pyutils import inspect from graphql.type import ( assert_directive, assert_enum_type, assert_input_object_type, assert_interface_type, assert_object_type, assert_scalar_type, assert_union_type, assert_valid_schema, is_input_type, is_output_type, validate_schema, GraphQLArgument, GraphQLDirective, GraphQLEnumType, GraphQLField, GraphQLInputField, GraphQLInputType, GraphQLInputObjectType, GraphQLInt, GraphQLInterfaceType, GraphQLList, GraphQLNamedType, GraphQLNonNull, GraphQLObjectType, GraphQLOutputType, GraphQLSchema, GraphQLString, GraphQLUnionType, ) from graphql.utilities import build_schema, extend_schema from ..utils import dedent SomeSchema = build_schema( """ scalar SomeScalar interface SomeInterface { f: SomeObject } type SomeObject implements SomeInterface { f: SomeObject } union SomeUnion = SomeObject enum SomeEnum { ONLY } input SomeInputObject { val: String = "hello" } directive @SomeDirective on QUERY """ ) get_type = SomeSchema.get_type SomeScalarType = assert_scalar_type(get_type("SomeScalar")) SomeInterfaceType = assert_interface_type(get_type("SomeInterface")) SomeObjectType = assert_object_type(get_type("SomeObject")) SomeUnionType = assert_union_type(get_type("SomeUnion")) SomeEnumType = assert_enum_type(get_type("SomeEnum")) SomeInputObjectType = assert_input_object_type(get_type("SomeInputObject")) SomeDirective = assert_directive(SomeSchema.get_directive("SomeDirective")) def with_modifiers( type_: GraphQLNamedType, ) -> List[Union[GraphQLNamedType, GraphQLNonNull, GraphQLList]]: return [ type_, GraphQLList(type_), GraphQLNonNull(type_), GraphQLNonNull(GraphQLList(type_)), ] output_types = [ *with_modifiers(GraphQLString), *with_modifiers(SomeScalarType), *with_modifiers(SomeEnumType), *with_modifiers(SomeObjectType), *with_modifiers(SomeUnionType), *with_modifiers(SomeInterfaceType), ] not_output_types = with_modifiers(SomeInputObjectType) input_types = [ *with_modifiers(GraphQLString), *with_modifiers(SomeScalarType), *with_modifiers(SomeEnumType), *with_modifiers(SomeInputObjectType), ] not_input_types = [ *with_modifiers(SomeObjectType), *with_modifiers(SomeUnionType), *with_modifiers(SomeInterfaceType), ] not_graphql_types = [ type("IntType", (int,), {"name": "IntType"}), type("FloatType", (float,), {"name": "FloatType"}), type("StringType", (str,), {"name": "StringType"}), ] get_name = attrgetter("__class__.__name__") def schema_with_field_type(type_): return GraphQLSchema( query=GraphQLObjectType(name="Query", fields={"f": GraphQLField(type_)}) ) def describe_type_system_a_schema_must_have_object_root_types(): def accepts_a_schema_whose_query_type_is_an_object_type(): schema = build_schema( """ type Query { test: String } """ ) assert validate_schema(schema) == [] schema_with_def = build_schema( """ schema { query: QueryRoot } type QueryRoot { test: String } """ ) assert validate_schema(schema_with_def) == [] def accepts_a_schema_whose_query_and_mutation_types_are_object_types(): schema = build_schema( """ type Query { test: String } type Mutation { test: String } """ ) assert validate_schema(schema) == [] schema_with_def = build_schema( """ schema { query: QueryRoot mutation: MutationRoot } type QueryRoot { test: String } type MutationRoot { test: String } """ ) assert validate_schema(schema_with_def) == [] def accepts_a_schema_whose_query_and_subscription_types_are_object_types(): schema = build_schema( """ type Query { test: String } type Subscription { test: String } """ ) assert validate_schema(schema) == [] schema_with_def = build_schema( """ schema { query: QueryRoot subscription: SubscriptionRoot } type QueryRoot { test: String } type SubscriptionRoot { test: String } """ ) assert validate_schema(schema_with_def) == [] def rejects_a_schema_without_a_query_type(): schema = build_schema( """ type Mutation { test: String } """ ) assert validate_schema(schema) == [ {"message": "Query root type must be provided.", "locations": None} ] schema_with_def = build_schema( """ schema { mutation: MutationRoot } type MutationRoot { test: String } """ ) assert validate_schema(schema_with_def) == [ {"message": "Query root type must be provided.", "locations": [(2, 13)]} ] def rejects_a_schema_whose_query_root_type_is_not_an_object_type(): schema = build_schema( """ input Query { test: String } """ ) assert validate_schema(schema) == [ { "message": "Query root type must be Object type," " it cannot be Query.", "locations": [(2, 13)], } ] schema_with_def = build_schema( """ schema { query: SomeInputObject } input SomeInputObject { test: String } """ ) assert validate_schema(schema_with_def) == [ { "message": "Query root type must be Object type," " it cannot be SomeInputObject.", "locations": [(3, 22)], } ] def rejects_a_schema_whose_mutation_type_is_an_input_type(): schema = build_schema( """ type Query { field: String } input Mutation { test: String } """ ) assert validate_schema(schema) == [ { "message": "Mutation root type must be Object type if provided," " it cannot be Mutation.", "locations": [(6, 13)], } ] schema_with_def = build_schema( """ schema { query: Query mutation: SomeInputObject } type Query { field: String } input SomeInputObject { test: String } """ ) assert validate_schema(schema_with_def) == [ { "message": "Mutation root type must be Object type if provided," " it cannot be SomeInputObject.", "locations": [(4, 25)], } ] def rejects_a_schema_whose_subscription_type_is_an_input_type(): schema = build_schema( """ type Query { field: String } input Subscription { test: String } """ ) assert validate_schema(schema) == [ { "message": "Subscription root type must be Object type if" " provided, it cannot be Subscription.", "locations": [(6, 13)], } ] schema_with_def = build_schema( """ schema { query: Query subscription: SomeInputObject } type Query { field: String } input SomeInputObject { test: String } """ ) assert validate_schema(schema_with_def) == [ { "message": "Subscription root type must be Object type if" " provided, it cannot be SomeInputObject.", "locations": [(4, 29)], } ] def rejects_a_schema_extended_with_invalid_root_types(): schema = build_schema( """ input SomeInputObject { test: String } """ ) schema = extend_schema( schema, parse( """ extend schema { query: SomeInputObject } """ ), ) schema = extend_schema( schema, parse( """ extend schema { mutation: SomeInputObject } """ ), ) schema = extend_schema( schema, parse( """ extend schema { subscription: SomeInputObject } """ ), ) assert validate_schema(schema) == [ { "message": "Query root type must be Object type," " it cannot be SomeInputObject.", "locations": [(3, 26)], }, { "message": "Mutation root type must be Object type" " if provided, it cannot be SomeInputObject.", "locations": [(3, 29)], }, { "message": "Subscription root type must be Object type" " if provided, it cannot be SomeInputObject.", "locations": [(3, 33)], }, ] def rejects_a_schema_whose_types_are_incorrectly_type(): # invalid schema cannot be built with Python with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLSchema( SomeObjectType, types=[{"name": "SomeType"}, SomeDirective], # type: ignore ) assert str(exc_info.value) == ( "Schema types must be specified as a collection of GraphQL types." ) # construct invalid schema manually schema = GraphQLSchema(SomeObjectType) schema.type_map = { "SomeType": {"name": "SomeType"}, # type: ignore "SomeDirective": SomeDirective, # type: ignore } assert validate_schema(schema) == [ {"message": "Expected GraphQL named type but got: {'name': 'SomeType'}."}, {"message": "Expected GraphQL named type but got: @SomeDirective."}, ] def rejects_a_schema_whose_directives_are_incorrectly_typed(): schema = GraphQLSchema( SomeObjectType, directives=[None, "SomeDirective", SomeScalarType], # type: ignore ) assert validate_schema(schema) == [ {"message": "Expected directive but got: None."}, {"message": "Expected directive but got: 'SomeDirective'."}, {"message": "Expected directive but got: SomeScalar."}, ] def describe_type_system_objects_must_have_fields(): def accepts_an_object_type_with_fields_object(): schema = build_schema( """ type Query { field: SomeObject } type SomeObject { field: String } """ ) assert validate_schema(schema) == [] def rejects_an_object_type_with_missing_fields(): schema = build_schema( """ type Query { test: IncompleteObject } type IncompleteObject """ ) assert validate_schema(schema) == [ { "message": "Type IncompleteObject must define one or more fields.", "locations": [(6, 13)], } ] manual_schema = schema_with_field_type( GraphQLObjectType("IncompleteObject", {}) ) msg = validate_schema(manual_schema)[0].message assert msg == "Type IncompleteObject must define one or more fields." manual_schema_2 = schema_with_field_type( GraphQLObjectType("IncompleteObject", lambda: {}) ) msg = validate_schema(manual_schema_2)[0].message assert msg == "Type IncompleteObject must define one or more fields." def rejects_an_object_type_with_incorrectly_named_fields(): schema = schema_with_field_type( GraphQLObjectType("SomeObject", {"__badName": GraphQLField(GraphQLString)}) ) msg = validate_schema(schema)[0].message assert msg == ( "Name '__badName' must not begin with '__'," " which is reserved by GraphQL introspection." ) def describe_type_system_field_args_must_be_properly_named(): def accepts_field_args_with_valid_names(): schema = schema_with_field_type( GraphQLObjectType( "SomeObject", { "goodField": GraphQLField( GraphQLString, args={"goodArg": GraphQLArgument(GraphQLString)} ) }, ) ) assert validate_schema(schema) == [] def rejects_field_args_with_invalid_names(): schema = schema_with_field_type( GraphQLObjectType( "SomeObject", { "badField": GraphQLField( GraphQLString, args={"__badName": GraphQLArgument(GraphQLString)}, ) }, ) ) msg = validate_schema(schema)[0].message assert msg == ( "Name '__badName' must not begin with '__'," " which is reserved by GraphQL introspection." ) def describe_type_system_union_types_must_be_valid(): def accepts_a_union_type_with_member_types(): schema = build_schema( """ type Query { test: GoodUnion } type TypeA { field: String } type TypeB { field: String } union GoodUnion = | TypeA | TypeB """ ) assert validate_schema(schema) == [] def rejects_a_union_type_with_empty_types(): schema = build_schema( """ type Query { test: BadUnion } union BadUnion """ ) schema = extend_schema( schema, parse( """ directive @test on UNION extend union BadUnion @test """ ), ) assert validate_schema(schema) == [ { "message": "Union type BadUnion must define one or more member types.", "locations": [(6, 13), (4, 17)], } ] def rejects_a_union_type_with_duplicated_member_type(): schema = build_schema( """ type Query { test: BadUnion } type TypeA { field: String } type TypeB { field: String } union BadUnion = | TypeA | TypeB | TypeA """ ) assert validate_schema(schema) == [ { "message": "Union type BadUnion can only include type TypeA once.", "locations": [(15, 17), (17, 17)], } ] schema = extend_schema(schema, parse("extend union BadUnion = TypeB")) assert validate_schema(schema) == [ { "message": "Union type BadUnion can only include type TypeA once.", "locations": [(15, 17), (17, 17)], }, { "message": "Union type BadUnion can only include type TypeB once.", "locations": [(16, 17), (1, 25)], }, ] def rejects_a_union_type_with_non_object_member_types(): # invalid schema cannot be built with Python with raises(TypeError) as exc_info: build_schema( """ type Query { test: BadUnion } type TypeA { field: String } type TypeB { field: String } union BadUnion = | TypeA | String | TypeB """ ) assert str(exc_info.value) == ( "BadUnion types must be specified" " as a collection of GraphQLObjectType instances." ) # construct invalid schema manually schema = build_schema( """ type Query { test: BadUnion } type TypeA { field: String } type TypeB { field: String } union BadUnion = | TypeA | TypeA | TypeB """ ) with raises(TypeError) as exc_info: extend_schema(schema, parse("extend union BadUnion = Int")) assert str(exc_info.value) == ( "BadUnion types must be specified" " as a collection of GraphQLObjectType instances." ) schema = extend_schema(schema, parse("extend union BadUnion = TypeB")) bad_union: Any = schema.get_type("BadUnion") types = bad_union.types assert isinstance(types, tuple) types = list(types) assert types[1].name == "TypeA" types[1] = GraphQLString assert types[3].name == "TypeB" types[3] = GraphQLInt bad_union.types = tuple(types) bad_union.ast_node.types[1].name.value = "String" bad_union.extension_ast_nodes[0].types[0].name.value = "Int" assert validate_schema(schema) == [ { "message": "Union type BadUnion can only include Object types," " it cannot include String.", "locations": [(16, 17)], }, { "message": "Union type BadUnion can only include Object types," " it cannot include Int.", "locations": [(1, 25)], }, ] bad_union_member_types = [ GraphQLString, GraphQLNonNull(SomeObjectType), GraphQLList(SomeObjectType), SomeInterfaceType, SomeUnionType, SomeEnumType, SomeInputObjectType, ] for member_type in bad_union_member_types: # invalid union type cannot be built with Python bad_union = GraphQLUnionType( "BadUnion", types=[member_type] # type: ignore ) with raises(TypeError) as exc_info: schema_with_field_type(bad_union) assert str(exc_info.value) == ( "BadUnion types must be specified" " as a collection of GraphQLObjectType instances." ) # noinspection PyPropertyAccess bad_union.types = [] bad_schema = schema_with_field_type(bad_union) # noinspection PyPropertyAccess bad_union.types = [member_type] assert validate_schema(bad_schema) == [ { "message": "Union type BadUnion can only include Object types," + f" it cannot include {inspect(member_type)}." } ] def describe_type_system_input_objects_must_have_fields(): def accepts_an_input_object_type_with_fields(): schema = build_schema( """ type Query { field(arg: SomeInputObject): String } input SomeInputObject { field: String } """ ) assert validate_schema(schema) == [] def rejects_an_input_object_type_with_missing_fields(): schema = build_schema( """ type Query { field(arg: SomeInputObject): String } input SomeInputObject """ ) schema = extend_schema( schema, parse( """ directive @test on INPUT_OBJECT extend input SomeInputObject @test """ ), ) assert validate_schema(schema) == [ { "message": "Input Object type SomeInputObject" " must define one or more fields.", "locations": [(6, 13), (4, 17)], } ] def accepts_an_input_object_with_breakable_circular_reference(): schema = build_schema( """ type Query { field(arg: SomeInputObject): String } input SomeInputObject { self: SomeInputObject arrayOfSelf: [SomeInputObject] nonNullArrayOfSelf: [SomeInputObject]! nonNullArrayOfNonNullSelf: [SomeInputObject!]! intermediateSelf: AnotherInputObject } input AnotherInputObject { parent: SomeInputObject } """ ) assert validate_schema(schema) == [] def rejects_an_input_object_with_non_breakable_circular_reference(): schema = build_schema( """ type Query { field(arg: SomeInputObject): String } input SomeInputObject { startLoop: AnotherInputObject! } input AnotherInputObject { nextInLoop: YetAnotherInputObject! } input YetAnotherInputObject { closeLoop: SomeInputObject! } """ ) assert validate_schema(schema) == [ { "message": "Cannot reference Input Object 'SomeInputObject'" " within itself through a series of non-null fields:" " 'startLoop.nextInLoop.closeLoop'.", "locations": [(7, 15), (11, 15), (15, 15)], } ] def rejects_an_input_object_with_multiple_non_breakable_circular_reference(): schema = build_schema( """ type Query { field(arg: SomeInputObject): String } input SomeInputObject { startLoop: AnotherInputObject! } input AnotherInputObject { closeLoop: SomeInputObject! startSecondLoop: YetAnotherInputObject! } input YetAnotherInputObject { closeSecondLoop: AnotherInputObject! nonNullSelf: YetAnotherInputObject! } """ ) assert validate_schema(schema) == [ { "message": "Cannot reference Input Object 'SomeInputObject'" " within itself through a series of non-null fields:" " 'startLoop.closeLoop'.", "locations": [(7, 15), (11, 15)], }, { "message": "Cannot reference Input Object 'AnotherInputObject'" " within itself through a series of non-null fields:" " 'startSecondLoop.closeSecondLoop'.", "locations": [(12, 15), (16, 15)], }, { "message": "Cannot reference Input Object 'YetAnotherInputObject'" " within itself through a series of non-null fields:" " 'nonNullSelf'.", "locations": [(17, 15)], }, ] def rejects_an_input_object_type_with_incorrectly_typed_fields(): # invalid schema cannot be built with Python with raises(TypeError) as exc_info: build_schema( """ type Query { field(arg: SomeInputObject): String } type SomeObject { field: String } union SomeUnion = SomeObject input SomeInputObject { badObject: SomeObject badUnion: SomeUnion goodInputObject: SomeInputObject } """ ) assert str(exc_info.value) == ( "SomeInputObject fields cannot be resolved." " Input field type must be a GraphQL input type." ) # construct invalid schema manually schema = build_schema( """ type Query { field(arg: SomeInputObject): String } type SomeObject { field: String } union SomeUnion = SomeObject input SomeInputObject { badObject: SomeInputObject badUnion: SomeInputObject goodInputObject: SomeInputObject } """ ) some_input_obj: Any = schema.get_type("SomeInputObject") some_input_obj.fields["badObject"].type = schema.get_type("SomeObject") some_input_obj.fields["badUnion"].type = schema.get_type("SomeUnion") assert validate_schema(schema) == [ { "message": "The type of SomeInputObject.badObject must be Input Type" " but got: SomeObject.", "locations": [(13, 26)], }, { "message": "The type of SomeInputObject.badUnion must be Input Type" " but got: SomeUnion.", "locations": [(14, 25)], }, ] def rejects_an_input_object_type_with_required_arguments_that_is_deprecated(): schema = build_schema( """ type Query { field(arg: SomeInputObject): String } input SomeInputObject { badField: String! @deprecated optionalField: String @deprecated anotherOptionalField: String! = "" @deprecated } """ ) assert validate_schema(schema) == [ { "message": "Required input field SomeInputObject.badField" " cannot be deprecated.", "locations": [(7, 33), (7, 25)], } ] def describe_type_system_enum_types_must_be_well_defined(): def rejects_an_enum_type_without_values(): schema = build_schema( """ type Query { field: SomeEnum } enum SomeEnum """ ) schema = extend_schema( schema, parse( """ directive @test on ENUM extend enum SomeEnum @test """ ), ) assert validate_schema(schema) == [ { "message": "Enum type SomeEnum must define one or more values.", "locations": [(6, 13), (4, 17)], } ] def rejects_an_enum_type_with_incorrectly_named_values(): schema = schema_with_field_type( GraphQLEnumType("SomeEnum", values={"__badName": {}}) ) assert validate_schema(schema) == [ { "message": "Name '__badName' must not begin with '__'," " which is reserved by GraphQL introspection." } ] def describe_type_system_object_fields_must_have_output_types(): def _schema_with_object_field(type_: GraphQLOutputType) -> GraphQLSchema: if is_output_type(type_): field = GraphQLField(type_) else: # invalid field cannot be built with Python directly with raises(TypeError) as exc_info: GraphQLField(type_) assert str(exc_info.value) == "Field type must be an output type." # therefore we need to monkey-patch a valid field field = GraphQLField(GraphQLString) field.type = type_ bad_object_type = GraphQLObjectType("BadObject", {"badField": field}) return GraphQLSchema( GraphQLObjectType("Query", {"f": GraphQLField(bad_object_type)}), types=[SomeObjectType], ) @mark.parametrize("type_", output_types, ids=get_name) def accepts_an_output_type_as_an_object_field_type(type_): schema = _schema_with_object_field(type_) assert validate_schema(schema) == [] def rejects_an_empty_object_field_type(): # noinspection PyTypeChecker schema = _schema_with_object_field(None) # type: ignore assert validate_schema(schema) == [ { "message": "The type of BadObject.badField must be Output Type" " but got: None." } ] @mark.parametrize("type_", not_output_types, ids=get_name) def rejects_a_non_output_type_as_an_object_field_type(type_): schema = _schema_with_object_field(type_) assert validate_schema(schema) == [ { "message": "The type of BadObject.badField must be Output Type" f" but got: {type_}." } ] @mark.parametrize("type_", not_graphql_types, ids=get_name) def rejects_a_non_type_value_as_an_object_field_type(type_): schema = _schema_with_object_field(type_) assert validate_schema(schema) == [ { "message": "The type of BadObject.badField must be Output Type" f" but got: {inspect(type_)}.", }, {"message": f"Expected GraphQL named type but got: {inspect(type_)}."}, ] def rejects_with_relevant_locations_for_a_non_output_type(): # invalid schema cannot be built with Python with raises(TypeError) as exc_info: build_schema( """ type Query { field: [SomeInputObject] } input SomeInputObject { field: String } """ ) assert str(exc_info.value) == ( "Query fields cannot be resolved. Field type must be an output type." ) # therefore we need to monkey-patch a valid schema schema = build_schema( """ type Query { field: [String] } input SomeInputObject { field: String } """ ) some_input_obj = schema.get_type("SomeInputObject") schema.query_type.fields["field"].type.of_type = some_input_obj # type: ignore assert validate_schema(schema) == [ { "message": "The type of Query.field must be Output Type" " but got: [SomeInputObject].", "locations": [(3, 22)], } ] def describe_type_system_objects_can_only_implement_unique_interfaces(): def rejects_an_object_implementing_a_non_type_value(): query_type = GraphQLObjectType( "BadObject", {"f": GraphQLField(GraphQLString)}, ) # noinspection PyTypeChecker query_type.interfaces = (None,) schema = GraphQLSchema(query_type) assert validate_schema(schema) == [ { "message": "Type BadObject must only implement Interface types," " it cannot implement None." } ] def rejects_an_object_implementing_a_non_interface_type(): # invalid schema cannot be built with Python with raises(TypeError) as exc_info: build_schema( """ type Query { test: BadObject } input SomeInputObject { field: String } type BadObject implements SomeInputObject { field: String } """ ) assert str(exc_info.value) == ( "BadObject interfaces must be specified" " as a collection of GraphQLInterfaceType instances." ) def rejects_an_object_implementing_the_same_interface_twice(): schema = build_schema( """ type Query { test: AnotherObject } interface AnotherInterface { field: String } type AnotherObject implements AnotherInterface & AnotherInterface { field: String } """ ) assert validate_schema(schema) == [ { "message": "Type AnotherObject can only implement" " AnotherInterface once.", "locations": [(10, 43), (10, 62)], } ] def rejects_an_object_implementing_same_interface_twice_due_to_extension(): schema = build_schema( """ type Query { test: AnotherObject } interface AnotherInterface { field: String } type AnotherObject implements AnotherInterface { field: String } """ ) extended_schema = extend_schema( schema, parse("extend type AnotherObject implements AnotherInterface") ) assert validate_schema(extended_schema) == [ { "message": "Type AnotherObject can only implement" " AnotherInterface once.", "locations": [(10, 43), (1, 38)], } ] def describe_type_system_interface_extensions_should_be_valid(): def rejects_object_implementing_extended_interface_due_to_missing_field(): schema = build_schema( """ type Query { test: AnotherObject } interface AnotherInterface { field: String } type AnotherObject implements AnotherInterface { field: String } """ ) extended_schema = extend_schema( schema, parse( """ extend interface AnotherInterface { newField: String } extend type AnotherObject { differentNewField: String } """ ), ) assert validate_schema(extended_schema) == [ { "message": "Interface field AnotherInterface.newField expected" " but AnotherObject does not provide it.", "locations": [(3, 19), (10, 13), (6, 17)], } ] def rejects_object_implementing_extended_interface_due_to_missing_args(): schema = build_schema( """ type Query { test: AnotherObject } interface AnotherInterface { field: String } type AnotherObject implements AnotherInterface { field: String } """ ) extended_schema = extend_schema( schema, parse( """ extend interface AnotherInterface { newField(test: Boolean): String } extend type AnotherObject { newField: String } """ ), ) assert validate_schema(extended_schema) == [ { "message": "Interface field argument" " AnotherInterface.newField(test:) expected" " but AnotherObject.newField does not provide it.", "locations": [(3, 28), (7, 19)], } ] def rejects_object_implementing_extended_interface_due_to_type_mismatch(): schema = build_schema( """ type Query { test: AnotherObject } interface AnotherInterface { field: String } type AnotherObject implements AnotherInterface { field: String } """ ) extended_schema = extend_schema( schema, parse( """ extend interface AnotherInterface { newInterfaceField: NewInterface } interface NewInterface { newField: String } interface MismatchingInterface { newField: String } extend type AnotherObject { newInterfaceField: MismatchingInterface } # Required to prevent unused interface errors type DummyObject implements NewInterface & MismatchingInterface { newField: String } """ ), ) assert validate_schema(extended_schema) == [ { "message": "Interface field AnotherInterface.newInterfaceField" " expects type NewInterface" " but AnotherObject.newInterfaceField" " is type MismatchingInterface.", "locations": [(3, 38), (15, 38)], } ] def describe_type_system_interface_fields_must_have_output_types(): def _schema_with_interface_field(type_: GraphQLOutputType) -> GraphQLSchema: if is_output_type(type_): field = GraphQLField(type_) else: # invalid field cannot be built with Python directly with raises(TypeError) as exc_info: GraphQLField(type_) assert str(exc_info.value) == "Field type must be an output type." # therefore we need to monkey-patch a valid field field = GraphQLField(GraphQLString) field.type = type_ fields = {"badField": field} bad_interface_type = GraphQLInterfaceType("BadInterface", fields) bad_implementing_type = GraphQLObjectType( "BadImplementing", fields, interfaces=[bad_interface_type], ) return GraphQLSchema( GraphQLObjectType("Query", {"f": GraphQLField(bad_interface_type)}), types=[bad_implementing_type, SomeObjectType], ) @mark.parametrize("type_", output_types, ids=get_name) def accepts_an_output_type_as_an_interface_field_type(type_): schema = _schema_with_interface_field(type_) assert validate_schema(schema) == [] def rejects_an_empty_interface_field_type(): # noinspection PyTypeChecker schema = _schema_with_interface_field(None) # type: ignore assert validate_schema(schema) == [ { "message": "The type of BadImplementing.badField must be Output Type" " but got: None.", }, { "message": "The type of BadInterface.badField must be Output Type" " but got: None.", }, ] @mark.parametrize("type_", not_output_types, ids=get_name) def rejects_a_non_output_type_as_an_interface_field_type(type_): schema = _schema_with_interface_field(type_) assert validate_schema(schema) == [ { "message": "The type of BadImplementing.badField must be Output Type" f" but got: {type_}.", }, { "message": "The type of BadInterface.badField must be Output Type" f" but got: {type_}.", }, ] @mark.parametrize("type_", not_graphql_types, ids=get_name) def rejects_a_non_type_value_as_an_interface_field_type(type_): schema = _schema_with_interface_field(type_) assert validate_schema(schema) == [ { "message": "The type of BadImplementing.badField must be Output Type" f" but got: {inspect(type_)}.", }, { "message": "The type of BadInterface.badField must be Output Type" f" but got: {inspect(type_)}.", }, {"message": f"Expected GraphQL named type but got: {inspect(type_)}."}, ] def rejects_a_non_output_type_as_an_interface_field_with_locations(): # invalid schema cannot be built with Python with raises(TypeError) as exc_info: build_schema( """ type Query { test: SomeInterface } interface SomeInterface { field: SomeInputObject } input SomeInputObject { foo: String } type SomeObject implements SomeInterface { field: SomeInputObject } """ ) assert str(exc_info.value) == ( "SomeInterface fields cannot be resolved." " Field type must be an output type." ) # therefore we need to monkey-patch a valid schema schema = build_schema( """ type Query { test: SomeInterface } interface SomeInterface { field: String } input SomeInputObject { foo: String } type SomeObject implements SomeInterface { field: String } """ ) # therefore we need to monkey-patch a valid schema some_input_obj = schema.get_type("SomeInputObject") some_interface: Any = schema.get_type("SomeInterface") some_interface.fields["field"].type = some_input_obj some_object: Any = schema.get_type("SomeObject") some_object.fields["field"].type = some_input_obj assert validate_schema(schema) == [ { "message": "The type of SomeInterface.field must be Output Type" " but got: SomeInputObject.", "locations": [(7, 22)], }, { "message": "The type of SomeObject.field must be Output Type" " but got: SomeInputObject.", "locations": [(15, 22)], }, ] def accepts_an_interface_not_implemented_by_at_least_one_object(): schema = build_schema( """ type Query { test: SomeInterface } interface SomeInterface { foo: String } """ ) assert validate_schema(schema) == [] def describe_type_system_arguments_must_have_input_types(): def _schema_with_arg(type_: GraphQLInputType) -> GraphQLSchema: if is_input_type(type_): argument = GraphQLArgument(type_) else: # invalid argument cannot be built with Python directly with raises(TypeError) as exc_info: GraphQLArgument(type_) assert str(exc_info.value) == "Argument type must be a GraphQL input type." # therefore we need to monkey-patch a valid argument argument = GraphQLArgument(GraphQLString) argument.type = type_ args = {"badArg": argument} bad_object_type = GraphQLObjectType( "BadObject", {"badField": GraphQLField(GraphQLString, args)}, ) return GraphQLSchema( GraphQLObjectType("Query", {"f": GraphQLField(bad_object_type)}), directives=[ GraphQLDirective( "BadDirective", [DirectiveLocation.QUERY], args, ) ], ) @mark.parametrize("type_", input_types, ids=get_name) def accepts_an_input_type_as_a_field_arg_type(type_): schema = _schema_with_arg(type_) assert validate_schema(schema) == [] def rejects_an_empty_field_arg_type(): # noinspection PyTypeChecker schema = _schema_with_arg(None) # type: ignore assert validate_schema(schema) == [ { "message": "The type of @BadDirective(badArg:) must be Input Type" " but got: None." }, { "message": "The type of BadObject.badField(badArg:) must be Input Type" " but got: None." }, ] @mark.parametrize("type_", not_input_types, ids=get_name) def rejects_a_non_input_type_as_a_field_arg_type(type_): schema = _schema_with_arg(type_) assert validate_schema(schema) == [ { "message": "The type of @BadDirective(badArg:) must be Input Type" f" but got: {type_}." }, { "message": "The type of BadObject.badField(badArg:) must be Input Type" f" but got: {type_}." }, ] @mark.parametrize("type_", not_graphql_types, ids=get_name) def rejects_a_non_type_value_as_a_field_arg_type(type_): schema = _schema_with_arg(type_) assert validate_schema(schema) == [ { "message": "The type of @BadDirective(badArg:) must be Input Type" f" but got: {inspect(type_)}." }, { "message": "The type of BadObject.badField(badArg:) must be Input Type" f" but got: {inspect(type_)}." }, {"message": f"Expected GraphQL named type but got: {inspect(type_)}."}, ] def rejects_a_required_argument_that_is_deprecated(): schema = build_schema( """ directive @BadDirective( badArg: String! @deprecated optionalArg: String @deprecated anotherOptionalArg: String! = "" @deprecated ) on FIELD type Query { test( badArg: String! @deprecated optionalArg: String @deprecated anotherOptionalArg: String! = "" @deprecated ): String } """ ) assert validate_schema(schema) == [ { "message": "Required argument @BadDirective(badArg:)" " cannot be deprecated.", "locations": [(3, 31), (3, 23)], }, { "message": "Required argument Query.test(badArg:)" " cannot be deprecated.", "locations": [(10, 33), (10, 25)], }, ] def rejects_a_non_input_type_as_a_field_arg_with_locations(): # invalid schema cannot be built with Python with raises(TypeError) as exc_info: build_schema( """ type Query { test(arg: SomeObject): String } type SomeObject { foo: String } """ ) assert str(exc_info.value) == ( "Query fields cannot be resolved." " Argument type must be a GraphQL input type." ) # therefore we need to monkey-patch a valid schema schema = build_schema( """ type Query { test(arg: String): String } type SomeObject { foo: String } """ ) some_object = schema.get_type("SomeObject") schema.query_type.fields["test"].args["arg"].type = some_object # type: ignore assert validate_schema(schema) == [ { "message": "The type of Query.test(arg:) must be Input Type" " but got: SomeObject.", "locations": [(3, 25)], }, ] def describe_type_system_input_object_fields_must_have_input_types(): def _schema_with_input_field(type_: GraphQLInputType) -> GraphQLSchema: if is_input_type(type_): input_field = GraphQLInputField(type_) else: # invalid input field cannot be built with Python directly with raises(TypeError) as exc_info: GraphQLInputField(type_) assert str(exc_info.value) == ( "Input field type must be a GraphQL input type." ) # therefore we need to monkey-patch a valid input field input_field = GraphQLInputField(GraphQLString) input_field.type = type_ bad_input_object_type = GraphQLInputObjectType( "BadInputObject", {"badField": input_field} ) return GraphQLSchema( GraphQLObjectType( "Query", { "f": GraphQLField( GraphQLString, args={"badArg": GraphQLArgument(bad_input_object_type)}, ) }, ) ) @mark.parametrize("type_", input_types, ids=get_name) def accepts_an_input_type_as_an_input_field_type(type_): schema = _schema_with_input_field(type_) assert validate_schema(schema) == [] def rejects_an_empty_input_field_type(): # noinspection PyTypeChecker schema = _schema_with_input_field(None) # type: ignore assert validate_schema(schema) == [ { "message": "The type of BadInputObject.badField must be Input Type" " but got: None." } ] @mark.parametrize("type_", not_input_types, ids=get_name) def rejects_a_non_input_type_as_an_input_field_type(type_): schema = _schema_with_input_field(type_) assert validate_schema(schema) == [ { "message": "The type of BadInputObject.badField must be Input Type" f" but got: {type_}." } ] @mark.parametrize("type_", not_graphql_types, ids=get_name) def rejects_a_non_type_value_as_an_input_field_type(type_): schema = _schema_with_input_field(type_) assert validate_schema(schema) == [ { "message": "The type of BadInputObject.badField must be Input Type" f" but got: {inspect(type_)}." }, {"message": f"Expected GraphQL named type but got: {inspect(type_)}."}, ] def rejects_with_relevant_locations_for_a_non_input_type(): # invalid schema cannot be built with Python with raises(TypeError) as exc_info: build_schema( """ type Query { test(arg: SomeInputObject): String } input SomeInputObject { foo: SomeObject } type SomeObject { bar: String } """ ) assert str(exc_info.value) == ( "SomeInputObject fields cannot be resolved." " Input field type must be a GraphQL input type." ) # therefore we need to monkey-patch a valid schema schema = build_schema( """ type Query { test(arg: SomeInputObject): String } input SomeInputObject { foo: String } type SomeObject { bar: String } """ ) some_object = schema.get_type("SomeObject") some_input_object: Any = schema.get_type("SomeInputObject") some_input_object.fields["foo"].type = some_object assert validate_schema(schema) == [ { "message": "The type of SomeInputObject.foo must be Input Type" " but got: SomeObject.", "locations": [(7, 20)], } ] def describe_objects_must_adhere_to_interfaces_they_implement(): def accepts_an_object_which_implements_an_interface(): schema = build_schema( """ type Query { test: AnotherObject } interface AnotherInterface { field(input: String): String } type AnotherObject implements AnotherInterface { field(input: String): String } """ ) assert validate_schema(schema) == [] def accepts_an_object_which_implements_an_interface_and_with_more_fields(): schema = build_schema( """ type Query { test: AnotherObject } interface AnotherInterface { field(input: String): String } type AnotherObject implements AnotherInterface { field(input: String): String anotherField: String } """ ) assert validate_schema(schema) == [] def accepts_an_object_which_implements_an_interface_field_with_more_args(): schema = build_schema( """ type Query { test: AnotherObject } interface AnotherInterface { field(input: String): String } type AnotherObject implements AnotherInterface { field(input: String, anotherInput: String): String } """ ) assert validate_schema(schema) == [] def rejects_an_object_missing_an_interface_field(): schema = build_schema( """ type Query { test: AnotherObject } interface AnotherInterface { field(input: String): String } type AnotherObject implements AnotherInterface { anotherField: String } """ ) assert validate_schema(schema) == [ { "message": "Interface field AnotherInterface.field expected but" " AnotherObject does not provide it.", "locations": [(7, 15), (10, 13)], } ] def rejects_an_object_with_an_incorrectly_typed_interface_field(): schema = build_schema( """ type Query { test: AnotherObject } interface AnotherInterface { field(input: String): String } type AnotherObject implements AnotherInterface { field(input: String): Int } """ ) assert validate_schema(schema) == [ { "message": "Interface field AnotherInterface.field" " expects type String but" " AnotherObject.field is type Int.", "locations": [(7, 37), (11, 37)], } ] def rejects_an_object_with_a_differently_typed_interface_field(): schema = build_schema( """ type Query { test: AnotherObject } type A { foo: String } type B { foo: String } interface AnotherInterface { field: A } type AnotherObject implements AnotherInterface { field: B } """ ) assert validate_schema(schema) == [ { "message": "Interface field AnotherInterface.field" " expects type A but AnotherObject.field is type B.", "locations": [(10, 22), (14, 22)], } ] def accepts_an_object_with_a_subtyped_interface_field_interface(): schema = build_schema( """ type Query { test: AnotherObject } interface AnotherInterface { field: AnotherInterface } type AnotherObject implements AnotherInterface { field: AnotherObject } """ ) assert validate_schema(schema) == [] def accepts_an_object_with_a_subtyped_interface_field_union(): schema = build_schema( """ type Query { test: AnotherObject } type SomeObject { field: String } union SomeUnionType = SomeObject interface AnotherInterface { field: SomeUnionType } type AnotherObject implements AnotherInterface { field: SomeObject } """ ) assert validate_schema(schema) == [] def rejects_an_object_missing_an_interface_argument(): schema = build_schema( """ type Query { test: AnotherObject } interface AnotherInterface { field(input: String): String } type AnotherObject implements AnotherInterface { field: String } """ ) assert validate_schema(schema) == [ { "message": "Interface field argument" " AnotherInterface.field(input:) expected" " but AnotherObject.field does not provide it.", "locations": [(7, 21), (11, 15)], } ] def rejects_an_object_with_an_incorrectly_typed_interface_argument(): schema = build_schema( """ type Query { test: AnotherObject } interface AnotherInterface { field(input: String): String } type AnotherObject implements AnotherInterface { field(input: Int): String } """ ) assert validate_schema(schema) == [ { "message": "Interface field argument" " AnotherInterface.field(input:) expects type String" " but AnotherObject.field(input:) is type Int.", "locations": [(7, 28), (11, 28)], } ] def rejects_an_object_with_an_incorrectly_typed_field_and_argument(): schema = build_schema( """ type Query { test: AnotherObject } interface AnotherInterface { field(input: String): String } type AnotherObject implements AnotherInterface { field(input: Int): Int } """ ) assert validate_schema(schema) == [ { "message": "Interface field AnotherInterface.field expects" " type String but AnotherObject.field is type Int.", "locations": [(7, 37), (11, 34)], }, { "message": "Interface field argument" " AnotherInterface.field(input:) expects type String" " but AnotherObject.field(input:) is type Int.", "locations": [(7, 28), (11, 28)], }, ] def rejects_object_implementing_an_interface_field_with_additional_args(): schema = build_schema( """ type Query { test: AnotherObject } interface AnotherInterface { field(baseArg: String): String } type AnotherObject implements AnotherInterface { field( baseArg: String, requiredArg: String! optionalArg1: String, optionalArg2: String = "", ): String } """ ) assert validate_schema(schema) == [ { "message": "Object field AnotherObject.field includes required" " argument requiredArg that is missing from the" " Interface field AnotherInterface.field.", "locations": [(13, 17), (7, 15)], } ] def accepts_an_object_with_an_equivalently_wrapped_interface_field_type(): schema = build_schema( """ type Query { test: AnotherObject } interface AnotherInterface { field: [String]! } type AnotherObject implements AnotherInterface { field: [String]! } """ ) assert validate_schema(schema) == [] def rejects_an_object_with_a_non_list_interface_field_list_type(): schema = build_schema( """ type Query { test: AnotherObject } interface AnotherInterface { field: [String] } type AnotherObject implements AnotherInterface { field: String } """ ) assert validate_schema(schema) == [ { "message": "Interface field AnotherInterface.field expects type" " [String] but AnotherObject.field is type String.", "locations": [(7, 22), (11, 22)], } ] def rejects_an_object_with_a_list_interface_field_non_list_type(): schema = build_schema( """ type Query { test: AnotherObject } interface AnotherInterface { field: String } type AnotherObject implements AnotherInterface { field: [String] } """ ) assert validate_schema(schema) == [ { "message": "Interface field AnotherInterface.field expects type" " String but AnotherObject.field is type [String].", "locations": [(7, 22), (11, 22)], } ] def accepts_an_object_with_a_subset_non_null_interface_field_type(): schema = build_schema( """ type Query { test: AnotherObject } interface AnotherInterface { field: String } type AnotherObject implements AnotherInterface { field: String! } """ ) assert validate_schema(schema) == [] def rejects_an_object_with_a_superset_nullable_interface_field_type(): schema = build_schema( """ type Query { test: AnotherObject } interface AnotherInterface { field: String! } type AnotherObject implements AnotherInterface { field: String } """ ) assert validate_schema(schema) == [ { "message": "Interface field AnotherInterface.field expects type" " String! but AnotherObject.field is type String.", "locations": [(7, 22), (11, 22)], } ] def rejects_an_object_missing_a_transitive_interface(): schema = build_schema( """ type Query { test: AnotherObject } interface SuperInterface { field: String! } interface AnotherInterface implements SuperInterface { field: String! } type AnotherObject implements AnotherInterface { field: String! } """ ) assert validate_schema(schema) == [ { "message": "Type AnotherObject must implement SuperInterface" " because it is implemented by AnotherInterface.", "locations": [(10, 51), (14, 43)], } ] def describe_interfaces_must_adhere_to_interface_they_implement(): def accepts_an_interface_which_implements_an_interface(): schema = build_schema( """ type Query { test: ChildInterface } interface ParentInterface { field(input: String): String } interface ChildInterface implements ParentInterface { field(input: String): String } """ ) assert validate_schema(schema) == [] def accepts_an_interface_which_implements_an_interface_along_with_more_fields(): schema = build_schema( """ type Query { test: ChildInterface } interface ParentInterface { field(input: String): String } interface ChildInterface implements ParentInterface { field(input: String): String anotherField: String } """ ) assert validate_schema(schema) == [] def accepts_an_interface_which_implements_an_interface_with_additional_args(): schema = build_schema( """ type Query { test: ChildInterface } interface ParentInterface { field(input: String): String } interface ChildInterface implements ParentInterface { field(input: String, anotherInput: String): String } """ ) assert validate_schema(schema) == [] def rejects_an_interface_missing_an_interface_field(): schema = build_schema( """ type Query { test: ChildInterface } interface ParentInterface { field(input: String): String } interface ChildInterface implements ParentInterface { anotherField: String } """ ) assert validate_schema(schema) == [ { "message": "Interface field ParentInterface.field expected" " but ChildInterface does not provide it.", "locations": [(7, 15), (10, 13)], } ] def rejects_an_interface_with_an_incorrectly_typed_interface_field(): schema = build_schema( """ type Query { test: ChildInterface } interface ParentInterface { field(input: String): String } interface ChildInterface implements ParentInterface { field(input: String): Int } """ ) assert validate_schema(schema) == [ { "message": "Interface field ParentInterface.field expects type String" " but ChildInterface.field is type Int.", "locations": [(7, 37), (11, 37)], } ] def rejects_an_interface_with_a_differently_typed_interface_field(): schema = build_schema( """ type Query { test: ChildInterface } type A { foo: String } type B { foo: String } interface ParentInterface { field: A } interface ChildInterface implements ParentInterface { field: B } """ ) assert validate_schema(schema) == [ { "message": "Interface field ParentInterface.field expects type A" " but ChildInterface.field is type B.", "locations": [(10, 22), (14, 22)], } ] def accepts_an_interface_with_a_subtyped_interface_field_interface(): schema = build_schema( """ type Query { test: ChildInterface } interface ParentInterface { field: ParentInterface } interface ChildInterface implements ParentInterface { field: ChildInterface } """ ) assert validate_schema(schema) == [] def accepts_an_interface_with_a_subtyped_interface_field_union(): schema = build_schema( """ type Query { test: ChildInterface } type SomeObject { field: String } union SomeUnionType = SomeObject interface ParentInterface { field: SomeUnionType } interface ChildInterface implements ParentInterface { field: SomeObject } """ ) assert validate_schema(schema) == [] def rejects_an_interface_implementing_a_non_interface_type(): # invalid schema cannot be built with Python with raises(TypeError) as exc_info: build_schema( """ type Query { field: String } input SomeInputObject { field: String } interface BadInterface implements SomeInputObject { field: String } """ ) assert str(exc_info.value) == ( "BadInterface interfaces must be specified as a collection" " of GraphQLInterfaceType instances." ) # therefore we construct the invalid schema manually some_input_obj = GraphQLInputObjectType( "SomeInputObject", {"field": GraphQLInputField(GraphQLString)} ) bad_interface = GraphQLInterfaceType( "BadInterface", {"field": GraphQLField(GraphQLString)} ) # noinspection PyTypeChecker bad_interface.interfaces = (some_input_obj,) schema = GraphQLSchema( GraphQLObjectType("Query", {"field": GraphQLField(GraphQLString)}), types=[bad_interface], ) assert validate_schema(schema) == [ { "message": "Type BadInterface must only implement Interface types," " it cannot implement SomeInputObject.", } ] def rejects_an_interface_missing_an_interface_argument(): schema = build_schema( """ type Query { test: ChildInterface } interface ParentInterface { field(input: String): String } interface ChildInterface implements ParentInterface { field: String } """ ) assert validate_schema(schema) == [ { "message": "Interface field argument ParentInterface.field(input:)" " expected but ChildInterface.field does not provide it.", "locations": [(7, 21), (11, 15)], } ] def rejects_an_interface_with_an_incorrectly_typed_interface_argument(): schema = build_schema( """ type Query { test: ChildInterface } interface ParentInterface { field(input: String): String } interface ChildInterface implements ParentInterface { field(input: Int): String } """ ) assert validate_schema(schema) == [ { "message": "Interface field argument ParentInterface.field(input:)" " expects type String but ChildInterface.field(input:) is type Int.", "locations": [(7, 28), (11, 28)], } ] def rejects_an_interface_with_both_an_incorrectly_typed_field_and_argument(): schema = build_schema( """ type Query { test: ChildInterface } interface ParentInterface { field(input: String): String } interface ChildInterface implements ParentInterface { field(input: Int): Int } """ ) assert validate_schema(schema) == [ { "message": "Interface field ParentInterface.field expects type String" " but ChildInterface.field is type Int.", "locations": [(7, 37), (11, 34)], }, { "message": "Interface field argument ParentInterface.field(input:)" " expects type String but ChildInterface.field(input:) is type Int.", "locations": [(7, 28), (11, 28)], }, ] def rejects_an_interface_implementing_an_interface_field_with_additional_args(): schema = build_schema( """ type Query { test: ChildInterface } interface ParentInterface { field(baseArg: String): String } interface ChildInterface implements ParentInterface { field( baseArg: String, requiredArg: String! optionalArg1: String, optionalArg2: String = "", ): String } """ ) assert validate_schema(schema) == [ { "message": "Object field ChildInterface.field includes" " required argument requiredArg that is missing" " from the Interface field ParentInterface.field.", "locations": [(13, 17), (7, 15)], } ] def accepts_an_interface_with_an_equivalently_wrapped_interface_field_type(): schema = build_schema( """ type Query { test: ChildInterface } interface ParentInterface { field: [String]! } interface ChildInterface implements ParentInterface { field: [String]! } """ ) assert validate_schema(schema) == [] def rejects_an_interface_with_a_non_list_interface_field_list_type(): schema = build_schema( """ type Query { test: ChildInterface } interface ParentInterface { field: [String] } interface ChildInterface implements ParentInterface { field: String } """ ) assert validate_schema(schema) == [ { "message": "Interface field ParentInterface.field" " expects type [String] but ChildInterface.field is type String.", "locations": [(7, 22), (11, 22)], } ] def rejects_an_interface_with_a_list_interface_field_non_list_type(): schema = build_schema( """ type Query { test: ChildInterface } interface ParentInterface { field: String } interface ChildInterface implements ParentInterface { field: [String] } """ ) assert validate_schema(schema) == [ { "message": "Interface field ParentInterface.field expects type String" " but ChildInterface.field is type [String].", "locations": [(7, 22), (11, 22)], } ] def accepts_an_interface_with_a_subset_non_null_interface_field_type(): schema = build_schema( """ type Query { test: ChildInterface } interface ParentInterface { field: String } interface ChildInterface implements ParentInterface { field: String! } """ ) assert validate_schema(schema) == [] def rejects_an_interface_with_a_superset_nullable_interface_field_type(): schema = build_schema( """ type Query { test: ChildInterface } interface ParentInterface { field: String! } interface ChildInterface implements ParentInterface { field: String } """ ) assert validate_schema(schema) == [ { "message": "Interface field ParentInterface.field expects type String!" " but ChildInterface.field is type String.", "locations": [(7, 22), (11, 22)], } ] def rejects_an_object_missing_a_transitive_interface(): schema = build_schema( """ type Query { test: ChildInterface } interface SuperInterface { field: String! } interface ParentInterface implements SuperInterface { field: String! } interface ChildInterface implements ParentInterface { field: String! } """ ) assert validate_schema(schema) == [ { "message": "Type ChildInterface must implement SuperInterface" " because it is implemented by ParentInterface.", "locations": [(10, 50), (14, 49)], } ] def rejects_a_self_reference_interface(): schema = build_schema( """ type Query { test: FooInterface } interface FooInterface implements FooInterface { field: String } """ ) assert validate_schema(schema) == [ { "message": "Type FooInterface cannot implement itself" " because it would create a circular reference.", "locations": [(6, 47)], } ] def rejects_a_circular_interface_implementation(): schema = build_schema( """ type Query { test: FooInterface } interface FooInterface implements BarInterface { field: String } interface BarInterface implements FooInterface { field: String } """ ) assert validate_schema(schema) == [ { "message": "Type FooInterface cannot implement BarInterface" " because it would create a circular reference.", "locations": [(10, 47), (6, 47)], }, { "message": "Type BarInterface cannot implement FooInterface" " because it would create a circular reference.", "locations": [(6, 47), (10, 47)], }, ] def describe_assert_valid_schema(): def does_not_throw_on_valid_schemas(): schema = build_schema( ( """ type Query { foo: String } """ ) ) assert_valid_schema(schema) def combines_multiple_errors(): schema = build_schema("type SomeType") with raises(TypeError) as exc_info: assert_valid_schema(schema) assert ( str(exc_info.value) == dedent( """ Query root type must be provided. Type SomeType must define one or more fields. """ ).rstrip() ) graphql-core-3.2.6/tests/utilities/000077500000000000000000000000001474546154300173005ustar00rootroot00000000000000graphql-core-3.2.6/tests/utilities/__init__.py000066400000000000000000000000421474546154300214050ustar00rootroot00000000000000"""Tests for graphql.utilities""" graphql-core-3.2.6/tests/utilities/test_ast_from_value.py000066400000000000000000000223051474546154300237210ustar00rootroot00000000000000from math import inf, nan from pytest import raises from graphql.error import GraphQLError from graphql.language import ( BooleanValueNode, EnumValueNode, FloatValueNode, IntValueNode, ListValueNode, NameNode, NullValueNode, ObjectFieldNode, ObjectValueNode, StringValueNode, ) from graphql.pyutils import Undefined from graphql.type import ( GraphQLBoolean, GraphQLEnumType, GraphQLFloat, GraphQLID, GraphQLInputField, GraphQLInputObjectType, GraphQLInt, GraphQLList, GraphQLNonNull, GraphQLScalarType, GraphQLString, ) from graphql.utilities import ast_from_value def describe_ast_from_value(): def converts_boolean_values_to_asts(): assert ast_from_value(True, GraphQLBoolean) == BooleanValueNode(value=True) assert ast_from_value(False, GraphQLBoolean) == BooleanValueNode(value=False) assert ast_from_value(Undefined, GraphQLBoolean) is None assert ast_from_value(None, GraphQLBoolean) == NullValueNode() assert ast_from_value(0, GraphQLBoolean) == BooleanValueNode(value=False) assert ast_from_value(1, GraphQLBoolean) == BooleanValueNode(value=True) non_null_boolean = GraphQLNonNull(GraphQLBoolean) assert ast_from_value(0, non_null_boolean) == BooleanValueNode(value=False) def converts_int_values_to_int_asts(): assert ast_from_value(-1, GraphQLInt) == IntValueNode(value="-1") assert ast_from_value(123.0, GraphQLInt) == IntValueNode(value="123") assert ast_from_value(1e4, GraphQLInt) == IntValueNode(value="10000") # GraphQL spec does not allow coercing non-integer values to Int to # avoid accidental data loss. with raises(GraphQLError) as exc_info: assert ast_from_value(123.5, GraphQLInt) msg = str(exc_info.value) assert msg == "Int cannot represent non-integer value: 123.5" # Note: outside the bounds of 32bit signed int. with raises(GraphQLError) as exc_info: assert ast_from_value(1e40, GraphQLInt) msg = str(exc_info.value) assert msg == "Int cannot represent non 32-bit signed integer value: 1e+40" with raises(GraphQLError) as exc_info: ast_from_value(nan, GraphQLInt) msg = str(exc_info.value) assert msg == "Int cannot represent non-integer value: nan" def converts_float_values_to_float_asts(): # luckily in Python we can discern between float and int assert ast_from_value(-1, GraphQLFloat) == FloatValueNode(value="-1") assert ast_from_value(123.0, GraphQLFloat) == FloatValueNode(value="123") assert ast_from_value(123.5, GraphQLFloat) == FloatValueNode(value="123.5") assert ast_from_value(1e4, GraphQLFloat) == FloatValueNode(value="10000") assert ast_from_value(1e40, GraphQLFloat) == FloatValueNode(value="1e+40") assert ast_from_value(123456789.01234567, GraphQLFloat) == FloatValueNode( value="123456789.01234567" ) assert ast_from_value(1.1, GraphQLFloat) == FloatValueNode(value="1.1") def converts_string_values_to_string_asts(): assert ast_from_value("hello", GraphQLString) == StringValueNode(value="hello") assert ast_from_value("VALUE", GraphQLString) == StringValueNode(value="VALUE") assert ast_from_value("VA\nLUE", GraphQLString) == StringValueNode( value="VA\nLUE" ) assert ast_from_value(123, GraphQLString) == StringValueNode(value="123") assert ast_from_value(False, GraphQLString) == StringValueNode(value="false") assert ast_from_value(None, GraphQLString) == NullValueNode() assert ast_from_value(Undefined, GraphQLString) is None def converts_id_values_to_int_or_string_asts(): assert ast_from_value("hello", GraphQLID) == StringValueNode(value="hello") assert ast_from_value("VALUE", GraphQLID) == StringValueNode(value="VALUE") # Note: EnumValues cannot contain non-identifier characters assert ast_from_value("VA\nLUE", GraphQLID) == StringValueNode(value="VA\nLUE") # Note: IntValues are used when possible. assert ast_from_value(-1, GraphQLID) == IntValueNode(value="-1") assert ast_from_value(123, GraphQLID) == IntValueNode(value="123") assert ast_from_value("123", GraphQLID) == IntValueNode(value="123") assert ast_from_value("01", GraphQLID) == StringValueNode(value="01") with raises(GraphQLError) as exc_info: assert ast_from_value(False, GraphQLID) assert str(exc_info.value) == "ID cannot represent value: False" assert ast_from_value(None, GraphQLID) == NullValueNode() assert ast_from_value(Undefined, GraphQLString) is None def converts_using_serialize_from_a_custom_scalar_type(): pass_through_scalar = GraphQLScalarType( "PassThroughScalar", serialize=lambda value: value, ) assert ast_from_value("value", pass_through_scalar) == StringValueNode( value="value" ) with raises(TypeError) as exc_info: assert ast_from_value(nan, pass_through_scalar) assert str(exc_info.value) == "Cannot convert value to AST: nan." with raises(TypeError) as exc_info: ast_from_value(inf, pass_through_scalar) assert str(exc_info.value) == "Cannot convert value to AST: inf." return_null_scalar = GraphQLScalarType( "ReturnNullScalar", serialize=lambda value: None, ) assert ast_from_value("value", return_null_scalar) is None class SomeClass: pass return_custom_class_scalar = GraphQLScalarType( "ReturnCustomClassScalar", serialize=lambda value: SomeClass(), ) with raises(TypeError) as exc_info: ast_from_value("value", return_custom_class_scalar) msg = str(exc_info.value) assert msg == "Cannot convert value to AST: ." def does_not_convert_non_null_values_to_null_value(): non_null_boolean = GraphQLNonNull(GraphQLBoolean) assert ast_from_value(None, non_null_boolean) is None complex_value = {"someArbitrary": "complexValue"} my_enum = GraphQLEnumType( "MyEnum", {"HELLO": None, "GOODBYE": None, "COMPLEX": complex_value} ) def converts_string_values_to_enum_asts_if_possible(): assert ast_from_value("HELLO", my_enum) == EnumValueNode(value="HELLO") assert ast_from_value(complex_value, my_enum) == EnumValueNode(value="COMPLEX") # Note: case sensitive with raises(GraphQLError) as exc_info: ast_from_value("hello", my_enum) assert exc_info.value.message == "Enum 'MyEnum' cannot represent value: 'hello'" # Note: not a valid enum value with raises(GraphQLError) as exc_info: ast_from_value("UNKNOWN_VALUE", my_enum) assert ( exc_info.value.message == "Enum 'MyEnum' cannot represent value: 'UNKNOWN_VALUE'" ) def converts_list_values_to_list_asts(): assert ast_from_value( ["FOO", "BAR"], GraphQLList(GraphQLString) ) == ListValueNode( values=[StringValueNode(value="FOO"), StringValueNode(value="BAR")] ) assert ast_from_value( ["HELLO", "GOODBYE"], GraphQLList(my_enum) ) == ListValueNode( values=[EnumValueNode(value="HELLO"), EnumValueNode(value="GOODBYE")] ) def list_generator(): yield 1 yield 2 yield 3 assert ast_from_value(list_generator(), GraphQLList(GraphQLInt)) == ( ListValueNode( values=[ IntValueNode(value="1"), IntValueNode(value="2"), IntValueNode(value="3"), ] ) ) def converts_list_singletons(): assert ast_from_value("FOO", GraphQLList(GraphQLString)) == StringValueNode( value="FOO" ) def skips_invalid_list_items(): ast = ast_from_value( ["FOO", None, "BAR"], GraphQLList(GraphQLNonNull(GraphQLString)) ) assert ast == ListValueNode( values=[StringValueNode(value="FOO"), StringValueNode(value="BAR")] ) input_obj = GraphQLInputObjectType( "MyInputObj", {"foo": GraphQLInputField(GraphQLFloat), "bar": GraphQLInputField(my_enum)}, ) def converts_input_objects(): assert ast_from_value({"foo": 3, "bar": "HELLO"}, input_obj) == ObjectValueNode( fields=[ ObjectFieldNode( name=NameNode(value="foo"), value=FloatValueNode(value="3") ), ObjectFieldNode( name=NameNode(value="bar"), value=EnumValueNode(value="HELLO") ), ] ) def converts_input_objects_with_explicit_nulls(): assert ast_from_value({"foo": None}, input_obj) == ObjectValueNode( fields=[ObjectFieldNode(name=NameNode(value="foo"), value=NullValueNode())] ) def does_not_convert_non_object_values_as_input_objects(): assert ast_from_value(5, input_obj) is None graphql-core-3.2.6/tests/utilities/test_ast_to_dict.py000066400000000000000000000642721474546154300232200ustar00rootroot00000000000000from graphql.language import parse, FieldNode, NameNode, OperationType, SelectionSetNode from graphql.utilities import ast_to_dict def describe_ast_to_disc(): def converts_name_node_to_dict(): node = NameNode(value="test") res = ast_to_dict(node) assert res == {"kind": "name", "value": "test"} assert list(res)[0] == "kind" assert ast_to_dict(node, locations=True) == res assert node.to_dict() == res assert node.to_dict(locations=True) == res def converts_two_name_nodes_to_list(): nodes = [NameNode(value="foo"), NameNode(value="bar")] res = ast_to_dict(nodes) assert ast_to_dict(nodes, locations=True) == res assert res == [ {"kind": "name", "value": "foo"}, {"kind": "name", "value": "bar"}, ] def converts_operation_type_to_its_value(): assert ast_to_dict(OperationType.QUERY) == "query" def keeps_all_other_leaf_nodes(): assert ast_to_dict(None) is None # type: ignore assert ast_to_dict(42) == 42 # type: ignore assert ast_to_dict("foo") == "foo" # type: ignore ast = {"foo": "bar"} assert ast_to_dict(ast) is ast # type: ignore def converts_recursive_ast_to_recursive_dict(): field = FieldNode(name="foo", arguments=(), selection_set=()) ast = SelectionSetNode(selections=(field,)) field.selection_set = ast res = ast_to_dict(ast) assert res == { "kind": "selection_set", "selections": [ { "kind": "field", "name": "foo", "alias": None, "arguments": [], "directives": None, "selection_set": res, } ], } def converts_simple_schema_to_dict(): ast = parse( """ type Query { me: User } type User { id: ID name: String } """ ) res = ast_to_dict(ast) assert ast.to_dict() == res assert res == { "definitions": [ { "description": None, "directives": [], "fields": [ { "arguments": [], "description": None, "directives": [], "kind": "field_definition", "name": {"kind": "name", "value": "me"}, "type": { "kind": "named_type", "name": {"kind": "name", "value": "User"}, }, } ], "interfaces": [], "kind": "object_type_definition", "name": {"kind": "name", "value": "Query"}, }, { "description": None, "directives": [], "fields": [ { "arguments": [], "description": None, "directives": [], "kind": "field_definition", "name": {"kind": "name", "value": "id"}, "type": { "kind": "named_type", "name": {"kind": "name", "value": "ID"}, }, }, { "arguments": [], "description": None, "directives": [], "kind": "field_definition", "name": {"kind": "name", "value": "name"}, "type": { "kind": "named_type", "name": {"kind": "name", "value": "String"}, }, }, ], "interfaces": [], "kind": "object_type_definition", "name": {"kind": "name", "value": "User"}, }, ], "kind": "document", } assert list(res)[0] == "kind" def converts_simple_schema_to_dict_with_locations(): ast = parse( """ type Query { me: User } type User { id: ID name: String } """ ) res = ast_to_dict(ast, locations=True) assert ast.to_dict(locations=True) == res assert res == { "definitions": [ { "description": None, "directives": [], "fields": [ { "arguments": [], "description": None, "directives": [], "kind": "field_definition", "loc": {"end": 48, "start": 40}, "name": { "kind": "name", "loc": {"end": 42, "start": 40}, "value": "me", }, "type": { "kind": "named_type", "loc": {"end": 48, "start": 44}, "name": { "kind": "name", "loc": {"end": 48, "start": 44}, "value": "User", }, }, } ], "interfaces": [], "kind": "object_type_definition", "loc": {"end": 62, "start": 13}, "name": { "kind": "name", "loc": {"end": 23, "start": 18}, "value": "Query", }, }, { "description": None, "directives": [], "fields": [ { "arguments": [], "description": None, "directives": [], "kind": "field_definition", "loc": {"end": 108, "start": 102}, "name": { "kind": "name", "loc": {"end": 104, "start": 102}, "value": "id", }, "type": { "kind": "named_type", "loc": {"end": 108, "start": 106}, "name": { "kind": "name", "loc": {"end": 108, "start": 106}, "value": "ID", }, }, }, { "arguments": [], "description": None, "directives": [], "kind": "field_definition", "loc": {"end": 135, "start": 123}, "name": { "kind": "name", "loc": {"end": 127, "start": 123}, "value": "name", }, "type": { "kind": "named_type", "loc": {"end": 135, "start": 129}, "name": { "kind": "name", "loc": {"end": 135, "start": 129}, "value": "String", }, }, }, ], "interfaces": [], "kind": "object_type_definition", "loc": {"end": 149, "start": 76}, "name": { "kind": "name", "loc": {"end": 85, "start": 81}, "value": "User", }, }, ], "kind": "document", "loc": {"end": 162, "start": 0}, } keys = list(res) assert keys[0] == "kind" assert keys[-1] == "loc" assert list(res["loc"]) == ["start", "end"] def converts_simple_query_to_dict(): ast = parse( """ query HeroForEpisode($ep: Episode!) { hero(episode: $ep) { name ... on Droid { primaryFunction } ... on Human { height } } } """ ) res = ast_to_dict(ast) assert ast.to_dict() == res assert res == { "definitions": [ { "directives": [], "kind": "operation_definition", "name": {"kind": "name", "value": "HeroForEpisode"}, "operation": "query", "selection_set": { "kind": "selection_set", "selections": [ { "alias": None, "arguments": [ { "kind": "argument", "name": {"kind": "name", "value": "episode"}, "value": { "kind": "variable", "name": {"kind": "name", "value": "ep"}, }, } ], "directives": [], "kind": "field", "name": {"kind": "name", "value": "hero"}, "selection_set": { "kind": "selection_set", "selections": [ { "alias": None, "arguments": [], "directives": [], "kind": "field", "name": {"kind": "name", "value": "name"}, "selection_set": None, }, { "directives": [], "kind": "inline_fragment", "selection_set": { "kind": "selection_set", "selections": [ { "alias": None, "arguments": [], "directives": [], "kind": "field", "name": { "kind": "name", "value": "primaryFunction", }, "selection_set": None, } ], }, "type_condition": { "kind": "named_type", "name": { "kind": "name", "value": "Droid", }, }, }, { "directives": [], "kind": "inline_fragment", "selection_set": { "kind": "selection_set", "selections": [ { "alias": None, "arguments": [], "directives": [], "kind": "field", "name": { "kind": "name", "value": "height", }, "selection_set": None, } ], }, "type_condition": { "kind": "named_type", "name": { "kind": "name", "value": "Human", }, }, }, ], }, } ], }, "variable_definitions": [ { "default_value": None, "directives": [], "kind": "variable_definition", "type": { "kind": "non_null_type", "type": { "kind": "named_type", "name": {"kind": "name", "value": "Episode"}, }, }, "variable": { "kind": "variable", "name": {"kind": "name", "value": "ep"}, }, } ], } ], "kind": "document", } assert list(res)[0] == "kind" def converts_simple_query_to_dict_with_locations(): ast = parse( """ query HeroForEpisode($ep: Episode!) { hero(episode: $ep) { name ... on Droid { primaryFunction } ... on Human { height } } } """ ) res = ast_to_dict(ast, locations=True) assert ast.to_dict(locations=True) == res assert res == { "definitions": [ { "directives": [], "kind": "operation_definition", "loc": {"end": 293, "start": 13}, "name": { "kind": "name", "loc": {"end": 33, "start": 19}, "value": "HeroForEpisode", }, "operation": "query", "selection_set": { "kind": "selection_set", "loc": {"end": 293, "start": 49}, "selections": [ { "alias": None, "arguments": [ { "kind": "argument", "loc": {"end": 82, "start": 70}, "name": { "kind": "name", "loc": {"end": 77, "start": 70}, "value": "episode", }, "value": { "kind": "variable", "loc": {"end": 82, "start": 79}, "name": { "kind": "name", "loc": {"end": 82, "start": 80}, "value": "ep", }, }, } ], "directives": [], "kind": "field", "loc": {"end": 279, "start": 65}, "name": { "kind": "name", "loc": {"end": 69, "start": 65}, "value": "hero", }, "selection_set": { "kind": "selection_set", "loc": {"end": 279, "start": 84}, "selections": [ { "alias": None, "arguments": [], "directives": [], "kind": "field", "loc": {"end": 106, "start": 102}, "name": { "kind": "name", "loc": {"end": 106, "start": 102}, "value": "name", }, "selection_set": None, }, { "directives": [], "kind": "inline_fragment", "loc": {"end": 189, "start": 123}, "selection_set": { "kind": "selection_set", "loc": {"end": 189, "start": 136}, "selections": [ { "alias": None, "arguments": [], "directives": [], "kind": "field", "loc": { "end": 171, "start": 156, }, "name": { "kind": "name", "loc": { "end": 171, "start": 156, }, "value": "primaryFunction", }, "selection_set": None, } ], }, "type_condition": { "kind": "named_type", "loc": {"end": 135, "start": 130}, "name": { "kind": "name", "loc": {"end": 135, "start": 130}, "value": "Droid", }, }, }, { "directives": [], "kind": "inline_fragment", "loc": {"end": 263, "start": 206}, "selection_set": { "kind": "selection_set", "loc": {"end": 263, "start": 219}, "selections": [ { "alias": None, "arguments": [], "directives": [], "kind": "field", "loc": { "end": 245, "start": 239, }, "name": { "kind": "name", "loc": { "end": 245, "start": 239, }, "value": "height", }, "selection_set": None, } ], }, "type_condition": { "kind": "named_type", "loc": {"end": 218, "start": 213}, "name": { "kind": "name", "loc": {"end": 218, "start": 213}, "value": "Human", }, }, }, ], }, } ], }, "variable_definitions": [ { "default_value": None, "directives": [], "kind": "variable_definition", "loc": {"end": 47, "start": 34}, "type": { "kind": "non_null_type", "loc": {"end": 47, "start": 39}, "type": { "kind": "named_type", "loc": {"end": 46, "start": 39}, "name": { "kind": "name", "loc": {"end": 46, "start": 39}, "value": "Episode", }, }, }, "variable": { "kind": "variable", "loc": {"end": 37, "start": 34}, "name": { "kind": "name", "loc": {"end": 37, "start": 35}, "value": "ep", }, }, } ], } ], "kind": "document", "loc": {"end": 306, "start": 0}, } keys = list(res) assert keys[0] == "kind" assert keys[-1] == "loc" assert list(res["loc"]) == ["start", "end"] graphql-core-3.2.6/tests/utilities/test_build_ast_schema.py000066400000000000000000001000061474546154300241740ustar00rootroot00000000000000from collections import namedtuple from typing import Union from pytest import mark, raises from graphql import graphql_sync from graphql.language import DocumentNode, InterfaceTypeDefinitionNode, parse, print_ast from graphql.type import ( GraphQLArgument, GraphQLBoolean, GraphQLDeprecatedDirective, GraphQLEnumType, GraphQLEnumValue, GraphQLField, GraphQLFloat, GraphQLID, GraphQLIncludeDirective, GraphQLInputField, GraphQLInt, GraphQLNamedType, GraphQLSchema, GraphQLSkipDirective, GraphQLSpecifiedByDirective, GraphQLString, assert_directive, assert_enum_type, assert_input_object_type, assert_interface_type, assert_object_type, assert_scalar_type, assert_union_type, introspection_types, validate_schema, ) from graphql.utilities import build_ast_schema, build_schema, print_schema, print_type from ..fixtures import big_schema_sdl # noqa: F401 from ..utils import dedent def cycle_sdl(sdl: str) -> str: """Full cycle test. This function does a full cycle of going from a string with the contents of the SDL, parsed in a schema AST, materializing that schema AST into an in-memory GraphQLSchema, and then finally printing that GraphQL into the SDL. """ ast = parse(sdl) schema = build_ast_schema(ast) return print_schema(schema) TypeWithAstNode = Union[ GraphQLArgument, GraphQLEnumValue, GraphQLField, GraphQLInputField, GraphQLNamedType ] TypeWithExtensionAstNodes = GraphQLNamedType def expect_ast_node(obj: TypeWithAstNode, expected: str) -> None: assert obj is not None and obj.ast_node is not None assert print_ast(obj.ast_node) == expected def expect_extension_ast_nodes(obj: TypeWithExtensionAstNodes, expected: str) -> None: assert obj is not None and obj.extension_ast_nodes is not None assert "\n\n".join(print_ast(node) for node in obj.extension_ast_nodes) == expected def describe_schema_builder(): def can_use_built_schema_for_limited_execution(): schema = build_ast_schema( parse( """ type Query { str: String } """ ) ) root_value = namedtuple("Data", "str")(123) # type: ignore result = graphql_sync(schema=schema, source="{ str }", root_value=root_value) assert result == ({"str": "123"}, None) def can_build_a_schema_directly_from_the_source(): schema = build_schema( """ type Query { add(x: Int, y: Int): Int } """ ) source = "{ add(x: 34, y: 55) }" # noinspection PyMethodMayBeStatic class RootValue: def add(self, _info, x, y): return x + y assert graphql_sync(schema=schema, source=source, root_value=RootValue()) == ( {"add": 89}, None, ) def ignores_non_type_system_definitions(): sdl = """ type Query { str: String } fragment SomeFragment on Query { str } """ build_schema(sdl) def match_order_of_default_types_and_directives(): schema = GraphQLSchema() sdl_schema = build_ast_schema(DocumentNode(definitions=[])) assert sdl_schema.directives == schema.directives assert sdl_schema.type_map == schema.type_map def empty_type(): sdl = dedent( """ type EmptyType """ ) assert cycle_sdl(sdl) == sdl def simple_type(): sdl = dedent( """ type Query { str: String int: Int float: Float id: ID bool: Boolean } """ ) assert cycle_sdl(sdl) == sdl schema = build_schema(sdl) # Built-ins are used assert schema.get_type("Int") is GraphQLInt assert schema.get_type("Float") is GraphQLFloat assert schema.get_type("String") is GraphQLString assert schema.get_type("Boolean") is GraphQLBoolean assert schema.get_type("ID") is GraphQLID def include_standard_type_only_if_it_is_used(): schema = build_schema("type Query") # Only String and Boolean are used by introspection types assert schema.get_type("Int") is None assert schema.get_type("Float") is None assert schema.get_type("String") is GraphQLString assert schema.get_type("Boolean") is GraphQLBoolean assert schema.get_type("ID") is None def with_directives(): sdl = dedent( """ directive @foo(arg: Int) on FIELD directive @repeatableFoo(arg: Int) repeatable on FIELD """ ) assert cycle_sdl(sdl) == sdl def supports_descriptions(): sdl = dedent( ''' """Do you agree that this is the most creative schema ever?""" schema { query: Query } """This is a directive""" directive @foo( """It has an argument""" arg: Int ) on FIELD """Who knows what's inside this scalar?""" scalar MysteryScalar """This is an input object type""" input FooInput { """It has a field""" field: Int } """This is an interface type""" interface Energy { """It also has a field""" str: String } """There is nothing inside!""" union BlackHole """With an enum""" enum Color { RED """Not a creative color""" GREEN BLUE } """What a great type""" type Query { """And a field to boot""" str: String } ''' ) assert cycle_sdl(sdl) == sdl def maintains_include_skip_and_specified_by_url_directives(): schema = build_schema("type Query") assert len(schema.directives) == 4 assert schema.get_directive("skip") is GraphQLSkipDirective assert schema.get_directive("include") is GraphQLIncludeDirective assert schema.get_directive("deprecated") is GraphQLDeprecatedDirective assert schema.get_directive("specifiedBy") is GraphQLSpecifiedByDirective def overriding_directives_excludes_specified(): schema = build_schema( """ directive @skip on FIELD directive @include on FIELD directive @deprecated on FIELD_DEFINITION directive @specifiedBy on FIELD_DEFINITION """ ) assert len(schema.directives) == 4 get_directive = schema.get_directive assert get_directive("skip") is not GraphQLSkipDirective assert get_directive("skip") is not None assert get_directive("include") is not GraphQLIncludeDirective assert get_directive("include") is not None assert get_directive("deprecated") is not GraphQLDeprecatedDirective assert get_directive("deprecated") is not None assert get_directive("specifiedBy") is not GraphQLSpecifiedByDirective assert get_directive("specifiedBy") is not None def adding_directives_maintains_include_skip_and_specified_by_directives(): schema = build_schema( """ directive @foo(arg: Int) on FIELD """ ) assert len(schema.directives) == 5 assert schema.get_directive("skip") is GraphQLSkipDirective assert schema.get_directive("include") is GraphQLIncludeDirective assert schema.get_directive("deprecated") is GraphQLDeprecatedDirective assert schema.get_directive("specifiedBy") is GraphQLSpecifiedByDirective assert schema.get_directive("foo") is not None def type_modifiers(): sdl = dedent( """ type Query { nonNullStr: String! listOfStrings: [String] listOfNonNullStrings: [String!] nonNullListOfStrings: [String]! nonNullListOfNonNullStrings: [String!]! } """ ) assert cycle_sdl(sdl) == sdl def recursive_type(): sdl = dedent( """ type Query { str: String recurse: Query } """ ) assert cycle_sdl(sdl) == sdl def two_types_circular(): sdl = dedent( """ type TypeOne { str: String typeTwo: TypeTwo } type TypeTwo { str: String typeOne: TypeOne } """ ) assert cycle_sdl(sdl) == sdl def single_argument_field(): sdl = dedent( """ type Query { str(int: Int): String floatToStr(float: Float): String idToStr(id: ID): String booleanToStr(bool: Boolean): String strToStr(bool: String): String } """ ) assert cycle_sdl(sdl) == sdl def simple_type_with_multiple_arguments(): sdl = dedent( """ type Query { str(int: Int, bool: Boolean): String } """ ) assert cycle_sdl(sdl) == sdl def empty_interface(): sdl = dedent( """ interface EmptyInterface """ ) definition = parse(sdl).definitions[0] assert isinstance(definition, InterfaceTypeDefinitionNode) assert definition.interfaces == () assert cycle_sdl(sdl) == sdl def simple_type_with_interface(): sdl = dedent( """ type Query implements WorldInterface { str: String } interface WorldInterface { str: String } """ ) assert cycle_sdl(sdl) == sdl def simple_interface_hierarchy(): sdl = dedent( """ schema { query: Child } interface Child implements Parent { str: String } type Hello implements Parent & Child { str: String } interface Parent { str: String } """ ) assert cycle_sdl(sdl) == sdl def empty_enum(): sdl = dedent( """ enum EmptyEnum """ ) assert cycle_sdl(sdl) == sdl def simple_output_enum(): sdl = dedent( """ enum Hello { WORLD } type Query { hello: Hello } """ ) assert cycle_sdl(sdl) == sdl def simple_input_enum(): sdl = dedent( """ enum Hello { WORLD } type Query { str(hello: Hello): String } """ ) assert cycle_sdl(sdl) == sdl def multiple_value_enum(): sdl = dedent( """ enum Hello { WO RLD } type Query { hello: Hello } """ ) assert cycle_sdl(sdl) == sdl # check that the internal values are the same as the names schema = build_schema(sdl) enum_type = schema.get_type("Hello") assert isinstance(enum_type, GraphQLEnumType) assert [value.value for value in enum_type.values.values()] == ["WO", "RLD"] def empty_union(): sdl = dedent( """ union EmptyUnion """ ) assert cycle_sdl(sdl) == sdl def simple_union(): sdl = dedent( """ union Hello = World type Query { hello: Hello } type World { str: String } """ ) assert cycle_sdl(sdl) == sdl def multiple_union(): sdl = dedent( """ union Hello = WorldOne | WorldTwo type Query { hello: Hello } type WorldOne { str: String } type WorldTwo { str: String } """ ) assert cycle_sdl(sdl) == sdl def can_build_recursive_union(): # invalid schema cannot be built with Python with raises(TypeError) as exc_info: build_schema( """ union Hello = Hello type Query { hello: Hello } """ ) assert ( str(exc_info.value) == "Hello types must be specified" " as a collection of GraphQLObjectType instances." ) def custom_scalar(): sdl = dedent( """ scalar CustomScalar type Query { customScalar: CustomScalar } """ ) assert cycle_sdl(sdl) == sdl def empty_input_object(): sdl = dedent( """ input EmptyInputObject """ ) assert cycle_sdl(sdl) == sdl def simple_input_object(): sdl = dedent( """ input Input { int: Int } type Query { field(in: Input): String } """ ) assert cycle_sdl(sdl) == sdl def simple_argument_field_with_default(): sdl = dedent( """ type Query { str(int: Int = 2): String } """ ) assert cycle_sdl(sdl) == sdl def custom_scalar_argument_field_with_default(): sdl = dedent( """ scalar CustomScalar type Query { str(int: CustomScalar = 2): String } """ ) assert cycle_sdl(sdl) == sdl def simple_type_with_mutation(): sdl = dedent( """ schema { query: HelloScalars mutation: Mutation } type HelloScalars { str: String int: Int bool: Boolean } type Mutation { addHelloScalars(str: String, int: Int, bool: Boolean): HelloScalars } """ ) assert cycle_sdl(sdl) == sdl def simple_type_with_subscription(): sdl = dedent( """ schema { query: HelloScalars subscription: Subscription } type HelloScalars { str: String int: Int bool: Boolean } type Subscription { subscribeHelloScalars(str: String, int: Int, bool: Boolean): HelloScalars } """ ) assert cycle_sdl(sdl) == sdl def unreferenced_type_implementing_referenced_interface(): sdl = dedent( """ type Concrete implements Interface { key: String } interface Interface { key: String } type Query { interface: Interface } """ ) assert cycle_sdl(sdl) == sdl def unreferenced_interface_implementing_referenced_interface(): sdl = dedent( """ interface Child implements Parent { key: String } interface Parent { key: String } type Query { interfaceField: Parent } """ ) assert cycle_sdl(sdl) == sdl def unreferenced_type_implementing_referenced_union(): sdl = dedent( """ type Concrete { key: String } type Query { union: Union } union Union = Concrete """ ) assert cycle_sdl(sdl) == sdl def supports_deprecated_directive(): sdl = dedent( """ enum MyEnum { VALUE OLD_VALUE @deprecated OTHER_VALUE @deprecated(reason: "Terrible reasons") } input MyInput { oldInput: String @deprecated otherInput: String @deprecated(reason: "Use newInput") newInput: String } type Query { field1: String @deprecated field2: Int @deprecated(reason: "Because I said so") enum: MyEnum field3(oldArg: String @deprecated, arg: String): String field4(oldArg: String @deprecated(reason: "Why not?"), arg: String): String field5(arg: MyInput): String } """ # noqa: E501 ) assert cycle_sdl(sdl) == sdl schema = build_schema(sdl) my_enum = assert_enum_type(schema.get_type("MyEnum")) value = my_enum.values["VALUE"] assert value.deprecation_reason is None old_value = my_enum.values["OLD_VALUE"] assert old_value.deprecation_reason == "No longer supported" other_value = my_enum.values["OTHER_VALUE"] assert other_value.deprecation_reason == "Terrible reasons" root_fields = assert_object_type(schema.get_type("Query")).fields field1 = root_fields["field1"] assert field1.deprecation_reason == "No longer supported" field2 = root_fields["field2"] assert field2.deprecation_reason == "Because I said so" input_fields = assert_input_object_type(schema.get_type("MyInput")).fields new_input = input_fields["newInput"] assert new_input.deprecation_reason is None old_input = input_fields["oldInput"] assert old_input.deprecation_reason == "No longer supported" other_input = input_fields["otherInput"] assert other_input.deprecation_reason == "Use newInput" field3_old_arg = root_fields["field3"].args["oldArg"] assert field3_old_arg.deprecation_reason == "No longer supported" field4_old_arg = root_fields["field4"].args["oldArg"] assert field4_old_arg.deprecation_reason == "Why not?" def supports_specified_by_directives(): sdl = dedent( """ scalar Foo @specifiedBy(url: "https://example.com/foo_spec") type Query { foo: Foo @deprecated } """ ) assert cycle_sdl(sdl) == sdl schema = build_schema(sdl) foo_scalar = assert_scalar_type(schema.get_type("Foo")) assert foo_scalar.specified_by_url == "https://example.com/foo_spec" def correctly_extend_scalar_type(): schema = build_schema( """ scalar SomeScalar extend scalar SomeScalar @foo extend scalar SomeScalar @bar directive @foo on SCALAR directive @bar on SCALAR """ ) some_scalar = assert_scalar_type(schema.get_type("SomeScalar")) assert print_type(some_scalar) == dedent( """ scalar SomeScalar """ ) expect_ast_node(some_scalar, "scalar SomeScalar") expect_extension_ast_nodes( some_scalar, dedent( """ extend scalar SomeScalar @foo extend scalar SomeScalar @bar """ ), ) def correctly_extend_object_type(): schema = build_schema( """ type SomeObject implements Foo { first: String } extend type SomeObject implements Bar { second: Int } extend type SomeObject implements Baz { third: Float } interface Foo interface Bar interface Baz """ ) some_object = assert_object_type(schema.get_type("SomeObject")) assert print_type(some_object) == dedent( """ type SomeObject implements Foo & Bar & Baz { first: String second: Int third: Float } """ ) expect_ast_node( some_object, dedent( """ type SomeObject implements Foo { first: String } """ ), ) expect_extension_ast_nodes( some_object, dedent( """ extend type SomeObject implements Bar { second: Int } extend type SomeObject implements Baz { third: Float } """ ), ) def correctly_extend_interface_type(): schema = build_schema( """ interface SomeInterface { first: String } extend interface SomeInterface { second: Int } extend interface SomeInterface { third: Float } """ ) some_interface = assert_interface_type(schema.get_type("SomeInterface")) assert print_type(some_interface) == dedent( """ interface SomeInterface { first: String second: Int third: Float } """ ) expect_ast_node( some_interface, dedent( """ interface SomeInterface { first: String } """ ), ) expect_extension_ast_nodes( some_interface, dedent( """ extend interface SomeInterface { second: Int } extend interface SomeInterface { third: Float } """ ), ) def correctly_extend_union_type(): schema = build_schema( """ union SomeUnion = FirstType extend union SomeUnion = SecondType extend union SomeUnion = ThirdType type FirstType type SecondType type ThirdType """ ) some_union = assert_union_type(schema.get_type("SomeUnion")) assert print_type(some_union) == dedent( """ union SomeUnion = FirstType | SecondType | ThirdType """ ) expect_ast_node(some_union, "union SomeUnion = FirstType") expect_extension_ast_nodes( some_union, dedent( """ extend union SomeUnion = SecondType extend union SomeUnion = ThirdType """ ), ) def correctly_extend_enum_type(): schema = build_schema( """ enum SomeEnum { FIRST } extend enum SomeEnum { SECOND } extend enum SomeEnum { THIRD } """ ) some_enum = assert_enum_type(schema.get_type("SomeEnum")) assert print_type(some_enum) == dedent( """ enum SomeEnum { FIRST SECOND THIRD } """ ) expect_ast_node( some_enum, dedent( """ enum SomeEnum { FIRST } """ ), ) expect_extension_ast_nodes( some_enum, dedent( """ extend enum SomeEnum { SECOND } extend enum SomeEnum { THIRD } """ ), ) def correctly_extend_input_object_type(): schema = build_schema( """ input SomeInput { first: String } extend input SomeInput { second: Int } extend input SomeInput { third: Float } """ ) some_input = assert_input_object_type(schema.get_type("SomeInput")) assert print_type(some_input) == dedent( """ input SomeInput { first: String second: Int third: Float } """ ) expect_ast_node( some_input, dedent( """ input SomeInput { first: String } """ ), ) expect_extension_ast_nodes( some_input, dedent( """ extend input SomeInput { second: Int } extend input SomeInput { third: Float } """ ), ) def correctly_assign_ast_nodes(): sdl = dedent( """ schema { query: Query } type Query { testField(testArg: TestInput): TestUnion } input TestInput { testInputField: TestEnum } enum TestEnum { TEST_VALUE } union TestUnion = TestType interface TestInterface { interfaceField: String } type TestType implements TestInterface { interfaceField: String } scalar TestScalar directive @test(arg: TestScalar) on FIELD """ ) ast = parse(sdl, no_location=True) schema = build_ast_schema(ast) query = assert_object_type(schema.get_type("Query")) test_input = assert_input_object_type(schema.get_type("TestInput")) test_enum = assert_enum_type(schema.get_type("TestEnum")) test_union = assert_union_type(schema.get_type("TestUnion")) test_interface = assert_interface_type(schema.get_type("TestInterface")) test_type = assert_object_type(schema.get_type("TestType")) test_scalar = assert_scalar_type(schema.get_type("TestScalar")) test_directive = assert_directive(schema.get_directive("test")) assert ( schema.ast_node, query.ast_node, test_input.ast_node, test_enum.ast_node, test_union.ast_node, test_interface.ast_node, test_type.ast_node, test_scalar.ast_node, test_directive.ast_node, ) == ast.definitions test_field = query.fields["testField"] expect_ast_node(test_field, "testField(testArg: TestInput): TestUnion") expect_ast_node(test_field.args["testArg"], "testArg: TestInput") expect_ast_node(test_input.fields["testInputField"], "testInputField: TestEnum") test_enum_value = test_enum.values["TEST_VALUE"] expect_ast_node(test_enum_value, "TEST_VALUE") expect_ast_node( test_interface.fields["interfaceField"], "interfaceField: String" ) expect_ast_node(test_directive.args["arg"], "arg: TestScalar") def root_operation_types_with_custom_names(): schema = build_schema( """ schema { query: SomeQuery mutation: SomeMutation subscription: SomeSubscription } type SomeQuery type SomeMutation type SomeSubscription """ ) assert schema.query_type assert schema.query_type.name == "SomeQuery" assert schema.mutation_type assert schema.mutation_type.name == "SomeMutation" assert schema.subscription_type assert schema.subscription_type.name == "SomeSubscription" def default_root_operation_type_names(): schema = build_schema( """ type Query type Mutation type Subscription """ ) assert schema.query_type assert schema.query_type.name == "Query" assert schema.mutation_type assert schema.mutation_type.name == "Mutation" assert schema.subscription_type assert schema.subscription_type.name == "Subscription" def can_build_invalid_schema(): # Invalid schema, because it is missing query root type schema = build_schema("type Mutation") errors = validate_schema(schema) assert errors def do_not_override_standard_types(): # Note: not sure it's desired behavior to just silently ignore override # attempts so just documenting it here. schema = build_schema( """ scalar ID scalar __Schema """ ) assert schema.get_type("ID") is GraphQLID assert schema.get_type("__Schema") is introspection_types["__Schema"] def allows_to_reference_introspection_types(): schema = build_schema( """ type Query { introspectionField: __EnumValue } """ ) query_type = assert_object_type(schema.get_type("Query")) __EnumValue = introspection_types["__EnumValue"] assert query_type.fields["introspectionField"].type is __EnumValue assert schema.get_type("__EnumValue") is introspection_types["__EnumValue"] def rejects_invalid_sdl(): sdl = """ type Query { foo: String @unknown } """ with raises(TypeError) as exc_info: build_schema(sdl) assert str(exc_info.value) == "Unknown directive '@unknown'." def allows_to_disable_sdl_validation(): sdl = """ type Query { foo: String @unknown } """ build_schema(sdl, assume_valid=True) build_schema(sdl, assume_valid_sdl=True) def throws_on_unknown_types(): sdl = """ type Query { unknown: UnknownType } """ with raises(TypeError) as exc_info: build_schema(sdl, assume_valid_sdl=True) assert str(exc_info.value).endswith("Unknown type: 'UnknownType'.") def rejects_invalid_ast(): with raises(TypeError) as exc_info: build_ast_schema(None) # type: ignore assert str(exc_info.value) == "Must provide valid Document AST." with raises(TypeError) as exc_info: build_ast_schema({}) # type: ignore assert str(exc_info.value) == "Must provide valid Document AST." # This currently does not work because of how extend_schema is implemented @mark.skip(reason="pickling of schemas is not yet supported") def can_pickle_and_unpickle_big_schema( big_schema_sdl, # noqa: F811 ): # pragma: no cover import pickle # create a schema from the kitchen sink SDL schema = build_schema(big_schema_sdl, assume_valid_sdl=True) # check that the schema can be pickled # (particularly, there should be no recursion error, # or errors because of trying to pickle lambdas or local functions) dumped = pickle.dumps(schema) # check that the pickle size is reasonable assert len(dumped) < 50 * len(big_schema_sdl) loaded = pickle.loads(dumped) # check that the un-pickled schema is still the same assert loaded == schema # check that pickling again creates the same result dumped_again = pickle.dumps(schema) assert dumped_again == dumped # check that printing the unpickled schema gives the same SDL assert cycle_sdl(print_schema(schema)) == cycle_sdl(big_schema_sdl) graphql-core-3.2.6/tests/utilities/test_build_client_schema.py000066400000000000000000001047261474546154300247000ustar00rootroot00000000000000from typing import cast from graphql import graphql_sync from graphql.type import ( GraphQLArgument, GraphQLBoolean, GraphQLEnumType, GraphQLEnumValue, GraphQLField, GraphQLFloat, GraphQLID, GraphQLInt, GraphQLObjectType, GraphQLSchema, GraphQLString, assert_enum_type, ) from graphql.utilities import ( build_client_schema, build_schema, introspection_from_schema, print_schema, ) from graphql.utilities.get_introspection_query import ( IntrospectionEnumType, IntrospectionInputObjectType, IntrospectionInterfaceType, IntrospectionObjectType, IntrospectionType, IntrospectionUnionType, ) from pytest import raises from ..utils import dedent def cycle_introspection(sdl_string: str): """Test that the client side introspection gives the same result. This function does a full cycle of going from a string with the contents of the SDL, build in-memory GraphQLSchema from it, produce a client-side representation of the schema by using "build_client_schema" and then return that schema printed as SDL. """ server_schema = build_schema(sdl_string) initial_introspection = introspection_from_schema(server_schema) client_schema = build_client_schema(initial_introspection) # If the client then runs the introspection query against the client-side schema, # it should get a result identical to what was returned by the server second_introspection = introspection_from_schema(client_schema) # If the client then runs the introspection query against the client-side # schema, it should get a result identical to what was returned by the server. assert initial_introspection == second_introspection return print_schema(client_schema) def describe_type_system_build_schema_from_introspection(): def builds_a_simple_schema(): sdl = dedent( ''' """Simple schema""" schema { query: Simple } """This is a simple type""" type Simple { """This is a string field""" string: String } ''' ) assert cycle_introspection(sdl) == sdl def builds_a_schema_without_the_query_type(): sdl = dedent( """ type Query { foo: String } """ ) schema = build_schema(sdl) introspection = introspection_from_schema(schema) del introspection["__schema"]["queryType"] # type: ignore client_schema = build_client_schema(introspection) assert client_schema.query_type is None assert print_schema(client_schema) == sdl def builds_a_simple_schema_with_all_operation_types(): sdl = dedent( ''' schema { query: QueryType mutation: MutationType subscription: SubscriptionType } """This is a simple mutation type""" type MutationType { """Set the string field""" string: String } """This is a simple query type""" type QueryType { """This is a string field""" string: String } """This is a simple subscription type""" type SubscriptionType { """This is a string field""" string: String } ''' ) assert cycle_introspection(sdl) == sdl def uses_built_in_scalars_when_possible(): sdl = dedent( """ scalar CustomScalar type Query { int: Int float: Float string: String boolean: Boolean id: ID custom: CustomScalar } """ ) assert cycle_introspection(sdl) == sdl schema = build_schema(sdl) introspection = introspection_from_schema(schema) client_schema = build_client_schema(introspection) # Built-ins are used assert client_schema.get_type("Int") is GraphQLInt assert client_schema.get_type("Float") is GraphQLFloat assert client_schema.get_type("String") is GraphQLString assert client_schema.get_type("Boolean") is GraphQLBoolean assert client_schema.get_type("ID") is GraphQLID # Custom are built custom_scalar = schema.get_type("CustomScalar") assert client_schema.get_type("CustomScalar") is not custom_scalar def includes_standard_types_only_if_they_are_used(): schema = build_schema( """ type Query { foo: String } """ ) introspection = introspection_from_schema(schema) client_schema = build_client_schema(introspection) assert client_schema.get_type("Int") is None assert client_schema.get_type("Float") is None assert client_schema.get_type("ID") is None def builds_a_schema_with_a_recursive_type_reference(): sdl = dedent( """ schema { query: Recur } type Recur { recur: Recur } """ ) assert cycle_introspection(sdl) == sdl def builds_a_schema_with_a_circular_type_reference(): sdl = dedent( """ type Dog { bestFriend: Human } type Human { bestFriend: Dog } type Query { dog: Dog human: Human } """ ) assert cycle_introspection(sdl) == sdl def builds_a_schema_with_an_interface(): sdl = dedent( ''' type Dog implements Friendly { bestFriend: Friendly } interface Friendly { """The best friend of this friendly thing""" bestFriend: Friendly } type Human implements Friendly { bestFriend: Friendly } type Query { friendly: Friendly } ''' ) assert cycle_introspection(sdl) == sdl def builds_a_schema_with_an_interface_hierarchy(): sdl = dedent( ''' type Dog implements Friendly & Named { bestFriend: Friendly name: String } interface Friendly implements Named { """The best friend of this friendly thing""" bestFriend: Friendly name: String } type Human implements Friendly & Named { bestFriend: Friendly name: String } interface Named { name: String } type Query { friendly: Friendly } ''' ) assert cycle_introspection(sdl) == sdl def builds_a_schema_with_an_implicit_interface(): sdl = dedent( ''' type Dog implements Friendly { bestFriend: Friendly } interface Friendly { """The best friend of this friendly thing""" bestFriend: Friendly } type Query { dog: Dog } ''' ) assert cycle_introspection(sdl) == sdl def builds_a_schema_with_a_union(): sdl = dedent( """ type Dog { bestFriend: Friendly } union Friendly = Dog | Human type Human { bestFriend: Friendly } type Query { friendly: Friendly } """ ) assert cycle_introspection(sdl) == sdl def builds_a_schema_with_complex_field_values(): sdl = dedent( """ type Query { string: String listOfString: [String] nonNullString: String! nonNullListOfString: [String]! nonNullListOfNonNullString: [String!]! } """ ) assert cycle_introspection(sdl) == sdl def builds_a_schema_with_field_arguments(): sdl = dedent( ''' type Query { """A field with a single arg""" one( """This is an int arg""" intArg: Int ): String """A field with a two args""" two( """This is an list of int arg""" listArg: [Int] """This is a required arg""" requiredArg: Boolean! ): String } ''' ) assert cycle_introspection(sdl) == sdl def builds_a_schema_with_default_value_on_custom_scalar_field(): sdl = dedent( """ scalar CustomScalar type Query { testField(testArg: CustomScalar = "default"): String } """ ) assert cycle_introspection(sdl) == sdl def builds_a_schema_with_an_enum(): food_enum = GraphQLEnumType( "Food", { "VEGETABLES": GraphQLEnumValue( 1, description="Foods that are vegetables." ), "FRUITS": GraphQLEnumValue(2), "OILS": GraphQLEnumValue(3, deprecation_reason="Too fatty."), }, description="Varieties of food stuffs", ) schema = GraphQLSchema( GraphQLObjectType( "EnumFields", { "food": GraphQLField( food_enum, args={ "kind": GraphQLArgument( food_enum, description="what kind of food?" ) }, description="Repeats the arg you give it", ) }, ) ) introspection = introspection_from_schema(schema) client_schema = build_client_schema(introspection) second_introspection = introspection_from_schema(client_schema) assert second_introspection == introspection # It's also an Enum type on the client. client_food_enum = assert_enum_type(client_schema.get_type("Food")) # Client types do not get server-only values, so the values mirror the names, # rather than using the integers defined in the "server" schema. values = { name: value.to_kwargs() for name, value in client_food_enum.values.items() } assert values == { "VEGETABLES": { "value": "VEGETABLES", "description": "Foods that are vegetables.", "deprecation_reason": None, "extensions": {}, "ast_node": None, }, "FRUITS": { "value": "FRUITS", "description": None, "deprecation_reason": None, "extensions": {}, "ast_node": None, }, "OILS": { "value": "OILS", "description": None, "deprecation_reason": "Too fatty.", "extensions": {}, "ast_node": None, }, } def builds_a_schema_with_an_input_object(): sdl = dedent( ''' """An input address""" input Address { """What street is this address?""" street: String! """The city the address is within?""" city: String! """The country (blank will assume USA).""" country: String = "USA" } type Query { """Get a geocode from an address""" geocode( """The address to lookup""" address: Address ): String } ''' ) assert cycle_introspection(sdl) == sdl def builds_a_schema_with_field_arguments_with_default_values(): sdl = dedent( """ input Geo { lat: Float lon: Float } type Query { defaultInt(intArg: Int = 30): String defaultList(listArg: [Int] = [1, 2, 3]): String defaultObject(objArg: Geo = {lat: 37.485, lon: -122.148}): String defaultNull(intArg: Int = null): String noDefault(intArg: Int): String } """ ) assert cycle_introspection(sdl) == sdl def builds_a_schema_with_custom_directives(): sdl = dedent( ''' """This is a custom directive""" directive @customDirective repeatable on FIELD type Query { string: String } ''' ) assert cycle_introspection(sdl) == sdl def builds_a_schema_without_directives(): sdl = dedent( """ type Query { foo: String } """ ) schema = build_schema(sdl) introspection = introspection_from_schema(schema) del introspection["__schema"]["directives"] # type: ignore client_schema = build_client_schema(introspection) assert schema.directives assert client_schema.directives == () assert print_schema(client_schema) == sdl def builds_a_schema_aware_of_deprecation(): sdl = dedent( ''' directive @someDirective( """This is a shiny new argument""" shinyArg: SomeInputObject """This was our design mistake :(""" oldArg: String @deprecated(reason: "Use shinyArg") ) on QUERY enum Color { """So rosy""" RED """So grassy""" GREEN """So calming""" BLUE """So sickening""" MAUVE @deprecated(reason: "No longer in fashion") } input SomeInputObject { """Nothing special about it, just deprecated for some unknown reason""" oldField: String @deprecated(reason: "Don't use it, use newField instead!") """Same field but with a new name""" newField: String } type Query { """This is a shiny string field""" shinyString: String """This is a deprecated string field""" deprecatedString: String @deprecated(reason: "Use shinyString") """Color of a week""" color: Color """Some random field""" someField( """This is a shiny new argument""" shinyArg: SomeInputObject """This was our design mistake :(""" oldArg: String @deprecated(reason: "Use shinyArg") ): String } ''' # noqa: E501 ) assert cycle_introspection(sdl) == sdl def builds_a_schema_with_empty_deprecation_reasons(): sdl = dedent( """ directive @someDirective(someArg: SomeInputObject @deprecated(reason: "")) on QUERY type Query { someField(someArg: SomeInputObject @deprecated(reason: "")): SomeEnum @deprecated(reason: "") } input SomeInputObject { someInputField: String @deprecated(reason: "") } enum SomeEnum { SOME_VALUE @deprecated(reason: "") } """ # noqa: E501 ) assert cycle_introspection(sdl) == sdl def builds_a_schema_with_specified_by_url(): sdl = dedent( """ scalar Foo @specifiedBy(url: "https://example.com/foo_spec") type Query { foo: Foo } """ ) assert cycle_introspection(sdl) == sdl def can_use_client_schema_for_limited_execution(): schema = build_schema( """ scalar CustomScalar type Query { foo(custom1: CustomScalar, custom2: CustomScalar): String } """ ) introspection = introspection_from_schema(schema) client_schema = build_client_schema(introspection) class Data: foo = "bar" unused = "value" result = graphql_sync( client_schema, "query Limited($v: CustomScalar) { foo(custom1: 123, custom2: $v) }", root_value=Data(), variable_values={"v": "baz"}, ) assert result.data == {"foo": "bar"} def can_build_invalid_schema(): schema = build_schema("type Query", assume_valid=True) introspection = introspection_from_schema(schema) client_schema = build_client_schema(introspection, assume_valid=True) assert client_schema.to_kwargs()["assume_valid"] is True def describe_throws_when_given_invalid_introspection(): dummy_schema = build_schema( """ type Query { foo(bar: String): String } interface SomeInterface { foo: String } union SomeUnion = Query enum SomeEnum { FOO } input SomeInputObject { foo: String } directive @SomeDirective on QUERY """ ) def throws_when_introspection_is_missing_schema_property(): with raises(TypeError) as exc_info: # noinspection PyTypeChecker build_client_schema(None) # type: ignore assert str(exc_info.value) == ( "Invalid or incomplete introspection result. Ensure that you" " are passing the 'data' attribute of an introspection response" " and no 'errors' were returned alongside: None." ) with raises(TypeError) as exc_info: # noinspection PyTypeChecker build_client_schema({}) # type: ignore assert str(exc_info.value) == ( "Invalid or incomplete introspection result. Ensure that you" " are passing the 'data' attribute of an introspection response" " and no 'errors' were returned alongside: {}." ) def throws_when_referenced_unknown_type(): introspection = introspection_from_schema(dummy_schema) introspection["__schema"]["types"] = [ type_ for type_ in introspection["__schema"]["types"] if type_["name"] != "Query" ] with raises(TypeError) as exc_info: build_client_schema(introspection) assert str(exc_info.value) == ( "Invalid or incomplete schema, unknown type: Query." " Ensure that a full introspection query is used" " in order to build a client schema." ) def throws_when_missing_definition_for_one_of_the_standard_scalars(): schema = build_schema( """ type Query { foo: Float } """ ) introspection = introspection_from_schema(schema) introspection["__schema"]["types"] = [ type_ for type_ in introspection["__schema"]["types"] if type_["name"] != "Float" ] with raises(TypeError) as exc_info: build_client_schema(introspection) assert str(exc_info.value).endswith( "Invalid or incomplete schema, unknown type: Float." " Ensure that a full introspection query is used" " in order to build a client schema." ) def throws_when_type_reference_is_missing_name(): introspection = introspection_from_schema(dummy_schema) query_type = cast(IntrospectionType, introspection["__schema"]["queryType"]) assert query_type["name"] == "Query" del query_type["name"] # type: ignore with raises(TypeError) as exc_info: build_client_schema(introspection) assert str(exc_info.value) == "Unknown type reference: {}." def throws_when_missing_kind(): introspection = introspection_from_schema(dummy_schema) query_type_introspection = next( type_ for type_ in introspection["__schema"]["types"] if type_["name"] == "Query" ) assert query_type_introspection["kind"] == "OBJECT" del query_type_introspection["kind"] with raises( TypeError, match=r"^Invalid or incomplete introspection result\." " Ensure that a full introspection query is used" r" in order to build a client schema: {'name': 'Query', .*}\.$", ): build_client_schema(introspection) def throws_when_missing_interfaces(): introspection = introspection_from_schema(dummy_schema) query_type_introspection = cast( IntrospectionObjectType, next( type_ for type_ in introspection["__schema"]["types"] if type_["name"] == "Query" ), ) assert query_type_introspection["interfaces"] == [] del query_type_introspection["interfaces"] # type: ignore with raises( TypeError, match="^Query interfaces cannot be resolved." " Introspection result missing interfaces:" r" {'kind': 'OBJECT', 'name': 'Query', .*}\.$", ): build_client_schema(introspection) def legacy_support_for_interfaces_with_null_as_interfaces_field(): introspection = introspection_from_schema(dummy_schema) some_interface_introspection = cast( IntrospectionInterfaceType, next( type_ for type_ in introspection["__schema"]["types"] if type_["name"] == "SomeInterface" ), ) assert some_interface_introspection["interfaces"] == [] some_interface_introspection["interfaces"] = None # type: ignore client_schema = build_client_schema(introspection) assert print_schema(client_schema) == print_schema(dummy_schema) def throws_when_missing_fields(): introspection = introspection_from_schema(dummy_schema) query_type_introspection = cast( IntrospectionObjectType, next( type_ for type_ in introspection["__schema"]["types"] if type_["name"] == "Query" ), ) assert query_type_introspection["fields"] del query_type_introspection["fields"] # type: ignore with raises( TypeError, match="^Query fields cannot be resolved." " Introspection result missing fields:" r" {'kind': 'OBJECT', 'name': 'Query', .*}\.$", ): build_client_schema(introspection) def throws_when_missing_field_args(): introspection = introspection_from_schema(dummy_schema) query_type_introspection = cast( IntrospectionObjectType, next( type_ for type_ in introspection["__schema"]["types"] if type_["name"] == "Query" ), ) field = query_type_introspection["fields"][0] assert field["args"] del field["args"] # type: ignore with raises( TypeError, match="^Query fields cannot be resolved." r" Introspection result missing field args: {'name': 'foo', .*}\.$", ): build_client_schema(introspection) def throws_when_output_type_is_used_as_an_arg_type(): introspection = introspection_from_schema(dummy_schema) query_type_introspection = cast( IntrospectionObjectType, next( type_ for type_ in introspection["__schema"]["types"] if type_["name"] == "Query" ), ) arg = query_type_introspection["fields"][0]["args"][0] assert arg["type"]["name"] == "String" arg["type"]["name"] = "SomeUnion" with raises(TypeError) as exc_info: build_client_schema(introspection) assert str(exc_info.value).startswith( "Query fields cannot be resolved." " Introspection must provide input type for arguments," " but received: SomeUnion." ) def throws_when_output_type_is_used_as_an_input_value_type(): introspection = introspection_from_schema(dummy_schema) input_object_type_introspection = cast( IntrospectionInputObjectType, next( type_ for type_ in introspection["__schema"]["types"] if type_["name"] == "SomeInputObject" ), ) input_field = input_object_type_introspection["inputFields"][0] assert input_field["type"]["name"] == "String" input_field["type"]["name"] = "SomeUnion" with raises(TypeError) as exc_info: build_client_schema(introspection) assert str(exc_info.value).startswith( "SomeInputObject fields cannot be resolved." " Introspection must provide input type for input fields," " but received: SomeUnion." ) def throws_when_input_type_is_used_as_a_field_type(): introspection = introspection_from_schema(dummy_schema) query_type_introspection = cast( IntrospectionObjectType, next( type_ for type_ in introspection["__schema"]["types"] if type_["name"] == "Query" ), ) field = query_type_introspection["fields"][0] assert field["type"]["name"] == "String" field["type"]["name"] = "SomeInputObject" with raises(TypeError) as exc_info: build_client_schema(introspection) assert str(exc_info.value).startswith( "Query fields cannot be resolved." " Introspection must provide output type for fields," " but received: SomeInputObject." ) def throws_when_missing_possible_types(): introspection = introspection_from_schema(dummy_schema) some_union_introspection = cast( IntrospectionUnionType, next( type_ for type_ in introspection["__schema"]["types"] if type_["name"] == "SomeUnion" ), ) assert some_union_introspection["possibleTypes"] del some_union_introspection["possibleTypes"] # type: ignore with raises( TypeError, match="^Introspection result missing possibleTypes:" r" {'kind': 'UNION', 'name': 'SomeUnion', .*}\.$", ): build_client_schema(introspection) def throws_when_missing_enum_values(): introspection = introspection_from_schema(dummy_schema) some_enum_introspection = cast( IntrospectionEnumType, next( type_ for type_ in introspection["__schema"]["types"] if type_["name"] == "SomeEnum" ), ) assert some_enum_introspection["enumValues"] del some_enum_introspection["enumValues"] # type: ignore with raises( TypeError, match="^Introspection result missing enumValues:" r" {'kind': 'ENUM', 'name': 'SomeEnum', .*}\.$", ): build_client_schema(introspection) def throws_when_missing_input_fields(): introspection = introspection_from_schema(dummy_schema) some_input_object_introspection = cast( IntrospectionInputObjectType, next( type_ for type_ in introspection["__schema"]["types"] if type_["name"] == "SomeInputObject" ), ) assert some_input_object_introspection["inputFields"] del some_input_object_introspection["inputFields"] # type: ignore with raises( TypeError, match="^Introspection result missing inputFields:" r" {'kind': 'INPUT_OBJECT', 'name': 'SomeInputObject', .*}\.$", ): build_client_schema(introspection) def throws_when_missing_directive_locations(): introspection = introspection_from_schema(dummy_schema) some_directive_introspection = introspection["__schema"]["directives"][0] assert some_directive_introspection["name"] == "SomeDirective" assert some_directive_introspection["locations"] == ["QUERY"] del some_directive_introspection["locations"] # type: ignore with raises( TypeError, match="^Introspection result missing directive locations:" r" {'name': 'SomeDirective', .*}\.$", ): build_client_schema(introspection) def throws_when_missing_directive_args(): introspection = introspection_from_schema(dummy_schema) some_directive_introspection = introspection["__schema"]["directives"][0] assert some_directive_introspection["name"] == "SomeDirective" assert some_directive_introspection["args"] == [] del some_directive_introspection["args"] # type: ignore with raises( TypeError, match="^Introspection result missing directive args:" r" {'name': 'SomeDirective', .*}\.$", ): build_client_schema(introspection) def describe_very_deep_decorators_are_not_supported(): def fails_on_very_deep_lists_more_than_8_levels(): schema = build_schema( """ type Query { foo: [[[[[[[[[[String]]]]]]]]]] } """ ) introspection = introspection_from_schema(schema) with raises(TypeError) as exc_info: build_client_schema(introspection) assert str(exc_info.value) == ( "Query fields cannot be resolved." " Decorated type deeper than introspection query." ) def fails_on_a_very_deep_non_null_more_than_8_levels(): schema = build_schema( """ type Query { foo: [[[[[String!]!]!]!]!] } """ ) introspection = introspection_from_schema(schema) with raises(TypeError) as exc_info: build_client_schema(introspection) assert str(exc_info.value) == ( "Query fields cannot be resolved." " Decorated type deeper than introspection query." ) def succeeds_on_deep_types_less_or_equal_8_levels(): # e.g., fully non-null 4D matrix sdl = dedent( """ type Query { foo: [[[[String!]!]!]!]! } """ ) assert cycle_introspection(sdl) == sdl def describe_prevents_infinite_recursion_on_invalid_introspection(): def recursive_interfaces(): sdl = """ type Query { foo: Foo } type Foo { foo: String } """ schema = build_schema(sdl, assume_valid=True) introspection = introspection_from_schema(schema) foo_introspection = cast( IntrospectionObjectType, next( type_ for type_ in introspection["__schema"]["types"] if type_["name"] == "Foo" ), ) assert foo_introspection["interfaces"] == [] # we need to patch here since invalid interfaces cannot be built with Python foo_introspection["interfaces"] = [ {"kind": "OBJECT", "name": "Foo", "ofType": None} ] with raises(TypeError) as exc_info: build_client_schema(introspection) assert str(exc_info.value) == ( "Foo interfaces cannot be resolved." " Expected Foo to be a GraphQL Interface type." ) def recursive_union(): sdl = """ type Query { foo: Foo } union Foo """ schema = build_schema(sdl, assume_valid=True) introspection = introspection_from_schema(schema) foo_introspection = next( type_ for type_ in introspection["__schema"]["types"] if type_["name"] == "Foo" ) assert foo_introspection["kind"] == "UNION" assert foo_introspection["possibleTypes"] == [] # we need to patch here since invalid unions cannot be built with Python foo_introspection["possibleTypes"] = [ {"kind": "UNION", "name": "Foo", "ofType": None} ] with raises(TypeError) as exc_info: build_client_schema(introspection) assert str(exc_info.value) == ( "Foo types cannot be resolved." " Expected Foo to be a GraphQL Object type." ) graphql-core-3.2.6/tests/utilities/test_coerce_input_value.py000066400000000000000000000327351474546154300245760ustar00rootroot00000000000000from math import nan from typing import Any, List, NamedTuple, Union from pytest import raises from graphql.error import GraphQLError from graphql.pyutils import Undefined from graphql.type import ( GraphQLEnumType, GraphQLFloat, GraphQLInputField, GraphQLInputObjectType, GraphQLInputType, GraphQLInt, GraphQLList, GraphQLNonNull, GraphQLScalarType, ) from graphql.utilities import coerce_input_value class CoercedValueError(NamedTuple): error: str path: List[Union[str, int]] value: Any class CoercedValue(NamedTuple): errors: List[CoercedValueError] value: Any def expect_value(result: CoercedValue) -> Any: assert result.errors == [] return result.value def expect_errors(result: CoercedValue) -> List[CoercedValueError]: return result.errors def describe_coerce_input_value(): def _coerce_value(input_value: Any, type_: GraphQLInputType): errors: List[CoercedValueError] = [] append = errors.append def on_error(path, invalid_value, error): append(CoercedValueError(error.message, path, invalid_value)) value = coerce_input_value(input_value, type_, on_error) return CoercedValue(errors, value) def describe_for_graphql_non_null(): TestNonNull = GraphQLNonNull(GraphQLInt) def returns_non_error_for_non_null_value(): result = _coerce_value(1, TestNonNull) assert expect_value(result) == 1 def returns_an_error_for_undefined_value(): result = _coerce_value(Undefined, TestNonNull) assert expect_errors(result) == [ ("Expected non-nullable type 'Int!' not to be None.", [], Undefined) ] def returns_an_error_for_null_value(): result = _coerce_value(None, TestNonNull) assert expect_errors(result) == [ ("Expected non-nullable type 'Int!' not to be None.", [], None) ] def describe_for_graphql_scalar(): def _parse_value(input_dict): assert isinstance(input_dict, dict) error = input_dict.get("error") if error: raise ValueError(error) return input_dict.get("value") TestScalar = GraphQLScalarType("TestScalar", parse_value=_parse_value) def returns_no_error_for_valid_input(): result = _coerce_value({"value": 1}, TestScalar) assert expect_value(result) == 1 def returns_no_error_for_null_result(): result = _coerce_value({"value": None}, TestScalar) assert expect_value(result) is None def returns_no_error_for_nan_result(): result = _coerce_value({"value": nan}, TestScalar) assert expect_value(result) is nan def returns_an_error_for_undefined_result(): result = _coerce_value({"value": Undefined}, TestScalar) assert expect_errors(result) == [ ("Expected type 'TestScalar'.", [], {"value": Undefined}) ] def returns_an_error_for_undefined_result_with_some_error_message(): input_value = {"error": "Some error message"} result = _coerce_value(input_value, TestScalar) assert expect_errors(result) == [ ( "Expected type 'TestScalar'. Some error message", [], {"error": "Some error message"}, ) ] def describe_for_graphql_enum(): TestEnum = GraphQLEnumType( "TestEnum", {"FOO": "InternalFoo", "BAR": 123_456_789} ) def returns_no_error_for_a_known_enum_name(): foo_result = _coerce_value("FOO", TestEnum) assert expect_value(foo_result) == "InternalFoo" bar_result = _coerce_value("BAR", TestEnum) assert expect_value(bar_result) == 123_456_789 def returns_an_error_for_misspelled_enum_value(): result = _coerce_value("foo", TestEnum) assert expect_errors(result) == [ ( "Value 'foo' does not exist in 'TestEnum' enum." " Did you mean the enum value 'FOO'?", [], "foo", ) ] def returns_an_error_for_incorrect_value_type(): result1 = _coerce_value(123, TestEnum) assert expect_errors(result1) == [ ("Enum 'TestEnum' cannot represent non-string value: 123.", [], 123) ] result2 = _coerce_value({"field": "value"}, TestEnum) assert expect_errors(result2) == [ ( "Enum 'TestEnum' cannot represent non-string value:" " {'field': 'value'}.", [], {"field": "value"}, ) ] def describe_for_graphql_input_object(): TestInputObject = GraphQLInputObjectType( "TestInputObject", { "foo": GraphQLInputField(GraphQLNonNull(GraphQLInt)), "bar": GraphQLInputField(GraphQLInt), }, ) def returns_no_error_for_a_valid_input(): result = _coerce_value({"foo": 123}, TestInputObject) assert expect_value(result) == {"foo": 123} def returns_an_error_for_a_non_dict_value(): result = _coerce_value(123, TestInputObject) assert expect_errors(result) == [ ("Expected type 'TestInputObject' to be a mapping.", [], 123) ] def returns_an_error_for_an_invalid_field(): result = _coerce_value({"foo": nan}, TestInputObject) assert expect_errors(result) == [ ( "Int cannot represent non-integer value: nan", ["foo"], nan, ) ] def returns_multiple_errors_for_multiple_invalid_fields(): result = _coerce_value({"foo": "abc", "bar": "def"}, TestInputObject) assert expect_errors(result) == [ ( "Int cannot represent non-integer value: 'abc'", ["foo"], "abc", ), ( "Int cannot represent non-integer value: 'def'", ["bar"], "def", ), ] def returns_error_for_a_missing_required_field(): result = _coerce_value({"bar": 123}, TestInputObject) assert expect_errors(result) == [ ( "Field 'foo' of required type 'Int!' was not provided.", [], {"bar": 123}, ) ] def returns_error_for_an_unknown_field(): result = _coerce_value({"foo": 123, "unknownField": 123}, TestInputObject) assert expect_errors(result) == [ ( "Field 'unknownField' is not defined by type 'TestInputObject'.", [], {"foo": 123, "unknownField": 123}, ) ] def returns_error_for_a_misspelled_field(): result = _coerce_value({"foo": 123, "bart": 123}, TestInputObject) assert expect_errors(result) == [ ( "Field 'bart' is not defined by type 'TestInputObject'." " Did you mean 'bar'?", [], {"foo": 123, "bart": 123}, ) ] def transforms_names_using_out_name(): # This is an extension of GraphQL.js. ComplexInputObject = GraphQLInputObjectType( "Complex", { "realPart": GraphQLInputField(GraphQLFloat, out_name="real_part"), "imagPart": GraphQLInputField( GraphQLFloat, default_value=0, out_name="imag_part" ), }, ) result = _coerce_value({"realPart": 1}, ComplexInputObject) assert expect_value(result) == {"real_part": 1, "imag_part": 0} def transforms_values_with_out_type(): # This is an extension of GraphQL.js. ComplexInputObject = GraphQLInputObjectType( "Complex", { "real": GraphQLInputField(GraphQLFloat), "imag": GraphQLInputField(GraphQLFloat), }, out_type=lambda value: complex(value["real"], value["imag"]), ) result = _coerce_value({"real": 1, "imag": 2}, ComplexInputObject) assert expect_value(result) == 1 + 2j def describe_for_graphql_input_object_with_default_value(): def _get_test_input_object(default_value): return GraphQLInputObjectType( "TestInputObject", { "foo": GraphQLInputField( GraphQLScalarType("TestScalar"), default_value=default_value ) }, ) def returns_no_errors_for_valid_input_value(): result = _coerce_value({"foo": 5}, _get_test_input_object(7)) assert expect_value(result) == {"foo": 5} def returns_object_with_default_value(): result = _coerce_value({}, _get_test_input_object(7)) assert expect_value(result) == {"foo": 7} def returns_null_as_value(): result = _coerce_value({}, _get_test_input_object(None)) assert expect_value(result) == {"foo": None} def returns_nan_as_value(): result = _coerce_value({}, _get_test_input_object(nan)) result_value = expect_value(result) assert "foo" in result_value assert result_value["foo"] is nan def describe_for_graphql_list(): TestList = GraphQLList(GraphQLInt) def returns_no_error_for_a_valid_input(): result = _coerce_value([1, 2, 3], TestList) assert expect_value(result) == [1, 2, 3] def returns_no_error_for_a_valid_iterable_input(): def list_generator(): yield 1 yield 2 yield 3 result = _coerce_value(list_generator(), TestList) assert expect_value(result) == [1, 2, 3] def returns_an_error_for_an_invalid_input(): result = _coerce_value([1, "b", True, 4], TestList) assert expect_errors(result) == [ ( "Int cannot represent non-integer value: 'b'", [1], "b", ), ( "Int cannot represent non-integer value: True", [2], True, ), ] def returns_a_list_for_a_non_list_value(): result = _coerce_value(42, TestList) assert expect_value(result) == [42] def returns_a_list_for_a_dictionary(): test_list_of_objects = GraphQLList( GraphQLInputObjectType( "TestObject", {"length": GraphQLInputField(GraphQLInt)} ) ) result = _coerce_value({"length": 100500}, test_list_of_objects) assert expect_value(result) == [{"length": 100500}] def returns_a_list_for_a_non_list_invalid_value(): result = _coerce_value("Undefined", TestList) assert expect_errors(result) == [ ( "Int cannot represent non-integer value: 'Undefined'", [], "Undefined", ) ] def returns_null_for_a_null_value(): result = _coerce_value(None, TestList) assert expect_value(result) is None def describe_for_nested_graphql_list(): TestNestedList = GraphQLList(GraphQLList(GraphQLInt)) def returns_no_error_for_a_valid_input(): result = _coerce_value([[1], [2], [3]], TestNestedList) assert expect_value(result) == [[1], [2], [3]] def returns_a_list_for_a_non_list_value(): result = _coerce_value(42, TestNestedList) assert expect_value(result) == [[42]] def returns_null_for_a_null_value(): result = _coerce_value(None, TestNestedList) assert expect_value(result) is None def returns_nested_list_for_nested_non_list_values(): result = _coerce_value([1, 2, 3], TestNestedList) assert expect_value(result) == [[1], [2], [3]] def returns_nested_null_for_nested_null_values(): result = _coerce_value([42, [None], None], TestNestedList) assert expect_value(result) == [[42], [None], None] def describe_with_default_on_error(): def throw_error_without_path(): with raises(GraphQLError) as exc_info: assert coerce_input_value(None, GraphQLNonNull(GraphQLInt)) assert exc_info.value.message == ( "Invalid value None: Expected non-nullable type 'Int!' not to be None." ) def throw_error_with_path(): with raises(GraphQLError) as exc_info: assert coerce_input_value( [None], GraphQLList(GraphQLNonNull(GraphQLInt)) ) assert exc_info.value.message == ( "Invalid value None at 'value[0]':" " Expected non-nullable type 'Int!' not to be None." ) graphql-core-3.2.6/tests/utilities/test_concat_ast.py000066400000000000000000000014011474546154300230230ustar00rootroot00000000000000from graphql.language import parse, print_ast, Source from graphql.utilities import concat_ast from ..utils import dedent def describe_concat_ast(): def concatenates_two_asts_together(): source_a = Source( """ { a, b, ... Frag } """ ) source_b = Source( """ fragment Frag on T { c } """ ) ast_a = parse(source_a) ast_b = parse(source_b) ast_c = concat_ast([ast_a, ast_b]) assert print_ast(ast_c) == dedent( """ { a b ...Frag } fragment Frag on T { c } """ ) graphql-core-3.2.6/tests/utilities/test_extend_schema.py000066400000000000000000001242021474546154300235210ustar00rootroot00000000000000from typing import Union from pytest import raises from graphql import graphql_sync from graphql.language import parse, print_ast from graphql.type import ( GraphQLArgument, GraphQLBoolean, GraphQLEnumValue, GraphQLField, GraphQLFloat, GraphQLID, GraphQLInputField, GraphQLInt, GraphQLNamedType, GraphQLSchema, GraphQLString, assert_directive, assert_enum_type, assert_input_object_type, assert_interface_type, assert_object_type, assert_scalar_type, assert_union_type, validate_schema, ) from graphql.utilities import ( build_schema, concat_ast, extend_schema, print_schema, ) from ..utils import dedent TypeWithAstNode = Union[ GraphQLArgument, GraphQLEnumValue, GraphQLField, GraphQLInputField, GraphQLNamedType, GraphQLSchema, ] TypeWithExtensionAstNodes = Union[ GraphQLNamedType, GraphQLSchema, ] def expect_extension_ast_nodes(obj: TypeWithExtensionAstNodes, expected: str) -> None: assert obj is not None and obj.extension_ast_nodes is not None assert "\n\n".join(print_ast(node) for node in obj.extension_ast_nodes) == expected def expect_ast_node(obj: TypeWithAstNode, expected: str) -> None: assert obj is not None and obj.ast_node is not None assert print_ast(obj.ast_node) == expected def expect_schema_changes( schema: GraphQLSchema, extended_schema: GraphQLSchema, expected: str ) -> None: schema_definitions = { print_ast(node) for node in parse(print_schema(schema)).definitions } assert ( "\n\n".join( schema_def for schema_def in ( print_ast(node) for node in parse(print_schema(extended_schema)).definitions ) if schema_def not in schema_definitions ) == expected ) def describe_extend_schema(): def returns_the_original_schema_when_there_are_no_type_definitions(): schema = build_schema("type Query") extended_schema = extend_schema(schema, parse("{ field }")) assert extended_schema == schema def can_be_used_for_limited_execution(): schema = build_schema("type Query") extend_ast = parse( """ extend type Query { newField: String } """ ) extended_schema = extend_schema(schema, extend_ast) result = graphql_sync( schema=extended_schema, source="{ newField }", root_value={"newField": 123} ) assert result == ({"newField": "123"}, None) def extends_objects_by_adding_new_fields(): schema = build_schema( ''' type Query { someObject: SomeObject } type SomeObject implements AnotherInterface & SomeInterface { self: SomeObject tree: [SomeObject]! """Old field description.""" oldField: String } interface SomeInterface { self: SomeInterface } interface AnotherInterface { self: SomeObject } ''' ) extension_sdl = dedent( ''' extend type SomeObject { """New field description.""" newField(arg: Boolean): String } ''' ) extended_schema = extend_schema(schema, parse(extension_sdl)) assert validate_schema(extended_schema) == [] expect_schema_changes( schema, extended_schema, dedent( ''' type SomeObject implements AnotherInterface & SomeInterface { self: SomeObject tree: [SomeObject]! """Old field description.""" oldField: String """New field description.""" newField(arg: Boolean): String } ''' ), ) def extends_objects_with_standard_type_fields(): schema = build_schema("type Query") # Only String and Boolean are used by introspection types assert schema.get_type("Int") is None assert schema.get_type("Float") is None assert schema.get_type("String") is GraphQLString assert schema.get_type("Boolean") is GraphQLBoolean assert schema.get_type("ID") is None extend_ast = parse( """ extend type Query { bool: Boolean } """ ) extended_schema = extend_schema(schema, extend_ast) assert validate_schema(extended_schema) == [] assert extended_schema.get_type("Int") is None assert extended_schema.get_type("Float") is None assert extended_schema.get_type("String") is GraphQLString assert extended_schema.get_type("Boolean") is GraphQLBoolean assert extended_schema.get_type("ID") is None extend_twice_ast = parse( """ extend type Query { int: Int float: Float id: ID } """ ) extended_twice_schema = extend_schema(schema, extend_twice_ast) assert validate_schema(extended_twice_schema) == [] assert extended_twice_schema.get_type("Int") is GraphQLInt assert extended_twice_schema.get_type("Float") is GraphQLFloat assert extended_twice_schema.get_type("String") is GraphQLString assert extended_twice_schema.get_type("Boolean") is GraphQLBoolean assert extended_twice_schema.get_type("ID") is GraphQLID def extends_enums_by_adding_new_values(): schema = build_schema( ''' type Query { someEnum(arg: SomeEnum): SomeEnum } directive @foo(arg: SomeEnum) on SCHEMA enum SomeEnum { """Old value description.""" OLD_VALUE } ''' ) extend_ast = parse( ''' extend enum SomeEnum { """New value description.""" NEW_VALUE } ''' ) extended_schema = extend_schema(schema, extend_ast) assert validate_schema(extended_schema) == [] expect_schema_changes( schema, extended_schema, dedent( ''' enum SomeEnum { """Old value description.""" OLD_VALUE """New value description.""" NEW_VALUE } ''' ), ) def extends_unions_by_adding_new_types(): schema = build_schema( """ type Query { someUnion: SomeUnion } union SomeUnion = Foo | Biz type Foo { foo: String } type Biz { biz: String } type Bar { bar: String } """ ) extend_ast = parse( """ extend union SomeUnion = Bar """ ) extended_schema = extend_schema(schema, extend_ast) assert validate_schema(extended_schema) == [] expect_schema_changes( schema, extended_schema, dedent( """ union SomeUnion = Foo | Biz | Bar """ ), ) def allows_extension_of_union_by_adding_itself(): schema = build_schema( """ union SomeUnion """ ) extend_ast = parse( """ extend union SomeUnion = SomeUnion """ ) # invalid schema cannot be built with Python with raises(TypeError) as exc_info: extend_schema(schema, extend_ast) assert str(exc_info.value) == ( "SomeUnion types must be specified" " as a collection of GraphQLObjectType instances." ) def extends_inputs_by_adding_new_fields(): schema = build_schema( ''' type Query { someInput(arg: SomeInput): String } directive @foo(arg: SomeInput) on SCHEMA input SomeInput { """Old field description.""" oldField: String } ''' ) extend_ast = parse( ''' extend input SomeInput { """New field description.""" newField: String } ''' ) extended_schema = extend_schema(schema, extend_ast) assert validate_schema(extended_schema) == [] expect_schema_changes( schema, extended_schema, dedent( ''' input SomeInput { """Old field description.""" oldField: String """New field description.""" newField: String } ''' ), ) def extends_scalars_by_adding_new_directives(): schema = build_schema( """ type Query { someScalar(arg: SomeScalar): SomeScalar } directive @foo(arg: SomeScalar) on SCALAR input FooInput { foo: SomeScalar } scalar SomeScalar """ ) extension_sdl = dedent( """ extend scalar SomeScalar @foo """ ) extended_schema = extend_schema(schema, parse(extension_sdl)) some_scalar = assert_scalar_type(extended_schema.get_type("SomeScalar")) assert validate_schema(extended_schema) == [] expect_extension_ast_nodes(some_scalar, extension_sdl) def extends_scalars_by_adding_specified_by_directive(): schema = build_schema( """ type Query { foo: Foo } scalar Foo directive @foo on SCALAR """ ) extension_sdl = dedent( """ extend scalar Foo @foo extend scalar Foo @specifiedBy(url: "https://example.com/foo_spec") """ ) extended_schema = extend_schema(schema, parse(extension_sdl)) foo = assert_scalar_type(extended_schema.get_type("Foo")) assert foo.specified_by_url == "https://example.com/foo_spec" assert validate_schema(extended_schema) == [] expect_extension_ast_nodes(foo, extension_sdl) def correctly_assigns_ast_nodes_to_new_and_extended_types(): schema = build_schema( """ type Query scalar SomeScalar enum SomeEnum union SomeUnion input SomeInput type SomeObject interface SomeInterface directive @foo on SCALAR """ ) first_extension_ast = parse( """ extend type Query { newField(testArg: TestInput): TestEnum } extend scalar SomeScalar @foo extend enum SomeEnum { NEW_VALUE } extend union SomeUnion = SomeObject extend input SomeInput { newField: String } extend interface SomeInterface { newField: String } enum TestEnum { TEST_VALUE } input TestInput { testInputField: TestEnum } """ ) extended_schema = extend_schema(schema, first_extension_ast) second_extension_ast = parse( """ extend type Query { oneMoreNewField: TestUnion } extend scalar SomeScalar @test extend enum SomeEnum { ONE_MORE_NEW_VALUE } extend union SomeUnion = TestType extend input SomeInput { oneMoreNewField: String } extend interface SomeInterface { oneMoreNewField: String } union TestUnion = TestType interface TestInterface { interfaceField: String } type TestType implements TestInterface { interfaceField: String } directive @test(arg: Int) repeatable on FIELD | SCALAR """ ) extended_twice_schema = extend_schema(extended_schema, second_extension_ast) extend_in_one_go_schema = extend_schema( schema, concat_ast([first_extension_ast, second_extension_ast]) ) assert print_schema(extend_in_one_go_schema) == print_schema( extended_twice_schema ) query = assert_object_type(extended_twice_schema.get_type("Query")) some_enum = assert_enum_type(extended_twice_schema.get_type("SomeEnum")) some_union = assert_union_type(extended_twice_schema.get_type("SomeUnion")) some_scalar = assert_scalar_type(extended_twice_schema.get_type("SomeScalar")) some_input = assert_input_object_type( extended_twice_schema.get_type("SomeInput") ) some_interface = assert_interface_type( extended_twice_schema.get_type("SomeInterface") ) test_input = assert_input_object_type( extended_twice_schema.get_type("TestInput") ) test_enum = assert_enum_type(extended_twice_schema.get_type("TestEnum")) test_union = assert_union_type(extended_twice_schema.get_type("TestUnion")) test_type = assert_object_type(extended_twice_schema.get_type("TestType")) test_interface = assert_interface_type( extended_twice_schema.get_type("TestInterface") ) test_directive = assert_directive(extended_twice_schema.get_directive("test")) assert test_type.extension_ast_nodes == () assert test_enum.extension_ast_nodes == () assert test_union.extension_ast_nodes == () assert test_input.extension_ast_nodes == () assert test_interface.extension_ast_nodes == () assert query.extension_ast_nodes assert len(query.extension_ast_nodes) == 2 assert some_scalar.extension_ast_nodes assert len(some_scalar.extension_ast_nodes) == 2 assert some_enum.extension_ast_nodes assert len(some_enum.extension_ast_nodes) == 2 assert some_union.extension_ast_nodes assert len(some_union.extension_ast_nodes) == 2 assert some_input.extension_ast_nodes assert len(some_input.extension_ast_nodes) == 2 assert some_interface.extension_ast_nodes assert len(some_interface.extension_ast_nodes) == 2 assert { test_input.ast_node, test_enum.ast_node, test_union.ast_node, test_interface.ast_node, test_type.ast_node, test_directive.ast_node, *query.extension_ast_nodes, *some_scalar.extension_ast_nodes, *some_enum.extension_ast_nodes, *some_union.extension_ast_nodes, *some_input.extension_ast_nodes, *some_interface.extension_ast_nodes, } == {*first_extension_ast.definitions, *second_extension_ast.definitions} new_field = query.fields["newField"] expect_ast_node(new_field, "newField(testArg: TestInput): TestEnum") expect_ast_node(new_field.args["testArg"], "testArg: TestInput") expect_ast_node(query.fields["oneMoreNewField"], "oneMoreNewField: TestUnion") expect_ast_node(some_enum.values["NEW_VALUE"], "NEW_VALUE") one_more_new_value = some_enum.values["ONE_MORE_NEW_VALUE"] expect_ast_node(one_more_new_value, "ONE_MORE_NEW_VALUE") expect_ast_node(some_input.fields["newField"], "newField: String") expect_ast_node(some_input.fields["oneMoreNewField"], "oneMoreNewField: String") expect_ast_node(some_interface.fields["newField"], "newField: String") expect_ast_node( some_interface.fields["oneMoreNewField"], "oneMoreNewField: String" ) expect_ast_node(test_input.fields["testInputField"], "testInputField: TestEnum") expect_ast_node(test_enum.values["TEST_VALUE"], "TEST_VALUE") expect_ast_node( test_interface.fields["interfaceField"], "interfaceField: String" ) expect_ast_node(test_type.fields["interfaceField"], "interfaceField: String") expect_ast_node(test_directive.args["arg"], "arg: Int") def builds_types_with_deprecated_fields_and_values(): schema = GraphQLSchema() extend_ast = parse( """ type SomeObject { deprecatedField: String @deprecated(reason: "not used anymore") } enum SomeEnum { DEPRECATED_VALUE @deprecated(reason: "do not use") } """ ) extended_schema = extend_schema(schema, extend_ast) some_type = assert_object_type(extended_schema.get_type("SomeObject")) deprecated_field = some_type.fields["deprecatedField"] assert deprecated_field.deprecation_reason == "not used anymore" some_enum = assert_enum_type(extended_schema.get_type("SomeEnum")) deprecated_enum = some_enum.values["DEPRECATED_VALUE"] assert deprecated_enum.deprecation_reason == "do not use" def extends_objects_with_deprecated_fields(): schema = build_schema("type SomeObject") extend_ast = parse( """ extend type SomeObject { deprecatedField: String @deprecated(reason: "not used anymore") } """ ) extended_schema = extend_schema(schema, extend_ast) some_type = assert_object_type(extended_schema.get_type("SomeObject")) deprecated_field = some_type.fields["deprecatedField"] assert deprecated_field.deprecation_reason == "not used anymore" def extend_enums_with_deprecated_values(): schema = build_schema("enum SomeEnum") extend_ast = parse( """ extend enum SomeEnum { DEPRECATED_VALUE @deprecated(reason: "do not use") } """ ) extended_schema = extend_schema(schema, extend_ast) some_enum = assert_enum_type(extended_schema.get_type("SomeEnum")) deprecated_value = some_enum.values["DEPRECATED_VALUE"] assert deprecated_value.deprecation_reason == "do not use" def adds_new_unused_types(): schema = build_schema( """ type Query { dummy: String } """ ) extension_sdl = dedent( """ type DummyUnionMember { someField: String } enum UnusedEnum { SOME_VALUE } input UnusedInput { someField: String } interface UnusedInterface { someField: String } type UnusedObject { someField: String } union UnusedUnion = DummyUnionMember """ ) extended_schema = extend_schema(schema, parse(extension_sdl)) assert validate_schema(extended_schema) == [] expect_schema_changes(schema, extended_schema, extension_sdl) def extends_objects_by_adding_new_fields_with_arguments(): schema = build_schema( """ type SomeObject type Query { someObject: SomeObject } """ ) extend_ast = parse( """ input NewInputObj { field1: Int field2: [Float] field3: String! } extend type SomeObject { newField(arg1: String, arg2: NewInputObj!): String } """ ) extended_schema = extend_schema(schema, extend_ast) assert validate_schema(extended_schema) == [] expect_schema_changes( schema, extended_schema, dedent( """ type SomeObject { newField(arg1: String, arg2: NewInputObj!): String } input NewInputObj { field1: Int field2: [Float] field3: String! } """ ), ) def extends_objects_by_adding_new_fields_with_existing_types(): schema = build_schema( """ type Query { someObject: SomeObject } type SomeObject enum SomeEnum { VALUE } """ ) extend_ast = parse( """ extend type SomeObject { newField(arg1: SomeEnum!): SomeEnum } """ ) extended_schema = extend_schema(schema, extend_ast) assert validate_schema(extended_schema) == [] expect_schema_changes( schema, extended_schema, dedent( """ type SomeObject { newField(arg1: SomeEnum!): SomeEnum } """ ), ) def extends_objects_by_adding_implemented_interfaces(): schema = build_schema( """ type Query { someObject: SomeObject } type SomeObject { foo: String } interface SomeInterface { foo: String } """ ) extend_ast = parse( """ extend type SomeObject implements SomeInterface """ ) extended_schema = extend_schema(schema, extend_ast) assert validate_schema(extended_schema) == [] expect_schema_changes( schema, extended_schema, dedent( """ type SomeObject implements SomeInterface { foo: String } """ ), ) def extends_objects_by_including_new_types(): schema = build_schema( """ type Query { someObject: SomeObject } type SomeObject { oldField: String } """ ) new_types_sdl = """ enum NewEnum { VALUE } interface NewInterface { baz: String } type NewObject implements NewInterface { baz: String } scalar NewScalar union NewUnion = NewObject """ extend_ast = parse( new_types_sdl + """ extend type SomeObject { newObject: NewObject newInterface: NewInterface newUnion: NewUnion newScalar: NewScalar newEnum: NewEnum newTree: [SomeObject]! } """ ) extended_schema = extend_schema(schema, extend_ast) assert validate_schema(extended_schema) == [] expect_schema_changes( schema, extended_schema, dedent( """ type SomeObject { oldField: String newObject: NewObject newInterface: NewInterface newUnion: NewUnion newScalar: NewScalar newEnum: NewEnum newTree: [SomeObject]! }\n""" + new_types_sdl ), ) def extends_objects_by_adding_implemented_new_interfaces(): schema = build_schema( """ type Query { someObject: SomeObject } type SomeObject implements OldInterface { oldField: String } interface OldInterface { oldField: String } """ ) extend_ast = parse( """ extend type SomeObject implements NewInterface { newField: String } interface NewInterface { newField: String } """ ) extended_schema = extend_schema(schema, extend_ast) assert validate_schema(extended_schema) == [] expect_schema_changes( schema, extended_schema, dedent( """ type SomeObject implements OldInterface & NewInterface { oldField: String newField: String } interface NewInterface { newField: String } """ ), ) def extends_different_types_multiple_times(): schema = build_schema( """ type Query { someScalar: SomeScalar someObject(someInput: SomeInput): SomeObject someInterface: SomeInterface someEnum: SomeEnum someUnion: SomeUnion } scalar SomeScalar type SomeObject implements SomeInterface { oldField: String } interface SomeInterface { oldField: String } enum SomeEnum { OLD_VALUE } union SomeUnion = SomeObject input SomeInput { oldField: String } """ ) new_types_sdl = dedent( """ scalar NewScalar scalar AnotherNewScalar type NewObject { foo: String } type AnotherNewObject { foo: String } interface NewInterface { newField: String } interface AnotherNewInterface { anotherNewField: String } """ ) schema_with_new_types = extend_schema(schema, parse(new_types_sdl)) expect_schema_changes(schema, schema_with_new_types, new_types_sdl) extend_ast = parse( """ extend scalar SomeScalar @specifiedBy(url: "http://example.com/foo_spec") extend type SomeObject implements NewInterface { newField: String } extend type SomeObject implements AnotherNewInterface { anotherNewField: String } extend enum SomeEnum { NEW_VALUE } extend enum SomeEnum { ANOTHER_NEW_VALUE } extend union SomeUnion = NewObject extend union SomeUnion = AnotherNewObject extend input SomeInput { newField: String } extend input SomeInput { anotherNewField: String } """ ) extended_schema = extend_schema(schema_with_new_types, extend_ast) assert validate_schema(extended_schema) == [] expect_schema_changes( schema, extended_schema, dedent( """ scalar SomeScalar @specifiedBy(url: "http://example.com/foo_spec") type SomeObject implements SomeInterface & NewInterface & AnotherNewInterface { oldField: String newField: String anotherNewField: String } enum SomeEnum { OLD_VALUE NEW_VALUE ANOTHER_NEW_VALUE } union SomeUnion = SomeObject | NewObject | AnotherNewObject input SomeInput { oldField: String newField: String anotherNewField: String } """ # noqa: E501 ) + "\n\n" + new_types_sdl, ) def extends_interfaces_by_adding_new_fields(): schema = build_schema( """ interface SomeInterface { oldField: String } interface AnotherInterface implements SomeInterface { oldField: String } type SomeObject implements SomeInterface & AnotherInterface { oldField: String } type Query { someInterface: SomeInterface } """ ) extend_ast = parse( """ extend interface SomeInterface { newField: String } extend interface AnotherInterface { newField: String } extend type SomeObject { newField: String } """ ) extended_schema = extend_schema(schema, extend_ast) assert validate_schema(extended_schema) == [] expect_schema_changes( schema, extended_schema, dedent( """ interface SomeInterface { oldField: String newField: String } interface AnotherInterface implements SomeInterface { oldField: String newField: String } type SomeObject implements SomeInterface & AnotherInterface { oldField: String newField: String } """ ), ) def extends_interfaces_by_adding_new_implemented_interfaces(): schema = build_schema( """ interface SomeInterface { oldField: String } interface AnotherInterface implements SomeInterface { oldField: String } type SomeObject implements SomeInterface & AnotherInterface { oldField: String } type Query { someInterface: SomeInterface } """ ) extend_ast = parse( """ interface NewInterface { newField: String } extend interface AnotherInterface implements NewInterface { newField: String } extend type SomeObject implements NewInterface { newField: String } """ ) extended_schema = extend_schema(schema, extend_ast) assert validate_schema(extended_schema) == [] expect_schema_changes( schema, extended_schema, dedent( """ interface AnotherInterface implements SomeInterface & NewInterface { oldField: String newField: String } type SomeObject implements SomeInterface & AnotherInterface & NewInterface { oldField: String newField: String } interface NewInterface { newField: String } """ # noqa: E501 ), ) def allows_extension_of_interface_with_missing_object_fields(): schema = build_schema( """ type Query { someInterface: SomeInterface } type SomeObject implements SomeInterface { oldField: SomeInterface } interface SomeInterface { oldField: SomeInterface } """ ) extend_ast = parse( """ extend interface SomeInterface { newField: String } """ ) extended_schema = extend_schema(schema, extend_ast) assert validate_schema(extended_schema) expect_schema_changes( schema, extended_schema, dedent( """ interface SomeInterface { oldField: SomeInterface newField: String } """ ), ) def extends_interfaces_multiple_times(): schema = build_schema( """ type Query { someInterface: SomeInterface } interface SomeInterface { some: SomeInterface } """ ) extend_ast = parse( """ extend interface SomeInterface { newFieldA: Int } extend interface SomeInterface { newFieldB(test: Boolean): String } """ ) extended_schema = extend_schema(schema, extend_ast) assert validate_schema(extended_schema) == [] expect_schema_changes( schema, extended_schema, dedent( """ interface SomeInterface { some: SomeInterface newFieldA: Int newFieldB(test: Boolean): String } """ ), ) def may_extend_mutations_and_subscriptions(): mutation_schema = build_schema( """ type Query { queryField: String } type Mutation { mutationField: String } type Subscription { subscriptionField: String } """ ) ast = parse( """ extend type Query { newQueryField: Int } extend type Mutation { newMutationField: Int } extend type Subscription { newSubscriptionField: Int } """ ) original_print = print_schema(mutation_schema) extended_schema = extend_schema(mutation_schema, ast) assert extended_schema != mutation_schema assert print_schema(mutation_schema) == original_print assert print_schema(extended_schema) == dedent( """ type Query { queryField: String newQueryField: Int } type Mutation { mutationField: String newMutationField: Int } type Subscription { subscriptionField: String newSubscriptionField: Int } """ ) def may_extend_directives_with_new_directive(): schema = build_schema( """ type Query { foo: String } """ ) extension_sdl = dedent( ''' """New directive.""" directive @new(enable: Boolean!, tag: String) repeatable on QUERY | FIELD ''' ) extended_schema = extend_schema(schema, parse(extension_sdl)) assert validate_schema(extended_schema) == [] expect_schema_changes(schema, extended_schema, extension_sdl) def rejects_invalid_sdl(): schema = GraphQLSchema() extend_ast = parse("extend schema @unknown") with raises(TypeError) as exc_info: extend_schema(schema, extend_ast) assert str(exc_info.value) == "Unknown directive '@unknown'." def allows_to_disable_sdl_validation(): schema = GraphQLSchema() extend_ast = parse("extend schema @unknown") extend_schema(schema, extend_ast, assume_valid=True) extend_schema(schema, extend_ast, assume_valid_sdl=True) def throws_on_unknown_types(): schema = GraphQLSchema() ast = parse( """ type Query { unknown: UnknownType } """ ) with raises(TypeError) as exc_info: extend_schema(schema, ast, assume_valid_sdl=True) assert str(exc_info.value).endswith("Unknown type: 'UnknownType'.") def rejects_invalid_ast(): schema = GraphQLSchema() with raises(TypeError) as exc_info: # noinspection PyTypeChecker extend_schema(schema, None) # type: ignore assert str(exc_info.value) == "Must provide valid Document AST." with raises(TypeError) as exc_info: # noinspection PyTypeChecker extend_schema(schema, {}) # type: ignore assert str(exc_info.value) == "Must provide valid Document AST." def does_not_allow_replacing_a_default_directive(): schema = GraphQLSchema() extend_ast = parse( """ directive @include(if: Boolean!) on FIELD | FRAGMENT_SPREAD """ ) with raises(TypeError) as exc_info: extend_schema(schema, extend_ast) assert str(exc_info.value).startswith( "Directive '@include' already exists in the schema." " It cannot be redefined." ) def does_not_allow_replacing_an_existing_enum_value(): schema = build_schema( """ enum SomeEnum { ONE } """ ) extend_ast = parse( """ extend enum SomeEnum { ONE } """ ) with raises(TypeError) as exc_info: extend_schema(schema, extend_ast) assert str(exc_info.value).startswith( "Enum value 'SomeEnum.ONE' already exists in the schema." " It cannot also be defined in this type extension." ) def describe_can_add_additional_root_operation_types(): def does_not_automatically_include_common_root_type_names(): schema = GraphQLSchema() extended_schema = extend_schema(schema, parse("type Mutation")) assert extended_schema.get_type("Mutation") assert extended_schema.mutation_type is None def adds_schema_definition_missing_in_the_original_schema(): schema = build_schema( """ directive @foo on SCHEMA type Foo """ ) assert schema.query_type is None extension_sdl = dedent( """ schema @foo { query: Foo } """ ) extended_schema = extend_schema(schema, parse(extension_sdl)) query_type = assert_object_type(extended_schema.query_type) assert query_type.name == "Foo" expect_ast_node(extended_schema, extension_sdl) def adds_new_root_types_via_schema_extension(): schema = build_schema( """ type Query type MutationRoot """ ) extension_sdl = dedent( """ extend schema { mutation: MutationRoot } """ ) extended_schema = extend_schema(schema, parse(extension_sdl)) mutation_type = assert_object_type(extended_schema.mutation_type) assert mutation_type.name == "MutationRoot" expect_extension_ast_nodes(extended_schema, extension_sdl) def adds_directive_via_schema_extension(): schema = build_schema( """ type Query directive @foo on SCHEMA """ ) extension_sdl = dedent( """ extend schema @foo """ ) extended_schema = extend_schema(schema, parse(extension_sdl)) expect_extension_ast_nodes(extended_schema, extension_sdl) def adds_multiple_new_root_types_via_schema_extension(): schema = build_schema("type Query") extend_ast = parse( """ extend schema { mutation: Mutation subscription: Subscription } type Mutation type Subscription """ ) extended_schema = extend_schema(schema, extend_ast) mutation_type = assert_object_type(extended_schema.mutation_type) assert mutation_type.name == "Mutation" subscription_type = assert_object_type(extended_schema.subscription_type) assert subscription_type.name == "Subscription" def applies_multiple_schema_extensions(): schema = build_schema("type Query") extend_ast = parse( """ extend schema { mutation: Mutation } type Mutation extend schema { subscription: Subscription } type Subscription """ ) extended_schema = extend_schema(schema, extend_ast) mutation_type = assert_object_type(extended_schema.mutation_type) assert mutation_type.name == "Mutation" subscription_type = assert_object_type(extended_schema.subscription_type) assert subscription_type.name == "Subscription" def schema_extension_ast_are_available_from_schema_object(): schema = build_schema( """ type Query directive @foo on SCHEMA """ ) extend_ast = parse( """ extend schema { mutation: Mutation } type Mutation extend schema { subscription: Subscription } type Subscription """ ) extended_schema = extend_schema(schema, extend_ast) second_extend_ast = parse("extend schema @foo") extended_twice_schema = extend_schema(extended_schema, second_extend_ast) expect_extension_ast_nodes( extended_twice_schema, dedent( """ extend schema { mutation: Mutation } extend schema { subscription: Subscription } extend schema @foo """ ), ) graphql-core-3.2.6/tests/utilities/test_find_breaking_changes.py000066400000000000000000001103071474546154300251650ustar00rootroot00000000000000from graphql.type import ( GraphQLSchema, GraphQLDeprecatedDirective, GraphQLIncludeDirective, GraphQLSkipDirective, GraphQLSpecifiedByDirective, ) from graphql.utilities import ( BreakingChangeType, DangerousChangeType, build_schema, find_breaking_changes, find_dangerous_changes, ) def describe_find_breaking_changes(): def should_detect_if_a_type_was_removed_or_not(): old_schema = build_schema( """ type Type1 type Type2 """ ) new_schema = build_schema( """ type Type2 """ ) assert find_breaking_changes(old_schema, new_schema) == [ (BreakingChangeType.TYPE_REMOVED, "Type1 was removed.") ] assert find_breaking_changes(old_schema, old_schema) == [] def should_detect_if_a_standard_scalar_was_removed(): old_schema = build_schema( """ type Query { foo: Float } """ ) new_schema = build_schema( """ type Query { foo: String } """ ) assert find_breaking_changes(old_schema, new_schema) == [ ( BreakingChangeType.TYPE_REMOVED, "Standard scalar Float was removed" " because it is not referenced anymore.", ), ( BreakingChangeType.FIELD_CHANGED_KIND, "Query.foo changed type from Float to String.", ), ] def should_detect_if_a_type_changed_its_type(): old_schema = build_schema( """ scalar TypeWasScalarBecomesEnum interface TypeWasInterfaceBecomesUnion type TypeWasObjectBecomesInputObject """ ) new_schema = build_schema( """ enum TypeWasScalarBecomesEnum union TypeWasInterfaceBecomesUnion input TypeWasObjectBecomesInputObject """ ) assert find_breaking_changes(old_schema, new_schema) == [ ( BreakingChangeType.TYPE_CHANGED_KIND, "TypeWasScalarBecomesEnum changed from a Scalar type to an Enum type.", ), ( BreakingChangeType.TYPE_CHANGED_KIND, "TypeWasInterfaceBecomesUnion changed" " from an Interface type to a Union type.", ), ( BreakingChangeType.TYPE_CHANGED_KIND, "TypeWasObjectBecomesInputObject changed" " from an Object type to an Input type.", ), ] def should_detect_if_a_field_on_type_was_deleted_or_changed_type(): old_schema = build_schema( """ type TypeA type TypeB interface Type1 { field1: TypeA field2: String field3: String field4: TypeA field6: String field7: [String] field8: Int field9: Int! field10: [Int]! field11: Int field12: [Int] field13: [Int!] field14: [Int] field15: [[Int]] field16: Int! field17: [Int] field18: [[Int!]!] } """ ) new_schema = build_schema( """ type TypeA type TypeB interface Type1 { field1: TypeA field3: Boolean field4: TypeB field5: String field6: [String] field7: String field8: Int! field9: Int field10: [Int] field11: [Int]! field12: [Int!] field13: [Int] field14: [[Int]] field15: [Int] field16: [Int]! field17: [Int]! field18: [[Int!]] } """ ) assert find_breaking_changes(old_schema, new_schema) == [ (BreakingChangeType.FIELD_REMOVED, "Type1.field2 was removed."), ( BreakingChangeType.FIELD_CHANGED_KIND, "Type1.field3 changed type from String to Boolean.", ), ( BreakingChangeType.FIELD_CHANGED_KIND, "Type1.field4 changed type from TypeA to TypeB.", ), ( BreakingChangeType.FIELD_CHANGED_KIND, "Type1.field6 changed type from String to [String].", ), ( BreakingChangeType.FIELD_CHANGED_KIND, "Type1.field7 changed type from [String] to String.", ), ( BreakingChangeType.FIELD_CHANGED_KIND, "Type1.field9 changed type from Int! to Int.", ), ( BreakingChangeType.FIELD_CHANGED_KIND, "Type1.field10 changed type from [Int]! to [Int].", ), ( BreakingChangeType.FIELD_CHANGED_KIND, "Type1.field11 changed type from Int to [Int]!.", ), ( BreakingChangeType.FIELD_CHANGED_KIND, "Type1.field13 changed type from [Int!] to [Int].", ), ( BreakingChangeType.FIELD_CHANGED_KIND, "Type1.field14 changed type from [Int] to [[Int]].", ), ( BreakingChangeType.FIELD_CHANGED_KIND, "Type1.field15 changed type from [[Int]] to [Int].", ), ( BreakingChangeType.FIELD_CHANGED_KIND, "Type1.field16 changed type from Int! to [Int]!.", ), ( BreakingChangeType.FIELD_CHANGED_KIND, "Type1.field18 changed type from [[Int!]!] to [[Int!]].", ), ] def should_detect_if_fields_on_input_types_changed_kind_or_were_removed(): old_schema = build_schema( """ input InputType1 { field1: String field2: Boolean field3: [String] field4: String! field5: String field6: [Int] field7: [Int]! field8: Int field9: [Int] field10: [Int!] field11: [Int] field12: [[Int]] field13: Int! field14: [[Int]!] field15: [[Int]!] } """ ) new_schema = build_schema( """ input InputType1 { field1: Int field3: String field4: String field5: String! field6: [Int]! field7: [Int] field8: [Int]! field9: [Int!] field10: [Int] field11: [[Int]] field12: [Int] field13: [Int]! field14: [[Int]] field15: [[Int!]!] } """ ) assert find_breaking_changes(old_schema, new_schema) == [ (BreakingChangeType.FIELD_REMOVED, "InputType1.field2 was removed."), ( BreakingChangeType.FIELD_CHANGED_KIND, "InputType1.field1 changed type from String to Int.", ), ( BreakingChangeType.FIELD_CHANGED_KIND, "InputType1.field3 changed type from [String] to String.", ), ( BreakingChangeType.FIELD_CHANGED_KIND, "InputType1.field5 changed type from String to String!.", ), ( BreakingChangeType.FIELD_CHANGED_KIND, "InputType1.field6 changed type from [Int] to [Int]!.", ), ( BreakingChangeType.FIELD_CHANGED_KIND, "InputType1.field8 changed type from Int to [Int]!.", ), ( BreakingChangeType.FIELD_CHANGED_KIND, "InputType1.field9 changed type from [Int] to [Int!].", ), ( BreakingChangeType.FIELD_CHANGED_KIND, "InputType1.field11 changed type from [Int] to [[Int]].", ), ( BreakingChangeType.FIELD_CHANGED_KIND, "InputType1.field12 changed type from [[Int]] to [Int].", ), ( BreakingChangeType.FIELD_CHANGED_KIND, "InputType1.field13 changed type from Int! to [Int]!.", ), ( BreakingChangeType.FIELD_CHANGED_KIND, "InputType1.field15 changed type from [[Int]!] to [[Int!]!].", ), ] def should_detect_if_a_required_field_is_added_to_an_input_type(): old_schema = build_schema( """ input InputType1 { field1: String } """ ) new_schema = build_schema( """ input InputType1 { field1: String requiredField: Int! optionalField1: Boolean optionalField2: Boolean! = false } """ ) assert find_breaking_changes(old_schema, new_schema) == [ ( BreakingChangeType.REQUIRED_INPUT_FIELD_ADDED, "A required field requiredField on input type InputType1 was added.", ) ] def should_detect_if_a_type_was_removed_from_a_union_type(): old_schema = build_schema( """ type Type1 type Type2 type Type3 union UnionType1 = Type1 | Type2 """ ) new_schema = build_schema( """ type Type1 type Type2 type Type3 union UnionType1 = Type1 | Type3 """ ) assert find_breaking_changes(old_schema, new_schema) == [ ( BreakingChangeType.TYPE_REMOVED_FROM_UNION, "Type2 was removed from union type UnionType1.", ) ] def should_detect_if_a_value_was_removed_from_an_enum_type(): old_schema = build_schema( """ enum EnumType1 { VALUE0 VALUE1 VALUE2 } """ ) new_schema = build_schema( """ enum EnumType1 { VALUE0 VALUE2 VALUE3 } """ ) assert find_breaking_changes(old_schema, new_schema) == [ ( BreakingChangeType.VALUE_REMOVED_FROM_ENUM, "VALUE1 was removed from enum type EnumType1.", ) ] def should_detect_if_a_field_argument_was_removed(): old_schema = build_schema( """ interface Interface1 { field1(arg1: Boolean, objectArg: String): String } type Type1 { field1(name: String): String } """ ) new_schema = build_schema( """ interface Interface1 { field1: String } type Type1 { field1: String } """ ) assert find_breaking_changes(old_schema, new_schema) == [ (BreakingChangeType.ARG_REMOVED, "Interface1.field1 arg arg1 was removed."), ( BreakingChangeType.ARG_REMOVED, "Interface1.field1 arg objectArg was removed.", ), (BreakingChangeType.ARG_REMOVED, "Type1.field1 arg name was removed."), ] def should_detect_if_a_field_argument_has_changed_type(): old_schema = build_schema( """ type Type1 { field1( arg1: String arg2: String arg3: [String] arg4: String arg5: String! arg6: String! arg7: [Int]! arg8: Int arg9: [Int] arg10: [Int!] arg11: [Int] arg12: [[Int]] arg13: Int! arg14: [[Int]!] arg15: [[Int]!] ): String } """ ) new_schema = build_schema( """ type Type1 { field1( arg1: Int arg2: [String] arg3: String arg4: String! arg5: Int arg6: Int! arg7: [Int] arg8: [Int]! arg9: [Int!] arg10: [Int] arg11: [[Int]] arg12: [Int] arg13: [Int]! arg14: [[Int]] arg15: [[Int!]!] ): String } """ ) assert find_breaking_changes(old_schema, new_schema) == [ ( BreakingChangeType.ARG_CHANGED_KIND, "Type1.field1 arg arg1 has changed type from String to Int.", ), ( BreakingChangeType.ARG_CHANGED_KIND, "Type1.field1 arg arg2 has changed type from String to [String].", ), ( BreakingChangeType.ARG_CHANGED_KIND, "Type1.field1 arg arg3 has changed type from [String] to String.", ), ( BreakingChangeType.ARG_CHANGED_KIND, "Type1.field1 arg arg4 has changed type from String to String!.", ), ( BreakingChangeType.ARG_CHANGED_KIND, "Type1.field1 arg arg5 has changed type from String! to Int.", ), ( BreakingChangeType.ARG_CHANGED_KIND, "Type1.field1 arg arg6 has changed type from String! to Int!.", ), ( BreakingChangeType.ARG_CHANGED_KIND, "Type1.field1 arg arg8 has changed type from Int to [Int]!.", ), ( BreakingChangeType.ARG_CHANGED_KIND, "Type1.field1 arg arg9 has changed type from [Int] to [Int!].", ), ( BreakingChangeType.ARG_CHANGED_KIND, "Type1.field1 arg arg11 has changed type from [Int] to [[Int]].", ), ( BreakingChangeType.ARG_CHANGED_KIND, "Type1.field1 arg arg12 has changed type from [[Int]] to [Int].", ), ( BreakingChangeType.ARG_CHANGED_KIND, "Type1.field1 arg arg13 has changed type from Int! to [Int]!.", ), ( BreakingChangeType.ARG_CHANGED_KIND, "Type1.field1 arg arg15 has changed type from [[Int]!] to [[Int!]!].", ), ] def should_detect_if_a_required_field_argument_was_added(): old_schema = build_schema( """ type Type1 { field1(arg1: String): String } """ ) new_schema = build_schema( """ type Type1 { field1( arg1: String, newRequiredArg: String! newOptionalArg1: Int newOptionalArg2: Int! = 0 ): String } """ ) assert find_breaking_changes(old_schema, new_schema) == [ ( BreakingChangeType.REQUIRED_ARG_ADDED, "A required arg newRequiredArg on Type1.field1 was added.", ) ] def should_not_flag_args_with_the_same_type_signature_as_breaking(): old_schema = build_schema( """ input InputType1 { field1: String } type Type1 { field1(arg1: Int!, arg2: InputType1): Int } """ ) new_schema = build_schema( """ input InputType1 { field1: String } type Type1 { field1(arg1: Int!, arg2: InputType1): Int } """ ) assert find_breaking_changes(old_schema, new_schema) == [] def should_consider_args_that_move_away_from_non_null_as_non_breaking(): old_schema = build_schema( """ type Type1 { field1(name: String!): String } """ ) new_schema = build_schema( """ type Type1 { field1(name: String): String } """ ) assert find_breaking_changes(old_schema, new_schema) == [] def should_detect_interfaces_removed_from_types(): old_schema = build_schema( """ interface Interface1 type Type1 implements Interface1 """ ) new_schema = build_schema( """ interface Interface1 type Type1 """ ) assert find_breaking_changes(old_schema, new_schema) == [ ( BreakingChangeType.IMPLEMENTED_INTERFACE_REMOVED, "Type1 no longer implements interface Interface1.", ) ] def should_detect_intrefaces_removed_from_interfaces(): old_schema = build_schema( """ interface Interface1 interface Interface2 implements Interface1 """ ) new_schema = build_schema( """ interface Interface1 interface Interface2 """ ) assert find_breaking_changes(old_schema, new_schema) == [ ( BreakingChangeType.IMPLEMENTED_INTERFACE_REMOVED, "Interface2 no longer implements interface Interface1.", ) ] def should_ignore_changes_in_order_of_interfaces(): old_schema = build_schema( """ interface FirstInterface interface SecondInterface type Type1 implements FirstInterface & SecondInterface """ ) new_schema = build_schema( """ interface FirstInterface interface SecondInterface type Type1 implements SecondInterface & FirstInterface """ ) assert find_breaking_changes(old_schema, new_schema) == [] def should_detect_all_breaking_changes(): old_schema = build_schema( """ directive @DirectiveThatIsRemoved on FIELD_DEFINITION directive @DirectiveThatRemovesArg(arg1: String) on FIELD_DEFINITION directive @NonNullDirectiveAdded on FIELD_DEFINITION directive @DirectiveThatWasRepeatable repeatable on FIELD_DEFINITION directive @DirectiveName on FIELD_DEFINITION | QUERY type ArgThatChanges { field1(id: Float): String } enum EnumTypeThatLosesAValue { VALUE0 VALUE1 VALUE2 } interface Interface1 type TypeThatLoosesInterface1 implements Interface1 type TypeInUnion1 type TypeInUnion2 union UnionTypeThatLosesAType = TypeInUnion1 | TypeInUnion2 type TypeThatChangesType type TypeThatGetsRemoved interface TypeThatHasBreakingFieldChanges { field1: String field2: String } """ ) new_schema = build_schema( """ directive @DirectiveThatRemovesArg on FIELD_DEFINITION directive @NonNullDirectiveAdded(arg1: Boolean!) on FIELD_DEFINITION directive @DirectiveThatWasRepeatable on FIELD_DEFINITION directive @DirectiveName on FIELD_DEFINITION type ArgThatChanges { field1(id: String): String } enum EnumTypeThatLosesAValue { VALUE1 VALUE2 } interface Interface1 type TypeThatLoosesInterface1 type TypeInUnion1 type TypeInUnion2 union UnionTypeThatLosesAType = TypeInUnion1 interface TypeThatChangesType interface TypeThatHasBreakingFieldChanges { field2: Boolean } """ ) assert find_breaking_changes(old_schema, new_schema) == [ ( BreakingChangeType.TYPE_REMOVED, "Standard scalar Float was removed" " because it is not referenced anymore.", ), (BreakingChangeType.TYPE_REMOVED, "TypeThatGetsRemoved was removed."), ( BreakingChangeType.ARG_CHANGED_KIND, "ArgThatChanges.field1 arg id has changed type from Float to String.", ), ( BreakingChangeType.VALUE_REMOVED_FROM_ENUM, "VALUE0 was removed from enum type EnumTypeThatLosesAValue.", ), ( BreakingChangeType.IMPLEMENTED_INTERFACE_REMOVED, "TypeThatLoosesInterface1 no longer implements interface Interface1.", ), ( BreakingChangeType.TYPE_REMOVED_FROM_UNION, "TypeInUnion2 was removed from union type UnionTypeThatLosesAType.", ), ( BreakingChangeType.TYPE_CHANGED_KIND, "TypeThatChangesType changed from an Object type to an" " Interface type.", ), ( BreakingChangeType.FIELD_REMOVED, "TypeThatHasBreakingFieldChanges.field1 was removed.", ), ( BreakingChangeType.FIELD_CHANGED_KIND, "TypeThatHasBreakingFieldChanges.field2 changed type" " from String to Boolean.", ), ( BreakingChangeType.DIRECTIVE_REMOVED, "DirectiveThatIsRemoved was removed.", ), ( BreakingChangeType.DIRECTIVE_ARG_REMOVED, "arg1 was removed from DirectiveThatRemovesArg.", ), ( BreakingChangeType.REQUIRED_DIRECTIVE_ARG_ADDED, "A required arg arg1 on directive NonNullDirectiveAdded was added.", ), ( BreakingChangeType.DIRECTIVE_REPEATABLE_REMOVED, "Repeatable flag was removed from DirectiveThatWasRepeatable.", ), ( BreakingChangeType.DIRECTIVE_LOCATION_REMOVED, "QUERY was removed from DirectiveName.", ), ] def should_detect_if_a_directive_was_explicitly_removed(): old_schema = build_schema( """ directive @DirectiveThatIsRemoved on FIELD_DEFINITION directive @DirectiveThatStays on FIELD_DEFINITION """ ) new_schema = build_schema( """ directive @DirectiveThatStays on FIELD_DEFINITION """ ) assert find_breaking_changes(old_schema, new_schema) == [ ( BreakingChangeType.DIRECTIVE_REMOVED, "DirectiveThatIsRemoved was removed.", ) ] def should_detect_if_a_directive_was_implicitly_removed(): old_schema = GraphQLSchema() new_schema = GraphQLSchema( directives=[ GraphQLSkipDirective, GraphQLIncludeDirective, GraphQLSpecifiedByDirective, ] ) assert find_breaking_changes(old_schema, new_schema) == [ ( BreakingChangeType.DIRECTIVE_REMOVED, f"{GraphQLDeprecatedDirective.name} was removed.", ) ] def should_detect_if_a_directive_argument_was_removed(): old_schema = build_schema( """ directive @DirectiveWithArg(arg1: String) on FIELD_DEFINITION """ ) new_schema = build_schema( """ directive @DirectiveWithArg on FIELD_DEFINITION """ ) assert find_breaking_changes(old_schema, new_schema) == [ ( BreakingChangeType.DIRECTIVE_ARG_REMOVED, "arg1 was removed from DirectiveWithArg.", ) ] def should_detect_if_an_optional_directive_argument_was_added(): old_schema = build_schema( """ directive @DirectiveName on FIELD_DEFINITION """ ) new_schema = build_schema( """ directive @DirectiveName( newRequiredArg: String! newOptionalArg1: Int newOptionalArg2: Int! = 0 ) on FIELD_DEFINITION """ ) assert find_breaking_changes(old_schema, new_schema) == [ ( BreakingChangeType.REQUIRED_DIRECTIVE_ARG_ADDED, "A required arg newRequiredArg on directive DirectiveName was added.", ) ] def should_detect_removal_of_repeatable_flag(): old_schema = build_schema( """ directive @DirectiveName repeatable on OBJECT """ ) new_schema = build_schema( """ directive @DirectiveName on OBJECT """ ) assert find_breaking_changes(old_schema, new_schema) == [ ( BreakingChangeType.DIRECTIVE_REPEATABLE_REMOVED, "Repeatable flag was removed from DirectiveName.", ) ] def should_detect_locations_removed_from_a_directive(): old_schema = build_schema( """ directive @DirectiveName on FIELD_DEFINITION | QUERY """ ) new_schema = build_schema( """ directive @DirectiveName on FIELD_DEFINITION """ ) assert find_breaking_changes(old_schema, new_schema) == [ ( BreakingChangeType.DIRECTIVE_LOCATION_REMOVED, "QUERY was removed from DirectiveName.", ) ] def describe_find_dangerous_changes(): def should_detect_if_a_default_value_changed_on_an_argument(): old_sdl = """ input Input1 { innerInputArray: [Input2] } input Input2 { arrayField: [Int] } type Type1 { field1( withDefaultValue: String = "TO BE DELETED" stringArg: String = "test" emptyArray: [Int!] = [] valueArray: [[String]] = [["a", "b"], ["c"]] complexObject: Input1 = { innerInputArray: [{ arrayField: [1, 2, 3] }] } ): String } """ old_schema = build_schema(old_sdl) copy_of_old_schema = build_schema(old_sdl) assert find_dangerous_changes(old_schema, copy_of_old_schema) == [] new_schema = build_schema( """ input Input1 { innerInputArray: [Input2] } input Input2 { arrayField: [Int] } type Type1 { field1( withDefaultValue: String stringArg: String = "Test" emptyArray: [Int!] = [7] valueArray: [[String]] = [["b", "a"], ["d"]] complexObject: Input1 = { innerInputArray: [{ arrayField: [3, 2, 1] }] } ): String } """ ) assert find_dangerous_changes(old_schema, new_schema) == [ ( DangerousChangeType.ARG_DEFAULT_VALUE_CHANGE, "Type1.field1 arg withDefaultValue defaultValue was removed.", ), ( DangerousChangeType.ARG_DEFAULT_VALUE_CHANGE, "Type1.field1 arg stringArg has changed defaultValue" ' from "test" to "Test".', ), ( DangerousChangeType.ARG_DEFAULT_VALUE_CHANGE, "Type1.field1 arg emptyArray has changed defaultValue from [] to [7].", ), ( DangerousChangeType.ARG_DEFAULT_VALUE_CHANGE, "Type1.field1 arg valueArray has changed defaultValue" ' from [["a", "b"], ["c"]] to [["b", "a"], ["d"]].', ), ( DangerousChangeType.ARG_DEFAULT_VALUE_CHANGE, "Type1.field1 arg complexObject has changed defaultValue" " from {innerInputArray: [{arrayField: [1, 2, 3]}]}" " to {innerInputArray: [{arrayField: [3, 2, 1]}]}.", ), ] def should_ignore_changes_in_field_order_of_default_value(): old_schema = build_schema( """ input Input1 { a: String b: String c: String } type Type1 { field1( arg1: Input1 = { a: "a", b: "b", c: "c" } ): String } """ ) new_schema = build_schema( """ input Input1 { a: String b: String c: String } type Type1 { field1( arg1: Input1 = { c: "c", b: "b", a: "a" } ): String } """ ) assert find_dangerous_changes(old_schema, new_schema) == [] def should_ignore_changes_in_field_definitions_order(): old_schema = build_schema( """ input Input1 { a: String b: String c: String } type Type1 { field1( arg1: Input1 = { a: "a", b: "b", c: "c" } ): String } """ ) new_schema = build_schema( """ input Input1 { c: String b: String a: String } type Type1 { field1( arg1: Input1 = { a: "a", b: "b", c: "c" } ): String } """ ) assert find_dangerous_changes(old_schema, new_schema) == [] def should_detect_if_a_value_was_added_to_an_enum_type(): old_schema = build_schema( """ enum EnumType1 { VALUE0 VALUE1 } """ ) new_schema = build_schema( """ enum EnumType1 { VALUE0 VALUE1 VALUE2 } """ ) assert find_dangerous_changes(old_schema, new_schema) == [ ( DangerousChangeType.VALUE_ADDED_TO_ENUM, "VALUE2 was added to enum type EnumType1.", ) ] def should_detect_interfaces_added_to_types(): old_schema = build_schema( """ interface OldInterface interface NewInterface type Type1 implements OldInterface """ ) new_schema = build_schema( """ interface OldInterface interface NewInterface type Type1 implements OldInterface & NewInterface """ ) assert find_dangerous_changes(old_schema, new_schema) == [ ( DangerousChangeType.IMPLEMENTED_INTERFACE_ADDED, "NewInterface added to interfaces implemented by Type1.", ) ] def should_detect_interfaces_added_to_interfaces(): old_schema = build_schema( """ interface OldInterface interface NewInterface interface Interface1 implements OldInterface """ ) new_schema = build_schema( """ interface OldInterface interface NewInterface interface Interface1 implements OldInterface & NewInterface """ ) assert find_dangerous_changes(old_schema, new_schema) == [ ( DangerousChangeType.IMPLEMENTED_INTERFACE_ADDED, "NewInterface added to interfaces implemented by Interface1.", ) ] def should_detect_if_a_type_was_added_to_a_union_type(): old_schema = build_schema( """ type Type1 type Type2 union UnionType1 = Type1 """ ) new_schema = build_schema( """ type Type1 type Type2 union UnionType1 = Type1 | Type2 """ ) assert find_dangerous_changes(old_schema, new_schema) == [ ( DangerousChangeType.TYPE_ADDED_TO_UNION, "Type2 was added to union type UnionType1.", ) ] def should_detect_if_an_optional_field_was_added_to_an_input(): old_schema = build_schema( """ input InputType1 { field1: String } """ ) new_schema = build_schema( """ input InputType1 { field1: String field2: Int } """ ) assert find_dangerous_changes(old_schema, new_schema) == [ ( DangerousChangeType.OPTIONAL_INPUT_FIELD_ADDED, "An optional field field2 on input type InputType1 was added.", ) ] def should_find_all_dangerous_changes(): old_schema = build_schema( """ enum EnumType1 { VALUE0 VALUE1 } type Type1 { field1(argThatChangesDefaultValue: String = "test"): String } interface Interface1 type TypeThatGainsInterface1 type TypeInUnion1 union UnionTypeThatGainsAType = TypeInUnion1 """ ) new_schema = build_schema( """ enum EnumType1 { VALUE0 VALUE1 VALUE2 } type Type1 { field1(argThatChangesDefaultValue: String = "Test"): String } interface Interface1 type TypeThatGainsInterface1 implements Interface1 type TypeInUnion1 type TypeInUnion2 union UnionTypeThatGainsAType = TypeInUnion1 | TypeInUnion2 """ ) assert find_dangerous_changes(old_schema, new_schema) == [ ( DangerousChangeType.VALUE_ADDED_TO_ENUM, "VALUE2 was added to enum type EnumType1.", ), ( DangerousChangeType.ARG_DEFAULT_VALUE_CHANGE, "Type1.field1 arg argThatChangesDefaultValue has changed defaultValue" ' from "test" to "Test".', ), ( DangerousChangeType.IMPLEMENTED_INTERFACE_ADDED, "Interface1 added to interfaces implemented" " by TypeThatGainsInterface1.", ), ( DangerousChangeType.TYPE_ADDED_TO_UNION, "TypeInUnion2 was added to union type UnionTypeThatGainsAType.", ), ] def should_detect_if_an_optional_field_argument_was_added(): old_schema = build_schema( """ type Type1 { field1(arg1: String): String } """ ) new_schema = build_schema( """ type Type1 { field1(arg1: String, arg2: String): String } """ ) assert find_dangerous_changes(old_schema, new_schema) == [ ( DangerousChangeType.OPTIONAL_ARG_ADDED, "An optional arg arg2 on Type1.field1 was added.", ) ] graphql-core-3.2.6/tests/utilities/test_get_introspection_query.py000066400000000000000000000064141474546154300257020ustar00rootroot00000000000000import re from typing import Pattern from graphql.language import parse from graphql.utilities import build_schema, get_introspection_query from graphql.validation import validate dummy_schema = build_schema( """ type Query { dummy: String } """ ) class ExcpectIntrospectionQuery: def __init__(self, **options): query = get_introspection_query(**options) validation_errors = validate(dummy_schema, parse(query)) assert validation_errors == [] self.query = query def to_match(self, name: str, times: int = 1) -> None: pattern = self.to_reg_exp(name) assert len(pattern.findall(self.query)) == times def to_not_match(self, name: str) -> None: pattern = self.to_reg_exp(name) assert not pattern.search(self.query) @staticmethod def to_reg_exp(name: str) -> Pattern: return re.compile(rf"\b{name}\b") def describe_get_introspection_query(): def skips_all_description_fields(): ExcpectIntrospectionQuery().to_match("description", 5) ExcpectIntrospectionQuery(descriptions=True).to_match("description", 5) ExcpectIntrospectionQuery(descriptions=False).to_not_match("description") def includes_is_repeatable_field_on_directives(): ExcpectIntrospectionQuery().to_not_match("isRepeatable") ExcpectIntrospectionQuery(directive_is_repeatable=True).to_match("isRepeatable") ExcpectIntrospectionQuery(directive_is_repeatable=False).to_not_match( "isRepeatable" ) def includes_description_field_on_schema(): ExcpectIntrospectionQuery().to_match("description", 5) ExcpectIntrospectionQuery(schema_description=False).to_match("description", 5) ExcpectIntrospectionQuery(schema_description=True).to_match("description", 6) ExcpectIntrospectionQuery( descriptions=False, schema_description=True ).to_not_match("description") def includes_specified_by_url_field(): ExcpectIntrospectionQuery().to_not_match("specifiedByURL") ExcpectIntrospectionQuery(specified_by_url=True).to_match("specifiedByURL") ExcpectIntrospectionQuery(specified_by_url=False).to_not_match("specifiedByURL") def includes_is_deprecated_field_on_input_values(): ExcpectIntrospectionQuery().to_match("isDeprecated", 2) ExcpectIntrospectionQuery(input_value_deprecation=True).to_match( "isDeprecated", 3 ) ExcpectIntrospectionQuery(input_value_deprecation=False).to_match( "isDeprecated", 2 ) def includes_deprecation_reason_field_on_input_values(): ExcpectIntrospectionQuery().to_match("deprecationReason", 2) ExcpectIntrospectionQuery(input_value_deprecation=True).to_match( "deprecationReason", 3 ) ExcpectIntrospectionQuery(input_value_deprecation=False).to_match( "deprecationReason", 2 ) def includes_deprecated_input_field_and_args(): ExcpectIntrospectionQuery().to_match("includeDeprecated: true", 2) ExcpectIntrospectionQuery(input_value_deprecation=True).to_match( "includeDeprecated: true", 5 ) ExcpectIntrospectionQuery(input_value_deprecation=False).to_match( "includeDeprecated: true", 2 ) graphql-core-3.2.6/tests/utilities/test_get_operation_ast.py000066400000000000000000000037051474546154300244240ustar00rootroot00000000000000from graphql.language import parse from graphql.utilities import get_operation_ast def describe_get_operation_ast(): def gets_an_operation_from_a_simple_document(): doc = parse("{ field }") assert get_operation_ast(doc) == doc.definitions[0] def gets_an_operation_from_a_document_with_named_op_mutation(): doc = parse("mutation Test { field }") assert get_operation_ast(doc) == doc.definitions[0] def gets_an_operation_from_a_document_with_named_op_subscription(): doc = parse("subscription Test { field }") assert get_operation_ast(doc) == doc.definitions[0] def does_not_get_missing_operation(): doc = parse("type Foo { field: String }") assert get_operation_ast(doc) is None def does_not_get_ambiguous_unnamed_operation(): doc = parse( """ { field } mutation Test { field } subscription TestSub { field } """ ) assert get_operation_ast(doc) is None def does_not_get_ambiguous_named_operation(): doc = parse( """ query TestQ { field } mutation TestM { field } subscription TestS { field } """ ) assert get_operation_ast(doc) is None def does_not_get_misnamed_operation(): doc = parse( """ query TestQ { field } mutation TestM { field } subscription TestS { field } """ ) assert get_operation_ast(doc, "Unknown") is None def gets_named_operation(): doc = parse( """ query TestQ { field } mutation TestM { field } subscription TestS { field } """ ) assert get_operation_ast(doc, "TestQ") == doc.definitions[0] assert get_operation_ast(doc, "TestM") == doc.definitions[1] assert get_operation_ast(doc, "TestS") == doc.definitions[2] graphql-core-3.2.6/tests/utilities/test_get_operation_root_type.py000066400000000000000000000112721474546154300256570ustar00rootroot00000000000000from pytest import raises from graphql.error import GraphQLError from graphql.language import ( parse, DocumentNode, OperationDefinitionNode, OperationTypeDefinitionNode, SchemaDefinitionNode, ) from graphql.type import GraphQLField, GraphQLObjectType, GraphQLSchema, GraphQLString from graphql.utilities import get_operation_root_type query_type = GraphQLObjectType("FooQuery", {"field": GraphQLField(GraphQLString)}) mutation_type = GraphQLObjectType("FooMutation", {"field": GraphQLField(GraphQLString)}) subscription_type = GraphQLObjectType( "FooSubscription", {"field": GraphQLField(GraphQLString)} ) def get_operation_node(doc: DocumentNode) -> OperationDefinitionNode: operation_node = doc.definitions[0] assert isinstance(operation_node, OperationDefinitionNode) return operation_node def describe_deprecated_get_operation_root_type(): def gets_a_query_type_for_an_unnamed_operation_definition_node(): test_schema = GraphQLSchema(query_type) doc = parse("{ field }") operation_node = get_operation_node(doc) assert get_operation_root_type(test_schema, operation_node) is query_type def gets_a_query_type_for_a_named_operation_definition_node(): test_schema = GraphQLSchema(query_type) doc = parse("query Q { field }") operation_node = get_operation_node(doc) assert get_operation_root_type(test_schema, operation_node) is query_type def gets_a_type_for_operation_definition_nodes(): test_schema = GraphQLSchema(query_type, mutation_type, subscription_type) doc = parse( """ schema { query: FooQuery mutation: FooMutation subscription: FooSubscription } """ ) schema_node = doc.definitions[0] assert isinstance(schema_node, SchemaDefinitionNode) query_node, mutation_node, subscription_node = schema_node.operation_types assert isinstance(query_node, OperationTypeDefinitionNode) assert get_operation_root_type(test_schema, query_node) is query_type assert isinstance(mutation_node, OperationTypeDefinitionNode) assert get_operation_root_type(test_schema, mutation_node) is mutation_type assert isinstance(subscription_node, OperationTypeDefinitionNode) assert ( get_operation_root_type(test_schema, subscription_node) is subscription_type ) def gets_a_mutation_type_for_an_operation_definition_node(): test_schema = GraphQLSchema(mutation=mutation_type) doc = parse("mutation { field }") operation_node = get_operation_node(doc) assert get_operation_root_type(test_schema, operation_node) is mutation_type def gets_a_subscription_type_for_an_operation_definition_node(): test_schema = GraphQLSchema(subscription=subscription_type) doc = parse("subscription { field }") operation_node = get_operation_node(doc) assert get_operation_root_type(test_schema, operation_node) is subscription_type def throws_when_query_type_not_defined_in_schema(): test_schema = GraphQLSchema() doc = parse("query { field }") operation_node = get_operation_node(doc) with raises(GraphQLError) as exc_info: get_operation_root_type(test_schema, operation_node) assert exc_info.value.message == ( "Schema does not define the required query root type." ) def throws_when_mutation_type_not_defined_in_schema(): test_schema = GraphQLSchema() doc = parse("mutation { field }") operation_node = get_operation_node(doc) with raises(GraphQLError) as exc_info: get_operation_root_type(test_schema, operation_node) assert exc_info.value.message == "Schema is not configured for mutations." def throws_when_subscription_type_not_defined_in_schema(): test_schema = GraphQLSchema() doc = parse("subscription { field }") operation_node = get_operation_node(doc) with raises(GraphQLError) as exc_info: get_operation_root_type(test_schema, operation_node) assert exc_info.value.message == "Schema is not configured for subscriptions." def throws_when_operation_not_a_valid_operation_kind(): test_schema = GraphQLSchema() doc = parse("{ field }") operation_node = get_operation_node(doc) operation_node.operation = "non_existent_operation" # type: ignore with raises(GraphQLError) as exc_info: get_operation_root_type(test_schema, operation_node) assert exc_info.value.message == ( "Can only have query, mutation and subscription operations." ) graphql-core-3.2.6/tests/utilities/test_introspection_from_schema.py000066400000000000000000000031021474546154300261500ustar00rootroot00000000000000from graphql.type import GraphQLSchema, GraphQLObjectType, GraphQLField, GraphQLString from graphql.utilities import ( build_client_schema, print_schema, introspection_from_schema, IntrospectionQuery, ) from ..utils import dedent def introspection_to_sdl(introspection: IntrospectionQuery) -> str: return print_schema(build_client_schema(introspection)) def describe_introspection_from_schema(): schema = GraphQLSchema( GraphQLObjectType( "Simple", { "string": GraphQLField( GraphQLString, description="This is a string field" ) }, description="This is a simple type", ), description="This is a simple schema", ) def converts_a_simple_schema(): introspection = introspection_from_schema(schema) assert introspection_to_sdl(introspection) == dedent( ''' """This is a simple schema""" schema { query: Simple } """This is a simple type""" type Simple { """This is a string field""" string: String } ''' ) def converts_a_simple_schema_without_description(): introspection = introspection_from_schema(schema, descriptions=False) assert introspection_to_sdl(introspection) == dedent( """ schema { query: Simple } type Simple { string: String } """ ) graphql-core-3.2.6/tests/utilities/test_lexicographic_sort_schema.py000066400000000000000000000172211474546154300261240ustar00rootroot00000000000000from graphql.utilities import build_schema, print_schema, lexicographic_sort_schema from ..utils import dedent def sort_sdl(sdl: str) -> str: schema = build_schema(sdl) return print_schema(lexicographic_sort_schema(schema)) def describe_lexicographic_sort_schema(): def sort_fields(): sorted_sdl = sort_sdl( """ input Bar { barB: String! barA: String barC: [String] } interface FooInterface { fooB: String! fooA: String fooC: [String] } type FooType implements FooInterface { fooC: [String] fooA: String fooB: String! } type Query { dummy(arg: Bar): FooType } """ ) assert sorted_sdl == dedent( """ input Bar { barA: String barB: String! barC: [String] } interface FooInterface { fooA: String fooB: String! fooC: [String] } type FooType implements FooInterface { fooA: String fooB: String! fooC: [String] } type Query { dummy(arg: Bar): FooType } """ ) def sort_implemented_interfaces(): sorted_sdl = sort_sdl( """ interface FooA { dummy: String } interface FooB { dummy: String } interface FooC implements FooB & FooA { dummy: String } type Query implements FooB & FooA & FooC { dummy: String } """ ) assert sorted_sdl == dedent( """ interface FooA { dummy: String } interface FooB { dummy: String } interface FooC implements FooA & FooB { dummy: String } type Query implements FooA & FooB & FooC { dummy: String } """ ) def sort_types_in_union(): sorted_sdl = sort_sdl( """ type FooA { dummy: String } type FooB { dummy: String } type FooC { dummy: String } union FooUnion = FooB | FooA | FooC type Query { dummy: FooUnion } """ ) assert sorted_sdl == dedent( """ type FooA { dummy: String } type FooB { dummy: String } type FooC { dummy: String } union FooUnion = FooA | FooB | FooC type Query { dummy: FooUnion } """ ) def sort_enum_types(): sorted_sdl = sort_sdl( """ enum Foo { B C A } type Query { dummy: Foo } """ ) assert sorted_sdl == dedent( """ enum Foo { A B C } type Query { dummy: Foo } """ ) def sort_field_arguments(): sorted_sdl = sort_sdl( """ type Query { dummy(argB: Int!, argA: String, argC: [Float]): ID } """ ) assert sorted_sdl == dedent( """ type Query { dummy(argA: String, argB: Int!, argC: [Float]): ID } """ ) def sort_types(): sorted_sdl = sort_sdl( """ type Query { dummy(arg1: FooF, arg2: FooA, arg3: FooG): FooD } type FooC implements FooE { dummy: String } enum FooG { enumValue } scalar FooA input FooF { dummy: String } union FooD = FooC | FooB interface FooE { dummy: String } type FooB { dummy: String } """ ) assert sorted_sdl == dedent( """ scalar FooA type FooB { dummy: String } type FooC implements FooE { dummy: String } union FooD = FooB | FooC interface FooE { dummy: String } input FooF { dummy: String } enum FooG { enumValue } type Query { dummy(arg1: FooF, arg2: FooA, arg3: FooG): FooD } """ ) def sort_directive_arguments(): sorted_sdl = sort_sdl( """ directive @test(argC: Float, argA: String, argB: Int) on FIELD type Query { dummy: String } """ ) assert sorted_sdl == dedent( """ directive @test(argA: String, argB: Int, argC: Float) on FIELD type Query { dummy: String } """ ) def sort_directive_locations(): sorted_sdl = sort_sdl( """ directive @test(argC: Float, argA: String, argB: Int) on UNION | FIELD | ENUM type Query { dummy: String } """ # noqa: E501 ) assert sorted_sdl == dedent( """ directive @test(argA: String, argB: Int, argC: Float) on ENUM | FIELD | UNION type Query { dummy: String } """ # noqa: E501 ) def sort_directives(): sorted_sdl = sort_sdl( """ directive @fooC on FIELD directive @fooB on UNION directive @fooA on ENUM type Query { dummy: String } """ ) assert sorted_sdl == dedent( """ directive @fooA on ENUM directive @fooB on UNION directive @fooC on FIELD type Query { dummy: String } """ ) def sort_recursive_types(): sorted_sdl = sort_sdl( """ interface FooC { fooB: FooB fooA: FooA fooC: FooC } type FooB implements FooC { fooB: FooB fooA: FooA } type FooA implements FooC { fooB: FooB fooA: FooA } type Query { fooC: FooC fooB: FooB fooA: FooA } """ ) assert sorted_sdl == dedent( """ type FooA implements FooC { fooA: FooA fooB: FooB } type FooB implements FooC { fooA: FooA fooB: FooB } interface FooC { fooA: FooA fooB: FooB fooC: FooC } type Query { fooA: FooA fooB: FooB fooC: FooC } """ ) graphql-core-3.2.6/tests/utilities/test_print_schema.py000066400000000000000000000642731474546154300234010ustar00rootroot00000000000000from typing import Any, Dict, cast from graphql.language import DirectiveLocation from graphql.type import ( GraphQLArgument, GraphQLBoolean, GraphQLDirective, GraphQLEnumType, GraphQLField, GraphQLFloat, GraphQLInputField, GraphQLInputObjectType, GraphQLInt, GraphQLInterfaceType, GraphQLList, GraphQLNonNull, GraphQLObjectType, GraphQLScalarType, GraphQLSchema, GraphQLString, GraphQLUnionType, ) from graphql.utilities import ( build_schema, print_introspection_schema, print_schema, print_value, ) from ..utils import dedent def expect_printed_schema(schema: GraphQLSchema) -> str: schema_text = print_schema(schema) # keep print_schema and build_schema in sync assert print_schema(build_schema(schema_text)) == schema_text return schema_text def build_single_field_schema(field: GraphQLField): query = GraphQLObjectType(name="Query", fields={"singleField": field}) return GraphQLSchema(query=query) def describe_type_system_printer(): def prints_string_field(): schema = build_single_field_schema(GraphQLField(GraphQLString)) assert expect_printed_schema(schema) == dedent( """ type Query { singleField: String } """ ) def prints_list_of_string_field(): schema = build_single_field_schema(GraphQLField(GraphQLList(GraphQLString))) assert expect_printed_schema(schema) == dedent( """ type Query { singleField: [String] } """ ) def prints_non_null_string_field(): schema = build_single_field_schema(GraphQLField(GraphQLNonNull(GraphQLString))) assert expect_printed_schema(schema) == dedent( """ type Query { singleField: String! } """ ) def prints_non_null_list_of_string_field(): schema = build_single_field_schema( GraphQLField(GraphQLNonNull(GraphQLList(GraphQLString))) ) assert expect_printed_schema(schema) == dedent( """ type Query { singleField: [String]! } """ ) def prints_list_of_non_null_string_field(): schema = build_single_field_schema( GraphQLField((GraphQLList(GraphQLNonNull(GraphQLString)))) ) assert expect_printed_schema(schema) == dedent( """ type Query { singleField: [String!] } """ ) def prints_non_null_list_of_non_null_string_field(): schema = build_single_field_schema( GraphQLField(GraphQLNonNull(GraphQLList(GraphQLNonNull(GraphQLString)))) ) assert expect_printed_schema(schema) == dedent( """ type Query { singleField: [String!]! } """ ) def prints_object_field(): foo_type = GraphQLObjectType( name="Foo", fields={"str": GraphQLField(GraphQLString)} ) schema = GraphQLSchema(types=[foo_type]) assert expect_printed_schema(schema) == dedent( """ type Foo { str: String } """ ) def prints_string_field_with_int_arg(): schema = build_single_field_schema( GraphQLField( type_=GraphQLString, args={"argOne": GraphQLArgument(GraphQLInt)} ) ) assert expect_printed_schema(schema) == dedent( """ type Query { singleField(argOne: Int): String } """ ) def prints_string_field_with_int_arg_with_default(): schema = build_single_field_schema( GraphQLField( type_=GraphQLString, args={"argOne": GraphQLArgument(GraphQLInt, default_value=2)}, ) ) assert expect_printed_schema(schema) == dedent( """ type Query { singleField(argOne: Int = 2): String } """ ) def prints_string_field_with_string_arg_with_default(): schema = build_single_field_schema( GraphQLField( type_=GraphQLString, args={ "argOne": GraphQLArgument( GraphQLString, default_value="tes\t de\fault" ) }, ) ) assert expect_printed_schema(schema) == dedent( r""" type Query { singleField(argOne: String = "tes\t de\fault"): String } """ ) def prints_string_field_with_int_arg_with_default_null(): schema = build_single_field_schema( GraphQLField( type_=GraphQLString, args={"argOne": GraphQLArgument(GraphQLInt, default_value=None)}, ) ) assert expect_printed_schema(schema) == dedent( """ type Query { singleField(argOne: Int = null): String } """ ) def prints_string_field_with_non_null_int_arg(): schema = build_single_field_schema( GraphQLField( type_=GraphQLString, args={"argOne": GraphQLArgument(GraphQLNonNull(GraphQLInt))}, ) ) assert expect_printed_schema(schema) == dedent( """ type Query { singleField(argOne: Int!): String } """ ) def prints_string_field_with_multiple_args(): schema = build_single_field_schema( GraphQLField( type_=GraphQLString, args={ "argOne": GraphQLArgument(GraphQLInt), "argTwo": GraphQLArgument(GraphQLString), }, ) ) assert expect_printed_schema(schema) == dedent( """ type Query { singleField(argOne: Int, argTwo: String): String } """ ) def prints_string_field_with_multiple_args_first_is_default(): schema = build_single_field_schema( GraphQLField( type_=GraphQLString, args={ "argOne": GraphQLArgument(GraphQLInt, default_value=1), "argTwo": GraphQLArgument(GraphQLString), "argThree": GraphQLArgument(GraphQLBoolean), }, ) ) assert expect_printed_schema(schema) == dedent( """ type Query { singleField(argOne: Int = 1, argTwo: String, argThree: Boolean): String } """ ) def prints_string_field_with_multiple_args_second_is_default(): schema = build_single_field_schema( GraphQLField( type_=GraphQLString, args={ "argOne": GraphQLArgument(GraphQLInt), "argTwo": GraphQLArgument(GraphQLString, default_value="foo"), "argThree": GraphQLArgument(GraphQLBoolean), }, ) ) assert expect_printed_schema(schema) == dedent( """ type Query { singleField(argOne: Int, argTwo: String = "foo", argThree: Boolean): String } """ # noqa: E501 ) def prints_string_field_with_multiple_args_last_is_default(): schema = build_single_field_schema( GraphQLField( type_=GraphQLString, args={ "argOne": GraphQLArgument(GraphQLInt), "argTwo": GraphQLArgument(GraphQLString), "argThree": GraphQLArgument(GraphQLBoolean, default_value=False), }, ) ) assert expect_printed_schema(schema) == dedent( """ type Query { singleField(argOne: Int, argTwo: String, argThree: Boolean = false): String } """ # noqa: E501 ) def prints_schema_with_description(): schema = GraphQLSchema( description="Schema description.", query=GraphQLObjectType("Query", {}) ) assert expect_printed_schema(schema) == dedent( ''' """Schema description.""" schema { query: Query } type Query ''' ) def omits_schema_of_common_names(): schema = GraphQLSchema( query=GraphQLObjectType("Query", {}), mutation=GraphQLObjectType("Mutation", {}), subscription=GraphQLObjectType("Subscription", {}), ) assert expect_printed_schema(schema) == dedent( """ type Query type Mutation type Subscription """ ) def prints_custom_query_root_types(): schema = GraphQLSchema(query=GraphQLObjectType("CustomType", {})) assert expect_printed_schema(schema) == dedent( """ schema { query: CustomType } type CustomType """ ) def prints_custom_mutation_root_types(): schema = GraphQLSchema(mutation=GraphQLObjectType("CustomType", {})) assert expect_printed_schema(schema) == dedent( """ schema { mutation: CustomType } type CustomType """ ) def prints_custom_subscription_root_types(): schema = GraphQLSchema(subscription=GraphQLObjectType("CustomType", {})) assert expect_printed_schema(schema) == dedent( """ schema { subscription: CustomType } type CustomType """ ) def prints_interface(): foo_type = GraphQLInterfaceType( name="Foo", fields={"str": GraphQLField(GraphQLString)} ) bar_type = GraphQLObjectType( name="Bar", fields={"str": GraphQLField(GraphQLString)}, interfaces=[foo_type], ) schema = GraphQLSchema(types=[bar_type]) assert expect_printed_schema(schema) == dedent( """ type Bar implements Foo { str: String } interface Foo { str: String } """ ) def prints_multiple_interfaces(): foo_type = GraphQLInterfaceType( name="Foo", fields={"str": GraphQLField(GraphQLString)} ) baz_type = GraphQLInterfaceType( name="Baz", fields={"int": GraphQLField(GraphQLInt)} ) bar_type = GraphQLObjectType( name="Bar", fields={ "str": GraphQLField(GraphQLString), "int": GraphQLField(GraphQLInt), }, interfaces=[foo_type, baz_type], ) schema = GraphQLSchema(types=[bar_type]) assert expect_printed_schema(schema) == dedent( """ type Bar implements Foo & Baz { str: String int: Int } interface Foo { str: String } interface Baz { int: Int } """ ) def prints_hierarchical_interface(): foo_type = GraphQLInterfaceType( name="Foo", fields={"str": GraphQLField(GraphQLString)} ) baz_type = GraphQLInterfaceType( name="Baz", interfaces=[foo_type], fields={ "int": GraphQLField(GraphQLInt), "str": GraphQLField(GraphQLString), }, ) bar_type = GraphQLObjectType( name="Bar", fields={ "str": GraphQLField(GraphQLString), "int": GraphQLField(GraphQLInt), }, interfaces=[foo_type, baz_type], ) query = GraphQLObjectType(name="Query", fields={"bar": GraphQLField(bar_type)}) schema = GraphQLSchema(query, types=[bar_type]) assert expect_printed_schema(schema) == dedent( """ type Bar implements Foo & Baz { str: String int: Int } interface Foo { str: String } interface Baz implements Foo { int: Int str: String } type Query { bar: Bar } """ ) def prints_unions(): foo_type = GraphQLObjectType( name="Foo", fields={"bool": GraphQLField(GraphQLBoolean)} ) bar_type = GraphQLObjectType( name="Bar", fields={"str": GraphQLField(GraphQLString)} ) single_union = GraphQLUnionType(name="SingleUnion", types=[foo_type]) multiple_union = GraphQLUnionType( name="MultipleUnion", types=[foo_type, bar_type] ) schema = GraphQLSchema(types=[single_union, multiple_union]) assert expect_printed_schema(schema) == dedent( """ union SingleUnion = Foo type Foo { bool: Boolean } union MultipleUnion = Foo | Bar type Bar { str: String } """ ) def prints_input_type(): input_type = GraphQLInputObjectType( name="InputType", fields={"int": GraphQLInputField(GraphQLInt)} ) schema = GraphQLSchema(types=[input_type]) assert expect_printed_schema(schema) == dedent( """ input InputType { int: Int } """ ) def prints_custom_scalar(): odd_type = GraphQLScalarType(name="Odd") schema = GraphQLSchema(types=[odd_type]) assert expect_printed_schema(schema) == dedent( """ scalar Odd """ ) def prints_custom_scalar_with_specified_by_url(): foo_type = GraphQLScalarType( name="Foo", specified_by_url="https://example.com/foo_spec" ) schema = GraphQLSchema(types=[foo_type]) assert expect_printed_schema(schema) == dedent( """ scalar Foo @specifiedBy(url: "https://example.com/foo_spec") """ ) def prints_enum(): rgb_type = GraphQLEnumType( name="RGB", values=dict.fromkeys(("RED", "GREEN", "BLUE")) ) schema = GraphQLSchema(types=[rgb_type]) assert expect_printed_schema(schema) == dedent( """ enum RGB { RED GREEN BLUE } """ ) def prints_empty_types(): schema = GraphQLSchema( types=[ GraphQLEnumType("SomeEnum", cast(Dict[str, Any], {})), GraphQLInputObjectType("SomeInputObject", {}), GraphQLInterfaceType("SomeInterface", {}), GraphQLObjectType("SomeObject", {}), GraphQLUnionType("SomeUnion", []), ] ) assert expect_printed_schema(schema) == dedent( """ enum SomeEnum input SomeInputObject interface SomeInterface type SomeObject union SomeUnion """ ) def prints_custom_directives(): simple_directive = GraphQLDirective( "simpleDirective", [DirectiveLocation.FIELD] ) complex_directive = GraphQLDirective( "complexDirective", [DirectiveLocation.FIELD, DirectiveLocation.QUERY], description="Complex Directive", args={ "stringArg": GraphQLArgument(GraphQLString), "intArg": GraphQLArgument(GraphQLInt, default_value=-1), }, is_repeatable=True, ) schema = GraphQLSchema(directives=[simple_directive, complex_directive]) assert expect_printed_schema(schema) == dedent( ''' directive @simpleDirective on FIELD """Complex Directive""" directive @complexDirective(stringArg: String, intArg: Int = -1) repeatable on FIELD | QUERY ''' # noqa: E501 ) def prints_an_empty_description(): schema = build_single_field_schema(GraphQLField(GraphQLString, description="")) assert expect_printed_schema(schema) == dedent( ''' type Query { """""" singleField: String } ''' ) def prints_a_description_with_only_whitespace(): schema = build_single_field_schema(GraphQLField(GraphQLString, description=" ")) assert expect_printed_schema(schema) == dedent( """ type Query { " " singleField: String } """ ) def one_line_prints_a_short_description(): schema = build_single_field_schema( GraphQLField(GraphQLString, description="This field is awesome") ) assert expect_printed_schema(schema) == dedent( ''' type Query { """This field is awesome""" singleField: String } ''' ) def prints_introspection_schema(): schema = GraphQLSchema() output = print_introspection_schema(schema) assert output == dedent( ''' """ Directs the executor to include this field or fragment only when the `if` argument is true. """ directive @include( """Included when true.""" if: Boolean! ) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT """ Directs the executor to skip this field or fragment when the `if` argument is true. """ directive @skip( """Skipped when true.""" if: Boolean! ) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT """Marks an element of a GraphQL schema as no longer supported.""" directive @deprecated( """ Explains why this element was deprecated, usually also including a suggestion for how to access supported similar data. Formatted using the Markdown syntax, as specified by [CommonMark](https://commonmark.org/). """ reason: String = "No longer supported" ) on FIELD_DEFINITION | ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION | ENUM_VALUE """Exposes a URL that specifies the behavior of this scalar.""" directive @specifiedBy( """The URL that specifies the behavior of this scalar.""" url: String! ) on SCALAR """ A GraphQL Schema defines the capabilities of a GraphQL server. It exposes all available types and directives on the server, as well as the entry points for query, mutation, and subscription operations. """ type __Schema { description: String """A list of all types supported by this server.""" types: [__Type!]! """The type that query operations will be rooted at.""" queryType: __Type! """ If this server supports mutation, the type that mutation operations will be rooted at. """ mutationType: __Type """ If this server support subscription, the type that subscription operations will be rooted at. """ subscriptionType: __Type """A list of all directives supported by this server.""" directives: [__Directive!]! } """ The fundamental unit of any GraphQL Schema is the type. There are many kinds of types in GraphQL as represented by the `__TypeKind` enum. Depending on the kind of a type, certain fields describe information about that type. Scalar types provide no information beyond a name, description and optional `specifiedByURL`, while Enum types provide their values. Object and Interface types provide the fields they describe. Abstract types, Union and Interface, provide the Object types possible at runtime. List and NonNull types compose other types. """ type __Type { kind: __TypeKind! name: String description: String specifiedByURL: String fields(includeDeprecated: Boolean = false): [__Field!] interfaces: [__Type!] possibleTypes: [__Type!] enumValues(includeDeprecated: Boolean = false): [__EnumValue!] inputFields(includeDeprecated: Boolean = false): [__InputValue!] ofType: __Type } """An enum describing what kind of type a given `__Type` is.""" enum __TypeKind { """Indicates this type is a scalar.""" SCALAR """ Indicates this type is an object. `fields` and `interfaces` are valid fields. """ OBJECT """ Indicates this type is an interface. `fields`, `interfaces`, and `possibleTypes` are valid fields. """ INTERFACE """Indicates this type is a union. `possibleTypes` is a valid field.""" UNION """Indicates this type is an enum. `enumValues` is a valid field.""" ENUM """ Indicates this type is an input object. `inputFields` is a valid field. """ INPUT_OBJECT """Indicates this type is a list. `ofType` is a valid field.""" LIST """Indicates this type is a non-null. `ofType` is a valid field.""" NON_NULL } """ Object and Interface types are described by a list of Fields, each of which has a name, potentially a list of arguments, and a return type. """ type __Field { name: String! description: String args(includeDeprecated: Boolean = false): [__InputValue!]! type: __Type! isDeprecated: Boolean! deprecationReason: String } """ Arguments provided to Fields or Directives and the input fields of an InputObject are represented as Input Values which describe their type and optionally a default value. """ type __InputValue { name: String! description: String type: __Type! """ A GraphQL-formatted string representing the default value for this input value. """ defaultValue: String isDeprecated: Boolean! deprecationReason: String } """ One possible value for a given Enum. Enum values are unique values, not a placeholder for a string or numeric value. However an Enum value is returned in a JSON response as a string. """ type __EnumValue { name: String! description: String isDeprecated: Boolean! deprecationReason: String } """ A Directive provides a way to describe alternate runtime execution and type validation behavior in a GraphQL document. In some cases, you need to provide options to alter GraphQL's execution behavior in ways field arguments will not suffice, such as conditionally including or skipping a field. Directives provide this by describing additional information to the executor. """ type __Directive { name: String! description: String isRepeatable: Boolean! locations: [__DirectiveLocation!]! args(includeDeprecated: Boolean = false): [__InputValue!]! } """ A Directive can be adjacent to many parts of the GraphQL language, a __DirectiveLocation describes one such possible adjacencies. """ enum __DirectiveLocation { """Location adjacent to a query operation.""" QUERY """Location adjacent to a mutation operation.""" MUTATION """Location adjacent to a subscription operation.""" SUBSCRIPTION """Location adjacent to a field.""" FIELD """Location adjacent to a fragment definition.""" FRAGMENT_DEFINITION """Location adjacent to a fragment spread.""" FRAGMENT_SPREAD """Location adjacent to an inline fragment.""" INLINE_FRAGMENT """Location adjacent to a variable definition.""" VARIABLE_DEFINITION """Location adjacent to a schema definition.""" SCHEMA """Location adjacent to a scalar definition.""" SCALAR """Location adjacent to an object type definition.""" OBJECT """Location adjacent to a field definition.""" FIELD_DEFINITION """Location adjacent to an argument definition.""" ARGUMENT_DEFINITION """Location adjacent to an interface definition.""" INTERFACE """Location adjacent to a union definition.""" UNION """Location adjacent to an enum definition.""" ENUM """Location adjacent to an enum value definition.""" ENUM_VALUE """Location adjacent to an input object type definition.""" INPUT_OBJECT """Location adjacent to an input object field definition.""" INPUT_FIELD_DEFINITION } ''' # noqa: E501 ) def describe_print_value(): def print_value_convenience_function(): assert print_value(1.5, GraphQLFloat) == "1.5" assert print_value("foo", GraphQLString) == '"foo"' graphql-core-3.2.6/tests/utilities/test_separate_operations.py000066400000000000000000000113471474546154300247660ustar00rootroot00000000000000from graphql.language import parse, print_ast from graphql.utilities import separate_operations from ..utils import dedent def separated_asts(ast): return {name: print_ast(node) for name, node in separate_operations(ast).items()} def describe_separate_operations(): def separates_one_ast_into_multiple_maintaining_document_order(): ast = parse( """ { ...Y ...X } query One { foo bar ...A ...X } fragment A on T { field ...B } fragment X on T { fieldX } query Two { ...A ...Y baz } fragment Y on T { fieldY } fragment B on T { something } """ ) assert separated_asts(ast) == { "": dedent( """ { ...Y ...X } fragment X on T { fieldX } fragment Y on T { fieldY } """ ), "One": dedent( """ query One { foo bar ...A ...X } fragment A on T { field ...B } fragment X on T { fieldX } fragment B on T { something } """ ), "Two": dedent( """ fragment A on T { field ...B } query Two { ...A ...Y baz } fragment Y on T { fieldY } fragment B on T { something } """ ), } def survives_circular_dependencies(): ast = parse( """ query One { ...A } fragment A on T { ...B } fragment B on T { ...A } query Two { ...B } """ ) assert separated_asts(ast) == { "One": dedent( """ query One { ...A } fragment A on T { ...B } fragment B on T { ...A } """ ), "Two": dedent( """ fragment A on T { ...B } fragment B on T { ...A } query Two { ...B } """ ), } def distinguishes_query_and_fragment_names(): ast = parse( """ { ...NameClash } fragment NameClash on T { oneField } query NameClash { ...ShouldBeSkippedInFirstQuery } fragment ShouldBeSkippedInFirstQuery on T { twoField } """ ) assert separated_asts(ast) == { "": dedent( """ { ...NameClash } fragment NameClash on T { oneField } """ ), "NameClash": dedent( """ query NameClash { ...ShouldBeSkippedInFirstQuery } fragment ShouldBeSkippedInFirstQuery on T { twoField } """ ), } def handles_unknown_fragments(): ast = parse( """ { ...Unknown ...Known } fragment Known on T { someField } """ ) assert separated_asts(ast) == { "": dedent( """ { ...Unknown ...Known } fragment Known on T { someField } """ ) } graphql-core-3.2.6/tests/utilities/test_sort_value_node.py000066400000000000000000000024301474546154300241000ustar00rootroot00000000000000from graphql.language import parse_value, print_ast from graphql.utilities.sort_value_node import sort_value_node def describe_sort_value_node(): def _expect_sorted_value(source: str, expected: str) -> None: assert print_ast(sort_value_node(parse_value(source))) == expected def do_not_change_non_object_values(): _expect_sorted_value("1", "1") _expect_sorted_value("3.14", "3.14") _expect_sorted_value("null", "null") _expect_sorted_value("true", "true") _expect_sorted_value("false", "false") _expect_sorted_value('"cba"', '"cba"') _expect_sorted_value( '[1, 3.14, null, false, "cba"]', '[1, 3.14, null, false, "cba"]' ) _expect_sorted_value( '[[1, 3.14, null, false, "cba"]]', '[[1, 3.14, null, false, "cba"]]' ) def sort_input_object_fields(): _expect_sorted_value("{ b: 2, a: 1 }", "{a: 1, b: 2}") _expect_sorted_value("{ a: { c: 3, b: 2 } }", "{a: {b: 2, c: 3}}") _expect_sorted_value( "[{ b: 2, a: 1 }, { d: 4, c: 3}]", "[{a: 1, b: 2}, {c: 3, d: 4}]", ) _expect_sorted_value( "{ b: { g: 7, f: 6 }, c: 3 , a: { d: 4, e: 5 } }", "{a: {d: 4, e: 5}, b: {f: 6, g: 7}, c: 3}", ) graphql-core-3.2.6/tests/utilities/test_strip_ignored_characters.py000066400000000000000000000334731474546154300257720ustar00rootroot00000000000000from json import dumps from typing import Optional from pytest import raises from graphql.error import GraphQLSyntaxError from graphql.language import Lexer, Source, TokenKind, parse from graphql.utilities import strip_ignored_characters from ..fixtures import kitchen_sink_query, kitchen_sink_sdl # noqa: F401 from ..utils import dedent ignored_tokens = [ # UnicodeBOM "\uFEFF", # Byte Order Mark (U+FEFF) # WhiteSpace "\t", # Horizontal Tab (U+0009) " ", # Space (U+0020) # LineTerminator "\n", # "New Line (U+000A)" "\r", # "Carriage Return (U+000D)" [ lookahead ! "New Line (U+000A)" ] "\r\n", # "Carriage Return (U+000D)" "New Line (U+000A)" # Comment '# "Comment" string\n', # `#` CommentChar* # Comma ",", # , ] punctuator_tokens = ["!", "$", "(", ")", "...", ":", "=", "@", "[", "]", "{", "|", "}"] non_punctuator_tokens = [ "name_token", # Name "1", # IntValue "3.14", # FloatValue '"some string value"', # StringValue '"""block\nstring\nvalue"""', # StringValue(BlockString) ] def lex_value(s: str) -> Optional[str]: lexer = Lexer(Source(s)) value = lexer.advance().value assert lexer.advance().kind == TokenKind.EOF, "Expected EOF" return value class ExpectStripped: def __init__(self, doc_string: str): self.doc_string = doc_string def to_equal(self, expected: str): doc_string = self.doc_string stripped = strip_ignored_characters(doc_string) assert stripped == expected, dedent( f""" Expected strip_ignored_characters({doc_string!r}) to equal {expected!r} but got {stripped!r} """ ) stripped_twice = strip_ignored_characters(stripped) assert stripped == stripped_twice, dedent( f"""" Expected strip_ignored_characters({stripped!r})" to equal {stripped!r} but got {stripped_twice!r} """ ) def to_stay_the_same(self): self.to_equal(self.doc_string) def describe_strip_ignored_characters(): def strips_ignored_characters_from_graphql_query_document(): query = dedent( """ query SomeQuery($foo: String!, $bar: String) { someField(foo: $foo, bar: $bar) { a b { c d } } } """ ) assert strip_ignored_characters(query) == ( "query SomeQuery($foo:String!$bar:String)" "{someField(foo:$foo bar:$bar){a b{c d}}}" ) def strips_ignored_characters_from_graphql_sdl_document(): sdl = dedent( ''' """ Type description """ type Foo { """ Field description """ bar: String } ''' ) assert strip_ignored_characters(sdl) == ( '"""Type description""" type Foo{"""Field description""" bar:String}' ) def report_document_with_invalid_token(): with raises(GraphQLSyntaxError) as exc_info: strip_ignored_characters('{ foo(arg: "\n"') assert str(exc_info.value) == dedent( """ Syntax Error: Unterminated string. GraphQL request:1:13 1 | { foo(arg: " | ^ 2 | " """ ) def strips_non_parsable_document(): ExpectStripped('{ foo(arg: "str"').to_equal('{foo(arg:"str"') def strips_documents_with_only_ignored_characters(): ExpectStripped("\n").to_equal("") ExpectStripped(",").to_equal("") ExpectStripped(",,").to_equal("") ExpectStripped("#comment\n, \n").to_equal("") for ignored in ignored_tokens: ExpectStripped(ignored).to_equal("") for another_ignored in ignored_tokens: ExpectStripped(ignored + another_ignored).to_equal("") ExpectStripped("".join(ignored_tokens)).to_equal("") def strips_leading_and_trailing_ignored_tokens(): ExpectStripped("\n1").to_equal("1") ExpectStripped(",1").to_equal("1") ExpectStripped(",,1").to_equal("1") ExpectStripped("#comment\n, \n1").to_equal("1") ExpectStripped("1\n").to_equal("1") ExpectStripped("1,").to_equal("1") ExpectStripped("1,,").to_equal("1") ExpectStripped("1#comment\n, \n").to_equal("1") for token in punctuator_tokens + non_punctuator_tokens: for ignored in ignored_tokens: ExpectStripped(ignored + token).to_equal(token) ExpectStripped(token + ignored).to_equal(token) for another_ignored in ignored_tokens: ExpectStripped(token + ignored + ignored).to_equal(token) ExpectStripped(ignored + another_ignored + token).to_equal(token) ExpectStripped("".join(ignored_tokens) + token).to_equal(token) ExpectStripped(token + "".join(ignored_tokens)).to_equal(token) def strips_ignored_tokens_between_punctuator_tokens(): ExpectStripped("[,)").to_equal("[)") ExpectStripped("[\r)").to_equal("[)") ExpectStripped("[\r\r)").to_equal("[)") ExpectStripped("[\r,)").to_equal("[)") ExpectStripped("[,\n)").to_equal("[)") for left in punctuator_tokens: for right in punctuator_tokens: for ignored in ignored_tokens: ExpectStripped(left + ignored + right).to_equal(left + right) for another_ignored in ignored_tokens: ExpectStripped( left + ignored + another_ignored + right ).to_equal(left + right) ExpectStripped(left + "".join(ignored_tokens) + right).to_equal( left + right ) def strips_ignored_tokens_between_punctuator_and_non_punctuator_tokens(): ExpectStripped("[,1").to_equal("[1") ExpectStripped("[\r1").to_equal("[1") ExpectStripped("[\r\r1").to_equal("[1") ExpectStripped("[\r,1").to_equal("[1") ExpectStripped("[,\n1").to_equal("[1") for non_punctuator in non_punctuator_tokens: for punctuator in punctuator_tokens: for ignored in ignored_tokens: ExpectStripped(punctuator + ignored + non_punctuator).to_equal( punctuator + non_punctuator ) for another_ignored in ignored_tokens: ExpectStripped( punctuator + ignored + another_ignored + non_punctuator ).to_equal(punctuator + non_punctuator) ExpectStripped( punctuator + "".join(ignored_tokens) + non_punctuator ).to_equal(punctuator + non_punctuator) def strips_ignored_tokens_between_non_punctuator_and_punctuator_tokens(): ExpectStripped("1,[").to_equal("1[") ExpectStripped("1\r[").to_equal("1[") ExpectStripped("1\r\r[").to_equal("1[") ExpectStripped("1\r,[").to_equal("1[") ExpectStripped("1,\n[").to_equal("1[") for non_punctuator in non_punctuator_tokens: for punctuator in punctuator_tokens: # Special case for that is handled in the below test if punctuator == "...": continue for ignored in ignored_tokens: ExpectStripped(non_punctuator + ignored + punctuator).to_equal( non_punctuator + punctuator ) for another_ignored in ignored_tokens: ExpectStripped( non_punctuator + ignored + another_ignored + punctuator ).to_equal(non_punctuator + punctuator) ExpectStripped( non_punctuator + "".join(ignored_tokens) + punctuator ).to_equal(non_punctuator + punctuator) def replace_ignored_tokens_between_non_punctuator_tokens_and_spread_with_space(): ExpectStripped("a ...").to_equal("a ...") ExpectStripped("1 ...").to_equal("1 ...") ExpectStripped("1 ... ...").to_equal("1 ......") for non_punctuator in non_punctuator_tokens: for ignored in ignored_tokens: ExpectStripped(non_punctuator + ignored + "...").to_equal( non_punctuator + " ..." ) for another_ignored in ignored_tokens: ExpectStripped( non_punctuator + ignored + another_ignored + " ..." ).to_equal(non_punctuator + " ...") ExpectStripped(non_punctuator + "".join(ignored_tokens) + "...").to_equal( non_punctuator + " ..." ) def replace_ignored_tokens_between_non_punctuator_tokens_with_space(): ExpectStripped("1 2").to_stay_the_same() ExpectStripped('"" ""').to_stay_the_same() ExpectStripped("a b").to_stay_the_same() ExpectStripped("a,1").to_equal("a 1") ExpectStripped("a,,1").to_equal("a 1") ExpectStripped("a 1").to_equal("a 1") ExpectStripped("a \t 1").to_equal("a 1") for left in non_punctuator_tokens: for right in non_punctuator_tokens: for ignored in ignored_tokens: ExpectStripped(left + ignored + right).to_equal(left + " " + right) for another_ignored in ignored_tokens: ExpectStripped( left + ignored + another_ignored + right ).to_equal(left + " " + right) ExpectStripped(left + "".join(ignored_tokens) + right).to_equal( left + " " + right ) def does_not_strip_ignored_tokens_embedded_in_the_string(): ExpectStripped('" "').to_stay_the_same() ExpectStripped('","').to_stay_the_same() ExpectStripped('",,"').to_stay_the_same() ExpectStripped('",|"').to_stay_the_same() for ignored in ignored_tokens: ExpectStripped(dumps(ignored)).to_stay_the_same() for another_ignored in ignored_tokens: ExpectStripped(dumps(ignored + another_ignored)).to_stay_the_same() ExpectStripped(dumps("".join(ignored_tokens))).to_stay_the_same() def does_not_strip_ignored_tokens_embedded_in_the_block_string(): ExpectStripped('""","""').to_stay_the_same() ExpectStripped('""",,"""').to_stay_the_same() ExpectStripped('""",|"""').to_stay_the_same() ignored_tokens_without_formatting = [ token for token in ignored_tokens if token not in ["\n", "\r", "\r\n", "\t", " "] ] for ignored in ignored_tokens_without_formatting: ExpectStripped('"""|' + ignored + '|"""').to_stay_the_same() for another_ignored in ignored_tokens_without_formatting: ExpectStripped( '"""|' + ignored + another_ignored + '|"""' ).to_stay_the_same() ExpectStripped( '"""|' + "".join(ignored_tokens_without_formatting) + '|"""' ).to_stay_the_same() def strips_ignored_characters_inside_block_strings(): # noinspection PyShadowingNames def expect_stripped_string(block_str: str): original_value = lex_value(block_str) stripped_value = lex_value(strip_ignored_characters(block_str)) assert original_value == stripped_value, dedent( f""" Expected lexValue(stripIgnoredCharacters({block_str!r}) to equal {original_value!r} but got {stripped_value!r} """ ) return ExpectStripped(block_str) expect_stripped_string('""""""').to_stay_the_same() expect_stripped_string('""" """').to_equal('""""""') expect_stripped_string('"""a"""').to_stay_the_same() expect_stripped_string('""" a"""').to_equal('""" a"""') expect_stripped_string('""" a """').to_equal('""" a """') expect_stripped_string('"""\n"""').to_equal('""""""') expect_stripped_string('"""a\nb"""').to_equal('"""a\nb"""') expect_stripped_string('"""a\rb"""').to_equal('"""a\nb"""') expect_stripped_string('"""a\r\nb"""').to_equal('"""a\nb"""') expect_stripped_string('"""a\r\n\nb"""').to_equal('"""a\n\nb"""') expect_stripped_string('"""\\\n"""').to_stay_the_same() expect_stripped_string('""""\n"""').to_stay_the_same() expect_stripped_string('"""\\"""\n"""').to_equal('"""\\""""""') expect_stripped_string('"""\na\n b"""').to_stay_the_same() expect_stripped_string('"""\n a\n b"""').to_equal('"""a\nb"""') expect_stripped_string('"""\na\n b\nc"""').to_equal('"""a\n b\nc"""') # noinspection PyShadowingNames def strips_kitchen_sink_query_but_maintains_the_exact_same_ast( kitchen_sink_query, # noqa: F811 ): stripped_query = strip_ignored_characters(kitchen_sink_query) assert strip_ignored_characters(stripped_query) == stripped_query query_ast = parse(kitchen_sink_query, no_location=True) stripped_ast = parse(stripped_query, no_location=True) assert stripped_ast == query_ast # noinspection PyShadowingNames def strips_kitchen_sink_sdl_but_maintains_the_exact_same_ast( kitchen_sink_sdl, # noqa: F811 ): stripped_sdl = strip_ignored_characters(kitchen_sink_sdl) assert strip_ignored_characters(stripped_sdl) == stripped_sdl sdl_ast = parse(kitchen_sink_sdl, no_location=True) stripped_ast = parse(stripped_sdl, no_location=True) assert stripped_ast == sdl_ast graphql-core-3.2.6/tests/utilities/test_strip_ignored_characters_fuzz.py000066400000000000000000000025631474546154300270440ustar00rootroot00000000000000from typing import Optional from pytest import mark from graphql.error import GraphQLSyntaxError from graphql.language import Lexer, Source, TokenKind from graphql.utilities import strip_ignored_characters from ..utils import dedent, gen_fuzz_strings def lex_value(s: str) -> Optional[str]: lexer = Lexer(Source(s)) value = lexer.advance().value assert lexer.advance().kind == TokenKind.EOF, "Expected EOF" return value def describe_strip_ignored_characters(): @mark.slow @mark.timeout(20) def strips_ignored_characters_inside_random_block_strings(): # Testing with length >7 is taking exponentially more time. However it is # highly recommended to test with increased limit if you make any change. for fuzz_str in gen_fuzz_strings(allowed_chars='\n\t "a\\', max_length=7): test_str = f'"""{fuzz_str}"""' try: test_value = lex_value(test_str) except (AssertionError, GraphQLSyntaxError): continue # skip invalid values stripped_value = lex_value(strip_ignored_characters(test_str)) assert test_value == stripped_value, dedent( f""" Expected lexValue(stripIgnoredCharacters({test_str!r}) to equal {test_value!r} but got {stripped_value!r} """ ) graphql-core-3.2.6/tests/utilities/test_type_comparators.py000066400000000000000000000075721474546154300243170ustar00rootroot00000000000000from graphql.type import ( GraphQLField, GraphQLFloat, GraphQLInt, GraphQLInterfaceType, GraphQLList, GraphQLNonNull, GraphQLObjectType, GraphQLOutputType, GraphQLSchema, GraphQLString, GraphQLUnionType, ) from graphql.utilities import is_equal_type, is_type_sub_type_of def describe_type_comparators(): def describe_is_equal_type(): def same_references_are_equal(): assert is_equal_type(GraphQLString, GraphQLString) is True def int_and_float_are_not_equal(): assert is_equal_type(GraphQLInt, GraphQLFloat) is False def lists_of_same_type_are_equal(): assert ( is_equal_type(GraphQLList(GraphQLInt), GraphQLList(GraphQLInt)) is True ) def lists_is_not_equal_to_item(): assert is_equal_type(GraphQLList(GraphQLInt), GraphQLInt) is False def nonnull_of_same_type_are_equal(): assert ( is_equal_type(GraphQLNonNull(GraphQLInt), GraphQLNonNull(GraphQLInt)) is True ) def nonnull_is_not_equal_to_nullable(): assert is_equal_type(GraphQLNonNull(GraphQLInt), GraphQLInt) is False def describe_is_type_sub_type_of(): def _test_schema(field_type: GraphQLOutputType = GraphQLString): return GraphQLSchema( query=GraphQLObjectType("Query", {"field": GraphQLField(field_type)}) ) def same_reference_is_subtype(): assert ( is_type_sub_type_of(_test_schema(), GraphQLString, GraphQLString) is True ) def int_is_not_subtype_of_float(): assert ( is_type_sub_type_of(_test_schema(), GraphQLInt, GraphQLFloat) is False ) def non_null_is_subtype_of_nullable(): assert ( is_type_sub_type_of( _test_schema(), GraphQLNonNull(GraphQLInt), GraphQLInt ) is True ) def nullable_is_not_subtype_of_non_null(): assert ( is_type_sub_type_of( _test_schema(), GraphQLInt, GraphQLNonNull(GraphQLInt) ) is False ) def item_is_not_subtype_of_list(): assert not is_type_sub_type_of( _test_schema(), GraphQLInt, GraphQLList(GraphQLInt) ) def list_is_not_subtype_of_item(): assert not is_type_sub_type_of( _test_schema(), GraphQLList(GraphQLInt), GraphQLInt ) def member_is_subtype_of_union(): member = GraphQLObjectType("Object", {"field": GraphQLField(GraphQLString)}) union = GraphQLUnionType("Union", [member]) schema = _test_schema(union) assert is_type_sub_type_of(schema, member, union) def implementing_object_is_subtype_of_interface(): iface = GraphQLInterfaceType( "Interface", {"field": GraphQLField(GraphQLString)} ) impl = GraphQLObjectType( "Object", {"field": GraphQLField(GraphQLString)}, [iface], ) schema = _test_schema(impl) assert is_type_sub_type_of(schema, impl, iface) def implementing_interface_is_subtype_of_interface(): iface = GraphQLInterfaceType( "Interface", {"field": GraphQLField(GraphQLString)} ) iface2 = GraphQLInterfaceType( "Interface2", {"field": GraphQLField(GraphQLString)}, [iface] ) impl = GraphQLObjectType( "Object", {"field": GraphQLField(GraphQLString)}, [iface2, iface], ) schema = _test_schema(impl) assert is_type_sub_type_of(schema, iface2, iface) graphql-core-3.2.6/tests/utilities/test_type_from_ast.py000066400000000000000000000025331474546154300235670ustar00rootroot00000000000000from pytest import raises from graphql.language import parse_type, TypeNode from graphql.type import GraphQLList, GraphQLNonNull, GraphQLObjectType from graphql.utilities import type_from_ast from ..validation.harness import test_schema def describe_type_from_ast(): def for_named_type_node(): node = parse_type("Cat") type_for_node = type_from_ast(test_schema, node) assert isinstance(type_for_node, GraphQLObjectType) assert type_for_node.name == "Cat" def for_list_type_node(): node = parse_type("[Cat]") type_for_node = type_from_ast(test_schema, node) assert isinstance(type_for_node, GraphQLList) of_type = type_for_node.of_type assert isinstance(of_type, GraphQLObjectType) assert of_type.name == "Cat" def for_non_null_type_node(): node = parse_type("Cat!") type_for_node = type_from_ast(test_schema, node) assert isinstance(type_for_node, GraphQLNonNull) of_type = type_for_node.of_type assert isinstance(of_type, GraphQLObjectType) assert of_type.name == "Cat" def for_unspecified_type_node(): node = TypeNode() with raises(TypeError) as exc_info: type_from_ast(test_schema, node) msg = str(exc_info.value) assert msg == "Unexpected type node: ." graphql-core-3.2.6/tests/utilities/test_type_info.py000066400000000000000000000423211474546154300227070ustar00rootroot00000000000000from graphql.language import ( FieldNode, NameNode, Node, OperationDefinitionNode, SelectionSetNode, parse, parse_value, print_ast, visit, Visitor, ) from graphql.type import GraphQLSchema, get_named_type, is_composite_type from graphql.utilities import TypeInfo, TypeInfoVisitor, build_schema from ..fixtures import kitchen_sink_query # noqa: F401 test_schema = build_schema( """ interface Pet { name: String } type Dog implements Pet { name: String } type Cat implements Pet { name: String } type Human { name: String pets: [Pet] } type Alien { name(surname: Boolean): String } type QueryRoot { human(id: ID): Human alien: Alien } schema { query: QueryRoot } """ ) def describe_type_info(): schema = GraphQLSchema() def allow_all_methods_to_be_called_before_entering_any_mode(): type_info = TypeInfo(schema) assert type_info.get_type() is None assert type_info.get_parent_type() is None assert type_info.get_input_type() is None assert type_info.get_parent_input_type() is None assert type_info.get_field_def() is None assert type_info.get_default_value() is None assert type_info.get_directive() is None assert type_info.get_argument() is None assert type_info.get_enum_value() is None def describe_visit_with_type_info(): def supports_different_operation_types(): schema = build_schema( """ schema { query: QueryRoot mutation: MutationRoot subscription: SubscriptionRoot } type QueryRoot { foo: String } type MutationRoot { bar: String } type SubscriptionRoot { baz: String } """ ) ast = parse( """ query { foo } mutation { bar } subscription { baz } """ ) class TestVisitor(Visitor): def __init__(self): super().__init__() self.root_types = {} def enter_operation_definition(self, node: OperationDefinitionNode, *_args): self.root_types[node.operation.value] = str(type_info.get_type()) type_info = TypeInfo(schema) test_visitor = TestVisitor() assert visit(ast, TypeInfoVisitor(type_info, test_visitor)) assert test_visitor.root_types == { "query": "QueryRoot", "mutation": "MutationRoot", "subscription": "SubscriptionRoot", } def provide_exact_same_arguments_to_wrapped_visitor(): ast = parse("{ human(id: 4) { name, pets { ... { name } }, unknown } }") class TestVisitor(Visitor): def __init__(self): super().__init__() self.args = [] def enter(self, *args): self.args.append(("enter", *args)) def leave(self, *args): self.args.append(("leave", *args)) test_visitor = TestVisitor() visit(ast, test_visitor) type_info = TypeInfo(test_schema) wrapped_visitor = TestVisitor() visit(ast, TypeInfoVisitor(type_info, wrapped_visitor)) assert test_visitor.args == wrapped_visitor.args def maintains_type_info_during_visit(): visited = [] type_info = TypeInfo(test_schema) ast = parse("{ human(id: 4) { name, pets { ... { name } }, unknown } }") class TestVisitor(Visitor): @staticmethod def enter(*args): parent_type = type_info.get_parent_type() type_ = type_info.get_type() input_type = type_info.get_input_type() node = args[0] visited.append( ( "enter", node.kind, node.value if node.kind == "name" else None, str(parent_type) if parent_type else None, str(type_) if type_ else None, str(input_type) if input_type else None, ) ) @staticmethod def leave(*args): parent_type = type_info.get_parent_type() type_ = type_info.get_type() input_type = type_info.get_input_type() node = args[0] visited.append( ( "leave", node.kind, node.value if node.kind == "name" else None, str(parent_type) if parent_type else None, str(type_) if type_ else None, str(input_type) if input_type else None, ) ) visit(ast, TypeInfoVisitor(type_info, TestVisitor())) assert visited == [ ("enter", "document", None, None, None, None), ("enter", "operation_definition", None, None, "QueryRoot", None), ("enter", "selection_set", None, "QueryRoot", "QueryRoot", None), ("enter", "field", None, "QueryRoot", "Human", None), ("enter", "name", "human", "QueryRoot", "Human", None), ("leave", "name", "human", "QueryRoot", "Human", None), ("enter", "argument", None, "QueryRoot", "Human", "ID"), ("enter", "name", "id", "QueryRoot", "Human", "ID"), ("leave", "name", "id", "QueryRoot", "Human", "ID"), ("enter", "int_value", None, "QueryRoot", "Human", "ID"), ("leave", "int_value", None, "QueryRoot", "Human", "ID"), ("leave", "argument", None, "QueryRoot", "Human", "ID"), ("enter", "selection_set", None, "Human", "Human", None), ("enter", "field", None, "Human", "String", None), ("enter", "name", "name", "Human", "String", None), ("leave", "name", "name", "Human", "String", None), ("leave", "field", None, "Human", "String", None), ("enter", "field", None, "Human", "[Pet]", None), ("enter", "name", "pets", "Human", "[Pet]", None), ("leave", "name", "pets", "Human", "[Pet]", None), ("enter", "selection_set", None, "Pet", "[Pet]", None), ("enter", "inline_fragment", None, "Pet", "Pet", None), ("enter", "selection_set", None, "Pet", "Pet", None), ("enter", "field", None, "Pet", "String", None), ("enter", "name", "name", "Pet", "String", None), ("leave", "name", "name", "Pet", "String", None), ("leave", "field", None, "Pet", "String", None), ("leave", "selection_set", None, "Pet", "Pet", None), ("leave", "inline_fragment", None, "Pet", "Pet", None), ("leave", "selection_set", None, "Pet", "[Pet]", None), ("leave", "field", None, "Human", "[Pet]", None), ("enter", "field", None, "Human", None, None), ("enter", "name", "unknown", "Human", None, None), ("leave", "name", "unknown", "Human", None, None), ("leave", "field", None, "Human", None, None), ("leave", "selection_set", None, "Human", "Human", None), ("leave", "field", None, "QueryRoot", "Human", None), ("leave", "selection_set", None, "QueryRoot", "QueryRoot", None), ("leave", "operation_definition", None, None, "QueryRoot", None), ("leave", "document", None, None, None, None), ] def maintains_type_info_during_edit(): visited = [] type_info = TypeInfo(test_schema) ast = parse("{ human(id: 4) { name, pets }, alien }") class TestVisitor(Visitor): @staticmethod def enter(*args): parent_type = type_info.get_parent_type() type_ = type_info.get_type() input_type = type_info.get_input_type() node = args[0] visited.append( ( "enter", node.kind, node.value if node.kind == "name" else None, str(parent_type) if parent_type else None, str(type_) if type_ else None, str(input_type) if input_type else None, ) ) # Make a query valid by adding missing selection sets. if ( node.kind == "field" and not node.selection_set and is_composite_type(get_named_type(type_)) ): return FieldNode( alias=node.alias, name=node.name, arguments=node.arguments, directives=node.directives, selection_set=SelectionSetNode( selections=[FieldNode(name=NameNode(value="__typename"))] ), ) @staticmethod def leave(*args): parent_type = type_info.get_parent_type() type_ = type_info.get_type() input_type = type_info.get_input_type() node = args[0] visited.append( ( "leave", node.kind, node.value if node.kind == "name" else None, str(parent_type) if parent_type else None, str(type_) if type_ else None, str(input_type) if input_type else None, ) ) edited_ast = visit(ast, TypeInfoVisitor(type_info, TestVisitor())) assert ast == parse("{ human(id: 4) { name, pets }, alien }") assert print_ast(edited_ast) == print_ast( parse( "{ human(id: 4) { name, pets { __typename } }," " alien { __typename } }" ) ) assert visited == [ ("enter", "document", None, None, None, None), ("enter", "operation_definition", None, None, "QueryRoot", None), ("enter", "selection_set", None, "QueryRoot", "QueryRoot", None), ("enter", "field", None, "QueryRoot", "Human", None), ("enter", "name", "human", "QueryRoot", "Human", None), ("leave", "name", "human", "QueryRoot", "Human", None), ("enter", "argument", None, "QueryRoot", "Human", "ID"), ("enter", "name", "id", "QueryRoot", "Human", "ID"), ("leave", "name", "id", "QueryRoot", "Human", "ID"), ("enter", "int_value", None, "QueryRoot", "Human", "ID"), ("leave", "int_value", None, "QueryRoot", "Human", "ID"), ("leave", "argument", None, "QueryRoot", "Human", "ID"), ("enter", "selection_set", None, "Human", "Human", None), ("enter", "field", None, "Human", "String", None), ("enter", "name", "name", "Human", "String", None), ("leave", "name", "name", "Human", "String", None), ("leave", "field", None, "Human", "String", None), ("enter", "field", None, "Human", "[Pet]", None), ("enter", "name", "pets", "Human", "[Pet]", None), ("leave", "name", "pets", "Human", "[Pet]", None), ("enter", "selection_set", None, "Pet", "[Pet]", None), ("enter", "field", None, "Pet", "String!", None), ("enter", "name", "__typename", "Pet", "String!", None), ("leave", "name", "__typename", "Pet", "String!", None), ("leave", "field", None, "Pet", "String!", None), ("leave", "selection_set", None, "Pet", "[Pet]", None), ("leave", "field", None, "Human", "[Pet]", None), ("leave", "selection_set", None, "Human", "Human", None), ("leave", "field", None, "QueryRoot", "Human", None), ("enter", "field", None, "QueryRoot", "Alien", None), ("enter", "name", "alien", "QueryRoot", "Alien", None), ("leave", "name", "alien", "QueryRoot", "Alien", None), ("enter", "selection_set", None, "Alien", "Alien", None), ("enter", "field", None, "Alien", "String!", None), ("enter", "name", "__typename", "Alien", "String!", None), ("leave", "name", "__typename", "Alien", "String!", None), ("leave", "field", None, "Alien", "String!", None), ("leave", "selection_set", None, "Alien", "Alien", None), ("leave", "field", None, "QueryRoot", "Alien", None), ("leave", "selection_set", None, "QueryRoot", "QueryRoot", None), ("leave", "operation_definition", None, None, "QueryRoot", None), ("leave", "document", None, None, None, None), ] def supports_traversal_of_input_values(): visited = [] schema = build_schema( """ input ComplexInput { stringListField: [String] } """ ) complex_input_type = schema.get_type("ComplexInput") assert complex_input_type is not None type_info = TypeInfo(schema, complex_input_type) ast = parse_value('{ stringListField: ["foo"] }') class TestVisitor(Visitor): @staticmethod def enter(node: Node, *_args): type_ = type_info.get_input_type() visited.append( ( "enter", node.kind, node.value if isinstance(node, NameNode) else None, str(type_), ) ) @staticmethod def leave(node: Node, *_args): type_ = type_info.get_input_type() visited.append( ( "leave", node.kind, node.value if isinstance(node, NameNode) else None, str(type_), ) ) visit(ast, TypeInfoVisitor(type_info, TestVisitor())) assert visited == [ ("enter", "object_value", None, "ComplexInput"), ("enter", "object_field", None, "[String]"), ("enter", "name", "stringListField", "[String]"), ("leave", "name", "stringListField", "[String]"), ("enter", "list_value", None, "String"), ("enter", "string_value", None, "String"), ("leave", "string_value", None, "String"), ("leave", "list_value", None, "String"), ("leave", "object_field", None, "[String]"), ("leave", "object_value", None, "ComplexInput"), ] def supports_traversal_of_selection_sets(): visited = [] human_type = test_schema.get_type("Human") assert human_type is not None type_info = TypeInfo(test_schema, human_type) ast = parse("{ name, pets { name } }") operation_node = ast.definitions[0] assert isinstance(operation_node, OperationDefinitionNode) class TestVisitor(Visitor): @staticmethod def enter(node: Node, *_args): parent_type = type_info.get_parent_type() type_ = type_info.get_type() visited.append( ( "enter", node.kind, node.value if isinstance(node, NameNode) else None, str(parent_type), str(type_), ) ) @staticmethod def leave(node: Node, *_args): parent_type = type_info.get_parent_type() type_ = type_info.get_type() visited.append( ( "leave", node.kind, node.value if isinstance(node, NameNode) else None, str(parent_type), str(type_), ) ) visit(operation_node.selection_set, TypeInfoVisitor(type_info, TestVisitor())) assert visited == [ ("enter", "selection_set", None, "Human", "Human"), ("enter", "field", None, "Human", "String"), ("enter", "name", "name", "Human", "String"), ("leave", "name", "name", "Human", "String"), ("leave", "field", None, "Human", "String"), ("enter", "field", None, "Human", "[Pet]"), ("enter", "name", "pets", "Human", "[Pet]"), ("leave", "name", "pets", "Human", "[Pet]"), ("enter", "selection_set", None, "Pet", "[Pet]"), ("enter", "field", None, "Pet", "String"), ("enter", "name", "name", "Pet", "String"), ("leave", "name", "name", "Pet", "String"), ("leave", "field", None, "Pet", "String"), ("leave", "selection_set", None, "Pet", "[Pet]"), ("leave", "field", None, "Human", "[Pet]"), ("leave", "selection_set", None, "Human", "Human"), ] graphql-core-3.2.6/tests/utilities/test_value_from_ast.py000066400000000000000000000241671474546154300237310ustar00rootroot00000000000000from math import isnan, nan from typing import Any, Dict, Optional from graphql.language import parse_value, ValueNode from graphql.pyutils import Undefined from graphql.type import ( GraphQLBoolean, GraphQLEnumType, GraphQLFloat, GraphQLID, GraphQLInputField, GraphQLInputObjectType, GraphQLInputType, GraphQLInt, GraphQLList, GraphQLNonNull, GraphQLScalarType, GraphQLString, ) from graphql.utilities import value_from_ast def describe_value_from_ast(): def _value_from( value_text: str, type_: GraphQLInputType, variables: Optional[Dict[str, Any]] = None, ): ast = parse_value(value_text) return value_from_ast(ast, type_, variables) def rejects_empty_input(): # noinspection PyTypeChecker assert value_from_ast(None, GraphQLBoolean) is Undefined def converts_according_to_input_coercion_rules(): assert _value_from("true", GraphQLBoolean) is True assert _value_from("false", GraphQLBoolean) is False assert _value_from("123", GraphQLInt) == 123 assert _value_from("123", GraphQLFloat) == 123 assert _value_from("123.456", GraphQLFloat) == 123.456 assert _value_from('"abc123"', GraphQLString) == "abc123" assert _value_from("123456", GraphQLID) == "123456" assert _value_from('"123456"', GraphQLID) == "123456" def does_not_convert_when_input_coercion_rules_reject_a_value(): assert _value_from("123", GraphQLBoolean) is Undefined assert _value_from("123.456", GraphQLInt) is Undefined assert _value_from("true", GraphQLInt) is Undefined assert _value_from('"123"', GraphQLInt) is Undefined assert _value_from('"123"', GraphQLFloat) is Undefined assert _value_from("123", GraphQLString) is Undefined assert _value_from("true", GraphQLString) is Undefined assert _value_from("123.456", GraphQLID) is Undefined def convert_using_parse_literal_from_a_custom_scalar_type(): def pass_through_parse_literal(node, _vars=None): assert node.kind == "string_value" return node.value pass_through_scalar = GraphQLScalarType( "PassThroughScalar", parse_literal=pass_through_parse_literal, parse_value=lambda value: value, # pragma: no cover ) assert _value_from('"value"', pass_through_scalar) == "value" def throw_parse_literal(_node: ValueNode, _vars=None): raise RuntimeError("Test") throw_scalar = GraphQLScalarType( "ThrowScalar", parse_literal=throw_parse_literal, parse_value=lambda value: value, # pragma: no cover ) assert _value_from("value", throw_scalar) is Undefined def undefined_parse_literal(_node: ValueNode, _vars=None): return Undefined return_undefined_scalar = GraphQLScalarType( "ReturnUndefinedScalar", parse_literal=undefined_parse_literal, parse_value=lambda value: value, # pragma: no cover ) assert _value_from("value", return_undefined_scalar) is Undefined def converts_enum_values_according_to_input_coercion_rules(): test_enum = GraphQLEnumType( "TestColor", { "RED": 1, "GREEN": 2, "BLUE": 3, "NULL": None, "NAN": nan, "NO_CUSTOM_VALUE": Undefined, }, ) assert _value_from("RED", test_enum) == 1 assert _value_from("BLUE", test_enum) == 3 assert _value_from("YELLOW", test_enum) is Undefined assert _value_from("3", test_enum) is Undefined assert _value_from('"BLUE"', test_enum) is Undefined assert _value_from("null", test_enum) is None assert _value_from("NULL", test_enum) is None assert _value_from("NULL", GraphQLNonNull(test_enum)) is None assert isnan(_value_from("NAN", test_enum)) assert _value_from("NO_CUSTOM_VALUE", test_enum) is Undefined # Boolean! non_null_bool = GraphQLNonNull(GraphQLBoolean) # [Boolean] list_of_bool = GraphQLList(GraphQLBoolean) # [Boolean!] list_of_non_null_bool = GraphQLList(non_null_bool) # [Boolean]! non_null_list_of_bool = GraphQLNonNull(list_of_bool) # [Boolean!]! non_null_list_of_non_mull_bool = GraphQLNonNull(list_of_non_null_bool) def coerces_to_null_unless_non_null(): assert _value_from("null", GraphQLBoolean) is None assert _value_from("null", non_null_bool) is Undefined def coerces_lists_of_values(): assert _value_from("true", list_of_bool) == [True] assert _value_from("123", list_of_bool) is Undefined assert _value_from("null", list_of_bool) is None assert _value_from("[true, false]", list_of_bool) == [True, False] assert _value_from("[true, 123]", list_of_bool) is Undefined assert _value_from("[true, null]", list_of_bool) == [True, None] assert _value_from("{ true: true }", list_of_bool) is Undefined def coerces_non_null_lists_of_values(): assert _value_from("true", non_null_list_of_bool) == [True] assert _value_from("123", non_null_list_of_bool) is Undefined assert _value_from("null", non_null_list_of_bool) is Undefined assert _value_from("[true, false]", non_null_list_of_bool) == [True, False] assert _value_from("[true, 123]", non_null_list_of_bool) is Undefined assert _value_from("[true, null]", non_null_list_of_bool) == [True, None] def coerces_lists_of_non_null_values(): assert _value_from("true", list_of_non_null_bool) == [True] assert _value_from("123", list_of_non_null_bool) is Undefined assert _value_from("null", list_of_non_null_bool) is None assert _value_from("[true, false]", list_of_non_null_bool) == [True, False] assert _value_from("[true, 123]", list_of_non_null_bool) is Undefined assert _value_from("[true, null]", list_of_non_null_bool) is Undefined def coerces_non_null_lists_of_non_null_values(): assert _value_from("true", non_null_list_of_non_mull_bool) == [True] assert _value_from("123", non_null_list_of_non_mull_bool) is Undefined assert _value_from("null", non_null_list_of_non_mull_bool) is Undefined assert _value_from("[true, false]", non_null_list_of_non_mull_bool) == [ True, False, ] assert _value_from("[true, 123]", non_null_list_of_non_mull_bool) is Undefined assert _value_from("[true, null]", non_null_list_of_non_mull_bool) is Undefined test_input_obj = GraphQLInputObjectType( "TestInput", { "int": GraphQLInputField(GraphQLInt, default_value=42), "bool": GraphQLInputField(GraphQLBoolean), "requiredBool": GraphQLInputField(non_null_bool), }, ) def coerces_input_objects_according_to_input_coercion_rules(): assert _value_from("null", test_input_obj) is None assert _value_from("[]", test_input_obj) is Undefined assert _value_from("123", test_input_obj) is Undefined assert _value_from("{ int: 123, requiredBool: false }", test_input_obj) == { "int": 123, "requiredBool": False, } assert _value_from("{ bool: true, requiredBool: false }", test_input_obj) == { "int": 42, "bool": True, "requiredBool": False, } assert ( _value_from("{ int: true, requiredBool: true }", test_input_obj) is Undefined ) assert _value_from("{ requiredBool: null }", test_input_obj) is Undefined assert _value_from("{ bool: true }", test_input_obj) is Undefined def accepts_variable_values_assuming_already_coerced(): assert _value_from("$var", GraphQLBoolean, {}) is Undefined assert _value_from("$var", GraphQLBoolean, {"var": True}) is True assert _value_from("$var", GraphQLBoolean, {"var": None}) is None assert _value_from("$var", non_null_bool, {"var": None}) is Undefined def asserts_variables_are_provided_as_items_in_lists(): assert _value_from("[ $foo ]", list_of_bool, {}) == [None] assert _value_from("[ $foo ]", list_of_non_null_bool, {}) is Undefined assert _value_from("[ $foo ]", list_of_non_null_bool, {"foo": True}) == [True] # Note: variables are expected to have already been coerced, so we # do not expect the singleton wrapping behavior for variables. assert _value_from("$foo", list_of_non_null_bool, {"foo": True}) is True assert _value_from("$foo", list_of_non_null_bool, {"foo": [True]}) == [True] def omits_input_object_fields_for_unprovided_variables(): assert _value_from( "{ int: $foo, bool: $foo, requiredBool: true }", test_input_obj, {} ) == {"int": 42, "requiredBool": True} assert _value_from("{ requiredBool: $foo }", test_input_obj, {}) is Undefined assert _value_from("{ requiredBool: $foo }", test_input_obj, {"foo": True}) == { "int": 42, "requiredBool": True, } def transforms_names_using_out_name(): # This is an extension of GraphQL.js. complex_input_obj = GraphQLInputObjectType( "Complex", { "realPart": GraphQLInputField(GraphQLFloat, out_name="real_part"), "imagPart": GraphQLInputField( GraphQLFloat, default_value=0, out_name="imag_part" ), }, ) assert _value_from("{ realPart: 1 }", complex_input_obj) == { "real_part": 1, "imag_part": 0, } def transforms_values_with_out_type(): # This is an extension of GraphQL.js. complex_input_obj = GraphQLInputObjectType( "Complex", { "real": GraphQLInputField(GraphQLFloat), "imag": GraphQLInputField(GraphQLFloat), }, out_type=lambda value: complex(value["real"], value["imag"]), ) assert _value_from("{ real: 1, imag: 2 }", complex_input_obj) == 1 + 2j graphql-core-3.2.6/tests/utilities/test_value_from_ast_untyped.py000066400000000000000000000053441474546154300254750ustar00rootroot00000000000000from math import nan from typing import Any, Dict, Optional from graphql.language import parse_value, FloatValueNode, IntValueNode from graphql.pyutils import Undefined from graphql.utilities import value_from_ast_untyped def describe_value_from_ast_untyped(): def _compare_value(value: Any, expected: Any): if expected is None: assert value is None elif expected is Undefined: assert value is Undefined elif expected is nan: assert value is nan else: assert value == expected def _expect_value_from(value_text: str, expected: Any): ast = parse_value(value_text) value = value_from_ast_untyped(ast) _compare_value(value, expected) def _expect_value_from_vars( value_text: str, variables: Optional[Dict[str, Any]], expected: Any ): ast = parse_value(value_text) value = value_from_ast_untyped(ast, variables) _compare_value(value, expected) def parses_simple_values(): _expect_value_from("null", None) _expect_value_from("true", True) _expect_value_from("false", False) _expect_value_from("123", 123) _expect_value_from("123.456", 123.456) _expect_value_from('"abc123"', "abc123") def parses_lists_of_values(): _expect_value_from("[true, false]", [True, False]) _expect_value_from("[true, 123.45]", [True, 123.45]) _expect_value_from("[true, null]", [True, None]) _expect_value_from('[true, ["foo", 1.2]]', [True, ["foo", 1.2]]) def parses_input_objects(): _expect_value_from("{ int: 123, bool: false }", {"int": 123, "bool": False}) _expect_value_from('{ foo: [ { bar: "baz"} ] }', {"foo": [{"bar": "baz"}]}) def parses_enum_values_as_plain_strings(): _expect_value_from("TEST_ENUM_VALUE", "TEST_ENUM_VALUE") _expect_value_from("[TEST_ENUM_VALUE]", ["TEST_ENUM_VALUE"]) def parses_variables(): _expect_value_from_vars("$testVariable", {"testVariable": "foo"}, "foo") _expect_value_from_vars("[$testVariable]", {"testVariable": "foo"}, ["foo"]) _expect_value_from_vars( "{a:[$testVariable]}", {"testVariable": "foo"}, {"a": ["foo"]} ) _expect_value_from_vars("$testVariable", {"testVariable": None}, None) _expect_value_from_vars("$testVariable", {"testVariable": nan}, nan) _expect_value_from_vars("$testVariable", {}, Undefined) _expect_value_from_vars("$testVariable", None, Undefined) def parse_invalid_int_as_nan(): assert value_from_ast_untyped(IntValueNode(value="invalid")) is nan def parse_invalid_float_as_nan(): assert value_from_ast_untyped(FloatValueNode(value="invalid")) is nan graphql-core-3.2.6/tests/utils/000077500000000000000000000000001474546154300164255ustar00rootroot00000000000000graphql-core-3.2.6/tests/utils/__init__.py000066400000000000000000000002121474546154300205310ustar00rootroot00000000000000"""Test utilities""" from .dedent import dedent from .gen_fuzz_strings import gen_fuzz_strings __all__ = ["dedent", "gen_fuzz_strings"] graphql-core-3.2.6/tests/utils/dedent.py000066400000000000000000000003161474546154300202420ustar00rootroot00000000000000from textwrap import dedent as _dedent __all__ = ["dedent"] def dedent(text: str) -> str: """Fix indentation and also trim given text string.""" return _dedent(text.lstrip("\n").rstrip(" \t\n")) graphql-core-3.2.6/tests/utils/gen_fuzz_strings.py000066400000000000000000000005711474546154300224020ustar00rootroot00000000000000from itertools import product from typing import Generator __all__ = ["gen_fuzz_strings"] def gen_fuzz_strings(allowed_chars: str, max_length: int) -> Generator[str, None, None]: """Generator that produces all possible combinations of allowed characters.""" for length in range(max_length + 1): yield from map("".join, product(allowed_chars, repeat=length)) graphql-core-3.2.6/tests/utils/test_dedent.py000066400000000000000000000043341474546154300213050ustar00rootroot00000000000000from . import dedent def describe_dedent(): def removes_indentation_in_typical_usage(): assert ( dedent( """ type Query { me: User } type User { id: ID name: String } """ ) == "type Query {\n me: User\n}\n\n" "type User {\n id: ID\n name: String\n}" ) def removes_only_the_first_level_of_indentation(): assert ( dedent( """ first second third fourth """ ) == "first\n second\n third\n fourth" ) def does_not_escape_special_characters(): assert ( dedent( """ type Root { field(arg: String = "wi\th de\fault"): String } """ ) == "type Root {\n" ' field(arg: String = "wi\th de\fault"): String\n}' ) def also_removes_indentation_using_tabs(): assert ( dedent( """ \t\t type Query { \t\t me: User \t\t } """ ) == "type Query {\n me: User\n}" ) def removes_leading_and_trailing_newlines(): assert ( dedent( """ type Query { me: User } """ ) == "type Query {\n me: User\n}" ) def removes_all_trailing_spaces_and_tabs(): assert ( dedent( """ type Query { me: User } \t\t \t """ ) == "type Query {\n me: User\n}" ) def works_on_text_without_leading_newline(): assert ( dedent( """ type Query { me: User } """ ) == "type Query {\n me: User\n}" ) graphql-core-3.2.6/tests/utils/test_gen_fuzz_strings.py000066400000000000000000000030421474546154300234350ustar00rootroot00000000000000from . import gen_fuzz_strings def describe_gen_fuzz_strings(): def always_provide_empty_string(): assert list(gen_fuzz_strings(allowed_chars="", max_length=0)) == [""] assert list(gen_fuzz_strings(allowed_chars="", max_length=1)) == [""] assert list(gen_fuzz_strings(allowed_chars="a", max_length=0)) == [""] def generate_strings_with_single_character(): assert list(gen_fuzz_strings(allowed_chars="a", max_length=1)) == ["", "a"] assert list(gen_fuzz_strings(allowed_chars="abc", max_length=1)) == [ "", "a", "b", "c", ] def generate_strings_with_multiple_character(): assert list(gen_fuzz_strings(allowed_chars="a", max_length=2)) == [ "", "a", "aa", ] assert list(gen_fuzz_strings(allowed_chars="abc", max_length=2)) == [ "", "a", "b", "c", "aa", "ab", "ac", "ba", "bb", "bc", "ca", "cb", "cc", ] def generate_strings_longer_than_possible_number_of_characters(): assert list(gen_fuzz_strings(allowed_chars="ab", max_length=3)) == [ "", "a", "b", "aa", "ab", "ba", "bb", "aaa", "aab", "aba", "abb", "baa", "bab", "bba", "bbb", ] graphql-core-3.2.6/tests/validation/000077500000000000000000000000001474546154300174175ustar00rootroot00000000000000graphql-core-3.2.6/tests/validation/__init__.py000066400000000000000000000002041474546154300215240ustar00rootroot00000000000000"""Tests for graphql.validation""" from pytest import register_assert_rewrite register_assert_rewrite("tests.validation.harness") graphql-core-3.2.6/tests/validation/harness.py000066400000000000000000000067471474546154300214520ustar00rootroot00000000000000from typing import Any, Dict, List, Optional, Type, Union from graphql.error import GraphQLError from graphql.language import parse from graphql.type import GraphQLSchema from graphql.utilities import build_schema from graphql.validation import ASTValidationRule from graphql.validation.validate import validate, validate_sdl __all__ = [ "test_schema", "assert_validation_errors", "assert_sdl_validation_errors", ] test_schema = build_schema( """ interface Mammal { mother: Mammal father: Mammal } interface Pet { name(surname: Boolean): String } interface Canine implements Mammal { name(surname: Boolean): String mother: Canine father: Canine } enum DogCommand { SIT HEEL DOWN } type Dog implements Pet & Mammal & Canine { name(surname: Boolean): String nickname: String barkVolume: Int barks: Boolean doesKnowCommand(dogCommand: DogCommand): Boolean isHouseTrained(atOtherHomes: Boolean = true): Boolean isAtLocation(x: Int, y: Int): Boolean mother: Dog father: Dog } type Cat implements Pet { name(surname: Boolean): String nickname: String meows: Boolean meowsVolume: Int furColor: FurColor } union CatOrDog = Cat | Dog type Human { name(surname: Boolean): String pets: [Pet] relatives: [Human] } enum FurColor { BROWN BLACK TAN SPOTTED NO_FUR UNKNOWN } input ComplexInput { requiredField: Boolean! nonNullField: Boolean! = false intField: Int stringField: String booleanField: Boolean stringListField: [String] } type ComplicatedArgs { # TODO List # TODO Coercion # TODO NotNulls intArgField(intArg: Int): String nonNullIntArgField(nonNullIntArg: Int!): String stringArgField(stringArg: String): String booleanArgField(booleanArg: Boolean): String enumArgField(enumArg: FurColor): String floatArgField(floatArg: Float): String idArgField(idArg: ID): String stringListArgField(stringListArg: [String]): String stringListNonNullArgField(stringListNonNullArg: [String!]): String complexArgField(complexArg: ComplexInput): String multipleReqs(req1: Int!, req2: Int!): String nonNullFieldWithDefault(arg: Int! = 0): String multipleOpts(opt1: Int = 0, opt2: Int = 0): String multipleOptAndReq(req1: Int!, req2: Int!, opt1: Int = 0, opt2: Int = 0): String } type QueryRoot { human(id: ID): Human dog: Dog cat: Cat pet: Pet catOrDog: CatOrDog complicatedArgs: ComplicatedArgs } schema { query: QueryRoot } directive @onField on FIELD """ ) def assert_validation_errors( rule: Type[ASTValidationRule], query_str: str, errors: List[Union[GraphQLError, Dict[str, Any]]], schema: GraphQLSchema = test_schema, ) -> List[GraphQLError]: doc = parse(query_str) returned_errors = validate(schema, doc, [rule]) assert returned_errors == errors return returned_errors def assert_sdl_validation_errors( rule: Type[ASTValidationRule], sdl_str: str, errors: List[Union[GraphQLError, Dict[str, Any]]], schema: Optional[GraphQLSchema] = None, ) -> List[GraphQLError]: doc = parse(sdl_str) returned_errors = validate_sdl(doc, schema, [rule]) assert returned_errors == errors return returned_errors graphql-core-3.2.6/tests/validation/test_executable_definitions.py000066400000000000000000000042721474546154300255510ustar00rootroot00000000000000from functools import partial from graphql.validation import ExecutableDefinitionsRule from .harness import assert_validation_errors assert_errors = partial(assert_validation_errors, ExecutableDefinitionsRule) assert_valid = partial(assert_errors, errors=[]) def describe_validate_executable_definitions(): def with_only_operation(): assert_valid( """ query Foo { dog { name } } """ ) def with_operation_and_fragment(): assert_valid( """ query Foo { dog { name ...Frag } } fragment Frag on Dog { name } """ ) def with_type_definition(): assert_errors( """ query Foo { dog { name } } type Cow { name: String } extend type Dog { color: String } """, [ { "message": "The 'Cow' definition is not executable.", "locations": [(8, 13)], }, { "message": "The 'Dog' definition is not executable.", "locations": [(12, 13)], }, ], ) def with_schema_definition(): assert_errors( """ schema { query: Query } type Query { test: String } extend schema @directive """, [ { "message": "The schema definition is not executable.", "locations": [(2, 13)], }, { "message": "The 'Query' definition is not executable.", "locations": [(6, 13)], }, { "message": "The schema definition is not executable.", "locations": [(10, 13)], }, ], ) graphql-core-3.2.6/tests/validation/test_fields_on_correct_type.py000066400000000000000000000306721474546154300255640ustar00rootroot00000000000000from functools import partial from graphql.language import parse from graphql.type import GraphQLSchema from graphql.utilities import build_schema from graphql.validation import validate, FieldsOnCorrectTypeRule from .harness import assert_validation_errors test_schema = build_schema( """ interface Pet { name: String } type Dog implements Pet { name: String nickname: String barkVolume: Int } type Cat implements Pet { name: String nickname: String meowVolume: Int } union CatOrDog = Cat | Dog type Human { name: String pets: [Pet] } type Query { human: Human } """ ) assert_errors = partial( assert_validation_errors, FieldsOnCorrectTypeRule, schema=test_schema ) assert_valid = partial(assert_errors, errors=[]) def describe_validate_fields_on_correct_type(): def object_field_selection(): assert_valid( """ fragment objectFieldSelection on Dog { __typename name } """ ) def aliased_object_field_selection(): assert_valid( """ fragment aliasedObjectFieldSelection on Dog { tn : __typename otherName : name } """ ) def interface_field_selection(): assert_valid( """ fragment interfaceFieldSelection on Pet { __typename name } """ ) def aliased_interface_field_selection(): assert_valid( """ fragment interfaceFieldSelection on Pet { otherName : name } """ ) def lying_alias_selection(): assert_valid( """ fragment lyingAliasSelection on Dog { name : nickname } """ ) def ignores_fields_on_unknown_type(): assert_valid( """ fragment unknownSelection on UnknownType { unknownField } """ ) def reports_errors_when_type_is_known_again(): assert_errors( """ fragment typeKnownAgain on Pet { unknown_pet_field { ... on Cat { unknown_cat_field } } }, """, [ { "message": "Cannot query field 'unknown_pet_field' on type 'Pet'.", "locations": [(3, 15)], }, { "message": "Cannot query field 'unknown_cat_field' on type 'Cat'.", "locations": [(5, 19)], }, ], ) def field_not_defined_on_fragment(): assert_errors( """ fragment fieldNotDefined on Dog { meowVolume } """, [ { "message": "Cannot query field 'meowVolume' on type 'Dog'." " Did you mean 'barkVolume'?", "locations": [(3, 15)], }, ], ) def ignores_deeply_unknown_field(): assert_errors( """ fragment deepFieldNotDefined on Dog { unknown_field { deeper_unknown_field } } """, [ { "message": "Cannot query field 'unknown_field' on type 'Dog'.", "locations": [(3, 15)], }, ], ) def sub_field_not_defined(): assert_errors( """ fragment subFieldNotDefined on Human { pets { unknown_field } } """, [ { "message": "Cannot query field 'unknown_field' on type 'Pet'.", "locations": [(4, 17)], }, ], ) def field_not_defined_on_inline_fragment(): assert_errors( """ fragment fieldNotDefined on Pet { ... on Dog { meowVolume } } """, [ { "message": "Cannot query field 'meowVolume' on type 'Dog'." " Did you mean 'barkVolume'?", "locations": [(4, 17)], }, ], ) def aliased_field_target_not_defined(): assert_errors( """ fragment aliasedFieldTargetNotDefined on Dog { volume : mooVolume } """, [ { "message": "Cannot query field 'mooVolume' on type 'Dog'." " Did you mean 'barkVolume'?", "locations": [(3, 15)], }, ], ) def aliased_lying_field_target_not_defined(): assert_errors( """ fragment aliasedLyingFieldTargetNotDefined on Dog { barkVolume : kawVolume } """, [ { "message": "Cannot query field 'kawVolume' on type 'Dog'." " Did you mean 'barkVolume'?", "locations": [(3, 15)], }, ], ) def not_defined_on_interface(): assert_errors( """ fragment notDefinedOnInterface on Pet { tailLength } """, [ { "message": "Cannot query field 'tailLength' on type 'Pet'.", "locations": [(3, 15)], }, ], ) def defined_on_implementors_but_not_on_interface(): assert_errors( """ fragment definedOnImplementorsButNotInterface on Pet { nickname } """, [ { "message": "Cannot query field 'nickname' on type 'Pet'." " Did you mean to use an inline fragment on 'Cat' or 'Dog'?", "locations": [(3, 15)], }, ], ) def meta_field_selection_on_union(): assert_valid( """ fragment directFieldSelectionOnUnion on CatOrDog { __typename } """ ) def direct_field_selection_on_union(): assert_errors( """ fragment directFieldSelectionOnUnion on CatOrDog { directField } """, [ { "message": "Cannot query field 'directField' on type 'CatOrDog'.", "locations": [(3, 15)], }, ], ) def defined_on_implementors_queried_on_union(): assert_errors( """ fragment definedOnImplementorsQueriedOnUnion on CatOrDog { name } """, [ { "message": "Cannot query field 'name' on type 'CatOrDog'." " Did you mean to use an inline fragment" " on 'Pet', 'Cat', or 'Dog'?", "locations": [(3, 15)], }, ], ) def valid_field_in_inline_fragment(): assert_valid( """ fragment objectFieldSelection on Pet { ... on Dog { name } ... { name } } """ ) def describe_fields_on_correct_type_error_message(): def _error_message(schema: GraphQLSchema, query_str: str): errors = validate(schema, parse(query_str), [FieldsOnCorrectTypeRule]) assert len(errors) == 1 return errors[0].message def fields_correct_type_no_suggestion(): schema = build_schema( """ type T { fieldWithVeryLongNameThatWillNeverBeSuggested: String } type Query { t: T } """ ) assert _error_message(schema, "{ t { f } }") == ( "Cannot query field 'f' on type 'T'." ) def works_with_no_small_numbers_of_type_suggestion(): schema = build_schema( """ union T = A | B type Query { t: T } type A { f: String } type B { f: String } """ ) assert _error_message(schema, "{ t { f } }") == ( "Cannot query field 'f' on type 'T'." " Did you mean to use an inline fragment on 'A' or 'B'?" ) def works_with_no_small_numbers_of_field_suggestion(): schema = build_schema( """ type T { y: String z: String } type Query { t: T } """ ) assert _error_message(schema, "{ t { f } }") == ( "Cannot query field 'f' on type 'T'. Did you mean 'y' or 'z'?" ) def only_shows_one_set_of_suggestions_at_a_time_preferring_types(): schema = build_schema( """ interface T { y: String z: String } type Query { t: T } type A implements T { f: String y: String z: String } type B implements T { f: String y: String z: String } """ ) assert _error_message(schema, "{ t { f } }") == ( "Cannot query field 'f' on type 'T'." " Did you mean to use an inline fragment on 'A' or 'B'?" ) def sort_type_suggestions_based_on_inheritance_order(): interface_schema = build_schema( """ interface T { bar: String } type Query { t: T } interface Z implements T { foo: String bar: String } interface Y implements Z & T { foo: String bar: String } type X implements Y & Z & T { foo: String bar: String } """ ) assert _error_message(interface_schema, "{ t { foo } }") == ( "Cannot query field 'foo' on type 'T'." " Did you mean to use an inline fragment on 'Z', 'Y', or 'X'?" ) union_schema = build_schema( """ interface Animal { name: String } interface Mammal implements Animal { name: String } interface Canine implements Animal & Mammal { name: String } type Dog implements Animal & Mammal & Canine { name: String } interface Feline implements Animal & Mammal { name: String } type Cat implements Animal & Mammal & Feline { name: String } union CatOrDog = Cat | Dog type Query { catOrDog: CatOrDog } """ ) assert _error_message(union_schema, "{ catOrDog { name } }") == ( "Cannot query field 'name' on type 'CatOrDog'." " Did you mean to use an inline fragment" " on 'Animal', 'Mammal', 'Canine', 'Dog', or 'Feline'?" ) def limits_lots_of_type_suggestions(): schema = build_schema( """ union T = A | B | C | D | E | F type Query { t: T } type A { f: String } type B { f: String } type C { f: String } type D { f: String } type E { f: String } type F { f: String } """ ) assert _error_message(schema, "{ t { f } }") == ( "Cannot query field 'f' on type 'T'. Did you mean to use" " an inline fragment on 'A', 'B', 'C', 'D', or 'E'?" ) def limits_lots_of_field_suggestions(): schema = build_schema( """ type T { u: String v: String w: String x: String y: String z: String } type Query { t: T } """ ) assert _error_message(schema, "{ t { f } }") == ( "Cannot query field 'f' on type 'T'." " Did you mean 'u', 'v', 'w', 'x', or 'y'?" ) graphql-core-3.2.6/tests/validation/test_fragments_on_composite_types.py000066400000000000000000000064771474546154300270360ustar00rootroot00000000000000from functools import partial from graphql.validation import FragmentsOnCompositeTypesRule from .harness import assert_validation_errors assert_errors = partial(assert_validation_errors, FragmentsOnCompositeTypesRule) assert_valid = partial(assert_errors, errors=[]) def describe_validate_fragments_on_composite_types(): def object_is_valid_fragment_type(): assert_valid( """ fragment validFragment on Dog { barks } """ ) def interface_is_valid_fragment_type(): assert_valid( """ fragment validFragment on Pet { name } """ ) def object_is_valid_inline_fragment_type(): assert_valid( """ fragment validFragment on Pet { ... on Dog { barks } } """ ) def interface_is_valid_inline_fragment_type(): assert_valid( """ fragment validFragment on Mammal { ... on Canine { name } } """ ) def inline_fragment_without_type_is_valid(): assert_valid( """ fragment validFragment on Pet { ... { name } } """ ) def union_is_valid_fragment_type(): assert_valid( """ fragment validFragment on CatOrDog { __typename } """ ) def scalar_is_invalid_fragment_type(): assert_errors( """ fragment scalarFragment on Boolean { bad } """, [ { "message": "Fragment 'scalarFragment' cannot condition" " on non composite type 'Boolean'.", "locations": [(2, 40)], }, ], ) def enum_is_invalid_fragment_type(): assert_errors( """ fragment scalarFragment on FurColor { bad } """, [ { "message": "Fragment 'scalarFragment' cannot condition" " on non composite type 'FurColor'.", "locations": [(2, 40)], }, ], ) def input_object_is_invalid_fragment_type(): assert_errors( """ fragment inputFragment on ComplexInput { stringField } """, [ { "message": "Fragment 'inputFragment' cannot condition" " on non composite type 'ComplexInput'.", "locations": [(2, 39)], }, ], ) def scalar_is_invalid_inline_fragment_type(): assert_errors( """ fragment invalidFragment on Pet { ... on String { barks } } """, [ { "message": "Fragment cannot condition" " on non composite type 'String'.", "locations": [(3, 22)], } ], ) graphql-core-3.2.6/tests/validation/test_known_argument_names.py000066400000000000000000000231141474546154300252520ustar00rootroot00000000000000from functools import partial from graphql.utilities import build_schema from graphql.validation import KnownArgumentNamesRule from graphql.validation.rules.known_argument_names import ( KnownArgumentNamesOnDirectivesRule, ) from .harness import assert_validation_errors, assert_sdl_validation_errors assert_errors = partial(assert_validation_errors, KnownArgumentNamesRule) assert_valid = partial(assert_errors, errors=[]) assert_sdl_errors = partial( assert_sdl_validation_errors, KnownArgumentNamesOnDirectivesRule ) assert_sdl_valid = partial(assert_sdl_errors, errors=[]) def describe_validate_known_argument_names(): def single_arg_is_known(): assert_valid( """ fragment argOnRequiredArg on Dog { doesKnowCommand(dogCommand: SIT) } """ ) def multiple_args_are_known(): assert_valid( """ fragment multipleArgs on ComplicatedArgs { multipleReqs(req1: 1, req2: 2) } """ ) def ignore_args_of_unknown_fields(): assert_valid( """ fragment argOnUnknownField on Dog { unknownField(unknownArg: SIT) } """ ) def multiple_args_in_reverse_order_are_known(): assert_valid( """ fragment multipleArgsReverseOrder on ComplicatedArgs { multipleReqs(req2: 2, req1: 1) } """ ) def no_args_on_optional_arg(): assert_valid( """ fragment noArgOnOptionalArg on Dog { isHouseTrained } """ ) def args_are_known_deeply(): assert_valid( """ { dog { doesKnowCommand(dogCommand: SIT) } human { pet { ... on Dog { doesKnowCommand(dogCommand: SIT) } } } } """ ) def directive_args_are_known(): assert_valid( """ { dog @skip(if: true) } """ ) def field_args_are_invalid(): assert_errors( """ { dog @skip(unless: true) } """, [ { "message": "Unknown argument 'unless' on directive '@skip'.", "locations": [(3, 25)], } ], ) def directive_without_args_is_valid(): assert_valid( """ { dog @onField } """ ) def arg_passed_to_directive_without_args_is_reported(): assert_errors( """ { dog @onField(if: true) } """, [ { "message": "Unknown argument 'if' on directive '@onField'.", "locations": [(3, 30)], } ], ) def misspelled_directive_args_are_reported(): assert_errors( """ { dog @skip(iff: true) } """, [ { "message": "Unknown argument 'iff' on directive '@skip'." " Did you mean 'if'?", "locations": [(3, 25)], } ], ) def invalid_arg_name(): assert_errors( """ fragment invalidArgName on Dog { doesKnowCommand(unknown: true) } """, [ { "message": "Unknown argument 'unknown'" " on field 'Dog.doesKnowCommand'.", "locations": [(3, 31)], }, ], ) def misspelled_arg_name_is_reported(): assert_errors( """ fragment invalidArgName on Dog { doesKnowCommand(DogCommand: true) } """, [ { "message": "Unknown argument 'DogCommand'" " on field 'Dog.doesKnowCommand'." " Did you mean 'dogCommand'?", "locations": [(3, 31)], } ], ) def unknown_args_amongst_known_args(): assert_errors( """ fragment oneGoodArgOneInvalidArg on Dog { doesKnowCommand(whoKnows: 1, dogCommand: SIT, unknown: true) } """, [ { "message": "Unknown argument 'whoKnows'" " on field 'Dog.doesKnowCommand'.", "locations": [(3, 31)], }, { "message": "Unknown argument 'unknown'" " on field 'Dog.doesKnowCommand'.", "locations": [(3, 61)], }, ], ) def unknown_args_deeply(): assert_errors( """ { dog { doesKnowCommand(unknown: true) } human { pet { ... on Dog { doesKnowCommand(unknown: true) } } } } """, [ { "message": "Unknown argument 'unknown'" " on field 'Dog.doesKnowCommand'.", "locations": [(4, 33)], }, { "message": "Unknown argument 'unknown'" " on field 'Dog.doesKnowCommand'.", "locations": [(9, 37)], }, ], ) def describe_within_sdl(): def known_arg_on_directive_inside_sdl(): assert_sdl_valid( """ type Query { foo: String @test(arg: "") } directive @test(arg: String) on FIELD_DEFINITION """ ) def unknown_arg_on_directive_defined_inside_sdl(): assert_sdl_errors( """ type Query { foo: String @test(unknown: "") } directive @test(arg: String) on FIELD_DEFINITION """, [ { "message": "Unknown argument 'unknown' on directive '@test'.", "locations": [(3, 37)], }, ], ) def misspelled_arg_name_is_reported_on_directive_defined_inside_sdl(): assert_sdl_errors( """ type Query { foo: String @test(agr: "") } directive @test(arg: String) on FIELD_DEFINITION """, [ { "message": "Unknown argument 'agr' on directive '@test'." " Did you mean 'arg'?", "locations": [(3, 37)], }, ], ) def unknown_arg_on_standard_directive(): assert_sdl_errors( """ type Query { foo: String @deprecated(unknown: "") } """, [ { "message": "Unknown argument 'unknown'" " on directive '@deprecated'.", "locations": [(3, 43)], }, ], ) def unknown_arg_on_overridden_standard_directive(): assert_sdl_errors( """ type Query { foo: String @deprecated(reason: "") } directive @deprecated(arg: String) on FIELD """, [ { "message": "Unknown argument 'reason'" " on directive '@deprecated'.", "locations": [(3, 43)], }, ], ) def unknown_arg_on_directive_defined_in_schema_extension(): schema = build_schema( """ type Query { foo: String } """ ) assert_sdl_errors( """ directive @test(arg: String) on OBJECT extend type Query @test(unknown: "") """, [ { "message": "Unknown argument 'unknown' on directive '@test'.", "locations": [(4, 42)], }, ], schema, ) def unknown_arg_on_directive_used_in_schema_extension(): schema = build_schema( """ directive @test(arg: String) on OBJECT type Query { foo: String } """ ) assert_sdl_errors( """ extend type Query @test(unknown: "") """, [ { "message": "Unknown argument 'unknown' on directive '@test'.", "locations": [(2, 41)], }, ], schema, ) graphql-core-3.2.6/tests/validation/test_known_directives.py000066400000000000000000000333531474546154300244140ustar00rootroot00000000000000from functools import partial from graphql.utilities import build_schema from graphql.validation import KnownDirectivesRule from .harness import assert_validation_errors, assert_sdl_validation_errors schema_with_directives = build_schema( """ type Query { dummy: String } directive @onQuery on QUERY directive @onMutation on MUTATION directive @onSubscription on SUBSCRIPTION directive @onField on FIELD directive @onFragmentDefinition on FRAGMENT_DEFINITION directive @onFragmentSpread on FRAGMENT_SPREAD directive @onInlineFragment on INLINE_FRAGMENT directive @onVariableDefinition on VARIABLE_DEFINITION """ ) schema_with_sdl_directives = build_schema( """ directive @onSchema on SCHEMA directive @onScalar on SCALAR directive @onObject on OBJECT directive @onFieldDefinition on FIELD_DEFINITION directive @onArgumentDefinition on ARGUMENT_DEFINITION directive @onInterface on INTERFACE directive @onUnion on UNION directive @onEnum on ENUM directive @onEnumValue on ENUM_VALUE directive @onInputObject on INPUT_OBJECT directive @onInputFieldDefinition on INPUT_FIELD_DEFINITION """ ) assert_errors = partial( assert_validation_errors, KnownDirectivesRule, schema=schema_with_directives ) assert_valid = partial(assert_errors, errors=[]) assert_sdl_errors = partial(assert_sdl_validation_errors, KnownDirectivesRule) assert_sdl_valid = partial(assert_sdl_errors, errors=[]) def describe_known_directives(): def with_no_directives(): assert_valid( """ query Foo { name ...Frag } fragment Frag on Dog { name } """ ) def with_standard_directives(): assert_valid( """ { human @skip(if: false) { name pets { ... on Dog @include(if: true) { name } } } } """ ) def with_unknown_directive(): assert_errors( """ { human @unknown(directive: "value") { name } } """, [{"message": "Unknown directive '@unknown'.", "locations": [(3, 21)]}], ) def with_many_unknown_directives(): assert_errors( """ { __typename @unknown human @unknown { name pets @unknown { name } } } """, [ {"message": "Unknown directive '@unknown'.", "locations": [(3, 26)]}, {"message": "Unknown directive '@unknown'.", "locations": [(4, 21)]}, {"message": "Unknown directive '@unknown'.", "locations": [(6, 22)]}, ], ) def with_well_placed_directives(): assert_valid( """ query ($var: Boolean @onVariableDefinition) @onQuery { human @onField { ...Frag @onFragmentSpread ... @onInlineFragment { name @onField } } } mutation @onMutation { someField @onField } subscription @onSubscription { someField @onField } fragment Frag on Human @onFragmentDefinition { name @onField } """ ) def with_misplaced_directives(): assert_errors( """ query ($var: Boolean @onQuery) @onMutation { human @onQuery { ...Frag @onQuery ... @onQuery { name @onQuery } } } mutation @onQuery { someField @onQuery } subscription @onQuery { someField @onQuery } fragment Frag on Human @onQuery { name @onQuery } """, [ { "message": "Directive '@onQuery'" " may not be used on variable definition.", "locations": [(2, 34)], }, { "message": "Directive '@onMutation' may not be used on query.", "locations": [(2, 44)], }, { "message": "Directive '@onQuery' may not be used on field.", "locations": [(3, 21)], }, { "message": "Directive '@onQuery'" " may not be used on fragment spread.", "locations": [(4, 25)], }, { "message": "Directive '@onQuery'" " may not be used on inline fragment.", "locations": [(5, 21)], }, { "message": "Directive '@onQuery' may not be used on field.", "locations": [(6, 24)], }, { "message": "Directive '@onQuery' may not be used on mutation.", "locations": [(11, 22)], }, { "message": "Directive '@onQuery' may not be used on field.", "locations": [(12, 25)], }, { "message": "Directive '@onQuery' may not be used on subscription.", "locations": [(15, 26)], }, { "message": "Directive '@onQuery' may not be used on field.", "locations": [(16, 25)], }, { "message": "Directive '@onQuery'" " may not be used on fragment definition.", "locations": [(19, 36)], }, { "message": "Directive '@onQuery' may not be used on field.", "locations": [(20, 20)], }, ], ) def with_misplaced_variable_definition_directive(): assert_errors( """ query Foo($var: Boolean @onField) { name } """, [ { "message": "Directive '@onField'" " may not be used on variable definition.", "locations": [(2, 37)], }, ], ) def describe_within_sdl(): def with_directive_defined_inside_sdl(): assert_sdl_valid( """ type Query { foo: String @test } directive @test on FIELD_DEFINITION """ ) def with_standard_directive(): assert_sdl_valid( """ type Query { foo: String @deprecated } """ ) def with_overridden_standard_directive(): assert_sdl_valid( """ schema @deprecated { query: Query } directive @deprecated on SCHEMA """ ) def with_directive_defined_in_schema_extension(): schema = build_schema( """ type Query { foo: String } """ ) assert_sdl_valid( """ directive @test on OBJECT extend type Query @test """, schema=schema, ) def with_directive_used_in_schema_extension(): schema = build_schema( """ directive @test on OBJECT type Query { foo: String } """ ) assert_sdl_valid( """ extend type Query @test """, schema=schema, ) def with_unknown_directive_in_schema_extension(): schema = build_schema( """ type Query { foo: String } """ ) assert_sdl_errors( """ extend type Query @unknown """, [{"message": "Unknown directive '@unknown'.", "locations": [(2, 35)]}], schema, ) def with_well_placed_directives(): assert_sdl_valid( """ type MyObj implements MyInterface @onObject { myField(myArg: Int @onArgumentDefinition): String @onFieldDefinition } extend type MyObj @onObject scalar MyScalar @onScalar extend scalar MyScalar @onScalar interface MyInterface @onInterface { myField(myArg: Int @onArgumentDefinition): String @onFieldDefinition } extend interface MyInterface @onInterface union MyUnion @onUnion = MyObj | Other extend union MyUnion @onUnion enum MyEnum @onEnum { MY_VALUE @onEnumValue } extend enum MyEnum @onEnum input MyInput @onInputObject { myField: Int @onInputFieldDefinition } extend input MyInput @onInputObject schema @onSchema { query: MyQuery } extend schema @onSchema """, schema=schema_with_sdl_directives, ) def with_misplaced_directives(): assert_sdl_errors( """ type MyObj implements MyInterface @onInterface { myField(myArg: Int @onInputFieldDefinition): String @onInputFieldDefinition } scalar MyScalar @onEnum interface MyInterface @onObject { myField(myArg: Int @onInputFieldDefinition): String @onInputFieldDefinition } union MyUnion @onEnumValue = MyObj | Other enum MyEnum @onScalar { MY_VALUE @onUnion } input MyInput @onEnum { myField: Int @onArgumentDefinition } schema @onObject { query: MyQuery } extend schema @onObject """, # noqa: E501 [ { "message": "Directive '@onInterface'" " may not be used on object.", "locations": [(2, 51)], }, { "message": "Directive '@onInputFieldDefinition'" " may not be used on argument definition.", "locations": [(3, 38)], }, { "message": "Directive '@onInputFieldDefinition'" " may not be used on field definition.", "locations": [(3, 71)], }, { "message": "Directive '@onEnum' may not be used on scalar.", "locations": [(6, 33)], }, { "message": "Directive '@onObject'" " may not be used on interface.", "locations": [(8, 39)], }, { "message": "Directive '@onInputFieldDefinition'" " may not be used on argument definition.", "locations": [(9, 38)], }, { "message": "Directive '@onInputFieldDefinition'" " may not be used on field definition.", "locations": [(9, 71)], }, { "message": "Directive '@onEnumValue' may not be used on union.", "locations": [(12, 31)], }, { "message": "Directive '@onScalar' may not be used on enum.", "locations": [(14, 29)], }, { "message": "Directive '@onUnion'" " may not be used on enum value.", "locations": [(15, 28)], }, { "message": "Directive '@onEnum'" " may not be used on input object.", "locations": [(18, 31)], }, { "message": "Directive '@onArgumentDefinition'" " may not be used on input field definition.", "locations": [(19, 32)], }, { "message": "Directive '@onObject' may not be used on schema.", "locations": [(22, 24)], }, { "message": "Directive '@onObject' may not be used on schema.", "locations": [(26, 31)], }, ], schema_with_sdl_directives, ) graphql-core-3.2.6/tests/validation/test_known_fragment_names.py000066400000000000000000000034641474546154300252410ustar00rootroot00000000000000from functools import partial from graphql.validation import KnownFragmentNamesRule from .harness import assert_validation_errors assert_errors = partial(assert_validation_errors, KnownFragmentNamesRule) assert_valid = partial(assert_errors, errors=[]) def describe_validate_known_fragment_names(): def known_fragment_names_are_valid(): assert_valid( """ { human(id: 4) { ...HumanFields1 ... on Human { ...HumanFields2 } ... { name } } } fragment HumanFields1 on Human { name ...HumanFields3 } fragment HumanFields2 on Human { name } fragment HumanFields3 on Human { name } """ ) def unknown_fragment_names_are_invalid(): assert_errors( """ { human(id: 4) { ...UnknownFragment1 ... on Human { ...UnknownFragment2 } } } fragment HumanFields on Human { name ...UnknownFragment3 } """, [ { "message": "Unknown fragment 'UnknownFragment1'.", "locations": [(4, 20)], }, { "message": "Unknown fragment 'UnknownFragment2'.", "locations": [(6, 22)], }, { "message": "Unknown fragment 'UnknownFragment3'.", "locations": [(12, 18)], }, ], ) graphql-core-3.2.6/tests/validation/test_known_type_names.py000066400000000000000000000250051474546154300244120ustar00rootroot00000000000000from functools import partial from graphql.utilities import build_schema from graphql.validation import KnownTypeNamesRule from .harness import assert_validation_errors, assert_sdl_validation_errors assert_errors = partial(assert_validation_errors, KnownTypeNamesRule) assert_valid = partial(assert_errors, errors=[]) assert_sdl_errors = partial(assert_sdl_validation_errors, KnownTypeNamesRule) assert_sdl_valid = partial(assert_sdl_errors, errors=[]) def describe_validate_known_type_names(): def known_type_names_are_valid(): assert_valid( """ query Foo( $var: String $required: [Int!]! $introspectionType: __EnumValue ) { user(id: 4) { pets { ... on Pet { name }, ...PetFields, ... { name } } } } fragment PetFields on Pet { name } """ ) def unknown_type_names_are_invalid(): assert_errors( """ query Foo($var: [JumbledUpLetters!]!) { user(id: 4) { name pets { ... on Badger { name }, ...PetFields, ... { name } } } } fragment PetFields on Peat { name } """, [ { "message": "Unknown type 'JumbledUpLetters'.", "locations": [(2, 30)], }, {"message": "Unknown type 'Badger'.", "locations": [(5, 31)]}, { "message": "Unknown type 'Peat'. Did you mean 'Pet' or 'Cat'?", "locations": [(8, 35)], }, ], ) def references_to_standard_scalars_that_are_missing_in_schema(): schema = build_schema("type Query { foo: String }") query = """ query ($id: ID, $float: Float, $int: Int) { __typename } """ assert_errors( query, [ {"message": "Unknown type 'ID'.", "locations": [(2, 25)]}, {"message": "Unknown type 'Float'.", "locations": [(2, 37)]}, {"message": "Unknown type 'Int'.", "locations": [(2, 50)]}, ], schema, ) def describe_within_sdl(): def use_standard_types(): assert_sdl_valid( """ type Query { string: String int: Int float: Float boolean: Boolean id: ID introspectionType: __EnumValue } """ ) def reference_types_defined_inside_the_same_document(): assert_sdl_valid( """ union SomeUnion = SomeObject | AnotherObject type SomeObject implements SomeInterface { someScalar(arg: SomeInputObject): SomeScalar } type AnotherObject { foo(arg: SomeInputObject): String } type SomeInterface { someScalar(arg: SomeInputObject): SomeScalar } input SomeInputObject { someScalar: SomeScalar } scalar SomeScalar type RootQuery { someInterface: SomeInterface someUnion: SomeUnion someScalar: SomeScalar someObject: SomeObject } schema { query: RootQuery } """ ) def unknown_type_references(): assert_sdl_errors( """ type A type B type SomeObject implements C { e(d: D): E } union SomeUnion = F | G interface SomeInterface { i(h: H): I } input SomeInput { j: J } directive @SomeDirective(k: K) on QUERY schema { query: L mutation: M subscription: N } """, [ { "message": "Unknown type 'C'. Did you mean 'A' or 'B'?", "locations": [(5, 44)], }, { "message": "Unknown type 'D'. Did you mean 'A', 'B', or 'ID'?", "locations": [(6, 24)], }, { "message": "Unknown type 'E'. Did you mean 'A' or 'B'?", "locations": [(6, 28)], }, { "message": "Unknown type 'F'. Did you mean 'A' or 'B'?", "locations": [(9, 35)], }, { "message": "Unknown type 'G'. Did you mean 'A' or 'B'?", "locations": [(9, 39)], }, { "message": "Unknown type 'H'. Did you mean 'A' or 'B'?", "locations": [(12, 24)], }, { "message": "Unknown type 'I'. Did you mean 'A', 'B', or 'ID'?", "locations": [(12, 28)], }, { "message": "Unknown type 'J'. Did you mean 'A' or 'B'?", "locations": [(16, 22)], }, { "message": "Unknown type 'K'. Did you mean 'A' or 'B'?", "locations": [(19, 45)], }, { "message": "Unknown type 'L'. Did you mean 'A' or 'B'?", "locations": [(22, 26)], }, { "message": "Unknown type 'M'. Did you mean 'A' or 'B'?", "locations": [(23, 29)], }, { "message": "Unknown type 'N'. Did you mean 'A' or 'B'?", "locations": [(24, 33)], }, ], ) def does_not_consider_non_type_definitions(): assert_sdl_errors( """ query Foo { __typename } fragment Foo on Query { __typename } directive @Foo on QUERY type Query { foo: Foo } """, [{"message": "Unknown type 'Foo'.", "locations": [(7, 24)]}], ) def reference_standard_types_inside_extension_document(): schema = build_schema("type Foo") sdl = """ type SomeType { string: String int: Int float: Float boolean: Boolean id: ID introspectionType: __EnumValue } """ assert_sdl_valid(sdl, schema=schema) def reference_types_inside_extension_document(): schema = build_schema("type Foo") sdl = """ type QueryRoot { foo: Foo bar: Bar } scalar Bar schema { query: QueryRoot } """ assert_sdl_valid(sdl, schema=schema) def unknown_type_references_inside_extension_document(): schema = build_schema("type A") sdl = """ type B type SomeObject implements C { e(d: D): E } union SomeUnion = F | G interface SomeInterface { i(h: H): I } input SomeInput { j: J } directive @SomeDirective(k: K) on QUERY schema { query: L mutation: M subscription: N } """ assert_sdl_errors( sdl, [ { "message": "Unknown type 'C'. Did you mean 'A' or 'B'?", "locations": [(4, 44)], }, { "message": "Unknown type 'D'. Did you mean 'A', 'B', or 'ID'?", "locations": [(5, 24)], }, { "message": "Unknown type 'E'. Did you mean 'A' or 'B'?", "locations": [(5, 28)], }, { "message": "Unknown type 'F'. Did you mean 'A' or 'B'?", "locations": [(8, 35)], }, { "message": "Unknown type 'G'. Did you mean 'A' or 'B'?", "locations": [(8, 39)], }, { "message": "Unknown type 'H'. Did you mean 'A' or 'B'?", "locations": [(11, 24)], }, { "message": "Unknown type 'I'. Did you mean 'A', 'B', or 'ID'?", "locations": [(11, 28)], }, { "message": "Unknown type 'J'. Did you mean 'A' or 'B'?", "locations": [(15, 22)], }, { "message": "Unknown type 'K'. Did you mean 'A' or 'B'?", "locations": [(18, 45)], }, { "message": "Unknown type 'L'. Did you mean 'A' or 'B'?", "locations": [(21, 26)], }, { "message": "Unknown type 'M'. Did you mean 'A' or 'B'?", "locations": [(22, 29)], }, { "message": "Unknown type 'N'. Did you mean 'A' or 'B'?", "locations": [(23, 33)], }, ], schema, ) graphql-core-3.2.6/tests/validation/test_lone_anonymous_operation.py000066400000000000000000000050521474546154300261570ustar00rootroot00000000000000from functools import partial from graphql.validation import LoneAnonymousOperationRule from .harness import assert_validation_errors assert_errors = partial(assert_validation_errors, LoneAnonymousOperationRule) assert_valid = partial(assert_errors, errors=[]) def describe_validate_anonymous_operation_must_be_alone(): def no_operations(): assert_valid( """ fragment fragA on Type { field } """ ) def one_anon_operation(): assert_valid( """ { field } """ ) def multiple_named_operation(): assert_valid( """ query Foo { field } query Bar { field } """ ) def anon_operation_with_fragment(): assert_valid( """ { ...Foo } fragment Foo on Type { field } """ ) def multiple_anon_operations(): assert_errors( """ { fieldA } { fieldB } """, [ { "message": "This anonymous operation" " must be the only defined operation.", "locations": [(2, 13)], }, { "message": "This anonymous operation" " must be the only defined operation.", "locations": [(5, 13)], }, ], ) def anon_operation_with_a_mutation(): assert_errors( """ { fieldA } mutation Foo { fieldB } """, [ { "message": "This anonymous operation" " must be the only defined operation.", "locations": [(2, 13)], }, ], ) def anon_operation_with_a_subscription(): assert_errors( """ { fieldA } subscription Foo { fieldB } """, [ { "message": "This anonymous operation" " must be the only defined operation.", "locations": [(2, 13)], }, ], ) graphql-core-3.2.6/tests/validation/test_lone_schema_definition.py000066400000000000000000000066141474546154300255240ustar00rootroot00000000000000from functools import partial from graphql.utilities import build_schema from graphql.validation.rules.lone_schema_definition import LoneSchemaDefinitionRule from .harness import assert_sdl_validation_errors assert_sdl_errors = partial(assert_sdl_validation_errors, LoneSchemaDefinitionRule) assert_sdl_valid = partial(assert_sdl_errors, errors=[]) def describe_validate_schema_definition_should_be_alone(): def no_schema(): assert_sdl_valid( """ type Query { foo: String } """ ) def one_schema_definition(): assert_sdl_valid( """ schema { query: Foo } type Foo { foo: String } """ ) def multiple_schema_definitions(): assert_sdl_errors( """ schema { query: Foo } type Foo { foo: String } schema { mutation: Foo } schema { subscription: Foo } """, [ { "message": "Must provide only one schema definition.", "locations": [(10, 13)], }, { "message": "Must provide only one schema definition.", "locations": [(14, 13)], }, ], ) def define_schema_in_schema_extension(): schema = build_schema( """ type Foo { foo: String } """ ) assert_sdl_valid( """ schema { query: Foo } """, schema=schema, ) def redefine_schema_in_schema_extension(): schema = build_schema( """ schema { query: Foo } type Foo { foo: String } """ ) assert_sdl_errors( """ schema { mutation: Foo } """, [ { "message": "Cannot define a new schema within a schema extension.", "locations": [(2, 13)], } ], schema, ) def redefine_implicit_schema_in_schema_extension(): schema = build_schema( """ type Query { fooField: Foo } type Foo { foo: String } """ ) assert_sdl_errors( """ schema { mutation: Foo } """, [ { "message": "Cannot define a new schema within a schema extension.", "locations": [(2, 13)], }, ], schema, ) def extend_schema_in_schema_extension(): schema = build_schema( """ type Query { fooField: Foo } type Foo { foo: String } """ ) assert_sdl_valid( """ extend schema { mutation: Foo } """, schema=schema, ) graphql-core-3.2.6/tests/validation/test_no_deprecated.py000066400000000000000000000212771474546154300236350ustar00rootroot00000000000000from functools import partial from typing import Callable, List, Tuple from graphql.utilities import build_schema from graphql.validation import NoDeprecatedCustomRule from .harness import assert_validation_errors def build_assertions( sdl_str: str, ) -> Tuple[Callable[[str], None], Callable[[str, List], None]]: schema = build_schema(sdl_str) assert_errors = partial( assert_validation_errors, NoDeprecatedCustomRule, schema=schema ) assert_valid = partial(assert_errors, errors=[]) return ( assert_valid, assert_errors, ) # type: ignore def describe_validate_no_deprecated(): def describe_no_deprecated_fields(): _assert_valid, _assert_errors = build_assertions( """ type Query { normalField: String deprecatedField: String @deprecated(reason: "Some field reason.") } """ ) def ignores_fields_and_enum_values_that_are_not_deprecated(): _assert_valid( """ { normalField } """ ) def ignores_unknown_fields(): _assert_valid( """ { unknownField } fragment UnknownFragment on UnknownType { deprecatedField } """ ) def reports_error_when_a_deprecated_field_is_selected(): message = ( "The field Query.deprecatedField is deprecated. Some field reason." ) _assert_errors( """ { deprecatedField } fragment QueryFragment on Query { deprecatedField } """, [ { "message": message, "locations": [(3, 19)], }, { "message": message, "locations": [(7, 19)], }, ], ) def describe_no_deprecated_arguments_on_fields(): _assert_valid, _assert_errors = build_assertions( """ type Query { someField( normalArg: String, deprecatedArg: String @deprecated(reason: "Some arg reason."), ): String } """ ) def ignores_arguments_that_are_not_deprecated(): _assert_valid( """ { normalField(normalArg: "") } """ ) def ignores_unknown_arguments(): _assert_valid( """ { someField(unknownArg: "") unknownField(deprecatedArg: "") } """ ) def reports_error_when_a_deprecated_argument_is_used(): _assert_errors( """ { someField(deprecatedArg: "") } """, [ { "message": "Field 'Query.someField' argument 'deprecatedArg'" " is deprecated. Some arg reason.", "locations": [(3, 31)], } ], ) def describe_no_deprecated_arguments_on_directives(): _assert_valid, _assert_errors = build_assertions( """ type Query { someField: String } directive @someDirective( normalArg: String, deprecatedArg: String @deprecated(reason: "Some arg reason."), ) on FIELD """ ) def ignores_arguments_that_are_not_deprecated(): _assert_valid( """ { someField @someDirective(normalArg: "") } """ ) def ignores_unknown_arguments(): _assert_valid( """ { someField @someDirective(unknownArg: "") someField @unknownDirective(deprecatedArg: "") } """ ) def reports_error_when_a_deprecated_argument_is_used(): _assert_errors( """ { someField @someDirective(deprecatedArg: "") } """, [ { "message": "Directive '@someDirective' argument 'deprecatedArg'" " is deprecated. Some arg reason.", "locations": [(3, 44)], } ], ) def describe_no_deprecated_input_fields(): _assert_valid, _assert_errors = build_assertions( """ input InputType { normalField: String deprecatedField: String @deprecated(reason: "Some input field reason.") } type Query { someField(someArg: InputType): String } directive @someDirective(someArg: InputType) on FIELD """ ) def ignores_input_fields_that_are_not_deprecated(): _assert_valid( """ { someField( someArg: { normalField: "" } ) @someDirective(someArg: { normalField: "" }) } """ ) def ignores_unknown_input_fields(): _assert_valid( """ { someField( someArg: { unknownField: "" } ) someField( unknownArg: { unknownField: "" } ) unknownField( unknownArg: { unknownField: "" } ) } """ ) def reports_error_when_a_deprecated_input_field_is_used(): message = ( "The input field InputType.deprecatedField is deprecated." " Some input field reason." ) _assert_errors( """ { someField( someArg: { deprecatedField: "" } ) @someDirective(someArg: { deprecatedField: "" }) } """, [ {"message": message, "locations": [(4, 32)]}, {"message": message, "locations": [(5, 47)]}, ], ) def describe_no_deprecated_enum_values(): _assert_valid, _assert_errors = build_assertions( """ enum EnumType { NORMAL_VALUE DEPRECATED_VALUE @deprecated(reason: "Some enum reason.") } type Query { someField(enumArg: EnumType): String } """ ) def ignores_enum_values_that_are_not_deprecated(): _assert_valid( """ { normalField(enumArg: NORMAL_VALUE) } """ ) def ignores_unknown_enum_values(): _assert_valid( """ query ( $unknownValue: EnumType = UNKNOWN_VALUE $unknownType: UnknownType = UNKNOWN_VALUE ) { someField(enumArg: UNKNOWN_VALUE) someField(unknownArg: UNKNOWN_VALUE) unknownField(unknownArg: UNKNOWN_VALUE) } fragment SomeFragment on Query { someField(enumArg: UNKNOWN_VALUE) } """ ) def reports_error_when_a_deprecated_enum_value_is_used(): message = ( "The enum value 'EnumType.DEPRECATED_VALUE' is deprecated." " Some enum reason." ) _assert_errors( """ query ( $variable: EnumType = DEPRECATED_VALUE ) { someField(enumArg: DEPRECATED_VALUE) } """, [ { "message": message, "locations": [(3, 41)], }, { "message": message, "locations": [(5, 38)], }, ], ) graphql-core-3.2.6/tests/validation/test_no_fragment_cycles.py000066400000000000000000000167521474546154300247040ustar00rootroot00000000000000from functools import partial from graphql.validation import NoFragmentCyclesRule from .harness import assert_validation_errors assert_errors = partial(assert_validation_errors, NoFragmentCyclesRule) assert_valid = partial(assert_errors, errors=[]) def describe_validate_no_circular_fragment_spreads(): def single_reference_is_valid(): assert_valid( """ fragment fragA on Dog { ...fragB } fragment fragB on Dog { name } """ ) def spreading_twice_is_not_circular(): assert_valid( """ fragment fragA on Dog { ...fragB, ...fragB } fragment fragB on Dog { name } """ ) def spreading_twice_indirectly_is_not_circular(): assert_valid( """ fragment fragA on Dog { ...fragB, ...fragC } fragment fragB on Dog { ...fragC } fragment fragC on Dog { name } """ ) def double_spread_within_abstract_types(): assert_valid( """ fragment nameFragment on Pet { ... on Dog { name } ... on Cat { name } } fragment spreadsInAnon on Pet { ... on Dog { ...nameFragment } ... on Cat { ...nameFragment } } """ ) def does_not_raise_false_positive_on_unknown_fragment(): assert_valid( """ fragment nameFragment on Pet { ...UnknownFragment } """ ) def spreading_recursively_within_field_fails(): assert_errors( """ fragment fragA on Human { relatives { ...fragA } }, """, [ { "message": "Cannot spread fragment 'fragA' within itself.", "locations": [(2, 51)], } ], ) def no_spreading_itself_directly(): assert_errors( """ fragment fragA on Dog { ...fragA } """, [ { "message": "Cannot spread fragment 'fragA' within itself.", "locations": [(2, 37)], } ], ) def no_spreading_itself_directly_within_inline_fragment(): assert_errors( """ fragment fragA on Pet { ... on Dog { ...fragA } } """, [ { "message": "Cannot spread fragment 'fragA' within itself.", "locations": [(4, 17)], } ], ) def no_spreading_itself_indirectly(): assert_errors( """ fragment fragA on Dog { ...fragB } fragment fragB on Dog { ...fragA } """, [ { "message": "Cannot spread fragment 'fragA'" " within itself via 'fragB'.", "locations": [(2, 37), (3, 37)], } ], ) def no_spreading_itself_indirectly_reports_opposite_order(): assert_errors( """ fragment fragB on Dog { ...fragA } fragment fragA on Dog { ...fragB } """, [ { "message": "Cannot spread fragment 'fragB'" " within itself via 'fragA'.", "locations": [(2, 37), (3, 37)], } ], ) def no_spreading_itself_indirectly_within_inline_fragment(): assert_errors( """ fragment fragA on Pet { ... on Dog { ...fragB } } fragment fragB on Pet { ... on Dog { ...fragA } } """, [ { "message": "Cannot spread fragment 'fragA'" " within itself via 'fragB'.", "locations": [(4, 17), (9, 17)], } ], ) def no_spreading_itself_deeply(): assert_errors( """ fragment fragA on Dog { ...fragB } fragment fragB on Dog { ...fragC } fragment fragC on Dog { ...fragO } fragment fragX on Dog { ...fragY } fragment fragY on Dog { ...fragZ } fragment fragZ on Dog { ...fragO } fragment fragO on Dog { ...fragP } fragment fragP on Dog { ...fragA, ...fragX } """, [ { "message": "Cannot spread fragment 'fragA' within itself" " via 'fragB', 'fragC', 'fragO', 'fragP'.", "locations": [(2, 37), (3, 37), (4, 37), (8, 37), (9, 37)], "path": None, }, { "message": "Cannot spread fragment 'fragO' within itself" " via 'fragP', 'fragX', 'fragY', 'fragZ'.", "locations": [(8, 37), (9, 47), (5, 37), (6, 37), (7, 37)], "path": None, }, ], ) def no_spreading_itself_deeply_two_paths(): assert_errors( """ fragment fragA on Dog { ...fragB, ...fragC } fragment fragB on Dog { ...fragA } fragment fragC on Dog { ...fragA } """, [ { "message": "Cannot spread fragment 'fragA'" " within itself via 'fragB'.", "locations": [(2, 37), (3, 37)], }, { "message": "Cannot spread fragment 'fragA'" " within itself via 'fragC'.", "locations": [(2, 47), (4, 37)], }, ], ) def no_spreading_itself_deeply_two_paths_alt_traverse_order(): assert_errors( """ fragment fragA on Dog { ...fragC } fragment fragB on Dog { ...fragC } fragment fragC on Dog { ...fragA, ...fragB } """, [ { "message": "Cannot spread fragment 'fragA'" " within itself via 'fragC'.", "locations": [(2, 37), (4, 37)], }, { "message": "Cannot spread fragment 'fragC'" " within itself via 'fragB'.", "locations": [(4, 47), (3, 37)], }, ], ) def no_spreading_itself_deeply_and_immediately(): assert_errors( """ fragment fragA on Dog { ...fragB } fragment fragB on Dog { ...fragB, ...fragC } fragment fragC on Dog { ...fragA, ...fragB } """, [ { "message": "Cannot spread fragment 'fragB' within itself.", "locations": [(3, 37)], }, { "message": "Cannot spread fragment 'fragA'" " within itself via 'fragB', 'fragC'.", "locations": [(2, 37), (3, 47), (4, 37)], }, { "message": "Cannot spread fragment 'fragB'" " within itself via 'fragC'.", "locations": [(3, 47), (4, 47)], }, ], ) graphql-core-3.2.6/tests/validation/test_no_schema_introspection.py000066400000000000000000000075561474546154300257610ustar00rootroot00000000000000from functools import partial from graphql.utilities import build_schema from graphql.validation import NoSchemaIntrospectionCustomRule from .harness import assert_validation_errors schema = build_schema( """ type Query { someQuery: SomeType } type SomeType { someField: String introspectionField: __EnumValue } """ ) assert_errors = partial( assert_validation_errors, NoSchemaIntrospectionCustomRule, schema=schema ) assert_valid = partial(assert_errors, errors=[]) def describe_validate_prohibit_introspection_queries(): def ignores_valid_fields_including_typename(): assert_valid( """ { someQuery { __typename someField } } """ ) def ignores_fields_not_in_the_schema(): assert_valid( """ { __introspect } """ ) def reports_error_when_a_field_with_an_introspection_type_is_requested(): assert_errors( """ { __schema { queryType { name } } } """, [ { "message": "GraphQL introspection has been disabled," " but the requested query contained the field '__schema'.", "locations": [(3, 15)], }, { "message": "GraphQL introspection has been disabled," " but the requested query contained the field 'queryType'.", "locations": [(4, 17)], }, ], ) def reports_error_when_a_field_with_introspection_type_is_requested_and_aliased(): assert_errors( """ { s: __schema { queryType { name } } } """, [ { "message": "GraphQL introspection has been disabled," " but the requested query contained the field '__schema'.", "locations": [(3, 15)], }, { "message": "GraphQL introspection has been disabled," " but the requested query contained the field 'queryType'.", "locations": [(4, 17)], }, ], ) def reports_error_when_using_a_fragment_with_a_field_with_an_introspection_type(): assert_errors( """ { ...QueryFragment } fragment QueryFragment on Query { __schema { queryType { name } } } """, [ { "message": "GraphQL introspection has been disabled," " but the requested query contained the field '__schema'.", "locations": [(7, 15)], }, { "message": "GraphQL introspection has been disabled," " but the requested query contained the field 'queryType'.", "locations": [(8, 17)], }, ], ) def reports_error_for_non_standard_introspection_fields(): assert_errors( """ { someQuery { introspectionField } } """, [ { "message": "GraphQL introspection has been disabled, but" " the requested query contained the field 'introspectionField'.", "locations": [(4, 17)], }, ], ) graphql-core-3.2.6/tests/validation/test_no_undefined_variables.py000066400000000000000000000237101474546154300255200ustar00rootroot00000000000000from functools import partial from graphql.validation import NoUndefinedVariablesRule from .harness import assert_validation_errors assert_errors = partial(assert_validation_errors, NoUndefinedVariablesRule) assert_valid = partial(assert_errors, errors=[]) def describe_validate_no_undefined_variables(): def all_variables_defined(): assert_valid( """ query Foo($a: String, $b: String, $c: String) { field(a: $a, b: $b, c: $c) } """ ) def all_variables_deeply_defined(): assert_valid( """ query Foo($a: String, $b: String, $c: String) { field(a: $a) { field(b: $b) { field(c: $c) } } } """ ) def all_variables_deeply_in_inline_fragments_defined(): assert_valid( """ query Foo($a: String, $b: String, $c: String) { ... on Type { field(a: $a) { field(b: $b) { ... on Type { field(c: $c) } } } } } """ ) def all_variables_in_fragments_deeply_defined(): assert_valid( """ query Foo($a: String, $b: String, $c: String) { ...FragA } fragment FragA on Type { field(a: $a) { ...FragB } } fragment FragB on Type { field(b: $b) { ...FragC } } fragment FragC on Type { field(c: $c) } """ ) def variable_within_single_fragment_defined_in_multiple_operations(): assert_valid( """ query Foo($a: String) { ...FragA } query Bar($a: String) { ...FragA } fragment FragA on Type { field(a: $a) } """ ) def variable_within_fragments_defined_in_operations(): assert_valid( """ query Foo($a: String) { ...FragA } query Bar($b: String) { ...FragB } fragment FragA on Type { field(a: $a) } fragment FragB on Type { field(b: $b) } """ ) def variable_within_recursive_fragment_defined(): assert_valid( """ query Foo($a: String) { ...FragA } fragment FragA on Type { field(a: $a) { ...FragA } } """ ) def variable_not_defined(): assert_errors( """ query Foo($a: String, $b: String, $c: String) { field(a: $a, b: $b, c: $c, d: $d) } """, [ { "message": "Variable '$d' is not defined by operation 'Foo'.", "locations": [(3, 45), (2, 13)], }, ], ) def variable_not_defined_by_unnamed_query(): assert_errors( """ { field(a: $a) } """, [ { "message": "Variable '$a' is not defined.", "locations": [(3, 24), (2, 13)], }, ], ) def multiple_variables_not_defined(): assert_errors( """ query Foo($b: String) { field(a: $a, b: $b, c: $c) } """, [ { "message": "Variable '$a' is not defined by operation 'Foo'.", "locations": [(3, 24), (2, 13)], }, { "message": "Variable '$c' is not defined by operation 'Foo'.", "locations": [(3, 38), (2, 13)], }, ], ) def variable_in_fragment_not_defined_by_unnamed_query(): assert_errors( """ { ...FragA } fragment FragA on Type { field(a: $a) } """, [ { "message": "Variable '$a' is not defined.", "locations": [(6, 24), (2, 13)], }, ], ) def variable_in_fragment_not_defined_by_operation(): assert_errors( """ query Foo($a: String, $b: String) { ...FragA } fragment FragA on Type { field(a: $a) { ...FragB } } fragment FragB on Type { field(b: $b) { ...FragC } } fragment FragC on Type { field(c: $c) } """, [ { "message": "Variable '$c' is not defined by operation 'Foo'.", "locations": [(16, 24), (2, 13)], }, ], ) def multiple_variables_in_fragments_not_defined(): assert_errors( """ query Foo($b: String) { ...FragA } fragment FragA on Type { field(a: $a) { ...FragB } } fragment FragB on Type { field(b: $b) { ...FragC } } fragment FragC on Type { field(c: $c) } """, [ { "message": "Variable '$a' is not defined by operation 'Foo'.", "locations": [(6, 24), (2, 13)], }, { "message": "Variable '$c' is not defined by operation 'Foo'.", "locations": [(16, 24), (2, 13)], }, ], ) def single_variable_in_fragment_not_defined_by_multiple_operations(): assert_errors( """ query Foo($a: String) { ...FragAB } query Bar($a: String) { ...FragAB } fragment FragAB on Type { field(a: $a, b: $b) } """, [ { "message": "Variable '$b' is not defined by operation 'Foo'.", "locations": [(9, 31), (2, 13)], }, { "message": "Variable '$b' is not defined by operation 'Bar'.", "locations": [(9, 31), (5, 13)], }, ], ) def variables_in_fragment_not_defined_by_multiple_operations(): assert_errors( """ query Foo($b: String) { ...FragAB } query Bar($a: String) { ...FragAB } fragment FragAB on Type { field(a: $a, b: $b) } """, [ { "message": "Variable '$a' is not defined by operation 'Foo'.", "locations": [(9, 24), (2, 13)], }, { "message": "Variable '$b' is not defined by operation 'Bar'.", "locations": [(9, 31), (5, 13)], }, ], ) def variable_in_fragment_used_by_other_operation(): assert_errors( """ query Foo($b: String) { ...FragA } query Bar($a: String) { ...FragB } fragment FragA on Type { field(a: $a) } fragment FragB on Type { field(b: $b) } """, [ { "message": "Variable '$a' is not defined by operation 'Foo'.", "locations": [(9, 24), (2, 13)], }, { "message": "Variable '$b' is not defined by operation 'Bar'.", "locations": [(12, 24), (5, 13)], }, ], ) def multiple_undefined_variables_produce_multiple_errors(): assert_errors( """ query Foo($b: String) { ...FragAB } query Bar($a: String) { ...FragAB } fragment FragAB on Type { field1(a: $a, b: $b) ...FragC field3(a: $a, b: $b) } fragment FragC on Type { field2(c: $c) } """, [ { "message": "Variable '$a' is not defined by operation 'Foo'.", "locations": [(9, 25), (2, 13)], }, { "message": "Variable '$a' is not defined by operation 'Foo'.", "locations": [(11, 25), (2, 13)], }, { "message": "Variable '$c' is not defined by operation 'Foo'.", "locations": [(14, 25), (2, 13)], }, { "message": "Variable '$b' is not defined by operation 'Bar'.", "locations": [(9, 32), (5, 13)], }, { "message": "Variable '$b' is not defined by operation 'Bar'.", "locations": [(11, 32), (5, 13)], }, { "message": "Variable '$c' is not defined by operation 'Bar'.", "locations": [(14, 25), (5, 13)], }, ], ) graphql-core-3.2.6/tests/validation/test_no_unused_fragments.py000066400000000000000000000077451474546154300251120ustar00rootroot00000000000000from functools import partial from graphql.validation import NoUnusedFragmentsRule from .harness import assert_validation_errors assert_errors = partial(assert_validation_errors, NoUnusedFragmentsRule) assert_valid = partial(assert_errors, errors=[]) def describe_validate_no_unused_fragments(): def all_fragment_names_are_used(): assert_valid( """ { human(id: 4) { ...HumanFields1 ... on Human { ...HumanFields2 } } } fragment HumanFields1 on Human { name ...HumanFields3 } fragment HumanFields2 on Human { name } fragment HumanFields3 on Human { name } """ ) def all_fragment_names_are_used_by_multiple_operations(): assert_valid( """ query Foo { human(id: 4) { ...HumanFields1 } } query Bar { human(id: 4) { ...HumanFields2 } } fragment HumanFields1 on Human { name ...HumanFields3 } fragment HumanFields2 on Human { name } fragment HumanFields3 on Human { name } """ ) def contains_unknown_fragments(): assert_errors( """ query Foo { human(id: 4) { ...HumanFields1 } } query Bar { human(id: 4) { ...HumanFields2 } } fragment HumanFields1 on Human { name ...HumanFields3 } fragment HumanFields2 on Human { name } fragment HumanFields3 on Human { name } fragment Unused1 on Human { name } fragment Unused2 on Human { name } """, [ { "message": "Fragment 'Unused1' is never used.", "locations": [(22, 13)], }, { "message": "Fragment 'Unused2' is never used.", "locations": [(25, 13)], }, ], ) def contains_unknown_fragments_with_ref_cycle(): assert_errors( """ query Foo { human(id: 4) { ...HumanFields1 } } query Bar { human(id: 4) { ...HumanFields2 } } fragment HumanFields1 on Human { name ...HumanFields3 } fragment HumanFields2 on Human { name } fragment HumanFields3 on Human { name } fragment Unused1 on Human { name ...Unused2 } fragment Unused2 on Human { name ...Unused1 } """, [ { "message": "Fragment 'Unused1' is never used.", "locations": [(22, 13)], }, { "message": "Fragment 'Unused2' is never used.", "locations": [(26, 13)], }, ], ) def contains_unknown_and_undefined_fragments(): assert_errors( """ query Foo { human(id: 4) { ...bar } } fragment foo on Human { name } """, [{"message": "Fragment 'foo' is never used.", "locations": [(7, 13)]}], ) graphql-core-3.2.6/tests/validation/test_no_unused_variables.py000066400000000000000000000141701474546154300250620ustar00rootroot00000000000000from functools import partial from graphql.validation import NoUnusedVariablesRule from .harness import assert_validation_errors assert_errors = partial(assert_validation_errors, NoUnusedVariablesRule) assert_valid = partial(assert_errors, errors=[]) def describe_validate_no_unused_variables(): def uses_all_variables(): assert_valid( """ query ($a: String, $b: String, $c: String) { field(a: $a, b: $b, c: $c) } """ ) def uses_all_variables_deeply(): assert_valid( """ query Foo($a: String, $b: String, $c: String) { field(a: $a) { field(b: $b) { field(c: $c) } } } """ ) def uses_all_variables_deeply_in_inline_fragments(): assert_valid( """ query Foo($a: String, $b: String, $c: String) { ... on Type { field(a: $a) { field(b: $b) { ... on Type { field(c: $c) } } } } } """ ) def uses_all_variables_in_fragment(): assert_valid( """ query Foo($a: String, $b: String, $c: String) { ...FragA } fragment FragA on Type { field(a: $a) { ...FragB } } fragment FragB on Type { field(b: $b) { ...FragC } } fragment FragC on Type { field(c: $c) } """ ) def variable_used_by_fragment_in_multiple_operations(): assert_valid( """ query Foo($a: String) { ...FragA } query Bar($b: String) { ...FragB } fragment FragA on Type { field(a: $a) } fragment FragB on Type { field(b: $b) } """ ) def variable_used_by_recursive_fragment(): assert_valid( """ query Foo($a: String) { ...FragA } fragment FragA on Type { field(a: $a) { ...FragA } } """ ) def variable_not_used(): assert_errors( """ query ($a: String, $b: String, $c: String) { field(a: $a, b: $b) } """, [{"message": "Variable '$c' is never used.", "locations": [(2, 44)]}], ) def multiple_variables_not_used(): assert_errors( """ query Foo($a: String, $b: String, $c: String) { field(b: $b) } """, [ { "message": "Variable '$a' is never used in operation 'Foo'.", "locations": [(2, 23)], }, { "message": "Variable '$c' is never used in operation 'Foo'.", "locations": [(2, 47)], }, ], ) def variable_not_used_in_fragments(): assert_errors( """ query Foo($a: String, $b: String, $c: String) { ...FragA } fragment FragA on Type { field(a: $a) { ...FragB } } fragment FragB on Type { field(b: $b) { ...FragC } } fragment FragC on Type { field } """, [ { "message": "Variable '$c' is never used in operation 'Foo'.", "locations": [(2, 47)], }, ], ) def multiple_variables_not_used_in_fragments(): assert_errors( """ query Foo($a: String, $b: String, $c: String) { ...FragA } fragment FragA on Type { field { ...FragB } } fragment FragB on Type { field(b: $b) { ...FragC } } fragment FragC on Type { field } """, [ { "message": "Variable '$a' is never used in operation 'Foo'.", "locations": [(2, 23)], }, { "message": "Variable '$c' is never used in operation 'Foo'.", "locations": [(2, 47)], }, ], ) def variable_not_used_by_unreferenced_fragment(): assert_errors( """ query Foo($b: String) { ...FragA } fragment FragA on Type { field(a: $a) } fragment FragB on Type { field(b: $b) } """, [ { "message": "Variable '$b' is never used in operation 'Foo'.", "locations": [(2, 23)], }, ], ) def variable_not_used_by_fragment_used_by_other_operation(): assert_errors( """ query Foo($b: String) { ...FragA } query Bar($a: String) { ...FragB } fragment FragA on Type { field(a: $a) } fragment FragB on Type { field(b: $b) } """, [ { "message": "Variable '$b' is never used in operation 'Foo'.", "locations": [(2, 23)], }, { "message": "Variable '$a' is never used in operation 'Bar'.", "locations": [(5, 23)], }, ], ) graphql-core-3.2.6/tests/validation/test_overlapping_fields_can_be_merged.py000066400000000000000000001033601474546154300275210ustar00rootroot00000000000000from functools import partial from graphql.utilities import build_schema from graphql.validation import OverlappingFieldsCanBeMergedRule from .harness import assert_validation_errors assert_errors = partial(assert_validation_errors, OverlappingFieldsCanBeMergedRule) assert_valid = partial(assert_errors, errors=[]) def describe_validate_overlapping_fields_can_be_merged(): def unique_fields(): assert_valid( """ fragment uniqueFields on Dog { name nickname } """ ) def identical_fields(): assert_valid( """ fragment mergeIdenticalFields on Dog { name name } """ ) def identical_fields_with_identical_args(): assert_valid( """ fragment mergeIdenticalFieldsWithIdenticalArgs on Dog { doesKnowCommand(dogCommand: SIT) doesKnowCommand(dogCommand: SIT) } """ ) def identical_fields_with_identical_directives(): assert_valid( """ fragment mergeSameFieldsWithSameDirectives on Dog { name @include(if: true) name @include(if: true) } """ ) def different_args_with_different_aliases(): assert_valid( """ fragment differentArgsWithDifferentAliases on Dog { knowsSit: doesKnowCommand(dogCommand: SIT) knowsDown: doesKnowCommand(dogCommand: DOWN) } """ ) def different_directives_with_different_aliases(): assert_valid( """ fragment differentDirectivesWithDifferentAliases on Dog { nameIfTrue: name @include(if: true) nameIfFalse: name @include(if: false) } """ ) def different_skip_or_include_directives_accepted(): # Note: Differing skip/include directives don't create an ambiguous # return value and are acceptable in conditions where differing runtime # values may have the same desired effect of including/skipping a field assert_valid( """ fragment differentDirectivesWithDifferentAliases on Dog { name @include(if: true) name @include(if: false) } """ ) def same_aliases_with_different_field_targets(): assert_errors( """ fragment sameAliasesWithDifferentFieldTargets on Dog { fido: name fido: nickname } """, [ { "message": "Fields 'fido' conflict" " because 'name' and 'nickname' are different fields." " Use different aliases on the fields" " to fetch both if this was intentional.", "locations": [(3, 15), (4, 15)], "path": None, } ], ) def same_aliases_allowed_on_non_overlapping_fields(): assert_valid( """ fragment sameAliasesWithDifferentFieldTargets on Pet { ... on Dog { name } ... on Cat { name: nickname } } """ ) def alias_masking_direct_field_access(): assert_errors( """ fragment aliasMaskingDirectFieldAccess on Dog { name: nickname name } """, [ { "message": "Fields 'name' conflict" " because 'nickname' and 'name' are different fields." " Use different aliases on the fields" " to fetch both if this was intentional.", "locations": [(3, 15), (4, 15)], } ], ) def different_args_second_adds_an_argument(): assert_errors( """ fragment conflictingArgs on Dog { doesKnowCommand doesKnowCommand(dogCommand: HEEL) } """, [ { "message": "Fields 'doesKnowCommand' conflict" " because they have differing arguments." " Use different aliases on the fields" " to fetch both if this was intentional.", "locations": [(3, 15), (4, 15)], } ], ) def different_args_second_missing_an_argument(): assert_errors( """ fragment conflictingArgs on Dog { doesKnowCommand(dogCommand: SIT) doesKnowCommand } """, [ { "message": "Fields 'doesKnowCommand' conflict" " because they have differing arguments." " Use different aliases on the fields" " to fetch both if this was intentional.", "locations": [(3, 15), (4, 15)], } ], ) def conflicting_arg_values(): assert_errors( """ fragment conflictingArgs on Dog { doesKnowCommand(dogCommand: SIT) doesKnowCommand(dogCommand: HEEL) } """, [ { "message": "Fields 'doesKnowCommand' conflict" " because they have differing arguments." " Use different aliases on the fields" " to fetch both if this was intentional.", "locations": [(3, 15), (4, 15)], } ], ) def conflicting_arg_names(): assert_errors( """ fragment conflictingArgs on Dog { isAtLocation(x: 0) isAtLocation(y: 0) } """, [ { "message": "Fields 'isAtLocation' conflict" " because they have differing arguments." " Use different aliases on the fields" " to fetch both if this was intentional.", "locations": [(3, 15), (4, 15)], } ], ) def allows_different_args_where_no_conflict_is_possible(): # This is valid since no object can be both a "Dog" and a "Cat", thus # these fields can never overlap. assert_valid( """ fragment conflictingArgs on Pet { ... on Dog { name(surname: true) } ... on Cat { name } } """ ) def allows_different_order_of_args(): schema = build_schema( """ type Query { someField(a: String, b: String): String } """ ) # This is valid since arguments are unordered, see: # https://spec.graphql.org/draft/# # sec-Language.Arguments.Arguments-are-unordered assert_valid( """ { someField(a: null, b: null) someField(b: null, a: null) } """, schema=schema, ) def allows_different_order_of_input_object_fields_in_arg_values(): schema = build_schema( """ input SomeInput { a: String b: String } type Query { someField(arg: SomeInput): String } """ ) # This is valid since input object fields are unordered, see: # https://spec.graphql.org/draft/# # sec-Input-Object-Values.Input-object-fields-are-unordered assert_valid( """ { someField(arg: { a: null, b: null }) someField(arg: { b: null, a: null }) } """, schema=schema, ) def encounters_conflict_in_fragments(): assert_errors( """ { ...A ...B } fragment A on Type { x: a } fragment B on Type { x: b } """, [ { "message": "Fields 'x' conflict" " because 'a' and 'b' are different fields." " Use different aliases on the fields" " to fetch both if this was intentional.", "locations": [(7, 15), (10, 15)], } ], ) def reports_each_conflict_once(): assert_errors( """ { f1 { ...A ...B } f2 { ...B ...A } f3 { ...A ...B x: c } } fragment A on Type { x: a } fragment B on Type { x: b } """, [ { "message": "Fields 'x' conflict" " because 'a' and 'b' are different fields." " Use different aliases on the fields" " to fetch both if this was intentional.", "locations": [(18, 15), (21, 15)], }, { "message": "Fields 'x' conflict" " because 'c' and 'a' are different fields." " Use different aliases on the fields" " to fetch both if this was intentional.", "locations": [(14, 17), (18, 15)], }, { "message": "Fields 'x' conflict" " because 'c' and 'b' are different fields." " Use different aliases on the fields" " to fetch both if this was intentional.", "locations": [(14, 17), (21, 15)], }, ], ) def deep_conflict(): assert_errors( """ { field { x: a }, field { x: b } } """, [ { "message": "Fields 'field' conflict" " because subfields 'x' conflict" " because 'a' and 'b' are different fields." " Use different aliases on the fields" " to fetch both if this was intentional.", "locations": [(3, 15), (4, 17), (6, 15), (7, 17)], } ], ) def deep_conflict_with_multiple_issues(): assert_errors( """ { field { x: a y: c }, field { x: b y: d } } """, [ { "message": "Fields 'field' conflict" " because subfields 'x' conflict" " because 'a' and 'b' are different fields" " and subfields 'y' conflict" " because 'c' and 'd' are different fields." " Use different aliases on the fields" " to fetch both if this was intentional.", "locations": [(3, 15), (4, 17), (5, 17), (7, 15), (8, 17), (9, 17)], "path": None, } ], ) def very_deep_conflict(): assert_errors( """ { field { deepField { x: a } }, field { deepField { x: b } } } """, [ { "message": "Fields 'field' conflict" " because subfields 'deepField' conflict" " because subfields 'x' conflict" " because 'a' and 'b' are different fields." " Use different aliases on the fields" " to fetch both if this was intentional.", "locations": [ (3, 15), (4, 17), (5, 19), (8, 15), (9, 17), (10, 19), ], "path": None, } ], ) def reports_deep_conflict_to_nearest_common_ancestor(): assert_errors( """ { field { deepField { x: a } deepField { x: b } }, field { deepField { y } } } """, [ { "message": "Fields 'deepField' conflict" " because subfields 'x' conflict" " because 'a' and 'b' are different fields." " Use different aliases on the fields" " to fetch both if this was intentional.", "locations": [(4, 17), (5, 19), (7, 17), (8, 19)], } ], ) def reports_deep_conflict_to_nearest_common_ancestor_in_fragments(): assert_errors( """ { field { ...F } field { ...F } } fragment F on T { deepField { deeperField { x: a } deeperField { x: b } }, deepField { deeperField { y } } } """, [ { "message": "Fields 'deeperField' conflict" " because subfields 'x' conflict" " because 'a' and 'b' are different fields." " Use different aliases on the fields" " to fetch both if this was intentional.", "locations": [(12, 17), (13, 19), (15, 17), (16, 19)], } ], ) def reports_deep_conflict_in_nested_fragments(): assert_errors( """ { field { ...F }, field { ...I } } fragment F on T { x: a ...G } fragment G on T { y: c } fragment I on T { y: d ...J } fragment J on T { x: b } """, [ { "message": "Fields 'field' conflict" " because subfields 'x' conflict" " because 'a' and 'b' are different fields" " and subfields 'y' conflict" " because 'c' and 'd' are different fields." " Use different aliases on the fields" " to fetch both if this was intentional.", "locations": [ (3, 15), (11, 15), (15, 15), (6, 15), (22, 15), (18, 15), ], "path": None, } ], ) def ignores_unknown_fragments(): assert_valid( """ { field ...Unknown ...Known } fragment Known on T { field ...OtherUnknown } """ ) def describe_return_types_must_be_unambiguous(): schema = build_schema( """ interface SomeBox { deepBox: SomeBox unrelatedField: String } type StringBox implements SomeBox { scalar: String deepBox: StringBox unrelatedField: String listStringBox: [StringBox] stringBox: StringBox intBox: IntBox } type IntBox implements SomeBox { scalar: Int deepBox: IntBox unrelatedField: String listStringBox: [StringBox] stringBox: StringBox intBox: IntBox } interface NonNullStringBox1 { scalar: String! } type NonNullStringBox1Impl implements SomeBox & NonNullStringBox1 { scalar: String! unrelatedField: String deepBox: SomeBox } interface NonNullStringBox2 { scalar: String! } type NonNullStringBox2Impl implements SomeBox & NonNullStringBox2 { scalar: String! unrelatedField: String deepBox: SomeBox } type Connection { edges: [Edge] } type Edge { node: Node } type Node { id: ID name: String } type Query { someBox: SomeBox connection: Connection } """ ) def conflicting_return_types_which_potentially_overlap(): # This is invalid since an object could potentially be both the # Object type IntBox and the interface type NonNullStringBox1. # While that condition does not exist in the current schema, the # schema could expand in the future to allow this. assert_errors( """ { someBox { ...on IntBox { scalar } ...on NonNullStringBox1 { scalar } } } """, [ { "message": "Fields 'scalar' conflict because" " they return conflicting types 'Int' and 'String!'." " Use different aliases on the fields" " to fetch both if this was intentional.", "locations": [(5, 23), (8, 23)], } ], schema, ) def compatible_return_shapes_on_different_return_types(): # In this case `deepBox` returns `SomeBox` in the first usage, and # `StringBox` in the second usage. These types are not the same! # However this is valid because the return *shapes* are compatible. assert_valid( """ { someBox { ... on SomeBox { deepBox { unrelatedField } } ... on StringBox { deepBox { unrelatedField } } } } """, schema=schema, ) def disallows_differing_return_types_despite_no_overlap(): assert_errors( """ { someBox { ... on IntBox { scalar } ... on StringBox { scalar } } } """, [ { "message": "Fields 'scalar' conflict because" " they return conflicting types 'Int' and 'String'." " Use different aliases on the fields" " to fetch both if this was intentional.", "locations": [(5, 23), (8, 23)], } ], schema, ) def reports_correctly_when_a_non_exclusive_follows_an_exclusive(): assert_errors( """ { someBox { ... on IntBox { deepBox { ...X } } } someBox { ... on StringBox { deepBox { ...Y } } } memoed: someBox { ... on IntBox { deepBox { ...X } } } memoed: someBox { ... on StringBox { deepBox { ...Y } } } other: someBox { ...X } other: someBox { ...Y } } fragment X on SomeBox { scalar } fragment Y on SomeBox { scalar: unrelatedField } """, [ { "message": "Fields 'other' conflict because" " subfields 'scalar' conflict because" " 'scalar' and 'unrelatedField' are different fields." " Use different aliases on the fields" " to fetch both if this was intentional.", "locations": [(31, 19), (39, 19), (34, 19), (42, 19)], "path": None, } ], schema, ) def disallows_differing_return_type_nullability_despite_no_overlap(): assert_errors( """ { someBox { ... on NonNullStringBox1 { scalar } ... on StringBox { scalar } } } """, [ { "message": "Fields 'scalar' conflict because" " they return conflicting types 'String!' and 'String'." " Use different aliases on the fields" " to fetch both if this was intentional.", "locations": [(5, 23), (8, 23)], } ], schema, ) def disallows_differing_return_type_list_despite_no_overlap_1(): assert_errors( """ { someBox { ... on IntBox { box: listStringBox { scalar } } ... on StringBox { box: stringBox { scalar } } } } """, [ { "message": "Fields 'box' conflict because they return" " conflicting types '[StringBox]' and 'StringBox'." " Use different aliases on the fields" " to fetch both if this was intentional.", "locations": [(5, 23), (10, 23)], } ], schema, ) assert_errors( """ { someBox { ... on IntBox { box: stringBox { scalar } } ... on StringBox { box: listStringBox { scalar } } } } """, [ { "message": "Fields 'box' conflict because they return" " conflicting types 'StringBox' and '[StringBox]'." " Use different aliases on the fields" " to fetch both if this was intentional.", "locations": [(5, 23), (10, 23)], } ], schema, ) def disallows_differing_subfields(): assert_errors( """ { someBox { ... on IntBox { box: stringBox { val: scalar val: unrelatedField } } ... on StringBox { box: stringBox { val: scalar } } } } """, [ { "message": "Fields 'val' conflict because" " 'scalar' and 'unrelatedField' are different fields." " Use different aliases on the fields" " to fetch both if this was intentional.", "locations": [(6, 25), (7, 25)], } ], schema, ) def disallows_differing_deep_return_types_despite_no_overlap(): assert_errors( """ { someBox { ... on IntBox { box: stringBox { scalar } } ... on StringBox { box: intBox { scalar } } } } """, [ { "message": "Fields 'box' conflict" " because subfields 'scalar' conflict" " because they return conflicting types 'String' and 'Int'." " Use different aliases on the fields" " to fetch both if this was intentional.", "locations": [(5, 23), (6, 25), (10, 23), (11, 25)], "path": None, } ], schema, ) def allows_non_conflicting_overlapping_types(): assert_valid( """ { someBox { ... on IntBox { scalar: unrelatedField } ... on StringBox { scalar } } } """, schema=schema, ) def same_wrapped_scalar_return_types(): assert_valid( """ { someBox { ...on NonNullStringBox1 { scalar } ...on NonNullStringBox2 { scalar } } } """, schema=schema, ) def allows_inline_fragments_without_type_condition(): assert_valid( """ { a ... { a } } """, schema=schema, ) def compares_deep_types_including_list(): assert_errors( """ { connection { ...edgeID edges { node { id: name } } } } fragment edgeID on Connection { edges { node { id } } } """, [ { "message": "Fields 'edges' conflict" " because subfields 'node' conflict" " because subfields 'id' conflict" " because 'name' and 'id' are different fields." " Use different aliases on the fields" " to fetch both if this was intentional.", "locations": [ (5, 21), (6, 23), (7, 25), (14, 19), (15, 21), (16, 23), ], "path": None, } ], schema, ) def ignores_unknown_types(): assert_valid( """ { someBox { ...on UnknownType { scalar } ...on NonNullStringBox2 { scalar } } } """, schema=schema, ) def works_for_field_names_that_are_js_keywords(): schema_with_keywords = build_schema( """ type Foo { constructor: String } type Query { foo: Foo } """ ) assert_valid( """ { foo { constructor } } """, schema=schema_with_keywords, ) def works_for_field_names_that_are_python_keywords(): schema_with_keywords = build_schema( """ type Foo { class: String } type Query { foo: Foo } """ ) assert_valid( """ { foo { class } } """, schema=schema_with_keywords, ) def does_not_infinite_loop_on_recursive_fragments(): assert_valid( """ { ...fragA } fragment fragA on Human { name, relatives { name, ...fragA } } """ ) def does_not_infinite_loop_on_immediately_recursive_fragments(): assert_valid( """ { ...fragA } fragment fragA on Human { name, ...fragA } """ ) def does_not_infinite_loop_on_recursive_fragment_with_field_named_after_fragment(): assert_valid( """ { ...fragA fragA } fragment fragA on Query { ...fragA } """ ) def finds_invalid_cases_even_with_field_named_after_fragment(): assert_errors( """ { fragA ...fragA } fragment fragA on Type { fragA: b } """, [ { "message": "Fields 'fragA' conflict" " because 'fragA' and 'b' are different fields." " Use different aliases on the fields" " to fetch both if this was intentional.", "locations": [(3, 15), (8, 15)], } ], ) def does_not_infinite_loop_on_transitively_recursive_fragments(): assert_valid( """ { ...fragA fragB } fragment fragA on Human { name, ...fragB } fragment fragB on Human { name, ...fragC } fragment fragC on Human { name, ...fragA } """ ) def finds_invalid_case_even_with_immediately_recursive_fragment(): assert_errors( """ fragment sameAliasesWithDifferentFieldTargets on Dog { ...sameAliasesWithDifferentFieldTargets fido: name fido: nickname } """, [ { "message": "Fields 'fido' conflict" " because 'name' and 'nickname' are different fields." " Use different aliases on the fields" " to fetch both if this was intentional.", "locations": [(4, 15), (5, 15)], } ], ) graphql-core-3.2.6/tests/validation/test_possible_fragment_spreads.py000066400000000000000000000234451474546154300262640ustar00rootroot00000000000000from functools import partial from graphql.utilities import build_schema from graphql.validation import PossibleFragmentSpreadsRule from .harness import assert_validation_errors test_schema = build_schema( """ interface Being { name: String } interface Pet implements Being { name: String } type Dog implements Being & Pet { name: String barkVolume: Int } type Cat implements Being & Pet { name: String meowVolume: Int } union CatOrDog = Cat | Dog interface Intelligent { iq: Int } type Human implements Being & Intelligent { name: String pets: [Pet] iq: Int } type Alien implements Being & Intelligent { name: String iq: Int } union DogOrHuman = Dog | Human union HumanOrAlien = Human | Alien type Query { catOrDog: CatOrDog dogOrHuman: DogOrHuman humanOrAlien: HumanOrAlien } """ ) assert_errors = partial( assert_validation_errors, PossibleFragmentSpreadsRule, schema=test_schema ) assert_valid = partial(assert_errors, errors=[]) def describe_validate_possible_fragment_spreads(): def of_the_same_object(): assert_valid( """ fragment objectWithinObject on Dog { ...dogFragment } fragment dogFragment on Dog { barkVolume } """ ) def of_the_same_object_inline_fragment(): assert_valid( """ fragment objectWithinObjectAnon on Dog { ... on Dog { barkVolume } } """ ) def object_into_implemented_interface(): assert_valid( """ fragment objectWithinInterface on Pet { ...dogFragment } fragment dogFragment on Dog { barkVolume } """ ) def object_into_containing_union(): assert_valid( """ fragment objectWithinUnion on CatOrDog { ...dogFragment } fragment dogFragment on Dog { barkVolume } """ ) def union_into_contained_object(): assert_valid( """ fragment unionWithinObject on Dog { ...catOrDogFragment } fragment catOrDogFragment on CatOrDog { __typename } """ ) def union_into_overlapping_interface(): assert_valid( """ fragment unionWithinInterface on Pet { ...catOrDogFragment } fragment catOrDogFragment on CatOrDog { __typename } """ ) def union_into_overlapping_union(): assert_valid( """ fragment unionWithinUnion on DogOrHuman { ...catOrDogFragment } fragment catOrDogFragment on CatOrDog { __typename } """ ) def interface_into_implemented_object(): assert_valid( """ fragment interfaceWithinObject on Dog { ...petFragment } fragment petFragment on Pet { name } """ ) def interface_into_overlapping_interface(): assert_valid( """ fragment interfaceWithinInterface on Pet { ...beingFragment } fragment beingFragment on Being { name } """ ) def interface_into_overlapping_interface_in_inline_fragment(): assert_valid( """ fragment interfaceWithinInterface on Pet { ... on Being { name } } """ ) def interface_into_overlapping_union(): assert_valid( """ fragment interfaceWithinUnion on CatOrDog { ...petFragment } fragment petFragment on Pet { name } """ ) def ignores_incorrect_type_caught_by_fragments_on_composite_types(): assert_valid( """ fragment petFragment on Pet { ...badInADifferentWay } fragment badInADifferentWay on String { name } """ ) def ignores_unknown_fragments_caught_by_known_fragment_names(): assert_valid( """ fragment petFragment on Pet { ...UnknownFragment } """ ) def different_object_into_object(): assert_errors( """ fragment invalidObjectWithinObject on Cat { ...dogFragment } fragment dogFragment on Dog { barkVolume } """, [ { "message": "Fragment 'dogFragment' cannot be spread here" " as objects of type 'Cat' can never be of type 'Dog'.", "locations": [(2, 57)], }, ], ) def different_object_into_object_in_inline_fragment(): assert_errors( """ fragment invalidObjectWithinObjectAnon on Cat { ... on Dog { barkVolume } } """, [ { "message": "Fragment cannot be spread here" " as objects of type 'Cat' can never be of type 'Dog'.", "locations": [(3, 15)], }, ], ) def object_into_not_implementing_interface(): assert_errors( """ fragment invalidObjectWithinInterface on Pet { ...humanFragment } fragment humanFragment on Human { pets { name } } """, [ { "message": "Fragment 'humanFragment' cannot be spread here" " as objects of type 'Pet' can never be of type 'Human'.", "locations": [(2, 60)], }, ], ) def object_into_not_containing_union(): assert_errors( """ fragment invalidObjectWithinUnion on CatOrDog { ...humanFragment } fragment humanFragment on Human { pets { name } } """, [ { "message": "Fragment 'humanFragment' cannot be spread here" " as objects of type 'CatOrDog' can never be of type 'Human'.", "locations": [(2, 61)], }, ], ) def union_into_not_contained_object(): assert_errors( """ fragment invalidUnionWithinObject on Human { ...catOrDogFragment } fragment catOrDogFragment on CatOrDog { __typename } """, [ { "message": "Fragment 'catOrDogFragment' cannot be spread here" " as objects of type 'Human' can never be of type 'CatOrDog'.", "locations": [(2, 58)], }, ], ) def union_into_non_overlapping_interface(): assert_errors( """ fragment invalidUnionWithinInterface on Pet { ...humanOrAlienFragment } fragment humanOrAlienFragment on HumanOrAlien { __typename } """, [ { "message": "Fragment 'humanOrAlienFragment' cannot be spread here" " as objects of type 'Pet' can never be of type 'HumanOrAlien'.", "locations": [(2, 59)], }, ], ) def union_into_non_overlapping_union(): assert_errors( """ fragment invalidUnionWithinUnion on CatOrDog { ...humanOrAlienFragment } fragment humanOrAlienFragment on HumanOrAlien { __typename } """, [ { "message": "Fragment 'humanOrAlienFragment'" " cannot be spread here as objects of type 'CatOrDog'" " can never be of type 'HumanOrAlien'.", "locations": [(2, 60)], }, ], ) def interface_into_non_implementing_object(): assert_errors( """ fragment invalidInterfaceWithinObject on Cat { ...intelligentFragment } fragment intelligentFragment on Intelligent { iq } """, [ { "message": "Fragment 'intelligentFragment' cannot be spread here" " as objects of type 'Cat' can never be of type 'Intelligent'.", "locations": [(2, 60)], }, ], ) def interface_into_non_overlapping_interface(): assert_errors( """ fragment invalidInterfaceWithinInterface on Pet { ...intelligentFragment } fragment intelligentFragment on Intelligent { iq } """, [ { "message": "Fragment 'intelligentFragment' cannot be spread here" " as objects of type 'Pet' can never be of type 'Intelligent'.", "locations": [(3, 15)], }, ], ) def interface_into_non_overlapping_interface_in_inline_fragment(): assert_errors( """ fragment invalidInterfaceWithinInterfaceAnon on Pet { ...on Intelligent { iq } } """, [ { "message": "Fragment cannot be spread here as objects" " of type 'Pet' can never be of type 'Intelligent'.", "locations": [(3, 15)], }, ], ) def interface_into_non_overlapping_union(): assert_errors( """ fragment invalidInterfaceWithinUnion on HumanOrAlien { ...petFragment } fragment petFragment on Pet { name } """, [ { "message": "Fragment 'petFragment' cannot be spread here" " as objects of type 'HumanOrAlien' can never be of type 'Pet'.", "locations": [(2, 68)], }, ], ) graphql-core-3.2.6/tests/validation/test_possible_type_extensions.py000066400000000000000000000210361474546154300261720ustar00rootroot00000000000000from functools import partial from graphql.utilities import build_schema from graphql.validation.rules.possible_type_extensions import PossibleTypeExtensionsRule from .harness import assert_sdl_validation_errors assert_errors = partial(assert_sdl_validation_errors, PossibleTypeExtensionsRule) assert_valid = partial(assert_errors, errors=[]) def describe_validate_possible_type_extensions(): def no_extensions(): assert_valid( """ scalar FooScalar type FooObject interface FooInterface union FooUnion enum FooEnum input FooInputObject """ ) def one_extension_per_type(): assert_valid( """ scalar FooScalar type FooObject interface FooInterface union FooUnion enum FooEnum input FooInputObject extend scalar FooScalar @dummy extend type FooObject @dummy extend interface FooInterface @dummy extend union FooUnion @dummy extend enum FooEnum @dummy extend input FooInputObject @dummy """ ) def many_extensions_per_type(): assert_valid( """ scalar FooScalar type FooObject interface FooInterface union FooUnion enum FooEnum input FooInputObject extend scalar FooScalar @dummy extend type FooObject @dummy extend interface FooInterface @dummy extend union FooUnion @dummy extend enum FooEnum @dummy extend input FooInputObject @dummy extend scalar FooScalar @dummy extend type FooObject @dummy extend interface FooInterface @dummy extend union FooUnion @dummy extend enum FooEnum @dummy extend input FooInputObject @dummy """ ) def extending_unknown_type(): message = ( "Cannot extend type 'Unknown' because it is not defined." " Did you mean 'Known'?" ) assert_errors( """ type Known extend scalar Unknown @dummy extend type Unknown @dummy extend interface Unknown @dummy extend union Unknown @dummy extend enum Unknown @dummy extend input Unknown @dummy """, [ {"message": message, "locations": [(4, 27)]}, {"message": message, "locations": [(5, 25)]}, {"message": message, "locations": [(6, 30)]}, {"message": message, "locations": [(7, 26)]}, {"message": message, "locations": [(8, 25)]}, {"message": message, "locations": [(9, 26)]}, ], ) def does_not_consider_non_type_definitions(): message = "Cannot extend type 'Foo' because it is not defined." assert_errors( """ query Foo { __typename } fragment Foo on Query { __typename } directive @Foo on SCHEMA extend scalar Foo @dummy extend type Foo @dummy extend interface Foo @dummy extend union Foo @dummy extend enum Foo @dummy extend input Foo @dummy """, [ {"message": message, "locations": [(6, 27)]}, {"message": message, "locations": [(7, 25)]}, {"message": message, "locations": [(8, 30)]}, {"message": message, "locations": [(9, 26)]}, {"message": message, "locations": [(10, 25)]}, {"message": message, "locations": [(11, 26)]}, ], ) def extending_with_different_kinds(): assert_errors( """ scalar FooScalar type FooObject interface FooInterface union FooUnion enum FooEnum input FooInputObject extend type FooScalar @dummy extend interface FooObject @dummy extend union FooInterface @dummy extend enum FooUnion @dummy extend input FooEnum @dummy extend scalar FooInputObject @dummy """, [ { "message": "Cannot extend non-object type 'FooScalar'.", "locations": [(2, 13), (9, 13)], }, { "message": "Cannot extend non-interface type 'FooObject'.", "locations": [(3, 13), (10, 13)], }, { "message": "Cannot extend non-union type 'FooInterface'.", "locations": [(4, 13), (11, 13)], }, { "message": "Cannot extend non-enum type 'FooUnion'.", "locations": [(5, 13), (12, 13)], }, { "message": "Cannot extend non-input object type 'FooEnum'.", "locations": [(6, 13), (13, 13)], }, { "message": "Cannot extend non-scalar type 'FooInputObject'.", "locations": [(7, 13), (14, 13)], }, ], ) def extending_types_within_existing_schema(): schema = build_schema( """ scalar FooScalar type FooObject interface FooInterface union FooUnion enum FooEnum input FooInputObject """ ) sdl = """ extend scalar FooScalar @dummy extend type FooObject @dummy extend interface FooInterface @dummy extend union FooUnion @dummy extend enum FooEnum @dummy extend input FooInputObject @dummy """ assert_valid(sdl, schema=schema) def extending_unknown_types_within_existing_schema(): schema = build_schema("type Known") sdl = """ extend scalar Unknown @dummy extend type Unknown @dummy extend interface Unknown @dummy extend union Unknown @dummy extend enum Unknown @dummy extend input Unknown @dummy """ message = ( "Cannot extend type 'Unknown' because it is not defined." " Did you mean 'Known'?" ) assert_errors( sdl, [ {"message": message, "locations": [(2, 27)]}, {"message": message, "locations": [(3, 25)]}, {"message": message, "locations": [(4, 30)]}, {"message": message, "locations": [(5, 26)]}, {"message": message, "locations": [(6, 25)]}, {"message": message, "locations": [(7, 26)]}, ], schema, ) def extending_types_with_different_kinds_within_existing_schema(): schema = build_schema( """ scalar FooScalar type FooObject interface FooInterface union FooUnion enum FooEnum input FooInputObject """ ) sdl = """ extend type FooScalar @dummy extend interface FooObject @dummy extend union FooInterface @dummy extend enum FooUnion @dummy extend input FooEnum @dummy extend scalar FooInputObject @dummy """ assert_errors( sdl, [ { "message": "Cannot extend non-object type 'FooScalar'.", "locations": [(2, 13)], }, { "message": "Cannot extend non-interface type 'FooObject'.", "locations": [(3, 13)], }, { "message": "Cannot extend non-union type 'FooInterface'.", "locations": [(4, 13)], }, { "message": "Cannot extend non-enum type 'FooUnion'.", "locations": [(5, 13)], }, { "message": "Cannot extend non-input object type 'FooEnum'.", "locations": [(6, 13)], }, { "message": "Cannot extend non-scalar type 'FooInputObject'.", "locations": [(7, 13)], }, ], schema, ) graphql-core-3.2.6/tests/validation/test_provided_required_arguments.py000066400000000000000000000245751474546154300266460ustar00rootroot00000000000000from functools import partial from graphql.utilities import build_schema from graphql.validation import ProvidedRequiredArgumentsRule from graphql.validation.rules.provided_required_arguments import ( ProvidedRequiredArgumentsOnDirectivesRule, ) from .harness import assert_validation_errors, assert_sdl_validation_errors assert_errors = partial(assert_validation_errors, ProvidedRequiredArgumentsRule) assert_valid = partial(assert_errors, errors=[]) assert_sdl_errors = partial( assert_sdl_validation_errors, ProvidedRequiredArgumentsOnDirectivesRule ) assert_sdl_valid = partial(assert_sdl_errors, errors=[]) def describe_validate_provided_required_arguments(): def ignores_unknown_arguments(): assert_valid( """ { dog { isHouseTrained(unknownArgument: true) } }""" ) def describe_valid_non_nullable_value(): def arg_on_optional_arg(): assert_valid( """ { dog { isHouseTrained(atOtherHomes: true) } }""" ) def no_arg_on_optional_arg(): assert_valid( """ { dog { isHouseTrained } }""" ) def no_arg_on_non_null_field_with_default(): assert_valid( """ { complicatedArgs { nonNullFieldWithDefault } }""" ) def multiple_args(): assert_valid( """ { complicatedArgs { multipleReqs(req1: 1, req2: 2) } } """ ) def multiple_args_reverse_order(): assert_valid( """ { complicatedArgs { multipleReqs(req2: 2, req1: 1) } } """ ) def no_args_on_multiple_optional(): assert_valid( """ { complicatedArgs { multipleOpts } } """ ) def one_arg_on_multiple_optional(): assert_valid( """ { complicatedArgs { multipleOpts(opt1: 1) } } """ ) def second_arg_on_multiple_optional(): assert_valid( """ { complicatedArgs { multipleOpts(opt2: 1) } } """ ) def multiple_required_args_on_mixed_list(): assert_valid( """ { complicatedArgs { multipleOptAndReq(req1: 3, req2: 4) } } """ ) def multiple_required_and_one_optional_arg_on_mixed_list(): assert_valid( """ { complicatedArgs { multipleOptAndReq(req1: 3, req2: 4, opt1: 5) } } """ ) def all_required_and_optional_args_on_mixed_list(): assert_valid( """ { complicatedArgs { multipleOptAndReq(req1: 3, req2: 4, opt1: 5, opt2: 6) } } """ ) def describe_invalid_non_nullable_value(): def missing_one_non_nullable_argument(): assert_errors( """ { complicatedArgs { multipleReqs(req2: 2) } } """, [ { "message": "Field 'multipleReqs' argument 'req1'" " of type 'Int!' is required, but it was not provided.", "locations": [(4, 21)], }, ], ) def missing_multiple_non_nullable_arguments(): assert_errors( """ { complicatedArgs { multipleReqs } } """, [ { "message": "Field 'multipleReqs' argument 'req1'" " of type 'Int!' is required, but it was not provided.", "locations": [(4, 21)], }, { "message": "Field 'multipleReqs' argument 'req2'" " of type 'Int!' is required, but it was not provided.", "locations": [(4, 21)], }, ], ) def incorrect_value_and_missing_argument(): assert_errors( """ { complicatedArgs { multipleReqs(req1: "one") } } """, [ { "message": "Field 'multipleReqs' argument 'req2'" " of type 'Int!' is required, but it was not provided.", "locations": [(4, 21)], }, ], ) def describe_directive_arguments(): def ignores_unknown_directives(): assert_valid( """ { dog @unknown } """ ) def with_directives_of_valid_type(): assert_valid( """ { dog @include(if: true) { name } human @skip(if: false) { name } } """ ) def with_directive_with_missing_types(): assert_errors( """ { dog @include { name @skip } } """, [ { "message": "Directive '@include' argument 'if' of type" " 'Boolean!' is required, but it was not provided.", "locations": [(3, 23)], }, { "message": "Directive '@skip' argument 'if' of type" " 'Boolean!' is required, but it was not provided.", "locations": [(4, 26)], }, ], ) def describe_within_sdl(): def missing_optional_args_on_directive_defined_inside_sdl(): assert_sdl_valid( """ type Query { foo: String @test } directive @test(arg1: String, arg2: String! = "") on FIELD_DEFINITION """ ) def missing_arg_on_directive_defined_inside_sdl(): assert_sdl_errors( """ type Query { foo: String @test } directive @test(arg: String!) on FIELD_DEFINITION """, [ { "message": "Directive '@test' argument 'arg' of type" " 'String!' is required, but it was not provided.", "locations": [(3, 31)], }, ], ) def missing_arg_on_standard_directive(): assert_sdl_errors( """ type Query { foo: String @include } """, [ { "message": "Directive '@include' argument 'if' of type" " 'Boolean!' is required, but it was not provided.", "locations": [(3, 31)], }, ], ) def missing_arg_on_overridden_standard_directive(): assert_sdl_errors( """ type Query { foo: String @deprecated } directive @deprecated(reason: String!) on FIELD """, [ { "message": "Directive '@deprecated' argument 'reason' of type" " 'String!' is required, but it was not provided.", "locations": [(3, 31)], }, ], ) def missing_arg_on_directive_defined_in_schema_extension(): schema = build_schema( """ type Query { foo: String } """ ) assert_sdl_errors( """ directive @test(arg: String!) on OBJECT extend type Query @test """, [ { "message": "Directive '@test' argument 'arg' of type" " 'String!' is required, but it was not provided.", "locations": [(4, 36)], }, ], schema, ) def missing_arg_on_directive_used_in_schema_extension(): schema = build_schema( """ directive @test(arg: String!) on OBJECT type Query { foo: String } """ ) assert_sdl_errors( """ extend type Query @test """, [ { "message": "Directive '@test' argument 'arg' of type" " 'String!' is required, but it was not provided.", "locations": [(2, 36)], }, ], schema, ) graphql-core-3.2.6/tests/validation/test_scalar_leafs.py000066400000000000000000000101001474546154300234370ustar00rootroot00000000000000from functools import partial from graphql.validation import ScalarLeafsRule from .harness import assert_validation_errors assert_errors = partial(assert_validation_errors, ScalarLeafsRule) assert_valid = partial(assert_errors, errors=[]) def describe_validate_scalar_leafs(): def valid_scalar_selection(): assert_valid( """ fragment scalarSelection on Dog { barks } """ ) def object_type_missing_selection(): assert_errors( """ query directQueryOnObjectWithoutSubFields { human } """, [ { "message": "Field 'human' of type 'Human'" " must have a selection of subfields." " Did you mean 'human { ... }'?", "locations": [(3, 15)], }, ], ) def interface_type_missing_selection(): assert_errors( """ { human { pets } } """, [ { "message": "Field 'pets' of type '[Pet]'" " must have a selection of subfields." " Did you mean 'pets { ... }'?", "locations": [(3, 23)], }, ], ) def valid_scalar_selection_with_args(): assert_valid( """ fragment scalarSelectionWithArgs on Dog { doesKnowCommand(dogCommand: SIT) } """ ) def scalar_selection_not_allowed_on_boolean(): assert_errors( """ fragment scalarSelectionsNotAllowedOnBoolean on Dog { barks { sinceWhen } } """, [ { "message": "Field 'barks' must not have a selection" " since type 'Boolean' has no subfields.", "locations": [(3, 21)], }, ], ) def scalar_selection_not_allowed_on_enum(): assert_errors( """ fragment scalarSelectionsNotAllowedOnEnum on Cat { furColor { inHexDec } } """, [ { "message": "Field 'furColor' must not have a selection" " since type 'FurColor' has no subfields.", "locations": [(3, 24)], }, ], ) def scalar_selection_not_allowed_with_args(): assert_errors( """ fragment scalarSelectionsNotAllowedWithArgs on Dog { doesKnowCommand(dogCommand: SIT) { sinceWhen } } """, [ { "message": "Field 'doesKnowCommand' must not have a selection" " since type 'Boolean' has no subfields.", "locations": [(3, 48)], }, ], ) def scalar_selection_not_allowed_with_directives(): assert_errors( """ fragment scalarSelectionsNotAllowedWithDirectives on Dog { name @include(if: true) { isAlsoHumanName } } """, [ { "message": "Field 'name' must not have a selection" " since type 'String' has no subfields.", "locations": [(3, 39)], }, ], ) def scalar_selection_not_allowed_with_directives_and_args(): assert_errors( """ fragment scalarSelectionsNotAllowedWithDirectivesAndArgs on Dog { doesKnowCommand(dogCommand: SIT) @include(if: true) { sinceWhen } } """, [ { "message": "Field 'doesKnowCommand' must not have a selection" " since type 'Boolean' has no subfields.", "locations": [(3, 67)], }, ], ) graphql-core-3.2.6/tests/validation/test_single_field_subscriptions.py000066400000000000000000000200431474546154300264420ustar00rootroot00000000000000from functools import partial from graphql.utilities import build_schema from graphql.validation import SingleFieldSubscriptionsRule from .harness import assert_validation_errors schema = build_schema( """ type Message { body: String sender: String } type SubscriptionRoot { importantEmails: [String] notImportantEmails: [String] moreImportantEmails: [String] spamEmails: [String] deletedEmails: [String] newMessage: Message } type QueryRoot { dummy: String } schema { query: QueryRoot subscription: SubscriptionRoot } """ ) assert_errors = partial( assert_validation_errors, SingleFieldSubscriptionsRule, schema=schema ) assert_valid = partial(assert_errors, errors=[]) def describe_validate_subscriptions_with_single_field(): def valid_subscription(): assert_valid( """ subscription ImportantEmails { importantEmails } """ ) def valid_subscription_with_fragment(): assert_valid( """ subscription sub { ...newMessageFields } fragment newMessageFields on SubscriptionRoot { newMessage { body sender } } """ ) def valid_subscription_with_fragment_and_field(): assert_valid( """ subscription sub { newMessage { body } ...newMessageFields } fragment newMessageFields on SubscriptionRoot { newMessage { body sender } } """ ) def fails_with_more_than_one_root_field(): assert_errors( """ subscription ImportantEmails { importantEmails notImportantEmails } """, [ { "message": "Subscription 'ImportantEmails'" " must select only one top level field.", "locations": [(4, 15)], } ], ) def fails_with_more_than_one_root_field_including_introspection(): assert_errors( """ subscription ImportantEmails { importantEmails __typename } """, [ { "message": "Subscription 'ImportantEmails'" " must select only one top level field.", "locations": [(4, 15)], }, { "message": "Subscription 'ImportantEmails'" " must not select an introspection top level field.", "locations": [(4, 15)], }, ], ) def fails_with_more_than_one_root_field_including_aliased_introspection(): assert_errors( """ subscription ImportantEmails { importantEmails ...Introspection } fragment Introspection on SubscriptionRoot { typename: __typename } """, [ { "message": "Subscription 'ImportantEmails'" " must select only one top level field.", "locations": [(7, 15)], }, { "message": "Subscription 'ImportantEmails'" " must not select an introspection top level field.", "locations": [(7, 15)], }, ], ) def fails_with_many_more_than_one_root_field(): assert_errors( """ subscription ImportantEmails { importantEmails notImportantEmails spamEmails } """, [ { "message": "Subscription 'ImportantEmails'" " must select only one top level field.", "locations": [(4, 15), (5, 15)], } ], ) def fails_with_more_than_one_root_field_via_fragments(): assert_errors( """ subscription ImportantEmails { importantEmails ... { more: moreImportantEmails } ...NotImportantEmails } fragment NotImportantEmails on SubscriptionRoot { notImportantEmails deleted: deletedEmails ...SpamEmails } fragment SpamEmails on SubscriptionRoot { spamEmails } """, [ { "message": "Subscription 'ImportantEmails'" " must select only one top level field.", "locations": [(5, 17), (10, 15), (11, 15), (15, 15)], }, ], ) def does_not_infinite_loop_on_recursive_fragments(): assert_errors( """ subscription NoInfiniteLoop { ...A } fragment A on SubscriptionRoot { ...A } """, [], ) def fails_with_more_than_one_root_field_via_fragments_anonymous(): assert_errors( """ subscription { importantEmails ... { more: moreImportantEmails ...NotImportantEmails } ...NotImportantEmails } fragment NotImportantEmails on SubscriptionRoot { notImportantEmails deleted: deletedEmails ... { ... { archivedEmails } } ...SpamEmails } fragment SpamEmails on SubscriptionRoot { spamEmails ...NonExistentFragment } """, [ { "message": "Anonymous Subscription" " must select only one top level field.", "locations": [(5, 17), (11, 15), (12, 15), (15, 19), (21, 15)], }, ], ) def fails_with_more_than_one_root_field_in_anonymous_subscriptions(): assert_errors( """ subscription { importantEmails notImportantEmails } """, [ { "message": "Anonymous Subscription" " must select only one top level field.", "locations": [(4, 15)], } ], ) def fails_with_introspection_field(): assert_errors( """ subscription ImportantEmails { __typename } """, [ { "message": "Subscription 'ImportantEmails' must not" " select an introspection top level field.", "locations": [(3, 15)], } ], ) def fails_with_introspection_field_in_anonymous_subscription(): assert_errors( """ subscription { __typename } """, [ { "message": "Anonymous Subscription must not" " select an introspection top level field.", "locations": [(3, 15)], } ], ) def skips_if_not_subscription_type(): empty_schema = build_schema( """ type Query { dummy: String } """ ) assert_errors( """ subscription { __typename } """, [], schema=empty_schema, ) graphql-core-3.2.6/tests/validation/test_unique_argument_definition_names.py000066400000000000000000000101411474546154300276300ustar00rootroot00000000000000from functools import partial from graphql.validation.rules.unique_argument_definition_names import ( UniqueArgumentDefinitionNamesRule, ) from .harness import assert_sdl_validation_errors assert_sdl_errors = partial( assert_sdl_validation_errors, UniqueArgumentDefinitionNamesRule ) assert_sdl_valid = partial(assert_sdl_errors, errors=[]) def describe_validate_unique_argument_definition_names(): def no_args(): assert_sdl_valid( """ type SomeObject { someField: String } interface SomeInterface { someField: String } directive @someDirective on QUERY """ ) def one_argument(): assert_sdl_valid( """ type SomeObject { someField(foo: String): String } interface SomeInterface { someField(foo: String): String } extend type SomeObject { anotherField(foo: String): String } extend interface SomeInterface { anotherField(foo: String): String } directive @someDirective(foo: String) on QUERY """ ) def multiple_arguments(): assert_sdl_valid( """ type SomeObject { someField( foo: String bar: String ): String } interface SomeInterface { someField( foo: String bar: String ): String } extend type SomeObject { anotherField( foo: String bar: String ): String } extend interface SomeInterface { anotherField( foo: String bar: String ): String } directive @someDirective( foo: String bar: String ) on QUERY """ ) def duplicating_arguments(): assert_sdl_errors( """ type SomeObject { someField( foo: String bar: String foo: String ): String } interface SomeInterface { someField( foo: String bar: String foo: String ): String } extend type SomeObject { anotherField( foo: String bar: String bar: String ): String } extend interface SomeInterface { anotherField( bar: String foo: String foo: String ): String } directive @someDirective( foo: String bar: String foo: String ) on QUERY """, [ { "message": "Argument 'SomeObject.someField(foo:)'" " can only be defined once.", "locations": [(4, 17), (6, 17)], }, { "message": "Argument 'SomeInterface.someField(foo:)'" " can only be defined once.", "locations": [(12, 17), (14, 17)], }, { "message": "Argument 'SomeObject.anotherField(bar:)'" " can only be defined once.", "locations": [(21, 17), (22, 17)], }, { "message": "Argument 'SomeInterface.anotherField(foo:)'" " can only be defined once.", "locations": [(29, 17), (30, 17)], }, { "message": "Argument '@someDirective(foo:)'" " can only be defined once.", "locations": [(35, 15), (37, 15)], }, ], ) graphql-core-3.2.6/tests/validation/test_unique_argument_names.py000066400000000000000000000067461474546154300254400ustar00rootroot00000000000000from functools import partial from graphql.validation import UniqueArgumentNamesRule from .harness import assert_validation_errors assert_errors = partial(assert_validation_errors, UniqueArgumentNamesRule) assert_valid = partial(assert_errors, errors=[]) def describe_validate_unique_argument_names(): def no_arguments_on_field(): assert_valid( """ { field } """ ) def no_arguments_on_directive(): assert_valid( """ { field } """ ) def argument_on_field(): assert_valid( """ { field(arg: "value") } """ ) def argument_on_directive(): assert_valid( """ { field @directive(arg: "value") } """ ) def same_argument_on_two_fields(): assert_valid( """ { one: field(arg: "value") two: field(arg: "value") } """ ) def same_argument_on_field_and_directive(): assert_valid( """ { field(arg: "value") @directive(arg: "value") } """ ) def same_argument_on_two_directives(): assert_valid( """ { field @directive1(arg: "value") @directive2(arg: "value") } """ ) def multiple_field_arguments(): assert_valid( """ { field(arg1: "value", arg2: "value", arg3: "value") } """ ) def multiple_directive_arguments(): assert_valid( """ { field @directive(arg1: "value", arg2: "value", arg3: "value") } """ ) def duplicate_field_arguments(): assert_errors( """ { field(arg1: "value", arg1: "value") } """, [ { "message": "There can be only one argument named 'arg1'.", "locations": [(3, 21), (3, 36)], }, ], ) def many_duplicate_field_arguments(): assert_errors( """ { field(arg1: "value", arg1: "value", arg1: "value") } """, [ { "message": "There can be only one argument named 'arg1'.", "locations": [(3, 21), (3, 36), (3, 51)], }, ], ) def duplicate_directive_arguments(): assert_errors( """ { field @directive(arg1: "value", arg1: "value") } """, [ { "message": "There can be only one argument named 'arg1'.", "locations": [(3, 32), (3, 47)], }, ], ) def many_duplicate_directive_arguments(): assert_errors( """ { field @directive(arg1: "value", arg1: "value", arg1: "value") } """, [ { "message": "There can be only one argument named 'arg1'.", "locations": [(3, 32), (3, 47), (3, 62)], }, ], ) graphql-core-3.2.6/tests/validation/test_unique_directive_names.py000066400000000000000000000052541474546154300255650ustar00rootroot00000000000000from functools import partial from graphql.utilities import build_schema from graphql.validation.rules.unique_directive_names import UniqueDirectiveNamesRule from .harness import assert_sdl_validation_errors assert_errors = partial(assert_sdl_validation_errors, UniqueDirectiveNamesRule) assert_valid = partial(assert_errors, errors=[]) def describe_validate_unique_directive_names(): def no_directive(): assert_valid( """ type Foo """ ) def one_directive(): assert_valid( """ directive @foo on SCHEMA """ ) def many_directives(): assert_valid( """ directive @foo on SCHEMA directive @bar on SCHEMA directive @baz on SCHEMA """ ) def directive_and_non_directive_definitions_named_the_same(): assert_valid( """ query foo { __typename } fragment foo on foo { __typename } type foo directive @foo on SCHEMA """ ) def directives_named_the_same(): assert_errors( """ directive @foo on SCHEMA directive @foo on SCHEMA """, [ { "message": "There can be only one directive named '@foo'.", "locations": [(2, 24), (4, 24)], } ], ) def adding_new_directive_to_existing_schema(): schema = build_schema("directive @foo on SCHEMA") assert_valid("directive @bar on SCHEMA", schema=schema) def adding_new_directive_with_standard_name_to_existing_schema(): schema = build_schema("type foo") assert_errors( "directive @skip on SCHEMA", [ { "message": "Directive '@skip' already exists in the schema." " It cannot be redefined.", "locations": [(1, 12)], } ], schema, ) def adding_new_directive_to_existing_schema_with_same_named_type(): schema = build_schema("type foo") assert_valid("directive @foo on SCHEMA", schema=schema) def adding_conflicting_directives_to_existing_schema(): schema = build_schema("directive @foo on SCHEMA") assert_errors( "directive @foo on SCHEMA", [ { "message": "Directive '@foo' already exists in the schema." " It cannot be redefined.", "locations": [(1, 12)], } ], schema, ) graphql-core-3.2.6/tests/validation/test_unique_directives_per_location.py000066400000000000000000000252341474546154300273230ustar00rootroot00000000000000from functools import partial from graphql.language import parse from graphql.utilities import extend_schema from graphql.validation import UniqueDirectivesPerLocationRule from .harness import assert_validation_errors, assert_sdl_validation_errors, test_schema extension_sdl = """ directive @directive on FIELD | FRAGMENT_DEFINITION directive @directiveA on FIELD | FRAGMENT_DEFINITION directive @directiveB on FIELD | FRAGMENT_DEFINITION directive @repeatable repeatable on FIELD | FRAGMENT_DEFINITION """ schema_with_directives = extend_schema(test_schema, parse(extension_sdl)) assert_errors = partial( assert_validation_errors, UniqueDirectivesPerLocationRule, schema=schema_with_directives, ) assert_valid = partial(assert_errors, errors=[]) assert_sdl_errors = partial( assert_sdl_validation_errors, UniqueDirectivesPerLocationRule ) def describe_validate_directives_are_unique_per_location(): def no_directives(): assert_valid( """ { field } """ ) def unique_directives_in_different_locations(): assert_valid( """ fragment Test on Type @directiveA { field @directiveB } """ ) def unique_directives_in_same_locations(): assert_valid( """ fragment Test on Type @directiveA @directiveB { field @directiveA @directiveB } """ ) def same_directives_in_different_locations(): assert_valid( """ fragment Test on Type @directiveA { field @directiveA } """ ) def same_directives_in_similar_locations(): assert_valid( """ fragment Test on Type { field @directive field @directive } """ ) def repeatable_directives_in_same_location(): assert_valid( """ fragment Test on Type @repeatable @repeatable { field @repeatable @repeatable } """ ) def unknown_directives_must_be_ignored(): assert_valid( """ type Test @unknown @unknown { field: String! @unknown @unknown } extend type Test @unknown { anotherField: String! } """ ) def duplicate_directives_in_one_location(): assert_errors( """ fragment Test on Type { field @directive @directive } """, [ { "message": "The directive '@directive'" " can only be used once at this location.", "locations": [(3, 21), (3, 32)], }, ], ) def many_duplicate_directives_in_one_location(): assert_errors( """ fragment Test on Type { field @directive @directive @directive } """, [ { "message": "The directive '@directive'" " can only be used once at this location.", "locations": [(3, 21), (3, 32)], }, { "message": "The directive '@directive'" " can only be used once at this location.", "locations": [(3, 21), (3, 43)], }, ], ) def different_duplicate_directives_in_one_location(): assert_errors( """ fragment Test on Type { field @directiveA @directiveB @directiveA @directiveB } """, [ { "message": "The directive '@directiveA'" " can only be used once at this location.", "locations": [(3, 21), (3, 45)], }, { "message": "The directive '@directiveB'" " can only be used once at this location.", "locations": [(3, 33), (3, 57)], }, ], ) def different_duplicate_directives_in_many_locations(): assert_errors( """ fragment Test on Type @directive @directive { field @directive @directive } """, [ { "message": "The directive '@directive'" " can only be used once at this location.", "locations": [(2, 35), (2, 46)], }, { "message": "The directive '@directive'" " can only be used once at this location.", "locations": [(3, 21), (3, 32)], }, ], ) def duplicate_directives_on_sdl_definitions(): assert_sdl_errors( """ directive @nonRepeatable on SCHEMA | SCALAR | OBJECT | INTERFACE | UNION | INPUT_OBJECT schema @nonRepeatable @nonRepeatable { query: Dummy } scalar TestScalar @nonRepeatable @nonRepeatable type TestObject @nonRepeatable @nonRepeatable interface TestInterface @nonRepeatable @nonRepeatable union TestUnion @nonRepeatable @nonRepeatable input TestInput @nonRepeatable @nonRepeatable """, [ { "message": "The directive '@nonRepeatable'" " can only be used once at this location.", "locations": [(5, 20), (5, 35)], }, { "message": "The directive '@nonRepeatable'" " can only be used once at this location.", "locations": [(7, 31), (7, 46)], }, { "message": "The directive '@nonRepeatable'" " can only be used once at this location.", "locations": [(8, 29), (8, 44)], }, { "message": "The directive '@nonRepeatable'" " can only be used once at this location.", "locations": [(9, 37), (9, 52)], }, { "message": "The directive '@nonRepeatable'" " can only be used once at this location.", "locations": [(10, 29), (10, 44)], }, { "message": "The directive '@nonRepeatable'" " can only be used once at this location.", "locations": [(11, 29), (11, 44)], }, ], ) def duplicate_directives_on_sdl_extensions(): assert_sdl_errors( """ directive @nonRepeatable on SCHEMA | SCALAR | OBJECT | INTERFACE | UNION | INPUT_OBJECT extend schema @nonRepeatable @nonRepeatable extend scalar TestScalar @nonRepeatable @nonRepeatable extend type TestObject @nonRepeatable @nonRepeatable extend interface TestInterface @nonRepeatable @nonRepeatable extend union TestUnion @nonRepeatable @nonRepeatable extend input TestInput @nonRepeatable @nonRepeatable """, [ { "message": "The directive '@nonRepeatable'" " can only be used once at this location.", "locations": [(5, 27), (5, 42)], }, { "message": "The directive '@nonRepeatable'" " can only be used once at this location.", "locations": [(7, 38), (7, 53)], }, { "message": "The directive '@nonRepeatable'" " can only be used once at this location.", "locations": [(8, 36), (8, 51)], }, { "message": "The directive '@nonRepeatable'" " can only be used once at this location.", "locations": [(9, 44), (9, 59)], }, { "message": "The directive '@nonRepeatable'" " can only be used once at this location.", "locations": [(10, 36), (10, 51)], }, { "message": "The directive '@nonRepeatable'" " can only be used once at this location.", "locations": [(11, 36), (11, 51)], }, ], ) def duplicate_directives_between_sdl_definitions_and_extensions(): assert_sdl_errors( """ directive @nonRepeatable on SCHEMA schema @nonRepeatable { query: Dummy } extend schema @nonRepeatable """, [ { "message": "The directive '@nonRepeatable'" " can only be used once at this location.", "locations": [(4, 20), (5, 27)], }, ], ) assert_sdl_errors( """ directive @nonRepeatable on SCALAR scalar TestScalar @nonRepeatable extend scalar TestScalar @nonRepeatable scalar TestScalar @nonRepeatable """, [ { "message": "The directive '@nonRepeatable'" " can only be used once at this location.", "locations": [(4, 31), (5, 38)], }, { "message": "The directive '@nonRepeatable'" " can only be used once at this location.", "locations": [(4, 31), (6, 31)], }, ], ) assert_sdl_errors( """ directive @nonRepeatable on OBJECT extend type TestObject @nonRepeatable type TestObject @nonRepeatable extend type TestObject @nonRepeatable """, [ { "message": "The directive '@nonRepeatable'" " can only be used once at this location.", "locations": [(4, 36), (5, 29)], }, { "message": "The directive '@nonRepeatable'" " can only be used once at this location.", "locations": [(4, 36), (6, 36)], }, ], ) graphql-core-3.2.6/tests/validation/test_unique_enum_value_names.py000066400000000000000000000110771474546154300257470ustar00rootroot00000000000000from functools import partial from graphql.utilities import build_schema from graphql.validation.rules.unique_enum_value_names import UniqueEnumValueNamesRule from .harness import assert_sdl_validation_errors assert_errors = partial(assert_sdl_validation_errors, UniqueEnumValueNamesRule) assert_valid = partial(assert_errors, errors=[]) def describe_validate_unique_field_definition_names(): def no_values(): assert_valid( """ enum SomeEnum """ ) def one_value(): assert_valid( """ enum SomeEnum { FOO } """ ) def multiple_values(): assert_valid( """ enum SomeEnum { FOO BAR } """ ) def duplicate_values_inside_the_same_enum_definition(): assert_errors( """ enum SomeEnum { FOO BAR FOO } """, [ { "message": "Enum value 'SomeEnum.FOO' can only be defined once.", "locations": [(3, 15), (5, 15)], }, ], ) def extend_enum_with_new_value(): assert_valid( """ enum SomeEnum { FOO } extend enum SomeEnum { BAR } extend enum SomeEnum { BAZ } """ ) def extend_enum_with_duplicate_value(): assert_errors( """ extend enum SomeEnum { FOO } enum SomeEnum { FOO } """, [ { "message": "Enum value 'SomeEnum.FOO' can only be defined once.", "locations": [(3, 15), (6, 15)], }, ], ) def duplicate_value_inside_extension(): assert_errors( """ enum SomeEnum extend enum SomeEnum { FOO BAR FOO } """, [ { "message": "Enum value 'SomeEnum.FOO' can only be defined once.", "locations": [(4, 15), (6, 15)], }, ], ) def duplicate_value_inside_different_extension(): assert_errors( """ enum SomeEnum extend enum SomeEnum { FOO } extend enum SomeEnum { FOO } """, [ { "message": "Enum value 'SomeEnum.FOO' can only be defined once.", "locations": [(4, 15), (7, 15)], }, ], ) def adding_new_value_to_the_enum_inside_existing_schema(): schema = build_schema("enum SomeEnum") sdl = """ extend enum SomeEnum { FOO } """ assert_valid(sdl, schema=schema) def adding_conflicting_value_to_existing_schema_twice(): schema = build_schema( """ enum SomeEnum { FOO } """ ) sdl = """ extend enum SomeEnum { FOO } extend enum SomeEnum { FOO } """ assert_errors( sdl, [ { "message": "Enum value 'SomeEnum.FOO' already exists in the schema." " It cannot also be defined in this type extension.", "locations": [(3, 15)], }, { "message": "Enum value 'SomeEnum.FOO' already exists in the schema." " It cannot also be defined in this type extension.", "locations": [(6, 15)], }, ], schema, ) def adding_enum_values_to_existing_schema_twice(): schema = build_schema("enum SomeEnum") sdl = """ extend enum SomeEnum { FOO } extend enum SomeEnum { FOO } """ assert_errors( sdl, [ { "message": "Enum value 'SomeEnum.FOO' can only be defined once.", "locations": [(3, 15), (6, 15)], }, ], schema, ) graphql-core-3.2.6/tests/validation/test_unique_field_definition_names.py000066400000000000000000000257571474546154300271140ustar00rootroot00000000000000from functools import partial from graphql.utilities import build_schema from graphql.validation.rules.unique_field_definition_names import ( UniqueFieldDefinitionNamesRule, ) from .harness import assert_sdl_validation_errors assert_errors = partial(assert_sdl_validation_errors, UniqueFieldDefinitionNamesRule) assert_valid = partial(assert_errors, errors=[]) def describe_validate_unique_field_definition_names(): def no_fields(): assert_valid( """ type SomeObject interface SomeInterface input SomeInputObject """ ) def one_field(): assert_valid( """ type SomeObject { foo: String } interface SomeInterface { foo: String } input SomeInputObject { foo: String } """ ) def multiple_fields(): assert_valid( """ type SomeObject { foo: String bar: String } interface SomeInterface { foo: String bar: String } input SomeInputObject { foo: String bar: String } """ ) def duplicate_fields_inside_the_same_type_definition(): assert_errors( """ type SomeObject { foo: String bar: String foo: String } interface SomeInterface { foo: String bar: String foo: String } input SomeInputObject { foo: String bar: String foo: String } """, [ { "message": "Field 'SomeObject.foo' can only be defined once.", "locations": [(3, 15), (5, 15)], }, { "message": "Field 'SomeInterface.foo' can only be defined once.", "locations": [(9, 15), (11, 15)], }, { "message": "Field 'SomeInputObject.foo' can only be defined once.", "locations": [(15, 15), (17, 15)], }, ], ) def extend_type_with_new_field(): assert_valid( """ type SomeObject { foo: String } extend type SomeObject { bar: String } extend type SomeObject { baz: String } interface SomeInterface { foo: String } extend interface SomeInterface { bar: String } extend interface SomeInterface { baz: String } input SomeInputObject { foo: String } extend input SomeInputObject { bar: String } extend input SomeInputObject { baz: String } """ ) def extend_type_with_duplicate_field(): assert_errors( """ extend type SomeObject { foo: String } type SomeObject { foo: String } extend interface SomeInterface { foo: String } interface SomeInterface { foo: String } extend input SomeInputObject { foo: String } input SomeInputObject { foo: String } """, [ { "message": "Field 'SomeObject.foo' can only be defined once.", "locations": [(3, 15), (6, 15)], }, { "message": "Field 'SomeInterface.foo' can only be defined once.", "locations": [(10, 15), (13, 15)], }, { "message": "Field 'SomeInputObject.foo' can only be defined once.", "locations": [(17, 15), (20, 15)], }, ], ) def duplicate_field_inside_extension(): assert_errors( """ type SomeObject extend type SomeObject { foo: String bar: String foo: String } interface SomeInterface extend interface SomeInterface { foo: String bar: String foo: String } input SomeInputObject extend input SomeInputObject { foo: String bar: String foo: String } """, [ { "message": "Field 'SomeObject.foo' can only be defined once.", "locations": [(4, 15), (6, 15)], }, { "message": "Field 'SomeInterface.foo' can only be defined once.", "locations": [(11, 15), (13, 15)], }, { "message": "Field 'SomeInputObject.foo' can only be defined once.", "locations": [(18, 15), (20, 15)], }, ], ) def duplicate_field_inside_different_extension(): assert_errors( """ type SomeObject extend type SomeObject { foo: String } extend type SomeObject { foo: String } interface SomeInterface extend interface SomeInterface { foo: String } extend interface SomeInterface { foo: String } input SomeInputObject extend input SomeInputObject { foo: String } extend input SomeInputObject { foo: String } """, [ { "message": "Field 'SomeObject.foo' can only be defined once.", "locations": [(4, 15), (7, 15)], }, { "message": "Field 'SomeInterface.foo' can only be defined once.", "locations": [(12, 15), (15, 15)], }, { "message": "Field 'SomeInputObject.foo' can only be defined once.", "locations": [(20, 15), (23, 15)], }, ], ) def adding_new_field_to_the_type_inside_existing_schema(): schema = build_schema( """ type SomeObject interface SomeInterface input SomeInputObject """ ) sdl = """ extend type SomeObject { foo: String } extend interface SomeInterface { foo: String } extend input SomeInputObject { foo: String } """ assert_valid(sdl, schema=schema) def adding_conflicting_fields_to_existing_schema_twice(): schema = build_schema( """ type SomeObject { foo: String } interface SomeInterface { foo: String } input SomeInputObject { foo: String } """ ) sdl = """ extend type SomeObject { foo: String } extend interface SomeInterface { foo: String } extend input SomeInputObject { foo: String } extend type SomeObject { foo: String } extend interface SomeInterface { foo: String } extend input SomeInputObject { foo: String } """ assert_errors( sdl, [ { "message": "Field 'SomeObject.foo' already exists in the schema." " It cannot also be defined in this type extension.", "locations": [(3, 15)], }, { "message": "Field 'SomeInterface.foo' already exists in the schema." " It cannot also be defined in this type extension.", "locations": [(6, 15)], }, { "message": "Field 'SomeInputObject.foo'" " already exists in the schema." " It cannot also be defined in this type extension.", "locations": [(9, 15)], }, { "message": "Field 'SomeObject.foo' already exists in the schema." " It cannot also be defined in this type extension.", "locations": [(13, 15)], }, { "message": "Field 'SomeInterface.foo'" " already exists in the schema." " It cannot also be defined in this type extension.", "locations": [(16, 15)], }, { "message": "Field 'SomeInputObject.foo'" " already exists in the schema." " It cannot also be defined in this type extension.", "locations": [(19, 15)], }, ], schema, ) def adding_fields_to_existing_schema_twice(): schema = build_schema( """ type SomeObject interface SomeInterface input SomeInputObject """ ) sdl = """ extend type SomeObject { foo: String } extend type SomeObject { foo: String } extend interface SomeInterface { foo: String } extend interface SomeInterface { foo: String } extend input SomeInputObject { foo: String } extend input SomeInputObject { foo: String } """ assert_errors( sdl, [ { "message": "Field 'SomeObject.foo' can only be defined once.", "locations": [(3, 15), (6, 15)], }, { "message": "Field 'SomeInterface.foo' can only be defined once.", "locations": [(10, 15), (13, 15)], }, { "message": "Field 'SomeInputObject.foo' can only be defined once.", "locations": [(17, 15), (20, 15)], }, ], schema, ) graphql-core-3.2.6/tests/validation/test_unique_fragment_names.py000066400000000000000000000047541474546154300254160ustar00rootroot00000000000000from functools import partial from graphql.validation import UniqueFragmentNamesRule from .harness import assert_validation_errors assert_errors = partial(assert_validation_errors, UniqueFragmentNamesRule) assert_valid = partial(assert_errors, errors=[]) def describe_validate_unique_fragment_names(): def no_fragments(): assert_valid( """ { field } """ ) def one_fragment(): assert_valid( """ { ...fragA } fragment fragA on Type { field } """ ) def many_fragments(): assert_valid( """ { ...fragA ...fragB ...fragC } fragment fragA on Type { fieldA } fragment fragB on Type { fieldB } fragment fragC on Type { fieldC } """ ) def inline_fragments_are_always_unique(): assert_valid( """ { ...on Type { fieldA } ...on Type { fieldB } } """ ) def fragment_and_operation_named_the_same(): assert_valid( """ query Foo { ...Foo } fragment Foo on Type { field } """ ) def fragments_named_the_same(): assert_errors( """ { ...fragA } fragment fragA on Type { fieldA } fragment fragA on Type { fieldB } """, [ { "message": "There can be only one fragment named 'fragA'.", "locations": [(5, 22), (8, 22)], }, ], ) def fragments_named_the_same_without_being_referenced(): assert_errors( """ fragment fragA on Type { fieldA } fragment fragA on Type { fieldB } """, [ { "message": "There can be only one fragment named 'fragA'.", "locations": [(2, 22), (5, 22)], }, ], ) graphql-core-3.2.6/tests/validation/test_unique_input_field_names.py000066400000000000000000000050611474546154300261050ustar00rootroot00000000000000from functools import partial from graphql.validation import UniqueInputFieldNamesRule from .harness import assert_validation_errors assert_errors = partial(assert_validation_errors, UniqueInputFieldNamesRule) assert_valid = partial(assert_errors, errors=[]) def describe_validate_unique_input_field_names(): def input_object_with_fields(): assert_valid( """ { field(arg: { f: true }) } """ ) def same_input_object_within_two_args(): assert_valid( """ { field(arg1: { f: true }, arg2: { f: true }) } """ ) def multiple_input_object_fields(): assert_valid( """ { field(arg: { f1: "value", f2: "value", f3: "value" }) } """ ) def allows_for_nested_input_objects_with_similar_fields(): assert_valid( """ { field(arg: { deep: { deep: { id: 1 } id: 1 } id: 1 }) } """ ) def duplicate_input_object_fields(): assert_errors( """ { field(arg: { f1: "value", f1: "value" }) } """, [ { "message": "There can be only one input field named 'f1'.", "locations": [(3, 28), (3, 41)], }, ], ) def many_duplicate_input_object_fields(): assert_errors( """ { field(arg: { f1: "value", f1: "value", f1: "value" }) } """, [ { "message": "There can be only one input field named 'f1'.", "locations": [(3, 28), (3, 41)], }, { "message": "There can be only one input field named 'f1'.", "locations": [(3, 28), (3, 54)], }, ], ) def nested_duplicate_input_object_fields(): assert_errors( """ { field(arg: { f1: {f2: "value", f2: "value" }}) } """, [ { "message": "There can be only one input field named 'f2'.", "locations": [(3, 33), (3, 46)], }, ], ) graphql-core-3.2.6/tests/validation/test_unique_operation_names.py000066400000000000000000000054551474546154300256120ustar00rootroot00000000000000from functools import partial from graphql.validation import UniqueOperationNamesRule from .harness import assert_validation_errors assert_errors = partial(assert_validation_errors, UniqueOperationNamesRule) assert_valid = partial(assert_errors, errors=[]) def describe_validate_unique_operation_names(): def no_operations(): assert_valid( """ fragment fragA on Type { field } """ ) def one_anon_operation(): assert_valid( """ { field } """ ) def one_named_operation(): assert_valid( """ query Foo { field } """ ) def multiple_operations(): assert_valid( """ query Foo { field } query Bar { field } """ ) def multiple_operations_of_different_types(): assert_valid( """ query Foo { field } mutation Bar { field } subscription Baz { field } """ ) def fragment_and_operation_named_the_same(): assert_valid( """ query Foo { ...Foo } fragment Foo on Type { field } """ ) def multiple_operations_of_same_name(): assert_errors( """ query Foo { fieldA } query Foo { fieldB } """, [ { "message": "There can be only one operation named 'Foo'.", "locations": [(2, 19), (5, 19)], }, ], ) def multiple_ops_of_same_name_of_different_types_mutation(): assert_errors( """ query Foo { fieldA } mutation Foo { fieldB } """, [ { "message": "There can be only one operation named 'Foo'.", "locations": [(2, 19), (5, 22)], }, ], ) def multiple_ops_of_same_name_of_different_types_subscription(): assert_errors( """ query Foo { fieldA } subscription Foo { fieldB } """, [ { "message": "There can be only one operation named 'Foo'.", "locations": [(2, 19), (5, 26)], }, ], ) graphql-core-3.2.6/tests/validation/test_unique_operation_types.py000066400000000000000000000232271474546154300256500ustar00rootroot00000000000000from functools import partial from graphql.utilities import build_schema from graphql.validation.rules.unique_operation_types import UniqueOperationTypesRule from .harness import assert_sdl_validation_errors assert_errors = partial(assert_sdl_validation_errors, UniqueOperationTypesRule) assert_valid = partial(assert_errors, errors=[]) def describe_validate_unique_operation_types(): def no_schema_definition(): assert_valid( """ type Foo """ ) def schema_definition_with_all_types(): assert_valid( """ type Foo schema { query: Foo mutation: Foo subscription: Foo } """ ) def schema_definition_with_single_extension(): assert_valid( """ type Foo schema { query: Foo } extend schema { mutation: Foo subscription: Foo } """ ) def schema_definition_with_separate_extensions(): assert_valid( """ type Foo schema { query: Foo } extend schema { mutation: Foo } extend schema { subscription: Foo } """ ) def extend_schema_before_definition(): assert_valid( """ type Foo extend schema { mutation: Foo } extend schema { subscription: Foo } schema { query: Foo } """ ) def duplicate_operation_types_inside_single_schema_definition(): assert_errors( """ type Foo schema { query: Foo mutation: Foo subscription: Foo query: Foo mutation: Foo subscription: Foo } """, [ { "message": "There can be only one query type in schema.", "locations": [(5, 15), (9, 15)], }, { "message": "There can be only one mutation type in schema.", "locations": [(6, 15), (10, 15)], }, { "message": "There can be only one subscription type in schema.", "locations": [(7, 15), (11, 15)], }, ], ) def duplicate_operation_types_inside_schema_extension(): assert_errors( """ type Foo schema { query: Foo mutation: Foo subscription: Foo } extend schema { query: Foo mutation: Foo subscription: Foo } """, [ { "message": "There can be only one query type in schema.", "locations": [(5, 15), (11, 15)], }, { "message": "There can be only one mutation type in schema.", "locations": [(6, 15), (12, 15)], }, { "message": "There can be only one subscription type in schema.", "locations": [(7, 15), (13, 15)], }, ], ) def duplicate_operation_types_inside_schema_extension_twice(): assert_errors( """ type Foo schema { query: Foo mutation: Foo subscription: Foo } extend schema { query: Foo mutation: Foo subscription: Foo } extend schema { query: Foo mutation: Foo subscription: Foo } """, [ { "message": "There can be only one query type in schema.", "locations": [(5, 15), (11, 15)], }, { "message": "There can be only one mutation type in schema.", "locations": [(6, 15), (12, 15)], }, { "message": "There can be only one subscription type in schema.", "locations": [(7, 15), (13, 15)], }, { "message": "There can be only one query type in schema.", "locations": [(5, 15), (17, 15)], }, { "message": "There can be only one mutation type in schema.", "locations": [(6, 15), (18, 15)], }, { "message": "There can be only one subscription type in schema.", "locations": [(7, 15), (19, 15)], }, ], ) def duplicate_operation_types_inside_second_schema_extension(): assert_errors( """ type Foo schema { query: Foo } extend schema { mutation: Foo subscription: Foo } extend schema { query: Foo mutation: Foo subscription: Foo } """, [ { "message": "There can be only one query type in schema.", "locations": [(5, 15), (14, 15)], }, { "message": "There can be only one mutation type in schema.", "locations": [(9, 15), (15, 15)], }, { "message": "There can be only one subscription type in schema.", "locations": [(10, 15), (16, 15)], }, ], ) def define_schema_inside_extension_sdl(): schema = build_schema("type Foo") sdl = """ schema { query: Foo mutation: Foo subscription: Foo } """ assert_valid(sdl, schema=schema) def define_and_extend_schema_inside_extension_sdl(): schema = build_schema("type Foo") sdl = """ schema { query: Foo } extend schema { mutation: Foo } extend schema { subscription: Foo } """ assert_valid(sdl, schema=schema) def adding_new_operation_types_to_existing_schema(): schema = build_schema("type Query") sdl = """ extend schema { mutation: Foo } extend schema { subscription: Foo } """ assert_valid(sdl, schema=schema) def adding_conflicting_operation_types_to_existing_schema(): schema = build_schema( """ type Query type Mutation type Subscription type Foo """ ) sdl = """ extend schema { query: Foo mutation: Foo subscription: Foo } """ assert_errors( sdl, [ { "message": "Type for query already defined in the schema." " It cannot be redefined.", "locations": [(3, 15)], }, { "message": "Type for mutation already defined in the schema." " It cannot be redefined.", "locations": [(4, 15)], }, { "message": "Type for subscription already defined in the schema." " It cannot be redefined.", "locations": [(5, 15)], }, ], schema, ) def adding_conflicting_operation_types_to_existing_schema_twice(): schema = build_schema( """ type Query type Mutation type Subscription """ ) sdl = """ extend schema { query: Foo mutation: Foo subscription: Foo } extend schema { query: Foo mutation: Foo subscription: Foo } """ assert_errors( sdl, [ { "message": "Type for query already defined in the schema." " It cannot be redefined.", "locations": [(3, 15)], }, { "message": "Type for mutation already defined in the schema." " It cannot be redefined.", "locations": [(4, 15)], }, { "message": "Type for subscription already defined in the schema." " It cannot be redefined.", "locations": [(5, 15)], }, { "message": "Type for query already defined in the schema." " It cannot be redefined.", "locations": [(9, 15)], }, { "message": "Type for mutation already defined in the schema." " It cannot be redefined.", "locations": [(10, 15)], }, { "message": "Type for subscription already defined in the schema." " It cannot be redefined.", "locations": [(11, 15)], }, ], schema, ) graphql-core-3.2.6/tests/validation/test_unique_type_names.py000066400000000000000000000103751474546154300245700ustar00rootroot00000000000000from functools import partial from graphql.utilities import build_schema from graphql.validation.rules.unique_type_names import UniqueTypeNamesRule from .harness import assert_sdl_validation_errors assert_errors = partial(assert_sdl_validation_errors, UniqueTypeNamesRule) assert_valid = partial(assert_errors, errors=[]) def describe_validate_unique_type_names(): def no_types(): assert_valid( """ directive @test on SCHEMA """ ) def one_type(): assert_valid( """ type Foo """ ) def many_types(): assert_valid( """ type Foo type Bar type Baz """ ) def type_and_non_type_definitions_named_the_same(): assert_valid( """ query Foo { __typename } fragment Foo on Query { __typename } directive @Foo on SCHEMA type Foo """ ) def types_named_the_same(): assert_errors( """ type Foo scalar Foo type Foo interface Foo union Foo enum Foo input Foo """, [ { "message": "There can be only one type named 'Foo'.", "locations": [(2, 18), (4, 20)], }, { "message": "There can be only one type named 'Foo'.", "locations": [(2, 18), (5, 18)], }, { "message": "There can be only one type named 'Foo'.", "locations": [(2, 18), (6, 23)], }, { "message": "There can be only one type named 'Foo'.", "locations": [(2, 18), (7, 19)], }, { "message": "There can be only one type named 'Foo'.", "locations": [(2, 18), (8, 18)], }, { "message": "There can be only one type named 'Foo'.", "locations": [(2, 18), (9, 19)], }, ], ) def adding_new_type_to_existing_schema(): schema = build_schema("type Foo") assert_valid("type Bar", schema=schema) def adding_new_type_to_existing_schema_with_same_named_directive(): schema = build_schema("directive @Foo on SCHEMA") assert_valid("type Foo", schema=schema) def adding_conflicting_types_to_existing_schema(): schema = build_schema("type Foo") sdl = """ scalar Foo type Foo interface Foo union Foo enum Foo input Foo """ assert_errors( sdl, [ { "message": "Type 'Foo' already exists in the schema." " It cannot also be defined in this type definition.", "locations": [(2, 20)], }, { "message": "Type 'Foo' already exists in the schema." " It cannot also be defined in this type definition.", "locations": [(3, 18)], }, { "message": "Type 'Foo' already exists in the schema." " It cannot also be defined in this type definition.", "locations": [(4, 23)], }, { "message": "Type 'Foo' already exists in the schema." " It cannot also be defined in this type definition.", "locations": [(5, 19)], }, { "message": "Type 'Foo' already exists in the schema." " It cannot also be defined in this type definition.", "locations": [(6, 18)], }, { "message": "Type 'Foo' already exists in the schema." " It cannot also be defined in this type definition.", "locations": [(7, 19)], }, ], schema, ) graphql-core-3.2.6/tests/validation/test_unique_variable_names.py000066400000000000000000000024651474546154300253750ustar00rootroot00000000000000from functools import partial from graphql.validation import UniqueVariableNamesRule from .harness import assert_validation_errors assert_errors = partial(assert_validation_errors, UniqueVariableNamesRule) assert_valid = partial(assert_errors, errors=[]) def describe_validate_unique_variable_names(): def unique_variable_names(): assert_valid( """ query A($x: Int, $y: String) { __typename } query B($x: String, $y: Int) { __typename } """ ) def duplicate_variable_names(): assert_errors( """ query A($x: Int, $x: Int, $x: String) { __typename } query B($x: String, $x: Int) { __typename } query C($x: Int, $x: Int) { __typename } """, [ { "message": "There can be only one variable named '$x'.", "locations": [(2, 22), (2, 31), (2, 40)], }, { "message": "There can be only one variable named '$x'.", "locations": [(3, 22), (3, 34)], }, { "message": "There can be only one variable named '$x'.", "locations": [(4, 22), (4, 31)], }, ], ) graphql-core-3.2.6/tests/validation/test_validation.py000066400000000000000000000142431474546154300231660ustar00rootroot00000000000000from pytest import raises from graphql.error import GraphQLError from graphql.language import parse from graphql.utilities import TypeInfo, build_schema from graphql.validation import ValidationRule, validate from .harness import test_schema def describe_validate_supports_full_validation(): def rejects_invalid_documents(): with raises(TypeError) as exc_info: # noinspection PyTypeChecker assert validate(test_schema, None) # type: ignore assert str(exc_info.value) == "Must provide document." def rejects_invalid_type_info(): with raises(TypeError) as exc_info: # noinspection PyTypeChecker assert validate( test_schema, parse("query { name }"), type_info={} # type: ignore ) assert str(exc_info.value) == "Not a TypeInfo object: {}." def rejects_invalid_rules(): with raises(TypeError) as exc_info: # noinspection PyTypeChecker assert validate( test_schema, parse("query { name }"), rules=[None] # type: ignore ) assert ( str(exc_info.value) == "Rules must be specified as a collection" " of ASTValidationRule subclasses." ) def rejects_invalid_max_errors(): with raises(TypeError) as exc_info: # noinspection PyTypeChecker assert validate( test_schema, parse("query { name }"), max_errors=2.5 # type: ignore ) assert ( str(exc_info.value) == "The maximum number of errors must be passed as an int." ) def validates_queries(): doc = parse( """ query { human { pets { ... on Cat { meowsVolume } ... on Dog { barkVolume } } } } """ ) errors = validate(test_schema, doc) assert errors == [] def detects_unknown_fields(): doc = parse( """ { unknown } """ ) errors = validate(test_schema, doc) assert errors == [ {"message": "Cannot query field 'unknown' on type 'QueryRoot'."} ] def deprecated_validates_using_a_custom_type_info(): # This TypeInfo will never return a valid field. type_info = TypeInfo(test_schema, None, lambda *args: None) doc = parse( """ query { human { pets { ... on Cat { meowsVolume } ... on Dog { barkVolume } } } } """ ) errors = validate(test_schema, doc, None, None, type_info) assert [error.message for error in errors] == [ "Cannot query field 'human' on type 'QueryRoot'. Did you mean 'human'?", "Cannot query field 'meowsVolume' on type 'Cat'." " Did you mean 'meowsVolume'?", "Cannot query field 'barkVolume' on type 'Dog'." " Did you mean 'barkVolume'?", ] def validates_using_a_custom_rule(): schema = build_schema( """ directive @custom(arg: String) on FIELD type Query { foo: String } """ ) doc = parse( """ query { name @custom } """ ) class CustomRule(ValidationRule): def enter_directive(self, node, *_args): directive_def = self.context.get_directive() error = GraphQLError("Reporting directive: " + str(directive_def), node) self.context.report_error(error) errors = validate(schema, doc, [CustomRule]) assert errors == [ {"message": "Reporting directive: @custom", "locations": [(3, 20)]} ] def describe_validate_limit_maximum_number_of_validation_errors(): query = """ { firstUnknownField secondUnknownField thirdUnknownField } """ doc = parse(query, no_location=True) def _validate_document(max_errors=None): return validate(test_schema, doc, max_errors=max_errors) def _invalid_field_error(field_name: str): return { "message": f"Cannot query field '{field_name}' on type 'QueryRoot'.", } def when_max_errors_is_equal_to_number_of_errors(): errors = _validate_document(max_errors=3) assert errors == [ _invalid_field_error("firstUnknownField"), _invalid_field_error("secondUnknownField"), _invalid_field_error("thirdUnknownField"), ] def when_max_errors_is_less_than_number_of_errors(): errors = _validate_document(max_errors=2) assert errors == [ _invalid_field_error("firstUnknownField"), _invalid_field_error("secondUnknownField"), { "message": "Too many validation errors, error limit reached." " Validation aborted." }, ] def limits_to_100_when_max_errors_is_not_passed(): errors = validate( test_schema, parse( "{" + " ".join(f"unknownField{n}" for n in range(120)) + "}", no_location=True, ), ) assert len(errors) == 101 assert errors[0] == _invalid_field_error("unknownField0") assert errors[-2] == _invalid_field_error("unknownField99") assert errors[-1] == { "message": "Too many validation errors, error limit reached." " Validation aborted." } def pass_through_exceptions_from_rules(): class CustomRule(ValidationRule): def enter_field(self, *_args): raise RuntimeError("Error from custom rule!") with raises(RuntimeError, match="^Error from custom rule!$"): validate(test_schema, doc, [CustomRule], max_errors=1) graphql-core-3.2.6/tests/validation/test_values_of_correct_type.py000066400000000000000000001064451474546154300256070ustar00rootroot00000000000000from functools import partial from graphql.pyutils import Undefined, inspect from graphql.type import ( GraphQLArgument, GraphQLField, GraphQLObjectType, GraphQLSchema, GraphQLScalarType, GraphQLString, ) from graphql.validation import ValuesOfCorrectTypeRule from .harness import assert_validation_errors assert_errors = partial(assert_validation_errors, ValuesOfCorrectTypeRule) assert_valid = partial(assert_errors, errors=[]) def describe_validate_values_of_correct_type(): def describe_valid_values(): def good_int_value(): assert_valid( """ { complicatedArgs { intArgField(intArg: 2) } } """ ) def good_negative_int_value(): assert_valid( """ { complicatedArgs { intArgField(intArg: -2) } } """ ) def good_boolean_value(): assert_valid( """ { complicatedArgs { booleanArgField(intArg: true) } } """ ) def good_string_value(): assert_valid( """ { complicatedArgs { stringArgField(intArg: "foo") } } """ ) def good_float_value(): assert_valid( """ { complicatedArgs { floatArgField(intArg: 1.1) } } """ ) def good_negative_float_value(): assert_valid( """ { complicatedArgs { floatArgField(intArg: -1.1) } } """ ) def int_into_id(): assert_valid( """ { complicatedArgs { idArgField(idArg: 1) } } """ ) def string_into_id(): assert_valid( """ { complicatedArgs { idArgField(idArg: "someIdString") } } """ ) def good_enum_value(): assert_valid( """ { dog { doesKnowCommand(dogCommand: SIT) } } """ ) def enum_with_undefined_value(): assert_valid( """ { complicatedArgs { enumArgField(enumArg: UNKNOWN) } } """ ) def enum_with_null_value(): assert_valid( """ { complicatedArgs { enumArgField(enumArg: NO_FUR) } } """ ) def null_into_nullable_type(): assert_valid( """ { complicatedArgs { intArgField(intArg: null) } } """ ) assert_valid( """ { dog(a: null, b: null, c:{ requiredField: true, intField: null }) { name } } """ ) def describe_invalid_string_values(): def int_into_string(): assert_errors( """ { complicatedArgs { stringArgField(stringArg: 1) } } """, [ { "message": "String cannot represent a non string value: 1", "locations": [(4, 47)], }, ], ) def float_into_string(): assert_errors( """ { complicatedArgs { stringArgField(stringArg: 1.0) } } """, [ { "message": "String cannot represent a non string value: 1.0", "locations": [(4, 47)], }, ], ) def boolean_into_string(): assert_errors( """ { complicatedArgs { stringArgField(stringArg: true) } } """, [ { "message": "String cannot represent a non string value: true", "locations": [(4, 47)], }, ], ) def unquoted_string_into_string(): assert_errors( """ { complicatedArgs { stringArgField(stringArg: BAR) } } """, [ { "message": "String cannot represent a non string value: BAR", "locations": [(4, 47)], }, ], ) def describe_invalid_int_values(): def string_into_int(): assert_errors( """ { complicatedArgs { intArgField(intArg: "3") } } """, [ { "message": 'Int cannot represent non-integer value: "3"', "locations": [(4, 41)], }, ], ) def big_int_into_int(): assert_errors( """ { complicatedArgs { intArgField(intArg: 829384293849283498239482938) } } """, [ { "message": "Int cannot represent non 32-bit signed integer" " value: 829384293849283498239482938", "locations": [(4, 41)], }, ], ) def unquoted_string_into_int(): assert_errors( """ { complicatedArgs { intArgField(intArg: FOO) } } """, [ { "message": "Int cannot represent non-integer value: FOO", "locations": [(4, 41)], }, ], ) def simple_float_into_int(): assert_errors( """ { complicatedArgs { intArgField(intArg: 3.0) } } """, [ { "message": "Int cannot represent non-integer value: 3.0", "locations": [(4, 41)], } ], ) def float_into_int(): assert_errors( """ { complicatedArgs { intArgField(intArg: 3.333) } } """, [ { "message": "Int cannot represent non-integer value: 3.333", "locations": [(4, 41)], }, ], ) def describe_invalid_float_values(): def string_into_float(): assert_errors( """ { complicatedArgs { floatArgField(floatArg: "3.333") } } """, [ { "message": 'Float cannot represent non numeric value: "3.333"', "locations": [(4, 45)], }, ], ) def boolean_into_float(): assert_errors( """ { complicatedArgs { floatArgField(floatArg: true) } } """, [ { "message": "Float cannot represent non numeric value: true", "locations": [(4, 45)], }, ], ) def unquoted_into_float(): assert_errors( """ { complicatedArgs { floatArgField(floatArg: FOO) } } """, [ { "message": "Float cannot represent non numeric value: FOO", "locations": [(4, 45)], }, ], ) def describe_invalid_boolean_value(): def int_into_boolean(): assert_errors( """ { complicatedArgs { booleanArgField(booleanArg: 2) } } """, [ { "message": "Boolean cannot represent a non boolean value: 2", "locations": [(4, 49)], }, ], ) def float_into_boolean(): assert_errors( """ { complicatedArgs { booleanArgField(booleanArg: 1.0) } } """, [ { "message": "Boolean cannot represent a non boolean value: 1.0", "locations": [(4, 49)], } ], ) def string_into_boolean(): assert_errors( """ { complicatedArgs { booleanArgField(booleanArg: "true") } } """, [ { "message": "Boolean cannot represent a non boolean value:" ' "true"', "locations": [(4, 49)], } ], ) def unquoted_into_boolean(): assert_errors( """ { complicatedArgs { booleanArgField(booleanArg: TRUE) } } """, [ { "message": "Boolean cannot represent a non boolean value: TRUE", "locations": [(4, 49)], }, ], ) def describe_invalid_id_value(): def float_into_id(): assert_errors( """ { complicatedArgs { idArgField(idArg: 1.0) } } """, [ { "message": "ID cannot represent a non-string" " and non-integer value: 1.0", "locations": [(4, 39)], } ], ) def boolean_into_id(): assert_errors( """ { complicatedArgs { idArgField(idArg: true) } } """, [ { "message": "ID cannot represent a non-string" " and non-integer value: true", "locations": [(4, 39)], }, ], ) def unquoted_into_id(): assert_errors( """ { complicatedArgs { idArgField(idArg: SOMETHING) } } """, [ { "message": "ID cannot represent a non-string" " and non-integer value: SOMETHING", "locations": [(4, 39)], }, ], ) def describe_invalid_enum_value(): def int_into_enum(): assert_errors( """ { dog { doesKnowCommand(dogCommand: 2) } } """, [ { "message": "Enum 'DogCommand' cannot represent non-enum value:" " 2.", "locations": [(4, 49)], }, ], ) def float_into_enum(): assert_errors( """ { dog { doesKnowCommand(dogCommand: 1.0) } } """, [ { "message": "Enum 'DogCommand' cannot represent non-enum value:" " 1.0.", "locations": [(4, 49)], }, ], ) def string_into_enum(): assert_errors( """ { dog { doesKnowCommand(dogCommand: "SIT") } } """, [ { "message": "Enum 'DogCommand' cannot represent non-enum value:" ' "SIT".' " Did you mean the enum value 'SIT'?", "locations": [(4, 49)], }, ], ) def boolean_into_enum(): assert_errors( """ { dog { doesKnowCommand(dogCommand: true) } } """, [ { "message": "Enum 'DogCommand' cannot represent non-enum value:" " true.", "locations": [(4, 49)], }, ], ) def unknown_enum_value_into_enum(): assert_errors( """ { dog { doesKnowCommand(dogCommand: JUGGLE) } } """, [ { "message": "Value 'JUGGLE'" " does not exist in 'DogCommand' enum.", "locations": [(4, 49)], }, ], ) def different_case_enum_value_into_enum(): assert_errors( """ { dog { doesKnowCommand(dogCommand: sit) } } """, [ { "message": "Value 'sit' does not exist in 'DogCommand' enum." " Did you mean the enum value 'SIT'?", "locations": [(4, 49)], }, ], ) def describe_valid_list_value(): def good_list_value(): assert_valid( """ { complicatedArgs { stringListArgField(stringListArg: ["one", null, "two"]) } } """ ) def empty_list_value(): assert_valid( """ { complicatedArgs { stringListArgField(stringListArg: []) } } """ ) def null_value(): assert_valid( """ { complicatedArgs { stringListArgField(stringListArg: null) } } """ ) def single_value_into_list(): assert_valid( """ { complicatedArgs { stringListArgField(stringListArg: "one") } } """ ) def describe_invalid_list_value(): def incorrect_item_type(): assert_errors( """ { complicatedArgs { stringListArgField(stringListArg: ["one", 2]) } } """, [ { "message": "String cannot represent a non string value: 2", "locations": [(4, 63)], }, ], ) def single_value_of_incorrect_type(): assert_errors( """ { complicatedArgs { stringListArgField(stringListArg: 1) } } """, [ { "message": "String cannot represent a non string value: 1", "locations": [(4, 55)], }, ], ) def describe_valid_non_nullable_value(): def arg_on_optional_arg(): assert_valid( """ { dog { isHouseTrained(atOtherHomes: true) } } """ ) def no_arg_on_optional_arg(): assert_valid( """ { dog { isHouseTrained } } """ ) def multiple_args(): assert_valid( """ { complicatedArgs { multipleReqs(req1: 1, req2: 2) } } """ ) def multiple_args_reverse_order(): assert_valid( """ { complicatedArgs { multipleReqs(req2: 2, req1: 1) } } """ ) def no_args_on_multiple_optional(): assert_valid( """ { complicatedArgs { multipleOpts } } """ ) def one_arg_on_multiple_optional(): assert_valid( """ { complicatedArgs { multipleOpts(opt1: 1) } } """ ) def second_arg_on_multiple_optional(): assert_valid( """ { complicatedArgs { multipleOpts(opt2: 1) } } """ ) def multiple_required_args_on_mixed_list(): assert_valid( """ { complicatedArgs { multipleOptAndReq(req1: 3, req2: 4) } } """ ) def multiple_required_and_one_optional_arg_on_mixed_list(): assert_valid( """ { complicatedArgs { multipleOptAndReq(req1: 3, req2: 4, opt1: 5) } } """ ) def all_required_and_optional_args_on_mixed_list(): assert_valid( """ { complicatedArgs { multipleOptAndReq(req1: 3, req2: 4, opt1: 5, opt2: 6) } } """ ) def describe_invalid_non_nullable_value(): def incorrect_value_type(): assert_errors( """ { complicatedArgs { multipleReqs(req2: "two", req1: "one") } } """, [ { "message": 'Int cannot represent non-integer value: "two"', "locations": [(4, 40)], }, { "message": 'Int cannot represent non-integer value: "one"', "locations": [(4, 53)], }, ], ) def incorrect_value_and_missing_argument_provided_required_arguments(): assert_errors( """ { complicatedArgs { multipleReqs(req1: "one") } } """, [ { "message": 'Int cannot represent non-integer value: "one"', "locations": [(4, 40)], }, ], ) def null_value(): assert_errors( """ { complicatedArgs { multipleReqs(req1: null) } } """, [ { "message": "Expected value of type 'Int!', found null.", "locations": [(4, 40)], }, ], ) def describe_valid_input_object_value(): def optional_arg_despite_required_field_in_type(): assert_valid( """ { complicatedArgs { complexArgField } } """ ) def partial_object_only_required(): assert_valid( """ { complicatedArgs { complexArgField(complexArg: { requiredField: true }) } } """ ) def partial_object_required_field_can_be_falsy(): assert_valid( """ { complicatedArgs { complexArgField(complexArg: { requiredField: false }) } } """ ) def partial_object_including_required(): assert_valid( """ { complicatedArgs { complexArgField(complexArg: { requiredField: true, intField: 4 }) } } """ ) def full_object(): assert_valid( """ { complicatedArgs { complexArgField(complexArg: { requiredField: true, intField: 4, stringField: "foo", booleanField: false, stringListField: ["one", "two"] }) } } """ ) def full_object_with_fields_in_different_order(): assert_valid( """ { complicatedArgs { complexArgField(complexArg: { stringListField: ["one", "two"], booleanField: false, requiredField: true, stringField: "foo", intField: 4, }) } } """ ) def describe_invalid_input_object_value(): def partial_object_missing_required(): assert_errors( """ { complicatedArgs { complexArgField(complexArg: { intField: 4 }) } } """, [ { "message": "Field 'ComplexInput.requiredField'" " of required type 'Boolean!' was not provided.", "locations": [(4, 49)], }, ], ) def partial_object_invalid_field_type(): assert_errors( """ { complicatedArgs { complexArgField(complexArg: { stringListField: ["one", 2], requiredField: true, }) } } """, [ { "message": "String cannot represent a non string value: 2", "locations": [(5, 48)], }, ], ) def partial_object_null_to_non_null_field(): assert_errors( """ { complicatedArgs { complexArgField(complexArg: { requiredField: true, nonNullField: null, }) } } """, [ { "message": "Expected value of type 'Boolean!', found null.", "locations": [(6, 37)], } ], ) def partial_object_unknown_field_arg(): assert_errors( """ { complicatedArgs { complexArgField(complexArg: { requiredField: true, invalidField: "value" }) } } """, [ { "message": "Field 'invalidField'" " is not defined by type 'ComplexInput'." " Did you mean 'intField'?", "locations": [(6, 23)], }, ], ) def reports_original_error_for_custom_scalar_which_throws(): def parse_value(value): raise Exception(f"Invalid scalar is always invalid: {inspect(value)}") custom_scalar = GraphQLScalarType("Invalid", parse_value=parse_value) schema = GraphQLSchema( query=GraphQLObjectType( "Query", { "invalidArg": GraphQLField( GraphQLString, {"arg": GraphQLArgument(custom_scalar)} ) }, ) ) errors = assert_errors( "{ invalidArg(arg: 123) }", [ { "message": "Expected value of type 'Invalid', found 123;" " Invalid scalar is always invalid: 123", "locations": [(1, 19)], } ], schema=schema, ) assert str(errors[0].original_error) == ( "Invalid scalar is always invalid: 123" ) def reports_error_for_custom_scalar_that_returns_undefined(): custom_scalar = GraphQLScalarType( "CustomScalar", parse_value=lambda value: Undefined ) schema = GraphQLSchema( GraphQLObjectType( "Query", { "invalidArg": GraphQLField( GraphQLString, args={"arg": GraphQLArgument(custom_scalar)} ) }, ) ) assert_errors( "{ invalidArg(arg: 123) }", [ { "message": "Expected value of type 'CustomScalar', found 123.", "locations": [(1, 19)], }, ], schema=schema, ) def allows_custom_scalar_to_accept_complex_literals(): custom_scalar = GraphQLScalarType("Any") schema = GraphQLSchema( query=GraphQLObjectType( "Query", { "anyArg": GraphQLField( GraphQLString, {"arg": GraphQLArgument(custom_scalar)} ) }, ) ) assert_valid( """ { test1: anyArg(arg: 123) test2: anyArg(arg: "abc") test3: anyArg(arg: [123, "abc"]) test4: anyArg(arg: {deep: [123, "abc"]}) } """, schema=schema, ) def describe_directive_arguments(): def with_directives_of_valid_types(): assert_valid( """ { dog @include(if: true) { name } human @skip(if: false) { name } } """ ) def with_directives_with_incorrect_types(): assert_errors( """ { dog @include(if: "yes") { name @skip(if: ENUM) } } """, [ { "message": "Boolean cannot represent a non boolean value:" ' "yes"', "locations": [(3, 36)], }, { "message": "Boolean cannot represent a non boolean value: ENUM", "locations": [(4, 36)], }, ], ) def describe_variable_default_values(): def variables_with_valid_default_values(): assert_valid( """ query WithDefaultValues( $a: Int = 1, $b: String = "ok", $c: ComplexInput = { requiredField: true, intField: 3 } $d: Int! = 123 ) { dog { name } } """ ) def variables_with_valid_default_null_values(): assert_valid( """ query WithDefaultValues( $a: Int = null, $b: String = null, $c: ComplexInput = { requiredField: true, intField: null } ) { dog { name } } """ ) def variables_with_invalid_default_null_values(): assert_errors( """ query WithDefaultValues( $a: Int! = null, $b: String! = null, $c: ComplexInput = { requiredField: null, intField: null } ) { dog { name } } """, [ { "message": "Expected value of type 'Int!', found null.", "locations": [(3, 30)], }, { "message": "Expected value of type 'String!', found null.", "locations": [(4, 33)], }, { "message": "Expected value of type 'Boolean!', found null.", "locations": [(5, 55)], }, ], ) def variables_with_invalid_default_values(): assert_errors( """ query InvalidDefaultValues( $a: Int = "one", $b: String = 4, $c: ComplexInput = "NotVeryComplex" ) { dog { name } } """, [ { "message": 'Int cannot represent non-integer value: "one"', "locations": [(3, 29)], }, { "message": "String cannot represent a non string value: 4", "locations": [(4, 32)], }, { "message": "Expected value of type 'ComplexInput'," ' found "NotVeryComplex".', "locations": [(5, 38)], }, ], ) def variables_with_complex_invalid_default_values(): assert_errors( """ query WithDefaultValues( $a: ComplexInput = { requiredField: 123, intField: "abc" } ) { dog { name } } """, [ { "message": "Boolean cannot represent a non boolean value: 123", "locations": [(3, 55)], }, { "message": 'Int cannot represent non-integer value: "abc"', "locations": [(3, 70)], }, ], ) def complex_variables_missing_required_fields(): assert_errors( """ query MissingRequiredField($a: ComplexInput = {intField: 3}) { dog { name } } """, [ { "message": "Field 'ComplexInput.requiredField'" " of required type 'Boolean!' was not provided.", "locations": [(2, 63)], }, ], ) def list_variables_with_invalid_item(): assert_errors( """ query InvalidItem($a: [String] = ["one", 2]) { dog { name } } """, [ { "message": "String cannot represent a non string value: 2", "locations": [(2, 58)], }, ], ) graphql-core-3.2.6/tests/validation/test_variables_are_input_types.py000066400000000000000000000027511474546154300262770ustar00rootroot00000000000000from functools import partial from graphql.validation import VariablesAreInputTypesRule from .harness import assert_validation_errors assert_errors = partial(assert_validation_errors, VariablesAreInputTypesRule) assert_valid = partial(assert_errors, errors=[]) def describe_validate_variables_are_input_types(): def unknown_types_are_ignored(): assert_valid( """ query Foo($a: Unknown, $b: [[Unknown!]]!) { field(a: $a, b: $b) } """ ) def input_types_are_valid(): assert_valid( """ query Foo($a: String, $b: [Boolean!]!, $c: ComplexInput) { field(a: $a, b: $b, c: $c) } """ ) def output_types_are_invalid(): assert_errors( """ query Foo($a: Dog, $b: [[CatOrDog!]]!, $c: Pet) { field(a: $a, b: $b, c: $c) } """, [ { "locations": [(2, 27)], "message": "Variable '$a' cannot be non-input type 'Dog'.", }, { "locations": [(2, 36)], "message": "Variable '$b' cannot be" " non-input type '[[CatOrDog!]]!'.", }, { "locations": [(2, 56)], "message": "Variable '$c' cannot be non-input type 'Pet'.", }, ], ) graphql-core-3.2.6/tests/validation/test_variables_in_allowed_position.py000066400000000000000000000237161474546154300271320ustar00rootroot00000000000000from functools import partial from graphql.validation import VariablesInAllowedPositionRule from .harness import assert_validation_errors assert_errors = partial(assert_validation_errors, VariablesInAllowedPositionRule) assert_valid = partial(assert_errors, errors=[]) def describe_validate_variables_are_in_allowed_positions(): def boolean_to_boolean(): assert_valid( """ query Query($booleanArg: Boolean) { complicatedArgs { booleanArgField(booleanArg: $booleanArg) } } """ ) def boolean_to_boolean_in_fragment(): assert_valid( """ fragment booleanArgFrag on ComplicatedArgs { booleanArgField(booleanArg: $booleanArg) } query Query($booleanArg: Boolean) { complicatedArgs { ...booleanArgFrag } } """ ) assert_valid( """ query Query($booleanArg: Boolean) { complicatedArgs { ...booleanArgFrag } } fragment booleanArgFrag on ComplicatedArgs { booleanArgField(booleanArg: $booleanArg) } """ ) def non_null_boolean_to_boolean(): assert_valid( """ query Query($nonNullBooleanArg: Boolean!) { complicatedArgs { booleanArgField(booleanArg: $nonNullBooleanArg) } } """ ) def non_null_boolean_to_boolean_within_fragment(): assert_valid( """ fragment booleanArgFrag on ComplicatedArgs { booleanArgField(booleanArg: $nonNullBooleanArg) } query Query($nonNullBooleanArg: Boolean!) { complicatedArgs { ...booleanArgFrag } } """ ) def array_of_string_to_array_of_string(): assert_valid( """ query Query($stringListVar: [String]) { complicatedArgs { stringListArgField(stringListArg: $stringListVar) } } """ ) def array_of_non_null_string_to_array_of_string(): assert_valid( """ query Query($stringListVar: [String!]) { complicatedArgs { stringListArgField(stringListArg: $stringListVar) } } """ ) def string_to_array_of_string_in_item_position(): assert_valid( """ query Query($stringVar: String) { complicatedArgs { stringListArgField(stringListArg: [$stringVar]) } } """ ) def non_null_string_to_array_of_string_in_item_position(): assert_valid( """ query Query($stringVar: String!) { complicatedArgs { stringListArgField(stringListArg: [$stringVar]) } } """ ) def complex_input_to_complex_input(): assert_valid( """ query Query($complexVar: ComplexInput) { complicatedArgs { complexArgField(complexArg: $complexVar) } } """ ) def complex_input_to_complex_input_in_field_position(): assert_valid( """ query Query($boolVar: Boolean = false) { complicatedArgs { complexArgField(complexArg: {requiredArg: $boolVar}) } } """ ) def non_null_boolean_to_non_null_boolean_in_directive(): assert_valid( """ query Query($boolVar: Boolean!) { dog @include(if: $boolVar) } """ ) def int_to_non_null_int(): assert_errors( """ query Query($intArg: Int) { complicatedArgs { nonNullIntArgField(nonNullIntArg: $intArg) } } """, [ { "message": "Variable '$intArg' of type 'Int'" " used in position expecting type 'Int!'.", "locations": [(2, 25), (4, 51)], } ], ) def int_to_non_null_int_within_fragment(): assert_errors( """ fragment nonNullIntArgFieldFrag on ComplicatedArgs { nonNullIntArgField(nonNullIntArg: $intArg) } query Query($intArg: Int) { complicatedArgs { ...nonNullIntArgFieldFrag } } """, [ { "message": "Variable '$intArg' of type 'Int'" " used in position expecting type 'Int!'.", "locations": [(6, 25), (3, 49)], } ], ) def int_to_non_null_int_within_nested_fragment(): assert_errors( """ fragment outerFrag on ComplicatedArgs { ...nonNullIntArgFieldFrag } fragment nonNullIntArgFieldFrag on ComplicatedArgs { nonNullIntArgField(nonNullIntArg: $intArg) } query Query($intArg: Int) { complicatedArgs { ...outerFrag } } """, [ { "message": "Variable '$intArg' of type 'Int'" " used in position expecting type 'Int!'.", "locations": [(10, 25), (7, 49)], } ], ) def string_to_boolean(): assert_errors( """ query Query($stringVar: String) { complicatedArgs { booleanArgField(booleanArg: $stringVar) } } """, [ { "message": "Variable '$stringVar' of type 'String'" " used in position expecting type 'Boolean'.", "locations": [(2, 25), (4, 45)], } ], ) def string_to_array_of_string(): assert_errors( """ query Query($stringVar: String) { complicatedArgs { stringListArgField(stringListArg: $stringVar) } } """, [ { "message": "Variable '$stringVar' of type 'String'" " used in position expecting type '[String]'.", "locations": [(2, 25), (4, 51)], } ], ) def boolean_to_non_null_boolean_in_directive(): assert_errors( """ query Query($boolVar: Boolean) { dog @include(if: $boolVar) } """, [ { "message": "Variable '$boolVar' of type 'Boolean'" " used in position expecting type 'Boolean!'.", "locations": [(2, 25), (3, 32)], } ], ) def string_to_non_null_boolean_in_directive(): assert_errors( """ query Query($stringVar: String) { dog @include(if: $stringVar) } """, [ { "message": "Variable '$stringVar' of type 'String'" " used in position expecting type 'Boolean!'.", "locations": [(2, 25), (3, 32)], } ], ) def array_of_string_to_array_of_non_null_string(): assert_errors( """ query Query($stringListVar: [String]) { complicatedArgs { stringListNonNullArgField(stringListNonNullArg: $stringListVar) } } """, [ { "message": "Variable '$stringListVar' of type '[String]'" " used in position expecting type '[String!]'.", "locations": [(2, 25), (5, 65)], } ], ) def describe_allows_optional_nullable_variables_with_default_values(): def int_to_non_null_int_fails_when_var_provides_null_default_value(): assert_errors( """ query Query($intVar: Int = null) { complicatedArgs { nonNullIntArgField(nonNullIntArg: $intVar) } } """, [ { "message": "Variable '$intVar' of type 'Int'" " used in position expecting type 'Int!'.", "locations": [(2, 29), (4, 55)], } ], ) def int_to_non_null_int_when_var_provides_non_null_default_value(): assert_valid( """ query Query($intVar: Int = 1) { complicatedArgs { nonNullIntArgField(nonNullIntArg: $intVar) } } """ ) def int_to_non_null_int_when_optional_arg_provides_default_value(): assert_valid( """ query Query($intVar: Int) { complicatedArgs { nonNullFieldWithDefault(nonNullIntArg: $intVar) } } """ ) def bool_to_non_null_bool_in_directive_with_default_value_with_option(): assert_valid( """ query Query($boolVar: Boolean = false) { dog @include(if: $boolVar) } """ ) graphql-core-3.2.6/tox.ini000066400000000000000000000027041474546154300154410ustar00rootroot00000000000000[tox] envlist = py3{6,7,8,9,10,11,12,13}, pypy3{9,10}, black, flake8, mypy, docs, manifest isolated_build = true [gh-actions] python = 3: py311 3.6: py36 3.7: py37 3.8: py38 3.9: py39 3.10: py310 3.11: py311 3.12: py312 3.13: py313 pypy3: pypy39 pypy3.9: pypy39 pypy3.10: pypy310 [testenv:black] basepython = python3.12 deps = black==24.10.0 commands = black src tests setup.py -t py312 --check [testenv:flake8] basepython = python3.12 deps = flake8>=7,<8 commands = flake8 src tests setup.py [testenv:mypy] basepython = python3.12 deps = mypy>=1.14,<2 pytest>=8.3,<9 commands = mypy src tests [testenv:docs] basepython = python3.12 deps = sphinx>=8,<9 sphinx_rtd_theme>=3,<4 commands = sphinx-build -b html -nEW docs docs/_build/html [testenv:manifest] basepython = python3.12 deps = check-manifest>=0.50,<1 commands = check-manifest -v [testenv] deps = pytest>=6.2,<9 pytest-asyncio>=0.16,<1 pytest-benchmark>=3.4,<6 pytest-cov>=4,<7 pytest-describe>=2,<3 pytest-timeout>=2,<3 py3{6,7,8,9},pypy39: typing-extensions>=4.1,<5 commands = # to also run the time-consuming tests: tox -e py311 -- --run-slow # to run the benchmarks: tox -e py311 -- -k benchmarks --benchmark-enable py3{6,7,8,9,10,11,13},pypy3{9,10}: pytest tests {posargs} py312: pytest tests {posargs: --cov-report=term-missing --cov=graphql --cov=tests --cov-fail-under=100}