pax_global_header00006660000000000000000000000064136566174620014532gustar00rootroot0000000000000052 comment=6e2fbccdec655ce9122b84d3808c14242c4e6b96 graphql-core-legacy-2.3.2/000077500000000000000000000000001365661746200153645ustar00rootroot00000000000000graphql-core-legacy-2.3.2/.flake8000066400000000000000000000002131365661746200165330ustar00rootroot00000000000000[flake8] ignore = E203,E501,W503,W504 exclude = .git,.mypy_cache,.pytest_cache,.tox,.venv,__pycache__,build,dist,docs max-line-length = 88 graphql-core-legacy-2.3.2/.github/000077500000000000000000000000001365661746200167245ustar00rootroot00000000000000graphql-core-legacy-2.3.2/.github/ISSUE_TEMPLATE/000077500000000000000000000000001365661746200211075ustar00rootroot00000000000000graphql-core-legacy-2.3.2/.github/ISSUE_TEMPLATE/config.yml000066400000000000000000000000341365661746200230740ustar00rootroot00000000000000blank_issues_enabled: false graphql-core-legacy-2.3.2/.github/ISSUE_TEMPLATE/open-a-graphql-core-legacy-issue.md000066400000000000000000000025251365661746200275660ustar00rootroot00000000000000--- name: Open a GraphQL-core legacy issue about: General template for all GraphQL-core legacy 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 2 (legacy version) 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). Please note that GraphQL-core 2 is not under active development any more, therefore we only accept bug reports or requests for minor changes that do not break compatibility. Please do not suggest new features or anything that requires greater changes. These can be suggested in the issue tracker of the current version (see below), or as a GraphQL.js or GraphQL specification issue. 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 3 (current version) Please use the issue tracker of the [current repository](https://github.com/graphql-python/graphql-core) for issues with current versions of GraphQL-core. graphql-core-legacy-2.3.2/.gitignore000066400000000000000000000012661365661746200173610ustar00rootroot00000000000000# Compile Python files __pycache__/ *.py[cod] # Distribution / packaging .Python venv venv2 venv27 venv3 venv3[3-9] .venv .venv2 .venv27 .venv3 .venv3[3-9] env .env build/ develop-eggs/ dist/ downloads/ eggs/ .eggs/ lib/ lib64/ parts/ sdist/ var/ *.egg-info/ .installed.cfg *.egg # PyInstaller *.manifest *.spec # Installer logs pip-log.txt pip-delete-this-directory.txt # Unit test / coverage reports htmlcov/ .tox/ .coverage .coverage.* .cache nosetests.xml coverage.xml *.cover .pytest_cache/ .python-version # PyBuilder target/ # Type checking /.mypy_cache .pyre /type_info.json # Sphinx documentation docs/_build/ # IntelliJ .idea *.iml # Visual Studio /.vscode # OS X .DS_Store graphql-core-legacy-2.3.2/.pre-commit-config.yaml000066400000000000000000000012411365661746200216430ustar00rootroot00000000000000repos: - repo: git://github.com/pre-commit/pre-commit-hooks rev: v2.4.0 hooks: - id: check-merge-conflict - id: check-json - id: check-yaml - id: debug-statements - id: end-of-file-fixer exclude: ^docs/.*$ - id: pretty-format-json args: - --autofix - id: trailing-whitespace exclude: README.md - repo: https://github.com/asottile/pyupgrade rev: v1.26.2 hooks: - id: pyupgrade - repo: https://github.com/ambv/black rev: 19.10b0 hooks: - id: black - repo: https://github.com/pycqa/flake8 rev: 3.7.9 hooks: - id: flake8 exclude: test_.*$ graphql-core-legacy-2.3.2/.travis.yml000066400000000000000000000026751365661746200175070ustar00rootroot00000000000000language: python matrix: include: - env: TOXENV=py27 python: 2.7 - env: TOXENV=py35 python: 3.5 - env: TOXENV=py36 python: 3.6 - env: TOXENV=py37 python: 3.7 - env: TOXENV=py38 python: 3.8 - env: TOXENV=pypy python: pypy - env: TOXENV=pypy3 python: pypy3 - env: TOXENV=pre-commit python: 3.8 - env: TOXENV=mypy python: 3.8 install: pip install "tox==3.15.0" "coveralls==1.11.1" script: tox after_success: coveralls cache: directories: - $HOME/.cache/pip - $HOME/.cache/pre-commit deploy: provider: pypi distributions: "sdist bdist_wheel" on: branch: master tags: true python: 3.8 skip_existing: true user: syrusakbary password: secure: q7kMxnJQ5LWr8fxVbQPm3pAXKRfYa1d2defM1UXKTQ+Gi6ZQ+QEOAOSbX1SKzYH62+hNRY2JGTeLkTQBeEYn05GJRh+WOkFzIFV1EnsgFbimSb6B83EmM57099GjJnO2nRUU4jyuNGU1joTeaD/g08ede072Es1I7DTuholNbYIq+brL/LQMJycuqZMoWUW4+pP8dE9SmjThMNYHlqNhzdXSE3BlZU0xcw7F2Ea384DNcekIIcapZuPjL167VouuSH/oMQMxBJo+ExEHdbqn5zsA9xcoF931XCgz4ag8U3jHhE48ZXM/xwdQt+S8JnOZcuv3MoAAioMbh+bYXUt2lmENWXCKK1kMDz2bJymwEUeZLA6lFxJQwvlVShowdi7xeyDYLIbeF7yG90Hd+5BqCZn5imzlcQxpjanaQq6xLwAzo6AHssWtd5bBOjDydknPxd1t3QGDoDvtfRdqrfOhlVX5813Hmd/vAopBAba7msKPMLxhsqDZKkwsVrLJLJDjGdpHNl/bbVaMsYcPrsFxa2W8PuddQFviHbL4HDNqHn5SpRwJcQ18YL1X5StQnUz1J+4E0W4mLrU3YW1k8RGlKTes/GeTH4sU+Sh3I9vrDv7849A8U9sSFyB2PT4Jyy8O2R5UyjoqnZDrkYYbLdn/caVo3ThrubTpwdPBmNwcDLA= graphql-core-legacy-2.3.2/CODEOWNERS000066400000000000000000000000701365661746200167540ustar00rootroot00000000000000/ @syrusakbary @ekampf @dan98765 @projectcheshire @cito graphql-core-legacy-2.3.2/LICENSE000066400000000000000000000020711365661746200163710ustar00rootroot00000000000000The MIT License (MIT) Copyright (c) 2016 GraphQL Python 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-legacy-2.3.2/MANIFEST.in000066400000000000000000000001621365661746200171210ustar00rootroot00000000000000global-exclude tests/* recursive-exclude tests * recursive-exclude tests_py35 * include LICENSE include README.md graphql-core-legacy-2.3.2/README.md000066400000000000000000000140541365661746200166470ustar00rootroot00000000000000# GraphQL-core 2 ⚠️ This is the repository of GraphQL for Python 2 (legacy version). **The repository for the current version is available at [github.com/graphql-python/graphql-core](https://github.com/graphql-python/graphql-core).** [![Build Status](https://travis-ci.org/graphql-python/graphql-core-legacy.svg?branch=master)](https://travis-ci.org/graphql-python/graphql-core-legacy) [![Coverage Status](https://coveralls.io/repos/github/graphql-python/graphql-core-legacy/badge.svg?branch=master)](https://coveralls.io/github/graphql-python/graphql-core-legacy?branch=master) This library is a port of [GraphQL.js](https://github.com/graphql/graphql-js) to Python and up-to-date with release [0.6.0](https://github.com/graphql/graphql-js/releases/tag/v0.6.0). GraphQL-core 2 supports Python version 2.7, 3.5, 3.6, 3.7 and 3.8. GraphQL.js is the JavaScript reference implementation for GraphQL, a query language for APIs created by Facebook. See also the GraphQL documentation at [graphql.org](https://graphql.org/) and [graphql.org/graphql-js/graphql/](https://graphql.org/graphql-js/graphql/). For questions regarding GraphQL, ask [Stack Overflow](http://stackoverflow.com/questions/tagged/graphql). ## Getting Started An overview of the GraphQL language is available in the [README](https://github.com/graphql/graphql-spec/blob/master/README.md) for the [Specification for GraphQL](https://github.com/graphql/graphql-spec). The overview describes a simple set of GraphQL examples that exist as [tests](https://github.com/graphql-python/graphql-core-legacy/tree/master/tests/) in this repository. A good way to get started is to walk through that README and the corresponding tests in parallel. ### Using GraphQL-core 2 Install from pip: ```sh pip install "graphql-core<3" ``` 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 code base. ```python from graphql import ( graphql, GraphQLSchema, GraphQLObjectType, GraphQLField, GraphQLString ) schema = GraphQLSchema( query=GraphQLObjectType( name='RootQueryType', fields={ 'hello': GraphQLField( type=GraphQLString, resolver=lambda *_: 'world' ) } ) ) ``` This defines a simple schema with one type and one field, that resolves to a fixed value. The `resolver` function can return a value, a promise, or an array of promises. A more complex example is included in the top level [tests](https://github.com/graphql-python/graphql-core-legacy/tree/master/tests/) directory. Then, serve the result of a query against that type schema. ```python query = '{ hello }' result = graphql(schema, query) # Prints # {'hello': 'world'} (as OrderedDict) print result.data ``` This runs a query fetching the one field defined. The `graphql` function will first ensure the query is syntactically and semantically valid before executing it, reporting errors otherwise. ```python query = '{ boyhowdy }' result = graphql(schema, query) # Prints # [GraphQLError('Cannot query field "boyhowdy" on type "RootQueryType".',)] print result.errors ``` ### Executors The graphql query is executed, by default, synchronously (using `SyncExecutor`). However the following executors are available if we want to resolve our fields in parallel: - `graphql.execution.executors.asyncio.AsyncioExecutor`: This executor executes the resolvers in the Python asyncio event loop. - `graphql.execution.executors.gevent.GeventExecutor`: This executor executes the resolvers in the Gevent event loop. - `graphql.execution.executors.process.ProcessExecutor`: This executor executes each resolver as a process. - `graphql.execution.executors.thread.ThreadExecutor`: This executor executes each resolver in a Thread. - `graphql.execution.executors.sync.SyncExecutor`: This executor executes each resolver synchronusly (default). #### Usage You can specify the executor to use via the executor keyword argument in the `grapqhl.execution.execute` function. ```python from graphql import parse from graphql.execution import execute from graphql.execution.executors.sync import SyncExecutor ast = parse('{ hello }') result = execute(schema, ast, executor=SyncExecutor()) print result.data ``` ### Contributing After cloning this repo, create a [virtualenv](https://virtualenv.pypa.io/en/stable/) and ensure dependencies are installed by running: ```sh virtualenv venv source venv/bin/activate pip install -e ".[test]" ``` Well-written tests and maintaining good test coverage is important to this project. While developing, run new and existing tests with: ```sh pytest PATH/TO/MY/DIR/test_test.py # Single file pytest PATH/TO/MY/DIR/ # All tests in directory ``` Add the `-s` flag if you have introduced breakpoints into the code for debugging. Add the `-v` ("verbose") flag to get more detailed test output. For even more detailed output, use `-vv`. Check out the [pytest documentation](https://docs.pytest.org/en/latest/) for more options and test running controls. GraphQL-core 2 supports several versions of Python. To make sure that changes do not break compatibility with any of those versions, we use `tox` to create virtualenvs for each Python version and run tests with that version. To run against all python versions defined in the `tox.ini` config file, just run: ```sh tox ``` If you wish to run against a specific version defined in the `tox.ini` file: ```sh tox -e py36 ``` Tox can only use whatever versions of python are installed on your system. When you create a pull request, Travis will also be running the same tests and report the results, so there is no need for potential contributors to try to install every single version of python on their own system ahead of time. We appreciate opening issues and pull requests to make GraphQL-core even more stable & useful! ## Main Contributors - [@syrusakbary](https://github.com/syrusakbary/) - [@jhgg](https://github.com/jhgg/) - [@dittos](https://github.com/dittos/) ## License [MIT License](https://github.com/graphql-python/graphql-core-legacy/blob/master/LICENSE) graphql-core-legacy-2.3.2/bin/000077500000000000000000000000001365661746200161345ustar00rootroot00000000000000graphql-core-legacy-2.3.2/bin/autolinter000077500000000000000000000004311365661746200202460ustar00rootroot00000000000000#!/bin/bash # Install the required scripts with # pip install autoflake autopep8 isort autoflake ./graphql/ ./tests/ -r --remove-unused-variables --in-place autopep8 ./tests/ ./graphql/ -r --in-place --experimental --aggressive --max-line-length 120 isort -rc ./tests/ ./graphql/ graphql-core-legacy-2.3.2/conftest.py000066400000000000000000000020051365661746200175600ustar00rootroot00000000000000# Configuration for pytest to automatically collect types. # Thanks to Guilherme Salgado. import pytest try: import pyannotate_runtime # noqa: F401 PYANOTATE_PRESENT = True except ImportError: PYANOTATE_PRESENT = False if PYANOTATE_PRESENT: def pytest_collection_finish(session): """Handle the pytest collection finish hook: configure pyannotate. Explicitly delay importing `collect_types` until all tests have been collected. This gives gevent a chance to monkey patch the world before importing pyannotate. """ from pyannotate_runtime import collect_types collect_types.init_types_collection() @pytest.fixture(autouse=True) def collect_types_fixture(): from pyannotate_runtime import collect_types collect_types.resume() yield collect_types.pause() def pytest_sessionfinish(session, exitstatus): from pyannotate_runtime import collect_types collect_types.dump_stats("type_info.json") graphql-core-legacy-2.3.2/docs/000077500000000000000000000000001365661746200163145ustar00rootroot00000000000000graphql-core-legacy-2.3.2/docs/Makefile000066400000000000000000000164011365661746200177560ustar00rootroot00000000000000# Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = BUILDDIR = _build # User-friendly check for sphinx-build ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) endif # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . # the i18n builder cannot share the environment and doctrees with the others I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest coverage gettext help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @echo " dirhtml to make HTML files named index.html in directories" @echo " singlehtml to make a single large HTML file" @echo " pickle to make pickle files" @echo " json to make JSON files" @echo " htmlhelp to make HTML files and a HTML help project" @echo " qthelp to make HTML files and a qthelp project" @echo " applehelp to make an Apple Help Book" @echo " devhelp to make HTML files and a Devhelp project" @echo " epub to make an epub" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " latexpdf to make LaTeX files and run them through pdflatex" @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" @echo " text to make text files" @echo " man to make manual pages" @echo " texinfo to make Texinfo files" @echo " info to make Texinfo files and run them through makeinfo" @echo " gettext to make PO message catalogs" @echo " changes to make an overview of all changed/added/deprecated items" @echo " xml to make Docutils-native XML files" @echo " pseudoxml to make pseudoxml-XML files for display purposes" @echo " linkcheck to check all external links for integrity" @echo " doctest to run all doctests embedded in the documentation (if enabled)" @echo " coverage to run coverage check of the documentation (if enabled)" clean: rm -rf $(BUILDDIR)/* html: $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." singlehtml: $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml @echo @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." pickle: $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle @echo @echo "Build finished; now you can process the pickle files." json: $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json @echo @echo "Build finished; now you can process the JSON files." htmlhelp: $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in $(BUILDDIR)/htmlhelp." qthelp: $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in $(BUILDDIR)/qthelp, like this:" @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/graphql-py.qhcp" @echo "To view the help file:" @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/graphql-py.qhc" applehelp: $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp @echo @echo "Build finished. The help book is in $(BUILDDIR)/applehelp." @echo "N.B. You won't be able to view it unless you put it in" \ "~/Library/Documentation/Help or install it in your application" \ "bundle." devhelp: $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp @echo @echo "Build finished." @echo "To view the help file:" @echo "# mkdir -p $$HOME/.local/share/devhelp/graphql-py" @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/graphql-py" @echo "# devhelp" epub: $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub @echo @echo "Build finished. The epub file is in $(BUILDDIR)/epub." latex: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." @echo "Run \`make' in that directory to run these through (pdf)latex" \ "(use \`make latexpdf' here to do that automatically)." latexpdf: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through pdflatex..." $(MAKE) -C $(BUILDDIR)/latex all-pdf @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." latexpdfja: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through platex and dvipdfmx..." $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." text: $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text @echo @echo "Build finished. The text files are in $(BUILDDIR)/text." man: $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man @echo @echo "Build finished. The manual pages are in $(BUILDDIR)/man." texinfo: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." @echo "Run \`make' in that directory to run these through makeinfo" \ "(use \`make info' here to do that automatically)." info: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo "Running Texinfo files through makeinfo..." make -C $(BUILDDIR)/texinfo info @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." gettext: $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale @echo @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." changes: $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes @echo @echo "The overview file is in $(BUILDDIR)/changes." linkcheck: $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in $(BUILDDIR)/linkcheck/output.txt." doctest: $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in $(BUILDDIR)/doctest/output.txt." coverage: $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage @echo "Testing of coverage in the sources finished, look at the " \ "results in $(BUILDDIR)/coverage/python.txt." xml: $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml @echo @echo "Build finished. The XML files are in $(BUILDDIR)/xml." pseudoxml: $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml @echo @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." graphql-core-legacy-2.3.2/docs/conf.py000066400000000000000000000225351365661746200176220ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # graphqllib documentation build configuration file, created by # sphinx-quickstart on Wed Sep 16 20:08:39 2015. # # 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. import sys import os # 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. 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", "sphinx.ext.intersphinx", "sphinx.ext.todo", "sphinx.ext.coverage", "sphinx.ext.viewcode", ] # 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 = u"graphqllib" copyright = u"2015, Taeho Kim" author = u"Taeho Kim" # 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 = "2.3" # The full version, including alpha/beta/rc tags. release = "2.3.2" # 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 = None # 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. exclude_patterns = ["_build"] # 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 = True # -- 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 = "alabaster" # 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 = {} # Add any paths that contain custom themes here, relative to this directory. # html_theme_path = [] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". # html_title = None # 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 (within the static path) to use as 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 '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. # html_last_updated_fmt = '%b %d, %Y' # 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 = True # 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' # html_search_language = 'en' # A dictionary with options for the search language support, empty by default. # Now only 'ja' uses this config value # 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 = "graphqllibdoc" # -- 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, "graphqllib.tex", u"graphqllib Documentation", u"Taeho Kim", "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, "graphqllib", u"graphqllib 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, "graphqllib", u"graphqllib Documentation", author, "graphqllib", "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 # Example configuration for intersphinx: refer to the Python standard library. intersphinx_mapping = {"https://docs.python.org/": None} graphql-core-legacy-2.3.2/docs/index.rst000066400000000000000000000006631365661746200201620ustar00rootroot00000000000000.. graphql-py documentation master file, created by sphinx-quickstart on Wed Sep 16 20:08:39 2015. You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. Welcome to graphql-py's documentation! ====================================== Contents: .. toctree:: :maxdepth: 2 Indices and tables ================== * :ref:`genindex` * :ref:`modindex` * :ref:`search` graphql-core-legacy-2.3.2/docs/make.bat000066400000000000000000000161241365661746200177250ustar00rootroot00000000000000@ECHO OFF REM Command file for Sphinx documentation if "%SPHINXBUILD%" == "" ( set SPHINXBUILD=sphinx-build ) set BUILDDIR=_build set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . set I18NSPHINXOPTS=%SPHINXOPTS% . if NOT "%PAPER%" == "" ( set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% ) if "%1" == "" goto help if "%1" == "help" ( :help echo.Please use `make ^` where ^ is one of echo. html to make standalone HTML files echo. dirhtml to make HTML files named index.html in directories echo. singlehtml to make a single large HTML file echo. pickle to make pickle files echo. json to make JSON files echo. htmlhelp to make HTML files and a HTML help project echo. qthelp to make HTML files and a qthelp project echo. devhelp to make HTML files and a Devhelp project echo. epub to make an epub echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter echo. text to make text files echo. man to make manual pages echo. texinfo to make Texinfo files echo. gettext to make PO message catalogs echo. changes to make an overview over all changed/added/deprecated items echo. xml to make Docutils-native XML files echo. pseudoxml to make pseudoxml-XML files for display purposes echo. linkcheck to check all external links for integrity echo. doctest to run all doctests embedded in the documentation if enabled echo. coverage to run coverage check of the documentation if enabled goto end ) if "%1" == "clean" ( for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i del /q /s %BUILDDIR%\* goto end ) REM Check if sphinx-build is available and fallback to Python version if any %SPHINXBUILD% 2> nul if errorlevel 9009 goto sphinx_python goto sphinx_ok :sphinx_python set SPHINXBUILD=python -m sphinx.__init__ %SPHINXBUILD% 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 ) :sphinx_ok if "%1" == "html" ( %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/html. goto end ) if "%1" == "dirhtml" ( %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. goto end ) if "%1" == "singlehtml" ( %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. goto end ) if "%1" == "pickle" ( %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can process the pickle files. goto end ) if "%1" == "json" ( %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can process the JSON files. goto end ) if "%1" == "htmlhelp" ( %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can run HTML Help Workshop with the ^ .hhp project file in %BUILDDIR%/htmlhelp. goto end ) if "%1" == "qthelp" ( %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can run "qcollectiongenerator" with the ^ .qhcp project file in %BUILDDIR%/qthelp, like this: echo.^> qcollectiongenerator %BUILDDIR%\qthelp\graphql-py.qhcp echo.To view the help file: echo.^> assistant -collectionFile %BUILDDIR%\qthelp\graphql-py.ghc goto end ) if "%1" == "devhelp" ( %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp if errorlevel 1 exit /b 1 echo. echo.Build finished. goto end ) if "%1" == "epub" ( %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub if errorlevel 1 exit /b 1 echo. echo.Build finished. The epub file is in %BUILDDIR%/epub. goto end ) if "%1" == "latex" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex if errorlevel 1 exit /b 1 echo. echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. goto end ) if "%1" == "latexpdf" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex cd %BUILDDIR%/latex make all-pdf cd %~dp0 echo. echo.Build finished; the PDF files are in %BUILDDIR%/latex. goto end ) if "%1" == "latexpdfja" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex cd %BUILDDIR%/latex make all-pdf-ja cd %~dp0 echo. echo.Build finished; the PDF files are in %BUILDDIR%/latex. goto end ) if "%1" == "text" ( %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text if errorlevel 1 exit /b 1 echo. echo.Build finished. The text files are in %BUILDDIR%/text. goto end ) if "%1" == "man" ( %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man if errorlevel 1 exit /b 1 echo. echo.Build finished. The manual pages are in %BUILDDIR%/man. goto end ) if "%1" == "texinfo" ( %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo if errorlevel 1 exit /b 1 echo. echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. goto end ) if "%1" == "gettext" ( %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale if errorlevel 1 exit /b 1 echo. echo.Build finished. The message catalogs are in %BUILDDIR%/locale. goto end ) if "%1" == "changes" ( %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes if errorlevel 1 exit /b 1 echo. echo.The overview file is in %BUILDDIR%/changes. goto end ) if "%1" == "linkcheck" ( %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck if errorlevel 1 exit /b 1 echo. echo.Link check complete; look for any errors in the above output ^ or in %BUILDDIR%/linkcheck/output.txt. goto end ) if "%1" == "doctest" ( %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest if errorlevel 1 exit /b 1 echo. echo.Testing of doctests in the sources finished, look at the ^ results in %BUILDDIR%/doctest/output.txt. goto end ) if "%1" == "coverage" ( %SPHINXBUILD% -b coverage %ALLSPHINXOPTS% %BUILDDIR%/coverage if errorlevel 1 exit /b 1 echo. echo.Testing of coverage in the sources finished, look at the ^ results in %BUILDDIR%/coverage/python.txt. goto end ) if "%1" == "xml" ( %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml if errorlevel 1 exit /b 1 echo. echo.Build finished. The XML files are in %BUILDDIR%/xml. goto end ) if "%1" == "pseudoxml" ( %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml if errorlevel 1 exit /b 1 echo. echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. goto end ) :end graphql-core-legacy-2.3.2/graphql/000077500000000000000000000000001365661746200170225ustar00rootroot00000000000000graphql-core-legacy-2.3.2/graphql/__init__.py000066400000000000000000000151041365661746200211340ustar00rootroot00000000000000""" GraphQL.js provides a reference implementation for the GraphQL specification but is also a useful utility for operating on GraphQL files and building sophisticated tools. This primary module 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-directory directly. For example, the following two import statements are equivalent: from graphql import parse from graphql.language.base import parse """ from .pyutils.version import get_version # The primary entry point into fulfilling a GraphQL request. from .graphql import graphql # Create and operate on GraphQL type definitions and schema. from .type import ( # no import order GraphQLSchema, # Definitions GraphQLScalarType, GraphQLObjectType, GraphQLInterfaceType, GraphQLUnionType, GraphQLEnumType, GraphQLEnumValue, GraphQLInputObjectType, GraphQLList, GraphQLNonNull, GraphQLField, GraphQLInputObjectField, GraphQLArgument, # "Enum" of Type Kinds TypeKind, # "Enum" of Directive locations DirectiveLocation, # Scalars GraphQLInt, GraphQLFloat, GraphQLString, GraphQLBoolean, GraphQLID, # Directive definition GraphQLDirective, # Built-in directives defined by the Spec specified_directives, GraphQLSkipDirective, GraphQLIncludeDirective, GraphQLDeprecatedDirective, # Constant Deprecation Reason DEFAULT_DEPRECATION_REASON, # GraphQL Types for introspection. __Schema, __Directive, __DirectiveLocation, __Type, __Field, __InputValue, __EnumValue, __TypeKind, # Meta-field definitions. SchemaMetaFieldDef, TypeMetaFieldDef, TypeNameMetaFieldDef, # Predicates is_type, is_input_type, is_output_type, is_leaf_type, is_composite_type, is_abstract_type, # Un-modifiers get_nullable_type, get_named_type, ) # Parse and operate on GraphQL language source files. from .language.base import ( # no import order Source, get_location, # Parse parse, parse_value, # Print print_ast, # Visit visit, ParallelVisitor, TypeInfoVisitor, BREAK, ) # Execute GraphQL queries. from .execution import ( # no import order execute, subscribe, ResolveInfo, MiddlewareManager, middlewares, ) # Validate GraphQL queries. from .validation import validate, specified_rules # no import order # Create and format GraphQL errors. from .error import GraphQLError, format_error # Utilities for operating on GraphQL type schema and parsed sources. from .utils.base import ( # The GraphQL query recommended for a full schema introspection. introspection_query, # Gets the target Operation from a Document get_operation_ast, # Build a GraphQLSchema from an introspection result. build_client_schema, # Build a GraphQLSchema from a parsed GraphQL Schema language AST. build_ast_schema, # Extends an existing GraphQLSchema from a parsed GraphQL Schema # language AST. extend_schema, # Print a GraphQLSchema to GraphQL Schema language. print_schema, # Create a GraphQLType from a GraphQL language AST. type_from_ast, # Create a JavaScript value from a GraphQL language AST. value_from_ast, # Create a GraphQL language AST from a JavaScript value. ast_from_value, # A helper to use within recursive-descent visitors which need to be aware of # the GraphQL type system. TypeInfo, # Determine if JavaScript values adhere to a GraphQL type. is_valid_value, # Determine if AST values adhere to a GraphQL type. is_valid_literal_value, # Concatenates multiple AST together. concat_ast, # Comparators for types is_equal_type, is_type_sub_type_of, do_types_overlap, # Asserts a string is a valid GraphQL name. assert_valid_name, # Undefined const Undefined, ) # Utilities for dynamic execution engines from .backend import ( GraphQLBackend, GraphQLDocument, GraphQLCoreBackend, GraphQLDeciderBackend, GraphQLCachedBackend, get_default_backend, set_default_backend, ) VERSION = (2, 3, 2, "final", 0) __version__ = get_version(VERSION) __all__ = ( "__version__", "graphql", "GraphQLBoolean", "GraphQLEnumType", "GraphQLEnumValue", "GraphQLFloat", "GraphQLID", "GraphQLInputObjectType", "GraphQLInt", "GraphQLInterfaceType", "GraphQLList", "GraphQLNonNull", "GraphQLField", "GraphQLInputObjectField", "GraphQLArgument", "GraphQLObjectType", "GraphQLScalarType", "GraphQLSchema", "GraphQLString", "GraphQLUnionType", "GraphQLDirective", "specified_directives", "GraphQLSkipDirective", "GraphQLIncludeDirective", "GraphQLDeprecatedDirective", "DEFAULT_DEPRECATION_REASON", "TypeKind", "DirectiveLocation", "__Schema", "__Directive", "__DirectiveLocation", "__Type", "__Field", "__InputValue", "__EnumValue", "__TypeKind", "SchemaMetaFieldDef", "TypeMetaFieldDef", "TypeNameMetaFieldDef", "get_named_type", "get_nullable_type", "is_abstract_type", "is_composite_type", "is_input_type", "is_leaf_type", "is_output_type", "is_type", "BREAK", "ParallelVisitor", "Source", "TypeInfoVisitor", "get_location", "parse", "parse_value", "print_ast", "visit", "execute", "subscribe", "ResolveInfo", "MiddlewareManager", "middlewares", "specified_rules", "validate", "GraphQLError", "format_error", "TypeInfo", "assert_valid_name", "ast_from_value", "build_ast_schema", "build_client_schema", "concat_ast", "do_types_overlap", "extend_schema", "get_operation_ast", "introspection_query", "is_equal_type", "is_type_sub_type_of", "is_valid_literal_value", "is_valid_value", "print_schema", "type_from_ast", "value_from_ast", "get_version", "Undefined", "GraphQLBackend", "GraphQLDocument", "GraphQLCoreBackend", "GraphQLDeciderBackend", "GraphQLCachedBackend", "get_default_backend", "set_default_backend", ) graphql-core-legacy-2.3.2/graphql/backend/000077500000000000000000000000001365661746200204115ustar00rootroot00000000000000graphql-core-legacy-2.3.2/graphql/backend/__init__.py000066400000000000000000000017221365661746200225240ustar00rootroot00000000000000# -*- coding: utf-8 -*- """ This module provides a dynamic way of using different engines for a GraphQL schema query resolution. """ from .base import GraphQLBackend, GraphQLDocument from .core import GraphQLCoreBackend from .decider import GraphQLDeciderBackend from .cache import GraphQLCachedBackend _default_backend = None def get_default_backend(): # type: () -> GraphQLCoreBackend global _default_backend if _default_backend is None: _default_backend = GraphQLCoreBackend() return _default_backend def set_default_backend(backend): # type: (GraphQLCoreBackend) -> None global _default_backend assert isinstance( backend, GraphQLBackend ), "backend must be an instance of GraphQLBackend." _default_backend = backend __all__ = [ "GraphQLBackend", "GraphQLDocument", "GraphQLCoreBackend", "GraphQLDeciderBackend", "GraphQLCachedBackend", "get_default_backend", "set_default_backend", ] graphql-core-legacy-2.3.2/graphql/backend/base.py000066400000000000000000000042351365661746200217010ustar00rootroot00000000000000from abc import ABCMeta, abstractmethod import six from ..pyutils.cached_property import cached_property from ..language import ast # Necessary for static type checking if False: # flake8: noqa from typing import Dict, Optional, Union, Callable from ..language.ast import Document from ..type.schema import GraphQLSchema class GraphQLBackend(six.with_metaclass(ABCMeta)): @abstractmethod def document_from_string(self, schema, request_string): raise NotImplementedError( "document_from_string method not implemented in {}.".format(self.__class__) ) class GraphQLDocument(object): def __init__(self, schema, document_string, document_ast, execute): # type: (GraphQLSchema, str, Document, Callable) -> None self.schema = schema self.document_string = document_string self.document_ast = document_ast self.execute = execute @cached_property def operations_map(self): # type: () -> Dict[Union[str, None], str] """ returns a Mapping of operation names and it's associated types. E.g. {'myQuery': 'query', 'myMutation': 'mutation'} """ document_ast = self.document_ast operations = {} # type: Dict[Union[str, None], str] for definition in document_ast.definitions: if isinstance(definition, ast.OperationDefinition): if definition.name: operations[definition.name.value] = definition.operation else: operations[None] = definition.operation return operations def get_operation_type(self, operation_name): # type: (Optional[str]) -> Optional[str] """ Returns the operation type ('query', 'mutation', 'subscription' or None) for the given operation_name. If no operation_name is provided (and only one operation exists) it will return the operation type for that operation """ operations_map = self.operations_map if not operation_name and len(operations_map) == 1: return next(iter(operations_map.values())) return operations_map.get(operation_name) graphql-core-legacy-2.3.2/graphql/backend/cache.py000066400000000000000000000054311365661746200220310ustar00rootroot00000000000000from hashlib import sha1 from six import string_types from ..type import GraphQLSchema from .base import GraphQLBackend # Necessary for static type checking if False: # flake8: noqa from typing import Dict, Optional, Hashable from .base import GraphQLDocument _cached_schemas = {} # type: Dict[GraphQLSchema, str] _cached_queries = {} # type: Dict[str, str] def get_unique_schema_id(schema): # type: (GraphQLSchema) -> str """Get a unique id given a GraphQLSchema""" assert isinstance(schema, GraphQLSchema), ( "Must receive a GraphQLSchema as schema. Received {}" ).format(repr(schema)) if schema not in _cached_schemas: _cached_schemas[schema] = sha1(str(schema).encode("utf-8")).hexdigest() return _cached_schemas[schema] def get_unique_document_id(query_str): # type: (str) -> str """Get a unique id given a query_string""" assert isinstance(query_str, string_types), ( "Must receive a string as query_str. Received {}" ).format(repr(query_str)) if query_str not in _cached_queries: _cached_queries[query_str] = sha1(str(query_str).encode("utf-8")).hexdigest() return _cached_queries[query_str] class GraphQLCachedBackend(GraphQLBackend): """GraphQLCachedBackend will cache the document response from the backend given a key for that document""" def __init__( self, backend, # type: GraphQLBackend cache_map=None, # type: Optional[Dict[Hashable, GraphQLDocument]] use_consistent_hash=False, # type: bool ): # type: (...) -> None assert isinstance( backend, GraphQLBackend ), "Provided backend must be an instance of GraphQLBackend" if cache_map is None: cache_map = {} self.backend = backend self.cache_map = cache_map self.use_consistent_hash = use_consistent_hash def get_key_for_schema_and_document_string(self, schema, request_string): # type: (GraphQLSchema, str) -> int """This method returns a unique key given a schema and a request_string""" if self.use_consistent_hash: schema_id = get_unique_schema_id(schema) document_id = get_unique_document_id(request_string) return hash((schema_id, document_id)) return hash((schema, request_string)) def document_from_string(self, schema, request_string): # type: (GraphQLSchema, str) -> Optional[GraphQLDocument] """This method returns a GraphQLQuery (from cache if present)""" key = self.get_key_for_schema_and_document_string(schema, request_string) if key not in self.cache_map: self.cache_map[key] = self.backend.document_from_string( schema, request_string ) return self.cache_map[key] graphql-core-legacy-2.3.2/graphql/backend/compiled.py000066400000000000000000000037671365661746200225740ustar00rootroot00000000000000from six import string_types from .base import GraphQLDocument # Necessary for static type checking if False: # flake8: noqa from ..type.schema import GraphQLSchema from typing import Any, Optional, Dict, Callable, Union class GraphQLCompiledDocument(GraphQLDocument): @classmethod def from_code( cls, schema, # type: GraphQLSchema code, # type: Union[str, Any] uptodate=None, # type: Optional[bool] extra_namespace=None, # type: Optional[Dict[str, Any]] ): # type: (...) -> GraphQLCompiledDocument """Creates a GraphQLDocument object from compiled code and the globals. This is used by the loaders and schema to create a document object. """ if isinstance(code, string_types): filename = "" code = compile(code, filename, "exec") namespace = {"__file__": code.co_filename} exec(code, namespace) if extra_namespace: namespace.update(extra_namespace) rv = cls._from_namespace(schema, namespace) # rv._uptodate = uptodate return rv @classmethod def from_module_dict(cls, schema, module_dict): # type: (GraphQLSchema, Dict[str, Any]) -> GraphQLCompiledDocument """Creates a template object from a module. This is used by the module loader to create a document object. """ return cls._from_namespace(schema, module_dict) @classmethod def _from_namespace(cls, schema, namespace): # type: (GraphQLSchema, Dict[str, Any]) -> GraphQLCompiledDocument document_string = namespace.get("document_string", "") # type: str document_ast = namespace.get("document_ast") # type: ignore execute = namespace["execute"] # type: Callable namespace["schema"] = schema return cls( schema=schema, document_string=document_string, document_ast=document_ast, # type: ignore execute=execute, ) graphql-core-legacy-2.3.2/graphql/backend/core.py000066400000000000000000000037301365661746200217160ustar00rootroot00000000000000from functools import partial from six import string_types from ..execution import execute, ExecutionResult from ..language.base import parse, print_ast from ..language import ast from ..validation import validate from .base import GraphQLBackend, GraphQLDocument # Necessary for static type checking if False: # flake8: noqa from typing import Any, Optional, Union from ..language.ast import Document from ..type.schema import GraphQLSchema from rx import Observable def execute_and_validate( schema, # type: GraphQLSchema document_ast, # type: Document *args, # type: Any **kwargs # type: Any ): # type: (...) -> Union[ExecutionResult, Observable] do_validation = kwargs.get("validate", True) if do_validation: validation_errors = validate(schema, document_ast) if validation_errors: return ExecutionResult(errors=validation_errors, invalid=True) return execute(schema, document_ast, *args, **kwargs) class GraphQLCoreBackend(GraphQLBackend): """GraphQLCoreBackend will return a document using the default graphql executor""" def __init__(self, executor=None): # type: (Optional[Any]) -> None self.execute_params = {"executor": executor} def document_from_string(self, schema, document_string): # type: (GraphQLSchema, Union[Document, str]) -> GraphQLDocument if isinstance(document_string, ast.Document): document_ast = document_string document_string = print_ast(document_ast) else: assert isinstance( document_string, string_types ), "The query must be a string" document_ast = parse(document_string) return GraphQLDocument( schema=schema, document_string=document_string, document_ast=document_ast, execute=partial( execute_and_validate, schema, document_ast, **self.execute_params ), ) graphql-core-legacy-2.3.2/graphql/backend/decider.py000066400000000000000000000160151365661746200223650ustar00rootroot00000000000000import atexit import logging import threading import os from time import sleep, time from ..pyutils.compat import Queue, check_threads from .base import GraphQLBackend, GraphQLDocument from .cache import GraphQLCachedBackend # Necessary for static type checking if False: # flake8: noqa from typing import List, Union, Optional, Hashable, Dict, Tuple, Type from ..type.schema import GraphQLSchema DEFAULT_TIMEOUT = 10 logger = logging.getLogger("graphql.errors") # Code shamelessly taken from # https://github.com/getsentry/raven-python/blob/master/raven/transport/threaded.py # Why to create when we can take something that works? # Attributions to the Sentry team :) class AsyncWorker(object): _terminator = object() def __init__(self, shutdown_timeout=DEFAULT_TIMEOUT): check_threads() self._queue = Queue(-1) self._lock = threading.Lock() self._thread = None self._thread_for_pid = None self.options = {"shutdown_timeout": shutdown_timeout} self.start() def is_alive(self): if self._thread_for_pid != os.getpid(): return False return self._thread and self._thread.is_alive() def _ensure_thread(self): if self.is_alive(): return self.start() def main_thread_terminated(self): with self._lock: if not self.is_alive(): # thread not started or already stopped - nothing to do return # wake the processing thread up self._queue.put_nowait(self._terminator) timeout = self.options["shutdown_timeout"] # wait briefly, initially initial_timeout = min(0.1, timeout) if not self._timed_queue_join(initial_timeout): # if that didn't work, wait a bit longer # NB that size is an approximation, because other threads may # add or remove items size = self._queue.qsize() print("GraphQL is attempting to retrieve %i pending documents" % size) print("Waiting up to %s seconds" % timeout) if os.name == "nt": print("Press Ctrl-Break to quit") else: print("Press Ctrl-C to quit") self._timed_queue_join(timeout - initial_timeout) self._thread = None def _timed_queue_join(self, timeout): """ implementation of Queue.join which takes a 'timeout' argument returns true on success, false on timeout """ deadline = time() + timeout queue = self._queue queue.all_tasks_done.acquire() try: while queue.unfinished_tasks: delay = deadline - time() if delay <= 0: # timed out return False queue.all_tasks_done.wait(timeout=delay) return True finally: queue.all_tasks_done.release() def start(self): """ Starts the task thread. """ self._lock.acquire() try: if not self.is_alive(): self._thread = threading.Thread( target=self._target, name="graphql.AsyncWorker" ) self._thread.setDaemon(True) self._thread.start() self._thread_for_pid = os.getpid() finally: self._lock.release() atexit.register(self.main_thread_terminated) def stop(self, timeout=None): """ Stops the task thread. Synchronous! """ with self._lock: if self._thread: self._queue.put_nowait(self._terminator) self._thread.join(timeout=timeout) self._thread = None self._thread_for_pid = None def queue(self, callback, *args, **kwargs): self._ensure_thread() self._queue.put_nowait((callback, args, kwargs)) def _target(self): while True: record = self._queue.get() try: if record is self._terminator: break callback, args, kwargs = record try: callback(*args, **kwargs) except Exception: logger.error("Failed processing job", exc_info=True) finally: self._queue.task_done() sleep(0) class GraphQLDeciderBackend(GraphQLCachedBackend): """GraphQLDeciderBackend will offload the document generation to the main backend in a new thread, serving meanwhile the document from the fallback backend""" _worker = None fallback_backend = None # type: GraphQLBackend # _in_queue = object() def __init__( self, backend, # type: Union[List[GraphQLBackend], Tuple[GraphQLBackend, GraphQLBackend], GraphQLBackend] fallback_backend=None, # type: Optional[GraphQLBackend] cache_map=None, # type: Optional[Dict[Hashable, GraphQLDocument]] use_consistent_hash=False, # type: bool worker_class=AsyncWorker, # type: Type[AsyncWorker] ): # type: (...) -> None if not backend: raise Exception("Need to provide backends to decide into.") if isinstance(backend, (list, tuple)): if fallback_backend: raise Exception("Can't set a fallback backend and backends as array") if len(backend) != 2: raise Exception("Only two backends are supported for now") backend, fallback_backend = backend[0], backend[1] # type: ignore else: if not fallback_backend: raise Exception("Need to provide a fallback backend") self.fallback_backend = fallback_backend # type: ignore self.worker_class = worker_class super(GraphQLDeciderBackend, self).__init__( backend, cache_map=cache_map, use_consistent_hash=use_consistent_hash ) def queue_backend(self, key, schema, request_string): # type: (Hashable, GraphQLSchema, str) -> None self.cache_map[key] = self.backend.document_from_string(schema, request_string) def get_worker(self): # type: () -> AsyncWorker if self._worker is None or not self._worker.is_alive(): self._worker = self.worker_class() return self._worker def document_from_string(self, schema, request_string): # type: (GraphQLSchema, str) -> GraphQLDocument """This method returns a GraphQLQuery (from cache if present)""" key = self.get_key_for_schema_and_document_string(schema, request_string) if key not in self.cache_map: # We return from the fallback self.cache_map[key] = self.fallback_backend.document_from_string( schema, request_string ) # We ensure the main backend response is in the queue self.get_worker().queue(self.queue_backend, key, schema, request_string) return self.cache_map[key] graphql-core-legacy-2.3.2/graphql/backend/quiver_cloud.py000066400000000000000000000064231365661746200234710ustar00rootroot00000000000000try: import requests except ImportError: raise ImportError( "requests package is required for Quiver Cloud backend.\n" "You can install it using: pip install requests" ) from six.moves.urllib.parse import urlparse from ..utils.schema_printer import print_schema from .base import GraphQLBackend from .compiled import GraphQLCompiledDocument GRAPHQL_QUERY = """ mutation($schemaDsl: String!, $query: String!, $pythonOptions: PythonOptions) { generateCode( schemaDsl: $schemaDsl query: $query, language: PYTHON, pythonOptions: $pythonOptions ) { code compilationTime errors { type } } } """ class GraphQLQuiverCloudBackend(GraphQLBackend): def __init__(self, dsn, python_options=None, **options): super(GraphQLQuiverCloudBackend, self).__init__(**options) try: url = urlparse(dsn.strip()) except Exception: raise Exception("Received wrong url {}".format(dsn)) netloc = url.hostname if url.port: netloc += ":%s" % url.port path_bits = url.path.rsplit("/", 1) if len(path_bits) > 1: path = path_bits[0] else: path = "" self.api_url = "{}://{}{}".format(url.scheme.rsplit("+", 1)[-1], netloc, path) self.public_key = url.username self.secret_key = url.password self.extra_namespace = {} if python_options is None: python_options = {"asyncFramework": "PROMISE"} wait_for_promises = python_options.pop("wait_for_promises", None) if wait_for_promises: assert callable(wait_for_promises), "wait_for_promises must be callable." self.extra_namespace["wait_for_promises"] = wait_for_promises self.python_options = python_options def make_post_request(self, url, auth, json_payload): """This function executes the request with the provided json payload and return the json response""" response = requests.post(url, auth=auth, json=json_payload) return response.json() def generate_source(self, schema, query): variables = { "schemaDsl": print_schema(schema), "query": query, "pythonOptions": self.python_options, } json_response = self.make_post_request( "{}/graphql".format(self.api_url), auth=(self.public_key, self.secret_key), json_payload={"query": GRAPHQL_QUERY, "variables": variables}, ) errors = json_response.get("errors") if errors: raise Exception(errors[0].get("message")) data = json_response.get("data", {}) code_generation = data.get("generateCode", {}) code = code_generation.get("code") if not code: raise Exception("Cant get the code. Received json from Quiver Cloud") code = str(code) return code def document_from_string(self, schema, request_string): source = self.generate_source(schema, request_string) filename = "" code = compile(source, filename, "exec") def uptodate(): return True document = GraphQLCompiledDocument.from_code( schema, code, uptodate, self.extra_namespace ) return document graphql-core-legacy-2.3.2/graphql/backend/tests/000077500000000000000000000000001365661746200215535ustar00rootroot00000000000000graphql-core-legacy-2.3.2/graphql/backend/tests/__init__.py000066400000000000000000000000001365661746200236520ustar00rootroot00000000000000graphql-core-legacy-2.3.2/graphql/backend/tests/schema.py000066400000000000000000000003561365661746200233710ustar00rootroot00000000000000from graphql.type import GraphQLField, GraphQLObjectType, GraphQLSchema, GraphQLString Query = GraphQLObjectType( "Query", lambda: {"hello": GraphQLField(GraphQLString, resolver=lambda *_: "World")} ) schema = GraphQLSchema(Query) graphql-core-legacy-2.3.2/graphql/backend/tests/test_base.py000066400000000000000000000015471365661746200241050ustar00rootroot00000000000000import pytest from .. import get_default_backend, set_default_backend, GraphQLCoreBackend def test_get_default_backend_returns_core_by_default(): # type: () -> None backend = get_default_backend() assert isinstance(backend, GraphQLCoreBackend) def test_set_default_backend(): # type: () -> None default_backend = get_default_backend() new_backend = GraphQLCoreBackend() assert new_backend != default_backend set_default_backend(new_backend) assert get_default_backend() == new_backend def test_set_default_backend_fails_if_invalid_backend(): # type: () -> None default_backend = get_default_backend() with pytest.raises(Exception) as exc_info: set_default_backend(object()) assert str(exc_info.value) == "backend must be an instance of GraphQLBackend." assert get_default_backend() == default_backend graphql-core-legacy-2.3.2/graphql/backend/tests/test_cache.py000066400000000000000000000016431365661746200242330ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- """Tests for `graphql.backend.cache` module.""" import pytest from ..core import GraphQLCoreBackend from ..cache import GraphQLCachedBackend from graphql.execution.executors.sync import SyncExecutor from .schema import schema def test_cached_backend(): # type: () -> None cached_backend = GraphQLCachedBackend(GraphQLCoreBackend()) document1 = cached_backend.document_from_string(schema, "{ hello }") document2 = cached_backend.document_from_string(schema, "{ hello }") assert document1 == document2 def test_cached_backend_with_use_consistent_hash(): # type: () -> None cached_backend = GraphQLCachedBackend( GraphQLCoreBackend(), use_consistent_hash=True ) document1 = cached_backend.document_from_string(schema, "{ hello }") document2 = cached_backend.document_from_string(schema, "{ hello }") assert document1 == document2 graphql-core-legacy-2.3.2/graphql/backend/tests/test_compileddocument.py000066400000000000000000000032341365661746200265210ustar00rootroot00000000000000from ...language.base import parse from ...utils.ast_to_code import ast_to_code from ..compiled import GraphQLCompiledDocument from .schema import schema def test_compileddocument_from_module_dict(): # type: () -> None document_string = "{ hello }" document_ast = parse(document_string) document = GraphQLCompiledDocument.from_module_dict( schema, { "document_string": document_string, "document_ast": document_ast, "execute": lambda *_: True, }, ) assert document.operations_map == {None: "query"} assert document.document_string == document_string assert document.document_ast == document_ast assert document.schema == schema assert document.execute() def test_compileddocument_from_code(): # type: () -> None document_string = "{ hello }" document_ast = parse(document_string) code = ''' # -*- coding: utf-8 -*- from __future__ import unicode_literals from graphql.language import ast from graphql.language.parser import Loc from graphql.language.source import Source schema = None document_string = """{document_string}""" source = Source(document_string) def loc(start, end): return Loc(start, end, source) document_ast = {document_ast} def execute(*_): return True '''.format( document_string=document_string, document_ast=ast_to_code(document_ast) ) document = GraphQLCompiledDocument.from_code(schema, code) assert document.operations_map == {None: "query"} assert document.document_string == document_string assert document.document_ast == document_ast assert document.schema == schema assert document.execute() graphql-core-legacy-2.3.2/graphql/backend/tests/test_core.py000066400000000000000000000032271365661746200241200ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- """Tests for `graphql.backend.core` module.""" import pytest from graphql.execution.executors.sync import SyncExecutor from ..base import GraphQLBackend, GraphQLDocument from ..core import GraphQLCoreBackend from .schema import schema if False: from typing import Any def test_core_backend(): # type: () -> None """Sample pytest test function with the pytest fixture as an argument.""" backend = GraphQLCoreBackend() assert isinstance(backend, GraphQLBackend) document = backend.document_from_string(schema, "{ hello }") assert isinstance(document, GraphQLDocument) result = document.execute() assert not result.errors assert result.data == {"hello": "World"} def test_backend_is_not_cached_by_default(): # type: () -> None """Sample pytest test function with the pytest fixture as an argument.""" backend = GraphQLCoreBackend() document1 = backend.document_from_string(schema, "{ hello }") document2 = backend.document_from_string(schema, "{ hello }") assert document1 != document2 class BaseExecutor(SyncExecutor): executed = False def execute(self, *args, **kwargs): # type: (*Any, **Any) -> str self.executed = True return super(BaseExecutor, self).execute(*args, **kwargs) def test_backend_can_execute_custom_executor(): # type: () -> None executor = BaseExecutor() backend = GraphQLCoreBackend(executor=executor) document1 = backend.document_from_string(schema, "{ hello }") result = document1.execute() assert not result.errors assert result.data == {"hello": "World"} assert executor.executed graphql-core-legacy-2.3.2/graphql/backend/tests/test_decider.py000066400000000000000000000070621365661746200245700ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- """Tests for `graphql.backend.decider` module.""" import pytest from threading import Event from ..base import GraphQLBackend, GraphQLDocument from ..core import GraphQLCoreBackend from ..cache import GraphQLCachedBackend from ..decider import GraphQLDeciderBackend from .schema import schema if False: from typing import Any from time import sleep class FakeBackend(GraphQLBackend): def __init__(self, name, raises=False): # type: (str, bool) -> None self.raises = raises self.name = name self.event = Event() @property def reached(self): return self.event.is_set() def document_from_string(self, *args, **kwargs): # type: (*Any, **Any) -> str self.event.set() if self.raises: raise Exception("Backend failed") return self.name def wait(self): return self.event.wait() def reset(self): # type: () -> None self.event = Event() def test_decider_backend_healthy_backend(): # type: () -> None backend1 = FakeBackend(name="main") backend2 = FakeBackend(name="fallback") decider_backend = GraphQLDeciderBackend(backend1, backend2) document = decider_backend.document_from_string(schema, "{ hello }") # assert not backend1.reached # this is flaky (race condition) assert backend2.reached assert document == "fallback" backend1.wait() backend1.reset() backend2.reset() document = decider_backend.document_from_string(schema, "{ hello }") assert not backend1.reached assert not backend2.reached assert document == "main" def test_decider_backend_unhealthy_backend(): # type: () -> None backend1 = FakeBackend(name="main", raises=True) backend2 = FakeBackend(name="fallback") decider_backend = GraphQLDeciderBackend(backend1, backend2) document = decider_backend.document_from_string(schema, "{ hello }") # assert not backend1.reached # this is flaky (race condition) assert backend2.reached assert document == "fallback" backend1.wait() backend1.reset() backend2.reset() document = decider_backend.document_from_string(schema, "{ hello }") assert not backend1.reached assert not backend2.reached assert document == "fallback" def test_decider_old_syntax(): # type: () -> None backend1 = FakeBackend(name="main", raises=True) backend2 = FakeBackend(name="fallback") decider_backend = GraphQLDeciderBackend([backend1, backend2]) assert decider_backend.backend is backend1 assert decider_backend.fallback_backend is backend2 # def test_decider_backend_dont_use_cache(): # # type: () -> None # backend1 = FakeBackend() # backend2 = FakeBackend() # decider_backend = GraphQLDeciderBackend([backend1, backend2]) # decider_backend.document_from_string(schema, "{ hello }") # assert backend1.reached # assert not backend2.reached # backend1.reset() # decider_backend.document_from_string(schema, "{ hello }") # assert backend1.reached # def test_decider_backend_use_cache_if_provided(): # # type: () -> None # backend1 = FakeBackend() # backend2 = FakeBackend() # decider_backend = GraphQLDeciderBackend( # [GraphQLCachedBackend(backend1), GraphQLCachedBackend(backend2)] # ) # decider_backend.document_from_string(schema, "{ hello }") # assert backend1.reached # assert not backend2.reached # backend1.reset() # decider_backend.document_from_string(schema, "{ hello }") # assert not backend1.reached graphql-core-legacy-2.3.2/graphql/backend/tests/test_document.py000066400000000000000000000043021365661746200250010ustar00rootroot00000000000000from ...language.base import parse from ..base import GraphQLDocument from .schema import schema from graphql.backend.base import GraphQLDocument def create_document(document_string): # type: (str) -> GraphQLDocument document_ast = parse(document_string) return GraphQLDocument( schema=schema, document_string=document_string, document_ast=document_ast, execute=lambda *_: None, ) def test_document_operations_map_unnamed_operation(): # type: () -> None document = create_document("{ hello }") assert document.operations_map == {None: "query"} def test_document_operations_map_multiple_queries(): document = create_document( """ query MyQuery1 { hello } query MyQuery2 { hello } """ ) assert document.operations_map == {"MyQuery1": "query", "MyQuery2": "query"} def test_document_operations_map_multiple_queries(): # type: () -> None document = create_document( """ query MyQuery { hello } mutation MyMutation { hello } subscription MySubscription { hello } """ ) assert document.operations_map == { "MyQuery": "query", "MyMutation": "mutation", "MySubscription": "subscription", } def test_document_get_operation_type_unnamed_operation(): # type: () -> None document = create_document( """ query { hello } """ ) assert document.get_operation_type(None) == "query" assert document.get_operation_type("Unknown") is None def test_document_get_operation_type_multiple_operations(): # type: () -> None document = create_document( """ query MyQuery { hello } mutation MyMutation {hello} """ ) assert document.get_operation_type(None) is None assert document.get_operation_type("MyQuery") == "query" assert document.get_operation_type("MyMutation") == "mutation" assert document.get_operation_type("Unexistent") is None def test_document_get_operation_type_multiple_operations_empty_operation_name(): # type: () -> None document = create_document( """ query MyQuery { hello } mutation {hello} """ ) assert document.get_operation_type(None) == "mutation" graphql-core-legacy-2.3.2/graphql/error/000077500000000000000000000000001365661746200201535ustar00rootroot00000000000000graphql-core-legacy-2.3.2/graphql/error/__init__.py000066400000000000000000000003731365661746200222670ustar00rootroot00000000000000from .base import GraphQLError from .located_error import GraphQLLocatedError from .syntax_error import GraphQLSyntaxError from .format_error import format_error __all__ = ["GraphQLError", "GraphQLLocatedError", "GraphQLSyntaxError", "format_error"] graphql-core-legacy-2.3.2/graphql/error/base.py000066400000000000000000000045461365661746200214500ustar00rootroot00000000000000import six from ..language.location import get_location # Necessary for static type checking if False: # flake8: noqa from ..language.source import Source from ..language.location import SourceLocation from types import TracebackType from typing import Dict, Optional, List, Any, Union class GraphQLError(Exception): __slots__ = ( "message", "nodes", "stack", "original_error", "_source", "_positions", "_locations", "path", "extensions", ) def __init__( self, message, # type: str nodes=None, # type: Any stack=None, # type: Optional[TracebackType] source=None, # type: Optional[Any] positions=None, # type: Optional[Any] locations=None, # type: Optional[Any] path=None, # type: Union[List[Union[int, str]], List[str], None] extensions=None, # type: Optional[Dict[str, Any]] ): # type: (...) -> None super(GraphQLError, self).__init__(message) self.message = message self.nodes = nodes self.stack = stack self._source = source self._positions = positions self._locations = locations self.path = path self.extensions = extensions @property def source(self): # type: () -> Optional[Source] if self._source: return self._source if self.nodes: node = self.nodes[0] return node and node.loc and node.loc.source return None @property def positions(self): # type: () -> Optional[List[int]] if self._positions: return self._positions if self.nodes is not None: node_positions = [node.loc and node.loc.start for node in self.nodes] if any(node_positions): return node_positions return None def reraise(self): # type: () -> None if self.stack: six.reraise(type(self), self, self.stack) else: raise self @property def locations(self): # type: () -> Optional[List[SourceLocation]] if not self._locations: source = self.source if self.positions and source: self._locations = [get_location(source, pos) for pos in self.positions] return self._locations graphql-core-legacy-2.3.2/graphql/error/format_error.py000066400000000000000000000016031365661746200232260ustar00rootroot00000000000000from .base import GraphQLError # Necessary for static type checking if False: # flake8: noqa from typing import Any, Dict def format_error(error): # type: (Exception) -> Dict[str, Any] # Protect against UnicodeEncodeError when run in py2 (#216) try: message = str(error) except UnicodeEncodeError: message = error.message.encode("utf-8") # type: ignore formatted_error = {"message": message} # type: Dict[str, Any] if isinstance(error, GraphQLError): if error.locations is not None: formatted_error["locations"] = [ {"line": loc.line, "column": loc.column} for loc in error.locations ] if error.path is not None: formatted_error["path"] = error.path if error.extensions is not None: formatted_error["extensions"] = error.extensions return formatted_error graphql-core-legacy-2.3.2/graphql/error/located_error.py000066400000000000000000000025401365661746200233520ustar00rootroot00000000000000import sys from .base import GraphQLError # Necessary for static type checking if False: # flake8: noqa from ..language.ast import Field from typing import List, Union __all__ = ["GraphQLLocatedError"] class GraphQLLocatedError(GraphQLError): def __init__( self, nodes, # type: List[Field] original_error=None, # type: Exception path=None, # type: Union[List[Union[int, str]], List[str]] ): # type: (...) -> None if original_error: try: message = str(original_error) except UnicodeEncodeError: message = original_error.message.encode("utf-8") # type: ignore else: message = "An unknown error occurred." stack = ( original_error and ( getattr(original_error, "stack", None) # unfortunately, this is only available in Python 3: or getattr(original_error, "__traceback__", None) ) or sys.exc_info()[2] ) extensions = ( getattr(original_error, "extensions", None) if original_error else None ) super(GraphQLLocatedError, self).__init__( message=message, nodes=nodes, stack=stack, path=path, extensions=extensions ) self.original_error = original_error graphql-core-legacy-2.3.2/graphql/error/syntax_error.py000066400000000000000000000026011365661746200232630ustar00rootroot00000000000000from ..language.location import get_location from .base import GraphQLError # Necessary for static type checking if False: # flake8: noqa from ..language.source import Source from ..language.location import SourceLocation __all__ = ["GraphQLSyntaxError"] class GraphQLSyntaxError(GraphQLError): def __init__(self, source, position, description): # type: (Source, int, str) -> None location = get_location(source, position) super(GraphQLSyntaxError, self).__init__( message=u"Syntax Error {} ({}:{}) {}\n\n{}".format( source.name, location.line, location.column, description, highlight_source_at_location(source, location), ), source=source, positions=[position], ) def highlight_source_at_location(source, location): # type: (Source, SourceLocation) -> str line = location.line lines = source.body.splitlines() pad_len = len(str(line + 1)) result = u"" format = (u"{:>" + str(pad_len) + "}: {}\n").format if line >= 2: result += format(line - 1, lines[line - 2]) if line <= len(lines): result += format(line, lines[line - 1]) result += " " * (1 + pad_len + location.column) + "^\n" if line < len(lines): result += format(line + 1, lines[line]) return result graphql-core-legacy-2.3.2/graphql/error/tests/000077500000000000000000000000001365661746200213155ustar00rootroot00000000000000graphql-core-legacy-2.3.2/graphql/error/tests/__init__.py000066400000000000000000000000001365661746200234140ustar00rootroot00000000000000graphql-core-legacy-2.3.2/graphql/error/tests/test_base.py000066400000000000000000000055531365661746200236500ustar00rootroot00000000000000import sys import pytest import traceback from promise import Promise from graphql.execution import execute from graphql.language.parser import parse from graphql.type import GraphQLField, GraphQLObjectType, GraphQLSchema, GraphQLString # Necessary for static type checking if False: # flake8: noqa from graphql.execution.base import ResolveInfo from typing import Any from typing import Optional def test_raise(): # type: () -> None ast = parse("query Example { a }") def resolver(context, *_): # type: (Optional[Any], *ResolveInfo) -> None raise Exception("Failed") Type = GraphQLObjectType( "Type", {"a": GraphQLField(GraphQLString, resolver=resolver)} ) result = execute(GraphQLSchema(Type), ast) assert str(result.errors[0]) == "Failed" def test_reraise(): # type: () -> None ast = parse("query Example { a }") def resolver(context, *_): # type: (Optional[Any], *ResolveInfo) -> None raise Exception("Failed") Type = GraphQLObjectType( "Type", {"a": GraphQLField(GraphQLString, resolver=resolver)} ) result = execute(GraphQLSchema(Type), ast) with pytest.raises(Exception) as exc_info: result.errors[0].reraise() extracted = traceback.extract_tb(exc_info.tb) formatted_tb = [row[2:] for row in extracted] formatted_tb = [tb for tb in formatted_tb if tb[0] != "reraise"] assert formatted_tb == [ ("test_reraise", "result.errors[0].reraise()"), ( "resolve_or_error", "return executor.execute(resolve_fn, source, info, **args)", ), ("execute", "return fn(*args, **kwargs)"), ("resolver", 'raise Exception("Failed")'), ] assert str(exc_info.value) == "Failed" @pytest.mark.skipif(sys.version_info < (3,), reason="this works only with Python 3") def test_reraise_from_promise(): # type: () -> None ast = parse("query Example { a }") def fail(): raise Exception("Failed") def resolver(context, *_): # type: (Optional[Any], *ResolveInfo) -> None return Promise(lambda resolve, reject: resolve(fail())) Type = GraphQLObjectType( "Type", {"a": GraphQLField(GraphQLString, resolver=resolver)} ) result = execute(GraphQLSchema(Type), ast) with pytest.raises(Exception) as exc_info: result.errors[0].reraise() extracted = traceback.extract_tb(exc_info.tb) formatted_tb = [row[2:] for row in extracted] formatted_tb = [tb for tb in formatted_tb if tb[0] != "reraise"] assert formatted_tb == [ ("test_reraise_from_promise", "result.errors[0].reraise()"), ("_resolve_from_executor", "executor(resolve, reject)"), ("", "return Promise(lambda resolve, reject: resolve(fail()))"), ("fail", 'raise Exception("Failed")'), ] assert str(exc_info.value) == "Failed" graphql-core-legacy-2.3.2/graphql/execution/000077500000000000000000000000001365661746200210255ustar00rootroot00000000000000graphql-core-legacy-2.3.2/graphql/execution/__init__.py000066400000000000000000000014421365661746200231370ustar00rootroot00000000000000# -*- coding: utf-8 -*- """ 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 statements 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 }" """ from .executor import execute, subscribe from .base import ExecutionResult, ResolveInfo from .middleware import middlewares, MiddlewareManager __all__ = [ "execute", "subscribe", "ExecutionResult", "ResolveInfo", "MiddlewareManager", "middlewares", ] graphql-core-legacy-2.3.2/graphql/execution/base.py000066400000000000000000000072431365661746200223170ustar00rootroot00000000000000# We keep the following imports to preserve compatibility from .utils import ( ExecutionContext, SubscriberExecutionContext, get_operation_root_type, collect_fields, should_include_node, does_fragment_condition_match, get_field_entry_key, default_resolve_fn, get_field_def, ) from ..pyutils.ordereddict import OrderedDict from ..error.format_error import format_error as default_format_error # Necessary for static type checking if False: # flake8: noqa from typing import Any, Optional, Dict, List, Union, Callable, Type from ..language.ast import Field, OperationDefinition from ..type.definition import GraphQLList, GraphQLObjectType, GraphQLScalarType from ..type.schema import GraphQLSchema class ExecutionResult(object): """The result of execution. `data` is the result of executing the query, `errors` is null if no errors occurred, and is a non-empty array if an error occurred.""" __slots__ = "data", "errors", "invalid", "extensions" def __init__(self, data=None, errors=None, invalid=False, extensions=None): # type: (Optional[Dict], Optional[List[Exception]], bool, Optional[Any]) -> None self.data = data self.errors = errors self.extensions = extensions or dict() if invalid: assert data is None self.invalid = invalid def __eq__(self, other): # type: (Any) -> bool return self is other or ( isinstance(other, ExecutionResult) and self.data == other.data and self.errors == other.errors and self.invalid == other.invalid ) def __str__(self): return str(self.to_dict()) def to_dict(self, format_error=None, dict_class=OrderedDict): # type: (Optional[Callable[[Exception], Dict]], Type[Dict]) -> Dict[str, Any] if format_error is None: format_error = default_format_error response = dict_class() if self.errors: response["errors"] = [format_error(e) for e in self.errors] if not self.invalid: response["data"] = self.data return response class ResolveInfo(object): __slots__ = ( "field_name", "field_asts", "return_type", "parent_type", "schema", "fragments", "root_value", "operation", "variable_values", "context", "path", ) def __init__( self, field_name, # type: str field_asts, # type: List[Field] return_type, # type: Union[GraphQLList, GraphQLObjectType, GraphQLScalarType] parent_type, # type: GraphQLObjectType schema, # type: GraphQLSchema fragments, # type: Dict root_value, # type: Optional[type] operation, # type: OperationDefinition variable_values, # type: Dict context, # type: Optional[Any] path=None, # type: Union[List[Union[int, str]], List[str]] ): # type: (...) -> None self.field_name = field_name self.field_asts = field_asts self.return_type = return_type self.parent_type = parent_type self.schema = schema self.fragments = fragments self.root_value = root_value self.operation = operation self.variable_values = variable_values self.context = context self.path = path __all__ = [ "ExecutionResult", "ResolveInfo", "ExecutionContext", "SubscriberExecutionContext", "get_operation_root_type", "collect_fields", "should_include_node", "does_fragment_condition_match", "get_field_entry_key", "default_resolve_fn", "get_field_def", ] graphql-core-legacy-2.3.2/graphql/execution/executor.py000066400000000000000000000572741365661746200232540ustar00rootroot00000000000000import collections try: from collections.abc import Iterable except ImportError: # Python < 3.3 from collections import Iterable import functools import logging import sys import warnings from rx import Observable from six import string_types from promise import Promise, promise_for_dict, is_thenable from ..error import GraphQLError, GraphQLLocatedError from ..pyutils.default_ordered_dict import DefaultOrderedDict from ..pyutils.ordereddict import OrderedDict from ..utils.undefined import Undefined from ..type import ( GraphQLEnumType, GraphQLInterfaceType, GraphQLList, GraphQLNonNull, GraphQLObjectType, GraphQLScalarType, GraphQLSchema, GraphQLUnionType, ) from .base import ( ExecutionContext, ExecutionResult, ResolveInfo, collect_fields, default_resolve_fn, get_field_def, get_operation_root_type, SubscriberExecutionContext, ) from .executors.sync import SyncExecutor from .middleware import MiddlewareManager # Necessary for static type checking if False: # flake8: noqa from typing import Any, Optional, Union, Dict, List, Callable from ..language.ast import Document, OperationDefinition, Field logger = logging.getLogger(__name__) def subscribe(*args, **kwargs): # type: (*Any, **Any) -> Union[ExecutionResult, Observable] allow_subscriptions = kwargs.pop("allow_subscriptions", True) return execute( # type: ignore *args, allow_subscriptions=allow_subscriptions, **kwargs ) def execute( schema, # type: GraphQLSchema document_ast, # type: Document root_value=None, # type: Any context_value=None, # type: Optional[Any] variable_values=None, # type: Optional[Any] operation_name=None, # type: Optional[str] executor=None, # type: Any return_promise=False, # type: bool middleware=None, # type: Optional[Any] allow_subscriptions=False, # type: bool **options # type: Any ): # type: (...) -> Union[ExecutionResult, Promise[ExecutionResult]] if root_value is None and "root" in options: warnings.warn( "The 'root' alias has been deprecated. Please use 'root_value' instead.", category=DeprecationWarning, stacklevel=2, ) root_value = options["root"] if context_value is None and "context" in options: warnings.warn( "The 'context' alias has been deprecated. Please use 'context_value' instead.", category=DeprecationWarning, stacklevel=2, ) context_value = options["context"] if variable_values is None and "variables" in options: warnings.warn( "The 'variables' alias has been deprecated. Please use 'variable_values' instead.", category=DeprecationWarning, stacklevel=2, ) variable_values = options["variables"] assert schema, "Must provide schema" assert isinstance(schema, GraphQLSchema), ( "Schema must be an instance of GraphQLSchema. Also ensure that there are " + "not multiple versions of GraphQL installed in your node_modules directory." ) if middleware: if not isinstance(middleware, MiddlewareManager): middleware = MiddlewareManager(*middleware) assert isinstance(middleware, MiddlewareManager), ( "middlewares have to be an instance" ' of MiddlewareManager. Received "{}".'.format(middleware) ) if executor is None: executor = SyncExecutor() exe_context = ExecutionContext( schema, document_ast, root_value, context_value, variable_values or {}, operation_name, executor, middleware, allow_subscriptions, ) def promise_executor(v): # type: (Optional[Any]) -> Union[Dict, Promise[Dict], Observable] return execute_operation(exe_context, exe_context.operation, root_value) def on_rejected(error): # type: (Exception) -> None exe_context.errors.append(error) return None def on_resolve(data): # type: (Union[None, Dict, Observable]) -> Union[ExecutionResult, Observable] if isinstance(data, Observable): return data if not exe_context.errors: return ExecutionResult(data=data) return ExecutionResult(data=data, errors=exe_context.errors) promise = ( Promise.resolve(None).then(promise_executor).catch(on_rejected).then(on_resolve) ) if not return_promise: exe_context.executor.wait_until_finished() return promise.get() else: clean = getattr(exe_context.executor, "clean", None) if callable(clean): clean() return promise def execute_operation( exe_context, # type: ExecutionContext operation, # type: OperationDefinition root_value, # type: Any ): # type: (...) -> Union[Dict, Promise[Dict], Observable] type = get_operation_root_type(exe_context.schema, operation) fields = collect_fields( exe_context, type, operation.selection_set, DefaultOrderedDict(list), set() ) if operation.operation == "mutation": return execute_fields_serially(exe_context, type, root_value, [], fields) if operation.operation == "subscription": if not exe_context.allow_subscriptions: raise Exception( "Subscriptions are not allowed. " "You will need to either use the subscribe function " "or pass allow_subscriptions=True" ) return subscribe_fields(exe_context, type, root_value, fields) return execute_fields(exe_context, type, root_value, fields, [], None) def execute_fields_serially( exe_context, # type: ExecutionContext parent_type, # type: GraphQLObjectType source_value, # type: Any path, # type: List fields, # type: DefaultOrderedDict ): # type: (...) -> Promise def execute_field_callback(results, response_name): # type: (Dict, str) -> Union[Dict, Promise[Dict]] field_asts = fields[response_name] result = resolve_field( exe_context, parent_type, source_value, field_asts, None, path + [response_name], ) if result is Undefined: return results if is_thenable(result): def collect_result(resolved_result): # type: (Dict) -> Dict results[response_name] = resolved_result return results return result.then(collect_result, None) results[response_name] = result return results def execute_field(prev_promise, response_name): # type: (Promise, str) -> Promise return prev_promise.then( lambda results: execute_field_callback(results, response_name) ) return functools.reduce( execute_field, fields.keys(), Promise.resolve(collections.OrderedDict()) ) def execute_fields( exe_context, # type: ExecutionContext parent_type, # type: GraphQLObjectType source_value, # type: Any fields, # type: DefaultOrderedDict path, # type: List[Union[int, str]] info, # type: Optional[ResolveInfo] ): # type: (...) -> Union[Dict, Promise[Dict]] contains_promise = False final_results = OrderedDict() for response_name, field_asts in fields.items(): result = resolve_field( exe_context, parent_type, source_value, field_asts, info, path + [response_name], ) if result is Undefined: continue final_results[response_name] = result if is_thenable(result): contains_promise = True if not contains_promise: return final_results return promise_for_dict(final_results) def subscribe_fields( exe_context, # type: ExecutionContext parent_type, # type: GraphQLObjectType source_value, # type: Any fields, # type: DefaultOrderedDict only_first_field=True, # type: bool ): # type: (...) -> Observable subscriber_exe_context = SubscriberExecutionContext(exe_context) def on_error(error): subscriber_exe_context.report_error(error) def map_result(data): # type: (Dict[str, Any]) -> ExecutionResult if subscriber_exe_context.errors: res = ExecutionResult(data=data, errors=subscriber_exe_context.errors) else: res = ExecutionResult(data=data) subscriber_exe_context.reset() return res def catch_error(error): subscriber_exe_context.errors.append(error) return Observable.just(None) observables = [] # type: List[Observable] # TODO: Make sure this works with multiple fields (currently untested) # so we can remove the "only_first_field" argument. for response_name, field_asts in fields.items(): result = subscribe_field( subscriber_exe_context, parent_type, source_value, field_asts, [response_name], ) if result is Undefined: continue # Map observable results observable = result.catch_exception(catch_error).map( lambda data: map_result({response_name: data}) ) if only_first_field: return observable observables.append(observable) return Observable.merge(observables) def resolve_field( exe_context, # type: ExecutionContext parent_type, # type: GraphQLObjectType source, # type: Any field_asts, # type: List[Field] parent_info, # type: Optional[ResolveInfo] field_path, # type: List[Union[int, str]] ): # type: (...) -> Any field_ast = field_asts[0] field_name = field_ast.name.value field_def = get_field_def(exe_context.schema, parent_type, field_name) if not field_def: return Undefined return_type = field_def.type resolve_fn = field_def.resolver or default_resolve_fn # We wrap the resolve_fn from the middleware resolve_fn_middleware = exe_context.get_field_resolver(resolve_fn) # Build a dict of arguments from the field.arguments AST, using the variables scope to # fulfill any variable references. args = exe_context.get_argument_values(field_def, field_ast) # The resolve function's optional third argument is a context value that # is provided to every resolve function within an execution. It is commonly # used to represent an authenticated user, or request-specific caches. context = exe_context.context_value # The resolve function's optional third argument is a collection of # information about the current execution state. info = ResolveInfo( field_name, field_asts, return_type, parent_type, schema=exe_context.schema, fragments=exe_context.fragments, root_value=exe_context.root_value, operation=exe_context.operation, variable_values=exe_context.variable_values, context=context, path=field_path, ) executor = exe_context.executor result = resolve_or_error(resolve_fn_middleware, source, info, args, executor) return complete_value_catching_error( exe_context, return_type, field_asts, info, field_path, result ) def subscribe_field( exe_context, # type: SubscriberExecutionContext parent_type, # type: GraphQLObjectType source, # type: Any field_asts, # type: List[Field] path, # type: List[str] ): # type: (...) -> Observable field_ast = field_asts[0] field_name = field_ast.name.value field_def = get_field_def(exe_context.schema, parent_type, field_name) if not field_def: return Undefined return_type = field_def.type resolve_fn = field_def.resolver or default_resolve_fn # We wrap the resolve_fn from the middleware resolve_fn_middleware = exe_context.get_field_resolver(resolve_fn) # Build a dict of arguments from the field.arguments AST, using the variables scope to # fulfill any variable references. args = exe_context.get_argument_values(field_def, field_ast) # The resolve function's optional third argument is a context value that # is provided to every resolve function within an execution. It is commonly # used to represent an authenticated user, or request-specific caches. context = exe_context.context_value # The resolve function's optional third argument is a collection of # information about the current execution state. info = ResolveInfo( field_name, field_asts, return_type, parent_type, schema=exe_context.schema, fragments=exe_context.fragments, root_value=exe_context.root_value, operation=exe_context.operation, variable_values=exe_context.variable_values, context=context, path=path, ) executor = exe_context.executor result = resolve_or_error(resolve_fn_middleware, source, info, args, executor) if isinstance(result, Exception): raise result if not isinstance(result, Observable): raise GraphQLError( "Subscription must return Async Iterable or Observable. Received: {}".format( repr(result) ) ) return result.map( functools.partial( complete_value_catching_error, exe_context, return_type, field_asts, info, path, ) ) def resolve_or_error( resolve_fn, # type: Callable source, # type: Any info, # type: ResolveInfo args, # type: Dict executor, # type: Any ): # type: (...) -> Any try: return executor.execute(resolve_fn, source, info, **args) except Exception as e: logger.exception( "An error occurred while resolving field {}.{}".format( info.parent_type.name, info.field_name ) ) e.stack = sys.exc_info()[2] # type: ignore return e def complete_value_catching_error( exe_context, # type: ExecutionContext return_type, # type: Any field_asts, # type: List[Field] info, # type: ResolveInfo path, # type: List[Union[int, str]] result, # type: Any ): # type: (...) -> Any # If the field type is non-nullable, then it is resolved without any # protection from errors. if isinstance(return_type, GraphQLNonNull): return complete_value(exe_context, return_type, field_asts, info, path, result) # Otherwise, error protection is applied, logging the error and # resolving a null value for this field if one is encountered. try: completed = complete_value( exe_context, return_type, field_asts, info, path, result ) if is_thenable(completed): def handle_error(error): # type: (Union[GraphQLError, GraphQLLocatedError]) -> Optional[Any] traceback = completed._traceback # type: ignore exe_context.report_error(error, traceback) return None return completed.catch(handle_error) return completed except Exception as e: traceback = sys.exc_info()[2] exe_context.report_error(e, traceback) return None def complete_value( exe_context, # type: ExecutionContext return_type, # type: Any field_asts, # type: List[Field] info, # type: ResolveInfo path, # type: List[Union[int, str]] result, # type: Any ): # type: (...) -> Any """ Implements the instructions for completeValue as defined in the "Field entries" 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 field type is NonNull, complete for inner type, and throw field error # if result is null. if is_thenable(result): return Promise.resolve(result).then( lambda resolved: complete_value( exe_context, return_type, field_asts, info, path, resolved ), lambda error: Promise.rejected( # type: ignore GraphQLLocatedError( # type: ignore field_asts, original_error=error, path=path ) ), ) # print return_type, type(result) if isinstance(result, Exception): raise GraphQLLocatedError(field_asts, original_error=result, path=path) if isinstance(return_type, GraphQLNonNull): return complete_nonnull_value( exe_context, return_type, field_asts, info, path, result ) # If result is null-like, return null. if result is None: return None # If field type is List, complete each item in the list with the inner type if isinstance(return_type, GraphQLList): return complete_list_value( exe_context, return_type, field_asts, info, path, result ) # If field type is Scalar or Enum, serialize to a valid value, returning # null if coercion is not possible. if isinstance(return_type, (GraphQLScalarType, GraphQLEnumType)): return complete_leaf_value(return_type, path, result) if isinstance(return_type, (GraphQLInterfaceType, GraphQLUnionType)): return complete_abstract_value( exe_context, return_type, field_asts, info, path, result ) if isinstance(return_type, GraphQLObjectType): return complete_object_value( exe_context, return_type, field_asts, info, path, result ) assert False, u'Cannot complete value of unexpected type "{}".'.format(return_type) def complete_list_value( exe_context, # type: ExecutionContext return_type, # type: GraphQLList field_asts, # type: List[Field] info, # type: ResolveInfo path, # type: List[Union[int, str]] result, # type: Any ): # type: (...) -> List[Any] """ Complete a list value by completing each item in the list with the inner type """ assert isinstance(result, Iterable), ( "User Error: expected iterable, but did not find one " + "for field {}.{}." ).format(info.parent_type, info.field_name) item_type = return_type.of_type completed_results = [] contains_promise = False index = 0 for item in result: completed_item = complete_value_catching_error( exe_context, item_type, field_asts, info, path + [index], item ) if not contains_promise and is_thenable(completed_item): contains_promise = True completed_results.append(completed_item) index += 1 return ( Promise.all(completed_results) # type: ignore if contains_promise else completed_results ) def complete_leaf_value( return_type, # type: Union[GraphQLEnumType, GraphQLScalarType] path, # type: List[Union[int, str]] result, # type: Any ): # type: (...) -> Union[int, str, float, bool] """ Complete a Scalar or Enum by serializing to a valid value, returning null if serialization is not possible. """ assert hasattr(return_type, "serialize"), "Missing serialize method on type" serialized_result = return_type.serialize(result) if serialized_result is None: raise GraphQLError( ('Expected a value of type "{}" but ' + "received: {}").format( return_type, result ), path=path, ) return serialized_result def complete_abstract_value( exe_context, # type: ExecutionContext return_type, # type: Union[GraphQLInterfaceType, GraphQLUnionType] field_asts, # type: List[Field] info, # type: ResolveInfo path, # type: List[Union[int, str]] result, # type: Any ): # type: (...) -> Dict[str, Any] """ Complete an value of an abstract type by determining the runtime type of that value, then completing based on that type. """ runtime_type = None # type: Union[str, GraphQLObjectType, None] # Field type must be Object, Interface or Union and expect sub-selections. if isinstance(return_type, (GraphQLInterfaceType, GraphQLUnionType)): if return_type.resolve_type: runtime_type = return_type.resolve_type(result, info) else: runtime_type = get_default_resolve_type_fn(result, info, return_type) if isinstance(runtime_type, string_types): runtime_type = info.schema.get_type(runtime_type) # type: ignore if not isinstance(runtime_type, GraphQLObjectType): raise GraphQLError( ( "Abstract type {} must resolve to an Object type at runtime " + 'for field {}.{} with value "{}", received "{}".' ).format( return_type, info.parent_type, info.field_name, result, runtime_type ), field_asts, ) if not exe_context.schema.is_possible_type(return_type, runtime_type): raise GraphQLError( u'Runtime Object type "{}" is not a possible type for "{}".'.format( runtime_type, return_type ), field_asts, ) return complete_object_value( exe_context, runtime_type, field_asts, info, path, result ) def get_default_resolve_type_fn( value, # type: Any info, # type: ResolveInfo abstract_type, # type: Union[GraphQLInterfaceType, GraphQLUnionType] ): # type: (...) -> Optional[GraphQLObjectType] possible_types = info.schema.get_possible_types(abstract_type) for type in possible_types: if callable(type.is_type_of) and type.is_type_of(value, info): return type return None def complete_object_value( exe_context, # type: ExecutionContext return_type, # type: GraphQLObjectType field_asts, # type: List[Field] info, # type: ResolveInfo path, # type: List[Union[int, str]] result, # type: Any ): # type: (...) -> Dict[str, Any] """ Complete an Object value by evaluating all sub-selections. """ if return_type.is_type_of and not return_type.is_type_of(result, info): raise GraphQLError( u'Expected value of type "{}" but got: {}.'.format( return_type, type(result).__name__ ), field_asts, ) # Collect sub-fields to execute to complete this value. subfield_asts = exe_context.get_sub_fields(return_type, field_asts) return execute_fields( # type: ignore exe_context, return_type, result, subfield_asts, path, info ) def complete_nonnull_value( exe_context, # type: ExecutionContext return_type, # type: GraphQLNonNull field_asts, # type: List[Field] info, # type: ResolveInfo path, # type: List[Union[int, str]] result, # type: Any ): # type: (...) -> Any """ Complete a NonNull value by completing the inner type """ completed = complete_value( exe_context, return_type.of_type, field_asts, info, path, result ) if completed is None: raise GraphQLError( "Cannot return null for non-nullable field {}.{}.".format( info.parent_type, info.field_name ), field_asts, path=path, ) return completed graphql-core-legacy-2.3.2/graphql/execution/executors/000077500000000000000000000000001365661746200230465ustar00rootroot00000000000000graphql-core-legacy-2.3.2/graphql/execution/executors/__init__.py000066400000000000000000000000001365661746200251450ustar00rootroot00000000000000graphql-core-legacy-2.3.2/graphql/execution/executors/asyncio.py000066400000000000000000000047541365661746200250770ustar00rootroot00000000000000from __future__ import absolute_import from asyncio import Future, get_event_loop, iscoroutine, wait from promise import Promise # Necessary for static type checking if False: # flake8: noqa from asyncio import AbstractEventLoop from typing import Optional, Any, Callable, List try: from asyncio import ensure_future except ImportError: # ensure_future is only implemented in Python 3.4.4+ def ensure_future(coro_or_future, loop=None): # type: ignore """Wrap a coroutine or an awaitable in a future. If the argument is a Future, it is returned directly. """ if isinstance(coro_or_future, Future): if loop is not None and loop is not coro_or_future._loop: raise ValueError("loop argument must agree with Future") return coro_or_future elif iscoroutine(coro_or_future): if loop is None: loop = get_event_loop() task = loop.create_task(coro_or_future) if task._source_traceback: del task._source_traceback[-1] return task else: raise TypeError("A Future, a coroutine or an awaitable is required") try: from inspect import isasyncgen # type: ignore except Exception: def isasyncgen(object): # type: ignore False try: from .asyncio_utils import asyncgen_to_observable except Exception: def asyncgen_to_observable(asyncgen, loop=None): pass class AsyncioExecutor(object): def __init__(self, loop=None): # type: (Optional[AbstractEventLoop]) -> None if loop is None: loop = get_event_loop() self.loop = loop self.futures = [] # type: List[Future] def wait_until_finished(self): # type: () -> None # if there are futures to wait for while self.futures: # wait for the futures to finish futures = self.futures self.futures = [] self.loop.run_until_complete(wait(futures)) def clean(self): self.futures = [] def execute(self, fn, *args, **kwargs): # type: (Callable, *Any, **Any) -> Any result = fn(*args, **kwargs) if isinstance(result, Future) or iscoroutine(result): future = ensure_future(result, loop=self.loop) self.futures.append(future) return Promise.resolve(future) elif isasyncgen(result): return asyncgen_to_observable(result, loop=self.loop) return result graphql-core-legacy-2.3.2/graphql/execution/executors/asyncio_utils.py000066400000000000000000000013231365661746200263040ustar00rootroot00000000000000from asyncio import ensure_future, CancelledError from rx import AnonymousObservable def asyncgen_to_observable(asyncgen, loop=None): def emit(observer): task = ensure_future(iterate_asyncgen(asyncgen, observer), loop=loop) def dispose(): async def await_task(): await task task.cancel() ensure_future(await_task(), loop=loop) return dispose return AnonymousObservable(emit) async def iterate_asyncgen(asyncgen, observer): try: async for item in asyncgen: observer.on_next(item) observer.on_completed() except CancelledError: pass except Exception as e: observer.on_error(e) graphql-core-legacy-2.3.2/graphql/execution/executors/gevent.py000066400000000000000000000011451365661746200247110ustar00rootroot00000000000000from __future__ import absolute_import import gevent from promise import Promise from .utils import process class GeventExecutor(object): def __init__(self): self.jobs = [] def wait_until_finished(self): # gevent.joinall(self.jobs) while self.jobs: jobs = self.jobs self.jobs = [] [j.join() for j in jobs] def clean(self): self.jobs = [] def execute(self, fn, *args, **kwargs): promise = Promise() job = gevent.spawn(process, promise, fn, args, kwargs) self.jobs.append(job) return promise graphql-core-legacy-2.3.2/graphql/execution/executors/process.py000066400000000000000000000015711365661746200251020ustar00rootroot00000000000000from multiprocessing import Process, Queue from promise import Promise from .utils import process def queue_process(q): promise, fn, args, kwargs = q.get() process(promise, fn, args, kwargs) class ProcessExecutor(object): def __init__(self): self.processes = [] self.q = Queue() def wait_until_finished(self): while self.processes: processes = self.processes self.processes = [] [_process.join() for _process in processes] self.q.close() self.q.join_thread() def clean(self): self.processes = [] def execute(self, fn, *args, **kwargs): promise = Promise() self.q.put([promise, fn, args, kwargs], False) _process = Process(target=queue_process, args=(self.q)) _process.start() self.processes.append(_process) return promise graphql-core-legacy-2.3.2/graphql/execution/executors/sync.py000066400000000000000000000005571365661746200244030ustar00rootroot00000000000000# Necessary for static type checking if False: # flake8: noqa from typing import Any, Callable class SyncExecutor(object): def wait_until_finished(self): # type: () -> None pass def clean(self): pass def execute(self, fn, *args, **kwargs): # type: (Callable, *Any, **Any) -> Any return fn(*args, **kwargs) graphql-core-legacy-2.3.2/graphql/execution/executors/thread.py000066400000000000000000000025001365661746200246640ustar00rootroot00000000000000from multiprocessing.pool import ThreadPool from threading import Thread from promise import Promise from .utils import process # Necessary for static type checking if False: # flake8: noqa from typing import Any, Callable, List class ThreadExecutor(object): pool = None def __init__(self, pool=False): # type: (bool) -> None self.threads = [] # type: List[Thread] if pool: self.execute = self.execute_in_pool self.pool = ThreadPool(processes=pool) else: self.execute = self.execute_in_thread def wait_until_finished(self): # type: () -> None while self.threads: threads = self.threads self.threads = [] for thread in threads: thread.join() def clean(self): self.threads = [] def execute_in_thread(self, fn, *args, **kwargs): # type: (Callable, *Any, **Any) -> Promise promise = Promise() # type: ignore thread = Thread(target=process, args=(promise, fn, args, kwargs)) thread.start() self.threads.append(thread) return promise def execute_in_pool(self, fn, *args, **kwargs): promise = Promise() self.pool.map(lambda input: process(*input), [(promise, fn, args, kwargs)]) return promise graphql-core-legacy-2.3.2/graphql/execution/executors/utils.py000066400000000000000000000011231365661746200245550ustar00rootroot00000000000000from sys import exc_info # Necessary for static type checking if False: # flake8: noqa from ..base import ResolveInfo from promise import Promise from typing import Callable, Dict, Tuple, Any def process( p, # type: Promise f, # type: Callable args, # type: Tuple[Any, ResolveInfo] kwargs, # type: Dict[str, Any] ): # type: (...) -> None try: val = f(*args, **kwargs) p.do_resolve(val) except Exception as e: traceback = exc_info()[2] e.stack = traceback # type: ignore p.do_reject(e, traceback=traceback) graphql-core-legacy-2.3.2/graphql/execution/middleware.py000066400000000000000000000044411365661746200235170ustar00rootroot00000000000000import inspect from functools import partial from itertools import chain from promise import promisify # Necessary for static type checking if False: # flake8: noqa from typing import Any, Callable, Iterator, Tuple, Dict, Iterable MIDDLEWARE_RESOLVER_FUNCTION = "resolve" class MiddlewareManager(object): __slots__ = ( "middlewares", "wrap_in_promise", "_middleware_resolvers", "_cached_resolvers", ) def __init__(self, *middlewares, **kwargs): # type: (*Callable, **bool) -> None self.middlewares = middlewares self.wrap_in_promise = kwargs.get("wrap_in_promise", True) self._middleware_resolvers = ( list(get_middleware_resolvers(middlewares)) if middlewares else [] ) self._cached_resolvers = {} # type: Dict[Callable, Callable] def get_field_resolver(self, field_resolver): # type: (Callable) -> Callable if field_resolver not in self._cached_resolvers: self._cached_resolvers[field_resolver] = middleware_chain( field_resolver, self._middleware_resolvers, wrap_in_promise=self.wrap_in_promise, ) return self._cached_resolvers[field_resolver] middlewares = MiddlewareManager def get_middleware_resolvers(middlewares): # type: (Tuple[Any, ...]) -> Iterator[Callable] for middleware in middlewares: # If the middleware is a function instead of a class if inspect.isfunction(middleware): yield middleware if not hasattr(middleware, MIDDLEWARE_RESOLVER_FUNCTION): continue yield getattr(middleware, MIDDLEWARE_RESOLVER_FUNCTION) def middleware_chain(func, middlewares, wrap_in_promise): # type: (Callable, Iterable[Callable], bool) -> Callable if not middlewares: return func if wrap_in_promise: middlewares = chain((func, make_it_promise), middlewares) else: middlewares = chain((func,), middlewares) last_func = None for middleware in middlewares: last_func = partial(middleware, last_func) if last_func else middleware return last_func # type: ignore @promisify def make_it_promise(next, *args, **kwargs): # type: (Callable, *Any, **Any) -> Any return next(*args, **kwargs) graphql-core-legacy-2.3.2/graphql/execution/tests/000077500000000000000000000000001365661746200221675ustar00rootroot00000000000000graphql-core-legacy-2.3.2/graphql/execution/tests/__init__.py000066400000000000000000000000001365661746200242660ustar00rootroot00000000000000graphql-core-legacy-2.3.2/graphql/execution/tests/test_abstract.py000066400000000000000000000221001365661746200253760ustar00rootroot00000000000000# type: ignore from graphql import graphql from graphql.type import GraphQLBoolean, GraphQLSchema, GraphQLString from graphql.type.definition import ( GraphQLField, GraphQLInterfaceType, GraphQLList, GraphQLObjectType, GraphQLUnionType, ) class Dog(object): def __init__(self, name, woofs): # type: (str, bool) -> None self.name = name self.woofs = woofs class Cat(object): def __init__(self, name, meows): # type: (str, bool) -> None self.name = name self.meows = meows class Human(object): def __init__(self, name): # type: (str) -> None self.name = name def is_type_of(type): # type: (type) -> Callable return lambda obj, info: isinstance(obj, type) def make_type_resolver(types): # type: (Callable) -> Callable def resolve_type(obj, info): # type: (Union[Cat, Dog, Human], ResolveInfo) -> GraphQLObjectType if callable(types): t = types() else: t = types for klass, type in t: if isinstance(obj, klass): return type return None return resolve_type def test_is_type_of_used_to_resolve_runtime_type_for_interface(): # type: () -> None PetType = GraphQLInterfaceType( name="Pet", fields={"name": GraphQLField(GraphQLString)} ) DogType = GraphQLObjectType( name="Dog", interfaces=[PetType], is_type_of=is_type_of(Dog), fields={ "name": GraphQLField(GraphQLString), "woofs": GraphQLField(GraphQLBoolean), }, ) CatType = GraphQLObjectType( name="Cat", interfaces=[PetType], is_type_of=is_type_of(Cat), fields={ "name": GraphQLField(GraphQLString), "meows": GraphQLField(GraphQLBoolean), }, ) schema = GraphQLSchema( query=GraphQLObjectType( name="Query", fields={ "pets": GraphQLField( GraphQLList(PetType), resolver=lambda *_: [Dog("Odie", True), Cat("Garfield", False)], ) }, ), types=[CatType, DogType], ) query = """ { pets { name ... on Dog { woofs } ... on Cat { meows } } } """ result = graphql(schema, query) assert not result.errors assert result.data == { "pets": [{"woofs": True, "name": "Odie"}, {"name": "Garfield", "meows": False}] } def test_is_type_of_used_to_resolve_runtime_type_for_union(): # type: () -> None DogType = GraphQLObjectType( name="Dog", is_type_of=is_type_of(Dog), fields={ "name": GraphQLField(GraphQLString), "woofs": GraphQLField(GraphQLBoolean), }, ) CatType = GraphQLObjectType( name="Cat", is_type_of=is_type_of(Cat), fields={ "name": GraphQLField(GraphQLString), "meows": GraphQLField(GraphQLBoolean), }, ) PetType = GraphQLUnionType(name="Pet", types=[CatType, DogType]) schema = GraphQLSchema( query=GraphQLObjectType( name="Query", fields={ "pets": GraphQLField( GraphQLList(PetType), resolver=lambda *_: [Dog("Odie", True), Cat("Garfield", False)], ) }, ), types=[CatType, DogType], ) query = """ { pets { ... on Dog { name woofs } ... on Cat { name meows } } } """ result = graphql(schema, query) assert not result.errors assert result.data == { "pets": [{"woofs": True, "name": "Odie"}, {"name": "Garfield", "meows": False}] } def test_resolve_type_on_interface_yields_useful_error(): # type: () -> None PetType = GraphQLInterfaceType( name="Pet", fields={"name": GraphQLField(GraphQLString)}, resolve_type=make_type_resolver( lambda: [(Dog, DogType), (Cat, CatType), (Human, HumanType)] ), ) DogType = GraphQLObjectType( name="Dog", interfaces=[PetType], fields={ "name": GraphQLField(GraphQLString), "woofs": GraphQLField(GraphQLBoolean), }, ) HumanType = GraphQLObjectType( name="Human", fields={"name": GraphQLField(GraphQLString)} ) CatType = GraphQLObjectType( name="Cat", interfaces=[PetType], fields={ "name": GraphQLField(GraphQLString), "meows": GraphQLField(GraphQLBoolean), }, ) schema = GraphQLSchema( query=GraphQLObjectType( name="Query", fields={ "pets": GraphQLField( GraphQLList(PetType), resolver=lambda *_: [ Dog("Odie", True), Cat("Garfield", False), Human("Jon"), ], ) }, ), types=[DogType, CatType], ) query = """ { pets { name ... on Dog { woofs } ... on Cat { meows } } } """ result = graphql(schema, query) assert ( result.errors[0].message == 'Runtime Object type "Human" is not a possible type for "Pet".' ) assert result.data == { "pets": [ {"woofs": True, "name": "Odie"}, {"name": "Garfield", "meows": False}, None, ] } def test_resolve_type_on_union_yields_useful_error(): # type: () -> None DogType = GraphQLObjectType( name="Dog", fields={ "name": GraphQLField(GraphQLString), "woofs": GraphQLField(GraphQLBoolean), }, ) HumanType = GraphQLObjectType( name="Human", fields={"name": GraphQLField(GraphQLString)} ) CatType = GraphQLObjectType( name="Cat", fields={ "name": GraphQLField(GraphQLString), "meows": GraphQLField(GraphQLBoolean), }, ) PetType = GraphQLUnionType( name="Pet", types=[DogType, CatType], resolve_type=make_type_resolver( lambda: [(Dog, DogType), (Cat, CatType), (Human, HumanType)] ), ) schema = GraphQLSchema( query=GraphQLObjectType( name="Query", fields={ "pets": GraphQLField( GraphQLList(PetType), resolver=lambda *_: [ Dog("Odie", True), Cat("Garfield", False), Human("Jon"), ], ) }, ) ) query = """ { pets { ... on Dog { name woofs } ... on Cat { name meows } } } """ result = graphql(schema, query) assert ( result.errors[0].message == 'Runtime Object type "Human" is not a possible type for "Pet".' ) assert result.data == { "pets": [ {"woofs": True, "name": "Odie"}, {"name": "Garfield", "meows": False}, None, ] } def test_resolve_type_can_use_type_string(): # type: () -> None def type_string_resolver(obj, *_): # type: (Union[Cat, Dog], *ResolveInfo) -> str if isinstance(obj, Dog): return "Dog" if isinstance(obj, Cat): return "Cat" PetType = GraphQLInterfaceType( name="Pet", fields={"name": GraphQLField(GraphQLString)}, resolve_type=type_string_resolver, ) DogType = GraphQLObjectType( name="Dog", interfaces=[PetType], fields={ "name": GraphQLField(GraphQLString), "woofs": GraphQLField(GraphQLBoolean), }, ) CatType = GraphQLObjectType( name="Cat", interfaces=[PetType], fields={ "name": GraphQLField(GraphQLString), "meows": GraphQLField(GraphQLBoolean), }, ) schema = GraphQLSchema( query=GraphQLObjectType( name="Query", fields={ "pets": GraphQLField( GraphQLList(PetType), resolver=lambda *_: [Dog("Odie", True), Cat("Garfield", False)], ) }, ), types=[CatType, DogType], ) query = """ { pets { name ... on Dog { woofs } ... on Cat { meows } } } """ result = graphql(schema, query) assert not result.errors assert result.data == { "pets": [{"woofs": True, "name": "Odie"}, {"name": "Garfield", "meows": False}] } graphql-core-legacy-2.3.2/graphql/execution/tests/test_benchmark.py000066400000000000000000000044541365661746200255410ustar00rootroot00000000000000# type: ignore from collections import namedtuple from functools import partial from graphql import ( GraphQLField, GraphQLInt, GraphQLList, GraphQLObjectType, GraphQLSchema, Source, execute, parse, ) # from graphql.execution import executor # executor.use_experimental_executor = True SIZE = 10000 # set global fixtures Container = namedtuple("Container", "x y z o") big_int_list = [x for x in range(SIZE)] big_container_list = [Container(x=x, y=x, z=x, o=x) for x in range(SIZE)] ContainerType = GraphQLObjectType( "Container", fields={ "x": GraphQLField(GraphQLInt), "y": GraphQLField(GraphQLInt), "z": GraphQLField(GraphQLInt), "o": GraphQLField(GraphQLInt), }, ) def resolve_all_containers(root, info, **args): return big_container_list def resolve_all_ints(root, info, **args): return big_int_list def test_big_list_of_ints(benchmark): Query = GraphQLObjectType( "Query", fields={ "allInts": GraphQLField(GraphQLList(GraphQLInt), resolver=resolve_all_ints) }, ) schema = GraphQLSchema(Query) source = Source("{ allInts }") ast = parse(source) @benchmark def b(): return execute(schema, ast) def test_big_list_of_ints_serialize(benchmark): from ..executor import complete_leaf_value @benchmark def serialize(): map(GraphQLInt.serialize, big_int_list) def test_big_list_objecttypes_with_one_int_field(benchmark): Query = GraphQLObjectType( "Query", fields={ "allContainers": GraphQLField( GraphQLList(ContainerType), resolver=resolve_all_containers ) }, ) schema = GraphQLSchema(Query) source = Source("{ allContainers { x } }") ast = parse(source) @benchmark def b(): return execute(schema, ast) def test_big_list_objecttypes_with_two_int_fields(benchmark): Query = GraphQLObjectType( "Query", fields={ "allContainers": GraphQLField( GraphQLList(ContainerType), resolver=resolve_all_containers ) }, ) schema = GraphQLSchema(Query) source = Source("{ allContainers { x, y } }") ast = parse(source) @benchmark def b(): return execute(schema, ast) graphql-core-legacy-2.3.2/graphql/execution/tests/test_dataloader.py000066400000000000000000000104021365661746200256750ustar00rootroot00000000000000# type: ignore import pytest from promise import Promise from promise.dataloader import DataLoader from graphql import ( GraphQLObjectType, GraphQLField, GraphQLID, GraphQLArgument, GraphQLNonNull, GraphQLSchema, parse, execute, ) from graphql.execution.executors.sync import SyncExecutor from graphql.execution.executors.thread import ThreadExecutor @pytest.mark.parametrize( "executor", [ SyncExecutor(), # ThreadExecutor(), ], ) def test_batches_correctly(executor): # type: (SyncExecutor) -> None Business = GraphQLObjectType( "Business", lambda: { "id": GraphQLField(GraphQLID, resolver=lambda root, info, **args: root) }, ) Query = GraphQLObjectType( "Query", lambda: { "getBusiness": GraphQLField( Business, args={"id": GraphQLArgument(GraphQLNonNull(GraphQLID))}, resolver=lambda root, info, **args: info.context.business_data_loader.load( args.get("id") ), ) }, ) schema = GraphQLSchema(query=Query) doc = """ { business1: getBusiness(id: "1") { id } business2: getBusiness(id: "2") { id } } """ doc_ast = parse(doc) load_calls = [] class BusinessDataLoader(DataLoader): def batch_load_fn(self, keys): # type: (List[str]) -> Promise load_calls.append(keys) return Promise.resolve(keys) class Context(object): business_data_loader = BusinessDataLoader() result = execute(schema, doc_ast, None, context_value=Context(), executor=executor) assert not result.errors assert result.data == {"business1": {"id": "1"}, "business2": {"id": "2"}} assert load_calls == [["1", "2"]] @pytest.mark.parametrize( "executor", [ SyncExecutor(), # ThreadExecutor(), # Fails on pypy :O ], ) def test_batches_multiple_together(executor): # type: (SyncExecutor) -> None Location = GraphQLObjectType( "Location", lambda: { "id": GraphQLField(GraphQLID, resolver=lambda root, info, **args: root) }, ) Business = GraphQLObjectType( "Business", lambda: { "id": GraphQLField(GraphQLID, resolver=lambda root, info, **args: root), "location": GraphQLField( Location, resolver=lambda root, info, **args: info.context.location_data_loader.load( "location-{}".format(root) ), ), }, ) Query = GraphQLObjectType( "Query", lambda: { "getBusiness": GraphQLField( Business, args={"id": GraphQLArgument(GraphQLNonNull(GraphQLID))}, resolver=lambda root, info, **args: info.context.business_data_loader.load( args.get("id") ), ) }, ) schema = GraphQLSchema(query=Query) doc = """ { business1: getBusiness(id: "1") { id location { id } } business2: getBusiness(id: "2") { id location { id } } } """ doc_ast = parse(doc) business_load_calls = [] class BusinessDataLoader(DataLoader): def batch_load_fn(self, keys): # type: (List[str]) -> Promise business_load_calls.append(keys) return Promise.resolve(keys) location_load_calls = [] class LocationDataLoader(DataLoader): def batch_load_fn(self, keys): # type: (List[str]) -> Promise location_load_calls.append(keys) return Promise.resolve(keys) class Context(object): business_data_loader = BusinessDataLoader() location_data_loader = LocationDataLoader() result = execute(schema, doc_ast, None, context_value=Context(), executor=executor) assert not result.errors assert result.data == { "business1": {"id": "1", "location": {"id": "location-1"}}, "business2": {"id": "2", "location": {"id": "location-2"}}, } assert business_load_calls == [["1", "2"]] assert location_load_calls == [["location-1", "location-2"]] graphql-core-legacy-2.3.2/graphql/execution/tests/test_directives.py000066400000000000000000000141621365661746200257450ustar00rootroot00000000000000# type: ignore from graphql.execution import execute from graphql.language.parser import parse from graphql.type import GraphQLField, GraphQLObjectType, GraphQLSchema, GraphQLString schema = GraphQLSchema( query=GraphQLObjectType( name="TestType", fields={"a": GraphQLField(GraphQLString), "b": GraphQLField(GraphQLString)}, ) ) class Data(object): a = "a" b = "b" def execute_test_query(doc): # type: (str) -> ExecutionResult return execute(schema, parse(doc), Data) def test_basic_query_works(): # type: () -> None result = execute_test_query("{ a, b }") assert not result.errors assert result.data == {"a": "a", "b": "b"} def test_if_true_includes_scalar(): # type: () -> None result = execute_test_query("{ a, b @include(if: true) }") assert not result.errors assert result.data == {"a": "a", "b": "b"} def test_if_false_omits_on_scalar(): # type: () -> None result = execute_test_query("{ a, b @include(if: false) }") assert not result.errors assert result.data == {"a": "a"} def test_skip_false_includes_scalar(): # type: () -> None result = execute_test_query("{ a, b @skip(if: false) }") assert not result.errors assert result.data == {"a": "a", "b": "b"} def test_skip_true_omits_scalar(): # type: () -> None result = execute_test_query("{ a, b @skip(if: true) }") assert not result.errors assert result.data == {"a": "a"} def test_if_false_omits_fragment_spread(): # type: () -> None q = """ query Q { a ...Frag @include(if: false) } fragment Frag on TestType { b } """ result = execute_test_query(q) assert not result.errors assert result.data == {"a": "a"} def test_if_true_includes_fragment_spread(): # type: () -> None q = """ query Q { a ...Frag @include(if: true) } fragment Frag on TestType { b } """ result = execute_test_query(q) assert not result.errors assert result.data == {"a": "a", "b": "b"} def test_skip_false_includes_fragment_spread(): # type: () -> None q = """ query Q { a ...Frag @skip(if: false) } fragment Frag on TestType { b } """ result = execute_test_query(q) assert not result.errors assert result.data == {"a": "a", "b": "b"} def test_skip_true_omits_fragment_spread(): # type: () -> None q = """ query Q { a ...Frag @skip(if: true) } fragment Frag on TestType { b } """ result = execute_test_query(q) assert not result.errors assert result.data == {"a": "a"} def test_if_false_omits_inline_fragment(): # type: () -> None q = """ query Q { a ... on TestType @include(if: false) { b } } """ result = execute_test_query(q) assert not result.errors assert result.data == {"a": "a"} def test_if_true_includes_inline_fragment(): # type: () -> None q = """ query Q { a ... on TestType @include(if: true) { b } } """ result = execute_test_query(q) assert not result.errors assert result.data == {"a": "a", "b": "b"} def test_skip_false_includes_inline_fragment(): # type: () -> None q = """ query Q { a ... on TestType @skip(if: false) { b } } """ result = execute_test_query(q) assert not result.errors assert result.data == {"a": "a", "b": "b"} def test_skip_true_omits_inline_fragment(): # type: () -> None q = """ query Q { a ... on TestType @skip(if: true) { b } } """ result = execute_test_query(q) assert not result.errors assert result.data == {"a": "a"} def test_skip_true_omits_fragment(): # type: () -> None q = """ query Q { a ...Frag } fragment Frag on TestType @skip(if: true) { b } """ result = execute_test_query(q) assert not result.errors assert result.data == {"a": "a"} def test_skip_on_inline_anonymous_fragment_omits_field(): # type: () -> None q = """ query Q { a ... @skip(if: true) { b } } """ result = execute_test_query(q) assert not result.errors assert result.data == {"a": "a"} def test_skip_on_inline_anonymous_fragment_does_not_omit_field(): # type: () -> None q = """ query Q { a ... @skip(if: false) { b } } """ result = execute_test_query(q) assert not result.errors assert result.data == {"a": "a", "b": "b"} def test_include_on_inline_anonymous_fragment_omits_field(): # type: () -> None q = """ query Q { a ... @include(if: false) { b } } """ result = execute_test_query(q) assert not result.errors assert result.data == {"a": "a"} def test_include_on_inline_anonymous_fragment_does_not_omit_field(): # type: () -> None q = """ query Q { a ... @include(if: true) { b } } """ result = execute_test_query(q) assert not result.errors assert result.data == {"a": "a", "b": "b"} def test_works_directives_include_and_no_skip(): # type: () -> None result = execute_test_query("{ a, b @include(if: true) @skip(if: false) }") assert not result.errors assert result.data == {"a": "a", "b": "b"} def test_works_directives_include_and_skip(): # type: () -> None result = execute_test_query("{ a, b @include(if: true) @skip(if: true) }") assert not result.errors assert result.data == {"a": "a"} def test_works_directives_no_include_or_skip(): # type: () -> None result = execute_test_query("{ a, b @include(if: false) @skip(if: false) }") assert not result.errors assert result.data == {"a": "a"} graphql-core-legacy-2.3.2/graphql/execution/tests/test_execute_schema.py000066400000000000000000000116751365661746200265740ustar00rootroot00000000000000# type: ignore from graphql.execution import execute from graphql.language.parser import parse from graphql.type import ( GraphQLArgument, GraphQLBoolean, GraphQLField, GraphQLID, GraphQLInt, GraphQLList, GraphQLNonNull, GraphQLObjectType, GraphQLSchema, GraphQLString, ) def test_executes_using_a_schema(): # type: () -> None BlogImage = GraphQLObjectType( "BlogImage", { "url": GraphQLField(GraphQLString), "width": GraphQLField(GraphQLInt), "height": GraphQLField(GraphQLInt), }, ) BlogAuthor = GraphQLObjectType( "Author", lambda: { "id": GraphQLField(GraphQLString), "name": GraphQLField(GraphQLString), "pic": GraphQLField( BlogImage, args={ "width": GraphQLArgument(GraphQLInt), "height": GraphQLArgument(GraphQLInt), }, resolver=lambda obj, info, **args: obj.pic( args["width"], args["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)), }, ) BlogQuery = GraphQLObjectType( "Query", { "article": GraphQLField( BlogArticle, args={"id": GraphQLArgument(GraphQLID)}, resolver=lambda obj, info, **args: Article(args["id"]), ), "feed": GraphQLField( GraphQLList(BlogArticle), resolver=lambda *_: map(Article, range(1, 10 + 1)), ), }, ) BlogSchema = GraphQLSchema(BlogQuery) class Article(object): def __init__(self, id): # type: (int) -> None self.id = id self.isPublished = True self.author = Author() self.title = "My Article {}".format(id) self.body = "This is a post" self.hidden = "This data is not exposed in the schema" self.keywords = ["foo", "bar", 1, True, None] class Author(object): id = 123 name = "John Smith" def pic(self, width, height): # type: (int, int) -> Pic return Pic(123, width, height) @property def recentArticle(self): # type: () -> Article return Article(1) class Pic(object): def __init__(self, uid, width, height): # type: (int, int, int) -> None self.url = "cdn://{}".format(uid) self.width = str(width) self.height = str(height) request = """ { 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. result = execute(BlogSchema, parse(request)) assert not result.errors assert result.data == { "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], }, }, }, } graphql-core-legacy-2.3.2/graphql/execution/tests/test_executor.py000066400000000000000000000502021365661746200254350ustar00rootroot00000000000000# type: ignore import json from pytest import raises from graphql.error import GraphQLError from graphql.execution import execute from graphql.language.ast import ObjectTypeDefinition from graphql.language.parser import parse from graphql.type import ( GraphQLArgument, GraphQLBoolean, GraphQLField, GraphQLInt, GraphQLList, GraphQLObjectType, GraphQLSchema, GraphQLString, GraphQLNonNull, GraphQLID, ) from promise import Promise def test_executes_arbitary_code(): # type: () -> None class Data(object): a = "Apple" b = "Banana" c = "Cookie" d = "Donut" e = "Egg" f = "Fish" def pic(self, size=50): # type: (int) -> str return "Pic of size: {}".format(size) def deep(self): # type: () -> DeepData return DeepData() def promise(self): # type: () -> Data # FIXME: promise is unsupported return Data() class DeepData(object): a = "Already Been Done" b = "Boring" c = ["Contrived", None, "Confusing"] def deeper(self): # type: () -> List[Optional[Data]] return [Data(), None, Data()] doc = """ query Example($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 } """ ast = parse(doc) expected = { "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"}, ], }, } DataType = GraphQLObjectType( "DataType", lambda: { "a": GraphQLField(GraphQLString), "b": GraphQLField(GraphQLString), "c": GraphQLField(GraphQLString), "d": GraphQLField(GraphQLString), "e": GraphQLField(GraphQLString), "f": GraphQLField(GraphQLString), "pic": GraphQLField( args={"size": GraphQLArgument(GraphQLInt)}, type_=GraphQLString, resolver=lambda obj, info, size: obj.pic(size), ), "deep": GraphQLField(DeepDataType), "promise": GraphQLField(DataType), }, ) DeepDataType = GraphQLObjectType( "DeepDataType", { "a": GraphQLField(GraphQLString), "b": GraphQLField(GraphQLString), "c": GraphQLField(GraphQLList(GraphQLString)), "deeper": GraphQLField(GraphQLList(DataType)), }, ) schema = GraphQLSchema(query=DataType) result = execute( schema, ast, Data(), operation_name="Example", variable_values={"size": 100} ) assert not result.errors assert result.data == expected def test_merges_parallel_fragments(): # type: () -> None ast = parse( """ { a, deep {...FragOne, ...FragTwo} } fragment FragOne on Type { b deep { b, deeper: deep { b } } } fragment FragTwo on Type { c deep { c, deeper: deep { c } } } """ ) Type = GraphQLObjectType( "Type", lambda: { "a": GraphQLField(GraphQLString, resolver=lambda *_: "Apple"), "b": GraphQLField(GraphQLString, resolver=lambda *_: "Banana"), "c": GraphQLField(GraphQLString, resolver=lambda *_: "Cherry"), "deep": GraphQLField(Type, resolver=lambda *_: {}), }, ) schema = GraphQLSchema(query=Type) result = execute(schema, ast) assert not result.errors assert result.data == { "a": "Apple", "deep": { "b": "Banana", "c": "Cherry", "deep": { "b": "Banana", "c": "Cherry", "deeper": {"b": "Banana", "c": "Cherry"}, }, }, } def test_threads_root_value_context_correctly(): # type: () -> None doc = "query Example { a }" class Data(object): context_thing = "thing" ast = parse(doc) def resolver(root_value, *_): # type: (Data, *ResolveInfo) -> None assert root_value.context_thing == "thing" resolver.got_here = True resolver.got_here = False Type = GraphQLObjectType( "Type", {"a": GraphQLField(GraphQLString, resolver=resolver)} ) result = execute(GraphQLSchema(Type), ast, Data(), operation_name="Example") assert not result.errors assert resolver.got_here def test_correctly_threads_arguments(): # type: () -> None doc = """ query Example { b(numArg: 123, stringArg: "foo") } """ def resolver(source, info, numArg, stringArg): # type: (Optional[Any], ResolveInfo, int, str) -> None assert numArg == 123 assert stringArg == "foo" resolver.got_here = True resolver.got_here = False doc_ast = parse(doc) Type = GraphQLObjectType( "Type", { "b": GraphQLField( GraphQLString, args={ "numArg": GraphQLArgument(GraphQLInt), "stringArg": GraphQLArgument(GraphQLString), }, resolver=resolver, ) }, ) result = execute(GraphQLSchema(Type), doc_ast, None, operation_name="Example") assert not result.errors assert resolver.got_here def test_nulls_out_error_subtrees(): # type: () -> None doc = """{ ok, error }""" class Data(object): def ok(self): # type: () -> str return "ok" def error(self): # type: () -> NoReturn raise Exception("Error getting error") doc_ast = parse(doc) Type = GraphQLObjectType( "Type", {"ok": GraphQLField(GraphQLString), "error": GraphQLField(GraphQLString)}, ) result = execute(GraphQLSchema(Type), doc_ast, Data()) assert result.data == {"ok": "ok", "error": None} assert len(result.errors) == 1 assert result.errors[0].message == "Error getting error" # TODO: check error location def test_uses_the_inline_operation_if_no_operation_name_is_provided(): # type: () -> None doc = "{ a }" class Data(object): a = "b" ast = parse(doc) Type = GraphQLObjectType("Type", {"a": GraphQLField(GraphQLString)}) result = execute(GraphQLSchema(Type), ast, Data()) assert not result.errors assert result.data == {"a": "b"} def test_uses_the_only_operation_if_no_operation_name_is_provided(): # type: () -> None doc = "query Example { a }" class Data(object): a = "b" ast = parse(doc) Type = GraphQLObjectType("Type", {"a": GraphQLField(GraphQLString)}) result = execute(GraphQLSchema(Type), ast, Data()) assert not result.errors assert result.data == {"a": "b"} def test_uses_the_named_operation_if_operation_name_is_provided(): # type: () -> None doc = "query Example { first: a } query OtherExample { second: a }" class Data(object): a = "b" ast = parse(doc) Type = GraphQLObjectType("Type", {"a": GraphQLField(GraphQLString)}) result = execute(GraphQLSchema(Type), ast, Data(), operation_name="OtherExample") assert not result.errors assert result.data == {"second": "b"} def test_raises_if_no_operation_is_provided(): # type: () -> None doc = "fragment Example on Type { a }" class Data(object): a = "b" ast = parse(doc) Type = GraphQLObjectType("Type", {"a": GraphQLField(GraphQLString)}) with raises(GraphQLError) as excinfo: execute(GraphQLSchema(Type), ast, Data()) assert "Must provide an operation." == str(excinfo.value) def test_raises_if_no_operation_name_is_provided_with_multiple_operations(): # type: () -> None doc = "query Example { a } query OtherExample { a }" class Data(object): a = "b" ast = parse(doc) Type = GraphQLObjectType("Type", {"a": GraphQLField(GraphQLString)}) with raises(GraphQLError) as excinfo: execute(GraphQLSchema(Type), ast, Data(), operation_name="UnknownExample") assert 'Unknown operation named "UnknownExample".' == str(excinfo.value) def test_raises_if_unknown_operation_name_is_provided(): # type: () -> None doc = "query Example { a } query OtherExample { a }" class Data(object): a = "b" ast = parse(doc) Type = GraphQLObjectType("Type", {"a": GraphQLField(GraphQLString)}) with raises(GraphQLError) as excinfo: execute(GraphQLSchema(Type), ast, Data()) assert "Must provide operation name if query contains multiple operations." == str( excinfo.value ) def test_uses_the_query_schema_for_queries(): # type: () -> None doc = "query Q { a } mutation M { c } subscription S { a }" class Data(object): a = "b" c = "d" ast = parse(doc) Q = GraphQLObjectType("Q", {"a": GraphQLField(GraphQLString)}) M = GraphQLObjectType("M", {"c": GraphQLField(GraphQLString)}) S = GraphQLObjectType("S", {"a": GraphQLField(GraphQLString)}) result = execute(GraphQLSchema(Q, M, S), ast, Data(), operation_name="Q") assert not result.errors assert result.data == {"a": "b"} def test_uses_the_mutation_schema_for_queries(): # type: () -> None doc = "query Q { a } mutation M { c }" class Data(object): a = "b" c = "d" ast = parse(doc) Q = GraphQLObjectType("Q", {"a": GraphQLField(GraphQLString)}) M = GraphQLObjectType("M", {"c": GraphQLField(GraphQLString)}) result = execute(GraphQLSchema(Q, M), ast, Data(), operation_name="M") assert not result.errors assert result.data == {"c": "d"} def test_uses_the_subscription_schema_for_subscriptions(): # type: () -> None from rx import Observable doc = "query Q { a } subscription S { a }" class Data(object): a = "b" c = "d" ast = parse(doc) Q = GraphQLObjectType("Q", {"a": GraphQLField(GraphQLString)}) S = GraphQLObjectType( "S", { "a": GraphQLField( GraphQLString, resolver=lambda root, info: Observable.from_(["b"]) ) }, ) result = execute( GraphQLSchema(Q, subscription=S), ast, Data(), operation_name="S", allow_subscriptions=True, ) assert isinstance(result, Observable) l = [] result.subscribe(l.append) result = l[0] assert not result.errors assert result.data == {"a": "b"} def test_avoids_recursion(): # type: () -> None doc = """ query Q { a ...Frag ...Frag } fragment Frag on Type { a, ...Frag } """ class Data(object): a = "b" ast = parse(doc) Type = GraphQLObjectType("Type", {"a": GraphQLField(GraphQLString)}) result = execute(GraphQLSchema(Type), ast, Data(), operation_name="Q") assert not result.errors assert result.data == {"a": "b"} def test_does_not_include_illegal_fields_in_output(): # type: () -> None doc = "mutation M { thisIsIllegalDontIncludeMe }" ast = parse(doc) Q = GraphQLObjectType("Q", {"a": GraphQLField(GraphQLString)}) M = GraphQLObjectType("M", {"c": GraphQLField(GraphQLString)}) result = execute(GraphQLSchema(Q, M), ast) assert not result.errors assert result.data == {} def test_does_not_include_arguments_that_were_not_set(): # type: () -> None schema = GraphQLSchema( GraphQLObjectType( "Type", { "field": GraphQLField( GraphQLString, resolver=lambda source, info, **args: args and json.dumps(args, sort_keys=True, separators=(",", ":")), args={ "a": GraphQLArgument(GraphQLBoolean), "b": GraphQLArgument(GraphQLBoolean), "c": GraphQLArgument(GraphQLBoolean), "d": GraphQLArgument(GraphQLInt), "e": GraphQLArgument(GraphQLInt), }, ) }, ) ) ast = parse("{ field(a: true, c: false, e: 0) }") result = execute(schema, ast) assert result.data == {"field": '{"a":true,"c":false,"e":0}'} def test_fails_when_an_is_type_of_check_is_not_met(): # type: () -> None class Special(object): def __init__(self, value): # type: (str) -> None self.value = value class NotSpecial(object): def __init__(self, value): # type: (str) -> None self.value = value SpecialType = GraphQLObjectType( "SpecialType", fields={"value": GraphQLField(GraphQLString)}, is_type_of=lambda obj, info: isinstance(obj, Special), ) schema = GraphQLSchema( GraphQLObjectType( name="Query", fields={ "specials": GraphQLField( GraphQLList(SpecialType), resolver=lambda root, *_: root["specials"] ) }, ) ) query = parse("{ specials { value } }") value = {"specials": [Special("foo"), NotSpecial("bar")]} result = execute(schema, query, value) assert result.data == {"specials": [{"value": "foo"}, None]} assert 'Expected value of type "SpecialType" but got: NotSpecial.' in [ str(e) for e in result.errors ] def test_fails_to_execute_a_query_containing_a_type_definition(): # type: () -> None query = parse( """ { foo } type Query { foo: String } """ ) schema = GraphQLSchema( GraphQLObjectType(name="Query", fields={"foo": GraphQLField(GraphQLString)}) ) with raises(GraphQLError) as excinfo: execute(schema, query) error = excinfo.value assert ( error.message == "GraphQL cannot execute a request containing a ObjectTypeDefinition." ) nodes = error.nodes assert type(nodes) is list assert len(nodes) == 1 assert isinstance(nodes[0], ObjectTypeDefinition) def test_exceptions_are_reraised_if_specified(mocker): # type: (MockFixture) -> None logger = mocker.patch("graphql.execution.executor.logger") query = parse( """ { foo } """ ) def resolver(*_): # type: (*Any) -> NoReturn raise Exception("UH OH!") schema = GraphQLSchema( GraphQLObjectType( name="Query", fields={"foo": GraphQLField(GraphQLString, resolver=resolver)} ) ) execute(schema, query) logger.exception.assert_called_with( "An error occurred while resolving field Query.foo" ) def test_executor_properly_propogates_path_data(mocker): # type: (MockFixture) -> None time_mock = mocker.patch("time.time") time_mock.side_effect = range(0, 10000) BlogImage = GraphQLObjectType( "BlogImage", { "url": GraphQLField(GraphQLString), "width": GraphQLField(GraphQLInt), "height": GraphQLField(GraphQLInt), }, ) BlogAuthor = GraphQLObjectType( "Author", lambda: { "id": GraphQLField(GraphQLString), "name": GraphQLField(GraphQLString), "pic": GraphQLField( BlogImage, args={ "width": GraphQLArgument(GraphQLInt), "height": GraphQLArgument(GraphQLInt), }, resolver=lambda obj, info, **args: obj.pic( args["width"], args["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)), }, ) BlogQuery = GraphQLObjectType( "Query", { "article": GraphQLField( BlogArticle, args={"id": GraphQLArgument(GraphQLID)}, resolver=lambda obj, info, **args: Article(args["id"]), ), "feed": GraphQLField( GraphQLList(BlogArticle), resolver=lambda *_: map(Article, range(1, 2 + 1)), ), }, ) BlogSchema = GraphQLSchema(BlogQuery) class Article(object): def __init__(self, id): # type: (int) -> None self.id = id self.isPublished = True self.author = Author() self.title = "My Article {}".format(id) self.body = "This is a post" self.hidden = "This data is not exposed in the schema" self.keywords = ["foo", "bar", 1, True, None] class Author(object): id = 123 name = "John Smith" def pic(self, width, height): return Pic(123, width, height) @property def recentArticle(self): return Article(1) class Pic(object): def __init__(self, uid, width, height): self.url = "cdn://{}".format(uid) self.width = str(width) self.height = str(height) class PathCollectorMiddleware(object): def __init__(self): # type: () -> None self.paths = [] def resolve( self, _next, # type: Callable root, # type: Optional[Article] info, # type: ResolveInfo *args, # type: Any **kwargs # type: Any ): # type: (...) -> Promise self.paths.append(info.path) return _next(root, info, *args, **kwargs) request = """ { feed { id ...articleFields author { id name nameAlias: name } }, } fragment articleFields on Article { title, body, hidden, } """ paths_middleware = PathCollectorMiddleware() result = execute(BlogSchema, parse(request), middleware=(paths_middleware,)) assert not result.errors assert result.data == { "feed": [ { "id": "1", "title": "My Article 1", "body": "This is a post", "author": { "id": "123", "name": "John Smith", "nameAlias": "John Smith", }, }, { "id": "2", "title": "My Article 2", "body": "This is a post", "author": { "id": "123", "name": "John Smith", "nameAlias": "John Smith", }, }, ] } traversed_paths = paths_middleware.paths assert traversed_paths == [ ["feed"], ["feed", 0, "id"], ["feed", 0, "title"], ["feed", 0, "body"], ["feed", 0, "author"], ["feed", 1, "id"], ["feed", 1, "title"], ["feed", 1, "body"], ["feed", 1, "author"], ["feed", 0, "author", "id"], ["feed", 0, "author", "name"], ["feed", 0, "author", "nameAlias"], ["feed", 1, "author", "id"], ["feed", 1, "author", "name"], ["feed", 1, "author", "nameAlias"], ] graphql-core-legacy-2.3.2/graphql/execution/tests/test_executor_asyncio.py000066400000000000000000000066461365661746200271770ustar00rootroot00000000000000""" isort:skip_file """ # type: ignore # flake8: noqa import pytest asyncio = pytest.importorskip("asyncio") from graphql.error import format_error from graphql.execution import execute from graphql.language.parser import parse from graphql.type import GraphQLField, GraphQLObjectType, GraphQLSchema, GraphQLString from ..executors.asyncio import AsyncioExecutor from .test_mutations import assert_evaluate_mutations_serially def test_asyncio_executor(): # type: () -> None def resolver(context, *_): # type: (Optional[Any], *ResolveInfo) -> str asyncio.sleep(0.001) return "hey" @asyncio.coroutine def resolver_2(context, *_): # type: (Optional[Any], *ResolveInfo) -> str asyncio.sleep(0.003) return "hey2" def resolver_3(contest, *_): # type: (Optional[Any], *ResolveInfo) -> str return "hey3" Type = GraphQLObjectType( "Type", { "a": GraphQLField(GraphQLString, resolver=resolver), "b": GraphQLField(GraphQLString, resolver=resolver_2), "c": GraphQLField(GraphQLString, resolver=resolver_3), }, ) ast = parse("{ a b c }") result = execute(GraphQLSchema(Type), ast, executor=AsyncioExecutor()) assert not result.errors assert result.data == {"a": "hey", "b": "hey2", "c": "hey3"} def test_asyncio_executor_custom_loop(): # type: () -> None loop = asyncio.get_event_loop() def resolver(context, *_): # type: (Optional[Any], *ResolveInfo) -> str asyncio.sleep(0.001, loop=loop) return "hey" @asyncio.coroutine def resolver_2(context, *_): # type: (Optional[Any], *ResolveInfo) -> str asyncio.sleep(0.003, loop=loop) return "hey2" def resolver_3(contest, *_): # type: (Optional[Any], *ResolveInfo) -> str return "hey3" Type = GraphQLObjectType( "Type", { "a": GraphQLField(GraphQLString, resolver=resolver), "b": GraphQLField(GraphQLString, resolver=resolver_2), "c": GraphQLField(GraphQLString, resolver=resolver_3), }, ) ast = parse("{ a b c }") result = execute(GraphQLSchema(Type), ast, executor=AsyncioExecutor(loop=loop)) assert not result.errors assert result.data == {"a": "hey", "b": "hey2", "c": "hey3"} def test_asyncio_executor_with_error(): # type: () -> None ast = parse("query Example { a, b }") def resolver(context, *_): # type: (Optional[Any], *ResolveInfo) -> str asyncio.sleep(0.001) return "hey" def resolver_2(context, *_): # type: (Optional[Any], *ResolveInfo) -> NoReturn asyncio.sleep(0.003) raise Exception("resolver_2 failed!") Type = GraphQLObjectType( "Type", { "a": GraphQLField(GraphQLString, resolver=resolver), "b": GraphQLField(GraphQLString, resolver=resolver_2), }, ) result = execute(GraphQLSchema(Type), ast, executor=AsyncioExecutor()) formatted_errors = list(map(format_error, result.errors)) assert formatted_errors == [ { "locations": [{"line": 1, "column": 20}], "path": ["b"], "message": "resolver_2 failed!", } ] assert result.data == {"a": "hey", "b": None} def test_evaluates_mutations_serially(): # type: () -> None assert_evaluate_mutations_serially(executor=AsyncioExecutor()) graphql-core-legacy-2.3.2/graphql/execution/tests/test_executor_gevent.py000066400000000000000000000041621365661746200270110ustar00rootroot00000000000000""" isort:skip_file """ # type: ignore # flake8: noqa import pytest gevent = pytest.importorskip("gevent") from graphql.error import format_error from graphql.execution import execute from graphql.language.location import SourceLocation from graphql.language.parser import parse from graphql.type import GraphQLField, GraphQLObjectType, GraphQLSchema, GraphQLString from ..executors.gevent import GeventExecutor from .test_mutations import assert_evaluate_mutations_serially def test_gevent_executor(): def resolver(context, *_): gevent.sleep(0.001) return "hey" def resolver_2(context, *_): gevent.sleep(0.003) return "hey2" def resolver_3(contest, *_): return "hey3" Type = GraphQLObjectType( "Type", { "a": GraphQLField(GraphQLString, resolver=resolver), "b": GraphQLField(GraphQLString, resolver=resolver_2), "c": GraphQLField(GraphQLString, resolver=resolver_3), }, ) ast = parse("{ a b c }") result = execute(GraphQLSchema(Type), ast, executor=GeventExecutor()) assert not result.errors assert result.data == {"a": "hey", "b": "hey2", "c": "hey3"} def test_gevent_executor_with_error(): ast = parse("query Example { a, b }") def resolver(context, *_): gevent.sleep(0.001) return "hey" def resolver_2(context, *_): gevent.sleep(0.003) raise Exception("resolver_2 failed!") Type = GraphQLObjectType( "Type", { "a": GraphQLField(GraphQLString, resolver=resolver), "b": GraphQLField(GraphQLString, resolver=resolver_2), }, ) result = execute(GraphQLSchema(Type), ast, executor=GeventExecutor()) formatted_errors = list(map(format_error, result.errors)) assert formatted_errors == [ { "locations": [{"line": 1, "column": 20}], "path": ["b"], "message": "resolver_2 failed!", } ] assert result.data == {"a": "hey", "b": None} def test_evaluates_mutations_serially(): assert_evaluate_mutations_serially(executor=GeventExecutor()) graphql-core-legacy-2.3.2/graphql/execution/tests/test_executor_thread.py000066400000000000000000000211021365661746200267610ustar00rootroot00000000000000# type: ignore from graphql.error import format_error from graphql.execution import execute from graphql.language.parser import parse from graphql.type import ( GraphQLArgument, GraphQLField, GraphQLInt, GraphQLList, GraphQLObjectType, GraphQLSchema, GraphQLString, ) from pytest import mark from ..executors.thread import ThreadExecutor from .test_mutations import assert_evaluate_mutations_serially from .utils import rejected, resolved ### # Disabled because all these tests are flaky # The culprit is that the `ThreadExecutor` incorrectly assumes that # the `Promise` class is thread-safe. # See https://git.io/JeA3s ### @mark.xfail def test_executes_arbitary_code(): # type: () -> None class Data(object): a = "Apple" b = "Banana" c = "Cookie" d = "Donut" e = "Egg" @property def f(self): # type: () -> Promise return resolved("Fish") def pic(self, size=50): # type: (int) -> Promise return resolved("Pic of size: {}".format(size)) def deep(self): # type: () -> DeepData return DeepData() def promise(self): # type: () -> Promise return resolved(Data()) class DeepData(object): a = "Already Been Done" b = "Boring" c = ["Contrived", None, resolved("Confusing")] def deeper(self): # type: () -> List[Union[None, Data, Promise]] return [Data(), None, resolved(Data())] ast = parse( """ query Example($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 } """ ) expected = { "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"}, ], }, } DataType = GraphQLObjectType( "DataType", lambda: { "a": GraphQLField(GraphQLString), "b": GraphQLField(GraphQLString), "c": GraphQLField(GraphQLString), "d": GraphQLField(GraphQLString), "e": GraphQLField(GraphQLString), "f": GraphQLField(GraphQLString), "pic": GraphQLField( args={"size": GraphQLArgument(GraphQLInt)}, type=GraphQLString, resolver=lambda obj, info, **args: obj.pic(args["size"]), ), "deep": GraphQLField(DeepDataType), "promise": GraphQLField(DataType), }, ) DeepDataType = GraphQLObjectType( "DeepDataType", { "a": GraphQLField(GraphQLString), "b": GraphQLField(GraphQLString), "c": GraphQLField(GraphQLList(GraphQLString)), "deeper": GraphQLField(GraphQLList(DataType)), }, ) schema = GraphQLSchema(query=DataType) def handle_result(result): # type: (ExecutionResult) -> None assert not result.errors assert result.data == expected handle_result( execute( schema, ast, Data(), variable_values={"size": 100}, operation_name="Example", executor=ThreadExecutor(), ) ) handle_result( execute( schema, ast, Data(), variable_values={"size": 100}, operation_name="Example" ) ) @mark.xfail def test_synchronous_error_nulls_out_error_subtrees(): # type: () -> None ast = parse( """ { sync syncError syncReturnError syncReturnErrorList asyncBasic asyncReject asyncEmptyReject asyncReturnError } """ ) class Data: def sync(self): # type: () -> str return "sync" def syncError(self): # type: () -> NoReturn raise Exception("Error getting syncError") def syncReturnError(self): # type: () -> Exception return Exception("Error getting syncReturnError") def syncReturnErrorList(self): # type: () -> List[Union[Exception, str]] return [ "sync0", Exception("Error getting syncReturnErrorList1"), "sync2", Exception("Error getting syncReturnErrorList3"), ] def asyncBasic(self): # type: () -> Promise return resolved("async") def asyncReject(self): # type: () -> Promise return rejected(Exception("Error getting asyncReject")) def asyncEmptyReject(self): # type: () -> Promise return rejected(Exception("An unknown error occurred.")) def asyncReturnError(self): # type: () -> Promise return resolved(Exception("Error getting asyncReturnError")) schema = GraphQLSchema( query=GraphQLObjectType( name="Type", fields={ "sync": GraphQLField(GraphQLString), "syncError": GraphQLField(GraphQLString), "syncReturnError": GraphQLField(GraphQLString), "syncReturnErrorList": GraphQLField(GraphQLList(GraphQLString)), "asyncBasic": GraphQLField(GraphQLString), "asyncReject": GraphQLField(GraphQLString), "asyncEmptyReject": GraphQLField(GraphQLString), "asyncReturnError": GraphQLField(GraphQLString), }, ) ) def sort_key(item): # type: (Dict[str, Any]) -> Tuple[int, int] locations = item["locations"][0] return (locations["line"], locations["column"]) def handle_results(result): # type: (ExecutionResult) -> None assert result.data == { "asyncBasic": "async", "asyncEmptyReject": None, "asyncReject": None, "asyncReturnError": None, "sync": "sync", "syncError": None, "syncReturnError": None, "syncReturnErrorList": ["sync0", None, "sync2", None], } assert sorted(list(map(format_error, result.errors)), key=sort_key) == sorted( [ { "locations": [{"line": 4, "column": 9}], "path": ["syncError"], "message": "Error getting syncError", }, { "locations": [{"line": 5, "column": 9}], "path": ["syncReturnError"], "message": "Error getting syncReturnError", }, { "locations": [{"line": 6, "column": 9}], "path": ["syncReturnErrorList", 1], "message": "Error getting syncReturnErrorList1", }, { "locations": [{"line": 6, "column": 9}], "path": ["syncReturnErrorList", 3], "message": "Error getting syncReturnErrorList3", }, { "locations": [{"line": 8, "column": 9}], "path": ["asyncReject"], "message": "Error getting asyncReject", }, { "locations": [{"line": 9, "column": 9}], "path": ["asyncEmptyReject"], "message": "An unknown error occurred.", }, { "locations": [{"line": 10, "column": 9}], "path": ["asyncReturnError"], "message": "Error getting asyncReturnError", }, ], key=sort_key, ) handle_results(execute(schema, ast, Data(), executor=ThreadExecutor())) @mark.xfail def test_evaluates_mutations_serially(): # type: () -> None assert_evaluate_mutations_serially(executor=ThreadExecutor()) graphql-core-legacy-2.3.2/graphql/execution/tests/test_format_error.py000066400000000000000000000005641365661746200263060ustar00rootroot00000000000000# coding: utf-8 import pytest from graphql.error import GraphQLError, format_error @pytest.mark.parametrize( "error", [ GraphQLError("UNIÇODÉ!"), GraphQLError("\xd0\xbe\xd1\x88\xd0\xb8\xd0\xb1\xd0\xba\xd0\xb0"), ], ) def test_unicode_format_error(error): # type: (GraphQLError) -> None assert isinstance(format_error(error), dict) graphql-core-legacy-2.3.2/graphql/execution/tests/test_lists.py000066400000000000000000000271161365661746200247450ustar00rootroot00000000000000# type: ignore from collections import namedtuple from graphql.error import format_error from graphql.execution import execute from graphql.language.parser import parse from graphql.type import ( GraphQLField, GraphQLInt, GraphQLList, GraphQLNonNull, GraphQLObjectType, GraphQLSchema, ) from .utils import rejected, resolved Data = namedtuple("Data", "test") ast = parse("{ nest { test } }") def check(test_data, expected): def run_check(self): # type: (Any) -> None test_type = self.type data = Data(test=test_data) DataType = GraphQLObjectType( name="DataType", fields=lambda: { "test": GraphQLField(test_type), "nest": GraphQLField(DataType, resolver=lambda *_: data), }, ) schema = GraphQLSchema(query=DataType) response = execute(schema, ast, data) if response.errors: result = { "data": response.data, "errors": [format_error(e) for e in response.errors], } else: result = {"data": response.data} assert result == expected return run_check class Test_ListOfT_Array_T: # [T] Array type = GraphQLList(GraphQLInt) test_contains_values = check([1, 2], {"data": {"nest": {"test": [1, 2]}}}) test_contains_null = check([1, None, 2], {"data": {"nest": {"test": [1, None, 2]}}}) test_returns_null = check(None, {"data": {"nest": {"test": None}}}) class Test_ListOfT_Promise_Array_T: # [T] Promise> type = GraphQLList(GraphQLInt) test_contains_values = check(resolved([1, 2]), {"data": {"nest": {"test": [1, 2]}}}) test_contains_null = check( resolved([1, None, 2]), {"data": {"nest": {"test": [1, None, 2]}}} ) test_returns_null = check(resolved(None), {"data": {"nest": {"test": None}}}) test_rejected = check( lambda: rejected(Exception("bad")), { "data": {"nest": {"test": None}}, "errors": [ { "locations": [{"column": 10, "line": 1}], "path": ["nest", "test"], "message": "bad", } ], }, ) class Test_ListOfT_Array_Promise_T: # [T] Array> type = GraphQLList(GraphQLInt) test_contains_values = check( [resolved(1), resolved(2)], {"data": {"nest": {"test": [1, 2]}}} ) test_contains_null = check( [resolved(1), resolved(None), resolved(2)], {"data": {"nest": {"test": [1, None, 2]}}}, ) test_contains_reject = check( lambda: [resolved(1), rejected(Exception("bad")), resolved(2)], { "data": {"nest": {"test": [1, None, 2]}}, "errors": [ { "locations": [{"column": 10, "line": 1}], "path": ["nest", "test", 1], "message": "bad", } ], }, ) class Test_NotNullListOfT_Array_T: # [T]! Array type = GraphQLNonNull(GraphQLList(GraphQLInt)) test_contains_values = check(resolved([1, 2]), {"data": {"nest": {"test": [1, 2]}}}) test_contains_null = check( resolved([1, None, 2]), {"data": {"nest": {"test": [1, None, 2]}}} ) test_returns_null = check( resolved(None), { "data": {"nest": None}, "errors": [ { "locations": [{"column": 10, "line": 1}], "path": ["nest", "test"], "message": "Cannot return null for non-nullable field DataType.test.", } ], }, ) class Test_NotNullListOfT_Promise_Array_T: # [T]! Promise>> type = GraphQLNonNull(GraphQLList(GraphQLInt)) test_contains_values = check(resolved([1, 2]), {"data": {"nest": {"test": [1, 2]}}}) test_contains_null = check( resolved([1, None, 2]), {"data": {"nest": {"test": [1, None, 2]}}} ) test_returns_null = check( resolved(None), { "data": {"nest": None}, "errors": [ { "locations": [{"column": 10, "line": 1}], "path": ["nest", "test"], "message": "Cannot return null for non-nullable field DataType.test.", } ], }, ) test_rejected = check( lambda: rejected(Exception("bad")), { "data": {"nest": None}, "errors": [ { "locations": [{"column": 10, "line": 1}], "path": ["nest", "test"], "message": "bad", } ], }, ) class Test_NotNullListOfT_Array_Promise_T: # [T]! Promise>> type = GraphQLNonNull(GraphQLList(GraphQLInt)) test_contains_values = check( [resolved(1), resolved(2)], {"data": {"nest": {"test": [1, 2]}}} ) test_contains_null = check( [resolved(1), resolved(None), resolved(2)], {"data": {"nest": {"test": [1, None, 2]}}}, ) test_contains_reject = check( lambda: [resolved(1), rejected(Exception("bad")), resolved(2)], { "data": {"nest": {"test": [1, None, 2]}}, "errors": [ { "locations": [{"column": 10, "line": 1}], "path": ["nest", "test", 1], "message": "bad", } ], }, ) class TestListOfNotNullT_Array_T: # [T!] Array type = GraphQLList(GraphQLNonNull(GraphQLInt)) test_contains_values = check([1, 2], {"data": {"nest": {"test": [1, 2]}}}) test_contains_null = check( [1, None, 2], { "data": {"nest": {"test": None}}, "errors": [ { "locations": [{"column": 10, "line": 1}], "path": ["nest", "test", 1], "message": "Cannot return null for non-nullable field DataType.test.", } ], }, ) test_returns_null = check(None, {"data": {"nest": {"test": None}}}) class TestListOfNotNullT_Promise_Array_T: # [T!] Promise> type = GraphQLList(GraphQLNonNull(GraphQLInt)) test_contains_value = check(resolved([1, 2]), {"data": {"nest": {"test": [1, 2]}}}) test_contains_null = check( resolved([1, None, 2]), { "data": {"nest": {"test": None}}, "errors": [ { "locations": [{"column": 10, "line": 1}], "path": ["nest", "test", 1], "message": "Cannot return null for non-nullable field DataType.test.", } ], }, ) test_returns_null = check(resolved(None), {"data": {"nest": {"test": None}}}) test_rejected = check( lambda: rejected(Exception("bad")), { "data": {"nest": {"test": None}}, "errors": [ { "locations": [{"column": 10, "line": 1}], "path": ["nest", "test"], "message": "bad", } ], }, ) class TestListOfNotNullT_Array_Promise_T: # [T!] Array> type = GraphQLList(GraphQLNonNull(GraphQLInt)) test_contains_values = check( [resolved(1), resolved(2)], {"data": {"nest": {"test": [1, 2]}}} ) test_contains_null = check( [resolved(1), resolved(None), resolved(2)], { "data": {"nest": {"test": None}}, "errors": [ { "locations": [{"column": 10, "line": 1}], "path": ["nest", "test", 1], "message": "Cannot return null for non-nullable field DataType.test.", } ], }, ) test_contains_reject = check( lambda: [resolved(1), rejected(Exception("bad")), resolved(2)], { "data": {"nest": {"test": None}}, "errors": [ { "locations": [{"column": 10, "line": 1}], "path": ["nest", "test", 1], "message": "bad", } ], }, ) class TestNotNullListOfNotNullT_Array_T: # [T!]! Array type = GraphQLNonNull(GraphQLList(GraphQLNonNull(GraphQLInt))) test_contains_values = check([1, 2], {"data": {"nest": {"test": [1, 2]}}}) test_contains_null = check( [1, None, 2], { "data": {"nest": None}, "errors": [ { "locations": [{"column": 10, "line": 1}], "path": ["nest", "test", 1], "message": "Cannot return null for non-nullable field DataType.test.", } ], }, ) test_returns_null = check( None, { "data": {"nest": None}, "errors": [ { "locations": [{"column": 10, "line": 1}], "path": ["nest", "test"], "message": "Cannot return null for non-nullable field DataType.test.", } ], }, ) class TestNotNullListOfNotNullT_Promise_Array_T: # [T!]! Promise> type = GraphQLNonNull(GraphQLList(GraphQLNonNull(GraphQLInt))) test_contains_value = check(resolved([1, 2]), {"data": {"nest": {"test": [1, 2]}}}) test_contains_null = check( resolved([1, None, 2]), { "data": {"nest": None}, "errors": [ { "locations": [{"column": 10, "line": 1}], "path": ["nest", "test", 1], "message": "Cannot return null for non-nullable field DataType.test.", } ], }, ) test_returns_null = check( resolved(None), { "data": {"nest": None}, "errors": [ { "locations": [{"column": 10, "line": 1}], "path": ["nest", "test"], "message": "Cannot return null for non-nullable field DataType.test.", } ], }, ) test_rejected = check( lambda: rejected(Exception("bad")), { "data": {"nest": None}, "errors": [ { "locations": [{"column": 10, "line": 1}], "path": ["nest", "test"], "message": "bad", } ], }, ) class TestNotNullListOfNotNullT_Array_Promise_T: # [T!]! Array> type = GraphQLNonNull(GraphQLList(GraphQLNonNull(GraphQLInt))) test_contains_values = check( [resolved(1), resolved(2)], {"data": {"nest": {"test": [1, 2]}}} ) test_contains_null = check( [resolved(1), resolved(None), resolved(2)], { "data": {"nest": None}, "errors": [ { "locations": [{"column": 10, "line": 1}], "path": ["nest", "test", 1], "message": "Cannot return null for non-nullable field DataType.test.", } ], }, ) test_contains_reject = check( lambda: [resolved(1), rejected(Exception("bad")), resolved(2)], { "data": {"nest": None}, "errors": [ { "locations": [{"column": 10, "line": 1}], "path": ["nest", "test", 1], "message": "bad", } ], }, ) graphql-core-legacy-2.3.2/graphql/execution/tests/test_located_error.py000066400000000000000000000012241365661746200264230ustar00rootroot00000000000000# type: ignore # coding: utf-8 from graphql import ( GraphQLField, GraphQLObjectType, GraphQLSchema, GraphQLString, execute, parse, ) from graphql.error import GraphQLLocatedError def test_unicode_error_message(): # type: () -> None ast = parse("query Example { unicode }") def resolver(context, *_): # type: (Optional[Any], *ResolveInfo) -> NoReturn raise Exception(u"UNIÇODÉ!") Type = GraphQLObjectType( "Type", {"unicode": GraphQLField(GraphQLString, resolver=resolver)} ) result = execute(GraphQLSchema(Type), ast) assert isinstance(result.errors[0], GraphQLLocatedError) graphql-core-legacy-2.3.2/graphql/execution/tests/test_middleware.py000066400000000000000000000116241365661746200257210ustar00rootroot00000000000000# type: ignore from __future__ import print_function import json from pytest import raises from graphql.error import GraphQLError from graphql.execution import MiddlewareManager, execute from graphql.execution.middleware import get_middleware_resolvers, middleware_chain from graphql.language.parser import parse from graphql.type import ( GraphQLArgument, GraphQLBoolean, GraphQLField, GraphQLInt, GraphQLList, GraphQLObjectType, GraphQLSchema, GraphQLString, GraphQLNonNull, GraphQLID, ) from promise import Promise def test_middleware(): # type: () -> None doc = """{ ok not_ok }""" class Data(object): def ok(self): # type: () -> str return "ok" def not_ok(self): # type: () -> str return "not_ok" doc_ast = parse(doc) Type = GraphQLObjectType( "Type", {"ok": GraphQLField(GraphQLString), "not_ok": GraphQLField(GraphQLString)}, ) def reversed_middleware(next, *args, **kwargs): # type: (Callable, *Any, **Any) -> Promise p = next(*args, **kwargs) return p.then(lambda x: x[::-1]) middlewares = MiddlewareManager(reversed_middleware) result = execute(GraphQLSchema(Type), doc_ast, Data(), middleware=middlewares) assert result.data == {"ok": "ko", "not_ok": "ko_ton"} def test_middleware_class(): # type: () -> None doc = """{ ok not_ok }""" class Data(object): def ok(self): # type: () -> str return "ok" def not_ok(self): # type: () -> str return "not_ok" doc_ast = parse(doc) Type = GraphQLObjectType( "Type", {"ok": GraphQLField(GraphQLString), "not_ok": GraphQLField(GraphQLString)}, ) class MyMiddleware(object): def resolve(self, next, *args, **kwargs): # type: (Callable, *Any, **Any) -> Promise p = next(*args, **kwargs) return p.then(lambda x: x[::-1]) middlewares = MiddlewareManager(MyMiddleware()) result = execute(GraphQLSchema(Type), doc_ast, Data(), middleware=middlewares) assert result.data == {"ok": "ko", "not_ok": "ko_ton"} def test_middleware_skip_promise_wrap(): # type: () -> None doc = """{ ok not_ok }""" class Data(object): def ok(self): # type: () -> str return "ok" def not_ok(self): # type: () -> str return "not_ok" doc_ast = parse(doc) Type = GraphQLObjectType( "Type", {"ok": GraphQLField(GraphQLString), "not_ok": GraphQLField(GraphQLString)}, ) class MyPromiseMiddleware(object): def resolve(self, next, *args, **kwargs): # type: (Callable, *Any, **Any) -> Promise return Promise.resolve(next(*args, **kwargs)) class MyEmptyMiddleware(object): def resolve(self, next, *args, **kwargs): # type: (Callable, *Any, **Any) -> str return next(*args, **kwargs) middlewares_with_promise = MiddlewareManager( MyPromiseMiddleware(), wrap_in_promise=False ) middlewares_without_promise = MiddlewareManager( MyEmptyMiddleware(), wrap_in_promise=False ) result1 = execute( GraphQLSchema(Type), doc_ast, Data(), middleware=middlewares_with_promise ) result2 = execute( GraphQLSchema(Type), doc_ast, Data(), middleware=middlewares_without_promise ) assert result1.data == result2.data and result1.data == { "ok": "ok", "not_ok": "not_ok", } def test_middleware_chain(capsys): # type: (Any) -> None class CharPrintingMiddleware(object): def __init__(self, char): # type: (str) -> None self.char = char def resolve(self, next, *args, **kwargs): # type: (Callable, *Any, **Any) -> str print("resolve() called for middleware {}".format(self.char)) return next(*args, **kwargs).then( lambda x: print("then() for {}".format(self.char)) ) middlewares = [ CharPrintingMiddleware("a"), CharPrintingMiddleware("b"), CharPrintingMiddleware("c"), ] middlewares_resolvers = get_middleware_resolvers(middlewares) def func(): # type: () -> None return chain_iter = middleware_chain(func, middlewares_resolvers, wrap_in_promise=True) assert_stdout(capsys, "") chain_iter() expected_stdout = ( "resolve() called for middleware c\n" "resolve() called for middleware b\n" "resolve() called for middleware a\n" "then() for a\n" "then() for b\n" "then() for c\n" ) assert_stdout(capsys, expected_stdout) def assert_stdout(capsys, expected_stdout): # type: (Any, str) -> None captured = capsys.readouterr() assert captured.out == expected_stdout graphql-core-legacy-2.3.2/graphql/execution/tests/test_mutations.py000066400000000000000000000113711365661746200256260ustar00rootroot00000000000000# type: ignore from graphql.execution import execute from graphql.language.parser import parse from graphql.type import ( GraphQLArgument, GraphQLField, GraphQLInt, GraphQLList, GraphQLObjectType, GraphQLSchema, GraphQLString, ) # from graphql.execution.executors.asyncio import AsyncioExecutor # from graphql.execution.executors.thread import ThreadExecutor # from typing import Union class NumberHolder(object): def __init__(self, n): # type: (int) -> None self.theNumber = n class Root(object): def __init__(self, n): # type: (int) -> None self.numberHolder = NumberHolder(n) def immediately_change_the_number(self, n): # type: (int) -> NumberHolder self.numberHolder.theNumber = n return self.numberHolder def promise_to_change_the_number(self, n): # type: (int) -> NumberHolder # TODO: async return self.immediately_change_the_number(n) def fail_to_change_the_number(self, n): # type: (int) -> None raise Exception("Cannot change the number") def promise_and_fail_to_change_the_number(self, n): # type: (int) -> None # TODO: async self.fail_to_change_the_number(n) NumberHolderType = GraphQLObjectType( "NumberHolder", {"theNumber": GraphQLField(GraphQLInt)} ) QueryType = GraphQLObjectType("Query", {"numberHolder": GraphQLField(NumberHolderType)}) MutationType = GraphQLObjectType( "Mutation", { "immediatelyChangeTheNumber": GraphQLField( NumberHolderType, args={"newNumber": GraphQLArgument(GraphQLInt)}, resolver=lambda obj, info, **args: obj.immediately_change_the_number( args["newNumber"] ), ), "promiseToChangeTheNumber": GraphQLField( NumberHolderType, args={"newNumber": GraphQLArgument(GraphQLInt)}, resolver=lambda obj, info, **args: obj.promise_to_change_the_number( args["newNumber"] ), ), "failToChangeTheNumber": GraphQLField( NumberHolderType, args={"newNumber": GraphQLArgument(GraphQLInt)}, resolver=lambda obj, info, **args: obj.fail_to_change_the_number( args["newNumber"] ), ), "promiseAndFailToChangeTheNumber": GraphQLField( NumberHolderType, args={"newNumber": GraphQLArgument(GraphQLInt)}, resolver=lambda obj, info, **args: obj.promise_and_fail_to_change_the_number( args["newNumber"] ), ), }, ) schema = GraphQLSchema(QueryType, MutationType) def assert_evaluate_mutations_serially(executor=None): # type: (Union[None, AsyncioExecutor, ThreadExecutor]) -> None doc = """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 } }""" ast = parse(doc) result = execute(schema, ast, Root(6), operation_name="M", executor=executor) assert not result.errors assert result.data == { "first": {"theNumber": 1}, "second": {"theNumber": 2}, "third": {"theNumber": 3}, "fourth": {"theNumber": 4}, "fifth": {"theNumber": 5}, } def test_evaluates_mutations_serially(): # type: () -> None assert_evaluate_mutations_serially() def test_evaluates_mutations_correctly_in_the_presense_of_a_failed_mutation(): # type: () -> None doc = """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 } }""" ast = parse(doc) result = execute(schema, ast, Root(6), operation_name="M") assert result.data == { "first": {"theNumber": 1}, "second": {"theNumber": 2}, "third": None, "fourth": {"theNumber": 4}, "fifth": {"theNumber": 5}, "sixth": None, } assert len(result.errors) == 2 # TODO: check error location assert result.errors[0].message == "Cannot change the number" assert result.errors[1].message == "Cannot change the number" graphql-core-legacy-2.3.2/graphql/execution/tests/test_nonnull.py000066400000000000000000000566421365661746200253020ustar00rootroot00000000000000# type: ignore from graphql.error import format_error from graphql.execution import execute from graphql.language.parser import parse from graphql.type import ( GraphQLField, GraphQLNonNull, GraphQLObjectType, GraphQLSchema, GraphQLString, ) from .utils import rejected, resolved # Necessary for static type checking if False: # flake8: noqa from promise import Promise from typing import Any, Optional, Dict, Tuple, Union sync_error = Exception("sync") non_null_sync_error = Exception("nonNullSync") promise_error = Exception("promise") non_null_promise_error = Exception("nonNullPromise") class ThrowingData(object): def sync(self): # type: () -> None raise sync_error def nonNullSync(self): # type: () -> None raise non_null_sync_error def promise(self): # type: () -> Promise return rejected(promise_error) def nonNullPromise(self): # type: () -> Promise return rejected(non_null_promise_error) def nest(self): # type: () -> ThrowingData return ThrowingData() def nonNullNest(self): # type: () -> ThrowingData return ThrowingData() def promiseNest(self): # type: () -> Promise return resolved(ThrowingData()) def nonNullPromiseNest(self): # type: () -> Promise return resolved(ThrowingData()) class NullingData(object): def sync(self): # type: () -> Optional[Any] return None def nonNullSync(self): # type: () -> Optional[Any] return None def promise(self): # type: () -> Promise return resolved(None) def nonNullPromise(self): # type: () -> Promise return resolved(None) def nest(self): # type: () -> NullingData return NullingData() def nonNullNest(self): # type: () -> NullingData return NullingData() def promiseNest(self): # type: () -> Promise return resolved(NullingData()) def nonNullPromiseNest(self): # type: () -> Promise return resolved(NullingData()) DataType = GraphQLObjectType( "DataType", lambda: { "sync": GraphQLField(GraphQLString), "nonNullSync": GraphQLField(GraphQLNonNull(GraphQLString)), "promise": GraphQLField(GraphQLString), "nonNullPromise": GraphQLField(GraphQLNonNull(GraphQLString)), "nest": GraphQLField(DataType), "nonNullNest": GraphQLField(GraphQLNonNull(DataType)), "promiseNest": GraphQLField(DataType), "nonNullPromiseNest": GraphQLField(GraphQLNonNull(DataType)), }, ) schema = GraphQLSchema(DataType) def order_errors(error): # type: (Dict[str, Any]) -> Tuple[int, int] locations = error["locations"] return (locations[0]["column"], locations[0]["line"]) def check(doc, data, expected): # type: (str, Union[NullingData, ThrowingData], Dict[str, Any]) -> None ast = parse(doc) response = execute(schema, ast, data) if response.errors: result = { "data": response.data, "errors": [format_error(e) for e in response.errors], } if result["errors"] != expected["errors"]: assert result["data"] == expected["data"] # Sometimes the fields resolves asynchronously, so # we need to check that the errors are the same, but might be # raised in a different order. assert sorted(result["errors"], key=order_errors) == sorted( expected["errors"], key=order_errors ) else: assert result == expected else: result = {"data": response.data} assert result == expected def test_nulls_a_nullable_field_that_throws_sync(): # type: () -> None doc = """ query Q { sync } """ check( doc, ThrowingData(), { "data": {"sync": None}, "errors": [ { "locations": [{"column": 13, "line": 3}], "path": ["sync"], "message": str(sync_error), } ], }, ) def test_nulls_a_nullable_field_that_throws_in_a_promise(): # type: () -> None doc = """ query Q { promise } """ check( doc, ThrowingData(), { "data": {"promise": None}, "errors": [ { "locations": [{"column": 13, "line": 3}], "path": ["promise"], "message": str(promise_error), } ], }, ) def test_nulls_a_sync_returned_object_that_contains_a_non_nullable_field_that_throws(): # type: () -> None doc = """ query Q { nest { nonNullSync, } } """ check( doc, ThrowingData(), { "data": {"nest": None}, "errors": [ { "locations": [{"column": 17, "line": 4}], "path": ["nest", "nonNullSync"], "message": str(non_null_sync_error), } ], }, ) def test_nulls_a_synchronously_returned_object_that_contains_a_non_nullable_field_that_throws_in_a_promise(): # type: () -> None doc = """ query Q { nest { nonNullPromise, } } """ check( doc, ThrowingData(), { "data": {"nest": None}, "errors": [ { "locations": [{"column": 17, "line": 4}], "path": ["nest", "nonNullPromise"], "message": str(non_null_promise_error), } ], }, ) def test_nulls_an_object_returned_in_a_promise_that_contains_a_non_nullable_field_that_throws_synchronously(): # type: () -> None doc = """ query Q { promiseNest { nonNullSync, } } """ check( doc, ThrowingData(), { "data": {"promiseNest": None}, "errors": [ { "locations": [{"column": 17, "line": 4}], "path": ["promiseNest", "nonNullSync"], "message": str(non_null_sync_error), } ], }, ) def test_nulls_an_object_returned_in_a_promise_that_contains_a_non_nullable_field_that_throws_in_a_promise(): # type: () -> None doc = """ query Q { promiseNest { nonNullPromise, } } """ check( doc, ThrowingData(), { "data": {"promiseNest": None}, "errors": [ { "locations": [{"column": 17, "line": 4}], "path": ["promiseNest", "nonNullPromise"], "message": str(non_null_promise_error), } ], }, ) def test_nulls_a_complex_tree_of_nullable_fields_that_throw(): # type: () -> None doc = """ query Q { nest { sync promise nest { sync promise } promiseNest { sync promise } } promiseNest { sync promise nest { sync promise } promiseNest { sync promise } } } """ check( doc, ThrowingData(), { "data": { "nest": { "nest": {"promise": None, "sync": None}, "promise": None, "promiseNest": {"promise": None, "sync": None}, "sync": None, }, "promiseNest": { "nest": {"promise": None, "sync": None}, "promise": None, "promiseNest": {"promise": None, "sync": None}, "sync": None, }, }, "errors": [ { "locations": [{"column": 11, "line": 4}], "path": ["nest", "sync"], "message": str(sync_error), }, { "locations": [{"column": 11, "line": 5}], "path": ["nest", "promise"], "message": str(promise_error), }, { "locations": [{"column": 13, "line": 7}], "path": ["nest", "nest", "sync"], "message": str(sync_error), }, { "locations": [{"column": 13, "line": 8}], "path": ["nest", "nest", "promise"], "message": str(promise_error), }, { "locations": [{"column": 13, "line": 11}], "path": ["nest", "promiseNest", "sync"], "message": str(sync_error), }, { "locations": [{"column": 13, "line": 12}], "path": ["nest", "promiseNest", "promise"], "message": str(promise_error), }, { "locations": [{"column": 11, "line": 16}], "path": ["promiseNest", "sync"], "message": str(sync_error), }, { "locations": [{"column": 11, "line": 17}], "path": ["promiseNest", "promise"], "message": str(promise_error), }, { "locations": [{"column": 13, "line": 19}], "path": ["promiseNest", "nest", "sync"], "message": str(sync_error), }, { "locations": [{"column": 13, "line": 20}], "path": ["promiseNest", "nest", "promise"], "message": str(promise_error), }, { "locations": [{"column": 13, "line": 23}], "path": ["promiseNest", "promiseNest", "sync"], "message": str(sync_error), }, { "locations": [{"column": 13, "line": 24}], "path": ["promiseNest", "promiseNest", "promise"], "message": str(promise_error), }, ], }, ) def test_nulls_the_first_nullable_object_after_a_field_throws_in_a_long_chain_of_fields_that_are_non_null(): # type: () -> None doc = """ query Q { nest { nonNullNest { nonNullPromiseNest { nonNullNest { nonNullPromiseNest { nonNullSync } } } } } promiseNest { nonNullNest { nonNullPromiseNest { nonNullNest { nonNullPromiseNest { nonNullSync } } } } } anotherNest: nest { nonNullNest { nonNullPromiseNest { nonNullNest { nonNullPromiseNest { nonNullPromise } } } } } anotherPromiseNest: promiseNest { nonNullNest { nonNullPromiseNest { nonNullNest { nonNullPromiseNest { nonNullPromise } } } } } } """ check( doc, ThrowingData(), { "data": { "nest": None, "promiseNest": None, "anotherNest": None, "anotherPromiseNest": None, }, "errors": [ { "locations": [{"column": 19, "line": 8}], "path": [ "nest", "nonNullNest", "nonNullPromiseNest", "nonNullNest", "nonNullPromiseNest", "nonNullSync", ], "message": str(non_null_sync_error), }, { "locations": [{"column": 19, "line": 19}], "path": [ "promiseNest", "nonNullNest", "nonNullPromiseNest", "nonNullNest", "nonNullPromiseNest", "nonNullSync", ], "message": str(non_null_sync_error), }, { "locations": [{"column": 19, "line": 30}], "path": [ "anotherNest", "nonNullNest", "nonNullPromiseNest", "nonNullNest", "nonNullPromiseNest", "nonNullPromise", ], "message": str(non_null_promise_error), }, { "locations": [{"column": 19, "line": 41}], "path": [ "anotherPromiseNest", "nonNullNest", "nonNullPromiseNest", "nonNullNest", "nonNullPromiseNest", "nonNullPromise", ], "message": str(non_null_promise_error), }, ], }, ) def test_nulls_a_nullable_field_that_returns_null(): # type: () -> None doc = """ query Q { sync } """ check(doc, NullingData(), {"data": {"sync": None}}) def test_nulls_a_nullable_field_that_returns_null_in_a_promise(): # type: () -> None doc = """ query Q { promise } """ check(doc, NullingData(), {"data": {"promise": None}}) def test_nulls_a_sync_returned_object_that_contains_a_non_nullable_field_that_returns_null_synchronously(): # type: () -> None doc = """ query Q { nest { nonNullSync, } } """ check( doc, NullingData(), { "data": {"nest": None}, "errors": [ { "locations": [{"column": 17, "line": 4}], "path": ["nest", "nonNullSync"], "message": "Cannot return null for non-nullable field DataType.nonNullSync.", } ], }, ) def test_nulls_a_synchronously_returned_object_that_contains_a_non_nullable_field_that_returns_null_in_a_promise(): # type: () -> None doc = """ query Q { nest { nonNullPromise, } } """ check( doc, NullingData(), { "data": {"nest": None}, "errors": [ { "locations": [{"column": 17, "line": 4}], "path": ["nest", "nonNullPromise"], "message": "Cannot return null for non-nullable field DataType.nonNullPromise.", } ], }, ) def test_nulls_an_object_returned_in_a_promise_that_contains_a_non_nullable_field_that_returns_null_synchronously(): # type: () -> None doc = """ query Q { promiseNest { nonNullSync, } } """ check( doc, NullingData(), { "data": {"promiseNest": None}, "errors": [ { "locations": [{"column": 17, "line": 4}], "path": ["promiseNest", "nonNullSync"], "message": "Cannot return null for non-nullable field DataType.nonNullSync.", } ], }, ) def test_nulls_an_object_returned_in_a_promise_that_contains_a_non_nullable_field_that_returns_null_ina_a_promise(): # type: () -> None doc = """ query Q { promiseNest { nonNullPromise } } """ check( doc, NullingData(), { "data": {"promiseNest": None}, "errors": [ { "locations": [{"column": 17, "line": 4}], "path": ["promiseNest", "nonNullPromise"], "message": "Cannot return null for non-nullable field DataType.nonNullPromise.", } ], }, ) def test_nulls_a_complex_tree_of_nullable_fields_that_returns_null(): # type: () -> None doc = """ query Q { nest { sync promise nest { sync promise } promiseNest { sync promise } } promiseNest { sync promise nest { sync promise } promiseNest { sync promise } } } """ check( doc, NullingData(), { "data": { "nest": { "sync": None, "promise": None, "nest": {"sync": None, "promise": None}, "promiseNest": {"sync": None, "promise": None}, }, "promiseNest": { "sync": None, "promise": None, "nest": {"sync": None, "promise": None}, "promiseNest": {"sync": None, "promise": None}, }, } }, ) def test_nulls_the_first_nullable_object_after_a_field_returns_null_in_a_long_chain_of_fields_that_are_non_null(): # type: () -> None doc = """ query Q { nest { nonNullNest { nonNullPromiseNest { nonNullNest { nonNullPromiseNest { nonNullSync } } } } } promiseNest { nonNullNest { nonNullPromiseNest { nonNullNest { nonNullPromiseNest { nonNullSync } } } } } anotherNest: nest { nonNullNest { nonNullPromiseNest { nonNullNest { nonNullPromiseNest { nonNullPromise } } } } } anotherPromiseNest: promiseNest { nonNullNest { nonNullPromiseNest { nonNullNest { nonNullPromiseNest { nonNullPromise } } } } } } """ check( doc, NullingData(), { "data": { "nest": None, "promiseNest": None, "anotherNest": None, "anotherPromiseNest": None, }, "errors": [ { "locations": [{"column": 19, "line": 8}], "path": [ "nest", "nonNullNest", "nonNullPromiseNest", "nonNullNest", "nonNullPromiseNest", "nonNullSync", ], "message": "Cannot return null for non-nullable field DataType.nonNullSync.", }, { "locations": [{"column": 19, "line": 19}], "path": [ "promiseNest", "nonNullNest", "nonNullPromiseNest", "nonNullNest", "nonNullPromiseNest", "nonNullSync", ], "message": "Cannot return null for non-nullable field DataType.nonNullSync.", }, { "locations": [{"column": 19, "line": 30}], "path": [ "anotherNest", "nonNullNest", "nonNullPromiseNest", "nonNullNest", "nonNullPromiseNest", "nonNullPromise", ], "message": "Cannot return null for non-nullable field DataType.nonNullPromise.", }, { "locations": [{"column": 19, "line": 41}], "path": [ "anotherPromiseNest", "nonNullNest", "nonNullPromiseNest", "nonNullNest", "nonNullPromiseNest", "nonNullPromise", ], "message": "Cannot return null for non-nullable field DataType.nonNullPromise.", }, ], }, ) def test_nulls_the_top_level_if_sync_non_nullable_field_throws(): # type: () -> None doc = """ query Q { nonNullSync } """ check( doc, ThrowingData(), { "data": None, "errors": [ { "locations": [{"column": 19, "line": 2}], "path": ["nonNullSync"], "message": str(non_null_sync_error), } ], }, ) def test_nulls_the_top_level_if_async_non_nullable_field_errors(): # type: () -> None doc = """ query Q { nonNullPromise } """ check( doc, ThrowingData(), { "data": None, "errors": [ { "locations": [{"column": 19, "line": 2}], "path": ["nonNullPromise"], "message": str(non_null_promise_error), } ], }, ) def test_nulls_the_top_level_if_sync_non_nullable_field_returns_null(): # type: () -> None doc = """ query Q { nonNullSync } """ check( doc, NullingData(), { "data": None, "errors": [ { "locations": [{"column": 19, "line": 2}], "path": ["nonNullSync"], "message": "Cannot return null for non-nullable field DataType.nonNullSync.", } ], }, ) def test_nulls_the_top_level_if_async_non_nullable_field_resolves_null(): # type: () -> None doc = """ query Q { nonNullPromise } """ check( doc, NullingData(), { "data": None, "errors": [ { "locations": [{"column": 19, "line": 2}], "path": ["nonNullPromise"], "message": "Cannot return null for non-nullable field DataType.nonNullPromise.", } ], }, ) graphql-core-legacy-2.3.2/graphql/execution/tests/test_resolve.py000066400000000000000000000151601365661746200252620ustar00rootroot00000000000000# type: ignore import json from collections import OrderedDict from graphql import graphql from graphql.type import ( GraphQLArgument, GraphQLField, GraphQLInputObjectField, GraphQLInputObjectType, GraphQLInt, GraphQLList, GraphQLNonNull, GraphQLObjectType, GraphQLSchema, GraphQLString, ) from promise import Promise # from graphql.execution.base import ResolveInfo # from typing import Any # from typing import Optional # from promise.promise import Promise # from graphql.type.definition import GraphQLField # from graphql.type.schema import GraphQLSchema class CustomPromise(Promise): @classmethod def fulfilled(cls, x): # type: (str) -> CustomPromise p = cls() p.fulfill(x) return p resolve = fulfilled @classmethod def rejected(cls, reason): p = cls() p.reject(reason) return p def _test_schema(test_field): # type: (GraphQLField) -> GraphQLSchema return GraphQLSchema( query=GraphQLObjectType(name="Query", fields={"test": test_field}) ) def test_default_function_accesses_properties(): # type: () -> None schema = _test_schema(GraphQLField(GraphQLString)) class source: test = "testValue" result = graphql(schema, "{ test }", source) assert not result.errors assert result.data == {"test": "testValue"} def test_default_function_calls_methods(): # type: () -> None schema = _test_schema(GraphQLField(GraphQLString)) class source: _secret = "testValue" def test(self): # type: () -> str return self._secret result = graphql(schema, "{ test }", source()) assert not result.errors assert result.data == {"test": "testValue"} def test_uses_provided_resolve_function(): # type: () -> None def resolver(source, info, **args): # type: (Optional[str], ResolveInfo, **Any) -> str return json.dumps([source, args], separators=(",", ":")) schema = _test_schema( GraphQLField( GraphQLString, args=OrderedDict( [ ("aStr", GraphQLArgument(GraphQLString)), ("aInt", GraphQLArgument(GraphQLInt)), ] ), resolver=resolver, ) ) result = graphql(schema, "{ test }", None) assert not result.errors assert result.data == {"test": "[null,{}]"} result = graphql(schema, '{ test(aStr: "String!") }', "Source!") assert not result.errors assert result.data == {"test": '["Source!",{"aStr":"String!"}]'} result = graphql(schema, '{ test(aInt: -123, aStr: "String!",) }', "Source!") assert not result.errors assert result.data in [ {"test": '["Source!",{"aStr":"String!","aInt":-123}]'}, {"test": '["Source!",{"aInt":-123,"aStr":"String!"}]'}, ] def test_handles_resolved_promises(): # type: () -> None def resolver(source, info, **args): # type: (Optional[Any], ResolveInfo, **Any) -> Promise return Promise.resolve("foo") schema = _test_schema(GraphQLField(GraphQLString, resolver=resolver)) result = graphql(schema, "{ test }", None) assert not result.errors assert result.data == {"test": "foo"} def test_handles_resolved_custom_promises(): # type: () -> None def resolver(source, info, **args): # type: (Optional[Any], ResolveInfo, **Any) -> CustomPromise return CustomPromise.resolve("custom_foo") schema = _test_schema(GraphQLField(GraphQLString, resolver=resolver)) result = graphql(schema, "{ test }", None) assert not result.errors assert result.data == {"test": "custom_foo"} def test_maps_argument_out_names_well(): # type: () -> None def resolver(source, info, **args): # type: (Optional[str], ResolveInfo, **Any) -> str return json.dumps([source, args], separators=(",", ":")) schema = _test_schema( GraphQLField( GraphQLString, args=OrderedDict( [ ("aStr", GraphQLArgument(GraphQLString, out_name="a_str")), ("aInt", GraphQLArgument(GraphQLInt, out_name="a_int")), ] ), resolver=resolver, ) ) result = graphql(schema, "{ test }", None) assert not result.errors assert result.data == {"test": "[null,{}]"} result = graphql(schema, '{ test(aStr: "String!") }', "Source!") assert not result.errors assert result.data == {"test": '["Source!",{"a_str":"String!"}]'} result = graphql(schema, '{ test(aInt: -123, aStr: "String!",) }', "Source!") assert not result.errors assert result.data in [ {"test": '["Source!",{"a_str":"String!","a_int":-123}]'}, {"test": '["Source!",{"a_int":-123,"a_str":"String!"}]'}, ] def test_maps_argument_out_names_well_with_input(): # type: () -> None def resolver(source, info, **args): # type: (Optional[str], ResolveInfo, **Any) -> str return json.dumps([source, args], separators=(",", ":")) TestInputObject = GraphQLInputObjectType( "TestInputObject", lambda: OrderedDict( [ ( "inputOne", GraphQLInputObjectField(GraphQLString, out_name="input_one"), ), ( "inputRecursive", GraphQLInputObjectField( TestInputObject, out_name="input_recursive" ), ), ] ), ) schema = _test_schema( GraphQLField( GraphQLString, args=OrderedDict( [("aInput", GraphQLArgument(TestInputObject, out_name="a_input"))] ), resolver=resolver, ) ) result = graphql(schema, "{ test }", None) assert not result.errors assert result.data == {"test": "[null,{}]"} result = graphql(schema, '{ test(aInput: {inputOne: "String!"} ) }', "Source!") assert not result.errors assert result.data == {"test": '["Source!",{"a_input":{"input_one":"String!"}}]'} result = graphql( schema, '{ test(aInput: {inputRecursive:{inputOne: "SourceRecursive!"}} ) }', "Source!", ) assert not result.errors assert result.data == { "test": '["Source!",{"a_input":{"input_recursive":{"input_one":"SourceRecursive!"}}}]' } def test_default_resolve_works_with_dicts(): schema = _test_schema(GraphQLField(GraphQLString)) result = graphql(schema, "{ test }", {"test": "testValue"}) assert not result.errors assert result.data == {"test": "testValue"} graphql-core-legacy-2.3.2/graphql/execution/tests/test_subscribe.py000066400000000000000000000255371365661746200255750ustar00rootroot00000000000000from collections import OrderedDict, namedtuple from rx import Observable, Observer from rx.subjects import Subject from graphql import ( parse, GraphQLObjectType, GraphQLString, GraphQLBoolean, GraphQLInt, GraphQLField, GraphQLList, GraphQLSchema, graphql, subscribe, ) # Necessary for static type checking if False: # flake8: noqa from graphql.execution.base import ResolveInfo from rx import Observable from typing import Optional, Union, Any, Callable, Tuple from graphql.execution.base import ExecutionResult Email = namedtuple("Email", "from_,subject,message,unread") EmailType = GraphQLObjectType( name="Email", fields=OrderedDict( [ ("from", GraphQLField(GraphQLString, resolver=lambda x, info: x.from_)), ("subject", GraphQLField(GraphQLString)), ("message", GraphQLField(GraphQLString)), ("unread", GraphQLField(GraphQLBoolean)), ] ), ) InboxType = GraphQLObjectType( name="Inbox", fields=OrderedDict( [ ( "total", GraphQLField( GraphQLInt, resolver=lambda inbox, context: len(inbox.emails) ), ), ( "unread", GraphQLField( GraphQLInt, resolver=lambda inbox, context: len( [e for e in inbox.emails if e.unread] ), ), ), ("emails", GraphQLField(GraphQLList(EmailType))), ] ), ) QueryType = GraphQLObjectType( name="Query", fields=OrderedDict([("inbox", GraphQLField(InboxType))]) ) EmailEventType = GraphQLObjectType( name="EmailEvent", fields=OrderedDict( [ ("email", GraphQLField(EmailType, resolver=lambda root, info: root[0])), ("inbox", GraphQLField(InboxType, resolver=lambda root, info: root[1])), ] ), ) def get_unbound_function(func): # type: (Callable) -> Callable if not getattr(func, "__self__", True): return func.__func__ return func def email_schema_with_resolvers(resolve_fn=None): # type: (Callable) -> GraphQLSchema def default_resolver(root, info): # type: (Any, ResolveInfo) -> Union[Observable, Subject] func = getattr(root, "importantEmail", None) if func: func = get_unbound_function(func) return func() return Observable.empty() return GraphQLSchema( query=QueryType, subscription=GraphQLObjectType( name="Subscription", fields=OrderedDict( [ ( "importantEmail", GraphQLField( EmailEventType, resolver=resolve_fn or default_resolver ), ) ] ), ), ) email_schema = email_schema_with_resolvers() class MyObserver(Observer): def on_next(self, value): self.has_on_next = value def on_error(self, err): self.has_on_error = err def on_completed(self): self.has_on_completed = True def create_subscription( stream, # type: Subject schema=email_schema, # type: GraphQLSchema ast=None, # type: Optional[Any] vars=None, # type: Optional[Any] ): # type: (...) -> Tuple[Callable, Union[ExecutionResult, Observable]] class Root(object): class inbox(object): emails = [ Email( from_="joe@graphql.org", subject="Hello", message="Hello World", unread=False, ) ] @staticmethod def importantEmail(): return stream def send_important_email(new_email): # type: (Email) -> None Root.inbox.emails.append(new_email) stream.on_next((new_email, Root.inbox)) # stream.on_completed() default_ast = parse( """ subscription { importantEmail { email { from subject } inbox { unread total } } } """ ) return ( send_important_email, graphql(schema, ast or default_ast, Root, None, vars, allow_subscriptions=True), ) def test_accepts_an_object_with_named_properties_as_arguments(): # type: () -> None document = parse( """ subscription { importantEmail } """ ) result = subscribe(email_schema, document, root_value=None) assert isinstance(result, Observable) def test_accepts_multiple_subscription_fields_defined_in_schema(): # type: () -> None SubscriptionTypeMultiple = GraphQLObjectType( name="Subscription", fields=OrderedDict( [ ("importantEmail", GraphQLField(EmailEventType)), ("nonImportantEmail", GraphQLField(EmailEventType)), ] ), ) test_schema = GraphQLSchema(query=QueryType, subscription=SubscriptionTypeMultiple) stream = Subject() send_important_email, subscription = create_subscription(stream, test_schema) email = Email( from_="yuzhi@graphql.org", subject="Alright", message="Tests are good", unread=True, ) inbox = [] stream.subscribe(inbox.append) send_important_email(email) assert len(inbox) == 1 assert inbox[0][0] == email def test_accepts_type_definition_with_sync_subscribe_function(): # type: () -> None SubscriptionType = GraphQLObjectType( name="Subscription", fields=OrderedDict( [ ( "importantEmail", GraphQLField( EmailEventType, resolver=lambda *_: Observable.from_([None]) ), ) ] ), ) test_schema = GraphQLSchema(query=QueryType, subscription=SubscriptionType) stream = Subject() send_important_email, subscription = create_subscription(stream, test_schema) email = Email( from_="yuzhi@graphql.org", subject="Alright", message="Tests are good", unread=True, ) inbox = [] subscription.subscribe(inbox.append) send_important_email(email) assert len(inbox) == 1 assert inbox[0].data == {"importantEmail": None} def test_throws_an_error_if_subscribe_does_not_return_an_iterator(): # type: () -> None SubscriptionType = GraphQLObjectType( name="Subscription", fields=OrderedDict( [("importantEmail", GraphQLField(EmailEventType, resolver=lambda *_: None))] ), ) test_schema = GraphQLSchema(query=QueryType, subscription=SubscriptionType) stream = Subject() _, subscription = create_subscription(stream, test_schema) assert ( str(subscription.errors[0]) == "Subscription must return Async Iterable or Observable. Received: None" ) def test_returns_an_error_if_subscribe_function_returns_error(): # type: () -> None exc = Exception("Throw!") def thrower(root, info): # type: (Optional[Any], ResolveInfo) -> None raise exc erroring_email_schema = email_schema_with_resolvers(thrower) result = subscribe( erroring_email_schema, parse( """ subscription { importantEmail } """ ), ) assert result.errors == [exc] # Subscription Publish Phase def test_produces_a_payload_for_multiple_subscribe_in_same_subscription(): # type: () -> None stream = Subject() send_important_email, subscription1 = create_subscription(stream) subscription2 = create_subscription(stream)[1] payload1 = [] payload2 = [] subscription1.subscribe(payload1.append) subscription2.subscribe(payload2.append) email = Email( from_="yuzhi@graphql.org", subject="Alright", message="Tests are good", unread=True, ) send_important_email(email) expected_payload = { "importantEmail": { "email": {"from": "yuzhi@graphql.org", "subject": "Alright"}, "inbox": {"unread": 1, "total": 2}, } } assert payload1[0].data == expected_payload assert payload2[0].data == expected_payload # Subscription Publish Phase def test_produces_a_payload_per_subscription_event(): # type: () -> None stream = Subject() send_important_email, subscription = create_subscription(stream) payload = [] subscription.subscribe(payload.append) send_important_email( Email( from_="yuzhi@graphql.org", subject="Alright", message="Tests are good", unread=True, ) ) expected_payload = { "importantEmail": { "email": {"from": "yuzhi@graphql.org", "subject": "Alright"}, "inbox": {"unread": 1, "total": 2}, } } assert len(payload) == 1 assert payload[0].data == expected_payload send_important_email( Email( from_="hyo@graphql.org", subject="Tools", message="I <3 making things", unread=True, ) ) expected_payload = { "importantEmail": { "email": {"from": "hyo@graphql.org", "subject": "Tools"}, "inbox": {"unread": 2, "total": 3}, } } assert len(payload) == 2 assert payload[-1].data == expected_payload # The client decides to disconnect stream.on_completed() send_important_email( Email( from_="adam@graphql.org", subject="Important", message="Read me please", unread=True, ) ) assert len(payload) == 2 def test_event_order_is_correct_for_multiple_publishes(): # type: () -> None stream = Subject() send_important_email, subscription = create_subscription(stream) payload = [] subscription.subscribe(payload.append) send_important_email( Email( from_="yuzhi@graphql.org", subject="Message", message="Tests are good", unread=True, ) ) send_important_email( Email( from_="yuzhi@graphql.org", subject="Message 2", message="Tests are good 2", unread=True, ) ) expected_payload1 = { "importantEmail": { "email": {"from": "yuzhi@graphql.org", "subject": "Message"}, "inbox": {"unread": 1, "total": 2}, } } expected_payload2 = { "importantEmail": { "email": {"from": "yuzhi@graphql.org", "subject": "Message 2"}, "inbox": {"unread": 2, "total": 3}, } } assert len(payload) == 2 assert payload[0].data == expected_payload1 assert payload[1].data == expected_payload2 graphql-core-legacy-2.3.2/graphql/execution/tests/test_union_interface.py000066400000000000000000000217171365661746200267600ustar00rootroot00000000000000# type: ignore from graphql.execution import execute from graphql.language.parser import parse from graphql.type import ( GraphQLBoolean, GraphQLField, GraphQLInterfaceType, GraphQLList, GraphQLObjectType, GraphQLSchema, GraphQLString, GraphQLUnionType, ) # from typing import List # from graphql.execution.base import ResolveInfo # from graphql.type.definition import GraphQLObjectType # from typing import Union class Dog(object): def __init__(self, name, barks): self.name = name self.barks = barks class Cat(object): def __init__(self, name, meows): self.name = name self.meows = meows class Person(object): def __init__(self, name, pets, friends): # type: (str, List, List[Person]) -> None self.name = name self.pets = pets self.friends = friends NamedType = GraphQLInterfaceType("Named", {"name": GraphQLField(GraphQLString)}) DogType = GraphQLObjectType( name="Dog", interfaces=[NamedType], fields={"name": GraphQLField(GraphQLString), "barks": GraphQLField(GraphQLBoolean)}, is_type_of=lambda value, info: isinstance(value, Dog), ) CatType = GraphQLObjectType( name="Cat", interfaces=[NamedType], fields={"name": GraphQLField(GraphQLString), "meows": GraphQLField(GraphQLBoolean)}, is_type_of=lambda value, info: isinstance(value, Cat), ) def resolve_pet_type(value, info): # type: (Union[Cat, Dog], ResolveInfo) -> GraphQLObjectType if isinstance(value, Dog): return DogType if isinstance(value, Cat): return CatType PetType = GraphQLUnionType("Pet", [DogType, CatType], resolve_type=resolve_pet_type) PersonType = GraphQLObjectType( name="Person", interfaces=[NamedType], fields={ "name": GraphQLField(GraphQLString), "pets": GraphQLField(GraphQLList(PetType)), "friends": GraphQLField(GraphQLList(NamedType)), }, is_type_of=lambda value, info: isinstance(value, Person), ) schema = GraphQLSchema(query=PersonType, types=[PetType]) garfield = Cat("Garfield", False) odie = Dog("Odie", True) liz = Person("Liz", [], []) john = Person("John", [garfield, odie], [liz, odie]) # Execute: Union and intersection types def test_can_introspect_on_union_and_intersection_types(): # type: () -> None ast = parse( """ { Named: __type(name: "Named") { 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 } } }""" ) result = execute(schema, ast) assert not result.errors assert result.data == { "Named": { "enumValues": None, "name": "Named", "kind": "INTERFACE", "interfaces": None, "fields": [{"name": "name"}], "possibleTypes": [{"name": "Person"}, {"name": "Dog"}, {"name": "Cat"}], "inputFields": None, }, "Pet": { "enumValues": None, "name": "Pet", "kind": "UNION", "interfaces": None, "fields": None, "possibleTypes": [{"name": "Dog"}, {"name": "Cat"}], "inputFields": None, }, } def test_executes_using_union_types(): # type: () -> None # NOTE: This is an *invalid* query, but it should be an *executable* query. ast = parse( """ { __typename name pets { __typename name barks meows } } """ ) result = execute(schema, ast, john) assert not result.errors assert result.data == { "__typename": "Person", "name": "John", "pets": [ {"__typename": "Cat", "name": "Garfield", "meows": False}, {"__typename": "Dog", "name": "Odie", "barks": True}, ], } def test_executes_union_types_with_inline_fragment(): # type: () -> None # This is the valid version of the query in the above test. ast = parse( """ { __typename name pets { __typename ... on Dog { name barks } ... on Cat { name meows } } } """ ) result = execute(schema, ast, john) assert not result.errors assert result.data == { "__typename": "Person", "name": "John", "pets": [ {"__typename": "Cat", "name": "Garfield", "meows": False}, {"__typename": "Dog", "name": "Odie", "barks": True}, ], } def test_executes_using_interface_types(): # type: () -> None # NOTE: This is an *invalid* query, but it should be an *executable* query. ast = parse( """ { __typename name friends { __typename name barks meows } } """ ) result = execute(schema, ast, john) assert not result.errors assert result.data == { "__typename": "Person", "name": "John", "friends": [ {"__typename": "Person", "name": "Liz"}, {"__typename": "Dog", "name": "Odie", "barks": True}, ], } def test_executes_interface_types_with_inline_fragment(): # type: () -> None # This is the valid version of the query in the above test. ast = parse( """ { __typename name friends { __typename name ... on Dog { barks } ... on Cat { meows } } } """ ) result = execute(schema, ast, john) assert not result.errors assert result.data == { "__typename": "Person", "name": "John", "friends": [ {"__typename": "Person", "name": "Liz"}, {"__typename": "Dog", "name": "Odie", "barks": True}, ], } def test_allows_fragment_conditions_to_be_abstract_types(): # type: () -> None ast = parse( """ { __typename name pets { ...PetFields } 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 } } """ ) result = execute(schema, ast, john) assert not result.errors assert result.data == { "__typename": "Person", "name": "John", "pets": [ {"__typename": "Cat", "name": "Garfield", "meows": False}, {"__typename": "Dog", "name": "Odie", "barks": True}, ], "friends": [ {"__typename": "Person", "name": "Liz"}, {"__typename": "Dog", "name": "Odie", "barks": True}, ], } def test_only_include_fields_from_matching_fragment_condition(): # type: () -> None ast = parse( """ { pets { ...PetFields } } fragment PetFields on Pet { __typename ... on Dog { name } } """ ) result = execute(schema, ast, john) assert not result.errors assert result.data == { "pets": [{"__typename": "Cat"}, {"__typename": "Dog", "name": "Odie"}] } def test_gets_execution_info_in_resolver(): # type: () -> None class encountered: schema = None root_value = None context = None def resolve_type(obj, info): # type: (Person, ResolveInfo) -> GraphQLObjectType encountered.schema = info.schema encountered.root_value = info.root_value encountered.context = context return PersonType2 NamedType2 = GraphQLInterfaceType( name="Named", fields={"name": GraphQLField(GraphQLString)}, resolve_type=resolve_type, ) PersonType2 = GraphQLObjectType( name="Person", interfaces=[NamedType2], fields={ "name": GraphQLField(GraphQLString), "friends": GraphQLField(GraphQLList(NamedType2)), }, ) schema2 = GraphQLSchema(query=PersonType2) john2 = Person("John", [], [liz]) context = {"hey"} ast = parse("""{ name, friends { name } }""") result = execute(schema2, ast, john2, context_value=context) assert not result.errors assert result.data == {"name": "John", "friends": [{"name": "Liz"}]} assert encountered.schema == schema2 assert encountered.root_value == john2 assert encountered.context == context graphql-core-legacy-2.3.2/graphql/execution/tests/test_variables.py000066400000000000000000000515271365661746200255620ustar00rootroot00000000000000# type: ignore import json from collections import OrderedDict from pytest import raises from graphql.error import GraphQLError, format_error from graphql.execution import execute from graphql.language.parser import parse from graphql.type import ( GraphQLArgument, GraphQLField, GraphQLBoolean, GraphQLInputObjectField, GraphQLInputObjectType, GraphQLList, GraphQLNonNull, GraphQLObjectType, GraphQLScalarType, GraphQLSchema, GraphQLString, ) # from typing import Any # from graphql.execution.base import ResolveInfo # from typing import Optional # from typing import Dict # from typing import Union TestComplexScalar = GraphQLScalarType( name="ComplexScalar", serialize=lambda v: "SerializedValue" if v == "DeserializedValue" else None, parse_value=lambda v: "DeserializedValue" if v == "SerializedValue" else None, parse_literal=lambda v: "DeserializedValue" if v.value == "SerializedValue" else None, ) class my_special_dict(dict): pass TestInputObject = GraphQLInputObjectType( "TestInputObject", OrderedDict( [ ("a", GraphQLInputObjectField(GraphQLString)), ("b", GraphQLInputObjectField(GraphQLList(GraphQLString))), ("c", GraphQLInputObjectField(GraphQLNonNull(GraphQLString))), ("d", GraphQLInputObjectField(TestComplexScalar)), ] ), ) TestCustomInputObject = GraphQLInputObjectType( "TestCustomInputObject", OrderedDict([("a", GraphQLInputObjectField(GraphQLString))]), container_type=my_special_dict, ) def stringify(obj): # type: (Any) -> str return json.dumps(obj, sort_keys=True) def input_to_json(obj, info, **args): # type: (Optional[Any], ResolveInfo, **Any) -> Optional[str] input = args.get("input") if input: return stringify(input) TestNestedInputObject = GraphQLInputObjectType( name="TestNestedInputObject", fields={ "na": GraphQLInputObjectField(GraphQLNonNull(TestInputObject)), "nb": GraphQLInputObjectField(GraphQLNonNull(GraphQLString)), }, ) TestType = GraphQLObjectType( "TestType", { "fieldWithObjectInput": GraphQLField( GraphQLString, args={"input": GraphQLArgument(TestInputObject)}, resolver=input_to_json, ), "fieldWithCustomObjectInput": GraphQLField( GraphQLBoolean, args={"input": GraphQLArgument(TestCustomInputObject)}, resolver=lambda root, info, **args: isinstance( args.get("input"), my_special_dict ), ), "fieldWithNullableStringInput": GraphQLField( GraphQLString, args={"input": GraphQLArgument(GraphQLString)}, resolver=input_to_json, ), "fieldWithNonNullableStringInput": GraphQLField( GraphQLString, args={"input": GraphQLArgument(GraphQLNonNull(GraphQLString))}, resolver=input_to_json, ), "fieldWithDefaultArgumentValue": GraphQLField( GraphQLString, args={"input": GraphQLArgument(GraphQLString, "Hello World")}, resolver=input_to_json, ), "fieldWithNestedInputObject": GraphQLField( GraphQLString, args={"input": GraphQLArgument(TestNestedInputObject, "Hello World")}, resolver=input_to_json, ), "list": GraphQLField( GraphQLString, args={"input": GraphQLArgument(GraphQLList(GraphQLString))}, resolver=input_to_json, ), "nnList": GraphQLField( GraphQLString, args={"input": GraphQLArgument(GraphQLNonNull(GraphQLList(GraphQLString)))}, resolver=input_to_json, ), "listNN": GraphQLField( GraphQLString, args={"input": GraphQLArgument(GraphQLList(GraphQLNonNull(GraphQLString)))}, resolver=input_to_json, ), "nnListNN": GraphQLField( GraphQLString, args={ "input": GraphQLArgument( GraphQLNonNull(GraphQLList(GraphQLNonNull(GraphQLString))) ) }, resolver=input_to_json, ), }, ) schema = GraphQLSchema(TestType) def check( doc, # type: str expected, # type: Union[Dict[str, Dict[str, None]], Dict[str, Dict[str, str]]] args=None, # type: Any ): # type: (...) -> None ast = parse(doc) response = execute(schema, ast, variable_values=args) if response.errors: result = { "data": response.data, "errors": [format_error(e) for e in response.errors], } else: result = {"data": response.data} assert result == expected # Handles objects and nullability def test_inline_executes_with_complex_input(): # type: () -> None doc = """ { fieldWithObjectInput(input: {a: "foo", b: ["bar"], c: "baz"}) } """ check( doc, { "data": { "fieldWithObjectInput": stringify( {"a": "foo", "b": ["bar"], "c": "baz"} ) } }, ) def test_properly_parses_single_value_to_list(): # type: () -> None doc = """ { fieldWithObjectInput(input: {a: "foo", b: "bar", c: "baz"}) } """ check( doc, { "data": { "fieldWithObjectInput": stringify( {"a": "foo", "b": ["bar"], "c": "baz"} ) } }, ) def test_does_not_use_incorrect_value(): # type: () -> None doc = """ { fieldWithObjectInput(input: ["foo", "bar", "baz"]) } """ check(doc, {"data": {"fieldWithObjectInput": None}}) def test_properly_runs_parse_literal_on_complex_scalar_types(): # type: () -> None doc = """ { fieldWithObjectInput(input: {a: "foo", d: "SerializedValue"}) } """ check( doc, {"data": {"fieldWithObjectInput": '{"a": "foo", "d": "DeserializedValue"}'}}, ) # noinspection PyMethodMayBeStatic class TestUsingVariables: doc = """ query q($input: TestInputObject) { fieldWithObjectInput(input: $input) } """ def test_executes_with_complex_input(self): # type: () -> None params = {"input": {"a": "foo", "b": ["bar"], "c": "baz"}} check( self.doc, { "data": { "fieldWithObjectInput": stringify( {"a": "foo", "b": ["bar"], "c": "baz"} ) } }, params, ) def test_uses_default_value_when_not_provided(self): # type: () -> None with_defaults_doc = """ query q($input: TestInputObject = {a: "foo", b: ["bar"], c: "baz"}) { fieldWithObjectInput(input: $input) } """ check( with_defaults_doc, { "data": { "fieldWithObjectInput": stringify( {"a": "foo", "b": ["bar"], "c": "baz"} ) } }, ) def test_properly_parses_single_value_to_list(self): # type: () -> None params = {"input": {"a": "foo", "b": "bar", "c": "baz"}} check( self.doc, { "data": { "fieldWithObjectInput": stringify( {"a": "foo", "b": ["bar"], "c": "baz"} ) } }, params, ) def test_executes_with_complex_scalar_input(self): # type: () -> None params = {"input": {"c": "foo", "d": "SerializedValue"}} check( self.doc, { "data": { "fieldWithObjectInput": stringify( {"c": "foo", "d": "DeserializedValue"} ) } }, params, ) def test_errors_on_null_for_nested_non_null(self): # type: () -> None params = {"input": {"a": "foo", "b": "bar", "c": None}} with raises(GraphQLError) as excinfo: check(self.doc, {}, params) assert format_error(excinfo.value) == { "locations": [{"column": 13, "line": 2}], "message": 'Variable "$input" got invalid value {}.\n' 'In field "c": Expected "String!", found null.'.format( stringify(params["input"]) ), } def test_errors_on_incorrect_type(self): # type: () -> None params = {"input": "foo bar"} with raises(GraphQLError) as excinfo: check(self.doc, {}, params) assert format_error(excinfo.value) == { "locations": [{"column": 13, "line": 2}], "message": 'Variable "$input" got invalid value {}.\n' 'Expected "TestInputObject", found not an object.'.format( stringify(params["input"]) ), } def test_errors_on_omission_of_nested_non_null(self): # type: () -> None params = {"input": {"a": "foo", "b": "bar"}} with raises(GraphQLError) as excinfo: check(self.doc, {}, params) assert format_error(excinfo.value) == { "locations": [{"column": 13, "line": 2}], "message": 'Variable "$input" got invalid value {}.\n' 'In field "c": Expected "String!", found null.'.format( stringify(params["input"]) ), } def test_errors_on_deep_nested_errors_and_with_many_errors(self): # type: () -> None nested_doc = """ query q($input: TestNestedInputObject) { fieldWithNestedObjectInput(input: $input) } """ params = {"input": {"na": {"a": "foo"}}} with raises(GraphQLError) as excinfo: check(nested_doc, {}, params) assert format_error(excinfo.value) == { "locations": [{"column": 19, "line": 2}], "message": 'Variable "$input" got invalid value {}.\n' 'In field "na": In field "c": Expected "String!", found null.\n' 'In field "nb": Expected "String!", found null.'.format( stringify(params["input"]) ), } def test_errors_on_addition_of_input_field_of_incorrect_type(self): # type: () -> None params = {"input": {"a": "foo", "b": "bar", "c": "baz", "d": "dog"}} with raises(GraphQLError) as excinfo: check(self.doc, {}, params) assert format_error(excinfo.value) == { "locations": [{"column": 13, "line": 2}], "message": 'Variable "$input" got invalid value {}.\n' 'In field "d": Expected type "ComplexScalar", found "dog".'.format( stringify(params["input"]) ), } def test_errors_on_addition_of_unknown_input_field(self): # type: () -> None params = {"input": {"a": "foo", "b": "bar", "c": "baz", "extra": "dog"}} with raises(GraphQLError) as excinfo: check(self.doc, {}, params) assert format_error(excinfo.value) == { "locations": [{"column": 13, "line": 2}], "message": 'Variable "$input" got invalid value {}.\n' 'In field "extra": Unknown field.'.format(stringify(params["input"])), } def test_allows_nullable_inputs_to_be_omitted(): # type: () -> None doc = "{ fieldWithNullableStringInput }" check(doc, {"data": {"fieldWithNullableStringInput": None}}) def test_allows_nullable_inputs_to_be_omitted_in_a_variable(): # type: () -> None doc = """ query SetsNullable($value: String) { fieldWithNullableStringInput(input: $value) } """ check(doc, {"data": {"fieldWithNullableStringInput": None}}) def test_allows_nullable_inputs_to_be_omitted_in_an_unlisted_variable(): # type: () -> None doc = """ query SetsNullable { fieldWithNullableStringInput(input: $value) } """ check(doc, {"data": {"fieldWithNullableStringInput": None}}) def test_allows_nullable_inputs_to_be_set_to_null_in_a_variable(): # type: () -> None doc = """ query SetsNullable($value: String) { fieldWithNullableStringInput(input: $value) } """ check(doc, {"data": {"fieldWithNullableStringInput": None}}, {"value": None}) def test_allows_nullable_inputs_to_be_set_to_a_value_in_a_variable(): # type: () -> None doc = """ query SetsNullable($value: String) { fieldWithNullableStringInput(input: $value) } """ check(doc, {"data": {"fieldWithNullableStringInput": '"a"'}}, {"value": "a"}) def test_allows_nullable_inputs_to_be_set_to_a_value_directly(): # type: () -> None doc = """ { fieldWithNullableStringInput(input: "a") } """ check(doc, {"data": {"fieldWithNullableStringInput": '"a"'}}) def test_does_not_allow_non_nullable_inputs_to_be_omitted_in_a_variable(): # type: () -> None doc = """ query SetsNonNullable($value: String!) { fieldWithNonNullableStringInput(input: $value) } """ with raises(GraphQLError) as excinfo: check(doc, {}) assert format_error(excinfo.value) == { "locations": [{"column": 27, "line": 2}], "message": 'Variable "$value" of required type "String!" was not provided.', } def test_does_not_allow_non_nullable_inputs_to_be_set_to_null_in_a_variable(): # type: () -> None doc = """ query SetsNonNullable($value: String!) { fieldWithNonNullableStringInput(input: $value) } """ with raises(GraphQLError) as excinfo: check(doc, {}, {"value": None}) assert format_error(excinfo.value) == { "locations": [{"column": 27, "line": 2}], "message": 'Variable "$value" of required type "String!" was not provided.', } def test_allows_non_nullable_inputs_to_be_set_to_a_value_in_a_variable(): # type: () -> None doc = """ query SetsNonNullable($value: String!) { fieldWithNonNullableStringInput(input: $value) } """ check(doc, {"data": {"fieldWithNonNullableStringInput": '"a"'}}, {"value": "a"}) def test_allows_non_nullable_inputs_to_be_set_to_a_value_directly(): # type: () -> None doc = """ { fieldWithNonNullableStringInput(input: "a") } """ check(doc, {"data": {"fieldWithNonNullableStringInput": '"a"'}}) def test_passes_along_null_for_non_nullable_inputs_if_explcitly_set_in_the_query(): # type: () -> None doc = """ { fieldWithNonNullableStringInput } """ check( doc, { "errors": [ { "message": 'Argument "input" of required type String!" was not provided.' } ], "data": None, }, ) def test_uses_objectinput_container(): # type: () -> None doc = """ { fieldWithCustomObjectInput(input: {a: "b"}) } """ check(doc, {"data": {"fieldWithCustomObjectInput": True}}) def test_allows_lists_to_be_null(): # type: () -> None doc = """ query q($input: [String]) { list(input: $input) } """ check(doc, {"data": {"list": None}}) def test_allows_lists_to_contain_values(): # type: () -> None doc = """ query q($input: [String]) { list(input: $input) } """ check(doc, {"data": {"list": stringify(["A"])}}, {"input": ["A"]}) def test_allows_lists_to_contain_null(): # type: () -> None doc = """ query q($input: [String]) { list(input: $input) } """ check( doc, {"data": {"list": stringify(["A", None, "B"])}}, {"input": ["A", None, "B"]}, ) def test_does_not_allow_non_null_lists_to_be_null(): # type: () -> None doc = """ query q($input: [String]!) { nnList(input: $input) } """ with raises(GraphQLError) as excinfo: check(doc, {}, {"input": None}) assert format_error(excinfo.value) == { "locations": [{"column": 13, "line": 2}], "message": 'Variable "$input" of required type "[String]!" was not provided.', } def test_allows_non_null_lists_to_contain_values(): # type: () -> None doc = """ query q($input: [String]!) { nnList(input: $input) } """ check(doc, {"data": {"nnList": stringify(["A"])}}, {"input": ["A"]}) def test_allows_non_null_lists_to_contain_null(): # type: () -> None doc = """ query q($input: [String]!) { nnList(input: $input) } """ check( doc, {"data": {"nnList": stringify(["A", None, "B"])}}, {"input": ["A", None, "B"]}, ) def test_allows_lists_of_non_nulls_to_be_null(): # type: () -> None doc = """ query q($input: [String!]) { listNN(input: $input) } """ check(doc, {"data": {"listNN": None}}, {"input": None}) def test_allows_lists_of_non_nulls_to_contain_values(): # type: () -> None doc = """ query q($input: [String!]) { listNN(input: $input) } """ check(doc, {"data": {"listNN": stringify(["A"])}}, {"input": ["A"]}) def test_does_not_allow_lists_of_non_nulls_to_contain_null(): # type: () -> None doc = """ query q($input: [String!]) { listNN(input: $input) } """ params = {"input": ["A", None, "B"]} with raises(GraphQLError) as excinfo: check(doc, {}, params) assert format_error(excinfo.value) == { "locations": [{"column": 13, "line": 2}], "message": 'Variable "$input" got invalid value {}.\n' 'In element #1: Expected "String!", found null.'.format( stringify(params["input"]) ), } def test_does_not_allow_non_null_lists_of_non_nulls_to_be_null(): # type: () -> None doc = """ query q($input: [String!]!) { nnListNN(input: $input) } """ with raises(GraphQLError) as excinfo: check(doc, {}, {"input": None}) assert format_error(excinfo.value) == { "locations": [{"column": 13, "line": 2}], "message": 'Variable "$input" of required type "[String!]!" was not provided.', } def test_allows_non_null_lists_of_non_nulls_to_contain_values(): # type: () -> None doc = """ query q($input: [String!]!) { nnListNN(input: $input) } """ check(doc, {"data": {"nnListNN": stringify(["A"])}}, {"input": ["A"]}) def test_does_not_allow_non_null_lists_of_non_nulls_to_contain_null(): # type: () -> None doc = """ query q($input: [String!]!) { nnListNN(input: $input) } """ params = {"input": ["A", None, "B"]} with raises(GraphQLError) as excinfo: check(doc, {}, params) assert format_error(excinfo.value) == { "locations": [{"column": 13, "line": 2}], "message": 'Variable "$input" got invalid value {}.\n' 'In element #1: Expected "String!", found null.'.format( stringify(params["input"]) ), } def test_does_not_allow_invalid_types_to_be_used_as_values(): # type: () -> None doc = """ query q($input: TestType!) { fieldWithObjectInput(input: $input) } """ params = {"input": {"list": ["A", "B"]}} with raises(GraphQLError) as excinfo: check(doc, {}, params) assert format_error(excinfo.value) == { "locations": [{"column": 13, "line": 2}], "message": 'Variable "$input" expected value of type "TestType!" which cannot be used as an input type.', } def test_does_not_allow_unknown_types_to_be_used_as_values(): # type: () -> None doc = """ query q($input: UnknownType!) { fieldWithObjectInput(input: $input) } """ params = {"input": "whoknows"} with raises(GraphQLError) as excinfo: check(doc, {}, params) assert format_error(excinfo.value) == { "locations": [{"column": 13, "line": 2}], "message": 'Variable "$input" expected value of type "UnknownType!" which cannot be used as an input type.', } # noinspection PyMethodMayBeStatic class TestUsesArgumentDefaultValues: def test_when_no_argument_provided(self): # type: () -> None check( "{ fieldWithDefaultArgumentValue }", {"data": {"fieldWithDefaultArgumentValue": '"Hello World"'}}, ) def test_when_nullable_variable_provided(self): # type: () -> None check( """ query optionalVariable($optional: String) { fieldWithDefaultArgumentValue(input: $optional) } """, {"data": {"fieldWithDefaultArgumentValue": '"Hello World"'}}, ) def test_when_argument_provided_cannot_be_parsed(self): # type: () -> None check( """ { fieldWithDefaultArgumentValue(input: WRONG_TYPE) } """, {"data": {"fieldWithDefaultArgumentValue": '"Hello World"'}}, ) graphql-core-legacy-2.3.2/graphql/execution/tests/utils.py000066400000000000000000000003501365661746200236770ustar00rootroot00000000000000from promise import Promise from typing import Any def resolved(value): # type: (Any) -> Promise return Promise.fulfilled(value) def rejected(error): # type: (Exception) -> Promise return Promise.rejected(error) graphql-core-legacy-2.3.2/graphql/execution/utils.py000066400000000000000000000313331365661746200225420ustar00rootroot00000000000000# -*- coding: utf-8 -*- import logging from traceback import format_exception from ..error import GraphQLError from ..language import ast from ..pyutils.default_ordered_dict import DefaultOrderedDict from ..type.definition import GraphQLInterfaceType, GraphQLUnionType from ..type.directives import GraphQLIncludeDirective, GraphQLSkipDirective from ..type.introspection import ( SchemaMetaFieldDef, TypeMetaFieldDef, TypeNameMetaFieldDef, ) from ..utils.type_from_ast import type_from_ast from .values import get_argument_values, get_variable_values # Necessary for static type checking if False: # flake8: noqa from ..type.definition import GraphQLObjectType, GraphQLField from ..type.schema import GraphQLSchema from ..language.ast import ( Document, OperationDefinition, SelectionSet, Directive, FragmentDefinition, InlineFragment, Field, ) from .base import ResolveInfo from types import TracebackType from typing import Any, List, Dict, Optional, Union, Callable, Set, Tuple logger = logging.getLogger(__name__) class ExecutionContext(object): """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""" __slots__ = ( "schema", "fragments", "root_value", "operation", "variable_values", "errors", "context_value", "argument_values_cache", "executor", "middleware", "allow_subscriptions", "_subfields_cache", ) def __init__( self, schema, # type: GraphQLSchema document_ast, # type: Document root_value, # type: Any context_value, # type: Any variable_values, # type: Optional[Dict[str, Any]] operation_name, # type: Optional[str] executor, # type: Any middleware, # type: Optional[Any] allow_subscriptions, # type: bool ): # type: (...) -> None """Constructs a ExecutionContext object from the arguments passed to execute, which we will pass throughout the other execution methods.""" errors = [] # type: List[Exception] operation = None fragments = {} # type: Dict[str, FragmentDefinition] for definition in document_ast.definitions: if isinstance(definition, ast.OperationDefinition): if not operation_name and operation: raise GraphQLError( "Must provide operation name if query contains multiple operations." ) if ( not operation_name or definition.name and definition.name.value == operation_name ): operation = definition elif isinstance(definition, ast.FragmentDefinition): fragments[definition.name.value] = definition else: raise GraphQLError( u"GraphQL cannot execute a request containing a {}.".format( definition.__class__.__name__ ), [definition], ) if not operation: if operation_name: raise GraphQLError( u'Unknown operation named "{}".'.format(operation_name) ) else: raise GraphQLError("Must provide an operation.") variable_values = get_variable_values( schema, operation.variable_definitions or [], variable_values ) self.schema = schema self.fragments = fragments self.root_value = root_value self.operation = operation self.variable_values = variable_values self.errors = errors self.context_value = context_value self.argument_values_cache = ( {} ) # type: Dict[Tuple[GraphQLField, Field], Dict[str, Any]] self.executor = executor self.middleware = middleware self.allow_subscriptions = allow_subscriptions self._subfields_cache = ( {} ) # type: Dict[Tuple[GraphQLObjectType, Tuple[Field, ...]], DefaultOrderedDict] def get_field_resolver(self, field_resolver): # type: (Callable) -> Callable if not self.middleware: return field_resolver return self.middleware.get_field_resolver(field_resolver) def get_argument_values(self, field_def, field_ast): # type: (GraphQLField, Field) -> Dict[str, Any] k = field_def, field_ast if k not in self.argument_values_cache: self.argument_values_cache[k] = get_argument_values( field_def.args, field_ast.arguments, self.variable_values ) return self.argument_values_cache[k] def report_error(self, error, traceback=None): # type: (Exception, Optional[TracebackType]) -> None exception = format_exception( type(error), error, getattr(error, "stack", None) or traceback ) logger.error("".join(exception)) self.errors.append(error) def get_sub_fields(self, return_type, field_asts): # type: (GraphQLObjectType, List[Field]) -> DefaultOrderedDict k = return_type, tuple(field_asts) if k not in self._subfields_cache: subfield_asts = DefaultOrderedDict(list) visited_fragment_names = set() # type: Set[str] for field_ast in field_asts: selection_set = field_ast.selection_set if selection_set: subfield_asts = collect_fields( self, return_type, selection_set, subfield_asts, visited_fragment_names, ) self._subfields_cache[k] = subfield_asts return self._subfields_cache[k] class SubscriberExecutionContext(object): __slots__ = "exe_context", "errors" def __init__(self, exe_context): # type: (ExecutionContext) -> None self.exe_context = exe_context self.errors = [] # type: List[Exception] def reset(self): # type: () -> None self.errors = [] def __getattr__(self, name): # type: (str) -> Any return getattr(self.exe_context, name) def get_operation_root_type(schema, operation): # type: (GraphQLSchema, OperationDefinition) -> GraphQLObjectType op = operation.operation if op == "query": return schema.get_query_type() elif op == "mutation": mutation_type = schema.get_mutation_type() if not mutation_type: raise GraphQLError("Schema is not configured for mutations", [operation]) return mutation_type elif op == "subscription": subscription_type = schema.get_subscription_type() if not subscription_type: raise GraphQLError( "Schema is not configured for subscriptions", [operation] ) return subscription_type raise GraphQLError( "Can only execute queries, mutations and subscriptions", [operation] ) def collect_fields( ctx, # type: ExecutionContext runtime_type, # type: GraphQLObjectType selection_set, # type: SelectionSet fields, # type: DefaultOrderedDict prev_fragment_names, # type: Set[str] ): # type: (...) -> DefaultOrderedDict """ Given a selectionSet, adds all of the fields in that selection to the passed in map of fields, and returns it at the end. collect_fields requires the "runtime type" of an object. For a field which returns and Interface or Union type, the "runtime type" will be the actual Object type returned by that field. """ for selection in selection_set.selections: directives = selection.directives if isinstance(selection, ast.Field): if not should_include_node(ctx, directives): continue name = get_field_entry_key(selection) fields[name].append(selection) elif isinstance(selection, ast.InlineFragment): if not should_include_node( ctx, directives ) or not does_fragment_condition_match(ctx, selection, runtime_type): continue collect_fields( ctx, runtime_type, selection.selection_set, fields, prev_fragment_names ) elif isinstance(selection, ast.FragmentSpread): frag_name = selection.name.value if frag_name in prev_fragment_names or not should_include_node( ctx, directives ): continue prev_fragment_names.add(frag_name) fragment = ctx.fragments[frag_name] frag_directives = fragment.directives if ( not fragment or not should_include_node(ctx, frag_directives) or not does_fragment_condition_match(ctx, fragment, runtime_type) ): continue collect_fields( ctx, runtime_type, fragment.selection_set, fields, prev_fragment_names ) return fields def should_include_node(ctx, directives): # type: (ExecutionContext, Optional[List[Directive]]) -> bool """Determines if a field should be included based on the @include and @skip directives, where @skip has higher precidence than @include.""" # TODO: Refactor based on latest code if directives: skip_ast = None for directive in directives: if directive.name.value == GraphQLSkipDirective.name: skip_ast = directive break if skip_ast: args = get_argument_values( GraphQLSkipDirective.args, skip_ast.arguments, ctx.variable_values ) if args.get("if") is True: return False include_ast = None for directive in directives: if directive.name.value == GraphQLIncludeDirective.name: include_ast = directive break if include_ast: args = get_argument_values( GraphQLIncludeDirective.args, include_ast.arguments, ctx.variable_values ) if args.get("if") is False: return False return True def does_fragment_condition_match( ctx, # type: ExecutionContext fragment, # type: Union[FragmentDefinition, InlineFragment] type_, # type: GraphQLObjectType ): # type: (...) -> bool type_condition_ast = fragment.type_condition if not type_condition_ast: return True conditional_type = type_from_ast(ctx.schema, type_condition_ast) if conditional_type.is_same_type(type_): return True if isinstance(conditional_type, (GraphQLInterfaceType, GraphQLUnionType)): return ctx.schema.is_possible_type(conditional_type, type_) return False def get_field_entry_key(node): # type: (Field) -> str """Implements the logic to compute the key of a given field's entry""" if node.alias: return node.alias.value return node.name.value def default_resolve_fn(source, info, **args): # type: (Any, ResolveInfo, **Any) -> Optional[Any] """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.""" name = info.field_name if isinstance(source, dict): property = source.get(name) else: property = getattr(source, name, None) if callable(property): return property() return property def get_field_def( schema, # type: GraphQLSchema parent_type, # type: GraphQLObjectType field_name, # type: str ): # type: (...) -> Optional[GraphQLField] """This method looks up the field on the given type defintion. It has special casing for the two introspection fields, __schema 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 could get automatically added to the query type, but that would require mutating type definitions, which would cause issues.""" if field_name == "__schema" and schema.get_query_type() == parent_type: return SchemaMetaFieldDef elif field_name == "__type" and schema.get_query_type() == parent_type: return TypeMetaFieldDef elif field_name == "__typename": return TypeNameMetaFieldDef return parent_type.fields.get(field_name) graphql-core-legacy-2.3.2/graphql/execution/values.py000066400000000000000000000155321365661746200227040ustar00rootroot00000000000000try: from collections.abc import Iterable except ImportError: # Python <3.3 from collections import Iterable import json from six import string_types from ..error import GraphQLError from ..language import ast from ..language.printer import print_ast from ..type import ( GraphQLEnumType, GraphQLInputObjectType, GraphQLList, GraphQLNonNull, GraphQLScalarType, is_input_type, ) from ..utils.is_valid_value import is_valid_value from ..utils.type_from_ast import type_from_ast from ..utils.value_from_ast import value_from_ast # Necessary for static type checking if False: # flake8: noqa from ..language.ast import VariableDefinition, Argument from ..type.schema import GraphQLSchema from ..type.definition import GraphQLArgument from typing import Any, List, Union, Dict, Optional __all__ = ["get_variable_values", "get_argument_values"] def get_variable_values( schema, # type: GraphQLSchema definition_asts, # type: List[VariableDefinition] inputs, # type: Any ): # type: (...) -> Dict[str, Any] """Prepares an object map of variables 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 thrown.""" if inputs is None: inputs = {} values = {} for def_ast in definition_asts: var_name = def_ast.variable.name.value var_type = type_from_ast(schema, def_ast.type) value = inputs.get(var_name) if not is_input_type(var_type): raise GraphQLError( 'Variable "${var_name}" expected value of type "{var_type}" which cannot be used as an input type.'.format( var_name=var_name, var_type=print_ast(def_ast.type) ), [def_ast], ) elif value is None: if def_ast.default_value is not None: values[var_name] = value_from_ast( def_ast.default_value, var_type ) # type: ignore if isinstance(var_type, GraphQLNonNull): raise GraphQLError( 'Variable "${var_name}" of required type "{var_type}" was not provided.'.format( var_name=var_name, var_type=var_type ), [def_ast], ) else: errors = is_valid_value(value, var_type) if errors: message = u"\n" + u"\n".join(errors) raise GraphQLError( 'Variable "${}" got invalid value {}.{}'.format( var_name, json.dumps(value, sort_keys=True), message ), [def_ast], ) coerced_value = coerce_value(var_type, value) if coerced_value is None: raise Exception("Should have reported error.") values[var_name] = coerced_value return values def get_argument_values( arg_defs, # type: Union[Dict[str, GraphQLArgument], Dict] arg_asts, # type: Optional[List[Argument]] variables=None, # type: Optional[Dict[str, Union[List, Dict, int, float, bool, str, None]]] ): # type: (...) -> Dict[str, Any] """Prepares an object map of argument values given a list of argument definitions and list of argument AST nodes.""" if not arg_defs: return {} if arg_asts: arg_ast_map = { arg.name.value: arg for arg in arg_asts } # type: Dict[str, Argument] else: arg_ast_map = {} result = {} for name, arg_def in arg_defs.items(): arg_type = arg_def.type arg_ast = arg_ast_map.get(name) if name not in arg_ast_map: if arg_def.default_value is not None: result[arg_def.out_name or name] = arg_def.default_value continue elif isinstance(arg_type, GraphQLNonNull): raise GraphQLError( 'Argument "{name}" of required type {arg_type}" was not provided.'.format( name=name, arg_type=arg_type ), arg_asts, ) elif isinstance(arg_ast.value, ast.Variable): # type: ignore variable_name = arg_ast.value.name.value # type: ignore if variables and variable_name in variables: result[arg_def.out_name or name] = variables[variable_name] elif arg_def.default_value is not None: result[arg_def.out_name or name] = arg_def.default_value elif isinstance(arg_type, GraphQLNonNull): raise GraphQLError( 'Argument "{name}" of required type {arg_type}" provided the variable "${variable_name}" which was not provided'.format( name=name, arg_type=arg_type, variable_name=variable_name ), arg_asts, ) continue else: value = value_from_ast(arg_ast.value, arg_type, variables) # type: ignore if value is None: if arg_def.default_value is not None: value = arg_def.default_value result[arg_def.out_name or name] = value else: # We use out_name as the output name for the # dict if exists result[arg_def.out_name or name] = value return result def coerce_value(type, value): # type: (Any, Any) -> Union[List, Dict, int, float, bool, str, None] """Given a type and any value, return a runtime value coerced to match the type.""" if isinstance(type, GraphQLNonNull): # Note: we're not checking that the result of coerceValue is # non-null. # We only call this function after calling isValidValue. return coerce_value(type.of_type, value) if value is None: return None if isinstance(type, GraphQLList): item_type = type.of_type if not isinstance(value, string_types) and isinstance(value, Iterable): return [coerce_value(item_type, item) for item in value] else: return [coerce_value(item_type, value)] if isinstance(type, GraphQLInputObjectType): fields = type.fields obj = {} for field_name, field in fields.items(): if field_name not in value: if field.default_value is not None: field_value = field.default_value obj[field.out_name or field_name] = field_value else: field_value = coerce_value(field.type, value.get(field_name)) obj[field.out_name or field_name] = field_value return type.create_container(obj) assert isinstance(type, (GraphQLScalarType, GraphQLEnumType)), "Must be input type" return type.parse_value(value) graphql-core-legacy-2.3.2/graphql/flags.py000066400000000000000000000005001365661746200204630ustar00rootroot00000000000000# This file makes it easier to know what are the features # the GraphQL-core API supports # This permits to plug different backend when executing graphql(...) BACKEND_EXECUTOR = True # This add a new path attribute to ResolveInfo, filled with the # path of the field where is being executed PATH_IN_RESOLVEINFO = True graphql-core-legacy-2.3.2/graphql/graphql.py000066400000000000000000000053071365661746200210370ustar00rootroot00000000000000from .execution import ExecutionResult from .backend import get_default_backend from promise import promisify # Necessary for static type checking if False: # flake8: noqa from promise import Promise from rx import Observable from typing import Any, Union, Optional from .language.ast import Document from .type.schema import GraphQLSchema # 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. # schema: # The GraphQL type system to use when validating and executing a query. # requestString: # A GraphQL language formatted string representing the requested operation. # rootValue: # The value provided as the first argument to resolver functions on the top # level type (e.g. the query object type). # variableValues: # A mapping of variable name to runtime value to use for all variables # defined in the requestString. # operationName: # The name of the operation to use if requestString contains multiple # possible operations. Can be omitted if requestString contains only # one operation. def graphql(*args, **kwargs): # type: (*Any, **Any) -> Union[ExecutionResult, Observable, Promise[ExecutionResult]] return_promise = kwargs.get("return_promise", False) if return_promise: return execute_graphql_as_promise(*args, **kwargs) else: return execute_graphql(*args, **kwargs) def execute_graphql( schema, # type: GraphQLSchema request_string="", # type: Union[Document, str] root_value=None, # type: Any context_value=None, # type: Optional[Any] variable_values=None, # type: Optional[Any] operation_name=None, # type: Optional[Any] middleware=None, # type: Optional[Any] backend=None, # type: Optional[Any] **execute_options # type: Any ): # type: (...) -> Union[ExecutionResult, Observable, Promise[ExecutionResult]] try: if backend is None: backend = get_default_backend() document = backend.document_from_string(schema, request_string) return document.execute( root_value, context_value, operation_name=operation_name, variable_values=variable_values, middleware=middleware, **execute_options ) except Exception as e: return ExecutionResult(errors=[e], invalid=True) @promisify def execute_graphql_as_promise(*args, **kwargs): return execute_graphql(*args, **kwargs) graphql-core-legacy-2.3.2/graphql/language/000077500000000000000000000000001365661746200206055ustar00rootroot00000000000000graphql-core-legacy-2.3.2/graphql/language/__init__.py000066400000000000000000000000001365661746200227040ustar00rootroot00000000000000graphql-core-legacy-2.3.2/graphql/language/ast.py000066400000000000000000001173531365661746200217600ustar00rootroot00000000000000# Necessary for static type checking if False: # flake8: noqa from .parser import Loc from typing import Any, Optional, Union, List, Iterable # This is autogenerated code. DO NOT change this manually. # Run scripts/generate_ast.py to generate this file. class Node(object): __slots__ = () _fields = () # type: Iterable[str] loc = None # type: Optional[Loc] class Definition(Node): __slots__ = () class Document(Node): __slots__ = ("loc", "definitions") _fields = ("definitions",) def __init__(self, definitions, loc=None): # type: (Any, Optional[Loc]) -> None self.loc = loc self.definitions = definitions def __eq__(self, other): # type: (Any) -> bool return self is other or ( isinstance(other, Document) and # self.loc == other.loc and self.definitions == other.definitions ) def __repr__(self): # type: () -> str return ("Document(" "definitions={self.definitions!r}" ")").format(self=self) def __copy__(self): # type: () -> Document return type(self)(self.definitions, self.loc) def __hash__(self): # type: () -> int return id(self) class OperationDefinition(Definition): __slots__ = ( "loc", "operation", "name", "variable_definitions", "directives", "selection_set", ) _fields = ( "operation", "name", "variable_definitions", "directives", "selection_set", ) def __init__( self, operation, # type: str selection_set, # type: SelectionSet name=None, # type: Optional[Name] # variable_definitions=None, # type: Optional[List[VariableDefinition]] directives=None, # type: Optional[List[Directive]] loc=None, # type: Optional[Loc] ): # type: (...) -> None self.loc = loc self.operation = operation self.name = name self.variable_definitions = variable_definitions self.directives = directives self.selection_set = selection_set def __eq__(self, other): # type: (Any) -> bool return self is other or ( isinstance(other, OperationDefinition) and # self.loc == other.loc and self.operation == other.operation and self.name == other.name and self.variable_definitions == other.variable_definitions and self.directives == other.directives and self.selection_set == other.selection_set ) def __repr__(self): # type: () -> str return ( "OperationDefinition(" "operation={self.operation!r}" ", name={self.name!r}" ", variable_definitions={self.variable_definitions!r}" ", directives={self.directives!r}" ", selection_set={self.selection_set!r}" ")" ).format(self=self) def __copy__(self): # type: () -> OperationDefinition return type(self)( self.operation, self.selection_set, self.name, self.variable_definitions, self.directives, self.loc, ) def __hash__(self): # type: () -> int return id(self) class VariableDefinition(Node): __slots__ = ("loc", "variable", "type", "default_value") _fields = ("variable", "type", "default_value") def __init__(self, variable, type, default_value=None, loc=None): # type: (Variable, Any, Any, Optional[Loc]) -> None self.loc = loc self.variable = variable self.type = type self.default_value = default_value def __eq__(self, other): # type: (Any) -> bool return self is other or ( isinstance(other, VariableDefinition) and # self.loc == other.loc and self.variable == other.variable and self.type == other.type and self.default_value == other.default_value ) def __repr__(self): # type: () -> str return ( "VariableDefinition(" "variable={self.variable!r}" ", type={self.type!r}" ", default_value={self.default_value!r}" ")" ).format(self=self) def __copy__(self): # type: () -> VariableDefinition return type(self)(self.variable, self.type, self.default_value, self.loc) def __hash__(self): # type: () -> int return id(self) class SelectionSet(Node): __slots__ = ("loc", "selections") _fields = ("selections",) def __init__(self, selections, loc=None): # type: (Any, Optional[Loc]) -> None self.loc = loc self.selections = selections def __eq__(self, other): # type: (Any) -> bool return self is other or ( isinstance(other, SelectionSet) and # self.loc == other.loc and self.selections == other.selections ) def __repr__(self): # type: () -> str return ("SelectionSet(" "selections={self.selections!r}" ")").format(self=self) def __copy__(self): # type: () -> SelectionSet return type(self)(self.selections, self.loc) def __hash__(self): # type: () -> int return id(self) class Selection(Node): __slots__ = () class Field(Selection): __slots__ = ("loc", "alias", "name", "arguments", "directives", "selection_set") _fields = ("alias", "name", "arguments", "directives", "selection_set") def __init__( self, name, # type: Name alias=None, # type: Optional[Name] arguments=None, # type: Optional[List[Argument]] directives=None, # type: Optional[List[Directive]] selection_set=None, # type: Optional[SelectionSet] loc=None, # type: Optional[Loc] ): # type: (...) -> None self.loc = loc self.alias = alias self.name = name self.arguments = arguments self.directives = directives self.selection_set = selection_set def __eq__(self, other): # type: (Any) -> bool return self is other or ( isinstance(other, Field) and # self.loc == other.loc and self.alias == other.alias and self.name == other.name and self.arguments == other.arguments and self.directives == other.directives and self.selection_set == other.selection_set ) def __repr__(self): # type: () -> str return ( "Field(" "alias={self.alias!r}" ", name={self.name!r}" ", arguments={self.arguments!r}" ", directives={self.directives!r}" ", selection_set={self.selection_set!r}" ")" ).format(self=self) def __copy__(self): # type: () -> Field return type(self)( self.name, self.alias, self.arguments, self.directives, self.selection_set, self.loc, ) def __hash__(self): # type: () -> int return id(self) class Argument(Node): __slots__ = ("loc", "name", "value") _fields = ("name", "value") def __init__(self, name, value, loc=None): # type: (Name, Any, Optional[Loc]) -> None self.loc = loc self.name = name self.value = value def __eq__(self, other): # type: (Any) -> bool return self is other or ( isinstance(other, Argument) and # self.loc == other.loc and self.name == other.name and self.value == other.value ) def __repr__(self): # type: () -> str return ("Argument(" "name={self.name!r}" ", value={self.value!r}" ")").format( self=self ) def __copy__(self): # type: () -> Argument return type(self)(self.name, self.value, self.loc) def __hash__(self): # type: () -> int return id(self) class FragmentSpread(Selection): __slots__ = ("loc", "name", "directives") _fields = ("name", "directives") def __init__( self, name, # type: Name directives=None, # type: List[Directive] loc=None, # type: Optional[Loc] ): # type: (...) -> None self.loc = loc self.name = name self.directives = directives def __eq__(self, other): # type: (Any) -> bool return self is other or ( isinstance(other, FragmentSpread) and # self.loc == other.loc and self.name == other.name and self.directives == other.directives ) def __repr__(self): # type: () -> str return ( "FragmentSpread(" "name={self.name!r}" ", directives={self.directives!r}" ")" ).format(self=self) def __copy__(self): # type: () -> FragmentSpread return type(self)(self.name, self.directives, self.loc) def __hash__(self): # type: () -> int return id(self) class InlineFragment(Selection): __slots__ = ("loc", "type_condition", "directives", "selection_set") _fields = ("type_condition", "directives", "selection_set") def __init__( self, type_condition, # type: Optional[NamedType] selection_set, # type: SelectionSet directives=None, # type: Optional[List[Directive]] loc=None, # type: Optional[Loc] ): # type: (...) -> None self.loc = loc self.type_condition = type_condition self.directives = directives self.selection_set = selection_set def __eq__(self, other): # type: (Any) -> bool return self is other or ( isinstance(other, InlineFragment) and # self.loc == other.loc and self.type_condition == other.type_condition and self.directives == other.directives and self.selection_set == other.selection_set ) def __repr__(self): # type: () -> str return ( "InlineFragment(" "type_condition={self.type_condition!r}" ", directives={self.directives!r}" ", selection_set={self.selection_set!r}" ")" ).format(self=self) def __copy__(self): # type: () -> InlineFragment return type(self)( self.type_condition, self.selection_set, self.directives, self.loc ) def __hash__(self): # type: () -> int return id(self) class FragmentDefinition(Definition): __slots__ = ("loc", "name", "type_condition", "directives", "selection_set") _fields = ("name", "type_condition", "directives", "selection_set") def __init__( self, name, # type: Name type_condition, # type: Optional[NamedType] selection_set, # type: SelectionSet directives=None, # type: Optional[List[Directive]] loc=None, # type: Optional[Loc] ): # type: (...) -> None self.loc = loc self.name = name self.type_condition = type_condition self.directives = directives self.selection_set = selection_set def __eq__(self, other): # type: (Any) -> bool return self is other or ( isinstance(other, FragmentDefinition) and # self.loc == other.loc and self.name == other.name and self.type_condition == other.type_condition and self.directives == other.directives and self.selection_set == other.selection_set ) def __repr__(self): # type: () -> str return ( "FragmentDefinition(" "name={self.name!r}" ", type_condition={self.type_condition!r}" ", directives={self.directives!r}" ", selection_set={self.selection_set!r}" ")" ).format(self=self) def __copy__(self): # type: () -> FragmentDefinition return type(self)( self.name, self.type_condition, self.selection_set, self.directives, self.loc, ) def __hash__(self): # type: () -> int return id(self) class Value(Node): __slots__ = () class Variable(Value): __slots__ = ("loc", "name") _fields = ("name",) def __init__(self, name, loc=None): # type: (Name, Optional[Loc]) -> None self.loc = loc self.name = name def __eq__(self, other): # type: (Any) -> bool return self is other or ( isinstance(other, Variable) and self.name == other.name # and self.loc == other.loc ) def __repr__(self): # type: () -> str return ("Variable(" "name={self.name!r}" ")").format(self=self) def __copy__(self): # type: () -> Variable return type(self)(self.name, self.loc) def __hash__(self): # type: () -> int return id(self) class IntValue(Value): __slots__ = ("loc", "value") _fields = ("value",) def __init__(self, value, loc=None): # type: (str, Optional[Loc]) -> None self.loc = loc self.value = value def __eq__(self, other): # type: (Any) -> bool return self is other or ( isinstance(other, IntValue) and # self.loc == other.loc and self.value == other.value ) def __repr__(self): # type: () -> str return ("IntValue(" "value={self.value!r}" ")").format(self=self) def __copy__(self): # type: () -> IntValue return type(self)(self.value, self.loc) def __hash__(self): # type: () -> int return id(self) class FloatValue(Value): __slots__ = ("loc", "value") _fields = ("value",) def __init__(self, value, loc=None): # type: (str, Optional[Any]) -> None self.loc = loc self.value = value def __eq__(self, other): # type: (Any) -> bool return self is other or ( isinstance(other, FloatValue) and # self.loc == other.loc and self.value == other.value ) def __repr__(self): # type: () -> str return ("FloatValue(" "value={self.value!r}" ")").format(self=self) def __copy__(self): # type: () -> FloatValue return type(self)(self.value, self.loc) def __hash__(self): # type: () -> int return id(self) class StringValue(Value): __slots__ = ("loc", "value") _fields = ("value",) def __init__(self, value, loc=None): # type: (str, Optional[Loc]) -> None self.loc = loc self.value = value def __eq__(self, other): # type: (Any) -> bool return self is other or ( isinstance(other, StringValue) and # self.loc == other.loc and self.value == other.value ) def __repr__(self): # type: () -> str return ("StringValue(" "value={self.value!r}" ")").format(self=self) def __copy__(self): # type: () -> StringValue return type(self)(self.value, self.loc) def __hash__(self): # type: () -> int return id(self) class BooleanValue(Value): __slots__ = ("loc", "value") _fields = ("value",) def __init__(self, value, loc=None): # type: (bool, Optional[Loc]) -> None self.loc = loc self.value = value def __eq__(self, other): # type: (Any) -> bool return self is other or ( isinstance(other, BooleanValue) and # self.loc == other.loc and self.value == other.value ) def __repr__(self): # type: () -> str return ("BooleanValue(" "value={self.value!r}" ")").format(self=self) def __copy__(self): # type: () -> BooleanValue return type(self)(self.value, self.loc) def __hash__(self): # type: () -> int return id(self) class EnumValue(Value): __slots__ = ("loc", "value") _fields = ("value",) def __init__(self, value, loc=None): # type: (str, Optional[Loc]) -> None self.loc = loc self.value = value def __eq__(self, other): # type: (Any) -> bool return self is other or ( isinstance(other, EnumValue) and # self.loc == other.loc and self.value == other.value ) def __repr__(self): # type: () -> str return ("EnumValue(" "value={self.value!r}" ")").format(self=self) def __copy__(self): # type: () -> EnumValue return type(self)(self.value, self.loc) def __hash__(self): # type: () -> int return id(self) class ListValue(Value): __slots__ = ("loc", "values") _fields = ("values",) def __init__(self, values, loc=None): # type: (Any, Optional[Loc]) -> None self.loc = loc self.values = values def __eq__(self, other): # type: (Any) -> bool return self is other or ( isinstance(other, ListValue) and # self.loc == other.loc and self.values == other.values ) def __repr__(self): # type: () -> str return ("ListValue(" "values={self.values!r}" ")").format(self=self) def __copy__(self): # type: () -> ListValue return type(self)(self.values, self.loc) def __hash__(self): # type: () -> int return id(self) class ObjectValue(Value): __slots__ = ("loc", "fields") _fields = ("fields",) def __init__(self, fields, loc=None): # type: (List[ObjectField], Optional[Loc]) -> None self.loc = loc self.fields = fields def __eq__(self, other): # type: (Any) -> bool return self is other or ( isinstance(other, ObjectValue) and # self.loc == other.loc and self.fields == other.fields ) def __repr__(self): # type: () -> str return ("ObjectValue(" "fields={self.fields!r}" ")").format(self=self) def __copy__(self): # type: () -> ObjectValue return type(self)(self.fields, self.loc) def __hash__(self): # type: () -> int return id(self) class ObjectField(Node): __slots__ = ("loc", "name", "value") _fields = ("name", "value") def __init__(self, name, value, loc=None): # type: (Name, Any, Optional[Loc]) -> None self.loc = loc self.name = name self.value = value def __eq__(self, other): # type: (Any) -> bool return self is other or ( isinstance(other, ObjectField) and # self.loc == other.loc and self.name == other.name and self.value == other.value ) def __repr__(self): # type: () -> str return ( "ObjectField(" "name={self.name!r}" ", value={self.value!r}" ")" ).format(self=self) def __copy__(self): # type: () -> ObjectField return type(self)(self.name, self.value, self.loc) def __hash__(self): # type: () -> int return id(self) class Directive(Node): __slots__ = ("loc", "name", "arguments") _fields = ("name", "arguments") def __init__( self, name, # type: Name arguments=None, # type: Optional[List[Argument]] loc=None, # type: Optional[Loc] ): # type: (...) -> None self.loc = loc self.name = name self.arguments = arguments def __eq__(self, other): # type: (Any) -> bool return self is other or ( isinstance(other, Directive) and # self.loc == other.loc and self.name == other.name and self.arguments == other.arguments ) def __repr__(self): # type: () -> str return ( "Directive(" "name={self.name!r}" ", arguments={self.arguments!r}" ")" ).format(self=self) def __copy__(self): # type: () -> Directive return type(self)(self.name, self.arguments, self.loc) def __hash__(self): # type: () -> int return id(self) class Type(Node): __slots__ = () class NamedType(Type): __slots__ = ("loc", "name") _fields = ("name",) def __init__(self, name, loc=None): # type: (Name, Optional[Loc]) -> None self.loc = loc self.name = name def __eq__(self, other): # type: (Any) -> bool return self is other or ( isinstance(other, NamedType) and # self.loc == other.loc and self.name == other.name ) def __repr__(self): # type: () -> str return ("NamedType(" "name={self.name!r}" ")").format(self=self) def __copy__(self): # type: () -> NamedType return type(self)(self.name, self.loc) def __hash__(self): # type: () -> int return id(self) class ListType(Type): __slots__ = ("loc", "type") _fields = ("type",) def __init__(self, type, loc=None): # type: (Union[NamedType, NonNullType], Optional[Loc]) -> None self.loc = loc self.type = type def __eq__(self, other): # type: (Any) -> bool return self is other or ( isinstance(other, ListType) and # self.loc == other.loc and self.type == other.type ) def __repr__(self): # type: () -> str return ("ListType(" "type={self.type!r}" ")").format(self=self) def __copy__(self): # type: () -> ListType return type(self)(self.type, self.loc) def __hash__(self): # type: () -> int return id(self) class NonNullType(Type): __slots__ = ("loc", "type") _fields = ("type",) def __init__(self, type, loc=None): # type: (Union[ListType, NamedType], Optional[Loc]) -> None self.loc = loc self.type = type def __eq__(self, other): # type: (Any) -> bool return self is other or ( isinstance(other, NonNullType) and # self.loc == other.loc and self.type == other.type ) def __repr__(self): # type: () -> str return ("NonNullType(" "type={self.type!r}" ")").format(self=self) def __copy__(self): # type: () -> NonNullType return type(self)(self.type, self.loc) def __hash__(self): # type: () -> int return id(self) class Name(Node): __slots__ = ("loc", "value") _fields = ("value",) def __init__(self, value, loc=None): # type: (str, Optional[Loc]) -> None self.loc = loc self.value = value def __eq__(self, other): # type: (Any) -> bool return self is other or ( isinstance(other, Name) and # self.loc == other.loc and self.value == other.value ) def __repr__(self): # type: () -> str return ("Name(" "value={self.value!r}" ")").format(self=self) def __copy__(self): # type: () -> Name return type(self)(self.value, self.loc) def __hash__(self): # type: () -> int return id(self) # Type System Definition class TypeDefinition(Node): pass class TypeSystemDefinition(TypeDefinition): pass class SchemaDefinition(TypeSystemDefinition): __slots__ = ("loc", "directives", "operation_types") _fields = ("operation_types",) def __init__( self, operation_types, # type: List[OperationTypeDefinition] loc=None, # type: Optional[Loc] directives=None, # type: Optional[List[Directive]] ): # type: (...) -> None self.operation_types = operation_types self.loc = loc self.directives = directives def __eq__(self, other): # type: (Any) -> bool return self is other or ( isinstance(other, SchemaDefinition) and self.operation_types == other.operation_types and self.directives == other.directives ) def __repr__(self): # type: () -> str return ( "SchemaDefinition(" "operation_types={self.operation_types!r}" ", directives={self.directives!r}" ")" ).format(self=self) def __copy__(self): # type: () -> SchemaDefinition return type(self)(self.operation_types, self.loc, self.directives) def __hash__(self): # type: () -> int return id(self) class OperationTypeDefinition(Node): __slots__ = ("loc", "operation", "type") _fields = ("operation", "type") def __init__(self, operation, type, loc=None): # type: (str, NamedType, Optional[Loc]) -> None self.operation = operation self.type = type self.loc = loc def __eq__(self, other): # type: (Any) -> bool return self is other or ( isinstance(other, OperationTypeDefinition) and self.operation == other.operation and self.type == other.type ) def __repr__(self): # type: () -> str return ( "OperationTypeDefinition(" "operation={self.operation!r}" ", type={self.type!r}" ")" ).format(self=self) def __copy__(self): # type: () -> OperationTypeDefinition return type(self)(self.operation, self.type, self.loc) def __hash__(self): # type: () -> int return id(self) class ObjectTypeDefinition(TypeDefinition): __slots__ = ("loc", "name", "interfaces", "directives", "fields") _fields = ("name", "interfaces", "fields") def __init__( self, name, # type: Name fields, # type: List[FieldDefinition] interfaces=None, # type: Optional[List[NamedType]] loc=None, # type: Optional[Loc] directives=None, # type: Optional[List[Directive]] ): # type: (...) -> None self.loc = loc self.name = name self.interfaces = interfaces self.fields = fields self.directives = directives def __eq__(self, other): # type: (Any) -> bool return self is other or ( isinstance(other, ObjectTypeDefinition) and # self.loc == other.loc and self.name == other.name and self.interfaces == other.interfaces and self.fields == other.fields and self.directives == other.directives ) def __repr__(self): # type: () -> str return ( "ObjectTypeDefinition(" "name={self.name!r}" ", interfaces={self.interfaces!r}" ", fields={self.fields!r}" ", directives={self.directives!r}" ")" ).format(self=self) def __copy__(self): # type: () -> ObjectTypeDefinition return type(self)( self.name, self.fields, self.interfaces, self.loc, self.directives ) def __hash__(self): # type: () -> int return id(self) class FieldDefinition(Node): __slots__ = ("loc", "name", "arguments", "type", "directives") _fields = ("name", "arguments", "type") def __init__( self, name, # type: Name arguments, # type: List[InputValueDefinition] type, # type: Union[NamedType, NonNullType, ListType] loc=None, # type: Optional[Loc] directives=None, # type: Optional[List] ): # type: (...) -> None self.loc = loc self.name = name self.arguments = arguments self.type = type self.directives = directives def __eq__(self, other): # type: (Any) -> bool return self is other or ( isinstance(other, FieldDefinition) and # self.loc == other.loc and self.name == other.name and self.arguments == other.arguments and self.type == other.type and self.directives == other.directives ) def __repr__(self): # type: () -> str return ( "FieldDefinition(" "name={self.name!r}" ", arguments={self.arguments!r}" ", type={self.type!r}" ")" ).format(self=self) def __copy__(self): # type: () -> FieldDefinition return type(self)( self.name, self.arguments, self.type, self.loc, self.directives ) def __hash__(self): # type: () -> int return id(self) class InputValueDefinition(Node): __slots__ = ("loc", "name", "type", "default_value", "directives") _fields = ("name", "type", "default_value") def __init__( self, name, # type: Name type, # type: Union[NamedType, NonNullType, ListType] default_value=None, # type: Any loc=None, # type: Optional[Loc] directives=None, # type: Optional[List] ): # type: (...) -> None self.loc = loc self.name = name self.type = type self.default_value = default_value self.directives = directives def __eq__(self, other): # type: (Any) -> bool return self is other or ( isinstance(other, InputValueDefinition) and # self.loc == other.loc and self.name == other.name and self.type == other.type and self.default_value == other.default_value and self.directives == other.directives ) def __repr__(self): # type: () -> str return ( "InputValueDefinition(" "name={self.name!r}" ", type={self.type!r}" ", default_value={self.default_value!r}" ", directives={self.directives!r}" ")" ).format(self=self) def __copy__(self): # type: () -> InputValueDefinition return type(self)( self.name, self.type, self.default_value, self.loc, self.directives ) def __hash__(self): # type: () -> int return id(self) class InterfaceTypeDefinition(TypeDefinition): __slots__ = ("loc", "name", "fields", "directives") _fields = ("name", "fields") def __init__( self, name, # type: Name fields, # type: List[FieldDefinition] loc=None, # type: Optional[Loc] directives=None, # type: Optional[List[Directive]] ): # type: (...) -> None self.loc = loc self.name = name self.fields = fields self.directives = directives def __eq__(self, other): # type: (Any) -> bool return self is other or ( isinstance(other, InterfaceTypeDefinition) and # self.loc == other.loc and self.name == other.name and self.fields == other.fields and self.directives == other.directives ) def __repr__(self): # type: () -> str return ( "InterfaceTypeDefinition(" "name={self.name!r}" ", fields={self.fields!r}" ", directives={self.directives!r}" ")" ).format(self=self) def __copy__(self): # type: () -> InterfaceTypeDefinition return type(self)(self.name, self.fields, self.loc, self.directives) def __hash__(self): # type: () -> int return id(self) class UnionTypeDefinition(TypeDefinition): __slots__ = ("loc", "name", "types", "directives") _fields = ("name", "types") def __init__( self, name, # type: Name types, # type: List[NamedType] loc=None, # type: Optional[Loc] directives=None, # type: Optional[List[Directive]] ): # type: (...) -> None self.loc = loc self.name = name self.types = types self.directives = directives def __eq__(self, other): # type: (Any) -> bool return self is other or ( isinstance(other, UnionTypeDefinition) and # self.loc == other.loc and self.name == other.name and self.types == other.types and self.directives == other.directives ) def __repr__(self): # type: () -> str return ( "UnionTypeDefinition(" "name={self.name!r}" ", types={self.types!r}" ", directives={self.directives!r}" ")" ).format(self=self) def __copy__(self): # type: () -> UnionTypeDefinition return type(self)(self.name, self.types, self.loc, self.directives) def __hash__(self): # type: () -> int return id(self) class ScalarTypeDefinition(TypeDefinition): __slots__ = ("loc", "name", "directives") _fields = ("name",) def __init__( self, name, # type: Name loc=None, # type: Optional[Loc] directives=None, # type: Optional[List[Directive]] ): # type: (...) -> None self.loc = loc self.name = name self.directives = directives def __eq__(self, other): # type: (Any) -> bool return self is other or ( isinstance(other, ScalarTypeDefinition) and # self.loc == other.loc and self.name == other.name and self.directives == other.directives ) def __repr__(self): # type: () -> str return ( "ScalarTypeDefinition(" "name={self.name!r}" "directives={self.directives!r}" ")" ).format(self=self) def __copy__(self): # type: () -> ScalarTypeDefinition return type(self)(self.name, self.loc, self.directives) def __hash__(self): # type: () -> int return id(self) class EnumTypeDefinition(TypeDefinition): __slots__ = ("loc", "name", "values", "directives") _fields = ("name", "values") def __init__( self, name, # type: Name values, # type: List[EnumValueDefinition] loc=None, # type: Optional[Loc] directives=None, # type: Optional[List[Directive]] ): # type: (...) -> None self.loc = loc self.name = name self.values = values self.directives = directives def __eq__(self, other): # type: (Any) -> bool return self is other or ( isinstance(other, EnumTypeDefinition) and # self.loc == other.loc and self.name == other.name and self.values == other.values and self.directives == other.directives ) def __repr__(self): # type: () -> str return ( "EnumTypeDefinition(" "name={self.name!r}" ", values={self.values!r}" ", directives={self.directives!r}" ")" ).format(self=self) def __copy__(self): # type: () -> EnumTypeDefinition return type(self)(self.name, self.values, self.loc, self.directives) def __hash__(self): # type: () -> int return id(self) class EnumValueDefinition(Node): __slots__ = ("loc", "name", "directives") _fields = ("name",) def __init__( self, name, # type: Name loc=None, # type: Optional[Loc] directives=None, # type: Optional[List[Directive]] ): # type: (...) -> None self.loc = loc self.name = name self.directives = directives def __eq__(self, other): # type: (Any) -> bool return self is other or ( isinstance(other, EnumValueDefinition) and # self.loc == other.loc and self.name == other.name and self.directives == other.directives ) def __repr__(self): # type: () -> str return ( "EnumValueDefinition(" "name={self.name!r}" ", directives={self.directives!r}" ")" ).format(self=self) def __copy__(self): # type: () -> EnumValueDefinition return type(self)(self.name, self.loc, self.directives) def __hash__(self): # type: () -> int return id(self) class InputObjectTypeDefinition(TypeDefinition): __slots__ = ("loc", "name", "fields", "directives") _fields = ("name", "fields") def __init__( self, name, # type: Name fields, # type: List[InputValueDefinition] loc=None, # type: Optional[Loc] directives=None, # type: Optional[List[Directive]] ): # type: (...) -> None self.loc = loc self.name = name self.fields = fields self.directives = directives def __eq__(self, other): # type: (Any) -> bool return self is other or ( isinstance(other, InputObjectTypeDefinition) and # self.loc == other.loc and self.name == other.name and self.fields == other.fields and self.directives == other.directives ) def __repr__(self): # type: () -> str return ( "InputObjectTypeDefinition(" "name={self.name!r}" ", fields={self.fields!r}" ", directives={self.directives!r}" ")" ).format(self=self) def __copy__(self): # type: () -> InputObjectTypeDefinition return type(self)(self.name, self.fields, self.loc, self.directives) def __hash__(self): # type: () -> int return id(self) class TypeExtensionDefinition(TypeSystemDefinition): __slots__ = ("loc", "definition") _fields = ("definition",) def __init__(self, definition, loc=None): # type: (ObjectTypeDefinition, Optional[Loc]) -> None self.loc = loc self.definition = definition def __eq__(self, other): # type: (Any) -> bool return self is other or ( isinstance(other, TypeExtensionDefinition) and # self.loc == other.loc and self.definition == other.definition ) def __repr__(self): # type: () -> str return ("TypeExtensionDefinition(" "definition={self.definition!r}" ")").format( self=self ) def __copy__(self): # type: () -> TypeExtensionDefinition return type(self)(self.definition, self.loc) def __hash__(self): # type: () -> int return id(self) class DirectiveDefinition(TypeSystemDefinition): __slots__ = ("loc", "name", "arguments", "locations") _fields = ("name", "locations") def __init__( self, name, # type: Name locations, # type: List[Name] arguments=None, # type: Optional[List[InputValueDefinition]] loc=None, # type: Optional[Loc] ): # type: (...) -> None self.name = name self.locations = locations self.loc = loc self.arguments = arguments def __eq__(self, other): # type: (Any) -> bool return self is other or ( isinstance(other, DirectiveDefinition) and self.name == other.name and self.locations == other.locations and # self.loc == other.loc and self.arguments == other.arguments ) def __repr__(self): # type: () -> str return ( "DirectiveDefinition(" "name={self.name!r}, " "locations={self.locations!r}" ")" ).format(self=self) def __copy__(self): # type: () -> DirectiveDefinition return type(self)(self.name, self.locations, self.arguments, self.loc) def __hash__(self): # type: () -> int return id(self) graphql-core-legacy-2.3.2/graphql/language/base.py000066400000000000000000000006301365661746200220700ustar00rootroot00000000000000from .lexer import Lexer from .location import get_location from .parser import parse, parse_value from .printer import print_ast from .source import Source from .visitor import BREAK, ParallelVisitor, TypeInfoVisitor, visit __all__ = [ "Lexer", "get_location", "parse", "parse_value", "print_ast", "Source", "BREAK", "ParallelVisitor", "TypeInfoVisitor", "visit", ] graphql-core-legacy-2.3.2/graphql/language/lexer.py000066400000000000000000000310351365661746200223000ustar00rootroot00000000000000import json from six import unichr from ..error import GraphQLSyntaxError # Necessary for static type checking if False: # flake8: noqa from typing import Optional, Any, List from .source import Source __all__ = ["Token", "Lexer", "TokenKind", "get_token_desc", "get_token_kind_desc"] class Token(object): __slots__ = "kind", "start", "end", "value" def __init__(self, kind, start, end, value=None): # type: (int, int, int, Optional[str]) -> None self.kind = kind self.start = start self.end = end self.value = value def __repr__(self): # type: () -> str return u"".format( get_token_kind_desc(self.kind), self.start, self.end, repr(self.value) ) def __eq__(self, other): # type: (Any) -> bool return ( isinstance(other, Token) and self.kind == other.kind and self.start == other.start and self.end == other.end and self.value == other.value ) class Lexer(object): __slots__ = "source", "prev_position" def __init__(self, source): # type: (Source) -> None self.source = source self.prev_position = 0 def next_token(self, reset_position=None): # type: (Optional[int]) -> Token if reset_position is None: reset_position = self.prev_position token = read_token(self.source, reset_position) self.prev_position = token.end return token class TokenKind(object): EOF = 1 BANG = 2 DOLLAR = 3 PAREN_L = 4 PAREN_R = 5 SPREAD = 6 COLON = 7 EQUALS = 8 AT = 9 BRACKET_L = 10 BRACKET_R = 11 BRACE_L = 12 PIPE = 13 BRACE_R = 14 NAME = 15 VARIABLE = 16 INT = 17 FLOAT = 18 STRING = 19 def get_token_desc(token): # type: (Token) -> str if token.value: return u'{} "{}"'.format(get_token_kind_desc(token.kind), token.value) else: return get_token_kind_desc(token.kind) def get_token_kind_desc(kind): # type: (int) -> str return TOKEN_DESCRIPTION[kind] TOKEN_DESCRIPTION = { TokenKind.EOF: "EOF", TokenKind.BANG: "!", TokenKind.DOLLAR: "$", 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: "}", TokenKind.NAME: "Name", TokenKind.VARIABLE: "Variable", TokenKind.INT: "Int", TokenKind.FLOAT: "Float", TokenKind.STRING: "String", } def char_code_at(s, pos): # type: (str, int) -> Optional[int] if 0 <= pos < len(s): return ord(s[pos]) return None PUNCT_CODE_TO_KIND = { ord("!"): TokenKind.BANG, ord("$"): TokenKind.DOLLAR, ord("("): TokenKind.PAREN_L, ord(")"): TokenKind.PAREN_R, ord(":"): TokenKind.COLON, ord("="): TokenKind.EQUALS, ord("@"): TokenKind.AT, ord("["): TokenKind.BRACKET_L, ord("]"): TokenKind.BRACKET_R, ord("{"): TokenKind.BRACE_L, ord("|"): TokenKind.PIPE, ord("}"): TokenKind.BRACE_R, } def print_char_code(code): # type: (Optional[int]) -> str if code is None: return "" if code < 0x007F: return json.dumps(unichr(code)) return '"\\u%04X"' % code def read_token(source, from_position): # type: (Source, int) -> Token """Gets the next token from the source starting at the given position. This skips over whitespace and comments until it finds the next lexable token, then lexes punctuators immediately or calls the appropriate helper fucntion for more complicated tokens.""" body = source.body body_length = len(body) position = position_after_whitespace(body, from_position) if position >= body_length: return Token(TokenKind.EOF, position, position) code = char_code_at(body, position) if code: if code < 0x0020 and code not in (0x0009, 0x000A, 0x000D): raise GraphQLSyntaxError( source, position, u"Invalid character {}.".format(print_char_code(code)) ) kind = PUNCT_CODE_TO_KIND.get(code) if kind is not None: return Token(kind, position, position + 1) if code == 46: # . if ( char_code_at(body, position + 1) == char_code_at(body, position + 2) == 46 ): return Token(TokenKind.SPREAD, position, position + 3) elif 65 <= code <= 90 or code == 95 or 97 <= code <= 122: # A-Z, _, a-z return read_name(source, position) elif code == 45 or 48 <= code <= 57: # -, 0-9 return read_number(source, position, code) elif code == 34: # " return read_string(source, position) raise GraphQLSyntaxError( source, position, u"Unexpected character {}.".format(print_char_code(code)) ) ignored_whitespace_characters = frozenset( [ # BOM 0xFEFF, # White Space 0x0009, # tab 0x0020, # space # Line Terminator 0x000A, # new line 0x000D, # carriage return # Comma 0x002C, ] ) def position_after_whitespace(body, start_position): # type: (str, int) -> int """Reads from body starting at start_position until it finds a non-whitespace or commented character, then returns the position of that character for lexing.""" body_length = len(body) position = start_position while position < body_length: code = char_code_at(body, position) if code in ignored_whitespace_characters: position += 1 elif code == 35: # #, skip comments position += 1 while position < body_length: code = char_code_at(body, position) if not ( code is not None and (code > 0x001F or code == 0x0009) and code not in (0x000A, 0x000D) ): break position += 1 else: break return position def read_number(source, start, first_code): # type: (Source, int, Optional[int]) -> Token r"""Reads a number token from the source file, either a float or an int depending on whether a decimal point appears. Int: -?(0|[1-9][0-9]*) Float: -?(0|[1-9][0-9]*)(\.[0-9]+)?((E|e)(+|-)?[0-9]+)?""" code = first_code body = source.body position = start is_float = False if code == 45: # - position += 1 code = char_code_at(body, position) if code == 48: # 0 position += 1 code = char_code_at(body, position) if code is not None and 48 <= code <= 57: raise GraphQLSyntaxError( source, position, u"Invalid number, unexpected digit after 0: {}.".format( print_char_code(code) ), ) else: position = read_digits(source, position, code) code = char_code_at(body, position) if code == 46: # . is_float = True position += 1 code = char_code_at(body, position) position = read_digits(source, position, code) code = char_code_at(body, position) if code in (69, 101): # E e is_float = True position += 1 code = char_code_at(body, position) if code in (43, 45): # + - position += 1 code = char_code_at(body, position) position = read_digits(source, position, code) return Token( TokenKind.FLOAT if is_float else TokenKind.INT, start, position, body[start:position], ) def read_digits(source, start, first_code): # type: (Source, int, Optional[int]) -> int body = source.body position = start code = first_code if code is not None and 48 <= code <= 57: # 0 - 9 while True: position += 1 code = char_code_at(body, position) if not (code is not None and 48 <= code <= 57): break return position raise GraphQLSyntaxError( source, position, u"Invalid number, expected digit but got: {}.".format(print_char_code(code)), ) ESCAPED_CHAR_CODES = { 34: '"', 47: "/", 92: "\\", 98: "\b", 102: "\f", 110: "\n", 114: "\r", 116: "\t", } def read_string(source, start): # type: (Source, int) -> Token """Reads a string token from the source file. "([^"\\\u000A\u000D\u2028\u2029]|(\\(u[0-9a-fA-F]{4}|["\\/bfnrt])))*" """ body = source.body body_length = len(body) position = start + 1 chunk_start = position code = 0 # type: Optional[int] value = [] # type: List[str] append = value.append while position < body_length: code = char_code_at(body, position) if code in ( None, # LineTerminator 0x000A, 0x000D, # Quote 34, ): break if code < 0x0020 and code != 0x0009: # type: ignore raise GraphQLSyntaxError( source, position, u"Invalid character within String: {}.".format(print_char_code(code)), ) position += 1 if code == 92: # \ append(body[chunk_start : position - 1]) code = char_code_at(body, position) escaped = ESCAPED_CHAR_CODES.get(code) # type: ignore if escaped is not None: append(escaped) elif code == 117: # u char_code = uni_char_code( char_code_at(body, position + 1) or 0, char_code_at(body, position + 2) or 0, char_code_at(body, position + 3) or 0, char_code_at(body, position + 4) or 0, ) if char_code < 0: raise GraphQLSyntaxError( source, position, u"Invalid character escape sequence: \\u{}.".format( body[position + 1 : position + 5] ), ) append(unichr(char_code)) position += 4 else: raise GraphQLSyntaxError( source, position, u"Invalid character escape sequence: \\{}.".format( unichr(code) # type: ignore ), ) position += 1 chunk_start = position if code != 34: # Quote (") raise GraphQLSyntaxError(source, position, "Unterminated string") append(body[chunk_start:position]) return Token(TokenKind.STRING, start, position + 1, u"".join(value)) def uni_char_code(a, b, c, d): # type: (int, int, int, int) -> int """Converts four hexidecimal chars to the integer that the string represents. For example, uniCharCode('0','0','0','f') will return 15, and uniCharCode('0','0','f','f') returns 255. Returns a negative number on error, if a char was invalid. This is implemented by noting that char2hex() returns -1 on error, which means the result of ORing the char2hex() will also be negative. """ return char2hex(a) << 12 | char2hex(b) << 8 | char2hex(c) << 4 | char2hex(d) def char2hex(a): # type: (int) -> int """Converts a hex character to its integer value. '0' becomes 0, '9' becomes 9 'A' becomes 10, 'F' becomes 15 'a' becomes 10, 'f' becomes 15 Returns -1 on error.""" if 48 <= a <= 57: # 0-9 return a - 48 elif 65 <= a <= 70: # A-F return a - 55 elif 97 <= a <= 102: # a-f return a - 87 return -1 def read_name(source, position): # type: (Source, int) -> Token """Reads an alphanumeric + underscore name from the source. [_A-Za-z][_0-9A-Za-z]*""" body = source.body body_length = len(body) end = position + 1 while end != body_length: code = char_code_at(body, end) if not ( code is not None and ( code == 95 or 48 <= code <= 57 # _ or 65 <= code <= 90 # 0-9 or 97 <= code <= 122 # A-Z # a-z ) ): break end += 1 return Token(TokenKind.NAME, position, end, body[position:end]) graphql-core-legacy-2.3.2/graphql/language/location.py000066400000000000000000000017531365661746200227750ustar00rootroot00000000000000# Necessary for static type checking if False: # flake8: noqa from .source import Source from typing import Any __all__ = ["get_location", "SourceLocation"] class SourceLocation(object): __slots__ = "line", "column" def __init__(self, line, column): # type: (int, int) -> None self.line = line self.column = column def __repr__(self): # type: () -> str return "SourceLocation(line={}, column={})".format(self.line, self.column) def __eq__(self, other): # type: (Any) -> bool return ( isinstance(other, SourceLocation) and self.line == other.line and self.column == other.column ) def get_location(source, position): # type: (Source, int) -> SourceLocation lines = source.body[:position].splitlines() if lines: line = len(lines) column = len(lines[-1]) + 1 else: line = 1 column = 1 return SourceLocation(line, column) graphql-core-legacy-2.3.2/graphql/language/parser.py000066400000000000000000000601131365661746200224540ustar00rootroot00000000000000from six import string_types from . import ast from ..error import GraphQLSyntaxError from .lexer import Lexer, TokenKind, get_token_desc, get_token_kind_desc from .source import Source # Necessary for static type checking if False: # flake8: noqa from typing import Dict, Union, Any, Optional, Callable, List from .lexer import Token from .ast import ( Document, Name, OperationDefinition, VariableDefinition, Variable, SelectionSet, Field, FragmentSpread, Argument, InlineFragment, FragmentDefinition, IntValue, StringValue, BooleanValue, ObjectValue, ListValue, ObjectField, Directive, NamedType, NonNullType, ListType, SchemaDefinition, OperationTypeDefinition, ScalarTypeDefinition, ObjectTypeDefinition, FieldDefinition, InputValueDefinition, InterfaceTypeDefinition, UnionTypeDefinition, EnumTypeDefinition, EnumValueDefinition, InputObjectTypeDefinition, TypeExtensionDefinition, DirectiveDefinition, ) __all__ = ["parse"] def parse(source, **kwargs): # type: (Union[Source, str], **Any) -> Document """Given a GraphQL source, parses it into a Document.""" options = {"no_location": False, "no_source": False} options.update(kwargs) if isinstance(source, string_types): source_obj = Source(source) # type: Source else: source_obj = source # type: ignore parser = Parser(source_obj, options) return parse_document(parser) def parse_value(source, **kwargs): options = {"no_location": False, "no_source": False} options.update(kwargs) source_obj = source if isinstance(source, string_types): source_obj = Source(source) parser = Parser(source_obj, options) return parse_value_literal(parser, False) class Parser(object): __slots__ = "lexer", "source", "options", "prev_end", "token" def __init__(self, source, options): # type: (Source, Dict[str, bool]) -> None self.lexer = Lexer(source) self.source = source self.options = options self.prev_end = 0 self.token = self.lexer.next_token() class Loc(object): __slots__ = "start", "end", "source" def __init__(self, start, end, source=None): # type: (int, int, Union[Source, str]) -> None self.start = start self.end = end self.source = source def __repr__(self): # type: () -> str source = " source={}".format(self.source) if self.source else "" return "".format(self.start, self.end, source) def __eq__(self, other): return ( isinstance(other, Loc) and self.start == other.start and self.end == other.end and self.source == other.source ) def loc(parser, start): # type: (Parser, int) -> Optional[Loc] """Returns a location object, used to identify the place in the source that created a given parsed object.""" if parser.options["no_location"]: return None if parser.options["no_source"]: return Loc(start, parser.prev_end) return Loc(start, parser.prev_end, parser.source) def advance(parser): # type: (Parser) -> None """Moves the internal parser object to the next lexed token.""" prev_end = parser.token.end parser.prev_end = prev_end parser.token = parser.lexer.next_token(prev_end) def peek(parser, kind): # type: (Parser, int) -> bool """Determines if the next token is of a given kind""" return parser.token.kind == kind def skip(parser, kind): # type: (Parser, int) -> bool """If the next token is of the given kind, return true after advancing the parser. Otherwise, do not change the parser state and throw an error.""" match = parser.token.kind == kind if match: advance(parser) return match def expect(parser, kind): # type: (Parser, int) -> Token """If the next token is of the given kind, return that token after advancing the parser. Otherwise, do not change the parser state and return False.""" token = parser.token if token.kind == kind: advance(parser) return token raise GraphQLSyntaxError( parser.source, token.start, u"Expected {}, found {}".format( get_token_kind_desc(kind), get_token_desc(token) ), ) def expect_keyword(parser, value): # type: (Parser, str) -> Token """If the next token is a keyword with the given value, return that token after advancing the parser. Otherwise, do not change the parser state and return False.""" token = parser.token if token.kind == TokenKind.NAME and token.value == value: advance(parser) return token raise GraphQLSyntaxError( parser.source, token.start, u'Expected "{}", found {}'.format(value, get_token_desc(token)), ) def unexpected(parser, at_token=None): # type: (Parser, Optional[Any]) -> GraphQLSyntaxError """Helper function for creating an error when an unexpected lexed token is encountered.""" token = at_token or parser.token return GraphQLSyntaxError( parser.source, token.start, u"Unexpected {}".format(get_token_desc(token)) ) def any(parser, open_kind, parse_fn, close_kind): # type: (Parser, int, Callable, int) -> Any """Returns a possibly empty list of parse nodes, determined by the parse_fn. This list begins with a lex token of openKind and ends with a lex token of closeKind. Advances the parser to the next lex token after the closing token.""" expect(parser, open_kind) nodes = [] while not skip(parser, close_kind): nodes.append(parse_fn(parser)) return nodes def many(parser, open_kind, parse_fn, close_kind): # type: (Parser, int, Callable, int) -> Any """Returns a non-empty list of parse nodes, determined by the parse_fn. This list begins with a lex token of openKind and ends with a lex token of closeKind. Advances the parser to the next lex token after the closing token.""" expect(parser, open_kind) nodes = [parse_fn(parser)] while not skip(parser, close_kind): nodes.append(parse_fn(parser)) return nodes def parse_name(parser): # type: (Parser) -> Name """Converts a name lex token into a name parse node.""" token = expect(parser, TokenKind.NAME) return ast.Name(value=token.value, loc=loc(parser, token.start)) # type: ignore # Implements the parsing rules in the Document section. def parse_document(parser): # type: (Parser) -> Document start = parser.token.start definitions = [] while True: definitions.append(parse_definition(parser)) if skip(parser, TokenKind.EOF): break return ast.Document(definitions=definitions, loc=loc(parser, start)) def parse_definition(parser): # type: (Parser) -> Any if peek(parser, TokenKind.BRACE_L): return parse_operation_definition(parser) if peek(parser, TokenKind.NAME): name = parser.token.value if name in ("query", "mutation", "subscription"): return parse_operation_definition(parser) elif name == "fragment": return parse_fragment_definition(parser) elif name in ( "schema", "scalar", "type", "interface", "union", "enum", "input", "extend", "directive", ): return parse_type_system_definition(parser) raise unexpected(parser) # Implements the parsing rules in the Operations section. def parse_operation_definition(parser): # type: (Parser) -> OperationDefinition start = parser.token.start if peek(parser, TokenKind.BRACE_L): return ast.OperationDefinition( operation="query", name=None, variable_definitions=None, directives=[], selection_set=parse_selection_set(parser), loc=loc(parser, start), ) operation = parse_operation_type(parser) name = None if peek(parser, TokenKind.NAME): name = parse_name(parser) return ast.OperationDefinition( operation=operation, name=name, variable_definitions=parse_variable_definitions(parser), directives=parse_directives(parser), selection_set=parse_selection_set(parser), loc=loc(parser, start), ) def parse_operation_type(parser): # type: (Parser) -> str operation_token = expect(parser, TokenKind.NAME) operation = operation_token.value if operation == "query": return "query" elif operation == "mutation": return "mutation" elif operation == "subscription": return "subscription" raise unexpected(parser, operation_token) def parse_variable_definitions(parser): # type: (Parser) -> List[VariableDefinition] if peek(parser, TokenKind.PAREN_L): return many( parser, TokenKind.PAREN_L, parse_variable_definition, TokenKind.PAREN_R ) return [] def parse_variable_definition(parser): # type: (Parser) -> VariableDefinition start = parser.token.start return ast.VariableDefinition( variable=parse_variable(parser), type=expect(parser, TokenKind.COLON) and parse_type(parser), default_value=parse_value_literal(parser, True) if skip(parser, TokenKind.EQUALS) else None, loc=loc(parser, start), ) def parse_variable(parser): # type: (Parser) -> Variable start = parser.token.start expect(parser, TokenKind.DOLLAR) return ast.Variable(name=parse_name(parser), loc=loc(parser, start)) def parse_selection_set(parser): # type: (Parser) -> SelectionSet start = parser.token.start return ast.SelectionSet( selections=many(parser, TokenKind.BRACE_L, parse_selection, TokenKind.BRACE_R), loc=loc(parser, start), ) def parse_selection(parser): # type: (Parser) -> Union[Field, FragmentSpread, InlineFragment] if peek(parser, TokenKind.SPREAD): return parse_fragment(parser) else: return parse_field(parser) def parse_field(parser): # type: (Parser) -> Field # Corresponds to both Field and Alias in the spec start = parser.token.start name_or_alias = parse_name(parser) if skip(parser, TokenKind.COLON): alias = name_or_alias name = parse_name(parser) else: alias = None # type: ignore name = name_or_alias return ast.Field( alias=alias, name=name, arguments=parse_arguments(parser), directives=parse_directives(parser), selection_set=parse_selection_set(parser) if peek(parser, TokenKind.BRACE_L) else None, loc=loc(parser, start), ) def parse_arguments(parser): # type: (Parser) -> List[Argument] if peek(parser, TokenKind.PAREN_L): return many(parser, TokenKind.PAREN_L, parse_argument, TokenKind.PAREN_R) return [] def parse_argument(parser): # type: (Parser) -> Argument start = parser.token.start return ast.Argument( name=parse_name(parser), value=expect(parser, TokenKind.COLON) and parse_value_literal(parser, False), loc=loc(parser, start), ) # Implements the parsing rules in the Fragments section. def parse_fragment(parser): # type: (Parser) -> Union[FragmentSpread, InlineFragment] # Corresponds to both FragmentSpread and InlineFragment in the spec start = parser.token.start expect(parser, TokenKind.SPREAD) if peek(parser, TokenKind.NAME) and parser.token.value != "on": return ast.FragmentSpread( name=parse_fragment_name(parser), directives=parse_directives(parser), loc=loc(parser, start), ) type_condition = None if parser.token.value == "on": advance(parser) type_condition = parse_named_type(parser) return ast.InlineFragment( type_condition=type_condition, directives=parse_directives(parser), selection_set=parse_selection_set(parser), loc=loc(parser, start), ) def parse_fragment_definition(parser): # type: (Parser) -> FragmentDefinition start = parser.token.start expect_keyword(parser, "fragment") return ast.FragmentDefinition( name=parse_fragment_name(parser), type_condition=parse_named_type(parser) if expect_keyword(parser, "on") else None, directives=parse_directives(parser), selection_set=parse_selection_set(parser), loc=loc(parser, start), ) def parse_fragment_name(parser): # type: (Parser) -> Name if parser.token.value == "on": raise unexpected(parser) return parse_name(parser) def parse_value_literal(parser, is_const): # type: (Parser, bool) -> Any token = parser.token if token.kind == TokenKind.BRACKET_L: return parse_list(parser, is_const) elif token.kind == TokenKind.BRACE_L: return parse_object(parser, is_const) elif token.kind == TokenKind.INT: advance(parser) return ast.IntValue( value=token.value, loc=loc(parser, token.start) # type: ignore ) elif token.kind == TokenKind.FLOAT: advance(parser) return ast.FloatValue( value=token.value, loc=loc(parser, token.start) # type: ignore ) elif token.kind == TokenKind.STRING: advance(parser) return ast.StringValue( value=token.value, loc=loc(parser, token.start) # type: ignore ) elif token.kind == TokenKind.NAME: if token.value in ("true", "false"): advance(parser) return ast.BooleanValue( value=token.value == "true", loc=loc(parser, token.start) ) if token.value != "null": advance(parser) return ast.EnumValue( value=token.value, loc=loc(parser, token.start) # type: ignore ) elif token.kind == TokenKind.DOLLAR: if not is_const: return parse_variable(parser) raise unexpected(parser) # Implements the parsing rules in the Values section. def parse_variable_value(parser): # type: (Parser) -> Union[IntValue, StringValue, Variable] return parse_value_literal(parser, False) def parse_const_value(parser): # type: (Parser) -> Union[BooleanValue, ObjectValue, StringValue] return parse_value_literal(parser, True) def parse_list(parser, is_const): # type: (Parser, bool) -> ListValue start = parser.token.start item = parse_const_value if is_const else parse_variable_value return ast.ListValue( values=any(parser, TokenKind.BRACKET_L, item, TokenKind.BRACKET_R), loc=loc(parser, start), ) def parse_object(parser, is_const): # type: (Parser, bool) -> ObjectValue start = parser.token.start expect(parser, TokenKind.BRACE_L) fields = [] while not skip(parser, TokenKind.BRACE_R): fields.append(parse_object_field(parser, is_const)) return ast.ObjectValue(fields=fields, loc=loc(parser, start)) def parse_object_field(parser, is_const): # type: (Parser, bool) -> ObjectField start = parser.token.start return ast.ObjectField( name=parse_name(parser), value=expect(parser, TokenKind.COLON) and parse_value_literal(parser, is_const), loc=loc(parser, start), ) # Implements the parsing rules in the Directives section. def parse_directives(parser): # type: (Parser) -> List[Directive] directives = [] while peek(parser, TokenKind.AT): directives.append(parse_directive(parser)) return directives def parse_directive(parser): # type: (Parser) -> Directive start = parser.token.start expect(parser, TokenKind.AT) return ast.Directive( name=parse_name(parser), arguments=parse_arguments(parser), loc=loc(parser, start), ) # Implements the parsing rules in the Types section. def parse_type(parser): # type: (Parser) -> Union[NamedType, NonNullType, ListType] """Handles the 'Type': TypeName, ListType, and NonNullType parsing rules.""" start = parser.token.start if skip(parser, TokenKind.BRACKET_L): ast_type = parse_type(parser) expect(parser, TokenKind.BRACKET_R) ast_type = ast.ListType(type=ast_type, loc=loc(parser, start)) # type: ignore else: ast_type = parse_named_type(parser) if skip(parser, TokenKind.BANG): return ast.NonNullType(type=ast_type, loc=loc(parser, start)) return ast_type def parse_named_type(parser): # type: (Parser) -> NamedType start = parser.token.start return ast.NamedType(name=parse_name(parser), loc=loc(parser, start)) def parse_type_system_definition(parser): # type: (Parser) -> Any """ TypeSystemDefinition : - SchemaDefinition - TypeDefinition - TypeExtensionDefinition - DirectiveDefinition TypeDefinition : - ScalarTypeDefinition - ObjectTypeDefinition - InterfaceTypeDefinition - UnionTypeDefinition - EnumTypeDefinition - InputObjectTypeDefinition """ if not peek(parser, TokenKind.NAME): raise unexpected(parser) name = parser.token.value if name == "schema": return parse_schema_definition(parser) elif name == "scalar": return parse_scalar_type_definition(parser) elif name == "type": return parse_object_type_definition(parser) elif name == "interface": return parse_interface_type_definition(parser) elif name == "union": return parse_union_type_definition(parser) elif name == "enum": return parse_enum_type_definition(parser) elif name == "input": return parse_input_object_type_definition(parser) elif name == "extend": return parse_type_extension_definition(parser) elif name == "directive": return parse_directive_definition(parser) raise unexpected(parser) def parse_schema_definition(parser): # type: (Parser) -> SchemaDefinition start = parser.token.start expect_keyword(parser, "schema") directives = parse_directives(parser) operation_types = many( parser, TokenKind.BRACE_L, parse_operation_type_definition, TokenKind.BRACE_R ) return ast.SchemaDefinition( directives=directives, operation_types=operation_types, loc=loc(parser, start) ) def parse_operation_type_definition(parser): # type: (Parser) -> OperationTypeDefinition start = parser.token.start operation = parse_operation_type(parser) expect(parser, TokenKind.COLON) return ast.OperationTypeDefinition( operation=operation, type=parse_named_type(parser), loc=loc(parser, start) ) def parse_scalar_type_definition(parser): # type: (Parser) -> ScalarTypeDefinition start = parser.token.start expect_keyword(parser, "scalar") return ast.ScalarTypeDefinition( name=parse_name(parser), directives=parse_directives(parser), loc=loc(parser, start), ) def parse_object_type_definition(parser): # type: (Parser) -> ObjectTypeDefinition start = parser.token.start expect_keyword(parser, "type") return ast.ObjectTypeDefinition( name=parse_name(parser), interfaces=parse_implements_interfaces(parser), directives=parse_directives(parser), fields=any( parser, TokenKind.BRACE_L, parse_field_definition, TokenKind.BRACE_R ), loc=loc(parser, start), ) def parse_implements_interfaces(parser): # type: (Parser) -> List[NamedType] types = [] if parser.token.value == "implements": advance(parser) while True: types.append(parse_named_type(parser)) if not peek(parser, TokenKind.NAME): break return types def parse_field_definition(parser): # type: (Parser) -> FieldDefinition start = parser.token.start return ast.FieldDefinition( name=parse_name(parser), arguments=parse_argument_defs(parser), type=expect(parser, TokenKind.COLON) and parse_type(parser), # type: ignore directives=parse_directives(parser), loc=loc(parser, start), ) def parse_argument_defs(parser): # type: (Parser) -> List[InputValueDefinition] if not peek(parser, TokenKind.PAREN_L): return [] return many(parser, TokenKind.PAREN_L, parse_input_value_def, TokenKind.PAREN_R) def parse_input_value_def(parser): # type: (Parser) -> InputValueDefinition start = parser.token.start return ast.InputValueDefinition( name=parse_name(parser), type=expect(parser, TokenKind.COLON) and parse_type(parser), # type: ignore default_value=parse_const_value(parser) if skip(parser, TokenKind.EQUALS) else None, directives=parse_directives(parser), loc=loc(parser, start), ) def parse_interface_type_definition(parser): # type: (Parser) -> InterfaceTypeDefinition start = parser.token.start expect_keyword(parser, "interface") return ast.InterfaceTypeDefinition( name=parse_name(parser), directives=parse_directives(parser), fields=any( parser, TokenKind.BRACE_L, parse_field_definition, TokenKind.BRACE_R ), loc=loc(parser, start), ) def parse_union_type_definition(parser): # type: (Parser) -> UnionTypeDefinition start = parser.token.start expect_keyword(parser, "union") return ast.UnionTypeDefinition( name=parse_name(parser), directives=parse_directives(parser), types=expect(parser, TokenKind.EQUALS) # type: ignore and parse_union_members(parser), loc=loc(parser, start), ) def parse_union_members(parser): # type: (Parser) -> List[NamedType] members = [] while True: members.append(parse_named_type(parser)) if not skip(parser, TokenKind.PIPE): break return members def parse_enum_type_definition(parser): # type: (Parser) -> EnumTypeDefinition start = parser.token.start expect_keyword(parser, "enum") return ast.EnumTypeDefinition( name=parse_name(parser), directives=parse_directives(parser), values=many( parser, TokenKind.BRACE_L, parse_enum_value_definition, TokenKind.BRACE_R ), loc=loc(parser, start), ) def parse_enum_value_definition(parser): # type: (Parser) -> EnumValueDefinition start = parser.token.start return ast.EnumValueDefinition( name=parse_name(parser), directives=parse_directives(parser), loc=loc(parser, start), ) def parse_input_object_type_definition(parser): # type: (Parser) -> InputObjectTypeDefinition start = parser.token.start expect_keyword(parser, "input") return ast.InputObjectTypeDefinition( name=parse_name(parser), directives=parse_directives(parser), fields=any(parser, TokenKind.BRACE_L, parse_input_value_def, TokenKind.BRACE_R), loc=loc(parser, start), ) def parse_type_extension_definition(parser): # type: (Parser) -> TypeExtensionDefinition start = parser.token.start expect_keyword(parser, "extend") return ast.TypeExtensionDefinition( definition=parse_object_type_definition(parser), loc=loc(parser, start) ) def parse_directive_definition(parser): # type: (Parser) -> DirectiveDefinition start = parser.token.start expect_keyword(parser, "directive") expect(parser, TokenKind.AT) name = parse_name(parser) args = parse_argument_defs(parser) expect_keyword(parser, "on") locations = parse_directive_locations(parser) return ast.DirectiveDefinition( name=name, locations=locations, arguments=args, loc=loc(parser, start) ) def parse_directive_locations(parser): # type: (Parser) -> List[Name] locations = [] while True: locations.append(parse_name(parser)) if not skip(parser, TokenKind.PIPE): break return locations graphql-core-legacy-2.3.2/graphql/language/printer.py000066400000000000000000000176061365661746200226540ustar00rootroot00000000000000import json from .visitor import Visitor, visit # Necessary for static type checking if False: # flake8: noqa from typing import Any, List, Optional from graphql.language.ast import Node __all__ = ["print_ast"] def print_ast(ast): # type: (Node) -> str return visit(ast, PrintingVisitor()) class PrintingVisitor(Visitor): __slots__ = () def leave_Name(self, node, *args): # type: (Any, *Any) -> str return node.value # type: ignore def leave_Variable(self, node, *args): # type: (Any, *Any) -> str return "$" + node.name # type: ignore def leave_Document(self, node, *args): # type: (Any, *Any) -> str return join(node.definitions, "\n\n") + "\n" # type: ignore def leave_OperationDefinition(self, node, *args): # type: (Any, *Any) -> str name = node.name selection_set = node.selection_set op = node.operation var_defs = wrap("(", join(node.variable_definitions, ", "), ")") directives = join(node.directives, " ") if not name and not directives and not var_defs and op == "query": return selection_set return join([op, join([name, var_defs]), directives, selection_set], " ") def leave_VariableDefinition(self, node, *args): # type: (Any, *Any) -> str return node.variable + ": " + node.type + wrap(" = ", node.default_value) def leave_SelectionSet(self, node, *args): # type: (Any, *Any) -> str return block(node.selections) def leave_Field(self, node, *args): # type: (Any, *Any) -> str return join( [ wrap("", node.alias, ": ") + node.name + wrap("(", join(node.arguments, ", "), ")"), join(node.directives, " "), node.selection_set, ], " ", ) def leave_Argument(self, node, *args): # type: (Any, *Any) -> str return "{0.name}: {0.value}".format(node) # Fragments def leave_FragmentSpread(self, node, *args): # type: (Any, *Any) -> str return "..." + node.name + wrap(" ", join(node.directives, " ")) def leave_InlineFragment(self, node, *args): # type: (Any, *Any) -> str return join( [ "...", wrap("on ", node.type_condition), join(node.directives, ""), node.selection_set, ], " ", ) def leave_FragmentDefinition(self, node, *args): # type: (Any, *Any) -> str return ( "fragment {} on {} ".format(node.name, node.type_condition) + wrap("", join(node.directives, " "), " ") + node.selection_set ) # Value def leave_IntValue(self, node, *args): # type: (Any, *Any) -> str return node.value def leave_FloatValue(self, node, *args): return node.value def leave_StringValue(self, node, *args): # type: (Any, *Any) -> str return json.dumps(node.value) def leave_BooleanValue(self, node, *args): # type: (Any, *Any) -> str return json.dumps(node.value) def leave_EnumValue(self, node, *args): # type: (Any, *Any) -> str return node.value def leave_ListValue(self, node, *args): # type: (Any, *Any) -> str return "[" + join(node.values, ", ") + "]" def leave_ObjectValue(self, node, *args): # type: (Any, *Any) -> str return "{" + join(node.fields, ", ") + "}" def leave_ObjectField(self, node, *args): # type: (Any, *Any) -> str return node.name + ": " + node.value # Directive def leave_Directive(self, node, *args): # type: (Any, *Any) -> str return "@" + node.name + wrap("(", join(node.arguments, ", "), ")") # Type def leave_NamedType(self, node, *args): # type: (Any, *Any) -> str return node.name def leave_ListType(self, node, *args): # type: (Any, *Any) -> str return "[" + node.type + "]" def leave_NonNullType(self, node, *args): # type: (Any, *Any) -> str return node.type + "!" # Type Definitions: def leave_SchemaDefinition(self, node, *args): # type: (Any, *Any) -> str return join( ["schema", join(node.directives, " "), block(node.operation_types)], " " ) def leave_OperationTypeDefinition(self, node, *args): # type: (Any, *Any) -> str return "{}: {}".format(node.operation, node.type) def leave_ScalarTypeDefinition(self, node, *args): # type: (Any, *Any) -> str return "scalar " + node.name + wrap(" ", join(node.directives, " ")) def leave_ObjectTypeDefinition(self, node, *args): # type: (Any, *Any) -> str return join( [ "type", node.name, wrap("implements ", join(node.interfaces, ", ")), join(node.directives, " "), block(node.fields), ], " ", ) def leave_FieldDefinition(self, node, *args): # type: (Any, *Any) -> str return ( node.name + wrap("(", join(node.arguments, ", "), ")") + ": " + node.type + wrap(" ", join(node.directives, " ")) ) def leave_InputValueDefinition(self, node, *args): # type: (Any, *Any) -> str return ( node.name + ": " + node.type + wrap(" = ", node.default_value) + wrap(" ", join(node.directives, " ")) ) def leave_InterfaceTypeDefinition(self, node, *args): # type: (Any, *Any) -> str return ( "interface " + node.name + wrap(" ", join(node.directives, " ")) + " " + block(node.fields) ) def leave_UnionTypeDefinition(self, node, *args): # type: (Any, *Any) -> str return ( "union " + node.name + wrap(" ", join(node.directives, " ")) + " = " + join(node.types, " | ") ) def leave_EnumTypeDefinition(self, node, *args): # type: (Any, *Any) -> str return ( "enum " + node.name + wrap(" ", join(node.directives, " ")) + " " + block(node.values) ) def leave_EnumValueDefinition(self, node, *args): # type: (Any, *Any) -> str return node.name + wrap(" ", join(node.directives, " ")) def leave_InputObjectTypeDefinition(self, node, *args): # type: (Any, *Any) -> str return ( "input " + node.name + wrap(" ", join(node.directives, " ")) + " " + block(node.fields) ) def leave_TypeExtensionDefinition(self, node, *args): # type: (Any, *Any) -> str return "extend " + node.definition def leave_DirectiveDefinition(self, node, *args): # type: (Any, *Any) -> str return "directive @{}{} on {}".format( node.name, wrap("(", join(node.arguments, ", "), ")"), " | ".join(node.locations), ) def join(maybe_list, separator=""): # type: (Optional[List[str]], str) -> str if maybe_list: return separator.join(filter(None, maybe_list)) return "" def block(_list): # type: (List[str]) -> str """Given a list, print each item on its own line, wrapped in an indented "{ }" block.""" if _list: return indent("{\n" + join(_list, "\n")) + "\n}" return "{}" def wrap(start, maybe_str, end=""): # type: (str, Optional[str], str) -> str if maybe_str: return start + maybe_str + end return "" def indent(maybe_str): # type: (Optional[str]) -> str if maybe_str: return maybe_str.replace("\n", "\n ") return "" graphql-core-legacy-2.3.2/graphql/language/source.py000066400000000000000000000006201365661746200224550ustar00rootroot00000000000000__all__ = ["Source"] class Source(object): __slots__ = "body", "name" def __init__(self, body, name="GraphQL"): # type: (str, str) -> None self.body = body self.name = name def __eq__(self, other): return self is other or ( isinstance(other, Source) and self.body == other.body and self.name == other.name ) graphql-core-legacy-2.3.2/graphql/language/tests/000077500000000000000000000000001365661746200217475ustar00rootroot00000000000000graphql-core-legacy-2.3.2/graphql/language/tests/__init__.py000066400000000000000000000000001365661746200240460ustar00rootroot00000000000000graphql-core-legacy-2.3.2/graphql/language/tests/fixtures.py000066400000000000000000000051461365661746200242000ustar00rootroot00000000000000KITCHEN_SINK = """ # Copyright (c) 2015, Facebook, Inc. # All rights reserved. # # This source code is licensed under the BSD-style license found in the # LICENSE file in the root directory of this source tree. An additional grant # of patent rights can be found in the PATENTS file in the same directory. query queryName($foo: ComplexType, $site: Site = MOBILE) { whoever123is: node(id: [123, 456]) { id , ... on User @defer { field2 { id , alias: field1(first:10, after:$foo,) @include(if: $foo) { id, ...frag } } } ... @skip(unless: $foo) { id } ... { id } } } mutation likeStory { like(story: 123) @defer { story { id } } } subscription StoryLikeSubscription($input: StoryLikeSubscribeInput) { storyLikeSubscribe(input: $input) { story { likers { count } likeSentence { text } } } } fragment frag on Friend { foo(size: $size, bar: $b, obj: {key: "value"}) } { unnamed(truthy: true, falsey: false), query } """ SCHEMA_KITCHEN_SINK = """ # Copyright (c) 2015, Facebook, Inc. # All rights reserved. # # This source code is licensed under the BSD-style license found in the # LICENSE file in the root directory of this source tree. An additional grant # of patent rights can be found in the PATENTS file in the same directory. schema { query: QueryType mutation: MutationType } type Foo implements Bar { one: Type two(argument: InputType!): Type three(argument: InputType, other: String): Int four(argument: String = "string"): String five(argument: [String] = ["string", "string"]): String six(argument: InputType = {key: "value"}): Type } type AnnotatedObject @onObject(arg: "value") { annotatedField(arg: Type = "default" @onArg): Type @onField } interface Bar { one: Type four(argument: String = "string"): String } interface AnnotatedInterface @onInterface { annotatedField(arg: Type @onArg): Type @onField } union Feed = Story | Article | Advert union AnnotatedUnion @onUnion = A | B scalar CustomScalar scalar AnnotatedScalar @onScalar enum Site { DESKTOP MOBILE } enum AnnotatedEnum @onEnum { ANNOTATED_VALUE @onEnumValue OTHER_VALUE } input InputType { key: String! answer: Int = 42 } input AnnotatedInput @onInputObjectType { annotatedField: Type @onField } extend type Foo { seven(argument: [String]): Type } extend type Foo @onType {} type NoFields {} directive @skip(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT directive @include(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT """ graphql-core-legacy-2.3.2/graphql/language/tests/test_ast.py000066400000000000000000000012441365661746200241500ustar00rootroot00000000000000import copy from graphql.language.visitor_meta import QUERY_DOCUMENT_KEYS def test_ast_is_hashable(): # type: () -> None for node_class in QUERY_DOCUMENT_KEYS: node = node_class(loc=None, **{k: k for k in node_class._fields}) assert hash(node) def test_ast_is_copyable(): # type: () -> None for node_class in QUERY_DOCUMENT_KEYS: node = node_class(loc=None, **{k: k for k in node_class._fields}) assert copy.copy(node) == node def test_ast_is_reprable(): # type: () -> None for node_class in QUERY_DOCUMENT_KEYS: node = node_class(loc=None, **{k: k for k in node_class._fields}) assert repr(node) graphql-core-legacy-2.3.2/graphql/language/tests/test_lexer.py000066400000000000000000000233261365661746200245050ustar00rootroot00000000000000from pytest import raises from graphql.error import GraphQLSyntaxError from graphql.language.lexer import Lexer, Token, TokenKind from graphql.language.source import Source def lex_one(s): # type: (str) -> Token return Lexer(Source(s)).next_token() def test_repr_token(): # type: () -> None token = lex_one("500") assert repr(token) == "" def test_disallows_uncommon_control_characters(): # type: () -> None with raises(GraphQLSyntaxError) as excinfo: lex_one(u"\u0007") assert ( u'Syntax Error GraphQL (1:1) Invalid character "\\u0007"' in excinfo.value.message ) def test_accepts_bom_header(): # type: () -> None assert lex_one(u"\uFEFF foo") == Token(TokenKind.NAME, 2, 5, u"foo") def test_skips_whitespace(): # type: () -> None assert ( lex_one( u""" foo """ ) == Token(TokenKind.NAME, 6, 9, "foo") ) assert ( lex_one( u""" #comment foo#comment """ ) == Token(TokenKind.NAME, 18, 21, "foo") ) assert lex_one(u""",,,foo,,,""") == Token(TokenKind.NAME, 3, 6, "foo") def test_errors_respect_whitespace(): # type: () -> None with raises(GraphQLSyntaxError) as excinfo: lex_one( u""" ? """ ) assert excinfo.value.message == ( u'Syntax Error GraphQL (3:5) Unexpected character "?".\n' u"\n" u"2: \n" u"3: ?\n" u" ^\n" u"4: \n" ) def test_lexes_strings(): # type: () -> None assert lex_one(u'"simple"') == Token(TokenKind.STRING, 0, 8, "simple") assert lex_one(u'" white space "') == Token( TokenKind.STRING, 0, 15, " white space " ) assert lex_one(u'"quote \\""') == Token(TokenKind.STRING, 0, 10, 'quote "') assert lex_one(u'"escaped \\n\\r\\b\\t\\f"') == Token( TokenKind.STRING, 0, 20, "escaped \n\r\b\t\f" ) assert lex_one(u'"slashes \\\\ \\/"') == Token( TokenKind.STRING, 0, 15, "slashes \\ /" ) assert lex_one(u'"unicode \\u1234\\u5678\\u90AB\\uCDEF"') == Token( TokenKind.STRING, 0, 34, u"unicode \u1234\u5678\u90AB\uCDEF" ) def test_lex_reports_useful_string_errors(): # type: () -> None with raises(GraphQLSyntaxError) as excinfo: lex_one(u'"') assert u"Syntax Error GraphQL (1:2) Unterminated string" in excinfo.value.message with raises(GraphQLSyntaxError) as excinfo: lex_one(u'"no end quote') assert u"Syntax Error GraphQL (1:14) Unterminated string" in excinfo.value.message with raises(GraphQLSyntaxError) as excinfo: lex_one(u'"contains unescaped \u0007 control char"') assert ( u'Syntax Error GraphQL (1:21) Invalid character within String: "\\u0007".' in excinfo.value.message ) with raises(GraphQLSyntaxError) as excinfo: lex_one(u'"null-byte is not \u0000 end of file"') assert ( u'Syntax Error GraphQL (1:19) Invalid character within String: "\\u0000".' in excinfo.value.message ) with raises(GraphQLSyntaxError) as excinfo: lex_one(u'"multi\nline"') assert u"Syntax Error GraphQL (1:7) Unterminated string" in excinfo.value.message with raises(GraphQLSyntaxError) as excinfo: lex_one(u'"multi\rline"') assert u"Syntax Error GraphQL (1:7) Unterminated string" in excinfo.value.message with raises(GraphQLSyntaxError) as excinfo: lex_one(u'"bad \\z esc"') assert ( u"Syntax Error GraphQL (1:7) Invalid character escape sequence: \\z." in excinfo.value.message ) with raises(GraphQLSyntaxError) as excinfo: lex_one(u'"bad \\x esc"') assert ( u"Syntax Error GraphQL (1:7) Invalid character escape sequence: \\x." in excinfo.value.message ) with raises(GraphQLSyntaxError) as excinfo: lex_one(u'"bad \\u1 esc"') assert ( u"Syntax Error GraphQL (1:7) Invalid character escape sequence: \\u1 es." in excinfo.value.message ) with raises(GraphQLSyntaxError) as excinfo: lex_one(u'"bad \\u0XX1 esc"') assert ( u"Syntax Error GraphQL (1:7) Invalid character escape sequence: \\u0XX1." in excinfo.value.message ) with raises(GraphQLSyntaxError) as excinfo: lex_one(u'"bad \\uXXXX esc"') assert ( u"Syntax Error GraphQL (1:7) Invalid character escape sequence: \\uXXXX" in excinfo.value.message ) with raises(GraphQLSyntaxError) as excinfo: lex_one(u'"bad \\uFXXX esc"') assert ( u"Syntax Error GraphQL (1:7) Invalid character escape sequence: \\uFXXX." in excinfo.value.message ) with raises(GraphQLSyntaxError) as excinfo: lex_one(u'"bad \\uXXXF esc"') assert ( u"Syntax Error GraphQL (1:7) Invalid character escape sequence: \\uXXXF." in excinfo.value.message ) def test_lexes_numbers(): # type: () -> None assert lex_one(u"4") == Token(TokenKind.INT, 0, 1, "4") assert lex_one(u"4.123") == Token(TokenKind.FLOAT, 0, 5, "4.123") assert lex_one(u"-4") == Token(TokenKind.INT, 0, 2, "-4") assert lex_one(u"9") == Token(TokenKind.INT, 0, 1, "9") assert lex_one(u"0") == Token(TokenKind.INT, 0, 1, "0") assert lex_one(u"-4.123") == Token(TokenKind.FLOAT, 0, 6, "-4.123") assert lex_one(u"0.123") == Token(TokenKind.FLOAT, 0, 5, "0.123") assert lex_one(u"123e4") == Token(TokenKind.FLOAT, 0, 5, "123e4") assert lex_one(u"123E4") == Token(TokenKind.FLOAT, 0, 5, "123E4") assert lex_one(u"123e-4") == Token(TokenKind.FLOAT, 0, 6, "123e-4") assert lex_one(u"123e+4") == Token(TokenKind.FLOAT, 0, 6, "123e+4") assert lex_one(u"-1.123e4") == Token(TokenKind.FLOAT, 0, 8, "-1.123e4") assert lex_one(u"-1.123E4") == Token(TokenKind.FLOAT, 0, 8, "-1.123E4") assert lex_one(u"-1.123e-4") == Token(TokenKind.FLOAT, 0, 9, "-1.123e-4") assert lex_one(u"-1.123e+4") == Token(TokenKind.FLOAT, 0, 9, "-1.123e+4") assert lex_one(u"-1.123e4567") == Token(TokenKind.FLOAT, 0, 11, "-1.123e4567") def test_lex_reports_useful_number_errors(): # type: () -> None with raises(GraphQLSyntaxError) as excinfo: lex_one(u"00") assert ( u'Syntax Error GraphQL (1:2) Invalid number, unexpected digit after 0: "0".' in excinfo.value.message ) with raises(GraphQLSyntaxError) as excinfo: lex_one(u"+1") assert ( u'Syntax Error GraphQL (1:1) Unexpected character "+"' in excinfo.value.message ) with raises(GraphQLSyntaxError) as excinfo: lex_one(u"1.") assert ( u"Syntax Error GraphQL (1:3) Invalid number, expected digit but got: ." in excinfo.value.message ) with raises(GraphQLSyntaxError) as excinfo: lex_one(u".123") assert ( u'Syntax Error GraphQL (1:1) Unexpected character ".".' in excinfo.value.message ) with raises(GraphQLSyntaxError) as excinfo: lex_one(u"1.A") assert ( u'Syntax Error GraphQL (1:3) Invalid number, expected digit but got: "A".' in excinfo.value.message ) with raises(GraphQLSyntaxError) as excinfo: lex_one(u"-A") assert ( u'Syntax Error GraphQL (1:2) Invalid number, expected digit but got: "A".' in excinfo.value.message ) with raises(GraphQLSyntaxError) as excinfo: lex_one(u"1.0e") assert ( u"Syntax Error GraphQL (1:5) Invalid number, expected digit but got: ." in excinfo.value.message ) with raises(GraphQLSyntaxError) as excinfo: lex_one(u"1.0eA") assert ( u'Syntax Error GraphQL (1:5) Invalid number, expected digit but got: "A".' in excinfo.value.message ) def test_lexes_punctuation(): # type: () -> None assert lex_one(u"!") == Token(TokenKind.BANG, 0, 1) assert lex_one(u"$") == Token(TokenKind.DOLLAR, 0, 1) assert lex_one(u"(") == Token(TokenKind.PAREN_L, 0, 1) assert lex_one(u")") == Token(TokenKind.PAREN_R, 0, 1) assert lex_one(u"...") == Token(TokenKind.SPREAD, 0, 3) assert lex_one(u":") == Token(TokenKind.COLON, 0, 1) assert lex_one(u"=") == Token(TokenKind.EQUALS, 0, 1) assert lex_one(u"@") == Token(TokenKind.AT, 0, 1) assert lex_one(u"[") == Token(TokenKind.BRACKET_L, 0, 1) assert lex_one(u"]") == Token(TokenKind.BRACKET_R, 0, 1) assert lex_one(u"{") == Token(TokenKind.BRACE_L, 0, 1) assert lex_one(u"|") == Token(TokenKind.PIPE, 0, 1) assert lex_one(u"}") == Token(TokenKind.BRACE_R, 0, 1) def test_lex_reports_useful_unknown_character_error(): # type: () -> None with raises(GraphQLSyntaxError) as excinfo: lex_one(u"..") assert ( u'Syntax Error GraphQL (1:1) Unexpected character "."' in excinfo.value.message ) with raises(GraphQLSyntaxError) as excinfo: lex_one(u"?") assert ( u'Syntax Error GraphQL (1:1) Unexpected character "?"' in excinfo.value.message ) with raises(GraphQLSyntaxError) as excinfo: lex_one(u"\u203B") assert ( u'Syntax Error GraphQL (1:1) Unexpected character "\\u203B"' in excinfo.value.message ) with raises(GraphQLSyntaxError) as excinfo: lex_one(u"\u200b") assert ( u'Syntax Error GraphQL (1:1) Unexpected character "\\u200B"' in excinfo.value.message ) def test_lex_reports_useful_information_for_dashes_in_names(): # type: () -> None q = u"a-b" lexer = Lexer(Source(q)) first_token = lexer.next_token() assert first_token == Token(TokenKind.NAME, 0, 1, "a") with raises(GraphQLSyntaxError) as excinfo: lexer.next_token() assert ( u'Syntax Error GraphQL (1:3) Invalid number, expected digit but got: "b".' in excinfo.value.message ) graphql-core-legacy-2.3.2/graphql/language/tests/test_location.py000066400000000000000000000003151365661746200251670ustar00rootroot00000000000000from graphql.language.location import SourceLocation def test_repr_source_location(): # type: () -> None loc = SourceLocation(10, 25) assert repr(loc) == "SourceLocation(line=10, column=25)" graphql-core-legacy-2.3.2/graphql/language/tests/test_parser.py000066400000000000000000000221171365661746200246570ustar00rootroot00000000000000from pytest import raises from graphql.error import GraphQLSyntaxError from graphql.language import ast from graphql.language.location import SourceLocation from graphql.language.parser import Loc, parse from graphql.language.source import Source from .fixtures import KITCHEN_SINK def test_repr_loc(): # type: () -> None loc = Loc(start=10, end=25, source="foo") assert repr(loc) == "" def test_empty_parse(): # type: () -> None with raises(GraphQLSyntaxError) as excinfo: parse("") assert ( u"Syntax Error GraphQL (1:1) Unexpected EOF\n" u"\n" ) == excinfo.value.message def test_parse_provides_useful_errors(): # type: () -> None with raises(GraphQLSyntaxError) as excinfo: parse("""{""") assert ( u"Syntax Error GraphQL (1:2) Expected Name, found EOF\n" u"\n" u"1: {\n" u" ^\n" u"" ) == excinfo.value.message assert excinfo.value.positions == [1] assert excinfo.value.locations == [SourceLocation(line=1, column=2)] with raises(GraphQLSyntaxError) as excinfo: parse( """{ ...MissingOn } fragment MissingOn Type """ ) assert 'Syntax Error GraphQL (2:20) Expected "on", found Name "Type"' in str( excinfo.value ) with raises(GraphQLSyntaxError) as excinfo: parse("{ field: {} }") assert "Syntax Error GraphQL (1:10) Expected Name, found {" in str(excinfo.value) with raises(GraphQLSyntaxError) as excinfo: parse("notanoperation Foo { field }") assert 'Syntax Error GraphQL (1:1) Unexpected Name "notanoperation"' in str( excinfo.value ) with raises(GraphQLSyntaxError) as excinfo: parse("...") assert "Syntax Error GraphQL (1:1) Unexpected ..." in str(excinfo.value) def test_parse_provides_useful_error_when_using_source(): # type: () -> None with raises(GraphQLSyntaxError) as excinfo: parse(Source("query", "MyQuery.graphql")) assert "Syntax Error MyQuery.graphql (1:6) Expected {, found EOF" in str( excinfo.value ) def test_parses_variable_inline_values(): # type: () -> None parse("{ field(complex: { a: { b: [ $var ] } }) }") def test_parses_constant_default_values(): # type: () -> None with raises(GraphQLSyntaxError) as excinfo: parse("query Foo($x: Complex = { a: { b: [ $var ] } }) { field }") assert "Syntax Error GraphQL (1:37) Unexpected $" in str(excinfo.value) def test_does_not_accept_fragments_named_on(): # type: () -> None with raises(GraphQLSyntaxError) as excinfo: parse("fragment on on on { on }") assert 'Syntax Error GraphQL (1:10) Unexpected Name "on"' in excinfo.value.message def test_does_not_accept_fragments_spread_of_on(): # type: () -> None with raises(GraphQLSyntaxError) as excinfo: parse("{ ...on }") assert "Syntax Error GraphQL (1:9) Expected Name, found }" in excinfo.value.message def test_does_not_allow_null_value(): # type: () -> None with raises(GraphQLSyntaxError) as excinfo: parse("{ fieldWithNullableStringInput(input: null) }") assert 'Syntax Error GraphQL (1:39) Unexpected Name "null"' in excinfo.value.message def test_parses_multi_byte_characters(): # type: () -> None result = parse( u""" # This comment has a \u0A0A multi-byte character. { field(arg: "Has a \u0A0A multi-byte character.") } """, no_location=True, no_source=True, ) assert result == ast.Document( definitions=[ ast.OperationDefinition( operation="query", name=None, variable_definitions=None, directives=[], selection_set=ast.SelectionSet( selections=[ ast.Field( alias=None, name=ast.Name(value=u"field"), arguments=[ ast.Argument( name=ast.Name(value=u"arg"), value=ast.StringValue( value=u"Has a \u0a0a multi-byte character." ), ) ], directives=[], selection_set=None, ) ] ), ) ] ) def tesst_allows_non_keywords_anywhere_a_name_is_allowed(): non_keywords = [ "on", "fragment", "query", "mutation", "subscription", "true", "false", ] query_template = """ query {keyword} { ... {fragment_name} ... on {keyword} { field } } fragment {fragment_name} on Type { {keyword}({keyword}: ${keyword}) @{keyword}({keyword}: {keyword}) } """ for keyword in non_keywords: fragment_name = keyword if keyword == "on": fragment_name = "a" parse(query_template.format(fragment_name=fragment_name, keyword=keyword)) def test_parses_kitchen_sink(): # type: () -> None parse(KITCHEN_SINK) def test_parses_anonymous_mutation_operations(): # type: () -> None parse( """ mutation { mutationField } """ ) def test_parses_anonymous_subscription_operations(): # type: () -> None parse( """ subscription { mutationField } """ ) def test_parses_named_mutation_operations(): # type: () -> None parse( """ mutation Foo { mutationField } """ ) def test_parses_named_subscription_operations(): # type: () -> None parse( """ subscription Foo { subscriptionField } """ ) def test_parse_creates_ast(): # type: () -> None source = Source( """{ node(id: 4) { id, name } } """ ) result = parse(source) assert result == ast.Document( loc=Loc(start=0, end=41, source=source), definitions=[ ast.OperationDefinition( loc=Loc(start=0, end=40, source=source), operation="query", name=None, variable_definitions=None, directives=[], selection_set=ast.SelectionSet( loc=Loc(start=0, end=40, source=source), selections=[ ast.Field( loc=Loc(start=4, end=38, source=source), alias=None, name=ast.Name( loc=Loc(start=4, end=8, source=source), value="node" ), arguments=[ ast.Argument( name=ast.Name( loc=Loc(start=9, end=11, source=source), value="id", ), value=ast.IntValue( loc=Loc(start=13, end=14, source=source), value="4", ), loc=Loc(start=9, end=14, source=source), ) ], directives=[], selection_set=ast.SelectionSet( loc=Loc(start=16, end=38, source=source), selections=[ ast.Field( loc=Loc(start=22, end=24, source=source), alias=None, name=ast.Name( loc=Loc(start=22, end=24, source=source), value="id", ), arguments=[], directives=[], selection_set=None, ), ast.Field( loc=Loc(start=30, end=34, source=source), alias=None, name=ast.Name( loc=Loc(start=30, end=34, source=source), value="name", ), arguments=[], directives=[], selection_set=None, ), ], ), ) ], ), ) ], ) graphql-core-legacy-2.3.2/graphql/language/tests/test_printer.py000066400000000000000000000053111365661746200250430ustar00rootroot00000000000000import copy from pytest import raises from graphql.language.ast import Field, Name from graphql.language.parser import parse from graphql.language.printer import print_ast from .fixtures import KITCHEN_SINK def test_does_not_alter_ast(): # type: () -> None ast = parse(KITCHEN_SINK) ast_copy = copy.deepcopy(ast) print_ast(ast) assert ast == ast_copy def test_prints_minimal_ast(): # type: () -> None ast = Field(name=Name(loc=None, value="foo")) assert print_ast(ast) == "foo" def test_produces_helpful_error_messages(): # type: () -> None bad_ast = {"random": "Data"} with raises(Exception) as excinfo: print_ast(bad_ast) assert "Invalid AST Node" in str(excinfo.value) def test_correctly_prints_query_operation_without_name(): # type: () -> None query_ast_shorthanded = parse("query { id, name }") assert ( print_ast(query_ast_shorthanded) == """{ id name } """ ) def test_correctly_prints_mutation_operation_without_name(): # type: () -> None mutation_ast = parse("mutation { id, name }") assert ( print_ast(mutation_ast) == """mutation { id name } """ ) def test_correctly_prints_query_with_artifacts(): # type: () -> None query_ast_shorthanded = parse("query ($foo: TestType) @testDirective { id, name }") assert ( print_ast(query_ast_shorthanded) == """query ($foo: TestType) @testDirective { id name } """ ) def test_correctly_prints_mutation_with_artifacts(): # type: () -> None query_ast_shorthanded = parse( "mutation ($foo: TestType) @testDirective { id, name }" ) assert ( print_ast(query_ast_shorthanded) == """mutation ($foo: TestType) @testDirective { id name } """ ) def test_prints_kitchen_sink(): # type: () -> None ast = parse(KITCHEN_SINK) printed = print_ast(ast) assert ( printed == """query queryName($foo: ComplexType, $site: Site = MOBILE) { whoever123is: node(id: [123, 456]) { id ... on User @defer { field2 { id alias: field1(first: 10, after: $foo) @include(if: $foo) { id ...frag } } } ... @skip(unless: $foo) { id } ... { id } } } mutation likeStory { like(story: 123) @defer { story { id } } } subscription StoryLikeSubscription($input: StoryLikeSubscribeInput) { storyLikeSubscribe(input: $input) { story { likers { count } likeSentence { text } } } } fragment frag on Friend { foo(size: $size, bar: $b, obj: {key: "value"}) } { unnamed(truthy: true, falsey: false) query } """ ) graphql-core-legacy-2.3.2/graphql/language/tests/test_schema_parser.py000066400000000000000000000427331365661746200262050ustar00rootroot00000000000000from pytest import raises from graphql import Source, parse from graphql.error import GraphQLSyntaxError from graphql.language import ast from graphql.language.parser import Loc from typing import Callable def create_loc_fn(body): # type: (str) -> Callable source = Source(body) return lambda start, end: Loc(start, end, source) def test_parses_simple_type(): # type: () -> None body = """ type Hello { world: String }""" doc = parse(body) loc = create_loc_fn(body) expected = ast.Document( definitions=[ ast.ObjectTypeDefinition( name=ast.Name(value="Hello", loc=loc(6, 11)), interfaces=[], directives=[], fields=[ ast.FieldDefinition( name=ast.Name(value="world", loc=loc(16, 21)), arguments=[], type=ast.NamedType( name=ast.Name(value="String", loc=loc(23, 29)), loc=loc(23, 29), ), directives=[], loc=loc(16, 29), ) ], loc=loc(1, 31), ) ], loc=loc(1, 31), ) assert doc == expected def test_parses_simple_extension(): # type: () -> None body = """ extend type Hello { world: String }""" doc = parse(body) loc = create_loc_fn(body) expected = ast.Document( definitions=[ ast.TypeExtensionDefinition( definition=ast.ObjectTypeDefinition( name=ast.Name(value="Hello", loc=loc(13, 18)), interfaces=[], directives=[], fields=[ ast.FieldDefinition( name=ast.Name(value="world", loc=loc(23, 28)), arguments=[], type=ast.NamedType( name=ast.Name(value="String", loc=loc(30, 36)), loc=loc(30, 36), ), directives=[], loc=loc(23, 36), ) ], loc=loc(8, 38), ), loc=loc(1, 38), ) ], loc=loc(1, 38), ) assert doc == expected def test_simple_non_null_type(): # type: () -> None body = """ type Hello { world: String! }""" doc = parse(body) loc = create_loc_fn(body) expected = ast.Document( definitions=[ ast.ObjectTypeDefinition( name=ast.Name(value="Hello", loc=loc(6, 11)), interfaces=[], directives=[], fields=[ ast.FieldDefinition( name=ast.Name(value="world", loc=loc(16, 21)), arguments=[], type=ast.NonNullType( type=ast.NamedType( name=ast.Name(value="String", loc=loc(23, 29)), loc=loc(23, 29), ), loc=loc(23, 30), ), directives=[], loc=loc(16, 30), ) ], loc=loc(1, 32), ) ], loc=loc(1, 32), ) assert doc == expected def test_parses_simple_type_inheriting_interface(): # type: () -> None body = "type Hello implements World { }" loc = create_loc_fn(body) doc = parse(body) expected = ast.Document( definitions=[ ast.ObjectTypeDefinition( name=ast.Name(value="Hello", loc=loc(5, 10)), interfaces=[ ast.NamedType( name=ast.Name(value="World", loc=loc(22, 27)), loc=loc(22, 27) ) ], directives=[], fields=[], loc=loc(0, 31), ) ], loc=loc(0, 31), ) assert doc == expected def test_parses_simple_type_inheriting_multiple_interfaces(): # type: () -> None body = "type Hello implements Wo, rld { }" loc = create_loc_fn(body) doc = parse(body) expected = ast.Document( definitions=[ ast.ObjectTypeDefinition( name=ast.Name(value="Hello", loc=loc(5, 10)), interfaces=[ ast.NamedType( name=ast.Name(value="Wo", loc=loc(22, 24)), loc=loc(22, 24) ), ast.NamedType( name=ast.Name(value="rld", loc=loc(26, 29)), loc=loc(26, 29) ), ], directives=[], fields=[], loc=loc(0, 33), ) ], loc=loc(0, 33), ) assert doc == expected def test_parses_single_value_enum(): # type: () -> None body = "enum Hello { WORLD }" loc = create_loc_fn(body) doc = parse(body) expected = ast.Document( definitions=[ ast.EnumTypeDefinition( name=ast.Name(value="Hello", loc=loc(5, 10)), directives=[], values=[ ast.EnumValueDefinition( name=ast.Name(value="WORLD", loc=loc(13, 18)), directives=[], loc=loc(13, 18), ) ], loc=loc(0, 20), ) ], loc=loc(0, 20), ) assert doc == expected def test_parses_double_value_enum(): # type: () -> None body = "enum Hello { WO, RLD }" loc = create_loc_fn(body) doc = parse(body) expected = ast.Document( definitions=[ ast.EnumTypeDefinition( name=ast.Name(value="Hello", loc=loc(5, 10)), directives=[], values=[ ast.EnumValueDefinition( name=ast.Name(value="WO", loc=loc(13, 15)), directives=[], loc=loc(13, 15), ), ast.EnumValueDefinition( name=ast.Name(value="RLD", loc=loc(17, 20)), directives=[], loc=loc(17, 20), ), ], loc=loc(0, 22), ) ], loc=loc(0, 22), ) assert doc == expected def test_parses_simple_interface(): # type: () -> None body = """ interface Hello { world: String } """ loc = create_loc_fn(body) doc = parse(body) expected = ast.Document( definitions=[ ast.InterfaceTypeDefinition( name=ast.Name(value="Hello", loc=loc(11, 16)), directives=[], fields=[ ast.FieldDefinition( name=ast.Name(value="world", loc=loc(21, 26)), arguments=[], type=ast.NamedType( name=ast.Name(value="String", loc=loc(28, 34)), loc=loc(28, 34), ), directives=[], loc=loc(21, 34), ) ], loc=loc(1, 36), ) ], loc=loc(1, 37), ) assert doc == expected def test_parses_simple_field_with_arg(): # type: () -> None body = """ type Hello { world(flag: Boolean): String }""" loc = create_loc_fn(body) doc = parse(body) expected = ast.Document( definitions=[ ast.ObjectTypeDefinition( name=ast.Name(value="Hello", loc=loc(6, 11)), interfaces=[], directives=[], fields=[ ast.FieldDefinition( name=ast.Name(value="world", loc=loc(16, 21)), arguments=[ ast.InputValueDefinition( name=ast.Name(value="flag", loc=loc(22, 26)), type=ast.NamedType( name=ast.Name(value="Boolean", loc=loc(28, 35)), loc=loc(28, 35), ), default_value=None, directives=[], loc=loc(22, 35), ) ], type=ast.NamedType( name=ast.Name(value="String", loc=loc(38, 44)), loc=loc(38, 44), ), directives=[], loc=loc(16, 44), ) ], loc=loc(1, 46), ) ], loc=loc(1, 46), ) assert doc == expected def test_parses_simple_field_with_arg_with_default_value(): # type: () -> None body = """ type Hello { world(flag: Boolean = true): String }""" loc = create_loc_fn(body) doc = parse(body) expected = ast.Document( definitions=[ ast.ObjectTypeDefinition( name=ast.Name(value="Hello", loc=loc(6, 11)), interfaces=[], directives=[], fields=[ ast.FieldDefinition( name=ast.Name(value="world", loc=loc(16, 21)), arguments=[ ast.InputValueDefinition( name=ast.Name(value="flag", loc=loc(22, 26)), type=ast.NamedType( name=ast.Name(value="Boolean", loc=loc(28, 35)), loc=loc(28, 35), ), default_value=ast.BooleanValue( value=True, loc=loc(38, 42) ), directives=[], loc=loc(22, 42), ) ], type=ast.NamedType( name=ast.Name(value="String", loc=loc(45, 51)), loc=loc(45, 51), ), directives=[], loc=loc(16, 51), ) ], loc=loc(1, 53), ) ], loc=loc(1, 53), ) assert doc == expected def test_parses_simple_field_with_list_arg(): # type: () -> None body = """ type Hello { world(things: [String]): String }""" loc = create_loc_fn(body) doc = parse(body) expected = ast.Document( definitions=[ ast.ObjectTypeDefinition( name=ast.Name(value="Hello", loc=loc(6, 11)), interfaces=[], directives=[], fields=[ ast.FieldDefinition( name=ast.Name(value="world", loc=loc(16, 21)), arguments=[ ast.InputValueDefinition( name=ast.Name(value="things", loc=loc(22, 28)), type=ast.ListType( type=ast.NamedType( name=ast.Name(value="String", loc=loc(31, 37)), loc=loc(31, 37), ), loc=loc(30, 38), ), default_value=None, directives=[], loc=loc(22, 38), ) ], type=ast.NamedType( name=ast.Name(value="String", loc=loc(41, 47)), loc=loc(41, 47), ), directives=[], loc=loc(16, 47), ) ], loc=loc(1, 49), ) ], loc=loc(1, 49), ) assert doc == expected def test_parses_simple_field_with_two_args(): # type: () -> None body = """ type Hello { world(argOne: Boolean, argTwo: Int): String }""" loc = create_loc_fn(body) doc = parse(body) expected = ast.Document( definitions=[ ast.ObjectTypeDefinition( name=ast.Name(value="Hello", loc=loc(6, 11)), interfaces=[], directives=[], fields=[ ast.FieldDefinition( name=ast.Name(value="world", loc=loc(16, 21)), arguments=[ ast.InputValueDefinition( name=ast.Name(value="argOne", loc=loc(22, 28)), type=ast.NamedType( name=ast.Name(value="Boolean", loc=loc(30, 37)), loc=loc(30, 37), ), default_value=None, directives=[], loc=loc(22, 37), ), ast.InputValueDefinition( name=ast.Name(value="argTwo", loc=loc(39, 45)), type=ast.NamedType( name=ast.Name(value="Int", loc=loc(47, 50)), loc=loc(47, 50), ), default_value=None, directives=[], loc=loc(39, 50), ), ], type=ast.NamedType( name=ast.Name(value="String", loc=loc(53, 59)), loc=loc(53, 59), ), directives=[], loc=loc(16, 59), ) ], loc=loc(1, 61), ) ], loc=loc(1, 61), ) assert doc == expected def test_parses_simple_union(): # type: () -> None body = "union Hello = World" loc = create_loc_fn(body) doc = parse(body) expected = ast.Document( definitions=[ ast.UnionTypeDefinition( name=ast.Name(value="Hello", loc=loc(6, 11)), directives=[], types=[ ast.NamedType( name=ast.Name(value="World", loc=loc(14, 19)), loc=loc(14, 19) ) ], loc=loc(0, 19), ) ], loc=loc(0, 19), ) assert doc == expected def test_parses_union_with_two_types(): # type: () -> None body = "union Hello = Wo | Rld" loc = create_loc_fn(body) doc = parse(body) expected = ast.Document( definitions=[ ast.UnionTypeDefinition( name=ast.Name(value="Hello", loc=loc(6, 11)), directives=[], types=[ ast.NamedType( name=ast.Name(value="Wo", loc=loc(14, 16)), loc=loc(14, 16) ), ast.NamedType( name=ast.Name(value="Rld", loc=loc(19, 22)), loc=loc(19, 22) ), ], loc=loc(0, 22), ) ], loc=loc(0, 22), ) assert doc == expected def test_parses_scalar(): # type: () -> None body = "scalar Hello" loc = create_loc_fn(body) doc = parse(body) expected = ast.Document( definitions=[ ast.ScalarTypeDefinition( name=ast.Name(value="Hello", loc=loc(7, 12)), directives=[], loc=loc(0, 12), ) ], loc=loc(0, 12), ) assert doc == expected def test_parses_simple_input_object(): # type: () -> None body = """ input Hello { world: String }""" loc = create_loc_fn(body) doc = parse(body) expected = ast.Document( definitions=[ ast.InputObjectTypeDefinition( name=ast.Name(value="Hello", loc=loc(7, 12)), directives=[], fields=[ ast.InputValueDefinition( name=ast.Name(value="world", loc=loc(17, 22)), type=ast.NamedType( name=ast.Name(value="String", loc=loc(24, 30)), loc=loc(24, 30), ), default_value=None, directives=[], loc=loc(17, 30), ) ], loc=loc(1, 32), ) ], loc=loc(1, 32), ) assert doc == expected def test_parsing_simple_input_object_with_args_should_fail(): # type: () -> None body = """ input Hello { world(foo: Int): String } """ with raises(GraphQLSyntaxError) as excinfo: parse(body) assert "Syntax Error GraphQL (3:8) Expected :, found (" in excinfo.value.message graphql-core-legacy-2.3.2/graphql/language/tests/test_schema_printer.py000066400000000000000000000042361365661746200263700ustar00rootroot00000000000000from copy import deepcopy from pytest import raises from graphql import parse from graphql.language import ast from graphql.language.printer import print_ast from .fixtures import SCHEMA_KITCHEN_SINK def test_prints_minimal_ast(): # type: () -> None node = ast.ScalarTypeDefinition(name=ast.Name("foo")) assert print_ast(node) == "scalar foo" def test_print_produces_helpful_error_messages(): # type: () -> None bad_ast = {"random": "Data"} with raises(AssertionError) as excinfo: print_ast(bad_ast) assert "Invalid AST Node: {'random': 'Data'}" in str(excinfo.value) def test_does_not_alter_ast(): # type: () -> None ast = parse(SCHEMA_KITCHEN_SINK) ast_copy = deepcopy(ast) print_ast(ast) assert ast == ast_copy def test_prints_kitchen_sink(): # type: () -> None ast = parse(SCHEMA_KITCHEN_SINK) printed = print_ast(ast) expected = """schema { query: QueryType mutation: MutationType } type Foo implements Bar { one: Type two(argument: InputType!): Type three(argument: InputType, other: String): Int four(argument: String = "string"): String five(argument: [String] = ["string", "string"]): String six(argument: InputType = {key: "value"}): Type } type AnnotatedObject @onObject(arg: "value") { annotatedField(arg: Type = "default" @onArg): Type @onField } interface Bar { one: Type four(argument: String = "string"): String } interface AnnotatedInterface @onInterface { annotatedField(arg: Type @onArg): Type @onField } union Feed = Story | Article | Advert union AnnotatedUnion @onUnion = A | B scalar CustomScalar scalar AnnotatedScalar @onScalar enum Site { DESKTOP MOBILE } enum AnnotatedEnum @onEnum { ANNOTATED_VALUE @onEnumValue OTHER_VALUE } input InputType { key: String! answer: Int = 42 } input AnnotatedInput @onInputObjectType { annotatedField: Type @onField } extend type Foo { seven(argument: [String]): Type } extend type Foo @onType {} type NoFields {} directive @skip(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT directive @include(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT """ assert printed == expected graphql-core-legacy-2.3.2/graphql/language/tests/test_visitor.py000066400000000000000000001363631365661746200250730ustar00rootroot00000000000000from graphql.language.ast import ( Document, Field, Name, OperationDefinition, SelectionSet, ) from graphql.language.parser import parse from graphql.language.printer import print_ast from graphql.language.visitor import ( BREAK, REMOVE, ParallelVisitor, TypeInfoVisitor, Visitor, visit, ) from graphql.type import get_named_type, is_composite_type from graphql.utils.type_info import TypeInfo from ...validation.tests.utils import test_schema from .fixtures import KITCHEN_SINK from graphql.language.ast import Document from graphql.language.ast import OperationDefinition from graphql.language.ast import SelectionSet from typing import Any from typing import Optional from typing import Union from graphql.language.ast import Field from graphql.language.ast import Name from graphql.language.visitor import _Falsey from typing import List from graphql.language.ast import Argument from graphql.language.ast import IntValue def test_allows_editing_a_node_both_on_enter_and_on_leave(): # type: () -> None ast = parse("{ a, b, c { a, b, c } }", no_location=True) class TestVisitor(Visitor): def __init__(self): # type: () -> None self.did_enter = False self.did_leave = False def enter( self, node, # type: Union[Document, OperationDefinition, SelectionSet] *args # type: Any ): # type: (...) -> Optional[OperationDefinition] if isinstance(node, OperationDefinition): self.did_enter = True selection_set = node.selection_set self.selections = None if selection_set: self.selections = selection_set.selections new_selection_set = SelectionSet(selections=[]) return OperationDefinition( name=node.name, variable_definitions=node.variable_definitions, directives=node.directives, loc=node.loc, operation=node.operation, selection_set=new_selection_set, ) def leave( self, node, # type: Union[Document, OperationDefinition, SelectionSet] *args # type: Any ): # type: (...) -> Optional[OperationDefinition] if isinstance(node, OperationDefinition): self.did_leave = True new_selection_set = None if self.selections: new_selection_set = SelectionSet(selections=self.selections) return OperationDefinition( name=node.name, variable_definitions=node.variable_definitions, directives=node.directives, loc=node.loc, operation=node.operation, selection_set=new_selection_set, ) visitor = TestVisitor() edited_ast = visit(ast, visitor) assert ast == parse("{ a, b, c { a, b, c } }", no_location=True) assert edited_ast == ast assert visitor.did_enter assert visitor.did_leave def test_allows_editing_the_root_node_on_enter_and_on_leave(): # type: () -> None ast = parse("{ a, b, c { a, b, c } }", no_location=True) definitions = ast.definitions class TestVisitor(Visitor): def __init__(self): # type: () -> None self.did_enter = False self.did_leave = False def enter(self, node, *args): # type: (Document, *Any) -> Document if isinstance(node, Document): self.did_enter = True return Document(loc=node.loc, definitions=[]) def leave(self, node, *args): # type: (Document, *Any) -> Document if isinstance(node, Document): self.did_leave = True return Document(loc=node.loc, definitions=definitions) visitor = TestVisitor() edited_ast = visit(ast, visitor) assert edited_ast == ast assert visitor.did_enter assert visitor.did_leave def test_allows_for_editing_on_enter(): # type: () -> None ast = parse("{ a, b, c { a, b, c } }", no_location=True) class TestVisitor(Visitor): def enter(self, node, *args): # type: (Any, *Any) -> Optional[Any] if isinstance(node, Field) and node.name.value == "b": return REMOVE 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) def test_allows_for_editing_on_leave(): # type: () -> None ast = parse("{ a, b, c { a, b, c } }", no_location=True) class TestVisitor(Visitor): def leave(self, node, *args): # type: (Union[Field, Name], *Any) -> Optional[Falsey] if isinstance(node, Field) and node.name.value == "b": return REMOVE 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) def test_visits_edited_node(): # type: () -> None added_field = Field(name=Name(value="__typename")) ast = parse("{ a { x } }") class TestVisitor(Visitor): def __init__(self): # type: () -> None self.did_visit_added_field = False def enter(self, node, *args): # type: (Any, *Any) -> Optional[Field] if isinstance(node, Field) and node.name.value == "a": selection_set = node.selection_set selections = [] if selection_set: selections = selection_set.selections new_selection_set = SelectionSet(selections=[added_field] + selections) return Field(name=None, selection_set=new_selection_set) if node is added_field: self.did_visit_added_field = True visitor = TestVisitor() visit(ast, visitor) assert visitor.did_visit_added_field def test_allows_skipping_a_subtree(): # type: () -> None visited = [] ast = parse("{ a, b { x }, c }") class TestVisitor(Visitor): def enter(self, node, *args): # type: (Any, *Any) -> Optional[Any] visited.append(["enter", type(node).__name__, getattr(node, "value", None)]) if isinstance(node, Field) and node.name.value == "b": return False def leave(self, node, *args): # type: (Union[Field, Name, SelectionSet], *Any) -> None visited.append(["leave", type(node).__name__, getattr(node, "value", None)]) visit(ast, TestVisitor()) assert visited == [ ["enter", "Document", None], ["enter", "OperationDefinition", None], ["enter", "SelectionSet", 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", "SelectionSet", None], ["leave", "OperationDefinition", None], ["leave", "Document", None], ] def test_allows_early_exit_while_visiting(): # type: () -> None visited = [] ast = parse("{ a, b { x }, c }") class TestVisitor(Visitor): def enter(self, node, *args): # type: (Any, *Any) -> Optional[Any] visited.append(["enter", type(node).__name__, getattr(node, "value", None)]) if isinstance(node, Name) and node.value == "x": return BREAK def leave(self, node, *args): # type: (Union[Field, Name], *Any) -> None visited.append(["leave", type(node).__name__, getattr(node, "value", None)]) visit(ast, TestVisitor()) assert visited == [ ["enter", "Document", None], ["enter", "OperationDefinition", None], ["enter", "SelectionSet", None], ["enter", "Field", None], ["enter", "Name", "a"], ["leave", "Name", "a"], ["leave", "Field", None], ["enter", "Field", None], ["enter", "Name", "b"], ["leave", "Name", "b"], ["enter", "SelectionSet", None], ["enter", "Field", None], ["enter", "Name", "x"], ] def test_allows_a_named_functions_visitor_api(): # type: () -> None visited = [] ast = parse("{ a, b { x }, c }") class TestVisitor(Visitor): def enter_Name(self, node, *args): # type: (Name, *Any) -> None visited.append(["enter", type(node).__name__, getattr(node, "value", None)]) def enter_SelectionSet(self, node, *args): # type: (SelectionSet, *Any) -> None visited.append(["enter", type(node).__name__, getattr(node, "value", None)]) def leave_SelectionSet(self, node, *args): # type: (SelectionSet, *Any) -> None visited.append(["leave", type(node).__name__, getattr(node, "value", None)]) visit(ast, TestVisitor()) assert visited == [ ["enter", "SelectionSet", None], ["enter", "Name", "a"], ["enter", "Name", "b"], ["enter", "SelectionSet", None], ["enter", "Name", "x"], ["leave", "SelectionSet", None], ["enter", "Name", "c"], ["leave", "SelectionSet", None], ] def test_visits_kitchen_sink(): # type: () -> None visited = [] ast = parse(KITCHEN_SINK) class TestVisitor(Visitor): def enter(self, node, key, parent, *args): # type: (Any, Union[None, int, str], Any, *List[Any]) -> None kind = parent and type(parent).__name__ if kind == "list": kind = None visited.append(["enter", type(node).__name__, key, kind]) def leave(self, node, key, parent, *args): # type: (Any, Union[int, str], Any, *List[Any]) -> None kind = parent and type(parent).__name__ if kind == "list": kind = None visited.append(["leave", type(node).__name__, key, kind]) visit(ast, TestVisitor()) assert visited == [ ["enter", "Document", None, None], ["enter", "OperationDefinition", 0, None], ["enter", "Name", "name", "OperationDefinition"], ["leave", "Name", "name", "OperationDefinition"], ["enter", "VariableDefinition", 0, None], ["enter", "Variable", "variable", "VariableDefinition"], ["enter", "Name", "name", "Variable"], ["leave", "Name", "name", "Variable"], ["leave", "Variable", "variable", "VariableDefinition"], ["enter", "NamedType", "type", "VariableDefinition"], ["enter", "Name", "name", "NamedType"], ["leave", "Name", "name", "NamedType"], ["leave", "NamedType", "type", "VariableDefinition"], ["leave", "VariableDefinition", 0, None], ["enter", "VariableDefinition", 1, None], ["enter", "Variable", "variable", "VariableDefinition"], ["enter", "Name", "name", "Variable"], ["leave", "Name", "name", "Variable"], ["leave", "Variable", "variable", "VariableDefinition"], ["enter", "NamedType", "type", "VariableDefinition"], ["enter", "Name", "name", "NamedType"], ["leave", "Name", "name", "NamedType"], ["leave", "NamedType", "type", "VariableDefinition"], ["enter", "EnumValue", "default_value", "VariableDefinition"], ["leave", "EnumValue", "default_value", "VariableDefinition"], ["leave", "VariableDefinition", 1, None], ["enter", "SelectionSet", "selection_set", "OperationDefinition"], ["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", "ListValue", "value", "Argument"], ["enter", "IntValue", 0, None], ["leave", "IntValue", 0, None], ["enter", "IntValue", 1, None], ["leave", "IntValue", 1, None], ["leave", "ListValue", "value", "Argument"], ["leave", "Argument", 0, None], ["enter", "SelectionSet", "selection_set", "Field"], ["enter", "Field", 0, None], ["enter", "Name", "name", "Field"], ["leave", "Name", "name", "Field"], ["leave", "Field", 0, None], ["enter", "InlineFragment", 1, None], ["enter", "NamedType", "type_condition", "InlineFragment"], ["enter", "Name", "name", "NamedType"], ["leave", "Name", "name", "NamedType"], ["leave", "NamedType", "type_condition", "InlineFragment"], ["enter", "Directive", 0, None], ["enter", "Name", "name", "Directive"], ["leave", "Name", "name", "Directive"], ["leave", "Directive", 0, None], ["enter", "SelectionSet", "selection_set", "InlineFragment"], ["enter", "Field", 0, None], ["enter", "Name", "name", "Field"], ["leave", "Name", "name", "Field"], ["enter", "SelectionSet", "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", "IntValue", "value", "Argument"], ["leave", "IntValue", "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", "SelectionSet", "selection_set", "Field"], ["enter", "Field", 0, None], ["enter", "Name", "name", "Field"], ["leave", "Name", "name", "Field"], ["leave", "Field", 0, None], ["enter", "FragmentSpread", 1, None], ["enter", "Name", "name", "FragmentSpread"], ["leave", "Name", "name", "FragmentSpread"], ["leave", "FragmentSpread", 1, None], ["leave", "SelectionSet", "selection_set", "Field"], ["leave", "Field", 1, None], ["leave", "SelectionSet", "selection_set", "Field"], ["leave", "Field", 0, None], ["leave", "SelectionSet", "selection_set", "InlineFragment"], ["leave", "InlineFragment", 1, None], ["enter", "InlineFragment", 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", "SelectionSet", "selection_set", "InlineFragment"], ["enter", "Field", 0, None], ["enter", "Name", "name", "Field"], ["leave", "Name", "name", "Field"], ["leave", "Field", 0, None], ["leave", "SelectionSet", "selection_set", "InlineFragment"], ["leave", "InlineFragment", 2, None], ["enter", "InlineFragment", 3, None], ["enter", "SelectionSet", "selection_set", "InlineFragment"], ["enter", "Field", 0, None], ["enter", "Name", "name", "Field"], ["leave", "Name", "name", "Field"], ["leave", "Field", 0, None], ["leave", "SelectionSet", "selection_set", "InlineFragment"], ["leave", "InlineFragment", 3, None], ["leave", "SelectionSet", "selection_set", "Field"], ["leave", "Field", 0, None], ["leave", "SelectionSet", "selection_set", "OperationDefinition"], ["leave", "OperationDefinition", 0, None], ["enter", "OperationDefinition", 1, None], ["enter", "Name", "name", "OperationDefinition"], ["leave", "Name", "name", "OperationDefinition"], ["enter", "SelectionSet", "selection_set", "OperationDefinition"], ["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", "IntValue", "value", "Argument"], ["leave", "IntValue", "value", "Argument"], ["leave", "Argument", 0, None], ["enter", "Directive", 0, None], ["enter", "Name", "name", "Directive"], ["leave", "Name", "name", "Directive"], ["leave", "Directive", 0, None], ["enter", "SelectionSet", "selection_set", "Field"], ["enter", "Field", 0, None], ["enter", "Name", "name", "Field"], ["leave", "Name", "name", "Field"], ["enter", "SelectionSet", "selection_set", "Field"], ["enter", "Field", 0, None], ["enter", "Name", "name", "Field"], ["leave", "Name", "name", "Field"], ["leave", "Field", 0, None], ["leave", "SelectionSet", "selection_set", "Field"], ["leave", "Field", 0, None], ["leave", "SelectionSet", "selection_set", "Field"], ["leave", "Field", 0, None], ["leave", "SelectionSet", "selection_set", "OperationDefinition"], ["leave", "OperationDefinition", 1, None], ["enter", "OperationDefinition", 2, None], ["enter", "Name", "name", "OperationDefinition"], ["leave", "Name", "name", "OperationDefinition"], ["enter", "VariableDefinition", 0, None], ["enter", "Variable", "variable", "VariableDefinition"], ["enter", "Name", "name", "Variable"], ["leave", "Name", "name", "Variable"], ["leave", "Variable", "variable", "VariableDefinition"], ["enter", "NamedType", "type", "VariableDefinition"], ["enter", "Name", "name", "NamedType"], ["leave", "Name", "name", "NamedType"], ["leave", "NamedType", "type", "VariableDefinition"], ["leave", "VariableDefinition", 0, None], ["enter", "SelectionSet", "selection_set", "OperationDefinition"], ["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", "SelectionSet", "selection_set", "Field"], ["enter", "Field", 0, None], ["enter", "Name", "name", "Field"], ["leave", "Name", "name", "Field"], ["enter", "SelectionSet", "selection_set", "Field"], ["enter", "Field", 0, None], ["enter", "Name", "name", "Field"], ["leave", "Name", "name", "Field"], ["enter", "SelectionSet", "selection_set", "Field"], ["enter", "Field", 0, None], ["enter", "Name", "name", "Field"], ["leave", "Name", "name", "Field"], ["leave", "Field", 0, None], ["leave", "SelectionSet", "selection_set", "Field"], ["leave", "Field", 0, None], ["enter", "Field", 1, None], ["enter", "Name", "name", "Field"], ["leave", "Name", "name", "Field"], ["enter", "SelectionSet", "selection_set", "Field"], ["enter", "Field", 0, None], ["enter", "Name", "name", "Field"], ["leave", "Name", "name", "Field"], ["leave", "Field", 0, None], ["leave", "SelectionSet", "selection_set", "Field"], ["leave", "Field", 1, None], ["leave", "SelectionSet", "selection_set", "Field"], ["leave", "Field", 0, None], ["leave", "SelectionSet", "selection_set", "Field"], ["leave", "Field", 0, None], ["leave", "SelectionSet", "selection_set", "OperationDefinition"], ["leave", "OperationDefinition", 2, None], ["enter", "FragmentDefinition", 3, None], ["enter", "Name", "name", "FragmentDefinition"], ["leave", "Name", "name", "FragmentDefinition"], ["enter", "NamedType", "type_condition", "FragmentDefinition"], ["enter", "Name", "name", "NamedType"], ["leave", "Name", "name", "NamedType"], ["leave", "NamedType", "type_condition", "FragmentDefinition"], ["enter", "SelectionSet", "selection_set", "FragmentDefinition"], ["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", "ObjectValue", "value", "Argument"], ["enter", "ObjectField", 0, None], ["enter", "Name", "name", "ObjectField"], ["leave", "Name", "name", "ObjectField"], ["enter", "StringValue", "value", "ObjectField"], ["leave", "StringValue", "value", "ObjectField"], ["leave", "ObjectField", 0, None], ["leave", "ObjectValue", "value", "Argument"], ["leave", "Argument", 2, None], ["leave", "Field", 0, None], ["leave", "SelectionSet", "selection_set", "FragmentDefinition"], ["leave", "FragmentDefinition", 3, None], ["enter", "OperationDefinition", 4, None], ["enter", "SelectionSet", "selection_set", "OperationDefinition"], ["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", "BooleanValue", "value", "Argument"], ["leave", "BooleanValue", "value", "Argument"], ["leave", "Argument", 0, None], ["enter", "Argument", 1, None], ["enter", "Name", "name", "Argument"], ["leave", "Name", "name", "Argument"], ["enter", "BooleanValue", "value", "Argument"], ["leave", "BooleanValue", "value", "Argument"], ["leave", "Argument", 1, None], ["leave", "Field", 0, None], ["enter", "Field", 1, None], ["enter", "Name", "name", "Field"], ["leave", "Name", "name", "Field"], ["leave", "Field", 1, None], ["leave", "SelectionSet", "selection_set", "OperationDefinition"], ["leave", "OperationDefinition", 4, None], ["leave", "Document", None, None], ] def test_visits_in_pararell_allows_skipping_a_subtree(): # type: () -> None visited = [] ast = parse("{ a, b { x }, c }") class TestVisitor(Visitor): def enter(self, node, key, parent, *args): # type: (Any, Union[None, int, str], Any, *List[Any]) -> Optional[Any] visited.append(["enter", type(node).__name__, getattr(node, "value", None)]) if type(node).__name__ == "Field" and node.name.value == "b": return False def leave( self, node, # type: Union[Field, Name, SelectionSet] key, # type: Union[int, str] parent, # type: Union[List[Field], Field, OperationDefinition] *args # type: List[Any] ): # type: (...) -> None visited.append(["leave", type(node).__name__, getattr(node, "value", None)]) visit(ast, ParallelVisitor([TestVisitor()])) assert visited == [ ["enter", "Document", None], ["enter", "OperationDefinition", None], ["enter", "SelectionSet", 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", "SelectionSet", None], ["leave", "OperationDefinition", None], ["leave", "Document", None], ] def test_visits_in_pararell_allows_skipping_different_subtrees(): # type: () -> None visited = [] ast = parse("{ a { x }, b { y} }") class TestVisitor(Visitor): def __init__(self, name): # type: (str) -> None self.name = name def enter( self, node, # type: Union[Document, OperationDefinition, SelectionSet] key, # type: Union[None, int, str] parent, # type: Union[List[OperationDefinition], None, OperationDefinition] *args # type: Any ): # type: (...) -> Optional[Any] visited.append( [ "no-{}".format(self.name), "enter", type(node).__name__, getattr(node, "value", None), ] ) if type(node).__name__ == "Field" and node.name.value == self.name: return False def leave( self, node, # type: Union[Field, Name, SelectionSet] key, # type: Union[int, str] parent, # type: Union[List[Field], Field] *args # type: List[Any] ): # type: (...) -> None visited.append( [ "no-{}".format(self.name), "leave", type(node).__name__, getattr(node, "value", None), ] ) visit(ast, ParallelVisitor([TestVisitor("a"), TestVisitor("b")])) assert visited == [ ["no-a", "enter", "Document", None], ["no-b", "enter", "Document", None], ["no-a", "enter", "OperationDefinition", None], ["no-b", "enter", "OperationDefinition", None], ["no-a", "enter", "SelectionSet", None], ["no-b", "enter", "SelectionSet", None], ["no-a", "enter", "Field", None], ["no-b", "enter", "Field", None], ["no-b", "enter", "Name", "a"], ["no-b", "leave", "Name", "a"], ["no-b", "enter", "SelectionSet", None], ["no-b", "enter", "Field", None], ["no-b", "enter", "Name", "x"], ["no-b", "leave", "Name", "x"], ["no-b", "leave", "Field", None], ["no-b", "leave", "SelectionSet", 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", "SelectionSet", None], ["no-a", "enter", "Field", None], ["no-a", "enter", "Name", "y"], ["no-a", "leave", "Name", "y"], ["no-a", "leave", "Field", None], ["no-a", "leave", "SelectionSet", None], ["no-a", "leave", "Field", None], ["no-a", "leave", "SelectionSet", None], ["no-b", "leave", "SelectionSet", None], ["no-a", "leave", "OperationDefinition", None], ["no-b", "leave", "OperationDefinition", None], ["no-a", "leave", "Document", None], ["no-b", "leave", "Document", None], ] def test_visits_in_pararell_allows_early_exit_while_visiting(): # type: () -> None visited = [] ast = parse("{ a, b { x }, c }") class TestVisitor(Visitor): def enter(self, node, key, parent, *args): # type: (Any, Union[None, int, str], Any, *List[Any]) -> None visited.append(["enter", type(node).__name__, getattr(node, "value", None)]) def leave( self, node, # type: Union[Field, Name] key, # type: Union[int, str] parent, # type: Union[List[Field], Field] *args # type: List[Any] ): # type: (...) -> Optional[object] visited.append(["leave", type(node).__name__, getattr(node, "value", None)]) if type(node).__name__ == "Name" and node.value == "x": return BREAK visit(ast, ParallelVisitor([TestVisitor()])) assert visited == [ ["enter", "Document", None], ["enter", "OperationDefinition", None], ["enter", "SelectionSet", None], ["enter", "Field", None], ["enter", "Name", "a"], ["leave", "Name", "a"], ["leave", "Field", None], ["enter", "Field", None], ["enter", "Name", "b"], ["leave", "Name", "b"], ["enter", "SelectionSet", None], ["enter", "Field", None], ["enter", "Name", "x"], ["leave", "Name", "x"], ] def test_visits_in_pararell_allows_early_exit_from_different_points(): # type: () -> None visited = [] ast = parse("{ a { y }, b { x } }") class TestVisitor(Visitor): def __init__(self, name): # type: (str) -> None self.name = name def enter( self, node, # type: Union[Document, OperationDefinition, SelectionSet] key, # type: Union[None, int, str] parent, # type: Union[List[OperationDefinition], None, OperationDefinition] *args # type: Any ): # type: (...) -> None visited.append( [ "break-{}".format(self.name), "enter", type(node).__name__, getattr(node, "value", None), ] ) def leave( self, node, # type: Union[Field, Name] key, # type: Union[int, str] parent, # type: Union[List[Field], Field] *args # type: List[Any] ): # type: (...) -> Optional[Any] visited.append( [ "break-{}".format(self.name), "leave", type(node).__name__, getattr(node, "value", None), ] ) if type(node).__name__ == "Field" and node.name.value == self.name: return BREAK visit(ast, ParallelVisitor([TestVisitor("a"), TestVisitor("b")])) assert visited == [ ["break-a", "enter", "Document", None], ["break-b", "enter", "Document", None], ["break-a", "enter", "OperationDefinition", None], ["break-b", "enter", "OperationDefinition", None], ["break-a", "enter", "SelectionSet", None], ["break-b", "enter", "SelectionSet", 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", "SelectionSet", None], ["break-b", "enter", "SelectionSet", 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", "SelectionSet", None], ["break-b", "leave", "SelectionSet", 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", "SelectionSet", None], ["break-b", "enter", "Field", None], ["break-b", "enter", "Name", "x"], ["break-b", "leave", "Name", "x"], ["break-b", "leave", "Field", None], ["break-b", "leave", "SelectionSet", None], ["break-b", "leave", "Field", None], ] def test_visits_in_pararell_allows_for_editing_on_enter(): # type: () -> None visited = [] ast = parse("{ a, b, c { a, b, c } }", no_location=True) class TestVisitor1(Visitor): def enter(self, node, key, parent, *args): # type: (Any, Union[None, int, str], Any, *List[Any]) -> Optional[Any] if type(node).__name__ == "Field" and node.name.value == "b": return REMOVE class TestVisitor2(Visitor): def enter(self, node, key, parent, *args): # type: (Any, Union[None, int, str], Any, *List[Any]) -> None visited.append(["enter", type(node).__name__, getattr(node, "value", None)]) def leave( self, node, # type: Union[Field, Name] key, # type: Union[int, str] parent, # type: Union[List[Field], Field] *args # type: List[Any] ): # type: (...) -> None visited.append(["leave", type(node).__name__, getattr(node, "value", None)]) 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", "OperationDefinition", None], ["enter", "SelectionSet", None], ["enter", "Field", None], ["enter", "Name", "a"], ["leave", "Name", "a"], ["leave", "Field", None], ["enter", "Field", None], ["enter", "Name", "c"], ["leave", "Name", "c"], ["enter", "SelectionSet", 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", "SelectionSet", None], ["leave", "Field", None], ["leave", "SelectionSet", None], ["leave", "OperationDefinition", None], ["leave", "Document", None], ] def test_visits_in_pararell_allows_for_editing_on_leave(): # type: () -> None visited = [] ast = parse("{ a, b, c { a, b, c } }", no_location=True) class TestVisitor1(Visitor): def leave( self, node, # type: Union[Field, Name] key, # type: Union[int, str] parent, # type: Union[List[Field], Field] *args # type: List[Any] ): # type: (...) -> Optional[Falsey] if type(node).__name__ == "Field" and node.name.value == "b": return REMOVE class TestVisitor2(Visitor): def enter(self, node, key, parent, *args): # type: (Any, Union[None, int, str], Any, *List[Any]) -> None visited.append(["enter", type(node).__name__, getattr(node, "value", None)]) def leave( self, node, # type: Union[Field, Name] key, # type: Union[int, str] parent, # type: Union[List[Field], Field] *args # type: List[Any] ): # type: (...) -> None visited.append(["leave", type(node).__name__, getattr(node, "value", None)]) 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", "OperationDefinition", None], ["enter", "SelectionSet", 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", "SelectionSet", 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", "SelectionSet", None], ["leave", "Field", None], ["leave", "SelectionSet", None], ["leave", "OperationDefinition", None], ["leave", "Document", None], ] def test_visits_with_typeinfo_maintains_type_info_during_visit(): # type: () -> None visited = [] ast = parse("{ human(id: 4) { name, pets { name }, unknown } }") type_info = TypeInfo(test_schema) class TestVisitor(Visitor): def enter(self, node, key, parent, *args): # type: (Any, Union[None, int, str], Any, *List[Any]) -> None parent_type = type_info.get_parent_type() _type = type_info.get_type() input_type = type_info.get_input_type() visited.append( [ "enter", type(node).__name__, node.value if type(node).__name__ == "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, ] ) def leave( self, node, # type: Union[Argument, IntValue, Name] key, # type: Union[int, str] parent, # type: Union[List[Argument], Argument, Field] *args # type: List[Any] ): # type: (...) -> None parent_type = type_info.get_parent_type() _type = type_info.get_type() input_type = type_info.get_input_type() visited.append( [ "leave", type(node).__name__, node.value if type(node).__name__ == "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", "OperationDefinition", None, None, "QueryRoot", None], ["enter", "SelectionSet", 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", "IntValue", None, "QueryRoot", "Human", "ID"], ["leave", "IntValue", None, "QueryRoot", "Human", "ID"], ["leave", "Argument", None, "QueryRoot", "Human", "ID"], ["enter", "SelectionSet", 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", "SelectionSet", 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", "SelectionSet", 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", "SelectionSet", None, "Human", "Human", None], ["leave", "Field", None, "QueryRoot", "Human", None], ["leave", "SelectionSet", None, "QueryRoot", "QueryRoot", None], ["leave", "OperationDefinition", None, None, "QueryRoot", None], ["leave", "Document", None, None, None, None], ] def test_visits_with_typeinfo_maintains_type_info_during_edit(): # type: () -> None visited = [] ast = parse("{ human(id: 4) { name, pets }, alien }") type_info = TypeInfo(test_schema) class TestVisitor(Visitor): def enter(self, node, key, parent, *args): # type: (Any, Union[None, int, str], Any, *List[Any]) -> Optional[Any] parent_type = type_info.get_parent_type() _type = type_info.get_type() input_type = type_info.get_input_type() visited.append( [ "enter", type(node).__name__, node.value if type(node).__name__ == "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 ( type(node).__name__ == "Field" and not node.selection_set and is_composite_type(get_named_type(_type)) ): return Field( alias=node.alias, name=node.name, arguments=node.arguments, directives=node.directives, selection_set=SelectionSet([Field(name=Name(value="__typename"))]), ) def leave( self, node, # type: Union[Argument, IntValue, Name] key, # type: Union[int, str] parent, # type: Union[List[Argument], Argument, Field] *args # type: List[Any] ): # type: (...) -> None parent_type = type_info.get_parent_type() _type = type_info.get_type() input_type = type_info.get_input_type() visited.append( [ "leave", type(node).__name__, node.value if type(node).__name__ == "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 print_ast(ast) == print_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", "OperationDefinition", None, None, "QueryRoot", None], ["enter", "SelectionSet", 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", "IntValue", None, "QueryRoot", "Human", "ID"], ["leave", "IntValue", None, "QueryRoot", "Human", "ID"], ["leave", "Argument", None, "QueryRoot", "Human", "ID"], ["enter", "SelectionSet", 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", "SelectionSet", 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", "SelectionSet", None, "Pet", "[Pet]", None], ["leave", "Field", None, "Human", "[Pet]", None], ["leave", "SelectionSet", 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", "SelectionSet", 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", "SelectionSet", None, "Alien", "Alien", None], ["leave", "Field", None, "QueryRoot", "Alien", None], ["leave", "SelectionSet", None, "QueryRoot", "QueryRoot", None], ["leave", "OperationDefinition", None, None, "QueryRoot", None], ["leave", "Document", None, None, None, None], ] graphql-core-legacy-2.3.2/graphql/language/tests/test_visitor_meta.py000066400000000000000000000023671365661746200260750ustar00rootroot00000000000000from graphql.language import ast from graphql.language.visitor import Visitor def test_visitor_meta_creates_enter_and_leave_handlers(): # type: () -> None class MyVisitor(Visitor): def enter_OperationDefinition(self): pass def leave_OperationDefinition(self): pass assert MyVisitor._get_enter_handler(ast.OperationDefinition) assert MyVisitor._get_leave_handler(ast.OperationDefinition) def test_visitor_inherits_parent_definitions(): # type: () -> None class MyVisitor(Visitor): def enter_OperationDefinition(self): pass def leave_OperationDefinition(self): pass assert MyVisitor._get_enter_handler(ast.OperationDefinition) assert MyVisitor._get_leave_handler(ast.OperationDefinition) class MyVisitorSubclassed(MyVisitor): def enter_FragmentDefinition(self): pass def leave_FragmentDefinition(self): pass assert MyVisitorSubclassed._get_enter_handler(ast.OperationDefinition) assert MyVisitorSubclassed._get_leave_handler(ast.OperationDefinition) assert MyVisitorSubclassed._get_enter_handler(ast.FragmentDefinition) assert MyVisitorSubclassed._get_leave_handler(ast.FragmentDefinition) graphql-core-legacy-2.3.2/graphql/language/visitor.py000066400000000000000000000205301365661746200226560ustar00rootroot00000000000000from copy import copy import six from . import ast from .visitor_meta import QUERY_DOCUMENT_KEYS, VisitorMeta # Necessary for static type checking if False: # flake8: noqa from typing import Any, List, Optional, Union, Tuple, Dict from ..utils.type_info import TypeInfo class _Falsey(object): def __nonzero__(self): return False def __bool__(self): # type: () -> bool return False class _Break(object): pass BREAK = _Break() REMOVE = _Falsey() class Stack(object): __slots__ = "in_array", "index", "keys", "edits", "prev" def __init__(self, in_array, index, keys, edits, prev): # type: (bool, int, Any, List[Tuple[Union[str, int], Any]], Optional[Stack]) -> None self.in_array = in_array self.index = index self.keys = keys self.edits = edits self.prev = prev def visit(root, visitor, key_map=None): # type: (Union[ast.Node, List[ast.Node]], Visitor, Optional[Dict[ast.Node, Tuple]]) -> Any visitor_keys = key_map or QUERY_DOCUMENT_KEYS stack = None # type: Optional[Stack] in_array = isinstance(root, list) keys = [root] index = -1 edits = [] # type: List[Tuple[Union[str, int], Any]] parent = None # type: Optional[ast.Node] path = [] # type: List ancestors = [] # type: List[ast.Node] new_root = root leave = visitor.leave enter = visitor.enter path_pop = path.pop ancestors_pop = ancestors.pop path_append = path.append ancestors_append = ancestors.append while True: index += 1 is_leaving = index == len(keys) is_edited = is_leaving and edits if is_leaving: key = path_pop() if ancestors else None node = parent parent = ancestors_pop() if ancestors else None if is_edited: if in_array: node = list(node) # type: ignore else: node = copy(node) edit_offset = 0 for edit_key, edit_value in edits: if in_array: edit_key -= edit_offset # type: ignore if in_array and edit_value is REMOVE: node.pop(edit_key) # type: ignore edit_offset += 1 else: if isinstance(node, list): node[edit_key] = edit_value else: setattr(node, edit_key, edit_value) # type: ignore index = stack.index # type: ignore keys = stack.keys # type: ignore edits = stack.edits # type: ignore in_array = stack.in_array # type: ignore stack = stack.prev # type: ignore else: if parent: key = index if in_array else keys[index] if isinstance(parent, list): node = parent[key] else: node = getattr(parent, key, None) else: key = None node = new_root # type: ignore if node is REMOVE or node is None: continue if parent: path_append(key) result = None if not isinstance(node, list): assert isinstance(node, ast.Node), "Invalid AST Node: " + repr(node) if is_leaving: result = leave(node, key, parent, path, ancestors) else: result = enter(node, key, parent, path, ancestors) if result is BREAK: break if 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, ast.Node): node = result else: path_pop() continue if result is None and is_edited: edits.append((key, node)) if not is_leaving: stack = Stack(in_array, index, keys, edits, stack) in_array = isinstance(node, list) keys = ( node # type: ignore if in_array else visitor_keys.get(type(node), None) or [] # type: ignore ) index = -1 edits = [] if parent: ancestors_append(parent) parent = node if not stack: break if edits: new_root = edits[-1][1] return new_root @six.add_metaclass(VisitorMeta) class Visitor(object): __slots__ = () def enter( self, node, # type: Any key, # type: Union[None, int, str] parent, # type: Any path, # type: List[Union[int, str]] ancestors, # type: List[Any] ): # type: (...) -> Any method = self._get_enter_handler(type(node)) # type: ignore if method: return method(self, node, key, parent, path, ancestors) return None def leave( self, node, # type: Any key, # type: Union[None, int, str] parent, # type: Any path, # type: List[Union[int, str]] ancestors, # type: List[Any] ): # type: (...) -> Any method = self._get_leave_handler(type(node)) # type: ignore if method: return method(self, node, key, parent, path, ancestors) return None class ParallelVisitor(Visitor): __slots__ = "skipping", "visitors" def __init__(self, visitors): # type: (List[Any]) -> None self.visitors = visitors self.skipping = [None] * len( visitors ) # type: List[Union[ast.Node, _Break, _Falsey, None]] return None def enter( self, node, # type: Any key, # type: Union[None, int, str] parent, # type: Any path, # type: List[Union[int, str]] ancestors, # type: List[Any] ): # type: (...) -> Any for i, visitor in enumerate(self.visitors): if not self.skipping[i]: result = visitor.enter(node, key, parent, path, ancestors) if result is False: self.skipping[i] = node elif result is BREAK: self.skipping[i] = BREAK elif result is not None: return result return None def leave( self, node, # type: Any key, # type: Union[None, int, str] parent, # type: Any path, # type: List[Union[int, str]] ancestors, # type: List[Any] ): # type: (...) -> Any for i, visitor in enumerate(self.visitors): if not self.skipping[i]: result = visitor.leave(node, key, parent, path, ancestors) if result is BREAK: self.skipping[i] = BREAK elif result is not None and result is not False: return result elif self.skipping[i] == node: self.skipping[i] = REMOVE return None class TypeInfoVisitor(Visitor): __slots__ = "visitor", "type_info" def __init__(self, type_info, visitor): # type: (TypeInfo, Visitor) -> None self.type_info = type_info self.visitor = visitor def enter( self, node, # type: Any key, # type: Union[None, int, str] parent, # type: Any path, # type: List[Union[int, str]] ancestors, # type: List[Any] ): # type: (...) -> Optional[Any] self.type_info.enter(node) result = self.visitor.enter(node, key, parent, path, ancestors) if result is not None: self.type_info.leave(node) if isinstance(result, ast.Node): self.type_info.enter(result) return result def leave( self, node, # type: Any key, # type: Union[None, int, str] parent, # type: Any path, # type: List[Union[int, str]] ancestors, # type: List[Any] ): # type: (...) -> Optional[Any] result = self.visitor.leave(node, key, parent, path, ancestors) self.type_info.leave(node) return result graphql-core-legacy-2.3.2/graphql/language/visitor_meta.py000066400000000000000000000056761365661746200237020ustar00rootroot00000000000000from . import ast QUERY_DOCUMENT_KEYS = { ast.Name: (), ast.Document: ("definitions",), ast.OperationDefinition: ( "name", "variable_definitions", "directives", "selection_set", ), ast.VariableDefinition: ("variable", "type", "default_value"), ast.Variable: ("name",), ast.SelectionSet: ("selections",), ast.Field: ("alias", "name", "arguments", "directives", "selection_set"), ast.Argument: ("name", "value"), ast.FragmentSpread: ("name", "directives"), ast.InlineFragment: ("type_condition", "directives", "selection_set"), ast.FragmentDefinition: ("name", "type_condition", "directives", "selection_set"), ast.IntValue: (), ast.FloatValue: (), ast.StringValue: (), ast.BooleanValue: (), ast.EnumValue: (), ast.ListValue: ("values",), ast.ObjectValue: ("fields",), ast.ObjectField: ("name", "value"), ast.Directive: ("name", "arguments"), ast.NamedType: ("name",), ast.ListType: ("type",), ast.NonNullType: ("type",), ast.SchemaDefinition: ("directives", "operation_types"), ast.OperationTypeDefinition: ("type",), ast.ScalarTypeDefinition: ("name", "directives"), ast.ObjectTypeDefinition: ("name", "interfaces", "directives", "fields"), ast.FieldDefinition: ("name", "arguments", "directives", "type"), ast.InputValueDefinition: ("name", "type", "directives", "default_value"), ast.InterfaceTypeDefinition: ("name", "directives", "fields"), ast.UnionTypeDefinition: ("name", "directives", "types"), ast.EnumTypeDefinition: ("name", "directives", "values"), ast.EnumValueDefinition: ("name", "directives"), ast.InputObjectTypeDefinition: ("name", "directives", "fields"), ast.TypeExtensionDefinition: ("definition",), ast.DirectiveDefinition: ("name", "arguments", "locations"), } AST_KIND_TO_TYPE = {c.__name__: c for c in QUERY_DOCUMENT_KEYS.keys()} class VisitorMeta(type): def __new__(cls, name, bases, attrs): enter_handlers = {} leave_handlers = {} for base in bases: if hasattr(base, "_enter_handlers"): enter_handlers.update(base._enter_handlers) if hasattr(base, "_leave_handlers"): leave_handlers.update(base._leave_handlers) for attr, val in attrs.items(): if attr.startswith("enter_"): ast_kind = attr[6:] ast_type = AST_KIND_TO_TYPE.get(ast_kind) enter_handlers[ast_type] = val elif attr.startswith("leave_"): ast_kind = attr[6:] ast_type = AST_KIND_TO_TYPE.get(ast_kind) leave_handlers[ast_type] = val attrs["_enter_handlers"] = enter_handlers attrs["_leave_handlers"] = leave_handlers attrs["_get_enter_handler"] = enter_handlers.get attrs["_get_leave_handler"] = leave_handlers.get return super(VisitorMeta, cls).__new__(cls, name, bases, attrs) graphql-core-legacy-2.3.2/graphql/py.typed000066400000000000000000000000001365661746200205070ustar00rootroot00000000000000graphql-core-legacy-2.3.2/graphql/pyutils/000077500000000000000000000000001365661746200205335ustar00rootroot00000000000000graphql-core-legacy-2.3.2/graphql/pyutils/__init__.py000066400000000000000000000000001365661746200226320ustar00rootroot00000000000000graphql-core-legacy-2.3.2/graphql/pyutils/cached_property.py000066400000000000000000000013131365661746200242560ustar00rootroot00000000000000# Necessary for static type checking if False: # flake8: noqa from typing import Any class cached_property(object): """ A property that is only computed once per instance and then replaces itself with an ordinary attribute. Deleting the attribute resets the property. Source: https://github.com/bottlepy/bottle/commit/fa7733e075da0d790d809aa3d2f53071897e6f76 """ def __init__(self, func): self.__doc__ = getattr(func, "__doc__") self.func = func def __get__(self, obj, cls): # type: (Any, type) -> Any if obj is None: return self value = obj.__dict__[self.func.__name__] = self.func(obj) return value graphql-core-legacy-2.3.2/graphql/pyutils/compat.py000066400000000000000000000132041365661746200223700ustar00rootroot00000000000000# flake8: noqa # Copyright (c) 2010-2013 Benjamin Peterson # # 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. from __future__ import absolute_import import operator import sys import types try: from enum import Enum except ImportError: from .enum import Enum # type: ignore if False: from typing import Callable PY2 = sys.version_info[0] == 2 PY3 = sys.version_info[0] == 3 if PY3: string_types = (str,) integer_types = (int,) class_types = (type,) text_type = str binary_type = bytes else: string_types = (basestring,) integer_types = (int, long) class_types = (type, types.ClassType) text_type = unicode binary_type = str try: advance_iterator = next except NameError: def advance_iterator(it): # type: ignore return it.next() next = advance_iterator # type: Callable try: callable = callable # type: Callable except NameError: def callable(obj): # type: ignore return any("__call__" in klass.__dict__ for klass in type(obj).__mro__) if PY3: Iterator = object else: class Iterator(object): def next(self): return type(self).__next__(self) if PY3: def iterkeys(d, **kw): return iter(d.keys(**kw)) def itervalues(d, **kw): return iter(d.values(**kw)) def iteritems(d, **kw): return iter(d.items(**kw)) def iterlists(d, **kw): return iter(d.lists(**kw)) else: def iterkeys(d, **kw): return d.iterkeys(**kw) def itervalues(d, **kw): return d.itervalues(**kw) def iteritems(d, **kw): return d.iteritems(**kw) def iterlists(d, **kw): return d.iterlists(**kw) if PY3: def b(s): return s.encode("latin-1") def u(s): return s import io StringIO = io.StringIO BytesIO = io.BytesIO else: def b(s): return s # Workaround for standalone backslash def u(s): return unicode(s.replace(r"\\", r"\\\\"), "unicode_escape") import StringIO StringIO = BytesIO = StringIO.StringIO if PY3: exec_ = getattr(__import__("builtins"), "exec") def reraise(tp, value, tb=None): try: if value is None: value = tp() if value.__traceback__ is not tb: raise value.with_traceback(tb) raise value finally: value = None tb = None else: def exec_(_code_, _globs_=None, _locs_=None): """Execute code in a namespace.""" if _globs_ is None: frame = sys._getframe(1) _globs_ = frame.f_globals if _locs_ is None: _locs_ = frame.f_locals del frame elif _locs_ is None: _locs_ = _globs_ exec("""exec _code_ in _globs_, _locs_""") exec_( """def reraise(tp, value, tb=None): try: raise tp, value, tb finally: tb = None """ ) if sys.version_info[:2] == (3, 2): exec_( """def raise_from(value, from_value): try: if from_value is None: raise value raise value from from_value finally: value = None """ ) elif sys.version_info[:2] > (3, 2): exec_( """def raise_from(value, from_value): try: raise value from from_value finally: value = None """ ) else: def raise_from(value, from_value): raise value if PY3: from urllib.error import HTTPError from http import client as httplib import urllib.request as urllib2 from queue import Queue from urllib.parse import quote as urllib_quote from urllib import parse as urlparse else: from urllib2 import HTTPError import httplib import urllib2 from Queue import Queue from urllib import quote as urllib_quote import urlparse def get_code(func): rv = getattr(func, "__code__", getattr(func, "func_code", None)) if rv is None: raise TypeError("Could not get code from %r" % type(func).__name__) return rv def check_threads(): try: from uwsgi import opt except ImportError: return # When `threads` is passed in as a uwsgi option, # `enable-threads` is implied on. if "threads" in opt: return if str(opt.get("enable-threads", "0")).lower() in ("false", "off", "no", "0"): from warnings import warn warn( Warning( "We detected the use of uwsgi with disabled threads. " "This will cause issues with the transport you are " "trying to use. Please enable threading for uwsgi. " '(Enable the "enable-threads" flag).' ) ) graphql-core-legacy-2.3.2/graphql/pyutils/contain_subset.py000066400000000000000000000021731365661746200241300ustar00rootroot00000000000000# Necessary for static type checking if False: # flake8: noqa from typing import Any obj = (dict, list, tuple) def contain_subset(expected, actual): # type: (Any, Any) -> bool t_actual = type(actual) t_expected = type(expected) actual_is_dict = issubclass(t_actual, dict) expected_is_dict = issubclass(t_expected, dict) both_dicts = actual_is_dict and expected_is_dict if not both_dicts and not ( issubclass(t_actual, t_expected) or issubclass(t_expected, t_actual) ): return False if not isinstance(expected, obj) or expected is None: return expected == actual if expected and not actual: return False if isinstance(expected, list): aa = actual[:] return all(any(contain_subset(exp, act) for act in aa) for exp in expected) for key in expected: # type: ignore eo = expected[key] ao = actual.get(key) if isinstance(eo, obj) and eo is not None and ao is not None: if not contain_subset(eo, ao): return False continue if ao != eo: return False return True graphql-core-legacy-2.3.2/graphql/pyutils/default_ordered_dict.py000066400000000000000000000026331365661746200252440ustar00rootroot00000000000000import copy from collections import OrderedDict # Necessary for static type checking if False: # flake8: noqa from typing import Any class DefaultOrderedDict(OrderedDict): __slots__ = ("default_factory",) # Source: http://stackoverflow.com/a/6190500/562769 def __init__(self, default_factory=None, *a, **kw): # type: (type, *Any, **Any) -> None if default_factory is not None and not callable(default_factory): raise TypeError("first argument must be callable") OrderedDict.__init__(self, *a, **kw) self.default_factory = default_factory def __missing__(self, key): # type: (str) -> Any if self.default_factory is None: raise KeyError(key) self[key] = value = self.default_factory() return value def __reduce__(self): if self.default_factory is None: args = tuple() else: args = (self.default_factory,) return type(self), args, None, None, iter(self.items()) def copy(self): return self.__copy__() def __copy__(self): return type(self)(self.default_factory, self) def __deepcopy__(self, memo): return self.__class__(self.default_factory, copy.deepcopy(list(self.items()))) def __repr__(self): return "DefaultOrderedDict({}, {})".format( self.default_factory, OrderedDict.__repr__(self)[19:-1] ) graphql-core-legacy-2.3.2/graphql/pyutils/enum.py000066400000000000000000000755121365661746200220630ustar00rootroot00000000000000# type: ignore """Python Enumerations""" import sys as _sys __all__ = ["Enum", "IntEnum", "unique"] version = 1, 1, 6 pyver = float("%s.%s" % _sys.version_info[:2]) try: any except NameError: def any(iterable): for element in iterable: if element: return True return False try: from collections import OrderedDict # type: ignore except ImportError: class OrderedDict(object): # type: ignore pass try: basestring # type: ignore except NameError: # In Python 2 basestring is the ancestor of both str and unicode # in Python 3 it's just str, but was missing in 3.1 basestring = str try: unicode # type: ignore except NameError: # In Python 3 unicode no longer exists (it's just str) unicode = str class _RouteClassAttributeToGetattr(object): """Route attribute access on a class to __getattr__. This is a descriptor, used to define attributes that act differently when accessed through an instance and through a class. Instance access remains normal, but access to an attribute through a class will be routed to the class's __getattr__ method; this is done by raising AttributeError. """ def __init__(self, fget=None): self.fget = fget def __get__(self, instance, ownerclass=None): if instance is None: raise AttributeError() return self.fget(instance) def __set__(self, instance, value): raise AttributeError("can't set attribute") def __delete__(self, instance): raise AttributeError("can't delete attribute") def _is_descriptor(obj): """Returns True if obj is a descriptor, False otherwise.""" return ( hasattr(obj, "__get__") or hasattr(obj, "__set__") or hasattr(obj, "__delete__") ) def _is_dunder(name): """Returns True if a __dunder__ name, False otherwise.""" return ( len(name) > 4 and name[:2] == name[-2:] == "__" and name[2:3] != "_" and name[-3:-2] != "_" ) def _is_sunder(name): """Returns True if a _sunder_ name, False otherwise.""" return ( len(name) > 2 and name[0] == name[-1] == "_" and name[1:2] != "_" and name[-2:-1] != "_" ) def _make_class_unpicklable(cls): """Make the given class un-picklable.""" def _break_on_call_reduce(self, protocol=None): raise TypeError("%r cannot be pickled" % self) cls.__reduce_ex__ = _break_on_call_reduce cls.__module__ = "" class _EnumDict(OrderedDict): """Track enum member order and ensure member names are not reused. EnumMeta will use the names found in self._member_names as the enumeration member names. """ def __init__(self): super(_EnumDict, self).__init__() self._member_names = [] def __setitem__(self, key, value): """Changes anything not dundered or not a descriptor. If a descriptor is added with the same name as an enum member, the name is removed from _member_names (this may leave a hole in the numerical sequence of values). If an enum member name is used twice, an error is raised; duplicate values are not checked for. Single underscore (sunder) names are reserved. Note: in 3.x __order__ is simply discarded as a not necessary piece leftover from 2.x """ if pyver >= 3.0 and key in ("_order_", "__order__"): return elif key == "__order__": key = "_order_" if _is_sunder(key): if key != "_order_": raise ValueError("_names_ are reserved for future Enum use") elif _is_dunder(key): pass elif key in self._member_names: # descriptor overwriting an enum? raise TypeError("Attempted to reuse key: %r" % key) elif not _is_descriptor(value): if key in self: # enum overwriting a descriptor? raise TypeError("Key already defined as: %r" % self[key]) self._member_names.append(key) super(_EnumDict, self).__setitem__(key, value) # Dummy value for Enum as EnumMeta explicity checks for it, but of course until # EnumMeta finishes running the first time the Enum class doesn't exist. This # is also why there are checks in EnumMeta like `if Enum is not None` Enum = None class EnumMeta(type): """Metaclass for Enum""" @classmethod def __prepare__(metacls, cls, bases): return _EnumDict() def __new__(metacls, cls, bases, classdict): # an Enum class is final once enumeration items have been defined; it # cannot be mixed with other types (int, float, etc.) if it has an # inherited __new__ unless a new __new__ is defined (or the resulting # class will fail). if isinstance(classdict, dict): original_dict = classdict classdict = _EnumDict() for k, v in original_dict.items(): classdict[k] = v member_type, first_enum = metacls._get_mixins_(bases) __new__, save_new, use_args = metacls._find_new_( classdict, member_type, first_enum ) # save enum items into separate mapping so they don't get baked into # the new class members = {k: classdict[k] for k in classdict._member_names} for name in classdict._member_names: del classdict[name] # py2 support for definition order _order_ = classdict.get("_order_") if _order_ is None: if pyver < 3.0: try: _order_ = [ name for (name, value) in sorted( members.items(), key=lambda item: item[1] ) ] except TypeError: _order_ = [name for name in sorted(members.keys())] else: _order_ = classdict._member_names else: del classdict["_order_"] if pyver < 3.0: _order_ = _order_.replace(",", " ").split() aliases = [name for name in members if name not in _order_] _order_ += aliases # check for illegal enum names (any others?) invalid_names = set(members) & {"mro"} if invalid_names: raise ValueError( "Invalid enum member name(s): {}".format(", ".join(invalid_names)) ) # save attributes from super classes so we know if we can take # the shortcut of storing members in the class dict base_attributes = {a for b in bases for a in b.__dict__} # create our new Enum type enum_class = super(EnumMeta, metacls).__new__(metacls, cls, bases, classdict) enum_class._member_names_ = [] # names in random order if OrderedDict is not None: enum_class._member_map_ = OrderedDict() else: enum_class._member_map_ = {} # name->value map enum_class._member_type_ = member_type # Reverse value->name map for hashable values. enum_class._value2member_map_ = {} # instantiate them, checking for duplicates as we go # we instantiate first instead of checking for duplicates first in case # a custom __new__ is doing something funky with the values -- such as # auto-numbering ;) if __new__ is None: __new__ = enum_class.__new__ for member_name in _order_: value = members[member_name] if not isinstance(value, tuple): args = (value,) else: args = value if member_type is tuple: # special case for tuple enums args = (args,) # wrap it one more time if not use_args or not args: enum_member = __new__(enum_class) if not hasattr(enum_member, "_value_"): enum_member._value_ = value else: enum_member = __new__(enum_class, *args) if not hasattr(enum_member, "_value_"): enum_member._value_ = member_type(*args) value = enum_member._value_ enum_member._name_ = member_name enum_member.__objclass__ = enum_class enum_member.__init__(*args) # If another member with the same value was already defined, the # new member becomes an alias to the existing one. for name, canonical_member in enum_class._member_map_.items(): if canonical_member.value == enum_member._value_: enum_member = canonical_member break else: # Aliases don't appear in member names (only in __members__). enum_class._member_names_.append(member_name) # performance boost for any member that would not shadow # a DynamicClassAttribute (aka _RouteClassAttributeToGetattr) if member_name not in base_attributes: setattr(enum_class, member_name, enum_member) # now add to _member_map_ enum_class._member_map_[member_name] = enum_member try: # This may fail if value is not hashable. We can't add the value # to the map, and by-value lookups for this value will be # linear. enum_class._value2member_map_[value] = enum_member except TypeError: pass # If a custom type is mixed into the Enum, and it does not know how # to pickle itself, pickle.dumps will succeed but pickle.loads will # fail. Rather than have the error show up later and possibly far # from the source, sabotage the pickle protocol for this class so # that pickle.dumps also fails. # # However, if the new class implements its own __reduce_ex__, do not # sabotage -- it's on them to make sure it works correctly. We use # __reduce_ex__ instead of any of the others as it is preferred by # pickle over __reduce__, and it handles all pickle protocols. unpicklable = False if "__reduce_ex__" not in classdict: if member_type is not object: methods = ( "__getnewargs_ex__", "__getnewargs__", "__reduce_ex__", "__reduce__", ) if not any(m in member_type.__dict__ for m in methods): _make_class_unpicklable(enum_class) unpicklable = True # double check that repr and friends are not the mixin's or various # things break (such as pickle) for name in ("__repr__", "__str__", "__format__", "__reduce_ex__"): class_method = getattr(enum_class, name) getattr(member_type, name, None) enum_method = getattr(first_enum, name, None) if name not in classdict and class_method is not enum_method: if name == "__reduce_ex__" and unpicklable: continue setattr(enum_class, name, enum_method) # method resolution and int's are not playing nice # Python's less than 2.6 use __cmp__ if pyver < 2.6: if issubclass(enum_class, int): setattr(enum_class, "__cmp__", getattr(int, "__cmp__")) elif pyver < 3.0: if issubclass(enum_class, int): for method in ( "__le__", "__lt__", "__gt__", "__ge__", "__eq__", "__ne__", "__hash__", ): setattr(enum_class, method, getattr(int, method)) # replace any other __new__ with our own (as long as Enum is not None, # anyway) -- again, this is to support pickle if Enum is not None: # if the user defined their own __new__, save it before it gets # clobbered in case they subclass later if save_new: setattr(enum_class, "__member_new__", enum_class.__dict__["__new__"]) setattr(enum_class, "__new__", Enum.__dict__["__new__"]) return enum_class def __bool__(cls): """ classes/types should always be True. """ return True def __call__(cls, value, names=None, module=None, type=None, start=1): """Either returns an existing member, or creates a new enum class. This method is used both when an enum class is given a value to match to an enumeration member (i.e. Color(3)) and for the functional API (i.e. Color = Enum('Color', names='red green blue')). When used for the functional API: `module`, if set, will be stored in the new class' __module__ attribute; `type`, if set, will be mixed in as the first base class. Note: if `module` is not set this routine will attempt to discover the calling module by walking the frame stack; if this is unsuccessful the resulting class will not be pickleable. """ if names is None: # simple value lookup return cls.__new__(cls, value) # otherwise, functional API: we're creating a new Enum type return cls._create_(value, names, module=module, type=type, start=start) def __contains__(cls, member): return isinstance(member, cls) and member.name in cls._member_map_ def __delattr__(cls, attr): # nicer error message when someone tries to delete an attribute # (see issue19025). if attr in cls._member_map_: raise AttributeError("%s: cannot delete Enum member." % cls.__name__) super(EnumMeta, cls).__delattr__(attr) def __dir__(self): return [ "__class__", "__doc__", "__members__", "__module__", ] + self._member_names_ @property def __members__(cls): """Returns a mapping of member name->value. This mapping lists all enum members, including aliases. Note that this is a copy of the internal mapping. """ return cls._member_map_.copy() def __getattr__(cls, name): """Return the enum member matching `name` We use __getattr__ instead of descriptors or inserting into the enum class' __dict__ in order to support `name` and `value` being both properties for enum members (which live in the class' __dict__) and enum members themselves. """ if _is_dunder(name): raise AttributeError(name) try: return cls._member_map_[name] except KeyError: raise AttributeError(name) def __getitem__(cls, name): return cls._member_map_[name] def __iter__(cls): return (cls._member_map_[name] for name in cls._member_names_) def __reversed__(cls): return (cls._member_map_[name] for name in reversed(cls._member_names_)) def __len__(cls): return len(cls._member_names_) __nonzero__ = __bool__ def __repr__(cls): return "" % cls.__name__ def __setattr__(cls, name, value): """Block attempts to reassign Enum members. A simple assignment to the class namespace only changes one of the several possible ways to get an Enum member from the Enum class, resulting in an inconsistent Enumeration. """ member_map = cls.__dict__.get("_member_map_", {}) if name in member_map: raise AttributeError("Cannot reassign members.") super(EnumMeta, cls).__setattr__(name, value) def _create_(cls, class_name, names=None, module=None, type=None, start=1): """Convenience method to create a new Enum class. `names` can be: * A string containing member names, separated either with spaces or commas. Values are auto-numbered from 1. * An iterable of member names. Values are auto-numbered from 1. * An iterable of (member name, value) pairs. * A mapping of member name -> value. """ if pyver < 3.0: # if class_name is unicode, attempt a conversion to ASCII if isinstance(class_name, unicode): try: class_name = class_name.encode("ascii") except UnicodeEncodeError: raise TypeError("%r is not representable in ASCII" % class_name) metacls = cls.__class__ if type is None: bases = (cls,) else: bases = (type, cls) classdict = metacls.__prepare__(class_name, bases) _order_ = [] # special processing needed for names? if isinstance(names, basestring): names = names.replace(",", " ").split() if isinstance(names, (tuple, list)) and isinstance(names[0], basestring): names = [(e, i + start) for (i, e) in enumerate(names)] # Here, names is either an iterable of (name, value) or a mapping. item = None # in case names is empty for item in names: if isinstance(item, basestring): member_name, member_value = item, names[item] else: member_name, member_value = item classdict[member_name] = member_value _order_.append(member_name) # only set _order_ in classdict if name/value was not from a mapping if not isinstance(item, basestring): classdict["_order_"] = " ".join(_order_) enum_class = metacls.__new__(metacls, class_name, bases, classdict) # TODO: replace the frame hack if a blessed way to know the calling # module is ever developed if module is None: try: module = _sys._getframe(2).f_globals["__name__"] except (AttributeError, ValueError): pass if module is None: _make_class_unpicklable(enum_class) else: enum_class.__module__ = module return enum_class @staticmethod def _get_mixins_(bases): """Returns the type for creating enum members, and the first inherited enum class. bases: the tuple of bases that was given to __new__ """ if not bases or Enum is None: return object, Enum # double check that we are not subclassing a class with existing # enumeration members; while we're at it, see if any other data # type has been mixed in so we can use the correct __new__ member_type = first_enum = None for base in bases: if base is not Enum and issubclass(base, Enum) and base._member_names_: raise TypeError("Cannot extend enumerations") # base is now the last base in bases if not issubclass(base, Enum): raise TypeError( "new enumerations must be created as " "`ClassName([mixin_type,] enum_type)`" ) # get correct mix-in type (either mix-in type of Enum subclass, or # first base if last base is Enum) if not issubclass(bases[0], Enum): member_type = bases[0] # first data type first_enum = bases[-1] # enum type else: for base in bases[0].__mro__: # most common: (IntEnum, int, Enum, object) # possible: (, , # , , # ) if issubclass(base, Enum): if first_enum is None: first_enum = base else: if member_type is None: member_type = base return member_type, first_enum if pyver < 3.0: @staticmethod def _find_new_(classdict, member_type, first_enum): """Returns the __new__ to be used for creating the enum members. classdict: the class dictionary given to __new__ member_type: the data type whose __new__ will be used by default first_enum: enumeration to check for an overriding __new__ """ # now find the correct __new__, checking to see of one was defined # by the user; also check earlier enum classes in case a __new__ was # saved as __member_new__ __new__ = classdict.get("__new__", None) if __new__: return None, True, True # __new__, save_new, use_args N__new__ = getattr(None, "__new__") O__new__ = getattr(object, "__new__") if Enum is None: E__new__ = N__new__ else: E__new__ = Enum.__dict__["__new__"] # check all possibles for __member_new__ before falling back to # __new__ for method in ("__member_new__", "__new__"): for possible in (member_type, first_enum): try: target = possible.__dict__[method] except (AttributeError, KeyError): target = getattr(possible, method, None) if target not in [None, N__new__, O__new__, E__new__]: if method == "__member_new__": classdict["__new__"] = target return None, False, True if isinstance(target, staticmethod): target = target.__get__(member_type) __new__ = target break if __new__ is not None: break else: __new__ = object.__new__ # if a non-object.__new__ is used then whatever value/tuple was # assigned to the enum member name will be passed to __new__ and to the # new enum member's __init__ if __new__ is object.__new__: use_args = False else: use_args = True return __new__, False, use_args else: @staticmethod def _find_new_(classdict, member_type, first_enum): """Returns the __new__ to be used for creating the enum members. classdict: the class dictionary given to __new__ member_type: the data type whose __new__ will be used by default first_enum: enumeration to check for an overriding __new__ """ # now find the correct __new__, checking to see of one was defined # by the user; also check earlier enum classes in case a __new__ was # saved as __member_new__ __new__ = classdict.get("__new__", None) # should __new__ be saved as __member_new__ later? save_new = __new__ is not None if __new__ is None: # check all possibles for __member_new__ before falling back to # __new__ for method in ("__member_new__", "__new__"): for possible in (member_type, first_enum): target = getattr(possible, method, None) if target not in ( None, None.__new__, object.__new__, Enum.__new__, ): __new__ = target break if __new__ is not None: break else: __new__ = object.__new__ # if a non-object.__new__ is used then whatever value/tuple was # assigned to the enum member name will be passed to __new__ and to the # new enum member's __init__ if __new__ is object.__new__: use_args = False else: use_args = True return __new__, save_new, use_args ######################################################## # In order to support Python 2 and 3 with a single # codebase we have to create the Enum methods separately # and then use the `type(name, bases, dict)` method to # create the class. ######################################################## temp_enum_dict = {} temp_enum_dict[ "__doc__" ] = "Generic enumeration.\n\n Derive from this class to define new enumerations.\n\n" def __new__(cls, value): # all enum instances are actually created during class construction # without calling this method; this method is called by the metaclass' # __call__ (i.e. Color(3) ), and by pickle if isinstance(value, cls): # For lookups like Color(Color.red) value = value.value # return value # by-value search for a matching enum member # see if it's in the reverse mapping (for hashable values) try: if value in cls._value2member_map_: return cls._value2member_map_[value] except TypeError: # not there, now do long search -- O(n) behavior for member in cls._member_map_.values(): if member.value == value: return member raise ValueError("{} is not a valid {}".format(value, cls.__name__)) temp_enum_dict["__new__"] = __new__ # type: ignore del __new__ def __repr__(self): return "<{}.{}: {!r}>".format(self.__class__.__name__, self._name_, self._value_) temp_enum_dict["__repr__"] = __repr__ # type: ignore del __repr__ def __str__(self): return "{}.{}".format(self.__class__.__name__, self._name_) temp_enum_dict["__str__"] = __str__ # type: ignore del __str__ if pyver >= 3.0: def __dir__(self): added_behavior = [ m for cls in self.__class__.mro() for m in cls.__dict__ if m[0] != "_" and m not in self._member_map_ ] return ["__class__", "__doc__", "__module__"] + added_behavior temp_enum_dict["__dir__"] = __dir__ # type: ignore del __dir__ def __format__(self, format_spec): # mixed-in Enums should use the mixed-in type's __format__, otherwise # we can get strange results with the Enum name showing up instead of # the value # pure Enum branch if self._member_type_ is object: cls = str val = str(self) # mix-in branch else: cls = self._member_type_ val = self.value return cls.__format__(val, format_spec) temp_enum_dict["__format__"] = __format__ # type: ignore del __format__ #################################### # Python's less than 2.6 use __cmp__ if pyver < 2.6: def __cmp__(self, other): if isinstance(other, self.__class__): if self is other: return 0 return -1 return NotImplemented raise TypeError( "unorderable types: %s() and %s()" % (self.__class__.__name__, other.__class__.__name__) ) temp_enum_dict["__cmp__"] = __cmp__ # type: ignore del __cmp__ else: def __le__(self, other): raise TypeError( "unorderable types: %s() <= %s()" % (self.__class__.__name__, other.__class__.__name__) ) temp_enum_dict["__le__"] = __le__ # type: ignore del __le__ def __lt__(self, other): raise TypeError( "unorderable types: %s() < %s()" % (self.__class__.__name__, other.__class__.__name__) ) temp_enum_dict["__lt__"] = __lt__ # type: ignore del __lt__ def __ge__(self, other): raise TypeError( "unorderable types: %s() >= %s()" % (self.__class__.__name__, other.__class__.__name__) ) temp_enum_dict["__ge__"] = __ge__ # type: ignore del __ge__ def __gt__(self, other): raise TypeError( "unorderable types: %s() > %s()" % (self.__class__.__name__, other.__class__.__name__) ) temp_enum_dict["__gt__"] = __gt__ # type: ignore del __gt__ def __eq__(self, other): if isinstance(other, self.__class__): return self is other return NotImplemented temp_enum_dict["__eq__"] = __eq__ # type: ignore del __eq__ def __ne__(self, other): if isinstance(other, self.__class__): return self is not other return NotImplemented temp_enum_dict["__ne__"] = __ne__ # type: ignore del __ne__ def __hash__(self): return hash(self._name_) temp_enum_dict["__hash__"] = __hash__ # type: ignore del __hash__ def __reduce_ex__(self, proto): return self.__class__, (self._value_,) temp_enum_dict["__reduce_ex__"] = __reduce_ex__ # type: ignore del __reduce_ex__ # _RouteClassAttributeToGetattr is used to provide access to the `name` # and `value` properties of enum members while keeping some measure of # protection from modification, while still allowing for an enumeration # to have members named `name` and `value`. This works because enumeration # members are not set directly on the enum class -- __getattr__ is # used to look them up. @_RouteClassAttributeToGetattr def name(self): return self._name_ temp_enum_dict["name"] = name # type: ignore del name @_RouteClassAttributeToGetattr def value(self): return self._value_ temp_enum_dict["value"] = value # type: ignore del value @classmethod # type: ignore def _convert(cls, name, module, filter, source=None): """ Create a new Enum subclass that replaces a collection of global constants """ # convert all constants from source (or module) that pass filter() to # a new Enum called name, and export the enum and its members back to # module; # also, replace the __reduce_ex__ method so unpickling works in # previous Python versions module_globals = vars(_sys.modules[module]) if source: source = vars(source) else: source = module_globals members = {name: value for name, value in source.items() if filter(name)} cls = cls(name, members, module=module) cls.__reduce_ex__ = _reduce_ex_by_name module_globals.update(cls.__members__) module_globals[name] = cls return cls temp_enum_dict["_convert"] = _convert # type: ignore del _convert Enum = EnumMeta("Enum", (object,), temp_enum_dict) del temp_enum_dict # Enum has now been created ########################### class IntEnum(int, Enum): # type: ignore """Enum where members are also (and must be) ints""" def _reduce_ex_by_name(self, proto): return self.name def unique(enumeration): """Class decorator that ensures only unique members exist in an enumeration.""" duplicates = [] for name, member in enumeration.__members__.items(): if name != member.name: duplicates.append((name, member.name)) if duplicates: duplicate_names = ", ".join( ["{} -> {}".format(alias, name) for (alias, name) in duplicates] ) raise ValueError( "duplicate names found in {!r}: {}".format(enumeration, duplicate_names) ) return enumeration graphql-core-legacy-2.3.2/graphql/pyutils/ordereddict.py000066400000000000000000000007011365661746200233730ustar00rootroot00000000000000import sys if sys.version_info >= (3, 7): # As of Python 3.7, dictionaries are specified to preserve insertion order OrderedDict = dict else: try: # Try to load the Cython performant OrderedDict (C) # as is more performant than collections.OrderedDict (Python) from cyordereddict import OrderedDict # type: ignore except ImportError: from collections import OrderedDict __all__ = ["OrderedDict"] graphql-core-legacy-2.3.2/graphql/pyutils/pair_set.py000066400000000000000000000024471365661746200227220ustar00rootroot00000000000000# Necessary for static type checking if False: # flake8: noqa from typing import Dict, Any class PairSet(object): __slots__ = ("_data",) def __init__(self): # type: () -> None self._data = {} # type: Dict[str, Any] def __contains__(self, item): return self.has(item[0], item[1], item[2]) def __str__(self): return str(self._data) def __repr__(self): return str(self._data) def has(self, a, b, are_mutually_exclusive): first = self._data.get(a) result = first and first.get(b) 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. if not are_mutually_exclusive: return not result return True def add(self, a, b, are_mutually_exclusive): _pair_set_add(self._data, a, b, are_mutually_exclusive) _pair_set_add(self._data, b, a, are_mutually_exclusive) return self def _pair_set_add(data, a, b, are_mutually_exclusive): sub_dict = data.get(a) if not sub_dict: sub_dict = {} data[a] = sub_dict sub_dict[b] = are_mutually_exclusive graphql-core-legacy-2.3.2/graphql/pyutils/tests/000077500000000000000000000000001365661746200216755ustar00rootroot00000000000000graphql-core-legacy-2.3.2/graphql/pyutils/tests/__init__.py000066400000000000000000000000001365661746200237740ustar00rootroot00000000000000graphql-core-legacy-2.3.2/graphql/pyutils/tests/test_contain_subset.py000066400000000000000000000042471365661746200263350ustar00rootroot00000000000000from ..contain_subset import contain_subset plain_object = {"a": "b", "c": "d"} complex_object = {"a": "b", "c": "d", "e": {"foo": "bar", "baz": {"qux": "quux"}}} def test_plain_object_should_pass_for_smaller_object(): # type: () -> None assert contain_subset({"a": "b"}, plain_object) def test_plain_object_should_pass_for_same_object(): # type: () -> None assert contain_subset({"a": "b", "c": "d"}, plain_object) def test_plain_object_should_reject_for_similar_object(): # type: () -> None assert not contain_subset({"a": "notB", "c": "d"}, plain_object) def test_complex_object_should_pass_for_smaller_object(): # type: () -> None assert contain_subset({"a": "b", "e": {"foo": "bar"}}, complex_object) def test_complex_object_should_pass_for_smaller_object_other(): # type: () -> None assert contain_subset({"e": {"foo": "bar", "baz": {"qux": "quux"}}}, complex_object) def test_complex_object_should_pass_for_same_object(): # type: () -> None assert contain_subset( {"a": "b", "c": "d", "e": {"foo": "bar", "baz": {"qux": "quux"}}}, complex_object, ) def test_complex_object_should_reject_for_similar_object(): # type: () -> None assert not contain_subset( {"e": {"foo": "bar", "baz": {"qux": "notAQuux"}}}, complex_object ) # def test_circular_objects_should_contain_subdocument(): # obj = {} # obj["arr"] = [obj, obj] # obj["arr"].append(obj["arr"]) # obj["obj"] = obj # assert contain_subset( # {"arr": [{"arr": []}, {"arr": []}, [{"arr": []}, {"arr": []}]]}, obj # ) # def test_circular_objects_should_not_contain_similardocument(): # obj = {} # obj["arr"] = [obj, obj] # obj["arr"].append(obj["arr"]) # obj["obj"] = obj # assert not contain_subset( # { # "arr": [ # {"arr": ["just random field"]}, # {"arr": []}, # [{"arr": []}, {"arr": []}], # ] # }, # obj, # ) def test_should_contain_others(): obj = {"elems": [{"a": "b", "c": "d", "e": "f"}, {"g": "h"}]} assert contain_subset({"elems": [{"g": "h"}, {"a": "b", "e": "f"}]}, obj) graphql-core-legacy-2.3.2/graphql/pyutils/tests/test_default_ordered_dict.py000066400000000000000000000043551365661746200274500ustar00rootroot00000000000000import copy import pickle from pytest import raises from graphql.pyutils.default_ordered_dict import DefaultOrderedDict def test_will_missing_will_set_value_from_factory(): d = DefaultOrderedDict(list) f = d["foo"] assert isinstance(f, list) assert d["foo"] is f def test_preserves_input_order(): d = DefaultOrderedDict(list) d["a"].append(1) d["b"].append(2) d["c"].append(3) d["a"].append(4) assert list(d.keys()) == ["a", "b", "c"] assert list(d.values()) == [[1, 4], [2], [3]] def test_will_act_list_default_dict_if_no_factory_defined(): d = DefaultOrderedDict() with raises(KeyError) as excinfo: assert d["test"] assert str(excinfo.value) == "'test'" def test_will_repr_properly(): d = DefaultOrderedDict(list, [("a", 1), ("b", 2)]) assert repr(d) == "DefaultOrderedDict({}, [('a', 1), ('b', 2)])".format(list) def test_requires_callable_default_factory(): with raises(TypeError) as excinfo: DefaultOrderedDict("not callable") assert str(excinfo.value) == "first argument must be callable" def test_picklable(): d = DefaultOrderedDict(list, [("a", 1), ("b", 2)]) d_copied = pickle.loads(pickle.dumps(d)) assert d_copied == d assert d.default_factory == d_copied.default_factory d = DefaultOrderedDict(None, [("a", 1), ("b", 2)]) d_copied = pickle.loads(pickle.dumps(d)) assert d_copied == d assert d.default_factory == d_copied.default_factory def test_copy(): d = DefaultOrderedDict(list, [("a", [1, 2]), ("b", [3, 4])]) d_copied = copy.copy(d) assert d_copied == d assert d.default_factory == d_copied.default_factory assert d_copied["a"] is d["a"] assert d_copied["b"] is d["b"] d_copied = d.copy() assert d_copied == d assert d.default_factory == d_copied.default_factory assert d_copied["a"] is d["a"] assert d_copied["b"] is d["b"] def test_deep_copy(): d = DefaultOrderedDict(list, [("a", [1, 2]), ("b", [3, 4])]) d_copied = copy.deepcopy(d) assert d_copied == d assert d.default_factory == d_copied.default_factory assert d_copied["a"] == d["a"] assert d_copied["a"] is not d["a"] assert d_copied["b"] == d["b"] assert d_copied["b"] is not d["b"] graphql-core-legacy-2.3.2/graphql/pyutils/tests/test_enum.py000066400000000000000000000011211365661746200242450ustar00rootroot00000000000000from ..enum import _is_dunder, _is_sunder def test__is_dunder(): dunder_names = ["__i__", "__test__"] non_dunder_names = ["test", "__test", "_test", "_test_", "test__", ""] for name in dunder_names: assert _is_dunder(name) is True for name in non_dunder_names: assert _is_dunder(name) is False def test__is_sunder(): sunder_names = ["_i_", "_test_"] non_sunder_names = ["__i__", "_i__", "__i_", ""] for name in sunder_names: assert _is_sunder(name) is True for name in non_sunder_names: assert _is_sunder(name) is False graphql-core-legacy-2.3.2/graphql/pyutils/tests/test_pair_set.py000066400000000000000000000023651365661746200251220ustar00rootroot00000000000000from graphql.pyutils.pair_set import PairSet def test_pair_set(): ps = PairSet() are_mutually_exclusive = True ps.add(1, 2, are_mutually_exclusive) ps.add(2, 4, are_mutually_exclusive) assert ps.has(1, 2, are_mutually_exclusive) assert ps.has(2, 1, are_mutually_exclusive) assert not ps.has(1, 2, not are_mutually_exclusive) assert not ps.has(2, 1, not are_mutually_exclusive) assert (1, 2, are_mutually_exclusive) in ps assert (2, 1, are_mutually_exclusive) in ps assert (1, 2, (not are_mutually_exclusive)) not in ps assert (2, 1, (not are_mutually_exclusive)) not in ps assert ps.has(4, 2, are_mutually_exclusive) assert ps.has(2, 4, are_mutually_exclusive) assert not ps.has(2, 3, are_mutually_exclusive) assert not ps.has(1, 3, are_mutually_exclusive) assert ps.has(4, 2, are_mutually_exclusive) assert ps.has(2, 4, are_mutually_exclusive) def test_pair_set_not_mutually_exclusive(): ps = PairSet() are_mutually_exclusive = False ps.add(1, 2, are_mutually_exclusive) assert ps.has(1, 2, are_mutually_exclusive) assert ps.has(2, 1, are_mutually_exclusive) assert ps.has(1, 2, not are_mutually_exclusive) assert ps.has(2, 1, not are_mutually_exclusive) graphql-core-legacy-2.3.2/graphql/pyutils/version.py000066400000000000000000000046761365661746200226070ustar00rootroot00000000000000from __future__ import unicode_literals import datetime import os import subprocess def get_version(version=None): "Returns a PEP 440-compliant version number from VERSION." version = get_complete_version(version) # Now build the two parts of the version number: # main = X.Y[.Z] # sub = .devN - for pre-alpha releases # | {a|b|rc}N - for alpha, beta, and rc releases main = get_main_version(version) sub = "" if version[3] == "alpha" and version[4] == 0: git_changeset = get_git_changeset() if git_changeset: sub = ".dev%s" % git_changeset else: sub = ".dev" elif version[3] != "final": mapping = {"alpha": "a", "beta": "b", "rc": "rc"} sub = mapping[version[3]] + str(version[4]) return str(main + sub) def get_main_version(version=None): "Returns main version (X.Y[.Z]) from VERSION." version = get_complete_version(version) parts = 2 if version[2] == 0 else 3 return ".".join(str(x) for x in version[:parts]) def get_complete_version(version=None): """Returns a tuple of the graphql version. If version argument is non-empty, then checks for correctness of the tuple provided. """ if version is None: from graphql import VERSION as version else: assert len(version) == 5 assert version[3] in ("alpha", "beta", "rc", "final") return version def get_docs_version(version=None): version = get_complete_version(version) if version[3] != "final": return "dev" else: return "%d.%d" % version[:2] def get_git_changeset(): """Returns a numeric identifier of the latest git changeset. The result is the UTC timestamp of the changeset in YYYYMMDDHHMMSS format. This value isn't guaranteed to be unique, but collisions are very unlikely, so it's sufficient for generating the development version numbers. """ repo_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) try: git_log = subprocess.Popen( "git log --pretty=format:%ct --quiet -1 HEAD", stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True, cwd=repo_dir, universal_newlines=True, ) timestamp = git_log.communicate()[0] timestamp = datetime.datetime.utcfromtimestamp(int(timestamp)) except Exception: return None return timestamp.strftime("%Y%m%d%H%M%S") graphql-core-legacy-2.3.2/graphql/type/000077500000000000000000000000001365661746200200035ustar00rootroot00000000000000graphql-core-legacy-2.3.2/graphql/type/__init__.py000066400000000000000000000025231365661746200221160ustar00rootroot00000000000000# flake8: noqa from .definition import ( # no import order GraphQLScalarType, GraphQLObjectType, GraphQLField, GraphQLArgument, GraphQLInterfaceType, GraphQLUnionType, GraphQLEnumType, GraphQLEnumValue, GraphQLInputObjectType, GraphQLInputObjectField, GraphQLList, GraphQLNonNull, get_named_type, is_abstract_type, is_composite_type, is_input_type, is_leaf_type, is_type, get_nullable_type, is_output_type, ) from .directives import ( # "Enum" of Directive locations DirectiveLocation, # Directive definition GraphQLDirective, # Built-in directives defined by the Spec specified_directives, GraphQLSkipDirective, GraphQLIncludeDirective, GraphQLDeprecatedDirective, # Constant Deprecation Reason DEFAULT_DEPRECATION_REASON, ) from .scalars import ( # no import order GraphQLInt, GraphQLFloat, GraphQLString, GraphQLBoolean, GraphQLID, ) from .schema import GraphQLSchema from .introspection import ( # "Enum" of Type Kinds TypeKind, # GraphQL Types for introspection. __Schema, __Directive, __DirectiveLocation, __Type, __Field, __InputValue, __EnumValue, __TypeKind, # Meta-field definitions. SchemaMetaFieldDef, TypeMetaFieldDef, TypeNameMetaFieldDef, ) graphql-core-legacy-2.3.2/graphql/type/definition.py000066400000000000000000000633461365661746200225210ustar00rootroot00000000000000import collections try: from collections.abc import Hashable, Mapping except ImportError: # Python < 3.3 from collections import Hashable, Mapping import copy from typing import Union from ..language import ast from ..pyutils.cached_property import cached_property from ..pyutils.ordereddict import OrderedDict from ..pyutils.compat import Enum as PyEnum from ..utils.assert_valid_name import assert_valid_name from ..utils.undefined import Undefined # Necessary for static type checking if False: # flake8: noqa from typing import List, Dict, Any, Callable, Optional, Type def is_type(type_): # type: (Any) -> bool return isinstance( type_, ( GraphQLScalarType, GraphQLObjectType, GraphQLInterfaceType, GraphQLUnionType, GraphQLEnumType, GraphQLInputObjectType, GraphQLList, GraphQLNonNull, ), ) def is_input_type(type_): # type: (Any) -> bool named_type = get_named_type(type_) return isinstance( named_type, (GraphQLScalarType, GraphQLEnumType, GraphQLInputObjectType) ) def get_nullable_type(type_): if isinstance(type_, GraphQLNonNull): return type_.of_type return type_ def get_named_type(type_): # type: (Optional[GraphQLType]) -> Optional[GraphQLType] unmodified_type = type_ while isinstance(unmodified_type, (GraphQLList, GraphQLNonNull)): unmodified_type = unmodified_type.of_type return unmodified_type class GraphQLType(object): pass class GraphQLNamedType(GraphQLType): __slots__ = ("name",) def __init__(self, name): # type: (str) -> None self.name = name def __str__(self): # type: () -> str return self.name def is_same_type(self, other): # type: (Any) -> bool return self.__class__ is other.__class__ and self.name == other.name def none_func(x): return None 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 coercion functions used to ensure validity. Example: def coerce_odd(value): if value % 2 == 1: return value return None OddType = GraphQLScalarType(name='Odd', serialize=coerce_odd) """ __slots__ = "name", "description", "serialize", "parse_value", "parse_literal" def __init__( self, name, # type: str description=None, # type: Optional[str] serialize=None, # type: Optional[Callable] parse_value=None, # type: Optional[Callable] parse_literal=None, # type: Optional[Callable] ): # type: (...) -> None assert name, "Type must be named." assert_valid_name(name) super(GraphQLScalarType, self).__init__(name) self.name = name self.description = description assert callable(serialize), ( '{} must provide "serialize" function. If this custom Scalar is ' 'also used as an input type, ensure "parse_value" and "parse_literal" ' "functions are also provided." ).format(self) if parse_value is not None or parse_literal is not None: assert callable(parse_value) and callable( parse_literal ), '{} must provide both "parse_value" and "parse_literal" functions.'.format( self ) self.serialize = serialize self.parse_value = parse_value or none_func self.parse_literal = parse_literal or none_func def __str__(self): # type: () -> str return self.name class GraphQLObjectType(GraphQLNamedType): """Object Type Definition Almost all of 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, resolver=lambda obj, info, **args: 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 static method to supply the fields lazily. Example: PersonType = GraphQLObjectType('Person', lambda: { 'name': GraphQLField(GraphQLString), 'bestFriend': GraphQLField(PersonType) }) """ def __init__( self, name, # type: str fields, # type: Union[Callable[[], Dict[str, GraphQLField]], Dict[str, GraphQLField]] interfaces=None, # type: Optional[List[GraphQLInterfaceType]] is_type_of=None, # type: Optional[Callable] description=None, # type: Optional[Any] ): # type: (...) -> None assert name, "Type must be named." assert_valid_name(name) super(GraphQLObjectType, self).__init__(name) self.name = name self.description = description if is_type_of is not None: assert callable( is_type_of ), '{} must provide "is_type_of" as a function.'.format(self) self.is_type_of = is_type_of self._fields = fields self._provided_interfaces = interfaces self._interfaces = None @cached_property def fields(self): # type: () -> Dict[str, GraphQLField] return define_field_map(self, self._fields) @cached_property def interfaces(self): # type: () -> List[GraphQLInterfaceType] return define_interfaces(self, self._provided_interfaces) def define_field_map( type_, # type: Union[GraphQLInterfaceType, GraphQLObjectType] field_map, # type: Union[Callable, Dict[str, GraphQLField], OrderedDict] ): # type: (...) -> OrderedDict if callable(field_map): field_map = field_map() assert isinstance(field_map, Mapping) and len(field_map) > 0, ( "{} fields must be a mapping (dict / OrderedDict) with field names as keys or a " "function which returns such a mapping." ).format(type_) for field_name, field in field_map.items(): assert_valid_name(field_name) assert isinstance( field, GraphQLField ), "{}.{} must be an instance of GraphQLField.".format(type_, field_name) field_args = getattr(field, "args", None) if field_args: assert isinstance( field_args, Mapping ), "{}.{} args must be a mapping (dict / OrderedDict) with argument names as keys.".format( type_, field_name ) for arg_name, arg in field_args.items(): assert_valid_name(arg_name) return OrderedDict(field_map) def define_interfaces( type_, # type: GraphQLObjectType interfaces, # type: Optional[List[GraphQLInterfaceType]] ): # type: (...) -> List[GraphQLInterfaceType] if callable(interfaces): interfaces = interfaces() if interfaces is None: interfaces = [] assert isinstance( interfaces, (list, tuple) ), "{} interfaces must be a list/tuple or a function which returns a list/tuple.".format( type_ ) for interface in interfaces: assert isinstance( interface, GraphQLInterfaceType ), "{} may only implement Interface types, it cannot implement: {}.".format( type_, interface ) if not callable(interface.resolve_type): assert callable(type_.is_type_of), ( 'Interface Type {} does not provide a "resolve_type" function ' 'and implementing Type {} does not provide a "is_type_of" ' "function. There is no way to resolve this implementing type " "during execution." ).format(interface, type_) return interfaces class GraphQLField(object): __slots__ = "type", "args", "resolver", "deprecation_reason", "description" def __init__( self, type_, # type: Any args=None, # type: Optional[Dict[str, GraphQLArgument]] resolver=None, # type: Optional[Callable] deprecation_reason=None, # type: Optional[Any] description=None, # type: Optional[Any] ): # type: (...) -> None self.type = type_ self.args = args or OrderedDict() self.resolver = resolver self.deprecation_reason = deprecation_reason self.description = description def __eq__(self, other): return self is other or ( isinstance(other, GraphQLField) and self.type == other.type and self.args == other.args and self.resolver == other.resolver and self.deprecation_reason == other.deprecation_reason and self.description == other.description ) def __hash__(self): # type: () -> int return id(self) @property def is_deprecated(self): return bool(self.deprecation_reason) class GraphQLArgument(object): __slots__ = "type", "default_value", "description", "out_name" def __init__( self, type_, # type: Union[GraphQLInputObjectType, GraphQLNonNull, GraphQLList, GraphQLScalarType] default_value=None, # type: Optional[Any] description=None, # type: Optional[Any] out_name=None, # type: Optional[str] ): # type: (...) -> None self.type = type_ self.default_value = default_value self.description = description self.out_name = out_name def __eq__(self, other): 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.out_name == other.out_name ) def __hash__(self): return id(self) class GraphQLInterfaceType(GraphQLNamedType): """Interface Type Definition When a field can return one of a heterogeneous set of types, a 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( name='Entity', fields={ 'name': GraphQLField(GraphQLString), }) """ def __init__( self, name, # type: str fields=None, # type: Union[Callable[[], Dict[str, GraphQLField]], Dict[str, GraphQLField]] resolve_type=None, # type: Optional[Callable] description=None, # type: Optional[Any] ): # type: (...) -> None assert name, "Type must be named." assert_valid_name(name) super(GraphQLInterfaceType, self).__init__(name) self.name = name self.description = description if resolve_type is not None: assert callable( resolve_type ), '{} must provide "resolve_type" as a function.'.format(self) self.resolve_type = resolve_type self._fields = fields @cached_property def fields(self): # type: () -> Dict[str, GraphQLField] assert self._fields is not None, '"fields" cannot be None' return define_field_map(self, self._fields) 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: class PetType(GraphQLUnionType): name = 'Pet' types = [DogType, CatType] def resolve_type(self, value): if isinstance(value, Dog): return DogType() if isinstance(value, Cat): return CatType() """ def __init__( self, name, # type: str types, # type: Union[Callable[[], List[GraphQLObjectType]], List[GraphQLObjectType]] resolve_type=None, # type: Optional[Callable] description=None, # type: Optional[Any] ): # type: (...) -> None assert name, "Type must be named." assert_valid_name(name) super(GraphQLUnionType, self).__init__(name) self.name = name self.description = description if resolve_type is not None: assert callable( resolve_type ), '{} must provide "resolve_type" as a function.'.format(self) self.resolve_type = resolve_type self._types = types @cached_property def types(self): # type: () -> List[GraphQLObjectType] return define_types(self, self._types) # fmt: off def define_types( union_type, # type: GraphQLUnionType types, # type: Union[Callable[[], List[GraphQLObjectType]], List[GraphQLObjectType]] ): # type: (...) -> List[GraphQLObjectType] # fmt: on if callable(types): types = types() assert ( isinstance(types, (list, tuple)) and len(types) > 0 ), "Must provide types for Union {}.".format(union_type.name) has_resolve_type_fn = callable(union_type.resolve_type) for type_ in types: assert isinstance( type_, GraphQLObjectType ), "{} may only contain Object types, it cannot contain: {}.".format( union_type, type_ ) if not has_resolve_type_fn: assert callable(type_.is_type_of), ( 'Union Type {} does not provide a "resolve_type" function ' 'and possible Type {} does not provide a "is_type_of" ' "function. There is no way to resolve this possible type " "during execution." ).format(union_type, type_) return types 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. Example: RGBType = GraphQLEnumType( name='RGB', values=OrderedDict([ ('RED', GraphQLEnumValue(0)), ('GREEN', GraphQLEnumValue(1)), ('BLUE', GraphQLEnumValue(2)) ]) ) Note: If a value is not provided in a definition, the name of the enum value will be used as it's internal value. """ def __init__(self, name, values, description=None): assert name, "Type must provide name." assert_valid_name(name) super(GraphQLEnumType, self).__init__(name) self.name = name self.description = description self.values = define_enum_values(self, values) def get_values(self): return self.values def get_value(self, name): return self._name_lookup.get(name) def serialize(self, value): # type: (Union[str, PyEnum]) -> Optional[str] if isinstance(value, PyEnum): # We handle PyEnum values value = value.value if isinstance(value, Hashable): enum_value = self._value_lookup.get(value) if enum_value: return enum_value.name return None def parse_value(self, value): if isinstance(value, Hashable): enum_value = self._name_lookup.get(value) if enum_value: return enum_value.value return None def parse_literal(self, value_ast): if isinstance(value_ast, ast.EnumValue): enum_value = self._name_lookup.get(value_ast.value) if enum_value: return enum_value.value @cached_property def _value_lookup(self): # type: () -> Dict[str, GraphQLEnumValue] return { value.value.value if isinstance(value.value, PyEnum) else value.value: value for value in self.values } @cached_property def _name_lookup(self): return {value.name: value for value in self.values} def define_enum_values(type, value_map): assert ( isinstance(value_map, Mapping) and len(value_map) > 0 ), "{} values must be a mapping (dict / OrderedDict) with value names as keys.".format( type ) values = [] if not isinstance(value_map, (collections.OrderedDict, OrderedDict)): value_map = OrderedDict(sorted(list(value_map.items()))) for value_name, value in value_map.items(): assert_valid_name(value_name) assert isinstance( value, GraphQLEnumValue ), "{}.{} must be an instance of GraphQLEnumValue, but got: {}".format( type, value_name, value ) value = copy.copy(value) value.name = value_name if value.value == Undefined: value.value = value_name values.append(value) return values class GraphQLEnumValue(object): __slots__ = "name", "value", "deprecation_reason", "description" def __init__( self, value=Undefined, deprecation_reason=None, description=None, name=None ): self.name = name self.value = value self.deprecation_reason = deprecation_reason self.description = description @property def is_deprecated(self): return bool(self.deprecation_reason) def __eq__(self, other): return self is other or ( isinstance(other, GraphQLEnumValue) and self.name == other.name and self.value == other.value and self.deprecation_reason == other.deprecation_reason and self.description == other.description ) 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': GraphQLInputObjectField(NonNullFloat), 'lon': GraphQLInputObjectField(NonNullFloat), 'alt': GraphQLInputObjectField(GraphQLFloat(), default_value=0) } """ def __init__( self, name, # type: str fields, # type: Union[Callable[[], Dict[str, GraphQLInputObjectField]], Dict[str, GraphQLInputObjectField]] description=None, # type: Optional[str] container_type=None, # type: Type[Dict[str, Any]] ): # type: (...) -> None assert name, "Type must be named." self.name = name self.description = description super(GraphQLInputObjectType, self).__init__(name) if container_type is None: container_type = OrderedDict # type: ignore assert callable(container_type), "container_type must be callable" self.container_type = container_type self._fields = fields def create_container(self, data): # type: (Dict[str, Any]) -> Dict[str, Any] return self.container_type(data) @cached_property def fields(self): # type: () -> Dict[str, GraphQLInputObjectField] return self._define_field_map() def _define_field_map(self): # type: () -> OrderedDict if callable(self._fields): fields = self._fields() else: fields = self._fields assert isinstance(fields, Mapping) and len(fields) > 0, ( "{} fields must be a mapping (dict / OrderedDict) with field names as keys or a " "function which returns such a mapping." ).format(self) if not isinstance(fields, (collections.OrderedDict, OrderedDict)): fields = OrderedDict(sorted(list(fields.items()))) for field_name, field in fields.items(): assert_valid_name(field_name) return fields class GraphQLInputObjectField(object): __slots__ = "type", "default_value", "description", "out_name" def __init__( self, type_, # type: Union[GraphQLInputObjectType, GraphQLScalarType] default_value=None, # type: Optional[Any] description=None, # type: Optional[Any] out_name=None, # type: str ): # type: (...) -> None self.type = type_ # type: Union[GraphQLInputObjectType, GraphQLScalarType] self.default_value = default_value self.description = description self.out_name = out_name def __eq__(self, other): return self is other or ( isinstance(other, GraphQLInputObjectField) and self.type == other.type and self.description == other.description and self.out_name == other.out_name ) class GraphQLList(GraphQLType): """List Modifier A list is a kind of type marker, 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' def get_fields(self): return { 'parents': GraphQLField(GraphQLList(PersonType())), 'children': GraphQLField(GraphQLList(PersonType())), } """ __slots__ = ("of_type",) def __init__(self, type_): # type: (Any) -> None assert is_type( type_ ), "Can only create List of a GraphQLType but got: {}.".format(type_) self.of_type = type_ def __str__(self): # type: () -> str return "[" + str(self.of_type) + "]" def is_same_type(self, other): return isinstance(other, GraphQLList) and self.of_type.is_same_type( other.of_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_): # type: (Any) -> bool return isinstance(type_, graphql_nullable_types) class GraphQLNonNull(GraphQLType): """Non-Null Modifier A non-null is a kind of type marker, 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(type=GraphQLNonNull(GraphQLString())) } Note: the enforcement of non-nullability occurs within the executor. """ __slots__ = ("of_type",) def __init__( self, type_, # type: GraphQLNullableType ): # type: (...) -> None assert is_type(type_) and not isinstance( type_, GraphQLNonNull ), "Can only create NonNull of a Nullable GraphQLType but got: {}.".format(type_) self.of_type = type_ # type: GraphQLNullableType def __str__(self): # type: () -> str return str(self.of_type) + "!" def is_same_type(self, other): return isinstance(other, GraphQLNonNull) and self.of_type.is_same_type( other.of_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, GraphQLNullableType ] def is_output_type(type_): # type: (Any) -> bool named_type = get_named_type(type_) return isinstance(named_type, graphql_output_types) def is_union_type(type_): # type: (Any) -> bool return isinstance(type_, GraphQLUnionType) def is_interface_type(type_): # type: (Any) -> bool return isinstance(type_, GraphQLInterfaceType) def is_list_type(type_): # type: (Any) -> bool return isinstance(type_, GraphQLList) def is_non_null_type(type_): # type: (Any) -> bool return isinstance(type_, GraphQLNonNull) def is_object_type(type_): # type: (Any) -> bool return isinstance(type_, GraphQLObjectType) # These types may describe types which may be leaf values. graphql_leaf_types = (GraphQLScalarType, GraphQLEnumType) GraphQLLeafType = Union[GraphQLScalarType, GraphQLEnumType] def is_leaf_type(type_): # type: (Any) -> bool return isinstance(type_, (GraphQLScalarType, GraphQLEnumType)) # 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_): # type: (Any) -> bool named_type = get_named_type(type_) return isinstance(named_type, graphql_composite_types) # These types may describe abstract types. graphql_abstract_types = (GraphQLInterfaceType, GraphQLUnionType) GraphQLAbstractType = Union[GraphQLInterfaceType, GraphQLUnionType] def is_abstract_type(type_): # type: (Any) -> bool return isinstance(type_, graphql_abstract_types) graphql-core-legacy-2.3.2/graphql/type/directives.py000066400000000000000000000100401365661746200225110ustar00rootroot00000000000000try: from collections.abc import Iterable, Mapping except ImportError: # Python < 3.3 from collections import Iterable, Mapping from ..pyutils.ordereddict import OrderedDict from ..utils.assert_valid_name import assert_valid_name from .definition import GraphQLArgument, GraphQLNonNull, is_input_type from .scalars import GraphQLBoolean, GraphQLString class DirectiveLocation(object): # Operations QUERY = "QUERY" MUTATION = "MUTATION" SUBSCRIPTION = "SUBSCRIPTION" FIELD = "FIELD" FRAGMENT_DEFINITION = "FRAGMENT_DEFINITION" FRAGMENT_SPREAD = "FRAGMENT_SPREAD" INLINE_FRAGMENT = "INLINE_FRAGMENT" # Schema 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" OPERATION_LOCATIONS = [QUERY, MUTATION, SUBSCRIPTION] FRAGMENT_LOCATIONS = [FRAGMENT_DEFINITION, FRAGMENT_SPREAD, INLINE_FRAGMENT] FIELD_LOCATIONS = [FIELD] class GraphQLDirective(object): __slots__ = "name", "args", "description", "locations" def __init__(self, name, description=None, args=None, locations=None): assert name, "Directive must be named." assert_valid_name(name) assert isinstance(locations, Iterable), "Must provide locations for directive." self.name = name self.description = description self.locations = locations if args: assert isinstance( args, Mapping ), "{} args must be a dict with argument names as keys.".format(name) for arg_name, _arg in args.items(): assert_valid_name(arg_name) assert is_input_type( _arg.type ), "{}({}) argument type must be Input Type but got {}.".format( name, arg_name, _arg.type ) self.args = args or OrderedDict() """Used to conditionally include fields or fragments.""" GraphQLIncludeDirective = GraphQLDirective( name="include", description="Directs the executor to include this field or fragment only when the `if` argument is true.", args={ "if": GraphQLArgument( type_=GraphQLNonNull(GraphQLBoolean), description="Included when true." ) }, locations=[ DirectiveLocation.FIELD, DirectiveLocation.FRAGMENT_SPREAD, DirectiveLocation.INLINE_FRAGMENT, ], ) """Used to conditionally skip (exclude) fields or fragments.""" GraphQLSkipDirective = GraphQLDirective( name="skip", description="Directs the executor to skip this field or fragment when the `if` argument is true.", args={ "if": GraphQLArgument( type_=GraphQLNonNull(GraphQLBoolean), description="Skipped when true." ) }, locations=[ DirectiveLocation.FIELD, DirectiveLocation.FRAGMENT_SPREAD, DirectiveLocation.INLINE_FRAGMENT, ], ) """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", description="Marks an element of a GraphQL schema as no longer supported.", args={ "reason": GraphQLArgument( type_=GraphQLString, 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/)." ), default_value=DEFAULT_DEPRECATION_REASON, ) }, locations=[DirectiveLocation.FIELD_DEFINITION, DirectiveLocation.ENUM_VALUE], ) specified_directives = [ GraphQLIncludeDirective, GraphQLSkipDirective, GraphQLDeprecatedDirective, ] graphql-core-legacy-2.3.2/graphql/type/introspection.py000066400000000000000000000551061365661746200232640ustar00rootroot00000000000000from collections import OrderedDict, namedtuple from ..language.printer import print_ast from ..utils.ast_from_value import ast_from_value from .definition import ( GraphQLArgument, GraphQLEnumType, GraphQLEnumValue, GraphQLField, GraphQLInputObjectType, GraphQLInterfaceType, GraphQLList, GraphQLNonNull, GraphQLObjectType, GraphQLScalarType, GraphQLUnionType, ) from .directives import DirectiveLocation from .scalars import GraphQLBoolean, GraphQLString # Necessary for static type checking if False: # flake8: noqa from ..execution.base import ResolveInfo from .definition import GraphQLInputObjectField from typing import Union, List, Optional, Any, Dict InputField = namedtuple("InputField", ["name", "description", "type", "default_value"]) Field = namedtuple( "Field", ["name", "type", "description", "args", "deprecation_reason"] ) def input_fields_to_list(input_fields): # type: (Dict[str, GraphQLInputObjectField]) -> List[InputField] fields = [] for field_name, field in input_fields.items(): fields.append( InputField( name=field_name, description=field.description, type=field.type, default_value=field.default_value, ) ) return fields __Schema = GraphQLObjectType( "__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: OrderedDict( [ ( "types", GraphQLField( description="A list of all types supported by this server.", type_=GraphQLNonNull( GraphQLList(GraphQLNonNull(__Type)) # type: ignore ), resolver=lambda schema, *_: schema.get_type_map().values(), ), ), ( "queryType", GraphQLField( description="The type that query operations will be rooted at.", type_=GraphQLNonNull(__Type), # type: ignore resolver=lambda schema, *_: schema.get_query_type(), ), ), ( "mutationType", GraphQLField( description="If this server supports mutation, the type that " "mutation operations will be rooted at.", type_=__Type, # type: ignore resolver=lambda schema, *_: schema.get_mutation_type(), ), ), ( "subscriptionType", GraphQLField( description="If this server support subscription, the type " "that subscription operations will be rooted at.", type_=__Type, # type: ignore resolver=lambda schema, *_: schema.get_subscription_type(), ), ), ( "directives", GraphQLField( description="A list of all directives supported by this server.", type_=GraphQLNonNull( GraphQLList(GraphQLNonNull(__Directive)) # type: ignore ), resolver=lambda schema, *_: schema.get_directives(), ), ), ] ), ) _on_operation_locations = set(DirectiveLocation.OPERATION_LOCATIONS) _on_fragment_locations = set(DirectiveLocation.FRAGMENT_LOCATIONS) _on_field_locations = set(DirectiveLocation.FIELD_LOCATIONS) __Directive = GraphQLObjectType( "__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: OrderedDict( [ ("name", GraphQLField(GraphQLNonNull(GraphQLString))), ("description", GraphQLField(GraphQLString)), ( "locations", GraphQLField( type_=GraphQLNonNull( GraphQLList(GraphQLNonNull(__DirectiveLocation)) # type: ignore ) ), ), ( "args", GraphQLField( type_=GraphQLNonNull( GraphQLList(GraphQLNonNull(__InputValue)) # type: ignore ), resolver=lambda directive, *args: input_fields_to_list( directive.args ), ), ), ( "onOperation", GraphQLField( type_=GraphQLNonNull(GraphQLBoolean), deprecation_reason="Use `locations`.", resolver=lambda directive, *args: set(directive.locations) & _on_operation_locations, ), ), ( "onFragment", GraphQLField( type_=GraphQLNonNull(GraphQLBoolean), deprecation_reason="Use `locations`.", resolver=lambda directive, *args: set(directive.locations) & _on_fragment_locations, ), ), ( "onField", GraphQLField( type_=GraphQLNonNull(GraphQLBoolean), deprecation_reason="Use `locations`.", resolver=lambda directive, *args: set(directive.locations) & _on_field_locations, ), ), ] ), ) __DirectiveLocation = GraphQLEnumType( "__DirectiveLocation", description=( "A Directive can be adjacent to many parts of the GraphQL language, a " + "__DirectiveLocation describes one such possible adjacencies." ), values=OrderedDict( [ ( "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.", ), ), ( "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 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 definition.", ), ), ( "INPUT_FIELD_DEFINITION", GraphQLEnumValue( DirectiveLocation.INPUT_FIELD_DEFINITION, description="Location adjacent to an input object field definition.", ), ), ] ), ) class TypeKind(object): SCALAR = "SCALAR" OBJECT = "OBJECT" INTERFACE = "INTERFACE" UNION = "UNION" ENUM = "ENUM" INPUT_OBJECT = "INPUT_OBJECT" LIST = "LIST" NON_NULL = "NON_NULL" class TypeFieldResolvers(object): _kinds = ( (GraphQLScalarType, TypeKind.SCALAR), (GraphQLObjectType, TypeKind.OBJECT), (GraphQLInterfaceType, TypeKind.INTERFACE), (GraphQLUnionType, TypeKind.UNION), (GraphQLEnumType, TypeKind.ENUM), (GraphQLInputObjectType, TypeKind.INPUT_OBJECT), (GraphQLList, TypeKind.LIST), (GraphQLNonNull, TypeKind.NON_NULL), ) @classmethod def kind( cls, type, # type: Union[GraphQLInterfaceType, GraphQLUnionType] *_ # type: ResolveInfo ): # type: (...) -> str for klass, kind in cls._kinds: if isinstance(type, klass): return kind raise Exception("Unknown kind of type: {}".format(type)) @staticmethod def fields( type, # type: Union[GraphQLInterfaceType, GraphQLUnionType] info, # type: ResolveInfo includeDeprecated=None, # type: bool ): # type: (...) -> Optional[List[Field]] if isinstance(type, (GraphQLObjectType, GraphQLInterfaceType)): fields = [] include_deprecated = includeDeprecated for field_name, field in type.fields.items(): if field.deprecation_reason and not include_deprecated: continue fields.append( Field( name=field_name, description=field.description, type=field.type, args=field.args, deprecation_reason=field.deprecation_reason, ) ) return fields return None @staticmethod def interfaces(type, info): # type: (Optional[GraphQLObjectType], ResolveInfo) -> Optional[List[GraphQLInterfaceType]] if isinstance(type, GraphQLObjectType): return type.interfaces return None @staticmethod def possible_types( type, # type: Union[GraphQLInterfaceType, GraphQLUnionType] info, # type: ResolveInfo **args # type: Any ): # type: (...) -> List[GraphQLObjectType] if isinstance(type, (GraphQLInterfaceType, GraphQLUnionType)): return info.schema.get_possible_types(type) @staticmethod def enum_values( type, # type: GraphQLEnumType info, # type: ResolveInfo includeDeprecated=None, # type: bool ): # type: (...) -> Optional[List[GraphQLEnumValue]] if isinstance(type, GraphQLEnumType): values = type.values if not includeDeprecated: values = [v for v in values if not v.deprecation_reason] return values return None @staticmethod def input_fields(type, info): # type: (GraphQLInputObjectType, ResolveInfo) -> List[InputField] if isinstance(type, GraphQLInputObjectType): return input_fields_to_list(type.fields) __Type = GraphQLObjectType( "__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=lambda: OrderedDict( [ ( "kind", GraphQLField( type_=GraphQLNonNull(__TypeKind), # type: ignore resolver=TypeFieldResolvers.kind, ), ), ("name", GraphQLField(GraphQLString)), ("description", GraphQLField(GraphQLString)), ( "fields", GraphQLField( type_=GraphQLList(GraphQLNonNull(__Field)), # type: ignore args={ "includeDeprecated": GraphQLArgument( GraphQLBoolean, default_value=False ) }, resolver=TypeFieldResolvers.fields, ), ), ( "interfaces", GraphQLField( type_=GraphQLList(GraphQLNonNull(__Type)), # type: ignore resolver=TypeFieldResolvers.interfaces, ), ), ( "possibleTypes", GraphQLField( type_=GraphQLList(GraphQLNonNull(__Type)), # type: ignore resolver=TypeFieldResolvers.possible_types, ), ), ( "enumValues", GraphQLField( type_=GraphQLList(GraphQLNonNull(__EnumValue)), # type: ignore args={ "includeDeprecated": GraphQLArgument( GraphQLBoolean, default_value=False ) }, resolver=TypeFieldResolvers.enum_values, ), ), ( "inputFields", GraphQLField( type_=GraphQLList(GraphQLNonNull(__InputValue)), # type: ignore resolver=TypeFieldResolvers.input_fields, ), ), ( "ofType", GraphQLField( type_=__Type, # type: ignore resolver=lambda type_, *_: getattr(type_, "of_type", None), ), ), ] ), ) __Field = GraphQLObjectType( "__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: OrderedDict( [ ("name", GraphQLField(GraphQLNonNull(GraphQLString))), ("description", GraphQLField(GraphQLString)), ( "args", GraphQLField( type_=GraphQLNonNull( GraphQLList(GraphQLNonNull(__InputValue)) # type: ignore ), resolver=lambda field, *_: input_fields_to_list(field.args), ), ), ("type", GraphQLField(GraphQLNonNull(__Type))), # type: ignore ( "isDeprecated", GraphQLField( type_=GraphQLNonNull(GraphQLBoolean), resolver=lambda field, *_: bool(field.deprecation_reason), ), ), ( "deprecationReason", GraphQLField( type_=GraphQLString, resolver=lambda field, *_: field.deprecation_reason, ), ), ] ), ) __InputValue = GraphQLObjectType( "__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: OrderedDict( [ ("name", GraphQLField(GraphQLNonNull(GraphQLString))), ("description", GraphQLField(GraphQLString)), ("type", GraphQLField(GraphQLNonNull(__Type))), ( "defaultValue", GraphQLField( type_=GraphQLString, resolver=lambda input_val, *_: None if input_val.default_value is None else print_ast(ast_from_value(input_val.default_value, input_val)), ), ), ] ), ) __EnumValue = GraphQLObjectType( "__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: OrderedDict( [ ("name", GraphQLField(GraphQLNonNull(GraphQLString))), ("description", GraphQLField(GraphQLString)), ( "isDeprecated", GraphQLField( type_=GraphQLNonNull(GraphQLBoolean), resolver=lambda field, *_: bool(field.deprecation_reason), ), ), ( "deprecationReason", GraphQLField( type_=GraphQLString, resolver=lambda enum_value, *_: enum_value.deprecation_reason, ), ), ] ), ) __TypeKind = GraphQLEnumType( "__TypeKind", description="An enum describing what kind of type a given `__Type` is", values=OrderedDict( [ ( "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` 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.", ), ), ] ), ) IntrospectionSchema = __Schema SchemaMetaFieldDef = GraphQLField( # name='__schema', type_=GraphQLNonNull(__Schema), description="Access the current type schema of this server.", resolver=lambda source, info, **args: info.schema, args={}, ) TypeMetaFieldDef = GraphQLField( type_=__Type, # name='__type', description="Request the type information of a single type.", args={"name": GraphQLArgument(GraphQLNonNull(GraphQLString))}, resolver=lambda source, info, **args: info.schema.get_type(args["name"]), ) TypeNameMetaFieldDef = GraphQLField( type_=GraphQLNonNull(GraphQLString), # name='__typename', description="The name of the current Object type at runtime.", resolver=lambda source, info, **args: info.parent_type.name, args={}, ) graphql-core-legacy-2.3.2/graphql/type/scalars.py000066400000000000000000000102501365661746200220030ustar00rootroot00000000000000from six import string_types, text_type from ..language.ast import BooleanValue, FloatValue, IntValue, StringValue from .definition import GraphQLScalarType # Necessary for static type checking if False: # flake8: noqa from typing import Any, Optional, Union # As per the GraphQL Spec, Integers are only treated as valid when a valid # 32-bit signed integer, providing the broadest support across platforms. # # n.b. JavaScript's integers are safe between -(2^31 - 1) and 2^31 - 1 because # they are internally represented as IEEE 754 doubles. MAX_INT = 2147483647 MIN_INT = -2147483648 def coerce_int(value): # type: (Any) -> int if isinstance(value, int): num = value else: try: num = int(value) except ValueError: num = int(float(value)) if MIN_INT <= num <= MAX_INT: return num raise Exception( ("Int cannot represent non 32-bit signed integer value: {}").format(value) ) def parse_int_literal(ast): # type: (IntValue) -> Optional[int] if isinstance(ast, IntValue): num = int(ast.value) if MIN_INT <= num <= MAX_INT: return num return None GraphQLInt = GraphQLScalarType( name="Int", description="The `Int` scalar type represents non-fractional signed whole numeric " "values. Int can represent values between -(2^31 - 1) and 2^31 - 1 since " "represented in JSON as double-precision floating point numbers specified" "by [IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point).", serialize=coerce_int, parse_value=coerce_int, parse_literal=parse_int_literal, ) def coerce_float(value): # type: (Any) -> float if isinstance(value, float): return value return float(value) def parse_float_literal(ast): # type: (Union[FloatValue, IntValue]) -> Optional[float] if isinstance(ast, (FloatValue, IntValue)): return float(ast.value) return None GraphQLFloat = GraphQLScalarType( name="Float", description="The `Float` scalar type represents signed double-precision fractional " "values as specified by " "[IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point). ", serialize=coerce_float, parse_value=coerce_float, parse_literal=parse_float_literal, ) def coerce_string(value): # type: (Any) -> str if isinstance(value, string_types): return value if isinstance(value, bool): return u"true" if value else u"false" return text_type(value) def coerce_str(value): # type: (Any) -> str if isinstance(value, string_types): return value return text_type(value) def parse_string_literal(ast): # type: (Union[StringValue]) -> Optional[str] if isinstance(ast, StringValue): return ast.value return None 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=coerce_string, parse_value=coerce_string, parse_literal=parse_string_literal, ) def parse_boolean_literal(ast): # type: (BooleanValue) -> Optional[bool] if isinstance(ast, BooleanValue): return ast.value return None GraphQLBoolean = GraphQLScalarType( name="Boolean", description="The `Boolean` scalar type represents `true` or `false`.", serialize=bool, parse_value=bool, parse_literal=parse_boolean_literal, ) def parse_id_literal(ast): # type: (StringValue) -> Optional[str] if isinstance(ast, (StringValue, IntValue)): return ast.value return None 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=coerce_str, parse_value=coerce_str, parse_literal=parse_id_literal, ) graphql-core-legacy-2.3.2/graphql/type/schema.py000066400000000000000000000114661365661746200216250ustar00rootroot00000000000000try: from collections.abc import Iterable except ImportError: # Python < 3.3 from collections import Iterable from collections import namedtuple from typing import Dict, Union, List, Optional from .definition import ( GraphQLNamedType, GraphQLInterfaceType, GraphQLObjectType, GraphQLUnionType, GraphQLType, ) from .directives import GraphQLDirective, specified_directives from .introspection import IntrospectionSchema from .typemap import GraphQLTypeMap InterfaceImplementations = namedtuple("InterfaceImplementations", "objects, interfaces") class GraphQLSchema(object): """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. Example: MyAppSchema = GraphQLSchema( query=MyAppQueryRootType, mutation=MyAppMutationRootType, ) Note: If an array of `directives` are 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.extend([MyCustomerDirective]), ) """ __slots__ = ( "_query", "_mutation", "_subscription", "_type_map", "_directives", "_implementations", "_possible_type_map", ) def __init__( self, query, # type: GraphQLObjectType mutation=None, # type: Optional[GraphQLObjectType] subscription=None, # type: Optional[GraphQLObjectType] directives=None, # type: Optional[List[GraphQLDirective]] types=None, # type: Optional[List[GraphQLNamedType]] ): # type: (...) -> None assert isinstance( query, GraphQLObjectType ), "Schema query must be Object Type but got: {}.".format(query) if mutation: assert isinstance( mutation, GraphQLObjectType ), "Schema mutation must be Object Type but got: {}.".format(mutation) if subscription: assert isinstance( subscription, GraphQLObjectType ), "Schema subscription must be Object Type but got: {}.".format( subscription ) if types: assert isinstance( types, Iterable ), "Schema types must be iterable if provided but got: {}.".format(types) self._query = query self._mutation = mutation self._subscription = subscription if directives is None: directives = specified_directives assert all( isinstance(d, GraphQLDirective) for d in directives ), "Schema directives must be List[GraphQLDirective] if provided but got: {}.".format( directives ) self._directives = directives initial_types = list( filter(None, [query, mutation, subscription, IntrospectionSchema]) ) # type: List[GraphQLNamedType] if types: initial_types += types self._type_map = GraphQLTypeMap(initial_types) def get_query_type(self): # type: () -> GraphQLObjectType return self._query def get_mutation_type(self): # type: () -> Optional[GraphQLObjectType] return self._mutation def get_subscription_type(self): # type: () -> Optional[GraphQLObjectType] return self._subscription def get_type_map(self): # type: () -> Dict[str, GraphQLType] return self._type_map def get_type(self, name): # type: (str) -> Optional[GraphQLNamedType] return self._type_map.get(name) # raise Exception("Type {name} not found in schema.".format(name=name)) def get_directives(self): # type: () -> List[GraphQLDirective] return self._directives def get_directive(self, name): # type: (str) -> Optional[GraphQLDirective] for directive in self.get_directives(): if directive.name == name: return directive return None def get_possible_types(self, abstract_type): # type: (Union[GraphQLInterfaceType, GraphQLUnionType]) -> List[GraphQLObjectType] return self._type_map.get_possible_types(abstract_type) def is_possible_type( self, abstract_type, # type: Union[GraphQLInterfaceType, GraphQLUnionType] possible_type, # type: GraphQLObjectType ): # type: (...) -> bool return self._type_map.is_possible_type(abstract_type, possible_type) graphql-core-legacy-2.3.2/graphql/type/tests/000077500000000000000000000000001365661746200211455ustar00rootroot00000000000000graphql-core-legacy-2.3.2/graphql/type/tests/__init__.py000066400000000000000000000000001365661746200232440ustar00rootroot00000000000000graphql-core-legacy-2.3.2/graphql/type/tests/test_definition.py000066400000000000000000000317241365661746200247150ustar00rootroot00000000000000from collections import OrderedDict from py.test import raises from graphql.type import ( GraphQLArgument, GraphQLBoolean, GraphQLEnumType, GraphQLEnumValue, GraphQLField, GraphQLInputObjectField, GraphQLInputObjectType, GraphQLInt, GraphQLInterfaceType, GraphQLList, GraphQLNonNull, GraphQLObjectType, GraphQLSchema, GraphQLString, GraphQLUnionType, ) from graphql.type.definition import is_input_type, is_output_type BlogImage = GraphQLObjectType( "Image", { "url": GraphQLField(GraphQLString), "width": GraphQLField(GraphQLInt), "height": GraphQLField(GraphQLInt), }, ) 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 ) }, ) ObjectType = GraphQLObjectType("Object", {}) InterfaceType = GraphQLInterfaceType("Interface") UnionType = GraphQLUnionType("Union", [ObjectType], resolve_type=lambda: None) EnumType = GraphQLEnumType("Enum", {"foo": GraphQLEnumValue()}) InputObjectType = GraphQLInputObjectType("InputObject", {}) def test_defines_a_query_only_schema(): BlogSchema = GraphQLSchema(BlogQuery) assert BlogSchema.get_query_type() == BlogQuery article_field = BlogQuery.fields["article"] assert article_field.type == BlogArticle assert article_field.type.name == "Article" # assert article_field.name == 'article' article_field_type = article_field.type assert isinstance(article_field_type, GraphQLObjectType) title_field = article_field_type.fields["title"] # assert title_field.name == 'title' assert title_field.type == GraphQLString assert title_field.type.name == "String" author_field = article_field_type.fields["author"] author_field_type = author_field.type assert isinstance(author_field_type, GraphQLObjectType) recent_article_field = author_field_type.fields["recentArticle"] assert recent_article_field.type == BlogArticle feed_field = BlogQuery.fields["feed"] assert feed_field.type.of_type == BlogArticle # assert feed_field.name == 'feed' def test_defines_a_mutation_schema(): BlogSchema = GraphQLSchema(BlogQuery, BlogMutation) assert BlogSchema.get_mutation_type() == BlogMutation write_mutation = BlogMutation.fields["writeArticle"] assert write_mutation.type == BlogArticle assert write_mutation.type.name == "Article" # assert write_mutation.name == 'writeArticle' def test_defines_a_subscription_schema(): BlogSchema = GraphQLSchema(query=BlogQuery, subscription=BlogSubscription) assert BlogSchema.get_subscription_type() == BlogSubscription subscription = BlogSubscription.fields["articleSubscribe"] assert subscription.type == BlogArticle assert subscription.type.name == "Article" # assert subscription.name == 'articleSubscribe' def test_defines_an_enum_type_with_deprecated_value(): EnumTypeWithDeprecatedValue = GraphQLEnumType( "EnumWithDeprecatedValue", {"foo": GraphQLEnumValue(deprecation_reason="Just because")}, ) value = EnumTypeWithDeprecatedValue.get_values()[0] assert value.name == "foo" assert value.description is None assert value.is_deprecated is True assert value.deprecation_reason == "Just because" assert value.value == "foo" def test_defines_an_enum_type_with_a_value_of_none(): EnumTypeWithNoneValue = GraphQLEnumType( "EnumWithNullishValue", {"NULL": GraphQLEnumValue(None)} ) value = EnumTypeWithNoneValue.get_values()[0] assert value.name == "NULL" assert value.description is None assert value.is_deprecated is False assert value.deprecation_reason is None assert value.value is None def test_defines_an_object_type_with_deprecated_field(): TypeWithDeprecatedField = GraphQLObjectType( "foo", fields={ "bar": GraphQLField( type_=GraphQLString, deprecation_reason="A terrible reason" ) }, ) field = TypeWithDeprecatedField.fields["bar"] assert field.type == GraphQLString assert field.description is None assert field.deprecation_reason == "A terrible reason" assert field.is_deprecated is True # assert field.name == 'bar' assert field.args == OrderedDict() def test_includes_nested_input_objects_in_the_map(): NestedInputObject = GraphQLInputObjectType( name="NestedInputObject", fields={"value": GraphQLInputObjectField(GraphQLString)}, ) SomeInputObject = GraphQLInputObjectType( name="SomeInputObject", fields={"nested": GraphQLInputObjectField(NestedInputObject)}, ) SomeMutation = GraphQLObjectType( name="SomeMutation", fields={ "mutateSomething": GraphQLField( type_=BlogArticle, args={"input": GraphQLArgument(SomeInputObject)} ) }, ) SomeSubscription = GraphQLObjectType( name="SomeSubscription", fields={ "subscribeToSomething": GraphQLField( type_=BlogArticle, args={"input": GraphQLArgument(SomeInputObject)} ) }, ) schema = GraphQLSchema( query=BlogQuery, mutation=SomeMutation, subscription=SomeSubscription ) assert schema.get_type_map()["NestedInputObject"] is NestedInputObject def test_includes_interface_possible_types_in_the_type_map(): SomeInterface = GraphQLInterfaceType( "SomeInterface", fields={"f": GraphQLField(GraphQLInt)} ) SomeSubtype = GraphQLObjectType( name="SomeSubtype", fields={"f": GraphQLField(GraphQLInt)}, interfaces=[SomeInterface], is_type_of=lambda: None, ) schema = GraphQLSchema( query=GraphQLObjectType( name="Query", fields={"iface": GraphQLField(SomeInterface)} ), types=[SomeSubtype], ) assert schema.get_type_map()["SomeSubtype"] == SomeSubtype def test_includes_interfaces_thunk_subtypes_in_the_type_map(): SomeInterface = GraphQLInterfaceType( name="SomeInterface", fields={"f": GraphQLField(GraphQLInt)} ) SomeSubtype = GraphQLObjectType( name="SomeSubtype", fields={"f": GraphQLField(GraphQLInt)}, interfaces=lambda: [SomeInterface], is_type_of=lambda: True, ) schema = GraphQLSchema( query=GraphQLObjectType( name="Query", fields={"iface": GraphQLField(SomeInterface)} ), types=[SomeSubtype], ) assert schema.get_type_map()["SomeSubtype"] is SomeSubtype def test_stringifies_simple_types(): assert str(GraphQLInt) == "Int" assert str(BlogArticle) == "Article" assert str(InterfaceType) == "Interface" assert str(UnionType) == "Union" assert str(EnumType) == "Enum" assert str(InputObjectType) == "InputObject" assert str(GraphQLNonNull(GraphQLInt)) == "Int!" assert str(GraphQLList(GraphQLInt)) == "[Int]" assert str(GraphQLNonNull(GraphQLList(GraphQLInt))) == "[Int]!" assert str(GraphQLList(GraphQLNonNull(GraphQLInt))) == "[Int!]" assert str(GraphQLList(GraphQLList(GraphQLInt))) == "[[Int]]" def test_identifies_input_types(): expected = ( (GraphQLInt, True), (ObjectType, False), (InterfaceType, False), (UnionType, False), (EnumType, True), (InputObjectType, True), ) for type, answer in expected: assert is_input_type(type) == answer assert is_input_type(GraphQLList(type)) == answer assert is_input_type(GraphQLNonNull(type)) == answer def test_identifies_output_types(): expected = ( (GraphQLInt, True), (ObjectType, True), (InterfaceType, True), (UnionType, True), (EnumType, True), (InputObjectType, False), ) for type, answer in expected: assert is_output_type(type) == answer assert is_output_type(GraphQLList(type)) == answer assert is_output_type(GraphQLNonNull(type)) == answer def test_prohibits_nesting_nonnull_inside_nonnull(): with raises(Exception) as excinfo: GraphQLNonNull(GraphQLNonNull(GraphQLInt)) assert "Can only create NonNull of a Nullable GraphQLType but got: Int!." in str( excinfo.value ) def test_prohibits_putting_non_object_types_in_unions(): bad_union_types = [ GraphQLInt, GraphQLNonNull(GraphQLInt), GraphQLList(GraphQLInt), InterfaceType, UnionType, EnumType, InputObjectType, ] for x in bad_union_types: with raises(Exception) as excinfo: GraphQLSchema( GraphQLObjectType( "Root", fields={"union": GraphQLField(GraphQLUnionType("BadUnion", [x]))}, ) ) assert "BadUnion may only contain Object types, it cannot contain: " + str( x ) + "." == str(excinfo.value) def test_does_not_mutate_passed_field_definitions(): fields = { "field1": GraphQLField(GraphQLString), "field2": GraphQLField( GraphQLString, args={"id": GraphQLArgument(GraphQLString)} ), } TestObject1 = GraphQLObjectType(name="Test1", fields=fields) TestObject2 = GraphQLObjectType(name="Test1", fields=fields) assert TestObject1.fields == TestObject2.fields assert fields == { "field1": GraphQLField(GraphQLString), "field2": GraphQLField( GraphQLString, args={"id": GraphQLArgument(GraphQLString)} ), } input_fields = { "field1": GraphQLInputObjectField(GraphQLString), "field2": GraphQLInputObjectField(GraphQLString), } TestInputObject1 = GraphQLInputObjectType(name="Test1", fields=input_fields) TestInputObject2 = GraphQLInputObjectType(name="Test2", fields=input_fields) assert TestInputObject1.fields == TestInputObject2.fields assert input_fields == { "field1": GraphQLInputObjectField(GraphQLString), "field2": GraphQLInputObjectField(GraphQLString), } # def test_sorts_fields_and_argument_keys_if_not_using_ordered_dict(): # fields = { # 'b': GraphQLField(GraphQLString), # 'c': GraphQLField(GraphQLString), # 'a': GraphQLField(GraphQLString), # 'd': GraphQLField(GraphQLString, args={ # 'q': GraphQLArgument(GraphQLString), # 'x': GraphQLArgument(GraphQLString), # 'v': GraphQLArgument(GraphQLString), # 'a': GraphQLArgument(GraphQLString), # 'n': GraphQLArgument(GraphQLString) # }) # } # test_object = GraphQLObjectType(name='Test', fields=fields) # ordered_fields = test_object.fields # assert list(ordered_fields.keys()) == ['a', 'b', 'c', 'd'] # field_with_args = test_object.fields.get('d') # assert list(field_with_args.args.keys()) == ['a', 'n', 'q', 'v', 'x'] def test_does_not_sort_fields_and_argument_keys_when_using_ordered_dict(): fields = OrderedDict( [ ("b", GraphQLField(GraphQLString)), ("c", GraphQLField(GraphQLString)), ("a", GraphQLField(GraphQLString)), ( "d", GraphQLField( GraphQLString, args=OrderedDict( [ ("q", GraphQLArgument(GraphQLString)), ("x", GraphQLArgument(GraphQLString)), ("v", GraphQLArgument(GraphQLString)), ("a", GraphQLArgument(GraphQLString)), ("n", GraphQLArgument(GraphQLString)), ] ), ), ), ] ) test_object = GraphQLObjectType(name="Test", fields=fields) ordered_fields = test_object.fields assert list(ordered_fields.keys()) == ["b", "c", "a", "d"] field_with_args = test_object.fields.get("d") assert list(field_with_args.args.keys()) == ["q", "x", "v", "a", "n"] graphql-core-legacy-2.3.2/graphql/type/tests/test_enum_type.py000066400000000000000000000204711365661746200245670ustar00rootroot00000000000000import sys from collections import OrderedDict from rx import Observable from graphql import graphql from graphql.type import ( GraphQLArgument, GraphQLEnumType, GraphQLEnumValue, GraphQLField, GraphQLInt, GraphQLObjectType, GraphQLSchema, GraphQLString, ) import pytest ColorType = GraphQLEnumType( name="Color", values=OrderedDict( [ ("RED", GraphQLEnumValue(0)), ("GREEN", GraphQLEnumValue(1)), ("BLUE", GraphQLEnumValue(2)), ] ), ) def get_first(args, *keys): for key in keys: if key in args: return args[key] return None QueryType = GraphQLObjectType( name="Query", fields={ "colorEnum": GraphQLField( type_=ColorType, args={ "fromEnum": GraphQLArgument(ColorType), "fromInt": GraphQLArgument(GraphQLInt), "fromString": GraphQLArgument(GraphQLString), }, resolver=lambda value, info, **args: get_first( args, "fromInt", "fromString", "fromEnum" ), ), "colorInt": GraphQLField( type_=GraphQLInt, args={ "fromEnum": GraphQLArgument(ColorType), "fromInt": GraphQLArgument(GraphQLInt), }, resolver=lambda value, info, **args: get_first(args, "fromInt", "fromEnum"), ), }, ) MutationType = GraphQLObjectType( name="Mutation", fields={ "favoriteEnum": GraphQLField( type_=ColorType, args={"color": GraphQLArgument(ColorType)}, resolver=lambda value, info, **args: args.get("color"), ) }, ) SubscriptionType = GraphQLObjectType( name="Subscription", fields={ "subscribeToEnum": GraphQLField( type_=ColorType, args={"color": GraphQLArgument(ColorType)}, resolver=lambda value, info, **args: Observable.from_([args.get("color")]), ) }, ) Schema = GraphQLSchema( query=QueryType, mutation=MutationType, subscription=SubscriptionType ) def test_accepts_enum_literals_as_input(): result = graphql(Schema, "{ colorInt(fromEnum: GREEN) }") assert not result.errors assert result.data == {"colorInt": 1} def test_enum_may_be_output_type(): result = graphql(Schema, "{ colorEnum(fromInt: 1) }") assert not result.errors assert result.data == {"colorEnum": "GREEN"} def test_enum_may_be_both_input_and_output_type(): result = graphql(Schema, "{ colorEnum(fromEnum: GREEN) }") assert not result.errors assert result.data == {"colorEnum": "GREEN"} def test_does_not_accept_string_literals(): result = graphql(Schema, '{ colorEnum(fromEnum: "GREEN") }') assert not result.data assert ( result.errors[0].message == 'Argument "fromEnum" has invalid value "GREEN".\n' 'Expected type "Color", found "GREEN".' ) def test_does_not_accept_values_not_in_the_enum(): result = graphql(Schema, "{ colorEnum(fromEnum: GREENISH) }") assert not result.data assert ( result.errors[0].message == 'Argument "fromEnum" has invalid value GREENISH.\n' 'Expected type "Color", found GREENISH.' ) def test_does_not_accept_values_with_incorrect_casing(): result = graphql(Schema, "{ colorEnum(fromEnum: green) }") assert not result.data assert ( result.errors[0].message == 'Argument "fromEnum" has invalid value green.\n' 'Expected type "Color", found green.' ) def test_does_not_accept_incorrect_internal_value(): result = graphql(Schema, '{ colorEnum(fromString: "GREEN") }') assert result.data == {"colorEnum": None} assert ( result.errors[0].message == 'Expected a value of type "Color" ' "but received: GREEN" ) def test_does_not_accept_internal_value_in_place_of_enum_literal(): result = graphql(Schema, "{ colorEnum(fromEnum: 1) }") assert not result.data assert ( result.errors[0].message == 'Argument "fromEnum" has invalid value 1.\n' 'Expected type "Color", found 1.' ) def test_does_not_accept_enum_literal_in_place_of_int(): result = graphql(Schema, "{ colorEnum(fromInt: GREEN) }") assert not result.data assert ( result.errors[0].message == 'Argument "fromInt" has invalid value GREEN.\n' 'Expected type "Int", found GREEN.' ) def test_accepts_json_string_as_enum_variable(): result = graphql( Schema, "query test($color: Color!) { colorEnum(fromEnum: $color) }", variable_values={"color": "BLUE"}, ) assert not result.errors assert result.data == {"colorEnum": "BLUE"} def test_accepts_enum_literals_as_input_arguments_to_mutations(): result = graphql( Schema, "mutation x($color: Color!) { favoriteEnum(color: $color) }", variable_values={"color": "GREEN"}, ) assert not result.errors assert result.data == {"favoriteEnum": "GREEN"} def test_accepts_enum_literals_as_input_arguments_to_subscriptions(): result = graphql( Schema, "subscription x($color: Color!) { subscribeToEnum(color: $color) }", variable_values={"color": "GREEN"}, allow_subscriptions=True, ) assert isinstance(result, Observable) lit = [] result.subscribe(lit.append) result = lit[0] assert not result.errors assert result.data == {"subscribeToEnum": "GREEN"} def test_does_not_accept_internal_value_as_enum_variable(): result = graphql( Schema, "query test($color: Color!) { colorEnum(fromEnum: $color) }", variable_values={"color": 2}, ) assert not result.data assert ( result.errors[0].message == 'Variable "$color" got invalid value 2.\n' 'Expected type "Color", found 2.' ) def test_does_not_accept_string_variables_as_enum_input(): result = graphql( Schema, "query test($color: String!) { colorEnum(fromEnum: $color) }", variable_values={"color": "BLUE"}, ) assert not result.data assert ( result.errors[0].message == 'Variable "color" of type "String!" used in position expecting type "Color".' ) def test_does_not_accept_internal_value_as_enum_input(): result = graphql( Schema, "query test($color: Int!) { colorEnum(fromEnum: $color) }", variable_values={"color": 2}, ) assert not result.data assert ( result.errors[0].message == 'Variable "color" of type "Int!" used in position expecting type "Color".' ) def test_enum_value_may_have_an_internal_value_of_0(): result = graphql(Schema, "{ colorEnum(fromEnum: RED) colorInt(fromEnum: RED) }") assert not result.errors assert result.data == {"colorEnum": "RED", "colorInt": 0} def test_enum_inputs_may_be_nullable(): result = graphql(Schema, "{ colorEnum colorInt }") assert not result.errors assert result.data == {"colorEnum": None, "colorInt": None} def test_presents_a_get_values_api(): values = ColorType.get_values() assert len(values) == 3 assert values[0].name == "RED" assert values[0].value == 0 assert values[1].name == "GREEN" assert values[1].value == 1 assert values[2].name == "BLUE" assert values[2].value == 2 def test_presents_a_get_value_api(): oneValue = ColorType.get_value("RED") assert oneValue.name == "RED" assert oneValue.value == 0 badUsage = ColorType.get_value(0) assert badUsage is None @pytest.mark.skipif( sys.version_info >= (3, 7), reason="As of Python 3.7 we use built-in dicts, which preserve order", ) def test_sorts_values_if_not_using_ordered_dict(): enum = GraphQLEnumType( name="Test", values={ "c": GraphQLEnumValue(), "b": GraphQLEnumValue(), "a": GraphQLEnumValue(), "d": GraphQLEnumValue(), }, ) assert [v.name for v in enum.values] == ["a", "b", "c", "d"] def test_does_not_sort_values_when_using_ordered_dict(): enum = GraphQLEnumType( name="Test", values=OrderedDict( [ ("c", GraphQLEnumValue()), ("b", GraphQLEnumValue()), ("a", GraphQLEnumValue()), ("d", GraphQLEnumValue()), ] ), ) assert [v.name for v in enum.values] == ["c", "b", "a", "d"] graphql-core-legacy-2.3.2/graphql/type/tests/test_introspection.py000066400000000000000000001272331365661746200254660ustar00rootroot00000000000000import json from collections import OrderedDict from graphql import graphql from graphql.error import format_error from graphql.execution import execute from graphql.language.parser import parse from graphql.type import ( GraphQLArgument, GraphQLEnumType, GraphQLEnumValue, GraphQLField, GraphQLInputObjectField, GraphQLInputObjectType, GraphQLList, GraphQLObjectType, GraphQLSchema, GraphQLString, ) from graphql.utils.introspection_query import introspection_query from graphql.validation.rules import ProvidedNonNullArguments from ...pyutils.contain_subset import contain_subset def test_executes_an_introspection_query(): EmptySchema = GraphQLSchema( GraphQLObjectType("QueryRoot", {"f": GraphQLField(GraphQLString)}) ) result = graphql(EmptySchema, introspection_query) assert not result.errors expected = { "__schema": { "mutationType": None, "subscriptionType": None, "queryType": {"name": "QueryRoot"}, "types": [ { "kind": "OBJECT", "name": "QueryRoot", "inputFields": None, "interfaces": [], "enumValues": None, "possibleTypes": None, }, { "kind": "OBJECT", "name": "__Schema", "fields": [ { "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"}, }, }, }, "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", }, }, }, }, "isDeprecated": False, "deprecationReason": None, }, ], "inputFields": None, "interfaces": [], "enumValues": None, "possibleTypes": None, }, { "kind": "OBJECT", "name": "__Type", "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": "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": [], "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", "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": "SCALAR", "name": "String", "fields": None, "inputFields": None, "interfaces": None, "enumValues": None, "possibleTypes": None, }, { "kind": "SCALAR", "name": "Boolean", "fields": None, "inputFields": None, "interfaces": None, "enumValues": None, "possibleTypes": None, }, { "kind": "OBJECT", "name": "__Field", "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": [], "type": { "kind": "NON_NULL", "name": None, "ofType": { "kind": "LIST", "name": None, "ofType": { "kind": "NON_NULL", "name": None, "ofType": { "kind": "OBJECT", "name": "__InputValue", }, }, }, }, "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", "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, }, ], "inputFields": None, "interfaces": [], "enumValues": None, "possibleTypes": None, }, { "kind": "OBJECT", "name": "__EnumValue", "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", "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": "locations", "args": [], "type": { "kind": "NON_NULL", "name": None, "ofType": { "kind": "LIST", "name": None, "ofType": { "kind": "NON_NULL", "name": None, "ofType": { "kind": "ENUM", "name": "__DirectiveLocation", }, }, }, }, "isDeprecated": False, "deprecationReason": None, }, { "name": "args", "args": [], "type": { "kind": "NON_NULL", "name": None, "ofType": { "kind": "LIST", "name": None, "ofType": { "kind": "NON_NULL", "name": None, "ofType": { "kind": "OBJECT", "name": "__InputValue", }, }, }, }, "isDeprecated": False, "deprecationReason": None, }, { "name": "onOperation", "args": [], "type": { "kind": "NON_NULL", "name": None, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": None, }, }, "isDeprecated": True, "deprecationReason": "Use `locations`.", }, { "name": "onFragment", "args": [], "type": { "kind": "NON_NULL", "name": None, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": None, }, }, "isDeprecated": True, "deprecationReason": "Use `locations`.", }, { "name": "onField", "args": [], "type": { "kind": "NON_NULL", "name": None, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": None, }, }, "isDeprecated": True, "deprecationReason": "Use `locations`.", }, ], "inputFields": None, "interfaces": [], "enumValues": None, "possibleTypes": None, }, { "kind": "ENUM", "name": "__DirectiveLocation", "fields": None, "inputFields": None, "interfaces": None, "enumValues": [ {"name": "QUERY", "isDeprecated": False}, {"name": "MUTATION", "isDeprecated": False}, {"name": "SUBSCRIPTION", "isDeprecated": False}, {"name": "FIELD", "isDeprecated": False}, {"name": "FRAGMENT_DEFINITION", "isDeprecated": False}, {"name": "FRAGMENT_SPREAD", "isDeprecated": False}, {"name": "INLINE_FRAGMENT", "isDeprecated": False}, ], "possibleTypes": None, }, ], "directives": [ { "name": "include", "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", "locations": ["FIELD", "FRAGMENT_SPREAD", "INLINE_FRAGMENT"], "args": [ { "defaultValue": None, "name": "if", "type": { "kind": "NON_NULL", "name": None, "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": None, }, }, } ], }, ], } } assert contain_subset(expected, result.data) def test_introspects_on_input_object(): TestInputObject = GraphQLInputObjectType( "TestInputObject", OrderedDict( [ ("a", GraphQLInputObjectField(GraphQLString, default_value="foo")), ("b", GraphQLInputObjectField(GraphQLList(GraphQLString))), ] ), ) TestType = GraphQLObjectType( "TestType", { "field": GraphQLField( type_=GraphQLString, args={"complex": GraphQLArgument(TestInputObject)}, resolver=lambda obj, info, **args: json.dumps(args.get("complex")), ) }, ) schema = GraphQLSchema(TestType) request = """ { __schema { types { kind name inputFields { name type { ...TypeRef } defaultValue } } } } fragment TypeRef on __Type { kind name ofType { kind name ofType { kind name ofType { kind name } } } } """ result = graphql(schema, request) assert not result.errors assert { "kind": "INPUT_OBJECT", "name": "TestInputObject", "inputFields": [ { "name": "a", "type": {"kind": "SCALAR", "name": "String", "ofType": None}, "defaultValue": '"foo"', }, { "name": "b", "type": { "kind": "LIST", "name": None, "ofType": {"kind": "SCALAR", "name": "String", "ofType": None}, }, "defaultValue": None, }, ], } in result.data["__schema"]["types"] def test_supports_the_type_root_field(): TestType = GraphQLObjectType("TestType", {"testField": GraphQLField(GraphQLString)}) schema = GraphQLSchema(TestType) request = '{ __type(name: "TestType") { name } }' result = execute(schema, parse(request), object()) assert not result.errors assert result.data == {"__type": {"name": "TestType"}} def test_identifies_deprecated_fields(): TestType = GraphQLObjectType( "TestType", OrderedDict( [ ("nonDeprecated", GraphQLField(GraphQLString)), ( "deprecated", GraphQLField(GraphQLString, deprecation_reason="Removed in 1.0"), ), ] ), ) schema = GraphQLSchema(TestType) request = """{__type(name: "TestType") { name fields(includeDeprecated: true) { name isDeprecated deprecationReason } } }""" result = graphql(schema, request) assert not result.errors assert result.data == { "__type": { "name": "TestType", "fields": [ { "name": "nonDeprecated", "isDeprecated": False, "deprecationReason": None, }, { "name": "deprecated", "isDeprecated": True, "deprecationReason": "Removed in 1.0", }, ], } } def test_respects_the_includedeprecated_parameter_for_fields(): TestType = GraphQLObjectType( "TestType", OrderedDict( [ ("nonDeprecated", GraphQLField(GraphQLString)), ( "deprecated", GraphQLField(GraphQLString, deprecation_reason="Removed in 1.0"), ), ] ), ) schema = GraphQLSchema(TestType) request = """{__type(name: "TestType") { name trueFields: fields(includeDeprecated: true) { name } falseFields: fields(includeDeprecated: false) { name } omittedFields: fields { name } } }""" result = graphql(schema, request) assert not result.errors assert result.data == { "__type": { "name": "TestType", "trueFields": [{"name": "nonDeprecated"}, {"name": "deprecated"}], "falseFields": [{"name": "nonDeprecated"}], "omittedFields": [{"name": "nonDeprecated"}], } } def test_identifies_deprecated_enum_values(): TestEnum = GraphQLEnumType( "TestEnum", OrderedDict( [ ("NONDEPRECATED", GraphQLEnumValue(0)), ( "DEPRECATED", GraphQLEnumValue(1, deprecation_reason="Removed in 1.0"), ), ("ALSONONDEPRECATED", GraphQLEnumValue(2)), ] ), ) TestType = GraphQLObjectType("TestType", {"testEnum": GraphQLField(TestEnum)}) schema = GraphQLSchema(TestType) request = """{__type(name: "TestEnum") { name enumValues(includeDeprecated: true) { name isDeprecated deprecationReason } } }""" result = graphql(schema, request) assert not result.errors assert result.data == { "__type": { "name": "TestEnum", "enumValues": [ { "name": "NONDEPRECATED", "isDeprecated": False, "deprecationReason": None, }, { "name": "DEPRECATED", "isDeprecated": True, "deprecationReason": "Removed in 1.0", }, { "name": "ALSONONDEPRECATED", "isDeprecated": False, "deprecationReason": None, }, ], } } def test_respects_the_includedeprecated_parameter_for_enum_values(): TestEnum = GraphQLEnumType( "TestEnum", OrderedDict( [ ("NONDEPRECATED", GraphQLEnumValue(0)), ( "DEPRECATED", GraphQLEnumValue(1, deprecation_reason="Removed in 1.0"), ), ("ALSONONDEPRECATED", GraphQLEnumValue(2)), ] ), ) TestType = GraphQLObjectType("TestType", {"testEnum": GraphQLField(TestEnum)}) schema = GraphQLSchema(TestType) request = """{__type(name: "TestEnum") { name trueValues: enumValues(includeDeprecated: true) { name } falseValues: enumValues(includeDeprecated: false) { name } omittedValues: enumValues { name } } }""" result = graphql(schema, request) assert not result.errors assert result.data == { "__type": { "name": "TestEnum", "trueValues": [ {"name": "NONDEPRECATED"}, {"name": "DEPRECATED"}, {"name": "ALSONONDEPRECATED"}, ], "falseValues": [{"name": "NONDEPRECATED"}, {"name": "ALSONONDEPRECATED"}], "omittedValues": [{"name": "NONDEPRECATED"}, {"name": "ALSONONDEPRECATED"}], } } def test_fails_as_expected_on_the_type_root_field_without_an_arg(): TestType = GraphQLObjectType("TestType", {"testField": GraphQLField(GraphQLString)}) schema = GraphQLSchema(TestType) request = """ { __type { name } }""" result = graphql(schema, request) expected_error = { "message": ProvidedNonNullArguments.missing_field_arg_message( "__type", "name", "String!" ), "locations": [dict(line=3, column=9)], } assert expected_error in [format_error(error) for error in result.errors] def test_exposes_descriptions_on_types_and_fields(): QueryRoot = GraphQLObjectType("QueryRoot", {"f": GraphQLField(GraphQLString)}) schema = GraphQLSchema(QueryRoot) request = """{ schemaType: __type(name: "__Schema") { name, description, fields { name, description } } } """ result = graphql(schema, request) assert not result.errors assert result.data == { "schemaType": { "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": "types", "description": "A list of all types supported by this server.", }, { "name": "queryType", "description": "The type that query operations will be rooted at.", }, { "name": "mutationType", "description": "If this server supports mutation, the type that " "mutation operations will be rooted at.", }, { "name": "subscriptionType", "description": "If this server support subscription, the type " "that subscription operations will be rooted at.", }, { "name": "directives", "description": "A list of all directives supported by this server.", }, ], } } def test_exposes_descriptions_on_enums(): QueryRoot = GraphQLObjectType("QueryRoot", {"f": GraphQLField(GraphQLString)}) schema = GraphQLSchema(QueryRoot) request = """{ typeKindType: __type(name: "__TypeKind") { name, description, enumValues { name, description } } } """ result = graphql(schema, request) assert not result.errors assert result.data == { "typeKindType": { "name": "__TypeKind", "description": "An enum describing what kind of type a given `__Type` is", "enumValues": [ {"description": "Indicates this type is a scalar.", "name": "SCALAR"}, { "description": "Indicates this type is an object. " + "`fields` and `interfaces` are valid fields.", "name": "OBJECT", }, { "description": "Indicates this type is an interface. " + "`fields` and `possibleTypes` are valid fields.", "name": "INTERFACE", }, { "description": "Indicates this type is a union. " + "`possibleTypes` is a valid field.", "name": "UNION", }, { "description": "Indicates this type is an enum. " + "`enumValues` is a valid field.", "name": "ENUM", }, { "description": "Indicates this type is an input object. " + "`inputFields` is a valid field.", "name": "INPUT_OBJECT", }, { "description": "Indicates this type is a list. " + "`ofType` is a valid field.", "name": "LIST", }, { "description": "Indicates this type is a non-null. " + "`ofType` is a valid field.", "name": "NON_NULL", }, ], } } graphql-core-legacy-2.3.2/graphql/type/tests/test_schema.py000066400000000000000000000021471365661746200240220ustar00rootroot00000000000000from pytest import raises from ...type import ( GraphQLField, GraphQLInterfaceType, GraphQLObjectType, GraphQLSchema, GraphQLString, ) interface_type = GraphQLInterfaceType( name="Interface", fields={ "field_name": GraphQLField( type_=GraphQLString, resolver=lambda *_: implementing_type ) }, ) implementing_type = GraphQLObjectType( name="Object", interfaces=[interface_type], fields={"field_name": GraphQLField(type_=GraphQLString, resolver=lambda *_: "")}, ) schema = GraphQLSchema( query=GraphQLObjectType( name="Query", fields={ "get_object": GraphQLField(type_=interface_type, resolver=lambda *_: {}) }, ) ) def test_throws_human_readable_error_if_schematypes_not_defined(): with raises(AssertionError) as exci: schema.is_possible_type(interface_type, implementing_type) assert str(exci.value) == ( "Could not find possible implementing types for Interface in schema. Check that " "schema.types is defined and is an array ofall possible types in the schema." ) graphql-core-legacy-2.3.2/graphql/type/tests/test_serialization.py000066400000000000000000000066741365661746200254500ustar00rootroot00000000000000import pytest from ..scalars import GraphQLBoolean, GraphQLFloat, GraphQLInt, GraphQLString from ..definition import GraphQLEnumType, GraphQLEnumValue from ...pyutils.compat import Enum def test_serializes_output_int(): assert GraphQLInt.serialize(1) == 1 assert GraphQLInt.serialize(0) == 0 assert GraphQLInt.serialize(-1) == -1 assert GraphQLInt.serialize(0.1) == 0 assert GraphQLInt.serialize(1.1) == 1 assert GraphQLInt.serialize(-1.1) == -1 assert GraphQLInt.serialize(1e5) == 100000 with pytest.raises(Exception): GraphQLInt.serialize(9876504321) with pytest.raises(Exception): GraphQLInt.serialize(-9876504321) with pytest.raises(Exception): GraphQLInt.serialize(1e100) with pytest.raises(Exception): GraphQLInt.serialize(-1e100) assert GraphQLInt.serialize("-1.1") == -1 with pytest.raises(Exception): GraphQLInt.serialize("one") assert GraphQLInt.serialize(False) == 0 assert GraphQLInt.serialize(True) == 1 def test_serializes_output_float(): assert GraphQLFloat.serialize(1) == 1.0 assert GraphQLFloat.serialize(0) == 0.0 assert GraphQLFloat.serialize(-1) == -1.0 assert GraphQLFloat.serialize(0.1) == 0.1 assert GraphQLFloat.serialize(1.1) == 1.1 assert GraphQLFloat.serialize(-1.1) == -1.1 assert GraphQLFloat.serialize("-1.1") == -1.1 with pytest.raises(Exception): GraphQLFloat.serialize("one") assert GraphQLFloat.serialize(False) == 0 assert GraphQLFloat.serialize(True) == 1 def test_serializes_output_string(): assert GraphQLString.serialize("string") == "string" assert GraphQLString.serialize(1) == "1" assert GraphQLString.serialize(-1.1) == "-1.1" assert GraphQLString.serialize(True) == "true" assert GraphQLString.serialize(False) == "false" assert GraphQLString.serialize(u"\U0001F601") == u"\U0001F601" def test_serializes_output_boolean(): assert GraphQLBoolean.serialize("string") is True assert GraphQLBoolean.serialize("") is False assert GraphQLBoolean.serialize(1) is True assert GraphQLBoolean.serialize(0) is False assert GraphQLBoolean.serialize(True) is True assert GraphQLBoolean.serialize(False) is False def test_serializes_enum(): class Color(Enum): RED = "RED" GREEN = "GREEN" BLUE = "BLUE" EXTRA = "EXTRA" enum_type = GraphQLEnumType( "Color", values={ "RED": GraphQLEnumValue("RED"), "GREEN": GraphQLEnumValue("GREEN"), "BLUE": GraphQLEnumValue("BLUE"), }, ) assert enum_type.serialize("RED") == "RED" assert enum_type.serialize("NON_EXISTING") is None assert enum_type.serialize(Color.RED) == "RED" assert enum_type.serialize(Color.RED.value) == "RED" assert enum_type.serialize(Color.EXTRA) is None assert enum_type.serialize(Color.EXTRA.value) is None def test_serialize_enum_pyenum(): class Color(Enum): RED = 1 GREEN = 2 BLUE = 3 EXTRA = 4 enum_type = GraphQLEnumType( "Color", values={ "RED": GraphQLEnumValue(Color.RED), "GREEN": GraphQLEnumValue(Color.GREEN), "BLUE": GraphQLEnumValue(Color.BLUE), }, ) assert enum_type.serialize(Color.RED) == "RED" assert enum_type.serialize(Color.RED.value) == "RED" assert enum_type.serialize(Color.EXTRA) is None assert enum_type.serialize(Color.EXTRA.value) is None graphql-core-legacy-2.3.2/graphql/type/tests/test_validation.py000066400000000000000000001615601365661746200247210ustar00rootroot00000000000000import re from pytest import raises from graphql.type import ( GraphQLEnumType, GraphQLEnumValue, GraphQLField, GraphQLInputObjectField, GraphQLInputObjectType, GraphQLInterfaceType, GraphQLList, GraphQLNonNull, GraphQLObjectType, GraphQLScalarType, GraphQLSchema, GraphQLString, GraphQLUnionType, ) from graphql.type.definition import GraphQLArgument _none = lambda *args: None _true = lambda *args: True _false = lambda *args: False SomeScalarType = GraphQLScalarType( name="SomeScalar", serialize=_none, parse_value=_none, parse_literal=_none ) SomeObjectType = GraphQLObjectType( name="SomeObject", fields={"f": GraphQLField(GraphQLString)} ) ObjectWithIsTypeOf = GraphQLObjectType( name="ObjectWithIsTypeOf", is_type_of=_true, fields={"f": GraphQLField(GraphQLString)}, ) SomeUnionType = GraphQLUnionType( name="SomeUnion", resolve_type=_none, types=[SomeObjectType] ) SomeInterfaceType = GraphQLInterfaceType( name="SomeInterface", resolve_type=_none, fields={"f": GraphQLField(GraphQLString)} ) SomeEnumType = GraphQLEnumType(name="SomeEnum", values={"ONLY": GraphQLEnumValue()}) SomeInputObjectType = GraphQLInputObjectType( name="SomeInputObject", fields={"val": GraphQLInputObjectField(GraphQLString, default_value="hello")}, ) def with_modifiers(types): return ( types + [GraphQLList(t) for t in types] + [GraphQLNonNull(t) for t in types] + [GraphQLNonNull(GraphQLList(t)) for t in types] ) output_types = with_modifiers( [ GraphQLString, SomeScalarType, SomeEnumType, SomeObjectType, SomeUnionType, SomeInterfaceType, ] ) not_output_types = with_modifiers([SomeInputObjectType]) + [str] input_types = with_modifiers( [GraphQLString, SomeScalarType, SomeEnumType, SomeInputObjectType] ) not_input_types = with_modifiers([SomeObjectType, SomeUnionType, SomeInterfaceType]) + [ str ] def schema_with_field_type(t): return GraphQLSchema( query=GraphQLObjectType(name="Query", fields={"f": GraphQLField(t)}), types=[t] ) # noinspection PyMethodMayBeStatic,PyPep8Naming class TestTypeSystem_ASchemaMustHaveObjectRootTypes: def test_accepts_a_schema_whose_query_type_is_an_object_type(self): assert GraphQLSchema(query=SomeObjectType) def test_accepts_a_schema_whose_query_and_mutation_types_are_object_types(self): MutationType = GraphQLObjectType( name="Mutation", fields={"edit": GraphQLField(GraphQLString)} ) assert GraphQLSchema(query=SomeObjectType, mutation=MutationType) def test_accepts_a_schema_whose_query_and_subscription_types_are_object_types(self): SubscriptionType = GraphQLObjectType( name="Subscription", fields={"subscribe": GraphQLField(GraphQLString)} ) assert GraphQLSchema(query=SomeObjectType, subscription=SubscriptionType) def test_rejects_a_schema_without_a_query_type(self): with raises(AssertionError) as excinfo: GraphQLSchema(query=None) assert str(excinfo.value) == "Schema query must be Object Type but got: None." def test_rejects_a_schema_whose_query_type_is_an_input_type(self): with raises(AssertionError) as excinfo: GraphQLSchema(query=SomeInputObjectType) assert ( str(excinfo.value) == "Schema query must be Object Type but got: SomeInputObject." ) def test_rejects_a_schema_whose_mutation_type_is_an_input_type(self): with raises(AssertionError) as excinfo: GraphQLSchema(query=SomeObjectType, mutation=SomeInputObjectType) assert ( str(excinfo.value) == "Schema mutation must be Object Type but got: SomeInputObject." ) def test_rejects_a_schema_whose_subscription_type_is_an_input_type(self): with raises(AssertionError) as excinfo: GraphQLSchema(query=SomeObjectType, subscription=SomeInputObjectType) assert ( str(excinfo.value) == "Schema subscription must be Object Type but got: SomeInputObject." ) def test_rejects_a_schema_whose_directives_are_incorrectly_typed(self): with raises(AssertionError) as excinfo: GraphQLSchema(query=SomeObjectType, directives=["somedirective"]) assert ( str(excinfo.value) == "Schema directives must be List[GraphQLDirective] if provided but got: " "['somedirective']." ) # noinspection PyMethodMayBeStatic,PyPep8Naming class TestTypeSystem_ASchemaMustContainUniquelyNamedTypes: def test_it_rejects_a_schema_which_defines_a_builtin_type(self): FakeString = GraphQLScalarType(name="String", serialize=_none) QueryType = GraphQLObjectType( name="Query", fields={ "normal": GraphQLField(GraphQLString), "fake": GraphQLField(FakeString), }, ) with raises(AssertionError) as excinfo: GraphQLSchema(query=QueryType) assert ( str(excinfo.value) == "Schema must contain unique named types but contains multiple types named " '"String".' ) # noinspection PyUnusedLocal def test_it_rejects_a_schema_which_have_same_named_objects_implementing_an_interface( self, ): AnotherInterface = GraphQLInterfaceType( name="AnotherInterface", resolve_type=_none, fields={"f": GraphQLField(GraphQLString)}, ) FirstBadObject = GraphQLObjectType( name="BadObject", interfaces=[AnotherInterface], fields={"f": GraphQLField(GraphQLString)}, ) SecondBadObject = GraphQLObjectType( name="BadObject", interfaces=[AnotherInterface], fields={"f": GraphQLField(GraphQLString)}, ) QueryType = GraphQLObjectType( name="Query", fields={"iface": GraphQLField(AnotherInterface)} ) with raises(AssertionError) as excinfo: GraphQLSchema(query=QueryType, types=[FirstBadObject, SecondBadObject]) assert ( str(excinfo.value) == "Schema must contain unique named types but contains multiple types named " '"BadObject".' ) # noinspection PyMethodMayBeStatic,PyPep8Naming class TestTypeSystem_ObjectsMustHaveFields: def test_accepts_an_object_type_with_fields_object(self): assert schema_with_field_type( GraphQLObjectType( name="SomeObject", fields={"f": GraphQLField(GraphQLString)} ) ) def test_accepts_an_object_type_with_a_field_function(self): assert schema_with_field_type( GraphQLObjectType( name="SomeObject", fields=lambda: {"f": GraphQLField(GraphQLString)} ) ) def test_rejects_an_object_type_with_missing_fields(self): with raises(AssertionError) as excinfo: schema_with_field_type(GraphQLObjectType(name="SomeObject", fields=None)) assert ( str(excinfo.value) == "SomeObject fields must be a mapping (dict / OrderedDict) with field names " "as keys or a function which returns such a mapping." ) def test_rejects_an_object_type_with_incorrectly_named_fields(self): with raises(AssertionError) as excinfo: schema_with_field_type( GraphQLObjectType( name="SomeObject", fields={"bad-name-with-dashes": GraphQLField(GraphQLString)}, ) ) assert ( str(excinfo.value) == 'Names must match /^[_a-zA-Z][_a-zA-Z0-9]*$/ but "bad-name-with-dashes" does not.' ) def test_rejects_an_object_type_with_incorrectly_typed_fields(self): with raises(AssertionError) as excinfo: schema_with_field_type( GraphQLObjectType( name="SomeObject", fields=[GraphQLField(GraphQLString)] ) ) assert ( str(excinfo.value) == "SomeObject fields must be a mapping (dict / OrderedDict) with field names " "as keys or a function which returns such a mapping." ) def test_rejects_an_object_type_with_empty_fields(self): with raises(AssertionError) as excinfo: schema_with_field_type(GraphQLObjectType(name="SomeObject", fields={})) assert ( str(excinfo.value) == "SomeObject fields must be a mapping (dict / OrderedDict) with field names " "as keys or a function which returns such a mapping." ) def test_rejects_an_object_type_with_a_field_function_that_returns_nothing(self): with raises(AssertionError) as excinfo: schema_with_field_type(GraphQLObjectType(name="SomeObject", fields=_none)) assert ( str(excinfo.value) == "SomeObject fields must be a mapping (dict / OrderedDict) with field names " "as keys or a function which returns such a mapping." ) def test_rejects_an_object_type_with_a_field_function_that_returns_empty(self): with raises(AssertionError) as excinfo: schema_with_field_type( GraphQLObjectType(name="SomeObject", fields=lambda: {}) ) assert ( str(excinfo.value) == "SomeObject fields must be a mapping (dict / OrderedDict) with field names " "as keys or a function which returns such a mapping." ) def test_rejects_an_object_type_with_a_field_with_an_invalid_value(self): with raises(AssertionError) as excinfo: schema_with_field_type( GraphQLObjectType(name="SomeObject", fields={"f": "hello"}) ) assert str(excinfo.value) == "SomeObject.f must be an instance of GraphQLField." def test_rejects_an_object_type_with_a_field_function_with_an_invalid_value(self): with raises(AssertionError) as excinfo: schema_with_field_type( GraphQLObjectType(name="SomeObject", fields=lambda: {"f": "hello"}) ) assert str(excinfo.value) == "SomeObject.f must be an instance of GraphQLField." # noinspection PyMethodMayBeStatic,PyPep8Naming class TestTypeSystem_FieldArgsMustBeProperlyNamed: def test_accepts_field_args_with_valid_names(self): assert schema_with_field_type( GraphQLObjectType( name="SomeObject", fields={ "goodField": GraphQLField( GraphQLString, args={"goodArg": GraphQLArgument(GraphQLString)} ) }, ) ) def test_reject_field_args_with_invalid_names(self): with raises(AssertionError) as excinfo: assert schema_with_field_type( GraphQLObjectType( name="SomeObject", fields={ "badField": GraphQLField( GraphQLString, args={ "bad-name-with-dashes": GraphQLArgument(GraphQLString) }, ) }, ) ) assert ( str(excinfo.value) == 'Names must match /^[_a-zA-Z][_a-zA-Z0-9]*$/ but "bad-name-with-dashes" does not.' ) # noinspection PyMethodMayBeStatic,PyPep8Naming class TestTypeSystem_FieldArgsMustBeObjects: def test_accepts_an_object_with_field_args(self): assert schema_with_field_type( GraphQLObjectType( name="SomeObject", fields={ "goodField": GraphQLField( GraphQLString, args={"goodArg": GraphQLArgument(GraphQLString)} ) }, ) ) def test_rejects_an_object_with_incorrectly_typed_field_args(self): with raises(AssertionError) as excinfo: assert schema_with_field_type( GraphQLObjectType( name="SomeObject", fields={ "badField": GraphQLField( GraphQLString, args=[GraphQLArgument(GraphQLString)] ) }, ) ) assert ( str(excinfo.value) == "SomeObject.badField args must be a mapping (dict / OrderedDict) with argument " "names as keys." ) def test_rejects_an_object_with_incorrectly_typed_field_args_with_an_invalid_value( self, ): with raises(AssertionError) as excinfo: assert schema_with_field_type( GraphQLObjectType( name="SomeObject", fields={ "badField": GraphQLField( GraphQLString, args={"badArg": "I am bad!"} ) }, ) ) assert ( str(excinfo.value) == "SomeObject.badField(badArg:) argument must be an instance of GraphQLArgument." ) # noinspection PyMethodMayBeStatic,PyPep8Naming class TestTypeSystem_ObjectInterfacesMustBeArray: def test_accepts_an_object_type_with_array_interface(self): AnotherInterfaceType = GraphQLInterfaceType( name="AnotherInterface", resolve_type=_none, fields={"f": GraphQLField(GraphQLString)}, ) assert schema_with_field_type( GraphQLObjectType( name="SomeObject", interfaces=[AnotherInterfaceType], fields={"f": GraphQLField(GraphQLString)}, ) ) def test_accepts_an_object_type_with_interfaces_as_a_function_returning_an_array( self, ): AnotherInterfaceType = GraphQLInterfaceType( name="AnotherInterface", resolve_type=_none, fields={"f": GraphQLField(GraphQLString)}, ) assert schema_with_field_type( GraphQLObjectType( name="SomeObject", interfaces=lambda: [AnotherInterfaceType], fields={"f": GraphQLField(GraphQLString)}, ) ) def test_rejects_an_object_type_with_incorrectly_typed_interfaces(self): with raises(AssertionError) as excinfo: schema_with_field_type( GraphQLObjectType( name="SomeObject", interfaces={}, fields={"f": GraphQLField(GraphQLString)}, ) ) assert ( str(excinfo.value) == "SomeObject interfaces must be a list/tuple or a function which returns a " "list/tuple." ) def test_rejects_an_object_type_with_interfaces_as_a_function_returning_an_incorrect_type( self, ): with raises(AssertionError) as excinfo: schema_with_field_type( GraphQLObjectType( name="SomeObject", interfaces=lambda: {}, fields={"f": GraphQLField(GraphQLString)}, ) ) assert ( str(excinfo.value) == "SomeObject interfaces must be a list/tuple or a function which returns a " "list/tuple." ) # noinspection PyMethodMayBeStatic,PyPep8Naming class TestTypeSystem_UnionTypesMustBeArray: def test_accepts_a_union_type_with_aray_types(self): assert schema_with_field_type( GraphQLUnionType( name="SomeUnion", resolve_type=_none, types=[SomeObjectType] ) ) def test_rejects_a_union_without_types(self): with raises(AssertionError) as excinfo: schema_with_field_type( GraphQLUnionType(name="SomeUnion", resolve_type=_none, types=[]) ) assert str(excinfo.value) == "Must provide types for Union SomeUnion." def test_rejects_a_union_type_with_empty_types(self): with raises(AssertionError) as excinfo: schema_with_field_type( GraphQLUnionType(name="SomeUnion", resolve_type=_none, types=[]) ) assert str(excinfo.value) == "Must provide types for Union SomeUnion." def test_rejects_a_union_type_with_incorrectly_typed_types(self): with raises(AssertionError) as excinfo: schema_with_field_type( GraphQLUnionType( name="SomeUnion", resolve_type=_none, types={"SomeObjectType": SomeObjectType}, ) ) assert str(excinfo.value) == "Must provide types for Union SomeUnion." # noinspection PyMethodMayBeStatic,PyPep8Naming class TestTypeSystem_UnionTypesMustBeCallableThatReturnsArray: def test_accepts_a_union_type_with_aray_types(self): assert schema_with_field_type( GraphQLUnionType( name="SomeUnion", resolve_type=_none, types=lambda: [SomeObjectType] ) ) def test_rejects_a_union_type_with_empty_types(self): with raises(AssertionError) as excinfo: schema_with_field_type( GraphQLUnionType(name="SomeUnion", resolve_type=_none, types=lambda: []) ) assert str(excinfo.value) == "Must provide types for Union SomeUnion." def test_rejects_a_union_type_with_incorrectly_typed_types(self): with raises(AssertionError) as excinfo: schema_with_field_type( GraphQLUnionType( name="SomeUnion", resolve_type=_none, types=lambda: {"SomeObjectType": SomeObjectType}, ) ) assert str(excinfo.value) == "Must provide types for Union SomeUnion." def schema_with_input_object(input_object_type): return GraphQLSchema( query=GraphQLObjectType( name="Query", fields={ "f": GraphQLField( GraphQLString, args={"badArg": GraphQLArgument(input_object_type)} ) }, ) ) # noinspection PyMethodMayBeStatic,PyPep8Naming class TestTypeSystem_InputObjectsMustHaveFields: def test_accepts_an_input_object_type_with_fields(self): assert schema_with_input_object( GraphQLInputObjectType( name="SomeInputObject", fields={"f": GraphQLInputObjectField(GraphQLString)}, ) ) def test_accepts_an_input_object_type_with_field_function(self): assert schema_with_input_object( GraphQLInputObjectType( name="SomeInputObject", fields=lambda: {"f": GraphQLInputObjectField(GraphQLString)}, ) ) def test_rejects_an_input_object_type_with_missing_fields(self): with raises(AssertionError) as excinfo: schema_with_input_object( GraphQLInputObjectType(name="SomeInputObject", fields=None) ) assert ( str(excinfo.value) == "SomeInputObject fields must be a mapping (dict / OrderedDict) with " "field names as keys or a function which returns such a mapping." ) def test_rejects_an_input_object_type_with_incorrectly_typed_fields(self): with raises(AssertionError) as excinfo: schema_with_input_object( GraphQLInputObjectType( name="SomeInputObject", fields=[GraphQLInputObjectField(GraphQLString)], ) ) assert ( str(excinfo.value) == "SomeInputObject fields must be a mapping (dict / OrderedDict) with " "field names as keys or a function which returns such a mapping." ) def test_rejects_an_input_object_type_with_incorrectly_typed_field_value(self): with raises(AssertionError) as excinfo: schema_with_input_object( GraphQLInputObjectType( name="SomeInputObject", fields={"f": GraphQLField(GraphQLString)} ) ) assert ( str(excinfo.value) == "SomeInputObject.f must be an instance of GraphQLInputObjectField." ) def test_rejects_an_input_object_type_with_fields_function_returning_incorrectly_typed_field_value( self, ): with raises(AssertionError) as excinfo: schema_with_input_object( GraphQLInputObjectType( name="SomeInputObject", fields=lambda: {"f": GraphQLField(GraphQLString)}, ) ) assert ( str(excinfo.value) == "SomeInputObject.f must be an instance of GraphQLInputObjectField." ) def test_rejects_an_input_object_type_with_empty_fields(self): with raises(AssertionError) as excinfo: schema_with_input_object( GraphQLInputObjectType(name="SomeInputObject", fields={}) ) assert ( str(excinfo.value) == "SomeInputObject fields must be a mapping (dict / OrderedDict) with " "field names as keys or a function which returns such a mapping." ) def test_rejects_an_input_object_type_with_a_field_function_that_returns_nothing( self, ): with raises(AssertionError) as excinfo: schema_with_input_object( GraphQLInputObjectType(name="SomeInputObject", fields=_none) ) assert ( str(excinfo.value) == "SomeInputObject fields must be a mapping (dict / OrderedDict) with " "field names as keys or a function which returns such a mapping." ) def test_rejects_an_input_object_type_with_a_field_function_that_returns_empty( self, ): with raises(AssertionError) as excinfo: schema_with_input_object( GraphQLInputObjectType(name="SomeInputObject", fields=lambda: {}) ) assert ( str(excinfo.value) == "SomeInputObject fields must be a mapping (dict / OrderedDict) with " "field names as keys or a function which returns such a mapping." ) # noinspection PyMethodMayBeStatic,PyPep8Naming class TestTypeSystem_ObjectTypesMustBeAssertable: def test_accepts_an_object_type_with_an_is_type_of_function(self): assert schema_with_field_type( GraphQLObjectType( name="AnotherObject", is_type_of=_true, fields={"f": GraphQLField(GraphQLString)}, ) ) def test_rejects_an_object_type_with_an_incorrect_type_for_is_type_of(self): with raises(AssertionError) as excinfo: schema_with_field_type( GraphQLObjectType( name="AnotherObject", is_type_of={}, fields={"f": GraphQLField(GraphQLString)}, ) ) assert ( str(excinfo.value) == 'AnotherObject must provide "is_type_of" as a function.' ) # noinspection PyMethodMayBeStatic,PyPep8Naming class TestTypeSystem_InterfaceTypesMustBeResolvable: def test_accepts_an_interface_type_defining_resolve_type(self): AnotherInterfaceType = GraphQLInterfaceType( name="AnotherInterface", resolve_type=_none, fields={"f": GraphQLField(GraphQLString)}, ) assert schema_with_field_type( GraphQLObjectType( name="SomeObject", interfaces=[AnotherInterfaceType], fields={"f": GraphQLField(GraphQLString)}, ) ) def test_accepts_an_interface_with_implementing_type_defining_is_type_of(self): AnotherInterfaceType = GraphQLInterfaceType( name="AnotherInterface", fields={"f": GraphQLField(GraphQLString)} ) assert schema_with_field_type( GraphQLObjectType( name="SomeObject", is_type_of=_true, interfaces=[AnotherInterfaceType], fields={"f": GraphQLField(GraphQLString)}, ) ) def test_accepts_an_interface_type_defining_resolve_type_with_implementing_type_defining_is_type_of( self, ): AnotherInterfaceType = GraphQLInterfaceType( name="AnotherInterface", resolve_type=_none, fields={"f": GraphQLField(GraphQLString)}, ) assert schema_with_field_type( GraphQLObjectType( name="SomeObject", is_type_of=_true, interfaces=[AnotherInterfaceType], fields={"f": GraphQLField(GraphQLString)}, ) ) def test_rejects_an_interface_type_with_an_incorrect_type_for_resolve_type(self): with raises(AssertionError) as excinfo: GraphQLInterfaceType( name="AnotherInterface", resolve_type={}, fields={"f": GraphQLField(GraphQLString)}, ) assert ( str(excinfo.value) == 'AnotherInterface must provide "resolve_type" as a function.' ) def test_rejects_an_interface_type_not_defining_resolve_type_with_implementing_type_not_defining_is_type_of( self, ): AnotherInterfaceType = GraphQLInterfaceType( name="AnotherInterface", fields={"f": GraphQLField(GraphQLString)} ) with raises(AssertionError) as excinfo: schema_with_field_type( GraphQLObjectType( name="SomeObject", interfaces=[AnotherInterfaceType], fields={"f": GraphQLField(GraphQLString)}, ) ) assert ( str(excinfo.value) == 'Interface Type AnotherInterface does not provide a "resolve_type" function and ' 'implementing Type SomeObject does not provide a "is_type_of" function. ' "There is no way to resolve this implementing type during execution." ) # noinspection PyMethodMayBeStatic,PyPep8Naming class TestTypeSystem_UnionTypesMustBeResolvable: def test_accepts_a_union_type_defining_resolve_type(self): assert schema_with_field_type( GraphQLUnionType( name="SomeUnion", resolve_type=_none, types=[SomeObjectType] ) ) def test_accepts_a_union_of_object_types_defining_is_type_of(self): assert schema_with_field_type( GraphQLUnionType(name="SomeUnion", types=[ObjectWithIsTypeOf]) ) def test_accepts_a_union_type_defning_resolve_type_of_objects_defning_is_type_of( self, ): assert schema_with_field_type( GraphQLUnionType( name="SomeUnion", resolve_type=_none, types=[ObjectWithIsTypeOf] ) ) def test_rejects_an_interface_type_with_an_incorrect_type_for_resolve_type(self): with raises(AssertionError) as excinfo: schema_with_field_type( GraphQLUnionType( name="SomeUnion", resolve_type={}, types=[ObjectWithIsTypeOf] ) ) assert ( str(excinfo.value) == 'SomeUnion must provide "resolve_type" as a function.' ) def test_rejects_a_union_type_not_defining_resolve_type_of_object_types_not_defining_is_type_of( self, ): with raises(AssertionError) as excinfo: schema_with_field_type( GraphQLUnionType(name="SomeUnion", types=[SomeObjectType]) ) assert ( str(excinfo.value) == 'Union Type SomeUnion does not provide a "resolve_type" function and possible ' 'Type SomeObject does not provide a "is_type_of" function. ' "There is no way to resolve this possible type during execution." ) # noinspection PyMethodMayBeStatic,PyPep8Naming class TestTypeSystem_ScalarTypesMustBeSerializable: def test_accepts_a_scalar_type_defining_serialize(self): assert schema_with_field_type( GraphQLScalarType(name="SomeScalar", serialize=_none) ) def test_rejects_a_scalar_type_not_defining_serialize(self): with raises(AssertionError) as excinfo: schema_with_field_type(GraphQLScalarType(name="SomeScalar")) assert ( str(excinfo.value) == 'SomeScalar must provide "serialize" function. If this custom Scalar is also ' 'used as an input type, ensure "parse_value" and "parse_literal" ' "functions are also provided." ) def test_rejects_a_scalar_type_defining_serialize_with_an_incorrect_type(self): with raises(AssertionError) as excinfo: schema_with_field_type(GraphQLScalarType(name="SomeScalar", serialize={})) assert ( str(excinfo.value) == 'SomeScalar must provide "serialize" function. If this custom Scalar is also ' 'used as an input type, ensure "parse_value" and "parse_literal" ' "functions are also provided." ) def test_accepts_scalar_type_defining_parse_value_and_parse_literal(self): assert schema_with_field_type( GraphQLScalarType( name="SomeScalar", serialize=_none, parse_literal=_none, parse_value=_none, ) ) def test_rejects_a_scalar_type_defining_parse_value_but_not_parse_literal(self): with raises(AssertionError) as excinfo: schema_with_field_type( GraphQLScalarType(name="SomeScalar", serialize=_none, parse_value=_none) ) assert ( str(excinfo.value) == 'SomeScalar must provide both "parse_value" and "parse_literal" functions.' ) def test_rejects_a_scalar_type_defining_parse_literal_but_not_parse_value(self): with raises(AssertionError) as excinfo: schema_with_field_type( GraphQLScalarType( name="SomeScalar", serialize=_none, parse_literal=_none ) ) assert ( str(excinfo.value) == 'SomeScalar must provide both "parse_value" and "parse_literal" functions.' ) def test_rejects_a_scalar_type_defining_parse_literal_and_parse_value_with_an_incorrect_type( self, ): with raises(AssertionError) as excinfo: schema_with_field_type( GraphQLScalarType( name="SomeScalar", serialize=_none, parse_literal={}, parse_value={} ) ) assert ( str(excinfo.value) == 'SomeScalar must provide both "parse_value" and "parse_literal" functions.' ) # noinspection PyMethodMayBeStatic,PyPep8Naming class TestTypeSystem_EnumTypesMustBeWellDefined: def test_accepts_a_well_defined_enum_type_with_empty_value_definition(self): assert GraphQLEnumType( name="SomeEnum", values={"FOO": GraphQLEnumValue(), "BAR": GraphQLEnumValue()}, ) def test_accepts_a_well_defined_enum_type_with_internal_value_definition(self): assert GraphQLEnumType( name="SomeEnum", values={"FOO": GraphQLEnumValue(10), "BAR": GraphQLEnumValue(20)}, ) def test_rejects_an_enum_without_values(self): with raises(AssertionError) as excinfo: GraphQLEnumType(name="SomeEnum", values=None) assert ( str(excinfo.value) == "SomeEnum values must be a mapping (dict / OrderedDict) with value names as keys." ) def test_rejects_an_enum_with_empty_values(self): with raises(AssertionError) as excinfo: GraphQLEnumType(name="SomeEnum", values={}) assert ( str(excinfo.value) == "SomeEnum values must be a mapping (dict / OrderedDict) with value names as keys." ) def test_rejects_an_enum_with_incorrectly_typed_values(self): with raises(AssertionError) as excinfo: GraphQLEnumType(name="SomeEnum", values=[{"foo": GraphQLEnumValue(10)}]) assert ( str(excinfo.value) == "SomeEnum values must be a mapping (dict / OrderedDict) with value names as keys." ) def test_rejects_an_enum_with_missing_value_definition(self): with raises(AssertionError) as excinfo: GraphQLEnumType(name="SomeEnum", values={"FOO": None}) assert ( str(excinfo.value) == "SomeEnum.FOO must be an instance of GraphQLEnumValue, but got: None" ) def test_rejects_an_enum_with_incorrectly_typed_value_definition(self): with raises(AssertionError) as excinfo: GraphQLEnumType(name="SomeEnum", values={"FOO": 10}) assert ( str(excinfo.value) == "SomeEnum.FOO must be an instance of GraphQLEnumValue, but got: 10" ) def schema_with_object_field_of_type(field_type): BadObjectType = GraphQLObjectType( name="BadObject", fields={"badField": GraphQLField(field_type)} ) return schema_with_field_type(BadObjectType) def repr_type_as_syntax_safe_fn(_type): if isinstance(_type, GraphQLList): return "list_" + repr_type_as_syntax_safe_fn(_type.of_type) if isinstance(_type, GraphQLNonNull): return "non_null_" + repr_type_as_syntax_safe_fn(_type.of_type) return re.sub(r"[^a-zA-Z]", "_", str(_type)) + "_" + type(_type).__name__ # noinspection PyMethodMayBeStatic,PyPep8Naming class TestTypeSystem_ObjectFieldsMustHaveOutputTypes: def accepts(self, type): assert schema_with_object_field_of_type(type) for i, type in enumerate(output_types): exec( "def test_accepts_an_output_type_as_an_object_field_type_{}(self): self.accepts(output_types[{}])".format( repr_type_as_syntax_safe_fn(type), i ) ) def test_rejects_an_empty_object_field_type(self): with raises(AssertionError) as excinfo: schema_with_object_field_of_type(None) assert ( str(excinfo.value) == "BadObject.badField field type must be Output Type but got: None." ) def rejects(self, type): with raises(AssertionError) as excinfo: schema_with_object_field_of_type(type) assert str( excinfo.value ) == "BadObject.badField field type must be Output Type but got: {}.".format( type ) for i, type in enumerate(not_output_types): exec( "def test_rejects_a_non_output_type_as_an_object_field_type_{}(self): self.rejects(not_output_types[{}])".format( repr_type_as_syntax_safe_fn(type), i ) ) def schema_with_object_implementing_type(implemented_type): BadObjectType = GraphQLObjectType( name="BadObject", interfaces=[implemented_type], fields={"f": GraphQLField(GraphQLString)}, ) return schema_with_field_type(BadObjectType) not_interface_types = with_modifiers( [SomeScalarType, SomeEnumType, SomeObjectType, SomeUnionType, SomeInputObjectType] ) # noinspection PyMethodMayBeStatic,PyPep8Naming class TestTypeSystem_ObjectsCanOnlyImplementInterfaces: def test_accepts_an_object_implementing_an_interface(self): AnotherInterfaceType = GraphQLInterfaceType( name="AnotherInterface", resolve_type=_none, fields={"f": GraphQLField(GraphQLString)}, ) assert schema_with_object_implementing_type(AnotherInterfaceType) def rejects(self, type): with raises(AssertionError) as excinfo: schema_with_object_implementing_type(type) assert str( excinfo.value ) == "BadObject may only implement Interface types, it cannot implement: {}.".format( type ) for i, type in enumerate(not_interface_types): exec( "def test_rejects_an_object_implementing_a_non_interface_type_{}(self):" " self.rejects(not_interface_types[{}])".format( repr_type_as_syntax_safe_fn(type), i ) ) not_object_types = with_modifiers( [ SomeScalarType, SomeEnumType, SomeInterfaceType, SomeUnionType, SomeInputObjectType, ] ) def schema_with_union_of_type(type): BadUnionType = GraphQLUnionType(name="BadUnion", resolve_type=_none, types=[type]) return schema_with_field_type(BadUnionType) # noinspection PyMethodMayBeStatic,PyPep8Naming class TestTypeSystem_UnionMustRepresentObjectTypes: def test_accepts_a_union_of_an_object_type(self): assert schema_with_union_of_type(SomeObjectType) def rejects(self, type): with raises(AssertionError) as excinfo: schema_with_union_of_type(type) assert str( excinfo.value ) == "BadUnion may only contain Object types, it cannot contain: {}.".format( type ) for i, type in enumerate(not_object_types): exec( "def test_rejects_a_union_of_non_object_type_{}(self):" " self.rejects(not_object_types[{}])".format( repr_type_as_syntax_safe_fn(type), i ) ) def schema_with_interface_field_of_type(field_type): BadInterfaceType = GraphQLInterfaceType( name="BadInterface", fields={"badField": GraphQLField(field_type)} ) return schema_with_field_type(BadInterfaceType) # noinspection PyMethodMayBeStatic,PyPep8Naming class TestTypeSystem_InterfaceFieldsMustHaveOutputTypes: def accepts(self, type): assert schema_with_interface_field_of_type(type) def rejects(self, type): with raises(AssertionError) as excinfo: schema_with_interface_field_of_type(type) assert str( excinfo.value ) == "BadInterface.badField field type must be Output Type but got: {}.".format( type ) for i, type in enumerate(output_types): exec( "def test_accepts_an_output_type_as_an_interface_field_type_{}(self):" " self.accepts(output_types[{}])".format( repr_type_as_syntax_safe_fn(type), i ) ) def test_rejects_an_empty_interface_field_type(self): self.rejects(None) for i, type in enumerate(not_output_types): exec( "def test_rejects_a_non_output_type_as_an_interface_field_type_{}(self):" " self.rejects(not_output_types[{}])".format( repr_type_as_syntax_safe_fn(type), i ) ) # noinspection PyMethodMayBeStatic,PyPep8Naming def schema_with_arg_of_type(arg_type): BadObjectType = GraphQLObjectType( name="BadObject", fields={ "badField": GraphQLField( type_=GraphQLString, args={"badArg": GraphQLArgument(arg_type)} ) }, ) return schema_with_field_type(BadObjectType) # noinspection PyMethodMayBeStatic,PyPep8Naming class TestTypeSystem_FieldArgumentsMustHaveInputTypes: def accepts(self, type): assert schema_with_arg_of_type(type) def rejects(self, type): with raises(AssertionError) as excinfo: schema_with_arg_of_type(type) assert str( excinfo.value ) == "BadObject.badField(badArg:) argument type must be Input " "Type but got: {}.".format( type ) for i, type in enumerate(input_types): exec( "def test_accepts_an_input_type_as_a_field_arg_type_{}(self):" " self.accepts(input_types[{}])".format( repr_type_as_syntax_safe_fn(type), i ) ) def test_rejects_an_empty_field_arg_type(self): self.rejects(None) for i, type in enumerate(not_input_types): exec( "def test_rejects_a_not_input_type_as_a_field_arg_type_{}(self):" " self.rejects(not_input_types[{}])".format( repr_type_as_syntax_safe_fn(type), i ) ) def schema_with_input_field_of_type(input_field_type): BadInputObjectType = GraphQLInputObjectType( name="BadInputObject", fields={"badField": GraphQLInputObjectField(input_field_type)}, ) return GraphQLSchema( query=GraphQLObjectType( name="Query", fields={ "f": GraphQLField( type_=GraphQLString, args={"badArg": GraphQLArgument(BadInputObjectType)}, ) }, ) ) # noinspection PyMethodMayBeStatic,PyPep8Naming class TestTypeSystem_InputObjectFieldsMustHaveInputTypes: def accepts(self, type): assert schema_with_input_field_of_type(type) def rejects(self, type): with raises(AssertionError) as excinfo: schema_with_input_field_of_type(type) assert str( excinfo.value ) == "BadInputObject.badField field type must be Input Type but got: {}.".format( type ) for i, type in enumerate(input_types): exec( "def test_accepts_an_input_type_as_an_input_field_type_{}(self):" " self.accepts(input_types[{}])".format( repr_type_as_syntax_safe_fn(type), i ) ) def test_rejects_an_empty_input_field_type(self): self.rejects(None) for i, type in enumerate(not_input_types): exec( "def test_rejects_non_input_type_as_an_input_field_type_{}(self):" " self.rejects(not_input_types[{}])".format( repr_type_as_syntax_safe_fn(type), i ) ) types = with_modifiers( [ GraphQLString, SomeScalarType, SomeObjectType, SomeUnionType, SomeInterfaceType, SomeEnumType, SomeInputObjectType, ] ) not_types = [{}, str, None, object(), set(), (), []] class TestTypeSystem_ListMustAcceptGraphQLTypes: def accepts(self, type): assert GraphQLList(type) def rejects(self, type): with raises(AssertionError) as excinfo: GraphQLList(type) assert str( excinfo.value ) == "Can only create List of a GraphQLType but got: {}.".format(type) for i, type in enumerate(types): exec( "def test_accepts_a_type_as_item_type_of_list_{}(self):" " self.accepts(types[{}])".format(repr_type_as_syntax_safe_fn(type), i) ) for i, type in enumerate(not_types): exec( "def test_accepts_a_type_as_item_type_of_list_{}(self):" " self.rejects(not_types[{}])".format(repr_type_as_syntax_safe_fn(type), i) ) nullable_types = [ GraphQLString, SomeScalarType, SomeObjectType, SomeUnionType, SomeInterfaceType, SomeEnumType, SomeInputObjectType, GraphQLList(GraphQLString), GraphQLList(GraphQLNonNull(GraphQLString)), ] not_nullable_types = [GraphQLNonNull(GraphQLString), {}, str, None, []] # noinspection PyMethodMayBeStatic,PyPep8Naming class TestTypeSystem_NonNullMustAcceptGraphQLTypes: def accepts(self, type): assert GraphQLNonNull(type) def rejects(self, type): with raises(AssertionError) as excinfo: GraphQLNonNull(type) assert str( excinfo.value ) == "Can only create NonNull of a Nullable GraphQLType but got: {}.".format( type ) for i, type in enumerate(nullable_types): exec( "def test_accepts_a_type_as_nullable_type_of_not_null_{}(self):" " self.accepts(nullable_types[{}])".format( repr_type_as_syntax_safe_fn(type), i ) ) for i, type in enumerate(not_nullable_types): exec( "def test_rejects_a_non_type_as_nullable_type_of_non_null_{}(self):" " self.rejects(not_nullable_types[{}])".format( repr_type_as_syntax_safe_fn(type), i ) ) # noinspection PyMethodMayBeStatic,PyPep8Naming class TestTypeSystem_ObjectsMustAdhereToInterfacesTheyImplement: def test_accepts_an_object_which_implements_an_interface(self): AnotherInterface = GraphQLInterfaceType( name="AnotherInterface", resolve_type=_none, fields={ "field": GraphQLField( type_=GraphQLString, args={"input": GraphQLArgument(GraphQLString)} ) }, ) AnotherObject = GraphQLObjectType( name="AnotherObject", interfaces=[AnotherInterface], fields={ "field": GraphQLField( type_=GraphQLString, args={"input": GraphQLArgument(GraphQLString)} ) }, ) assert schema_with_field_type(AnotherObject) def test_accepts_an_object_which_implements_an_interface_along_with_more_fields( self, ): AnotherInterface = GraphQLInterfaceType( name="AnotherInterface", resolve_type=_none, fields={ "field": GraphQLField( type_=GraphQLString, args={"input": GraphQLArgument(GraphQLString)} ) }, ) AnotherObject = GraphQLObjectType( name="AnotherObject", interfaces=[AnotherInterface], fields={ "field": GraphQLField( type_=GraphQLString, args={"input": GraphQLArgument(GraphQLString)} ), "anotherfield": GraphQLField(GraphQLString), }, ) assert schema_with_field_type(AnotherObject) def test_accepts_an_object_which_implements_an_interface_field_along_with_more_arguments( self, ): AnotherInterface = GraphQLInterfaceType( name="AnotherInterface", resolve_type=_none, fields={ "field": GraphQLField( type_=GraphQLString, args={"input": GraphQLArgument(GraphQLString)} ) }, ) AnotherObject = GraphQLObjectType( name="AnotherObject", interfaces=[AnotherInterface], fields={ "field": GraphQLField( type_=GraphQLString, args={ "input": GraphQLArgument(GraphQLString), "anotherInput": GraphQLArgument(GraphQLString), }, ) }, ) assert schema_with_field_type(AnotherObject) def test_rejects_an_object_which_implements_an_interface_field_along_with_additional_required_arguments( self, ): AnotherInterface = GraphQLInterfaceType( name="AnotherInterface", resolve_type=_none, fields={ "field": GraphQLField( type_=GraphQLString, args={"input": GraphQLArgument(GraphQLString)} ) }, ) AnotherObject = GraphQLObjectType( name="AnotherObject", interfaces=[AnotherInterface], fields={ "field": GraphQLField( type_=GraphQLString, args={ "input": GraphQLArgument(GraphQLString), "anotherInput": GraphQLArgument(GraphQLNonNull(GraphQLString)), }, ) }, ) with raises(AssertionError) as excinfo: schema_with_field_type(AnotherObject) assert ( str(excinfo.value) == 'AnotherObject.field(anotherInput:) is of required type "String!" but ' "is not also provided by the interface AnotherInterface.field." ) def test_rejects_an_object_missing_an_interface_field(self): AnotherInterface = GraphQLInterfaceType( name="AnotherInterface", resolve_type=_none, fields={ "field": GraphQLField( type_=GraphQLString, args={"input": GraphQLArgument(GraphQLString)} ) }, ) AnotherObject = GraphQLObjectType( name="AnotherObject", interfaces=[AnotherInterface], fields={"anotherfield": GraphQLField(GraphQLString)}, ) with raises(AssertionError) as excinfo: schema_with_field_type(AnotherObject) assert ( str(excinfo.value) == '"AnotherInterface" expects field "field" but "AnotherObject" does not provide it.' ) def test_rejects_an_object_with_an_incorrectly_typed_interface_field(self): AnotherInterface = GraphQLInterfaceType( name="AnotherInterface", resolve_type=_none, fields={"field": GraphQLField(GraphQLString)}, ) AnotherObject = GraphQLObjectType( name="AnotherObject", interfaces=[AnotherInterface], fields={"field": GraphQLField(SomeScalarType)}, ) with raises(AssertionError) as excinfo: schema_with_field_type(AnotherObject) assert ( str(excinfo.value) == 'AnotherInterface.field expects type "String" ' 'but AnotherObject.field provides type "SomeScalar".' ) def test_rejects_an_object_missing_an_interface_argument(self): AnotherInterface = GraphQLInterfaceType( name="AnotherInterface", resolve_type=_none, fields={ "field": GraphQLField( GraphQLString, args={"input": GraphQLArgument(GraphQLString)} ) }, ) AnotherObject = GraphQLObjectType( name="AnotherObject", interfaces=[AnotherInterface], fields={"field": GraphQLField(GraphQLString)}, ) with raises(AssertionError) as excinfo: schema_with_field_type(AnotherObject) assert ( str(excinfo.value) == 'AnotherInterface.field expects argument "input" ' "but AnotherObject.field does not provide it." ) def test_rejects_an_object_with_an_incorrectly_typed_interface_argument(self): AnotherInterface = GraphQLInterfaceType( name="AnotherInterface", resolve_type=_none, fields={ "field": GraphQLField( GraphQLString, args={"input": GraphQLArgument(GraphQLString)} ) }, ) AnotherObject = GraphQLObjectType( name="AnotherObject", interfaces=[AnotherInterface], fields={ "field": GraphQLField( GraphQLString, args={"input": GraphQLArgument(SomeScalarType)} ) }, ) with raises(AssertionError) as excinfo: schema_with_field_type(AnotherObject) assert ( str(excinfo.value) == 'AnotherInterface.field(input:) expects type "String" ' 'but AnotherObject.field(input:) provides type "SomeScalar".' ) def test_rejects_an_object_with_an_incorrectly_typed_interface_field(self): AnotherInterface = GraphQLInterfaceType( name="AnotherInterface", resolve_type=_none, fields={"field": GraphQLField(GraphQLString)}, ) AnotherObject = GraphQLObjectType( name="AnotherObject", interfaces=[AnotherInterface], fields={"field": GraphQLField(SomeScalarType)}, ) with raises(AssertionError) as excinfo: schema_with_field_type(AnotherObject) assert ( str(excinfo.value) == 'AnotherInterface.field expects type "String" ' 'but AnotherObject.field provides type "SomeScalar".' ) def test_rejects_an_object_with_a_differently_typed_Interface_field(self): TypeA = GraphQLObjectType(name="A", fields={"foo": GraphQLField(GraphQLString)}) TypeB = GraphQLObjectType(name="B", fields={"foo": GraphQLField(GraphQLString)}) AnotherInterface = GraphQLInterfaceType( name="AnotherInterface", resolve_type=_none, fields={"field": GraphQLField(TypeA)}, ) AnotherObject = GraphQLObjectType( name="AnotherObject", interfaces=[AnotherInterface], fields={"field": GraphQLField(TypeB)}, ) with raises(AssertionError) as excinfo: schema_with_field_type(AnotherObject) assert ( str(excinfo.value) == 'AnotherInterface.field expects type "A" but ' 'AnotherObject.field provides type "B".' ) def test_accepts_an_object_with_a_subtyped_interface_field_interface(self): AnotherInterface = GraphQLInterfaceType( name="AnotherInterface", resolve_type=_none, fields=lambda: {"field": GraphQLField(AnotherInterface)}, ) AnotherObject = GraphQLObjectType( name="AnotherObject", interfaces=[AnotherInterface], fields=lambda: {"field": GraphQLField(AnotherObject)}, ) assert schema_with_field_type(AnotherObject) def test_accepts_an_object_with_a_subtyped_interface_field_union(self): AnotherInterface = GraphQLInterfaceType( name="AnotherInterface", resolve_type=_none, fields=lambda: {"field": GraphQLField(SomeUnionType)}, ) AnotherObject = GraphQLObjectType( name="AnotherObject", interfaces=[AnotherInterface], fields=lambda: {"field": GraphQLField(SomeObjectType)}, ) assert schema_with_field_type(AnotherObject) def test_accepts_an_object_with_an_equivalently_modified_interface_field_type(self): AnotherInterface = GraphQLInterfaceType( name="AnotherInterface", resolve_type=_none, fields={"field": GraphQLField(GraphQLNonNull(GraphQLList(GraphQLString)))}, ) AnotherObject = GraphQLObjectType( name="AnotherObject", interfaces=[AnotherInterface], fields={"field": GraphQLField(GraphQLNonNull(GraphQLList(GraphQLString)))}, ) assert schema_with_field_type(AnotherObject) def test_rejects_an_object_with_a_non_list_interface_field_list_type(self): AnotherInterface = GraphQLInterfaceType( name="AnotherInterface", resolve_type=_none, fields={"field": GraphQLField(GraphQLList(GraphQLString))}, ) AnotherObject = GraphQLObjectType( name="AnotherObject", interfaces=[AnotherInterface], fields={"field": GraphQLField(GraphQLString)}, ) with raises(AssertionError) as excinfo: schema_with_field_type(AnotherObject) assert ( str(excinfo.value) == 'AnotherInterface.field expects type "[String]" ' 'but AnotherObject.field provides type "String".' ) def test_rejects_a_object_with_a_list_interface_field_non_list_type(self): AnotherInterface = GraphQLInterfaceType( name="AnotherInterface", resolve_type=_none, fields={"field": GraphQLField(GraphQLString)}, ) AnotherObject = GraphQLObjectType( name="AnotherObject", interfaces=[AnotherInterface], fields={"field": GraphQLField(GraphQLList(GraphQLString))}, ) with raises(AssertionError) as excinfo: schema_with_field_type(AnotherObject) assert ( str(excinfo.value) == 'AnotherInterface.field expects type "String" ' 'but AnotherObject.field provides type "[String]".' ) def test_accepts_an_object_with_a_subset_non_null_interface_field_type(self): AnotherInterface = GraphQLInterfaceType( name="AnotherInterface", resolve_type=_none, fields={"field": GraphQLField(GraphQLString)}, ) AnotherObject = GraphQLObjectType( name="AnotherObject", interfaces=[AnotherInterface], fields={"field": GraphQLField(GraphQLNonNull(GraphQLString))}, ) assert schema_with_field_type(AnotherObject) def test_rejects_a_object_with_a_superset_nullable_interface_field_type(self): AnotherInterface = GraphQLInterfaceType( name="AnotherInterface", resolve_type=_none, fields={"field": GraphQLField(GraphQLNonNull(GraphQLString))}, ) AnotherObject = GraphQLObjectType( name="AnotherObject", interfaces=[AnotherInterface], fields={"field": GraphQLField(GraphQLString)}, ) with raises(AssertionError) as excinfo: schema_with_field_type(AnotherObject) assert ( str(excinfo.value) == 'AnotherInterface.field expects type "String!" but ' 'AnotherObject.field provides type "String".' ) graphql-core-legacy-2.3.2/graphql/type/typemap.py000066400000000000000000000200461365661746200220360ustar00rootroot00000000000000from collections import OrderedDict, defaultdict from functools import reduce from typing import cast from ..utils.type_comparators import is_equal_type, is_type_sub_type_of from .definition import ( GraphQLArgument, GraphQLInputObjectField, GraphQLInputObjectType, GraphQLInterfaceType, GraphQLList, GraphQLNonNull, GraphQLObjectType, GraphQLUnionType, is_input_type, is_output_type, ) # Necessary for static type checking if False: # flake8: noqa from ..type.definition import GraphQLNamedType from ..type.schema import GraphQLSchema from typing import List, Union, Dict, Set, DefaultDict class GraphQLTypeMap(OrderedDict): def __init__(self, types): # type: (List[GraphQLNamedType]) -> None super(GraphQLTypeMap, self).__init__() self.update(reduce(self.reducer, types, OrderedDict())) # type: ignore self._possible_type_map = defaultdict(set) # type: DefaultDict[str, Set[str]] # Keep track of all implementations by interface name. self._implementations = defaultdict( list ) # type: DefaultDict[str, List[GraphQLObjectType]] for gql_type in self.values(): if isinstance(gql_type, GraphQLObjectType): for interface in gql_type.interfaces: self._implementations[interface.name].append(gql_type) # Enforce correct interface implementations. for type_ in self.values(): if isinstance(type_, GraphQLObjectType): for interface in type_.interfaces: self.assert_object_implements_interface(self, type_, interface) def get_possible_types(self, abstract_type): # type: (Union[GraphQLInterfaceType, GraphQLUnionType]) -> List[GraphQLObjectType] if isinstance(abstract_type, GraphQLUnionType): return abstract_type.types assert isinstance(abstract_type, GraphQLInterfaceType) if abstract_type.name not in self._implementations: return [] return self._implementations[abstract_type.name] def is_possible_type( self, abstract_type, # type: Union[GraphQLInterfaceType, GraphQLUnionType] possible_type, # type: GraphQLObjectType ): # type: (...) -> bool possible_types = self.get_possible_types(abstract_type) assert possible_types, ( "Could not find possible implementing types for {} in " + "schema. Check that schema.types is defined and is an array of" + "all possible types in the schema." ).format(abstract_type) if abstract_type.name not in self._possible_type_map: self._possible_type_map[abstract_type.name].update( [p.name for p in possible_types] ) return possible_type.name in self._possible_type_map[abstract_type.name] @classmethod def reducer(cls, map_, type_): # type: (Dict, Union[GraphQLNamedType, GraphQLList, GraphQLNonNull]) -> Dict if not type_: return map_ if isinstance(type_, (GraphQLList, GraphQLNonNull)): return cls.reducer(map_, type_.of_type) if type_.name in map_: assert map_[type_.name] == type_, ( 'Schema must contain unique named types but contains multiple types named "{}".' ).format(type_.name) return map_ map_[type_.name] = type_ # type: ignore reduced_map = map_ if isinstance(type_, GraphQLUnionType): for t in type_.types: reduced_map = cls.reducer(reduced_map, t) if isinstance(type_, GraphQLObjectType): for t in type_.interfaces: reduced_map = cls.reducer(reduced_map, t) if isinstance( type_, (GraphQLObjectType, GraphQLInterfaceType, GraphQLInputObjectType) ): field_map = type_.fields type_is_input = isinstance(type_, GraphQLInputObjectType) for field_name, field in field_map.items(): if type_is_input: assert isinstance( field, GraphQLInputObjectField ), "{}.{} must be an instance of GraphQLInputObjectField.".format( type_, field_name ) assert is_input_type( field.type ), "{}.{} field type must be Input Type but got: {}.".format( type_, field_name, field.type ) else: assert is_output_type( field.type ), "{}.{} field type must be Output Type but got: {}.".format( type_, field_name, field.type ) for arg_name, arg in field.args.items(): assert isinstance( arg, (GraphQLArgument, GraphQLArgument) ), "{}.{}({}:) argument must be an instance of GraphQLArgument.".format( type_, field_name, arg_name ) assert is_input_type( arg.type ), "{}.{}({}:) argument type must be Input Type but got: {}.".format( type_, field_name, arg_name, arg.type ) reduced_map = cls.reducer(reduced_map, arg.type) reduced_map = cls.reducer(reduced_map, getattr(field, "type", None)) return reduced_map @classmethod def assert_object_implements_interface( cls, schema, # type: Union[GraphQLTypeMap, GraphQLSchema] object, # type: GraphQLObjectType interface, # type: GraphQLInterfaceType ): # type: (...) -> None object_field_map = object.fields interface_field_map = interface.fields for field_name, interface_field in interface_field_map.items(): object_field = object_field_map.get(field_name) assert ( object_field ), '"{}" expects field "{}" but "{}" does not provide it.'.format( interface, field_name, object ) assert is_type_sub_type_of( cast("GraphQLSchema", schema), object_field.type, interface_field.type ), '{}.{} expects type "{}" but {}.{} provides type "{}".'.format( interface, field_name, interface_field.type, object, field_name, object_field.type, ) for arg_name, interface_arg in interface_field.args.items(): object_arg = object_field.args.get(arg_name) assert object_arg, ( '{}.{} expects argument "{}" but {}.{} does not provide it.' ).format(interface, field_name, arg_name, object, field_name) assert is_equal_type(interface_arg.type, object_arg.type), ( '{}.{}({}:) expects type "{}" but {}.{}({}:) provides type "{}".' ).format( interface, field_name, arg_name, interface_arg.type, object, field_name, arg_name, object_arg.type, ) for arg_name, object_arg in object_field.args.items(): interface_arg = interface_field.args.get(arg_name) if not interface_arg: assert not isinstance(object_arg.type, GraphQLNonNull), ( "{}.{}({}:) is of required type " '"{}" but is not also provided by the ' "interface {}.{}." ).format( object, field_name, arg_name, object_arg.type, interface, field_name, ) graphql-core-legacy-2.3.2/graphql/utils/000077500000000000000000000000001365661746200201625ustar00rootroot00000000000000graphql-core-legacy-2.3.2/graphql/utils/__init__.py000066400000000000000000000000001365661746200222610ustar00rootroot00000000000000graphql-core-legacy-2.3.2/graphql/utils/assert_valid_name.py000066400000000000000000000005541365661746200242200ustar00rootroot00000000000000import re NAME_PATTERN = r"^[_a-zA-Z][_a-zA-Z0-9]*$" COMPILED_NAME_PATTERN = re.compile(NAME_PATTERN) def assert_valid_name(name): # type: (str) -> None """Helper to assert that provided names are valid.""" assert COMPILED_NAME_PATTERN.match( name ), 'Names must match /{}/ but "{}" does not.'.format(NAME_PATTERN, name) return None graphql-core-legacy-2.3.2/graphql/utils/ast_from_value.py000066400000000000000000000037341365661746200235510ustar00rootroot00000000000000import json import sys from six import string_types from ..language import ast from ..type.definition import ( GraphQLEnumType, GraphQLInputObjectType, GraphQLList, GraphQLNonNull, ) from ..type.scalars import GraphQLFloat from .assert_valid_name import COMPILED_NAME_PATTERN def ast_from_value(value, type=None): if isinstance(type, GraphQLNonNull): return ast_from_value(value, type.of_type) if value is None: return None if isinstance(value, list): item_type = type.of_type if isinstance(type, GraphQLList) else None return ast.ListValue([ast_from_value(item, item_type) for item in value]) elif isinstance(type, GraphQLList): return ast_from_value(value, type.of_type) if isinstance(value, bool): return ast.BooleanValue(value) if isinstance(value, (int, float)): string_num = str(value) int_value = int(value) is_int_value = string_num.isdigit() if is_int_value or (int_value == value and value < sys.maxsize): if type == GraphQLFloat: return ast.FloatValue(str(float(value))) return ast.IntValue(str(int(value))) return ast.FloatValue(string_num) if isinstance(value, string_types): if isinstance(type, GraphQLEnumType) and COMPILED_NAME_PATTERN.match(value): return ast.EnumValue(value) return ast.StringValue(json.dumps(value)[1:-1]) assert isinstance(value, dict) fields = [] is_graph_ql_input_object_type = isinstance(type, GraphQLInputObjectType) for field_name, field_value in value.items(): field_type = None if is_graph_ql_input_object_type: field_def = type.fields.get(field_name) field_type = field_def and field_def.type field_value = ast_from_value(field_value, field_type) if field_value: fields.append(ast.ObjectField(ast.Name(field_name), field_value)) return ast.ObjectValue(fields) graphql-core-legacy-2.3.2/graphql/utils/ast_to_code.py000066400000000000000000000024301365661746200230160ustar00rootroot00000000000000from ..language.ast import Node from ..language.parser import Loc # Necessary for static type checking if False: # flake8: noqa from typing import Any def ast_to_code(ast, indent=0): # type: (Any, int) -> str """ Converts an ast into a python code representation of the AST. """ code = [] def append(line): # type: (str) -> None code.append((" " * indent) + line) if isinstance(ast, Node): append("ast.{}(".format(ast.__class__.__name__)) indent += 1 for i, k in enumerate(ast._fields, 1): v = getattr(ast, k) append("{}={},".format(k, ast_to_code(v, indent))) if ast.loc: append("loc={}".format(ast_to_code(ast.loc, indent))) indent -= 1 append(")") elif isinstance(ast, Loc): append("loc({}, {})".format(ast.start, ast.end)) elif isinstance(ast, list): if ast: append("[") indent += 1 for i, it in enumerate(ast, 1): is_last = i == len(ast) append(ast_to_code(it, indent) + ("," if not is_last else "")) indent -= 1 append("]") else: append("[]") else: append(repr(ast)) return "\n".join(code).strip() graphql-core-legacy-2.3.2/graphql/utils/ast_to_dict.py000066400000000000000000000010721365661746200230300ustar00rootroot00000000000000from ..language.ast import Node def ast_to_dict(node, include_loc=False): if isinstance(node, Node): d = {"kind": node.__class__.__name__} if hasattr(node, "_fields"): for field in node._fields: d[field] = ast_to_dict(getattr(node, field), include_loc) if include_loc and hasattr(node, "loc") and node.loc: d["loc"] = {"start": node.loc.start, "end": node.loc.end} return d elif isinstance(node, list): return [ast_to_dict(item, include_loc) for item in node] return node graphql-core-legacy-2.3.2/graphql/utils/base.py000066400000000000000000000041761365661746200214560ustar00rootroot00000000000000""" Base GraphQL utilities isort:skip_file """ # The GraphQL query recommended for a full schema introspection. from .introspection_query import introspection_query # Gets the target Operation from a Document from .get_operation_ast import get_operation_ast # Build a GraphQLSchema from an introspection result. from .build_client_schema import build_client_schema # Build a GraphQLSchema from a parsed GraphQL Schema language AST. from .build_ast_schema import build_ast_schema # Extends an existing GraphQLSchema from a parsed GraphQL Schema language AST. from .extend_schema import extend_schema # Print a GraphQLSchema to GraphQL Schema language. from .schema_printer import print_schema, print_introspection_schema # Create a GraphQLType from a GraphQL language AST. from .type_from_ast import type_from_ast # Create a JavaScript value from a GraphQL language AST. from .value_from_ast import value_from_ast # Create a GraphQL language AST from a JavaScript 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 # Determine if JavaScript values adhere to a GraphQL type. from .is_valid_value import is_valid_value # Determine if AST values adhere to a GraphQL type. from .is_valid_literal_value import is_valid_literal_value # Concatenates multiple AST together. from .concat_ast import concat_ast # Comparators for types from .type_comparators import is_equal_type, is_type_sub_type_of, do_types_overlap # Asserts that a string is a valid GraphQL name from .assert_valid_name import assert_valid_name # Undefined const from .undefined import Undefined __all__ = [ "introspection_query", "get_operation_ast", "build_client_schema", "build_ast_schema", "extend_schema", "print_introspection_schema", "print_schema", "type_from_ast", "value_from_ast", "ast_from_value", "TypeInfo", "is_valid_value", "is_valid_literal_value", "concat_ast", "do_types_overlap", "is_equal_type", "is_type_sub_type_of", "assert_valid_name", "Undefined", ] graphql-core-legacy-2.3.2/graphql/utils/build_ast_schema.py000066400000000000000000000255001365661746200240240ustar00rootroot00000000000000from ..execution.values import get_argument_values from ..language import ast from ..pyutils.ordereddict import OrderedDict from ..type import ( GraphQLArgument, GraphQLBoolean, GraphQLDeprecatedDirective, GraphQLDirective, GraphQLEnumType, GraphQLEnumValue, GraphQLField, GraphQLFloat, GraphQLID, GraphQLIncludeDirective, GraphQLInputObjectField, GraphQLInputObjectType, GraphQLInt, GraphQLInterfaceType, GraphQLList, GraphQLNonNull, GraphQLObjectType, GraphQLScalarType, GraphQLSchema, GraphQLSkipDirective, GraphQLString, GraphQLUnionType, ) from ..type.introspection import ( __Directive, __DirectiveLocation, __EnumValue, __Field, __InputValue, __Schema, __Type, __TypeKind, ) from ..utils.value_from_ast import value_from_ast def _build_wrapped_type(inner_type, input_type_ast): if isinstance(input_type_ast, ast.ListType): return GraphQLList(_build_wrapped_type(inner_type, input_type_ast.type)) if isinstance(input_type_ast, ast.NonNullType): return GraphQLNonNull(_build_wrapped_type(inner_type, input_type_ast.type)) return inner_type def _get_inner_type_name(type_ast): if isinstance(type_ast, (ast.ListType, ast.NonNullType)): return _get_inner_type_name(type_ast.type) return type_ast.name.value def _get_named_type_ast(type_ast): named_type = type_ast while isinstance(named_type, (ast.ListType, ast.NonNullType)): named_type = named_type.type return named_type def _false(*_): return False def _none(*_): return None def build_ast_schema(document): assert isinstance(document, ast.Document), "must pass in Document ast." schema_def = None type_asts = ( ast.ScalarTypeDefinition, ast.ObjectTypeDefinition, ast.InterfaceTypeDefinition, ast.EnumTypeDefinition, ast.UnionTypeDefinition, ast.InputObjectTypeDefinition, ) type_defs = [] directive_defs = [] for d in document.definitions: if isinstance(d, ast.SchemaDefinition): if schema_def: raise Exception("Must provide only one schema definition.") schema_def = d if isinstance(d, type_asts): type_defs.append(d) elif isinstance(d, ast.DirectiveDefinition): directive_defs.append(d) if not schema_def: raise Exception("Must provide a schema definition.") query_type_name = None mutation_type_name = None subscription_type_name = None for operation_type in schema_def.operation_types: type_name = operation_type.type.name.value if operation_type.operation == "query": if query_type_name: raise Exception("Must provide only one query type in schema.") query_type_name = type_name elif operation_type.operation == "mutation": if mutation_type_name: raise Exception("Must provide only one mutation type in schema.") mutation_type_name = type_name elif operation_type.operation == "subscription": if subscription_type_name: raise Exception("Must provide only one subscription type in schema.") subscription_type_name = type_name if not query_type_name: raise Exception("Must provide schema definition with query type.") ast_map = {d.name.value: d for d in type_defs} if query_type_name not in ast_map: raise Exception( 'Specified query type "{}" not found in document.'.format(query_type_name) ) if mutation_type_name and mutation_type_name not in ast_map: raise Exception( 'Specified mutation type "{}" not found in document.'.format( mutation_type_name ) ) if subscription_type_name and subscription_type_name not in ast_map: raise Exception( 'Specified subscription type "{}" not found in document.'.format( subscription_type_name ) ) inner_type_map = OrderedDict( [ ("String", GraphQLString), ("Int", GraphQLInt), ("Float", GraphQLFloat), ("Boolean", GraphQLBoolean), ("ID", GraphQLID), ("__Schema", __Schema), ("__Directive", __Directive), ("__DirectiveLocation", __DirectiveLocation), ("__Type", __Type), ("__Field", __Field), ("__InputValue", __InputValue), ("__EnumValue", __EnumValue), ("__TypeKind", __TypeKind), ] ) def get_directive(directive_ast): return GraphQLDirective( name=directive_ast.name.value, locations=[node.value for node in directive_ast.locations], args=make_input_values(directive_ast.arguments, GraphQLArgument), ) def get_object_type(type_ast): type = type_def_named(type_ast.name.value) assert isinstance(type, GraphQLObjectType), "AST must provide object type" return type def produce_type_def(type_ast): type_name = _get_named_type_ast(type_ast).name.value type_def = type_def_named(type_name) return _build_wrapped_type(type_def, type_ast) def type_def_named(type_name): if type_name in inner_type_map: return inner_type_map[type_name] if type_name not in ast_map: raise Exception('Type "{}" not found in document'.format(type_name)) inner_type_def = make_schema_def(ast_map[type_name]) if not inner_type_def: raise Exception('Nothing constructed for "{}".'.format(type_name)) inner_type_map[type_name] = inner_type_def return inner_type_def def make_schema_def(definition): if not definition: raise Exception("def must be defined.") handler = _schema_def_handlers.get(type(definition)) if not handler: raise Exception( 'Type kind "{}" not supported.'.format(type(definition).__name__) ) return handler(definition) def make_type_def(definition): return GraphQLObjectType( name=definition.name.value, fields=lambda: make_field_def_map(definition), interfaces=make_implemented_interfaces(definition), ) def make_field_def_map(definition): return OrderedDict( ( f.name.value, GraphQLField( type_=produce_type_def(f.type), args=make_input_values(f.arguments, GraphQLArgument), deprecation_reason=get_deprecation_reason(f.directives), ), ) for f in definition.fields ) def make_implemented_interfaces(definition): return [produce_type_def(i) for i in definition.interfaces] def make_input_values(values, cls): return OrderedDict( ( value.name.value, cls( type_=produce_type_def(value.type), default_value=value_from_ast( value.default_value, produce_type_def(value.type) ), ), ) for value in values ) def make_interface_def(definition): return GraphQLInterfaceType( name=definition.name.value, resolve_type=_none, fields=lambda: make_field_def_map(definition), ) def make_enum_def(definition): values = OrderedDict( ( v.name.value, GraphQLEnumValue( deprecation_reason=get_deprecation_reason(v.directives) ), ) for v in definition.values ) return GraphQLEnumType(name=definition.name.value, values=values) def make_union_def(definition): return GraphQLUnionType( name=definition.name.value, resolve_type=_none, types=[produce_type_def(t) for t in definition.types], ) def make_scalar_def(definition): return GraphQLScalarType( name=definition.name.value, serialize=_none, # Validation calls the parse functions to determine if a literal value is correct. # Returning none, however would cause the scalar to fail validation. Returning false, # will cause them to pass. parse_literal=_false, parse_value=_false, ) def make_input_object_def(definition): return GraphQLInputObjectType( name=definition.name.value, fields=lambda: make_input_values( definition.fields, GraphQLInputObjectField ), ) _schema_def_handlers = { ast.ObjectTypeDefinition: make_type_def, ast.InterfaceTypeDefinition: make_interface_def, ast.EnumTypeDefinition: make_enum_def, ast.UnionTypeDefinition: make_union_def, ast.ScalarTypeDefinition: make_scalar_def, ast.InputObjectTypeDefinition: make_input_object_def, } types = [type_def_named(definition.name.value) for definition in type_defs] directives = [get_directive(d) for d in directive_defs] # If specified directive were not explicitly declared, add them. find_skip_directive = ( directive.name for directive in directives if directive.name == "skip" ) find_include_directive = ( directive.name for directive in directives if directive.name == "include" ) find_deprecated_directive = ( directive.name for directive in directives if directive.name == "deprecated" ) if not next(find_skip_directive, None): directives.append(GraphQLSkipDirective) if not next(find_include_directive, None): directives.append(GraphQLIncludeDirective) if not next(find_deprecated_directive, None): directives.append(GraphQLDeprecatedDirective) schema_kwargs = {"query": get_object_type(ast_map[query_type_name])} if mutation_type_name: schema_kwargs["mutation"] = get_object_type(ast_map[mutation_type_name]) if subscription_type_name: schema_kwargs["subscription"] = get_object_type(ast_map[subscription_type_name]) if directive_defs: schema_kwargs["directives"] = directives if types: schema_kwargs["types"] = types return GraphQLSchema(**schema_kwargs) def get_deprecation_reason(directives): deprecated_ast = next( ( directive for directive in directives if directive.name.value == GraphQLDeprecatedDirective.name ), None, ) if deprecated_ast: args = get_argument_values( GraphQLDeprecatedDirective.args, deprecated_ast.arguments ) return args["reason"] else: return None graphql-core-legacy-2.3.2/graphql/utils/build_client_schema.py000066400000000000000000000245671365661746200245270ustar00rootroot00000000000000from ..language.parser import parse_value from ..pyutils.ordereddict import OrderedDict from ..type import ( GraphQLArgument, GraphQLBoolean, GraphQLEnumType, GraphQLEnumValue, GraphQLField, GraphQLFloat, GraphQLID, GraphQLInputObjectField, GraphQLInputObjectType, GraphQLInt, GraphQLInterfaceType, GraphQLList, GraphQLNonNull, GraphQLObjectType, GraphQLScalarType, GraphQLSchema, GraphQLString, GraphQLUnionType, is_input_type, is_output_type, ) from ..type.directives import DirectiveLocation, GraphQLDirective from ..type.introspection import ( TypeKind, __Directive, __DirectiveLocation, __EnumValue, __Field, __InputValue, __Schema, __Type, __TypeKind, ) from .value_from_ast import value_from_ast def _false(*_): return False def _none(*_): return None def no_execution(root, info, **args): raise Exception("Client Schema cannot be used for execution.") def build_client_schema(introspection): schema_introspection = introspection["__schema"] type_introspection_map = {t["name"]: t for t in schema_introspection["types"]} type_def_cache = { "String": GraphQLString, "Int": GraphQLInt, "Float": GraphQLFloat, "Boolean": GraphQLBoolean, "ID": GraphQLID, "__Schema": __Schema, "__Directive": __Directive, "__DirectiveLocation": __DirectiveLocation, "__Type": __Type, "__Field": __Field, "__InputValue": __InputValue, "__EnumValue": __EnumValue, "__TypeKind": __TypeKind, } def get_type(type_ref): kind = type_ref.get("kind") if kind == TypeKind.LIST: item_ref = type_ref.get("ofType") if not item_ref: raise Exception("Decorated type deeper than introspection query.") return GraphQLList(get_type(item_ref)) elif kind == TypeKind.NON_NULL: nullable_ref = type_ref.get("ofType") if not nullable_ref: raise Exception("Decorated type deeper than introspection query.") return GraphQLNonNull(get_type(nullable_ref)) return get_named_type(type_ref["name"]) def get_named_type(type_name): if type_name in type_def_cache: return type_def_cache[type_name] type_introspection = type_introspection_map.get(type_name) if not type_introspection: raise Exception( "Invalid or incomplete schema, unknown type: {}. Ensure that a full introspection query " "is used in order to build a client schema.".format(type_name) ) type_def = type_def_cache[type_name] = build_type(type_introspection) return type_def def get_input_type(type_ref): input_type = get_type(type_ref) assert is_input_type( input_type ), "Introspection must provide input type for arguments." return input_type def get_output_type(type_ref): output_type = get_type(type_ref) assert is_output_type( output_type ), "Introspection must provide output type for fields." return output_type def get_object_type(type_ref): object_type = get_type(type_ref) assert isinstance( object_type, GraphQLObjectType ), "Introspection must provide object type for possibleTypes." return object_type def get_interface_type(type_ref): interface_type = get_type(type_ref) assert isinstance( interface_type, GraphQLInterfaceType ), "Introspection must provide interface type for interfaces." return interface_type def build_type(type): type_kind = type.get("kind") handler = type_builders.get(type_kind) if not handler: raise Exception( "Invalid or incomplete schema, unknown kind: {}. Ensure that a full introspection query " "is used in order to build a client schema.".format(type_kind) ) return handler(type) def build_scalar_def(scalar_introspection): return GraphQLScalarType( name=scalar_introspection["name"], description=scalar_introspection.get("description"), serialize=_none, parse_value=_false, parse_literal=_false, ) def build_object_def(object_introspection): return GraphQLObjectType( name=object_introspection["name"], description=object_introspection.get("description"), interfaces=[ get_interface_type(i) for i in object_introspection.get("interfaces", []) ], fields=lambda: build_field_def_map(object_introspection), ) def build_interface_def(interface_introspection): return GraphQLInterfaceType( name=interface_introspection["name"], description=interface_introspection.get("description"), fields=lambda: build_field_def_map(interface_introspection), resolve_type=no_execution, ) def build_union_def(union_introspection): return GraphQLUnionType( name=union_introspection["name"], description=union_introspection.get("description"), types=[ get_object_type(t) for t in union_introspection.get("possibleTypes", []) ], resolve_type=no_execution, ) def build_enum_def(enum_introspection): return GraphQLEnumType( name=enum_introspection["name"], description=enum_introspection.get("description"), values=OrderedDict( [ ( value_introspection["name"], GraphQLEnumValue( description=value_introspection.get("description"), deprecation_reason=value_introspection.get( "deprecationReason" ), ), ) for value_introspection in enum_introspection.get("enumValues", []) ] ), ) def build_input_object_def(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.get("inputFields"), GraphQLInputObjectField ), ) type_builders = { TypeKind.SCALAR: build_scalar_def, TypeKind.OBJECT: build_object_def, TypeKind.INTERFACE: build_interface_def, TypeKind.UNION: build_union_def, TypeKind.ENUM: build_enum_def, TypeKind.INPUT_OBJECT: build_input_object_def, } def build_field_def_map(type_introspection): return OrderedDict( [ ( f["name"], GraphQLField( type_=get_output_type(f["type"]), description=f.get("description"), resolver=no_execution, deprecation_reason=f.get("deprecationReason"), args=build_input_value_def_map(f.get("args"), GraphQLArgument), ), ) for f in type_introspection.get("fields", []) ] ) def build_default_value(f): default_value = f.get("defaultValue") if default_value is None: return None return value_from_ast(parse_value(default_value), get_input_type(f["type"])) def build_input_value_def_map(input_value_introspection, argument_type): return OrderedDict( [ (f["name"], build_input_value(f, argument_type)) for f in input_value_introspection ] ) def build_input_value(input_value_introspection, argument_type): input_value = argument_type( description=input_value_introspection.get("description"), type_=get_input_type(input_value_introspection["type"]), default_value=build_default_value(input_value_introspection), ) return input_value def build_directive(directive_introspection): # Support deprecated `on****` fields for building `locations`, as this # is used by GraphiQL which may need to support outdated servers. locations = list(directive_introspection.get("locations", [])) if not locations: locations = [] if directive_introspection.get("onField", False): locations += list(DirectiveLocation.FIELD_LOCATIONS) if directive_introspection.get("onOperation", False): locations += list(DirectiveLocation.OPERATION_LOCATIONS) if directive_introspection.get("onFragment", False): locations += list(DirectiveLocation.FRAGMENT_LOCATIONS) return GraphQLDirective( name=directive_introspection["name"], description=directive_introspection.get("description"), # TODO: {} ? args=build_input_value_def_map( directive_introspection.get("args", {}), GraphQLArgument ), locations=locations, ) # Iterate through all types, getting the type definition for each, ensuring # that any type not directly referenced by a field will get created. types = [ get_named_type(type_introspection_name) for type_introspection_name in type_introspection_map.keys() ] query_type = get_object_type(schema_introspection["queryType"]) mutation_type = ( get_object_type(schema_introspection["mutationType"]) if schema_introspection.get("mutationType") else None ) subscription_type = ( get_object_type(schema_introspection["subscriptionType"]) if schema_introspection.get("subscriptionType") else None ) directives = ( [build_directive(d) for d in schema_introspection["directives"]] if schema_introspection["directives"] else [] ) return GraphQLSchema( query=query_type, mutation=mutation_type, subscription=subscription_type, directives=directives, types=types, ) graphql-core-legacy-2.3.2/graphql/utils/concat_ast.py000066400000000000000000000005571365661746200226610ustar00rootroot00000000000000import itertools from ..language.ast import Document # Necessary for static type checking if False: # flake8: noqa from typing import Iterable def concat_ast(asts): # type: (Iterable[Document]) -> Document return Document( definitions=list( itertools.chain.from_iterable(document.definitions for document in asts) ) ) graphql-core-legacy-2.3.2/graphql/utils/extend_schema.py000066400000000000000000000336221365661746200233510ustar00rootroot00000000000000from collections import defaultdict from ..error import GraphQLError from ..language import ast from ..pyutils.ordereddict import OrderedDict from ..type.definition import ( GraphQLArgument, GraphQLEnumType, GraphQLEnumValue, GraphQLField, GraphQLInputObjectField, GraphQLInputObjectType, GraphQLInterfaceType, GraphQLList, GraphQLNonNull, GraphQLObjectType, GraphQLScalarType, GraphQLUnionType, ) from ..type.introspection import ( __Directive, __DirectiveLocation, __EnumValue, __Field, __InputValue, __Schema, __Type, __TypeKind, ) from ..type.scalars import ( GraphQLBoolean, GraphQLFloat, GraphQLID, GraphQLInt, GraphQLString, ) from ..type.schema import GraphQLSchema from .value_from_ast import value_from_ast def extend_schema(schema, documentAST=None): """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.""" assert isinstance(schema, GraphQLSchema), "Must provide valid GraphQLSchema" assert documentAST and isinstance( documentAST, ast.Document ), "Must provide valid Document AST" # Collect the type definitions and extensions found in the document. type_definition_map = {} type_extensions_map = defaultdict(list) for _def in documentAST.definitions: if isinstance( _def, ( ast.ObjectTypeDefinition, ast.InterfaceTypeDefinition, ast.EnumTypeDefinition, ast.UnionTypeDefinition, ast.ScalarTypeDefinition, ast.InputObjectTypeDefinition, ), ): # Sanity check that none of the defined types conflict with the # schema's existing types. type_name = _def.name.value if schema.get_type(type_name): raise GraphQLError( ( 'Type "{}" already exists in the schema. It cannot also ' + "be defined in this type definition." ).format(type_name), [_def], ) type_definition_map[type_name] = _def elif isinstance(_def, ast.TypeExtensionDefinition): # Sanity check that this type extension exists within the # schema's existing types. extended_type_name = _def.definition.name.value existing_type = schema.get_type(extended_type_name) if not existing_type: raise GraphQLError( ( 'Cannot extend type "{}" because it does not ' + "exist in the existing schema." ).format(extended_type_name), [_def.definition], ) if not isinstance(existing_type, GraphQLObjectType): raise GraphQLError( 'Cannot extend non-object type "{}".'.format(extended_type_name), [_def.definition], ) type_extensions_map[extended_type_name].append(_def) # 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. def get_type_from_def(type_def): type = _get_named_type(type_def.name) assert type, "Invalid schema" return type def get_type_from_AST(astNode): type = _get_named_type(astNode.name.value) if not type: raise GraphQLError( ( 'Unknown type: "{}". Ensure that this type exists ' + "either in the original schema, or is added in a type definition." ).format(astNode.name.value), [astNode], ) return type # Given a name, returns a type from either the existing schema or an # added type. def _get_named_type(typeName): cached_type_def = type_def_cache.get(typeName) if cached_type_def: return cached_type_def existing_type = schema.get_type(typeName) if existing_type: type_def = extend_type(existing_type) type_def_cache[typeName] = type_def return type_def type_ast = type_definition_map.get(typeName) if type_ast: type_def = build_type(type_ast) type_def_cache[typeName] = type_def return type_def # Given a type's introspection result, construct the correct # GraphQLType instance. def extend_type(type): if isinstance(type, GraphQLObjectType): return extend_object_type(type) if isinstance(type, GraphQLInterfaceType): return extend_interface_type(type) if isinstance(type, GraphQLUnionType): return extend_union_type(type) return type def extend_object_type(type): return GraphQLObjectType( name=type.name, description=type.description, interfaces=lambda: extend_implemented_interfaces(type), fields=lambda: extend_field_map(type), ) def extend_interface_type(type): return GraphQLInterfaceType( name=type.name, description=type.description, fields=lambda: extend_field_map(type), resolve_type=cannot_execute_client_schema, ) def extend_union_type(type): return GraphQLUnionType( name=type.name, description=type.description, types=list(map(get_type_from_def, type.types)), resolve_type=cannot_execute_client_schema, ) def extend_implemented_interfaces(type): interfaces = list(map(get_type_from_def, type.interfaces)) # If there are any extensions to the interfaces, apply those here. extensions = type_extensions_map[type.name] for extension in extensions: for namedType in extension.definition.interfaces: interface_name = namedType.name.value if any([_def.name == interface_name for _def in interfaces]): raise GraphQLError( ( 'Type "{}" already implements "{}". ' + "It cannot also be implemented in this type extension." ).format(type.name, interface_name), [namedType], ) interfaces.append(get_type_from_AST(namedType)) return interfaces def extend_field_map(type): new_field_map = OrderedDict() old_field_map = type.fields for field_name, field in old_field_map.items(): new_field_map[field_name] = GraphQLField( extend_field_type(field.type), description=field.description, deprecation_reason=field.deprecation_reason, args=field.args, resolver=cannot_execute_client_schema, ) # If there are any extensions to the fields, apply those here. extensions = type_extensions_map[type.name] for extension in extensions: for field in extension.definition.fields: field_name = field.name.value if field_name in old_field_map: raise GraphQLError( ( 'Field "{}.{}" already exists in the ' + "schema. It cannot also be defined in this type extension." ).format(type.name, field_name), [field], ) new_field_map[field_name] = GraphQLField( build_field_type(field.type), args=build_input_values(field.arguments), resolver=cannot_execute_client_schema, ) return new_field_map def extend_field_type(type): if isinstance(type, GraphQLList): return GraphQLList(extend_field_type(type.of_type)) if isinstance(type, GraphQLNonNull): return GraphQLNonNull(extend_field_type(type.of_type)) return get_type_from_def(type) def build_type(type_ast): _type_build = { ast.ObjectTypeDefinition: build_object_type, ast.InterfaceTypeDefinition: build_interface_type, ast.UnionTypeDefinition: build_union_type, ast.ScalarTypeDefinition: build_scalar_type, ast.EnumTypeDefinition: build_enum_type, ast.InputObjectTypeDefinition: build_input_object_type, } func = _type_build.get(type(type_ast)) if func: return func(type_ast) def build_object_type(type_ast): return GraphQLObjectType( type_ast.name.value, interfaces=lambda: build_implemented_interfaces(type_ast), fields=lambda: build_field_map(type_ast), ) def build_interface_type(type_ast): return GraphQLInterfaceType( type_ast.name.value, fields=lambda: build_field_map(type_ast), resolve_type=cannot_execute_client_schema, ) def build_union_type(type_ast): return GraphQLUnionType( type_ast.name.value, types=list(map(get_type_from_AST, type_ast.types)), resolve_type=cannot_execute_client_schema, ) def build_scalar_type(type_ast): return GraphQLScalarType( type_ast.name.value, serialize=lambda *args, **kwargs: None, # Note: validation calls the parse functions to determine if a # literal value is correct. Returning null would cause use of custom # scalars to always fail validation. Returning false causes them to # always pass validation. parse_value=lambda *args, **kwargs: False, parse_literal=lambda *args, **kwargs: False, ) def build_enum_type(type_ast): return GraphQLEnumType( type_ast.name.value, values={v.name.value: GraphQLEnumValue() for v in type_ast.values}, ) def build_input_object_type(type_ast): return GraphQLInputObjectType( type_ast.name.value, fields=lambda: build_input_values(type_ast.fields, GraphQLInputObjectField), ) def build_implemented_interfaces(type_ast): return list(map(get_type_from_AST, type_ast.interfaces)) def build_field_map(type_ast): return { field.name.value: GraphQLField( build_field_type(field.type), args=build_input_values(field.arguments), resolver=cannot_execute_client_schema, ) for field in type_ast.fields } def build_input_values(values, input_type=GraphQLArgument): input_values = OrderedDict() for value in values: type = build_field_type(value.type) input_values[value.name.value] = input_type( type, default_value=value_from_ast(value.default_value, type) ) return input_values def build_field_type(type_ast): if isinstance(type_ast, ast.ListType): return GraphQLList(build_field_type(type_ast.type)) if isinstance(type_ast, ast.NonNullType): return GraphQLNonNull(build_field_type(type_ast.type)) return get_type_from_AST(type_ast) # If this document contains no new types, then return the same unmodified # GraphQLSchema instance. if not type_extensions_map and not type_definition_map: return schema # A cache to use to store the actual GraphQLType definition objects by name. # Initialize to the GraphQL built in scalars and introspection types. All # functions below are inline so that this type def cache is within the scope # of the closure. type_def_cache = { "String": GraphQLString, "Int": GraphQLInt, "Float": GraphQLFloat, "Boolean": GraphQLBoolean, "ID": GraphQLID, "__Schema": __Schema, "__Directive": __Directive, "__DirectiveLocation": __DirectiveLocation, "__Type": __Type, "__Field": __Field, "__InputValue": __InputValue, "__EnumValue": __EnumValue, "__TypeKind": __TypeKind, } # Get the root Query, Mutation, and Subscription types. query_type = get_type_from_def(schema.get_query_type()) existing_mutation_type = schema.get_mutation_type() mutationType = ( existing_mutation_type and get_type_from_def(existing_mutation_type) or None ) existing_subscription_type = schema.get_subscription_type() subscription_type = ( existing_subscription_type and get_type_from_def(existing_subscription_type) or None ) # Iterate through all types, getting the type definition for each, ensuring # that any type not directly referenced by a field will get created. types = [get_type_from_def(_def) for _def in schema.get_type_map().values()] # Do the same with new types, appending to the list of defined types. types += [get_type_from_AST(_def) for _def in type_definition_map.values()] # Then produce and return a Schema with these types. return GraphQLSchema( query=query_type, mutation=mutationType, subscription=subscription_type, # Copy directives. directives=schema.get_directives(), types=types, ) def cannot_execute_client_schema(*args, **kwargs): raise Exception("Client Schema cannot be used for execution.") graphql-core-legacy-2.3.2/graphql/utils/get_field_def.py000066400000000000000000000025621365661746200233010ustar00rootroot00000000000000from ..type.definition import GraphQLInterfaceType, GraphQLObjectType, GraphQLUnionType from ..type.introspection import ( SchemaMetaFieldDef, TypeMetaFieldDef, TypeNameMetaFieldDef, ) # Necessary for static type checking if False: # flake8: noqa from ..language.ast import Field from ..type.definition import GraphQLField from ..type.schema import GraphQLSchema from typing import Optional, Union def get_field_def( schema, # type: GraphQLSchema parent_type, # type: Union[GraphQLInterfaceType, GraphQLObjectType] field_ast, # type: Field ): # type: (...) -> Optional[GraphQLField] """Not exactly the same as the executor's definition of 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_ast.name.value if name == "__schema" and schema.get_query_type() == parent_type: return SchemaMetaFieldDef elif name == "__type" and schema.get_query_type() == parent_type: return TypeMetaFieldDef elif name == "__typename" and isinstance( parent_type, (GraphQLObjectType, GraphQLInterfaceType, GraphQLUnionType) ): return TypeNameMetaFieldDef elif isinstance(parent_type, (GraphQLObjectType, GraphQLInterfaceType)): return parent_type.fields.get(name) return None graphql-core-legacy-2.3.2/graphql/utils/get_operation_ast.py000066400000000000000000000020461365661746200242440ustar00rootroot00000000000000from ..language import ast # Necessary for static type checking if False: # flake8: noqa from ..language.ast import Document, OperationDefinition from typing import Optional def get_operation_ast(document_ast, operation_name=None): # type: (Document, Optional[str]) -> Optional[OperationDefinition] operation = None for definition in document_ast.definitions: if isinstance(definition, ast.OperationDefinition): if not operation_name: # If no operation name is provided, only return an Operation if it is the only one present in the # document. This means that if we've encountered a second operation as we were iterating over the # definitions in the document, there are more than one Operation defined, and we should return None. if operation: return None operation = definition elif definition.name and definition.name.value == operation_name: return definition return operation graphql-core-legacy-2.3.2/graphql/utils/introspection_query.py000066400000000000000000000027001365661746200246600ustar00rootroot00000000000000introspection_query = """ query IntrospectionQuery { __schema { queryType { name } mutationType { name } subscriptionType { name } types { ...FullType } directives { name description locations args { ...InputValue } } } } fragment FullType on __Type { kind name description fields(includeDeprecated: true) { name description args { ...InputValue } type { ...TypeRef } isDeprecated deprecationReason } inputFields { ...InputValue } interfaces { ...TypeRef } enumValues(includeDeprecated: true) { name description isDeprecated deprecationReason } possibleTypes { ...TypeRef } } fragment InputValue on __InputValue { name description type { ...TypeRef } defaultValue } 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 } } } } } } } } """ graphql-core-legacy-2.3.2/graphql/utils/is_valid_literal_value.py000066400000000000000000000055361365661746200252470ustar00rootroot00000000000000from ..language import ast from ..language.printer import print_ast from ..type.definition import ( GraphQLEnumType, GraphQLInputObjectType, GraphQLList, GraphQLNonNull, GraphQLScalarType, ) # Necessary for static type checking if False: # flake8: noqa from ..language.ast import ObjectValue, StringValue from typing import Union, Any, List _empty_list = [] # type: List def is_valid_literal_value(type, value_ast): # type: (Union[GraphQLInputObjectType, GraphQLScalarType, GraphQLNonNull, GraphQLList], Any) -> List if isinstance(type, GraphQLNonNull): of_type = type.of_type if not value_ast: return [u'Expected "{}", found null.'.format(type)] return is_valid_literal_value(of_type, value_ast) # type: ignore if not value_ast: return _empty_list if isinstance(value_ast, ast.Variable): return _empty_list if isinstance(type, GraphQLList): item_type = type.of_type if isinstance(value_ast, ast.ListValue): errors = [] for i, item_ast in enumerate(value_ast.values): item_errors = is_valid_literal_value(item_type, item_ast) for error in item_errors: errors.append(u"In element #{}: {}".format(i, error)) return errors return is_valid_literal_value(item_type, value_ast) if isinstance(type, GraphQLInputObjectType): if not isinstance(value_ast, ast.ObjectValue): return [u'Expected "{}", found not an object.'.format(type)] fields = type.fields field_asts = value_ast.fields errors = [] for provided_field_ast in field_asts: if provided_field_ast.name.value not in fields: errors.append( u'In field "{}": Unknown field.'.format( provided_field_ast.name.value ) ) field_ast_map = {field_ast.name.value: field_ast for field_ast in field_asts} def get_field_ast_value(field_name): # type: (str) -> Union[None, ObjectValue, StringValue] if field_name in field_ast_map: return field_ast_map[field_name].value return None for field_name, field in fields.items(): subfield_errors = is_valid_literal_value( field.type, get_field_ast_value(field_name) ) errors.extend( u'In field "{}": {}'.format(field_name, e) for e in subfield_errors ) return errors assert isinstance(type, (GraphQLScalarType, GraphQLEnumType)), "Must be input type" parse_result = type.parse_literal(value_ast) if parse_result is None: return [ u'Expected type "{}", found {}.'.format(type.name, print_ast(value_ast)) ] return _empty_list graphql-core-legacy-2.3.2/graphql/utils/is_valid_value.py000066400000000000000000000046061365661746200235300ustar00rootroot00000000000000""" Implementation of isValidJSValue from graphql.s """ try: from collections.abc import Iterable, Mapping except ImportError: # Python < 3.3 from collections import Iterable, Mapping import json from six import string_types from ..type import ( GraphQLEnumType, GraphQLInputObjectType, GraphQLList, GraphQLNonNull, GraphQLScalarType, ) # Necessary for static type checking if False: # flake8: noqa from typing import Any, List _empty_list = [] # type: List def is_valid_value(value, type): # type: (Any, Any) -> List """Given a type and any value, return True if that value is valid.""" if isinstance(type, GraphQLNonNull): of_type = type.of_type if value is None: return [u'Expected "{}", found null.'.format(type)] return is_valid_value(value, of_type) if value is None: return _empty_list if isinstance(type, GraphQLList): item_type = type.of_type if not isinstance(value, string_types) and isinstance(value, Iterable): errors = [] for i, item in enumerate(value): item_errors = is_valid_value(item, item_type) for error in item_errors: errors.append(u"In element #{}: {}".format(i, error)) return errors else: return is_valid_value(value, item_type) if isinstance(type, GraphQLInputObjectType): if not isinstance(value, Mapping): return [u'Expected "{}", found not an object.'.format(type)] fields = type.fields errors = [] for provided_field in sorted(value.keys()): if provided_field not in fields: errors.append(u'In field "{}": Unknown field.'.format(provided_field)) for field_name, field in fields.items(): subfield_errors = is_valid_value(value.get(field_name), field.type) errors.extend( u'In field "{}": {}'.format(field_name, e) for e in subfield_errors ) return errors assert isinstance(type, (GraphQLScalarType, GraphQLEnumType)), "Must be input type" # Scalar/Enum input checks to ensure the type can parse the value to # a non-null value. parse_result = type.parse_value(value) if parse_result is None: return [u'Expected type "{}", found {}.'.format(type, json.dumps(value))] return _empty_list graphql-core-legacy-2.3.2/graphql/utils/quoted_or_list.py000066400000000000000000000015101365661746200235650ustar00rootroot00000000000000import functools # Necessary for static type checking if False: # flake8: noqa from typing import List MAX_LENGTH = 5 def quoted_or_list(items): # type: (List[str]) -> str """Given [ A, B, C ] return '"A", "B" or "C"'.""" selected = items[:MAX_LENGTH] quoted_items = ('"{}"'.format(t) for t in selected) def quoted_or_text(text, quoted_and_index): index = quoted_and_index[0] quoted_item = quoted_and_index[1] text += ( (", " if len(selected) > 2 and not index == len(selected) - 1 else " ") + ("or " if index == len(selected) - 1 else "") + quoted_item ) return text enumerated_items = enumerate(quoted_items) first_item = next(enumerated_items)[1] return functools.reduce(quoted_or_text, enumerated_items, first_item) graphql-core-legacy-2.3.2/graphql/utils/schema_printer.py000066400000000000000000000137361365661746200235510ustar00rootroot00000000000000from ..language.printer import print_ast from ..type.definition import ( GraphQLEnumType, GraphQLInputObjectType, GraphQLInterfaceType, GraphQLObjectType, GraphQLScalarType, GraphQLUnionType, ) from ..type.directives import DEFAULT_DEPRECATION_REASON from .ast_from_value import ast_from_value # Necessary for static type checking if False: # flake8: noqa from ..type.definition import ( GraphQLArgument, GraphQLType, GraphQLField, GraphQLEnumValue, ) from ..type.schema import GraphQLSchema from ..type.directives import GraphQLDirective from typing import Any, Union, Callable def print_schema(schema): # type: (GraphQLSchema) -> str return _print_filtered_schema( schema, lambda n: not (is_spec_directive(n)), _is_defined_type ) def print_introspection_schema(schema): # type: (GraphQLSchema) -> str return _print_filtered_schema(schema, is_spec_directive, _is_introspection_type) def is_spec_directive(directive_name): # type: (str) -> bool return directive_name in ("skip", "include", "deprecated") def _is_defined_type(typename): # type: (Any) -> bool return not _is_introspection_type(typename) and not _is_builtin_scalar(typename) def _is_introspection_type(typename): # type: (str) -> bool return typename.startswith("__") _builtin_scalars = frozenset(["String", "Boolean", "Int", "Float", "ID"]) def _is_builtin_scalar(typename): # type: (str) -> bool return typename in _builtin_scalars def _print_filtered_schema(schema, directive_filter, type_filter): # type: (GraphQLSchema, Callable[[str], bool], Callable[[str], bool]) -> str return ( "\n\n".join( [_print_schema_definition(schema)] + [ _print_directive(directive) for directive in schema.get_directives() if directive_filter(directive.name) ] + [ _print_type(type) for typename, type in sorted(schema.get_type_map().items()) if type_filter(typename) ] ) + "\n" ) def _print_schema_definition(schema): # type: (GraphQLSchema) -> str operation_types = [] query_type = schema.get_query_type() if query_type: operation_types.append(" query: {}".format(query_type)) mutation_type = schema.get_mutation_type() if mutation_type: operation_types.append(" mutation: {}".format(mutation_type)) subscription_type = schema.get_subscription_type() if subscription_type: operation_types.append(" subscription: {}".format(subscription_type)) return "schema {{\n{}\n}}".format("\n".join(operation_types)) def _print_type(type): # type: (GraphQLType) -> str if isinstance(type, GraphQLScalarType): return _print_scalar(type) elif isinstance(type, GraphQLObjectType): return _print_object(type) elif isinstance(type, GraphQLInterfaceType): return _print_interface(type) elif isinstance(type, GraphQLUnionType): return _print_union(type) elif isinstance(type, GraphQLEnumType): return _print_enum(type) assert isinstance(type, GraphQLInputObjectType) return _print_input_object(type) def _print_scalar(type): # type: (GraphQLScalarType) -> str return "scalar {}".format(type.name) def _print_object(type): # type: (GraphQLObjectType) -> str interfaces = type.interfaces implemented_interfaces = ( " implements {}".format(", ".join(i.name for i in interfaces)) if interfaces else "" ) return ("type {}{} {{\n" "{}\n" "}}").format( type.name, implemented_interfaces, _print_fields(type) ) def _print_interface(type): # type: (GraphQLInterfaceType) -> str return ("interface {} {{\n" "{}\n" "}}").format(type.name, _print_fields(type)) def _print_union(type): # type: (GraphQLUnionType) -> str return "union {} = {}".format(type.name, " | ".join(str(t) for t in type.types)) def _print_enum(type): # type: (GraphQLEnumType) -> str return ("enum {} {{\n" "{}\n" "}}").format( type.name, "\n".join(" " + v.name + _print_deprecated(v) for v in type.values) ) def _print_input_object(type): # type: (GraphQLInputObjectType) -> str return ("input {} {{\n" "{}\n" "}}").format( type.name, "\n".join( " " + _print_input_value(name, field) for name, field in type.fields.items() ), ) def _print_fields(type): # type: (Union[GraphQLObjectType, GraphQLInterfaceType]) -> str return "\n".join( " {}{}: {}{}".format(f_name, _print_args(f), f.type, _print_deprecated(f)) for f_name, f in type.fields.items() ) def _print_deprecated(field_or_enum_value): # type: (Union[GraphQLField, GraphQLEnumValue]) -> str reason = field_or_enum_value.deprecation_reason if reason is None: return "" elif reason in ("", DEFAULT_DEPRECATION_REASON): return " @deprecated" else: return " @deprecated(reason: {})".format(print_ast(ast_from_value(reason))) def _print_args(field_or_directives): # type: (Union[GraphQLField, GraphQLDirective]) -> str if not field_or_directives.args: return "" return "({})".format( ", ".join( _print_input_value(arg_name, arg) for arg_name, arg in field_or_directives.args.items() ) ) def _print_input_value(name, arg): # type: (str, GraphQLArgument) -> str if arg.default_value is not None: default_value = " = " + print_ast(ast_from_value(arg.default_value, arg.type)) else: default_value = "" return "{}: {}{}".format(name, arg.type, default_value) def _print_directive(directive): # type: (GraphQLDirective) -> str return "directive @{}{} on {}".format( directive.name, _print_args(directive), " | ".join(directive.locations) ) __all__ = ["print_schema", "print_introspection_schema"] graphql-core-legacy-2.3.2/graphql/utils/suggestion_list.py000066400000000000000000000033451365661746200237630ustar00rootroot00000000000000from collections import OrderedDict def suggestion_list(inp, options): """ Given an invalid input string and a list of valid options, returns a filtered list of valid options sorted based on their similarity with the input. """ options_by_distance = OrderedDict() input_threshold = len(inp) / 2 for option in options: distance = lexical_distance(inp, option) threshold = max(input_threshold, len(option) / 2, 1) if distance <= threshold: options_by_distance[option] = distance return sorted( list(options_by_distance.keys()), key=lambda k: options_by_distance[k] ) def lexical_distance(a, b): """ 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 @returns distance in number of edits """ d = [[i] for i in range(len(a) + 1)] or [] d_len = len(d) or 1 for i in range(d_len): for j in range(1, len(b) + 1): if i == 0: d[i].append(j) else: d[i].append(0) for i in range(1, len(a) + 1): for j in range(1, len(b) + 1): cost = 0 if a[i - 1] == b[j - 1] else 1 d[i][j] = min(d[i - 1][j] + 1, d[i][j - 1] + 1, d[i - 1][j - 1] + cost) if i > 1 and j < 1 and a[i - 1] == b[j - 2] and a[i - 2] == b[j - 1]: d[i][j] = min(d[i][j], d[i - 2][j - 2] + cost) return d[len(a)][len(b)] graphql-core-legacy-2.3.2/graphql/utils/tests/000077500000000000000000000000001365661746200213245ustar00rootroot00000000000000graphql-core-legacy-2.3.2/graphql/utils/tests/__init__.py000066400000000000000000000000001365661746200234230ustar00rootroot00000000000000graphql-core-legacy-2.3.2/graphql/utils/tests/test_ast_from_value.py000066400000000000000000000061371365661746200257520ustar00rootroot00000000000000from collections import OrderedDict from graphql.language import ast from graphql.type.definition import ( GraphQLEnumType, GraphQLEnumValue, GraphQLInputObjectField, GraphQLInputObjectType, GraphQLList, ) from graphql.type.scalars import GraphQLFloat from graphql.utils.ast_from_value import ast_from_value def test_converts_boolean_values_to_asts(): assert ast_from_value(True) == ast.BooleanValue(True) assert ast_from_value(False) == ast.BooleanValue(False) def test_converts_numeric_values_to_asts(): assert ast_from_value(123) == ast.IntValue("123") assert ast_from_value(123.0) == ast.IntValue("123") assert ast_from_value(123.5) == ast.FloatValue("123.5") assert ast_from_value(1e4) == ast.IntValue("10000") assert ast_from_value(1e40) == ast.FloatValue("1e+40") def test_it_converts_numeric_values_to_float_asts(): assert ast_from_value(123, GraphQLFloat) == ast.FloatValue("123.0") assert ast_from_value(123.0, GraphQLFloat) == ast.FloatValue("123.0") assert ast_from_value(123.5, GraphQLFloat) == ast.FloatValue("123.5") assert ast_from_value(1e4, GraphQLFloat) == ast.FloatValue("10000.0") assert ast_from_value(1e40, GraphQLFloat) == ast.FloatValue("1e+40") def test_it_converts_string_values_to_asts(): assert ast_from_value("hello") == ast.StringValue("hello") assert ast_from_value("VALUE") == ast.StringValue("VALUE") assert ast_from_value(u"VAL\nUE") == ast.StringValue("VAL\\nUE") assert ast_from_value("VAL\nUE") == ast.StringValue("VAL\\nUE") assert ast_from_value("123") == ast.StringValue("123") my_enum = GraphQLEnumType( "MyEnum", {"HELLO": GraphQLEnumValue(1), "GOODBYE": GraphQLEnumValue(2)} ) def test_converts_string_values_to_enum_asts_if_possible(): assert ast_from_value("hello", my_enum) == ast.EnumValue("hello") assert ast_from_value("HELLO", my_enum) == ast.EnumValue("HELLO") assert ast_from_value("VAL\nUE", my_enum) == ast.StringValue("VAL\\nUE") assert ast_from_value("123", my_enum) == ast.StringValue("123") def test_converts_array_values_to_list_asts(): assert ast_from_value(["FOO", "BAR"]) == ast.ListValue( values=[ast.StringValue("FOO"), ast.StringValue("BAR")] ) def test_converts_list_singletons(): assert ast_from_value("FOO", GraphQLList(my_enum)) == ast.EnumValue("FOO") def test_converts_input_objects(): value = OrderedDict([("foo", 3), ("bar", "HELLO")]) assert ast_from_value(value) == ast.ObjectValue( fields=[ ast.ObjectField(name=ast.Name("foo"), value=ast.IntValue("3")), ast.ObjectField(name=ast.Name("bar"), value=ast.StringValue("HELLO")), ] ) input_obj = GraphQLInputObjectType( "MyInputObj", { "foo": GraphQLInputObjectField(GraphQLFloat), "bar": GraphQLInputObjectField(my_enum), }, ) assert ast_from_value(value, input_obj) == ast.ObjectValue( fields=[ ast.ObjectField(name=ast.Name("foo"), value=ast.FloatValue("3.0")), ast.ObjectField(name=ast.Name("bar"), value=ast.EnumValue("HELLO")), ] ) graphql-core-legacy-2.3.2/graphql/utils/tests/test_ast_to_code.py000066400000000000000000000010131365661746200252130ustar00rootroot00000000000000from graphql import Source, parse from graphql.language import ast from graphql.language.parser import Loc from graphql.utils.ast_to_code import ast_to_code from ...language.tests import fixtures def test_ast_to_code_using_kitchen_sink(): doc = parse(fixtures.KITCHEN_SINK) code_ast = ast_to_code(doc) source = Source(fixtures.KITCHEN_SINK) def loc(start, end): return Loc(start, end, source) parsed_code_ast = eval(code_ast, {}, {"ast": ast, "loc": loc}) assert doc == parsed_code_ast graphql-core-legacy-2.3.2/graphql/utils/tests/test_ast_to_dict.py000066400000000000000000000126101365661746200252310ustar00rootroot00000000000000from graphql.language import ast from graphql.language.parser import Loc, parse from graphql.utils.ast_to_dict import ast_to_dict def test_converts_simple_ast_to_dict(): node = ast.Name(value="test", loc=Loc(start=5, end=10)) assert ast_to_dict(node) == {"kind": "Name", "value": "test"} assert ast_to_dict(node, include_loc=True) == { "kind": "Name", "value": "test", "loc": {"start": 5, "end": 10}, } def test_converts_nested_ast_to_dict(): parsed_ast = parse( """ query x { someQuery(arg: "x") { a b } fragment Test on TestFoo { c d } } """ ) expected_ast_dict = { "definitions": [ { "directives": [], "kind": "OperationDefinition", "name": {"kind": "Name", "value": "x"}, "operation": "query", "selection_set": { "kind": "SelectionSet", "selections": [ { "alias": None, "arguments": [ { "kind": "Argument", "name": {"kind": "Name", "value": "arg"}, "value": {"kind": "StringValue", "value": "x"}, } ], "directives": [], "kind": "Field", "name": {"kind": "Name", "value": "someQuery"}, "selection_set": { "kind": "SelectionSet", "selections": [ { "alias": None, "arguments": [], "directives": [], "kind": "Field", "name": {"kind": "Name", "value": "a"}, "selection_set": None, }, { "alias": None, "arguments": [], "directives": [], "kind": "Field", "name": {"kind": "Name", "value": "b"}, "selection_set": None, }, ], }, }, { "alias": None, "arguments": [], "directives": [], "kind": "Field", "name": {"kind": "Name", "value": "fragment"}, "selection_set": None, }, { "alias": None, "arguments": [], "directives": [], "kind": "Field", "name": {"kind": "Name", "value": "Test"}, "selection_set": None, }, { "alias": None, "arguments": [], "directives": [], "kind": "Field", "name": {"kind": "Name", "value": "on"}, "selection_set": None, }, { "alias": None, "arguments": [], "directives": [], "kind": "Field", "name": {"kind": "Name", "value": "TestFoo"}, "selection_set": { "kind": "SelectionSet", "selections": [ { "alias": None, "arguments": [], "directives": [], "kind": "Field", "name": {"kind": "Name", "value": "c"}, "selection_set": None, }, { "alias": None, "arguments": [], "directives": [], "kind": "Field", "name": {"kind": "Name", "value": "d"}, "selection_set": None, }, ], }, }, ], }, "variable_definitions": [], } ], "kind": "Document", } assert ast_to_dict(parsed_ast) == expected_ast_dict graphql-core-legacy-2.3.2/graphql/utils/tests/test_build_ast_schema.py000066400000000000000000000323731365661746200262330ustar00rootroot00000000000000from pytest import raises from graphql import GraphQLInt, parse from graphql.utils.build_ast_schema import build_ast_schema from graphql.utils.schema_printer import print_schema from ...type import ( GraphQLDeprecatedDirective, GraphQLIncludeDirective, GraphQLSkipDirective, ) def cycle_output(body): """This function does a full cycle of going from a string with the contents of the DSL, parsed in a schema AST, materializing that schema AST into an in-memory GraphQLSchema, and then finally printing that GraphQL into the DSL""" ast = parse(body) schema = build_ast_schema(ast) return "\n" + print_schema(schema) def test_simple_type(): body = """ schema { query: HelloScalars } type HelloScalars { str: String int: Int float: Float id: ID bool: Boolean } """ output = cycle_output(body) assert output == body def test_with_directives(): body = """ schema { query: Hello } directive @foo(arg: Int) on FIELD type Hello { str: String } """ output = cycle_output(body) assert output == body def test_maintains_skip_and_include_directives(): body = """ schema { query: Hello } type Hello { str: String } """ schema = build_ast_schema(parse(body)) assert len(schema.get_directives()) == 3 assert schema.get_directive("skip") == GraphQLSkipDirective assert schema.get_directive("include") == GraphQLIncludeDirective assert schema.get_directive("deprecated") == GraphQLDeprecatedDirective def test_overriding_directives_excludes_specified(): body = """ schema { query: Hello } directive @skip on FIELD directive @include on FIELD directive @deprecated on FIELD_DEFINITION type Hello { str: String } """ schema = build_ast_schema(parse(body)) assert len(schema.get_directives()) == 3 assert schema.get_directive("skip") != GraphQLSkipDirective assert schema.get_directive("skip") is not None assert schema.get_directive("include") != GraphQLIncludeDirective assert schema.get_directive("include") is not None assert schema.get_directive("deprecated") != GraphQLDeprecatedDirective assert schema.get_directive("deprecated") is not None def test_overriding_skip_directive_excludes_built_in_one(): body = """ schema { query: Hello } directive @skip on FIELD type Hello { str: String } """ schema = build_ast_schema(parse(body)) assert len(schema.get_directives()) == 3 assert schema.get_directive("skip") != GraphQLSkipDirective assert schema.get_directive("skip") is not None assert schema.get_directive("include") == GraphQLIncludeDirective assert schema.get_directive("deprecated") == GraphQLDeprecatedDirective def test_overriding_include_directive_excludes_built_in_one(): body = """ schema { query: Hello } directive @include on FIELD type Hello { str: String } """ schema = build_ast_schema(parse(body)) assert len(schema.get_directives()) == 3 assert schema.get_directive("skip") == GraphQLSkipDirective assert schema.get_directive("deprecated") == GraphQLDeprecatedDirective assert schema.get_directive("include") != GraphQLIncludeDirective assert schema.get_directive("include") is not None def test_adding_directives_maintains_skip_and_include_directives(): body = """ schema { query: Hello } directive @foo(arg: Int) on FIELD type Hello { str: String } """ schema = build_ast_schema(parse(body)) assert len(schema.get_directives()) == 4 assert schema.get_directive("skip") == GraphQLSkipDirective assert schema.get_directive("include") == GraphQLIncludeDirective assert schema.get_directive("deprecated") == GraphQLDeprecatedDirective def test_type_modifiers(): body = """ schema { query: HelloScalars } type HelloScalars { nonNullStr: String! listOfStrs: [String] listOfNonNullStrs: [String!] nonNullListOfStrs: [String]! nonNullListOfNonNullStrs: [String!]! } """ output = cycle_output(body) assert output == body def test_recursive_type(): body = """ schema { query: Recurse } type Recurse { str: String recurse: Recurse } """ output = cycle_output(body) assert output == body def test_two_types_circular(): body = """ schema { query: TypeOne } type TypeOne { str: String typeTwo: TypeTwo } type TypeTwo { str: String typeOne: TypeOne } """ output = cycle_output(body) assert output == body def test_single_argument_field(): body = """ schema { query: Hello } type Hello { str(int: Int): String floatToStr(float: Float): String idToStr(id: ID): String booleanToStr(bool: Boolean): String strToStr(bool: String): String } """ output = cycle_output(body) assert output == body def test_simple_type_with_multiple_arguments(): body = """ schema { query: Hello } type Hello { str(int: Int, bool: Boolean): String } """ output = cycle_output(body) assert output == body def test_simple_type_with_interface(): body = """ schema { query: HelloInterface } type HelloInterface implements WorldInterface { str: String } interface WorldInterface { str: String } """ output = cycle_output(body) assert output == body def test_simple_output_enum(): body = """ schema { query: OutputEnumRoot } enum Hello { WORLD } type OutputEnumRoot { hello: Hello } """ output = cycle_output(body) assert output == body def test_simple_input_enum(): body = """ schema { query: InputEnumRoot } enum Hello { WORLD } type InputEnumRoot { str(hello: Hello): String } """ output = cycle_output(body) assert output == body def test_multiple_value_enum(): body = """ schema { query: OutputEnumRoot } enum Hello { WO RLD } type OutputEnumRoot { hello: Hello } """ output = cycle_output(body) assert output == body def test_simple_union(): body = """ schema { query: Root } union Hello = World type Root { hello: Hello } type World { str: String } """ output = cycle_output(body) assert output == body def test_multiple_union(): body = """ schema { query: Root } union Hello = WorldOne | WorldTwo type Root { hello: Hello } type WorldOne { str: String } type WorldTwo { str: String } """ output = cycle_output(body) assert output == body def test_custom_scalar(): body = """ schema { query: Root } scalar CustomScalar type Root { customScalar: CustomScalar } """ output = cycle_output(body) assert output == body def test_input_object(): body = """ schema { query: Root } input Input { int: Int } type Root { field(in: Input): String } """ output = cycle_output(body) assert output == body def test_input_types_are_read(): schema = build_ast_schema( parse( """ schema { query: Query } type Query { field(input: Input): Int } input Input { id: Int } """ ) ) input_type = schema.get_type("Input") assert input_type.fields["id"].type == GraphQLInt def test_input_types_can_be_recursive(): schema = build_ast_schema( parse( """ schema { query: Query } type Query { field(input: Input): Int } input Input { id: Input } """ ) ) input_type = schema.get_type("Input") assert input_type.fields["id"].type == input_type def test_simple_argument_field_with_default(): body = """ schema { query: Hello } type Hello { str(int: Int = 2): String } """ output = cycle_output(body) assert output == body def test_simple_type_with_mutation(): body = """ schema { query: HelloScalars mutation: Mutation } type HelloScalars { str: String int: Int bool: Boolean } type Mutation { addHelloScalars(str: String, int: Int, bool: Boolean): HelloScalars } """ output = cycle_output(body) assert output == body def test_simple_type_with_subscription(): body = """ schema { query: HelloScalars subscription: Subscription } type HelloScalars { str: String int: Int bool: Boolean } type Subscription { subscribeHelloScalars(str: String, int: Int, bool: Boolean): HelloScalars } """ output = cycle_output(body) assert output == body def test_unreferenced_type_implementing_referenced_interface(): body = """ schema { query: Query } type Concrete implements Iface { key: String } interface Iface { key: String } type Query { iface: Iface } """ output = cycle_output(body) assert output == body def test_unreferenced_type_implementing_referenced_union(): body = """ schema { query: Query } type Concrete { key: String } type Query { union: Union } union Union = Concrete """ output = cycle_output(body) assert output == body def test_supports_deprecated_directive(): body = """ schema { query: Query } enum MyEnum { VALUE OLD_VALUE @deprecated OTHER_VALUE @deprecated(reason: "Terrible reasons") } type Query { field1: String @deprecated field2: Int @deprecated(reason: "Because I said so") enum: MyEnum } """ output = cycle_output(body) assert output == body def test_requires_a_schema_definition(): body = """ type Hello { bar: Bar } """ doc = parse(body) with raises(Exception) as excinfo: build_ast_schema(doc) assert "Must provide a schema definition." == str(excinfo.value) def test_allows_only_a_single_schema_definition(): body = """ schema { query: Hello } schema { query: Hello } type Hello { bar: Bar } """ doc = parse(body) with raises(Exception) as excinfo: build_ast_schema(doc) assert "Must provide only one schema definition." == str(excinfo.value) def test_requires_a_query_type(): body = """ schema { mutation: Hello } type Hello { bar: Bar } """ doc = parse(body) with raises(Exception) as excinfo: build_ast_schema(doc) assert "Must provide schema definition with query type." == str(excinfo.value) def test_allows_only_a_single_query_type(): body = """ schema { query: Hello query: Yellow } type Hello { bar: Bar } type Yellow { isColor: Boolean } """ doc = parse(body) with raises(Exception) as excinfo: build_ast_schema(doc) assert "Must provide only one query type in schema." == str(excinfo.value) def test_allows_only_a_single_mutation_type(): body = """ schema { query: Hello mutation: Hello mutation: Yellow } type Hello { bar: Bar } type Yellow { isColor: Boolean } """ doc = parse(body) with raises(Exception) as excinfo: build_ast_schema(doc) assert "Must provide only one mutation type in schema." == str(excinfo.value) def test_allows_only_a_single_subscription_type(): body = """ schema { query: Hello subscription: Hello subscription: Yellow } type Hello { bar: Bar } type Yellow { isColor: Boolean } """ doc = parse(body) with raises(Exception) as excinfo: build_ast_schema(doc) assert "Must provide only one subscription type in schema." == str(excinfo.value) def test_unknown_type_referenced(): body = """ schema { query: Hello } type Hello { bar: Bar } """ doc = parse(body) with raises(Exception) as excinfo: build_ast_schema(doc) assert 'Type "Bar" not found in document' in str(excinfo.value) def test_unknown_type_in_union_list(): body = """ schema { query: Hello } union TestUnion = Bar type Hello { testUnion: TestUnion } """ doc = parse(body) with raises(Exception) as excinfo: build_ast_schema(doc) assert 'Type "Bar" not found in document' in str(excinfo.value) def test_unknown_query_type(): body = """ schema { query: Wat } type Hello { str: String } """ doc = parse(body) with raises(Exception) as excinfo: build_ast_schema(doc) assert 'Specified query type "Wat" not found in document' in str(excinfo.value) def test_unknown_mutation_type(): body = """ schema { query: Hello mutation: Wat } type Hello { str: String } """ doc = parse(body) with raises(Exception) as excinfo: build_ast_schema(doc) assert 'Specified mutation type "Wat" not found in document' in str(excinfo.value) def test_unknown_subscription_type(): body = """ schema { query: Hello mutation: Wat subscription: Awesome } type Hello { str: String } type Wat { str: String } """ doc = parse(body) with raises(Exception) as excinfo: build_ast_schema(doc) assert 'Specified subscription type "Awesome" not found in document' in str( excinfo.value ) def test_does_not_consider_query_names(): body = """ schema { query: Foo } type Hello { str: String } """ doc = parse(body) with raises(Exception) as excinfo: build_ast_schema(doc) assert 'Specified query type "Foo" not found in document' in str(excinfo.value) def test_does_not_consider_fragment_names(): body = """schema { query: Foo } fragment Foo on Type { field } """ doc = parse(body) with raises(Exception) as excinfo: build_ast_schema(doc) assert 'Specified query type "Foo" not found in document' in str(excinfo.value) graphql-core-legacy-2.3.2/graphql/utils/tests/test_build_client_schema.py000066400000000000000000000620761365661746200267250ustar00rootroot00000000000000from collections import OrderedDict from pytest import raises from graphql import graphql from graphql.error import format_error from graphql.type import ( GraphQLArgument, GraphQLBoolean, GraphQLEnumType, GraphQLEnumValue, GraphQLField, GraphQLFloat, GraphQLID, GraphQLInputObjectField, GraphQLInputObjectType, GraphQLInt, GraphQLInterfaceType, GraphQLList, GraphQLNonNull, GraphQLObjectType, GraphQLScalarType, GraphQLSchema, GraphQLString, GraphQLUnionType, ) from graphql.type.directives import GraphQLDirective from graphql.utils.build_client_schema import build_client_schema from graphql.utils.introspection_query import introspection_query from ...pyutils.contain_subset import contain_subset def _test_schema(server_schema): initial_introspection = graphql(server_schema, introspection_query) client_schema = build_client_schema(initial_introspection.data) second_introspection = graphql(client_schema, introspection_query) assert contain_subset( initial_introspection.data, second_introspection.data ), "\n{}\n{}".format(initial_introspection.data, second_introspection.data) return client_schema def test_it_builds_a_simple_schema(): schema = GraphQLSchema( query=GraphQLObjectType( name="Simple", description="This is a simple type", fields={ "string": GraphQLField( GraphQLString, description="This is a string field" ) }, ) ) _test_schema(schema) def test_builds_a_simple_schema_with_both_operation_types(): QueryType = GraphQLObjectType( name="QueryType", description="This is a simple query type", fields={ "string": GraphQLField(GraphQLString, description="This is a string field.") }, ) MutationType = GraphQLObjectType( name="MutationType", description="This is a simple mutation type", fields={ "setString": GraphQLField( GraphQLString, description="Set the string field", args={"value": GraphQLArgument(GraphQLString)}, ) }, ) SubscriptionType = GraphQLObjectType( name="SubscriptionType", description="This is a simple subscription type", fields={ "string": GraphQLField( type_=GraphQLString, description="This is a string field" ) }, ) schema = GraphQLSchema(QueryType, MutationType, SubscriptionType) _test_schema(schema) def test_uses_built_in_scalars_when_possible(): customScalar = GraphQLScalarType(name="CustomScalar", serialize=lambda: None) schema = GraphQLSchema( query=GraphQLObjectType( name="Scalars", fields=OrderedDict( [ ("int", GraphQLField(GraphQLInt)), ("float", GraphQLField(GraphQLFloat)), ("string", GraphQLField(GraphQLString)), ("boolean", GraphQLField(GraphQLBoolean)), ("id", GraphQLField(GraphQLID)), ("custom", GraphQLField(customScalar)), ] ), ) ) client_schema = _test_schema(schema) assert client_schema.get_type("Int") == GraphQLInt assert client_schema.get_type("Float") == GraphQLFloat assert client_schema.get_type("String") == GraphQLString assert client_schema.get_type("Boolean") == GraphQLBoolean assert client_schema.get_type("ID") == GraphQLID assert client_schema.get_type("CustomScalar") != customScalar def test_builds_a_schema_with_a_recursive_type_reference(): recurType = GraphQLObjectType( name="Recur", fields=lambda: {"recur": GraphQLField(recurType)} ) schema = GraphQLSchema(query=recurType) _test_schema(schema) def test_builds_a_schema_with_a_circular_type_reference(): DogType = GraphQLObjectType( name="Dog", fields=lambda: {"bestFriend": GraphQLField(HumanType)} ) HumanType = GraphQLObjectType( name="Human", fields=lambda: {"bestFriend": GraphQLField(DogType)} ) schema = GraphQLSchema( query=GraphQLObjectType( name="Circular", fields=OrderedDict( [("dog", GraphQLField(DogType)), ("human", GraphQLField(HumanType))] ), ) ) _test_schema(schema) def test_builds_a_schema_with_an_interface(): FriendlyType = GraphQLInterfaceType( name="Friendly", resolve_type=lambda: None, fields=lambda: { "bestFriend": GraphQLField( FriendlyType, description="The best friend of this friendly thing." ) }, ) DogType = GraphQLObjectType( name="DogType", interfaces=[FriendlyType], fields=lambda: {"bestFriend": GraphQLField(FriendlyType)}, ) HumanType = GraphQLObjectType( name="Human", interfaces=[FriendlyType], fields=lambda: {"bestFriend": GraphQLField(FriendlyType)}, ) schema = GraphQLSchema( query=GraphQLObjectType( name="WithInterface", fields={"friendly": GraphQLField(FriendlyType)} ), types=[DogType, HumanType], ) _test_schema(schema) def test_builds_a_schema_with_an_implicit_interface(): FriendlyType = GraphQLInterfaceType( name="Friendly", resolve_type=lambda: None, fields=lambda: { "bestFriend": GraphQLField( FriendlyType, description="The best friend of this friendly thing." ) }, ) DogType = GraphQLObjectType( name="DogType", interfaces=[FriendlyType], fields=lambda: {"bestFriend": GraphQLField(DogType)}, ) schema = GraphQLSchema( query=GraphQLObjectType( name="WithInterface", fields={"dog": GraphQLField(DogType)} ) ) _test_schema(schema) def test_builds_a_schema_with_a_union(): DogType = GraphQLObjectType( name="Dog", fields=lambda: {"bestFriend": GraphQLField(FriendlyType)} ) HumanType = GraphQLObjectType( name="Human", fields=lambda: {"bestFriend": GraphQLField(FriendlyType)} ) FriendlyType = GraphQLUnionType( name="Friendly", resolve_type=lambda: None, types=[DogType, HumanType] ) schema = GraphQLSchema( query=GraphQLObjectType( name="WithUnion", fields={"friendly": GraphQLField(FriendlyType)} ) ) _test_schema(schema) def test_builds_a_schema_with_complex_field_values(): schema = GraphQLSchema( query=GraphQLObjectType( name="ComplexFields", fields=OrderedDict( [ ("string", GraphQLField(GraphQLString)), ("listOfString", GraphQLField(GraphQLList(GraphQLString))), ("nonNullString", GraphQLField(GraphQLNonNull(GraphQLString))), ( "nonNullListOfString", GraphQLField(GraphQLNonNull(GraphQLList(GraphQLString))), ), ( "nonNullListOfNonNullString", GraphQLField( GraphQLNonNull(GraphQLList(GraphQLNonNull(GraphQLString))) ), ), ] ), ) ) _test_schema(schema) def test_builds_a_schema_with_field_arguments(): schema = GraphQLSchema( query=GraphQLObjectType( name="ArgFields", fields=OrderedDict( [ ( "one", GraphQLField( GraphQLString, description="A field with a single arg", args={ "intArg": GraphQLArgument( GraphQLInt, description="This is an int arg" ) }, ), ), ( "two", GraphQLField( GraphQLString, description="A field with two args", args=OrderedDict( [ ( "listArg", GraphQLArgument( GraphQLList(GraphQLInt), description="This is a list of int arg", ), ), ( "requiredArg", GraphQLArgument( GraphQLNonNull(GraphQLBoolean), description="This is a required arg", ), ), ] ), ), ), ] ), ) ) _test_schema(schema) def test_builds_a_schema_with_an_enum(): FoodEnum = GraphQLEnumType( name="Food", description="Varieties of food stuffs", values=OrderedDict( [ ( "VEGETABLES", GraphQLEnumValue(1, description="Foods that are vegetables."), ), ("FRUITS", GraphQLEnumValue(2, description="Foods that are fruits.")), ("OILS", GraphQLEnumValue(3, description="Foods that are oils.")), ("DAIRY", GraphQLEnumValue(4, description="Foods that are dairy.")), ("MEAT", GraphQLEnumValue(5, description="Foods that are meat.")), ] ), ) schema = GraphQLSchema( query=GraphQLObjectType( name="EnumFields", fields={ "food": GraphQLField( FoodEnum, description="Repeats the arg you give it", args={ "kind": GraphQLArgument( FoodEnum, description="what kind of food?" ) }, ) }, ) ) client_schema = _test_schema(schema) clientFoodEnum = client_schema.get_type("Food") assert isinstance(clientFoodEnum, GraphQLEnumType) assert clientFoodEnum.values == [ GraphQLEnumValue( name="VEGETABLES", value="VEGETABLES", description="Foods that are vegetables.", deprecation_reason=None, ), GraphQLEnumValue( name="FRUITS", value="FRUITS", description="Foods that are fruits.", deprecation_reason=None, ), GraphQLEnumValue( name="OILS", value="OILS", description="Foods that are oils.", deprecation_reason=None, ), GraphQLEnumValue( name="DAIRY", value="DAIRY", description="Foods that are dairy.", deprecation_reason=None, ), GraphQLEnumValue( name="MEAT", value="MEAT", description="Foods that are meat.", deprecation_reason=None, ), ] def test_builds_a_schema_with_an_input_object(): AddressType = GraphQLInputObjectType( name="Address", description="An input address", fields=OrderedDict( [ ( "street", GraphQLInputObjectField( GraphQLNonNull(GraphQLString), description="What street is this address?", ), ), ( "city", GraphQLInputObjectField( GraphQLNonNull(GraphQLString), description="The city the address is within?", ), ), ( "country", GraphQLInputObjectField( GraphQLString, description="The country (blank will assume USA).", default_value="USA", ), ), ] ), ) schema = GraphQLSchema( query=GraphQLObjectType( name="HasInputObjectFields", fields={ "geocode": GraphQLField( description="Get a geocode from an address", type_=GraphQLString, args={ "address": GraphQLArgument( description="The address to lookup", type_=AddressType ) }, ) }, ) ) _test_schema(schema) def test_builds_a_schema_with_field_arguments_with_default_values(): GeoType = GraphQLInputObjectType( name="Geo", fields=OrderedDict( [ ("lat", GraphQLInputObjectField(GraphQLFloat)), ("lon", GraphQLInputObjectField(GraphQLFloat)), ] ), ) schema = GraphQLSchema( query=GraphQLObjectType( name="ArgFields", fields=OrderedDict( [ ( "defaultInt", GraphQLField( GraphQLString, args={ "intArg": GraphQLArgument(GraphQLInt, default_value=10) }, ), ), ( "defaultList", GraphQLField( GraphQLString, args={ "listArg": GraphQLArgument( GraphQLList(GraphQLInt), default_value=[1, 2, 3] ) }, ), ), ( "defaultObject", GraphQLField( GraphQLString, args={ "objArg": GraphQLArgument( GeoType, default_value=OrderedDict( [("lat", 37.485), ("lon", -122.148)] ), ) }, ), ), ] ), ) ) _test_schema(schema) def test_builds_a_schema_with_custom_directives(): schema = GraphQLSchema( query=GraphQLObjectType( name="Simple", description="This is a simple type", fields={ "string": GraphQLField( type_=GraphQLString, description="This is a string field" ) }, ), directives=[ GraphQLDirective( name="customDirective", description="This is a custom directive", locations=["FIELD"], ) ], ) _test_schema(schema) def test_builds_a_schema_with_legacy_directives(): old_introspection = { "__schema": { "queryType": {"name": "Simple"}, "types": [ { "name": "Simple", "kind": "OBJECT", "fields": [ {"name": "simple", "args": [], "type": {"name": "Simple"}} ], "interfaces": [], } ], "directives": [ {"name": "Old1", "args": [], "onField": True}, {"name": "Old2", "args": [], "onFragment": True}, {"name": "Old3", "args": [], "onOperation": True}, {"name": "Old4", "args": [], "onField": True, "onFragment": True}, ], } } new_introspection = { "__schema": { "directives": [ {"name": "Old1", "args": [], "locations": ["FIELD"]}, { "name": "Old2", "args": [], "locations": [ "FRAGMENT_DEFINITION", "FRAGMENT_SPREAD", "INLINE_FRAGMENT", ], }, { "name": "Old3", "args": [], "locations": ["QUERY", "MUTATION", "SUBSCRIPTION"], }, { "name": "Old4", "args": [], "locations": [ "FIELD", "FRAGMENT_DEFINITION", "FRAGMENT_SPREAD", "INLINE_FRAGMENT", ], }, ] } } client_schema = build_client_schema(old_introspection) second_introspection = graphql(client_schema, introspection_query).data assert contain_subset(new_introspection, second_introspection) def test_builds_a_schema_aware_of_deprecation(): schema = GraphQLSchema( query=GraphQLObjectType( name="Simple", description="This is a simple type", fields=OrderedDict( [ ( "shinyString", GraphQLField( type_=GraphQLString, description="This is a shiny string field", ), ), ( "deprecatedString", GraphQLField( type_=GraphQLString, description="This is a deprecated string field", deprecation_reason="Use shinyString", ), ), ( "color", GraphQLField( type_=GraphQLEnumType( name="Color", values=OrderedDict( [ ( "RED", GraphQLEnumValue(description="So rosy"), ), ( "GREEN", GraphQLEnumValue(description="So grassy"), ), ( "BLUE", GraphQLEnumValue(description="So calming"), ), ( "MAUVE", GraphQLEnumValue( description="So sickening", deprecation_reason="No longer in fashion", ), ), ] ), ) ), ), ] ), ) ) _test_schema(schema) def test_cannot_use_client_schema_for_general_execution(): customScalar = GraphQLScalarType(name="CustomScalar", serialize=lambda: None) schema = GraphQLSchema( query=GraphQLObjectType( name="Query", fields={ "foo": GraphQLField( GraphQLString, args=OrderedDict( [ ("custom1", GraphQLArgument(customScalar)), ("custom2", GraphQLArgument(customScalar)), ] ), ) }, ) ) introspection = graphql(schema, introspection_query) client_schema = build_client_schema(introspection.data) class data: foo = "bar" result = graphql( client_schema, "query NoNo($v: CustomScalar) { foo(custom1: 123, custom2: $v) }", data, {"v": "baz"}, ) assert result.data == {"foo": None} assert [format_error(e) for e in result.errors] == [ { "locations": [{"column": 32, "line": 1}], "message": "Client Schema cannot be used for execution.", "path": ["foo"], } ] def test_throws_when_given_empty_types(): incomplete_introspection = { "__schema": {"queryType": {"name": "QueryType"}, "types": []} } with raises(Exception) as excinfo: build_client_schema(incomplete_introspection) assert ( str(excinfo.value) == "Invalid or incomplete schema, unknown type: QueryType. Ensure that a full " "introspection query is used in order to build a client schema." ) def test_throws_when_missing_kind(): incomplete_introspection = { "__schema": { "queryType": {"name": "QueryType"}, "types": [{"name": "QueryType"}], } } with raises(Exception) as excinfo: build_client_schema(incomplete_introspection) assert ( str(excinfo.value) == "Invalid or incomplete schema, unknown kind: None. Ensure that a full " "introspection query is used in order to build a client schema." ) def test_succeeds_on_smaller_equals_than_7_deep_lists(): schema = GraphQLSchema( query=GraphQLObjectType( name="Query", fields={ "foo": GraphQLField( GraphQLNonNull( GraphQLList( GraphQLNonNull( GraphQLList( GraphQLNonNull( GraphQLList(GraphQLNonNull(GraphQLString)) ) ) ) ) ) ) }, ) ) introspection = graphql(schema, introspection_query) build_client_schema(introspection.data) def test_fails_on_very_deep_lists(): schema = GraphQLSchema( query=GraphQLObjectType( name="Query", fields={ "foo": GraphQLField( GraphQLList( GraphQLList( GraphQLList( GraphQLList( GraphQLList( GraphQLList( GraphQLList( GraphQLList(GraphQLList(GraphQLString)) ) ) ) ) ) ) ) ) }, ) ) introspection = graphql(schema, introspection_query) with raises(Exception) as excinfo: build_client_schema(introspection.data) assert str(excinfo.value) == "Decorated type deeper than introspection query." def test_fails_on_a_very_deep_non_null(): schema = GraphQLSchema( query=GraphQLObjectType( name="Query", fields={ "foo": GraphQLField( GraphQLList( GraphQLList( GraphQLList( GraphQLList( GraphQLList( GraphQLList( GraphQLList( GraphQLList( GraphQLNonNull(GraphQLString) ) ) ) ) ) ) ) ) ) }, ) ) introspection = graphql(schema, introspection_query) with raises(Exception) as excinfo: build_client_schema(introspection.data) assert str(excinfo.value) == "Decorated type deeper than introspection query." graphql-core-legacy-2.3.2/graphql/utils/tests/test_concat_ast.py000066400000000000000000000010241365661746200250500ustar00rootroot00000000000000from graphql import Source, parse from graphql.language.printer import print_ast from graphql.utils.concat_ast import concat_ast def test_it_concatenates_two_acts_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) == """{ a b ...Frag } fragment Frag on T { c } """ ) graphql-core-legacy-2.3.2/graphql/utils/tests/test_extend_schema.py000066400000000000000000000403441365661746200255510ustar00rootroot00000000000000from collections import OrderedDict from pytest import raises from graphql import parse from graphql.execution import execute from graphql.type import ( GraphQLArgument, GraphQLEnumType, GraphQLEnumValue, GraphQLField, GraphQLID, GraphQLInterfaceType, GraphQLList, GraphQLNonNull, GraphQLObjectType, GraphQLSchema, GraphQLString, GraphQLUnionType, ) from graphql.utils.extend_schema import extend_schema from graphql.utils.schema_printer import print_schema # Test schema. SomeInterfaceType = GraphQLInterfaceType( name="SomeInterface", resolve_type=lambda: FooType, fields=lambda: OrderedDict( [ ("name", GraphQLField(GraphQLString)), ("some", GraphQLField(SomeInterfaceType)), ] ), ) FooType = GraphQLObjectType( name="Foo", interfaces=[SomeInterfaceType], fields=lambda: OrderedDict( [ ("name", GraphQLField(GraphQLString)), ("some", GraphQLField(SomeInterfaceType)), ("tree", GraphQLField(GraphQLNonNull(GraphQLList(FooType)))), ] ), ) BarType = GraphQLObjectType( name="Bar", interfaces=[SomeInterfaceType], fields=lambda: OrderedDict( [ ("name", GraphQLField(GraphQLString)), ("some", GraphQLField(SomeInterfaceType)), ("foo", GraphQLField(FooType)), ] ), ) BizType = GraphQLObjectType( name="Biz", fields=lambda: OrderedDict([("fizz", GraphQLField(GraphQLString))]) ) SomeUnionType = GraphQLUnionType( name="SomeUnion", resolve_type=lambda: FooType, types=[FooType, BizType] ) SomeEnumType = GraphQLEnumType( name="SomeEnum", values=OrderedDict([("ONE", GraphQLEnumValue(1)), ("TWO", GraphQLEnumValue(2))]), ) test_schema = GraphQLSchema( query=GraphQLObjectType( name="Query", fields=lambda: OrderedDict( [ ("foo", GraphQLField(FooType)), ("someUnion", GraphQLField(SomeUnionType)), ("someEnum", GraphQLField(SomeEnumType)), ( "someInterface", GraphQLField( SomeInterfaceType, args={"id": GraphQLArgument(GraphQLNonNull(GraphQLID))}, ), ), ] ), ), types=[FooType, BarType], ) def test_returns_original_schema_if_no_type_definitions(): ast = parse("{ field }") extended_schema = extend_schema(test_schema, ast) assert extended_schema == test_schema def test_extends_without_altering_original_schema(): ast = parse( """ extend type Query { newField: String } """ ) original_print = print_schema(test_schema) extended_schema = extend_schema(test_schema, ast) assert extend_schema != test_schema assert print_schema(test_schema) == original_print assert "newField" in print_schema(extended_schema) assert "newField" not in print_schema(test_schema) def test_cannot_be_used_for_execution(): ast = parse( """ extend type Query { newField: String } """ ) extended_schema = extend_schema(test_schema, ast) clientQuery = parse("{ newField }") result = execute(extended_schema, clientQuery, object()) assert result.data["newField"] is None assert str(result.errors[0]) == "Client Schema cannot be used for execution." def test_extends_objects_by_adding_new_fields(): ast = parse( """ extend type Foo { newField: String } """ ) original_print = print_schema(test_schema) extended_schema = extend_schema(test_schema, ast) assert extended_schema != test_schema assert print_schema(test_schema) == original_print # print original_print assert ( print_schema(extended_schema) == """schema { query: Query } type Bar implements SomeInterface { name: String some: SomeInterface foo: Foo } type Biz { fizz: String } type Foo implements SomeInterface { name: String some: SomeInterface tree: [Foo]! newField: String } type Query { foo: Foo someUnion: SomeUnion someEnum: SomeEnum someInterface(id: ID!): SomeInterface } enum SomeEnum { ONE TWO } interface SomeInterface { name: String some: SomeInterface } union SomeUnion = Foo | Biz """ ) def test_extends_objects_by_adding_new_unused_types(): ast = parse( """ type Unused { someField: String } """ ) original_print = print_schema(test_schema) extended_schema = extend_schema(test_schema, ast) assert extended_schema != test_schema assert print_schema(test_schema) == original_print # print original_print assert ( print_schema(extended_schema) == """schema { query: Query } type Bar implements SomeInterface { name: String some: SomeInterface foo: Foo } type Biz { fizz: String } type Foo implements SomeInterface { name: String some: SomeInterface tree: [Foo]! } type Query { foo: Foo someUnion: SomeUnion someEnum: SomeEnum someInterface(id: ID!): SomeInterface } enum SomeEnum { ONE TWO } interface SomeInterface { name: String some: SomeInterface } union SomeUnion = Foo | Biz type Unused { someField: String } """ ) def test_extends_objects_by_adding_new_fields_with_arguments(): ast = parse( """ extend type Foo { newField(arg1: String, arg2: NewInputObj!): String } input NewInputObj { field1: Int field2: [Float] field3: String! } """ ) original_print = print_schema(test_schema) extended_schema = extend_schema(test_schema, ast) assert extended_schema != test_schema assert print_schema(test_schema) == original_print assert ( print_schema(extended_schema) == """schema { query: Query } type Bar implements SomeInterface { name: String some: SomeInterface foo: Foo } type Biz { fizz: String } type Foo implements SomeInterface { name: String some: SomeInterface tree: [Foo]! newField(arg1: String, arg2: NewInputObj!): String } input NewInputObj { field1: Int field2: [Float] field3: String! } type Query { foo: Foo someUnion: SomeUnion someEnum: SomeEnum someInterface(id: ID!): SomeInterface } enum SomeEnum { ONE TWO } interface SomeInterface { name: String some: SomeInterface } union SomeUnion = Foo | Biz """ ) def test_extends_objects_by_adding_new_fields_with_existing_types(): ast = parse( """ extend type Foo { newField(arg1: SomeEnum!): SomeEnum } """ ) original_print = print_schema(test_schema) extended_schema = extend_schema(test_schema, ast) assert extended_schema != test_schema assert print_schema(test_schema) == original_print assert ( print_schema(extended_schema) == """schema { query: Query } type Bar implements SomeInterface { name: String some: SomeInterface foo: Foo } type Biz { fizz: String } type Foo implements SomeInterface { name: String some: SomeInterface tree: [Foo]! newField(arg1: SomeEnum!): SomeEnum } type Query { foo: Foo someUnion: SomeUnion someEnum: SomeEnum someInterface(id: ID!): SomeInterface } enum SomeEnum { ONE TWO } interface SomeInterface { name: String some: SomeInterface } union SomeUnion = Foo | Biz """ ) def test_extends_objects_by_adding_implemented_interfaces(): ast = parse( """ extend type Biz implements SomeInterface { name: String some: SomeInterface } """ ) original_print = print_schema(test_schema) extended_schema = extend_schema(test_schema, ast) assert extended_schema != test_schema assert print_schema(test_schema) == original_print assert ( print_schema(extended_schema) == """schema { query: Query } type Bar implements SomeInterface { name: String some: SomeInterface foo: Foo } type Biz implements SomeInterface { fizz: String name: String some: SomeInterface } type Foo implements SomeInterface { name: String some: SomeInterface tree: [Foo]! } type Query { foo: Foo someUnion: SomeUnion someEnum: SomeEnum someInterface(id: ID!): SomeInterface } enum SomeEnum { ONE TWO } interface SomeInterface { name: String some: SomeInterface } union SomeUnion = Foo | Biz """ ) def test_extends_objects_by_adding_implemented_interfaces_2(): ast = parse( """ extend type Foo { newObject: NewObject newInterface: NewInterface newUnion: NewUnion newScalar: NewScalar newEnum: NewEnum newTree: [Foo]! } type NewObject implements NewInterface { baz: String } type NewOtherObject { fizz: Int } interface NewInterface { baz: String } union NewUnion = NewObject | NewOtherObject scalar NewScalar enum NewEnum { OPTION_A OPTION_B } """ ) original_print = print_schema(test_schema) extended_schema = extend_schema(test_schema, ast) assert extended_schema != test_schema assert print_schema(test_schema) == original_print assert ( print_schema(extended_schema) == """schema { query: Query } type Bar implements SomeInterface { name: String some: SomeInterface foo: Foo } type Biz { fizz: String } type Foo implements SomeInterface { name: String some: SomeInterface tree: [Foo]! newObject: NewObject newInterface: NewInterface newUnion: NewUnion newScalar: NewScalar newEnum: NewEnum newTree: [Foo]! } enum NewEnum { OPTION_A OPTION_B } interface NewInterface { baz: String } type NewObject implements NewInterface { baz: String } type NewOtherObject { fizz: Int } scalar NewScalar union NewUnion = NewObject | NewOtherObject type Query { foo: Foo someUnion: SomeUnion someEnum: SomeEnum someInterface(id: ID!): SomeInterface } enum SomeEnum { ONE TWO } interface SomeInterface { name: String some: SomeInterface } union SomeUnion = Foo | Biz """ ) def test_extends_objects_by_adding_implemented_new_interfaces(): ast = parse( """ extend type Foo implements NewInterface { baz: String } interface NewInterface { baz: String } """ ) original_print = print_schema(test_schema) extended_schema = extend_schema(test_schema, ast) assert extended_schema != test_schema assert print_schema(test_schema) == original_print assert ( print_schema(extended_schema) == """schema { query: Query } type Bar implements SomeInterface { name: String some: SomeInterface foo: Foo } type Biz { fizz: String } type Foo implements SomeInterface, NewInterface { name: String some: SomeInterface tree: [Foo]! baz: String } interface NewInterface { baz: String } type Query { foo: Foo someUnion: SomeUnion someEnum: SomeEnum someInterface(id: ID!): SomeInterface } enum SomeEnum { ONE TWO } interface SomeInterface { name: String some: SomeInterface } union SomeUnion = Foo | Biz """ ) def test_extends_objects_multiple_times(): ast = parse( """ extend type Biz implements NewInterface { buzz: String } extend type Biz implements SomeInterface { name: String some: SomeInterface newFieldA: Int } extend type Biz { newFieldA: Int newFieldB: Float } interface NewInterface { buzz: String } """ ) original_print = print_schema(test_schema) extended_schema = extend_schema(test_schema, ast) assert extended_schema != test_schema assert print_schema(test_schema) == original_print assert ( print_schema(extended_schema) == """schema { query: Query } type Bar implements SomeInterface { name: String some: SomeInterface foo: Foo } type Biz implements NewInterface, SomeInterface { fizz: String buzz: String name: String some: SomeInterface newFieldA: Int newFieldB: Float } type Foo implements SomeInterface { name: String some: SomeInterface tree: [Foo]! } interface NewInterface { buzz: String } type Query { foo: Foo someUnion: SomeUnion someEnum: SomeEnum someInterface(id: ID!): SomeInterface } enum SomeEnum { ONE TWO } interface SomeInterface { name: String some: SomeInterface } union SomeUnion = Foo | Biz """ ) def test_may_extend_mutations_and_subscriptions(): mutationSchema = GraphQLSchema( query=GraphQLObjectType( "Query", fields=lambda: {"queryField": GraphQLField(GraphQLString)} ), mutation=GraphQLObjectType( "Mutation", fields={"mutationField": GraphQLField(GraphQLString)} ), subscription=GraphQLObjectType( "Subscription", fields={"subscriptionField": GraphQLField(GraphQLString)} ), ) ast = parse( """ extend type Query { newQueryField: Int } extend type Mutation { newMutationField: Int } extend type Subscription { newSubscriptionField: Int } """ ) original_print = print_schema(mutationSchema) extended_schema = extend_schema(mutationSchema, ast) assert extended_schema != mutationSchema assert print_schema(mutationSchema) == original_print assert ( print_schema(extended_schema) == """schema { query: Query mutation: Mutation subscription: Subscription } type Mutation { mutationField: String newMutationField: Int } type Query { queryField: String newQueryField: Int } type Subscription { subscriptionField: String newSubscriptionField: Int } """ ) def test_does_not_allow_replacing_an_existing_type(): ast = parse( """ type Bar { baz: String } """ ) with raises(Exception) as exc_info: extend_schema(test_schema, ast) assert str(exc_info.value) == ( 'Type "Bar" already exists in the schema. It cannot also be defined ' + "in this type definition." ) def test_does_not_allow_replacing_an_existing_field(): ast = parse( """ extend type Bar { foo: Foo } """ ) with raises(Exception) as exc_info: extend_schema(test_schema, ast) assert str(exc_info.value) == ( 'Field "Bar.foo" already exists in the schema. It cannot also be ' + "defined in this type extension." ) def test_does_not_allow_replacing_an_existing_interface(): ast = parse( """ extend type Foo implements SomeInterface { otherField: String } """ ) with raises(Exception) as exc_info: extend_schema(test_schema, ast) assert str(exc_info.value) == ( 'Type "Foo" already implements "SomeInterface". It cannot also be ' + "implemented in this type extension." ) def test_does_not_allow_referencing_an_unknown_type(): ast = parse( """ extend type Bar { quix: Quix } """ ) with raises(Exception) as exc_info: extend_schema(test_schema, ast) assert str(exc_info.value) == ( 'Unknown type: "Quix". Ensure that this type exists either in the ' + "original schema, or is added in a type definition." ) def test_does_not_allow_extending_an_unknown_type(): ast = parse( """ extend type UnknownType { baz: String } """ ) with raises(Exception) as exc_info: extend_schema(test_schema, ast) assert str(exc_info.value) == ( 'Cannot extend type "UnknownType" because it does not exist in the ' + "existing schema." ) def test_does_not_allow_extending_an_interface(): ast = parse( """ extend type SomeInterface { baz: String } """ ) with raises(Exception) as exc_info: extend_schema(test_schema, ast) assert str(exc_info.value) == 'Cannot extend non-object type "SomeInterface".' def test_does_not_allow_extending_a_scalar(): ast = parse( """ extend type String { baz: String } """ ) with raises(Exception) as exc_info: extend_schema(test_schema, ast) assert str(exc_info.value) == 'Cannot extend non-object type "String".' graphql-core-legacy-2.3.2/graphql/utils/tests/test_get_operation_ast.py000066400000000000000000000040221365661746200264410ustar00rootroot00000000000000from graphql import parse from graphql.utils.get_operation_ast import get_operation_ast def test_gets_an_operation_from_a_simple_document(): doc = parse("{ field }") assert get_operation_ast(doc) == doc.definitions[0] def test_gets_an_operation_from_a_document_with_named_mutation_operation(): doc = parse("mutation Test { field }") assert get_operation_ast(doc) == doc.definitions[0] def test_gets_an_operation_from_a_document_with_named_subscription_operation(): doc = parse("subscription Test { field }") assert get_operation_ast(doc) == doc.definitions[0] def test_does_not_get_missing_operation(): doc = parse("{ field } mutation Test { field }") assert not get_operation_ast(doc) def test_does_not_get_ambiguous_unnamed_operation(): doc = parse("{ field } mutation TestM { field } subscription TestSub { field }") assert not get_operation_ast(doc) def test_does_not_get_ambiguous_named_operation(): doc = parse( "query TestQ { field } mutation TestM { field } subscription TestSub { field }" ) assert not get_operation_ast(doc) def test_does_not_get_misnamed_operation(): doc = parse( "query TestQ { field } mutation TestM { field } subscription TestSub { field }" ) assert not get_operation_ast(doc, "Unknown") def test_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] def test_does_not_get_fragment(): doc = parse("fragment Foo on Type { field }") assert not get_operation_ast(doc) assert not get_operation_ast(doc, "Foo") def test_does_not_get_fragment_with_same_name_query(): doc = parse("fragment Foo on Type { field } query Foo { field }") assert get_operation_ast(doc) == doc.definitions[1] assert get_operation_ast(doc, "Foo") == doc.definitions[1] graphql-core-legacy-2.3.2/graphql/utils/tests/test_quoted_or_list.py000066400000000000000000000011141365661746200257660ustar00rootroot00000000000000from pytest import raises from ..quoted_or_list import quoted_or_list def test_does_not_accept_an_empty_list(): with raises(StopIteration): quoted_or_list([]) def test_returns_single_quoted_item(): assert quoted_or_list(["A"]) == '"A"' def test_returns_two_item_list(): assert quoted_or_list(["A", "B"]) == '"A" or "B"' def test_returns_comma_separated_many_item_list(): assert quoted_or_list(["A", "B", "C"]) == '"A", "B" or "C"' def test_limits_to_five_items(): assert quoted_or_list(["A", "B", "C", "D", "E", "F"]) == '"A", "B", "C", "D" or "E"' graphql-core-legacy-2.3.2/graphql/utils/tests/test_schema_printer.py000066400000000000000000000300151365661746200257370ustar00rootroot00000000000000from collections import OrderedDict from graphql.type import ( GraphQLBoolean, GraphQLEnumType, GraphQLInputObjectType, GraphQLInt, GraphQLInterfaceType, GraphQLList, GraphQLNonNull, GraphQLObjectType, GraphQLScalarType, GraphQLSchema, GraphQLString, GraphQLUnionType, ) from graphql.type.definition import ( GraphQLArgument, GraphQLEnumValue, GraphQLField, GraphQLInputObjectField, ) from graphql.utils.schema_printer import print_introspection_schema, print_schema def print_for_test(schema): return "\n" + print_schema(schema) def print_single_field_schema(field_config): Root = GraphQLObjectType(name="Root", fields={"singleField": field_config}) return print_for_test(GraphQLSchema(Root)) def test_prints_string_field(): output = print_single_field_schema(GraphQLField(GraphQLString)) assert ( output == """ schema { query: Root } type Root { singleField: String } """ ) def test_prints_list_string_field(): output = print_single_field_schema(GraphQLField(GraphQLList(GraphQLString))) assert ( output == """ schema { query: Root } type Root { singleField: [String] } """ ) def test_prints_non_null_list_string_field(): output = print_single_field_schema( GraphQLField(GraphQLNonNull(GraphQLList(GraphQLString))) ) assert ( output == """ schema { query: Root } type Root { singleField: [String]! } """ ) def test_prints_list_non_null_string_field(): output = print_single_field_schema( GraphQLField(GraphQLList(GraphQLNonNull(GraphQLString))) ) assert ( output == """ schema { query: Root } type Root { singleField: [String!] } """ ) def test_prints_non_null_list_non_null_string_field(): output = print_single_field_schema( GraphQLField(GraphQLNonNull(GraphQLList(GraphQLNonNull(GraphQLString)))) ) assert ( output == """ schema { query: Root } type Root { singleField: [String!]! } """ ) def test_prints_object_field(): FooType = GraphQLObjectType(name="Foo", fields={"str": GraphQLField(GraphQLString)}) Root = GraphQLObjectType(name="Root", fields={"foo": GraphQLField(FooType)}) Schema = GraphQLSchema(Root) output = print_for_test(Schema) assert ( output == """ schema { query: Root } type Foo { str: String } type Root { foo: Foo } """ ) def test_prints_string_field_with_int_arg(): output = print_single_field_schema( GraphQLField(type_=GraphQLString, args={"argOne": GraphQLArgument(GraphQLInt)}) ) assert ( output == """ schema { query: Root } type Root { singleField(argOne: Int): String } """ ) def test_prints_string_field_with_int_arg_with_default(): output = print_single_field_schema( GraphQLField( type_=GraphQLString, args={"argOne": GraphQLArgument(GraphQLInt, default_value=2)}, ) ) assert ( output == """ schema { query: Root } type Root { singleField(argOne: Int = 2): String } """ ) def test_prints_string_field_with_non_null_int_arg(): output = print_single_field_schema( GraphQLField( type_=GraphQLString, args={"argOne": GraphQLArgument(GraphQLNonNull(GraphQLInt))}, ) ) assert ( output == """ schema { query: Root } type Root { singleField(argOne: Int!): String } """ ) def test_prints_string_field_with_multiple_args(): output = print_single_field_schema( GraphQLField( type_=GraphQLString, args=OrderedDict( [ ("argOne", GraphQLArgument(GraphQLInt)), ("argTwo", GraphQLArgument(GraphQLString)), ] ), ) ) assert ( output == """ schema { query: Root } type Root { singleField(argOne: Int, argTwo: String): String } """ ) def test_prints_string_field_with_multiple_args_first_is_default(): output = print_single_field_schema( GraphQLField( type_=GraphQLString, args=OrderedDict( [ ("argOne", GraphQLArgument(GraphQLInt, default_value=1)), ("argTwo", GraphQLArgument(GraphQLString)), ("argThree", GraphQLArgument(GraphQLBoolean)), ] ), ) ) assert ( output == """ schema { query: Root } type Root { singleField(argOne: Int = 1, argTwo: String, argThree: Boolean): String } """ ) def test_prints_string_field_with_multiple_args_second_is_default(): output = print_single_field_schema( GraphQLField( type_=GraphQLString, args=OrderedDict( [ ("argOne", GraphQLArgument(GraphQLInt)), ("argTwo", GraphQLArgument(GraphQLString, default_value="foo")), ("argThree", GraphQLArgument(GraphQLBoolean)), ] ), ) ) assert ( output == """ schema { query: Root } type Root { singleField(argOne: Int, argTwo: String = "foo", argThree: Boolean): String } """ ) def test_prints_string_field_with_multiple_args_last_is_default(): output = print_single_field_schema( GraphQLField( type_=GraphQLString, args=OrderedDict( [ ("argOne", GraphQLArgument(GraphQLInt)), ("argTwo", GraphQLArgument(GraphQLString)), ("argThree", GraphQLArgument(GraphQLBoolean, default_value=False)), ] ), ) ) assert ( output == """ schema { query: Root } type Root { singleField(argOne: Int, argTwo: String, argThree: Boolean = false): String } """ ) def test_prints_interface(): FooType = GraphQLInterfaceType( name="Foo", resolve_type=lambda *_: None, fields={"str": GraphQLField(GraphQLString)}, ) BarType = GraphQLObjectType( name="Bar", fields={"str": GraphQLField(GraphQLString)}, interfaces=[FooType] ) Root = GraphQLObjectType(name="Root", fields={"bar": GraphQLField(BarType)}) Schema = GraphQLSchema(Root, types=[BarType]) output = print_for_test(Schema) assert ( output == """ schema { query: Root } type Bar implements Foo { str: String } interface Foo { str: String } type Root { bar: Bar } """ ) def test_prints_multiple_interfaces(): FooType = GraphQLInterfaceType( name="Foo", resolve_type=lambda *_: None, fields={"str": GraphQLField(GraphQLString)}, ) BaazType = GraphQLInterfaceType( name="Baaz", resolve_type=lambda *_: None, fields={"int": GraphQLField(GraphQLInt)}, ) BarType = GraphQLObjectType( name="Bar", fields=OrderedDict( [("str", GraphQLField(GraphQLString)), ("int", GraphQLField(GraphQLInt))] ), interfaces=[FooType, BaazType], ) Root = GraphQLObjectType(name="Root", fields={"bar": GraphQLField(BarType)}) Schema = GraphQLSchema(Root, types=[BarType]) output = print_for_test(Schema) assert ( output == """ schema { query: Root } interface Baaz { int: Int } type Bar implements Foo, Baaz { str: String int: Int } interface Foo { str: String } type Root { bar: Bar } """ ) def test_prints_unions(): FooType = GraphQLObjectType( name="Foo", fields={"bool": GraphQLField(GraphQLBoolean)} ) BarType = GraphQLObjectType(name="Bar", fields={"str": GraphQLField(GraphQLString)}) SingleUnion = GraphQLUnionType( name="SingleUnion", resolve_type=lambda *_: None, types=[FooType] ) MultipleUnion = GraphQLUnionType( name="MultipleUnion", resolve_type=lambda *_: None, types=[FooType, BarType] ) Root = GraphQLObjectType( name="Root", fields=OrderedDict( [ ("single", GraphQLField(SingleUnion)), ("multiple", GraphQLField(MultipleUnion)), ] ), ) Schema = GraphQLSchema(Root) output = print_for_test(Schema) assert ( output == """ schema { query: Root } type Bar { str: String } type Foo { bool: Boolean } union MultipleUnion = Foo | Bar type Root { single: SingleUnion multiple: MultipleUnion } union SingleUnion = Foo """ ) def test_prints_input_type(): InputType = GraphQLInputObjectType( name="InputType", fields={"int": GraphQLInputObjectField(GraphQLInt)} ) Root = GraphQLObjectType( name="Root", fields={ "str": GraphQLField( GraphQLString, args={"argOne": GraphQLArgument(InputType)} ) }, ) Schema = GraphQLSchema(Root) output = print_for_test(Schema) assert ( output == """ schema { query: Root } input InputType { int: Int } type Root { str(argOne: InputType): String } """ ) def test_prints_custom_scalar(): OddType = GraphQLScalarType( name="Odd", serialize=lambda v: v if v % 2 == 1 else None ) Root = GraphQLObjectType(name="Root", fields={"odd": GraphQLField(OddType)}) Schema = GraphQLSchema(Root) output = print_for_test(Schema) assert ( output == """ schema { query: Root } scalar Odd type Root { odd: Odd } """ ) def test_print_enum(): RGBType = GraphQLEnumType( name="RGB", values=OrderedDict( [ ("RED", GraphQLEnumValue(0)), ("GREEN", GraphQLEnumValue(1)), ("BLUE", GraphQLEnumValue(2)), ] ), ) Root = GraphQLObjectType(name="Root", fields={"rgb": GraphQLField(RGBType)}) Schema = GraphQLSchema(Root) output = print_for_test(Schema) assert ( output == """ schema { query: Root } enum RGB { RED GREEN BLUE } type Root { rgb: RGB } """ ) def test_print_introspection_schema(): Root = GraphQLObjectType( name="Root", fields={"onlyField": GraphQLField(GraphQLString)} ) Schema = GraphQLSchema(Root) output = "\n" + print_introspection_schema(Schema) assert ( output == """ schema { query: Root } directive @include(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT directive @skip(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT directive @deprecated(reason: String = "No longer supported") on FIELD_DEFINITION | ENUM_VALUE type __Directive { name: String! description: String locations: [__DirectiveLocation!]! args: [__InputValue!]! onOperation: Boolean! @deprecated(reason: "Use `locations`.") onFragment: Boolean! @deprecated(reason: "Use `locations`.") onField: Boolean! @deprecated(reason: "Use `locations`.") } enum __DirectiveLocation { QUERY MUTATION SUBSCRIPTION FIELD FRAGMENT_DEFINITION FRAGMENT_SPREAD INLINE_FRAGMENT SCHEMA SCALAR OBJECT FIELD_DEFINITION ARGUMENT_DEFINITION INTERFACE UNION ENUM ENUM_VALUE INPUT_OBJECT INPUT_FIELD_DEFINITION } type __EnumValue { name: String! description: String isDeprecated: Boolean! deprecationReason: String } type __Field { name: String! description: String args: [__InputValue!]! type: __Type! isDeprecated: Boolean! deprecationReason: String } type __InputValue { name: String! description: String type: __Type! defaultValue: String } type __Schema { types: [__Type!]! queryType: __Type! mutationType: __Type subscriptionType: __Type directives: [__Directive!]! } type __Type { kind: __TypeKind! name: String description: String fields(includeDeprecated: Boolean = false): [__Field!] interfaces: [__Type!] possibleTypes: [__Type!] enumValues(includeDeprecated: Boolean = false): [__EnumValue!] inputFields: [__InputValue!] ofType: __Type } enum __TypeKind { SCALAR OBJECT INTERFACE UNION ENUM INPUT_OBJECT LIST NON_NULL } """ ) graphql-core-legacy-2.3.2/graphql/utils/tests/test_suggestion_list.py000066400000000000000000000010201365661746200261500ustar00rootroot00000000000000from graphql.utils.suggestion_list import suggestion_list def test_returns_results_when_input_is_empty(): assert suggestion_list("", ["a"]) == ["a"] def test_returns_empty_array_when_there_are_no_options(): assert suggestion_list("input", []) == [] def test_returns_options_sorted_based_on_similarity(): assert suggestion_list("abc", ["a", "ab", "abc"]) == ["abc", "ab"] assert suggestion_list("csutomer", ["customer", "stomer", "store"]) == [ "customer", "stomer", "store", ] graphql-core-legacy-2.3.2/graphql/utils/tests/test_type_comparators.py000066400000000000000000000063301365661746200263320ustar00rootroot00000000000000from collections import OrderedDict from graphql.type import ( GraphQLField, GraphQLFloat, GraphQLInt, GraphQLInterfaceType, GraphQLList, GraphQLNonNull, GraphQLObjectType, GraphQLSchema, GraphQLString, GraphQLUnionType, ) from ..type_comparators import is_equal_type, is_type_sub_type_of def _test_schema(field_type): return GraphQLSchema( query=GraphQLObjectType( name="Query", fields=OrderedDict([("field", GraphQLField(field_type))]) ) ) def test_is_equal_type_same_reference_are_equal(): assert is_equal_type(GraphQLString, GraphQLString) def test_is_equal_type_int_and_float_are_not_equal(): assert not is_equal_type(GraphQLInt, GraphQLFloat) def test_is_equal_type_lists_of_same_type_are_equal(): assert is_equal_type(GraphQLList(GraphQLInt), GraphQLList(GraphQLInt)) def test_is_equal_type_lists_is_not_equal_to_item(): assert not is_equal_type(GraphQLList(GraphQLInt), GraphQLInt) def test_is_equal_type_nonnull_of_same_type_are_equal(): assert is_equal_type(GraphQLNonNull(GraphQLInt), GraphQLNonNull(GraphQLInt)) def test_is_equal_type_nonnull_is_not_equal_to_nullable(): assert not is_equal_type(GraphQLNonNull(GraphQLInt), GraphQLInt) def test_is_equal_type_nonnull_is_not_equal_to_nullable(): assert not is_equal_type(GraphQLNonNull(GraphQLInt), GraphQLInt) def test_is_type_sub_type_of_same_reference_is_subtype(): schema = _test_schema(GraphQLString) assert is_type_sub_type_of(schema, GraphQLString, GraphQLString) def test_is_type_sub_type_of_int_is_not_subtype_of_float(): schema = _test_schema(GraphQLString) assert not is_type_sub_type_of(schema, GraphQLInt, GraphQLFloat) def test_is_type_sub_type_of_non_null_is_subtype_of_nullable(): schema = _test_schema(GraphQLString) assert is_type_sub_type_of(schema, GraphQLNonNull(GraphQLInt), GraphQLInt) def test_is_type_sub_type_of_nullable_is_not_subtype_of_non_null(): schema = _test_schema(GraphQLString) assert not is_type_sub_type_of(schema, GraphQLInt, GraphQLNonNull(GraphQLInt)) def test_is_type_sub_type_of_item_is_not_subtype_of_list(): schema = _test_schema(GraphQLString) assert not is_type_sub_type_of(schema, GraphQLInt, GraphQLList(GraphQLInt)) def test_is_type_sub_type_of_list_is_not_subtype_of_item(): schema = _test_schema(GraphQLString) assert not is_type_sub_type_of(schema, GraphQLList(GraphQLInt), GraphQLInt) def test_is_type_sub_type_of_member_is_subtype_of_union(): member = GraphQLObjectType( name="Object", is_type_of=lambda *_: True, fields={"field": GraphQLField(GraphQLString)}, ) union = GraphQLUnionType(name="Union", types=[member]) schema = _test_schema(union) assert is_type_sub_type_of(schema, member, union) def test_is_type_sub_type_of_implementation_is_subtype_of_interface(): iface = GraphQLInterfaceType( name="Interface", fields={"field": GraphQLField(GraphQLString)} ) impl = GraphQLObjectType( name="Object", is_type_of=lambda *_: True, interfaces=[iface], fields={"field": GraphQLField(GraphQLString)}, ) schema = _test_schema(impl) assert is_type_sub_type_of(schema, impl, iface) graphql-core-legacy-2.3.2/graphql/utils/type_comparators.py000066400000000000000000000077141365661746200241400ustar00rootroot00000000000000from ..type.definition import ( GraphQLAbstractType, GraphQLInterfaceType, GraphQLList, GraphQLNonNull, GraphQLObjectType, GraphQLType, GraphQLUnionType, is_abstract_type, is_interface_type, is_list_type, is_non_null_type, is_object_type, ) from typing import cast # Necessary for static type checking if False: # flake8: noqa from ..type.schema import GraphQLSchema from typing import Union def is_equal_type(type_a, type_b): if type_a is type_b: return True if isinstance(type_a, GraphQLNonNull) and isinstance(type_b, GraphQLNonNull): return is_equal_type(type_a.of_type, type_b.of_type) if isinstance(type_a, GraphQLList) and isinstance(type_b, GraphQLList): return is_equal_type(type_a.of_type, type_b.of_type) return False def is_type_sub_type_of( schema, # type: GraphQLSchema maybe_subtype, # type: GraphQLType super_type, # type: GraphQLType ): # type: (...) -> 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_possible_type( cast(GraphQLAbstractType, super_type), cast(GraphQLObjectType, maybe_subtype), ) ) def do_types_overlap( schema, # type: GraphQLSchema t1, # type: Union[GraphQLInterfaceType, GraphQLUnionType] t2, # type: Union[GraphQLInterfaceType, GraphQLUnionType] ): # type: (...) -> bool # print 'do_types_overlap', t1, t2 if t1 == t2: # print '1' return True if isinstance(t1, (GraphQLInterfaceType, GraphQLUnionType)): if isinstance(t2, (GraphQLInterfaceType, GraphQLUnionType)): # If both types are abstract, then determine if there is any intersection # between possible concrete types of each. s = any( [ schema.is_possible_type(t2, type) for type in schema.get_possible_types(t1) ] ) # print '2',s return s # Determine if the latter type is a possible concrete type of the former. r = schema.is_possible_type(t1, t2) # print '3', r return r if isinstance(t2, (GraphQLInterfaceType, GraphQLUnionType)): t = schema.is_possible_type(t2, t1) # print '4', t return t # print '5' return False graphql-core-legacy-2.3.2/graphql/utils/type_from_ast.py000066400000000000000000000020661365661746200234130ustar00rootroot00000000000000from ..language import ast from ..type.definition import GraphQLList, GraphQLNonNull # Necessary for static type checking if False: # flake8: noqa from ..language.ast import ListType, NamedType, NonNullType from ..type.definition import GraphQLNamedType from ..type.schema import GraphQLSchema from typing import Union def type_from_ast(schema, type_node): # type: (GraphQLSchema, Union[ListType, NamedType, NonNullType]) -> Union[GraphQLList, GraphQLNonNull, GraphQLNamedType] if isinstance(type_node, ast.ListType): inner_type = type_from_ast(schema, type_node.type) return inner_type and GraphQLList(inner_type) elif isinstance(type_node, ast.NonNullType): inner_type = type_from_ast(schema, type_node.type) return inner_type and GraphQLNonNull(inner_type) # type: ignore elif isinstance(type_node, ast.NamedType): schema_type = schema.get_type(type_node.name.value) return schema_type # type: ignore raise Exception("Unexpected type kind: {type_kind}".format(type_kind=type_node)) graphql-core-legacy-2.3.2/graphql/utils/type_info.py000066400000000000000000000157221365661746200225370ustar00rootroot00000000000000import six from ..language import visitor_meta from ..type.definition import ( GraphQLInputObjectType, GraphQLList, get_named_type, get_nullable_type, is_composite_type, ) from .get_field_def import get_field_def from .type_from_ast import type_from_ast # Necessary for static type checking if False: # flake8: noqa from ..type.schema import GraphQLSchema from ..type.definition import ( GraphQLType, GraphQLInterfaceType, GraphQLObjectType, GraphQLField, GraphQLArgument, GraphQLNonNull, GraphQLScalarType, ) from ..type.directives import GraphQLDirective from ..language.ast import ( SelectionSet, Field, OperationDefinition, InlineFragment, Argument, ObjectField, ) from typing import Callable, Optional, Any, List, Union def pop(lst): # type: (Any) -> None if lst: lst.pop() # noinspection PyPep8Naming @six.add_metaclass(visitor_meta.VisitorMeta) class TypeInfo(object): __slots__ = ( "_schema", "_type_stack", "_parent_type_stack", "_input_type_stack", "_field_def_stack", "_directive", "_argument", "_get_field_def_fn", ) def __init__(self, schema, get_field_def_fn=get_field_def): # type: (GraphQLSchema, Callable) -> None self._schema = schema self._type_stack = [] # type: List[Optional[GraphQLType]] self._parent_type_stack = ( [] ) # type: List[Union[GraphQLInterfaceType, GraphQLObjectType, None]] self._input_type_stack = ( [] ) # type: List[Optional[Union[GraphQLInputObjectType, GraphQLNonNull, GraphQLList, GraphQLScalarType, None]]] self._field_def_stack = [] # type: List[Optional[GraphQLField]] self._directive = None # type: Optional[GraphQLDirective] self._argument = None # type: Optional[GraphQLArgument] self._get_field_def_fn = get_field_def_fn def get_type(self): # type: () -> Optional[GraphQLType] if self._type_stack: return self._type_stack[-1] return None def get_parent_type(self): # type: () -> Union[GraphQLInterfaceType, GraphQLObjectType, None] if self._parent_type_stack: return self._parent_type_stack[-1] return None def get_input_type(self): # type: () -> Union[GraphQLInputObjectType, GraphQLNonNull, GraphQLList, GraphQLScalarType, None] if self._input_type_stack: return self._input_type_stack[-1] return None def get_field_def(self): # type: () -> Optional[GraphQLField] if self._field_def_stack: return self._field_def_stack[-1] return None def get_directive(self): # type: () -> Optional[Any] return self._directive def get_argument(self): # type: () -> Optional[GraphQLArgument] return self._argument def leave(self, node): # type: (Any) -> Optional[Any] method = self._get_leave_handler(type(node)) # type: ignore if method: return method(self) return None def enter(self, node): # type: (Any) -> Optional[Any] method = self._get_enter_handler(type(node)) # type: ignore if method: return method(self, node) return None def enter_SelectionSet(self, node): # type: (SelectionSet) -> None named_type = get_named_type(self.get_type()) composite_type = None if is_composite_type(named_type): composite_type = named_type self._parent_type_stack.append(composite_type) # type: ignore def enter_Field(self, node): # type: (Field) -> None parent_type = self.get_parent_type() field_def = None if parent_type: field_def = self._get_field_def_fn(self._schema, parent_type, node) self._field_def_stack.append(field_def) self._type_stack.append(field_def.type if field_def else None) def enter_Directive(self, node): self._directive = self._schema.get_directive(node.name.value) def enter_OperationDefinition(self, node): # type: (OperationDefinition) -> None definition_type = None if node.operation == "query": definition_type = self._schema.get_query_type() elif node.operation == "mutation": definition_type = self._schema.get_mutation_type() elif node.operation == "subscription": definition_type = self._schema.get_subscription_type() self._type_stack.append(definition_type) def enter_InlineFragment(self, node): # type: (InlineFragment) -> None type_condition_ast = node.type_condition type = ( type_from_ast(self._schema, type_condition_ast) if type_condition_ast else self.get_type() ) self._type_stack.append(type) enter_FragmentDefinition = enter_InlineFragment def enter_VariableDefinition(self, node): self._input_type_stack.append(type_from_ast(self._schema, node.type)) def enter_Argument(self, node): # type: (Argument) -> None arg_def = None arg_type = 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) if arg_def: arg_type = arg_def.type self._argument = arg_def self._input_type_stack.append(arg_type) def enter_ListValue(self, node): list_type = get_nullable_type(self.get_input_type()) self._input_type_stack.append( list_type.of_type if isinstance(list_type, GraphQLList) else None ) def enter_ObjectField(self, node): # type: (ObjectField) -> None object_type = get_named_type(self.get_input_type()) field_type = None if isinstance(object_type, GraphQLInputObjectType): input_field = object_type.fields.get(node.name.value) field_type = input_field.type if input_field else None self._input_type_stack.append(field_type) def leave_SelectionSet(self): # type: () -> None pop(self._parent_type_stack) def leave_Field(self): # type: () -> None pop(self._field_def_stack) pop(self._type_stack) def leave_Directive(self): self._directive = None def leave_OperationDefinition(self): # type: () -> None pop(self._type_stack) leave_InlineFragment = leave_OperationDefinition leave_FragmentDefinition = leave_OperationDefinition def leave_VariableDefinition(self): pop(self._input_type_stack) def leave_Argument(self): # type: () -> None self._argument = None pop(self._input_type_stack) def leave_ListValue(self): # type: () -> None pop(self._input_type_stack) leave_ObjectField = leave_ListValue graphql-core-legacy-2.3.2/graphql/utils/undefined.py000066400000000000000000000004641365661746200225010ustar00rootroot00000000000000class _Undefined(object): """A representation of an Undefined value distinct from a None value""" def __bool__(self): # type: () -> bool return False __nonzero__ = __bool__ def __repr__(self): # type: () -> str return "Undefined" Undefined = _Undefined() graphql-core-legacy-2.3.2/graphql/utils/value_from_ast.py000066400000000000000000000060141365661746200235430ustar00rootroot00000000000000from ..language import ast from ..pyutils.ordereddict import OrderedDict from ..type import ( GraphQLEnumType, GraphQLInputObjectType, GraphQLList, GraphQLNonNull, GraphQLScalarType, ) # Necessary for static type checking if False: # flake8: noqa from ..language.ast import Node from ..type.definition import GraphQLType from typing import Dict, Union, Optional, List def value_from_ast(value_ast, type, variables=None): # type: (Optional[Node], GraphQLType, Optional[Dict[str, Union[List, Dict, int, float, bool, str, None]]]) -> Union[List, Dict, int, float, bool, str, None] """Given a type and a value AST node known to match this type, build a runtime value.""" if isinstance(type, GraphQLNonNull): # Note: we're not checking that the result of coerceValueAST is non-null. # We're assuming that this query has been validated and the value used here is of the correct type. return value_from_ast(value_ast, type.of_type, variables) if value_ast is None: return None if isinstance(value_ast, ast.Variable): variable_name = value_ast.name.value if not variables or variable_name not in variables: return None # Note: we're not doing any checking that this variable is correct. We're assuming that this query # has been validated and the variable usage here is of the correct type. return variables.get(variable_name) if isinstance(type, GraphQLList): item_type = type.of_type if isinstance(value_ast, ast.ListValue): return [ value_from_ast(item_ast, item_type, variables) for item_ast in value_ast.values ] else: return [value_from_ast(value_ast, item_type, variables)] if isinstance(type, GraphQLInputObjectType): fields = type.fields if not isinstance(value_ast, ast.ObjectValue): return None field_asts = {} for field_ast in value_ast.fields: field_asts[field_ast.name.value] = field_ast obj_items = [] for field_name, field in fields.items(): if field_name not in field_asts: if field.default_value is not None: # We use out_name as the output name for the # dict if exists obj_items.append( (field.out_name or field_name, field.default_value) ) continue field_ast = field_asts[field_name] field_value_ast = field_ast.value field_value = value_from_ast(field_value_ast, field.type, variables) # We use out_name as the output name for the # dict if exists obj_items.append((field.out_name or field_name, field_value)) obj = OrderedDict(obj_items) return type.create_container(obj) assert isinstance(type, (GraphQLScalarType, GraphQLEnumType)), "Must be input type" return type.parse_literal(value_ast) graphql-core-legacy-2.3.2/graphql/validation/000077500000000000000000000000001365661746200211545ustar00rootroot00000000000000graphql-core-legacy-2.3.2/graphql/validation/__init__.py000066400000000000000000000001571365661746200232700ustar00rootroot00000000000000from .validation import validate from .rules import specified_rules __all__ = ["validate", "specified_rules"] graphql-core-legacy-2.3.2/graphql/validation/rules/000077500000000000000000000000001365661746200223065ustar00rootroot00000000000000graphql-core-legacy-2.3.2/graphql/validation/rules/__init__.py000066400000000000000000000055361365661746200244300ustar00rootroot00000000000000from .arguments_of_correct_type import ArgumentsOfCorrectType from .default_values_of_correct_type import DefaultValuesOfCorrectType from .fields_on_correct_type import FieldsOnCorrectType from .fragments_on_composite_types import FragmentsOnCompositeTypes from .known_argument_names import KnownArgumentNames from .known_directives import KnownDirectives from .known_fragment_names import KnownFragmentNames from .known_type_names import KnownTypeNames from .lone_anonymous_operation import LoneAnonymousOperation from .no_fragment_cycles import NoFragmentCycles from .no_undefined_variables import NoUndefinedVariables from .no_unused_fragments import NoUnusedFragments from .no_unused_variables import NoUnusedVariables from .overlapping_fields_can_be_merged import OverlappingFieldsCanBeMerged from .possible_fragment_spreads import PossibleFragmentSpreads from .provided_non_null_arguments import ProvidedNonNullArguments from .scalar_leafs import ScalarLeafs from .unique_argument_names import UniqueArgumentNames from .unique_fragment_names import UniqueFragmentNames from .unique_input_field_names import UniqueInputFieldNames from .unique_operation_names import UniqueOperationNames from .unique_variable_names import UniqueVariableNames from .variables_are_input_types import VariablesAreInputTypes from .variables_in_allowed_position import VariablesInAllowedPosition # Necessary for static type checking if False: # flake8: noqa from typing import List, Type from .base import ValidationRule specified_rules = [ UniqueOperationNames, LoneAnonymousOperation, KnownTypeNames, FragmentsOnCompositeTypes, VariablesAreInputTypes, ScalarLeafs, FieldsOnCorrectType, UniqueFragmentNames, KnownFragmentNames, NoUnusedFragments, PossibleFragmentSpreads, NoFragmentCycles, NoUndefinedVariables, NoUnusedVariables, KnownDirectives, KnownArgumentNames, UniqueArgumentNames, ArgumentsOfCorrectType, ProvidedNonNullArguments, DefaultValuesOfCorrectType, VariablesInAllowedPosition, OverlappingFieldsCanBeMerged, UniqueInputFieldNames, UniqueVariableNames, ] # type: List[Type[ValidationRule]] __all__ = [ "ArgumentsOfCorrectType", "DefaultValuesOfCorrectType", "FieldsOnCorrectType", "FragmentsOnCompositeTypes", "KnownArgumentNames", "KnownDirectives", "KnownFragmentNames", "KnownTypeNames", "LoneAnonymousOperation", "NoFragmentCycles", "UniqueVariableNames", "NoUndefinedVariables", "NoUnusedFragments", "NoUnusedVariables", "OverlappingFieldsCanBeMerged", "PossibleFragmentSpreads", "ProvidedNonNullArguments", "ScalarLeafs", "UniqueArgumentNames", "UniqueFragmentNames", "UniqueInputFieldNames", "UniqueOperationNames", "VariablesAreInputTypes", "VariablesInAllowedPosition", "specified_rules", ] graphql-core-legacy-2.3.2/graphql/validation/rules/arguments_of_correct_type.py000066400000000000000000000025421365661746200301360ustar00rootroot00000000000000from ...error import GraphQLError from ...language.printer import print_ast from ...utils.is_valid_literal_value import is_valid_literal_value from .base import ValidationRule # Necessary for static type checking if False: # flake8: noqa from ...language.ast import Argument from typing import Any, List, Union class ArgumentsOfCorrectType(ValidationRule): def enter_Argument( self, node, # type: Argument key, # type: int parent, # type: List[Argument] path, # type: List[Union[int, str]] ancestors, # type: List[Any] ): # type: (...) -> bool arg_def = self.context.get_argument() if arg_def: errors = is_valid_literal_value(arg_def.type, node.value) if errors: self.context.report_error( GraphQLError( self.bad_value_message( node.name.value, arg_def.type, print_ast(node.value), errors ), [node.value], ) ) return False @staticmethod def bad_value_message(arg_name, type, value, verbose_errors): message = (u"\n" + u"\n".join(verbose_errors)) if verbose_errors else "" return 'Argument "{}" has invalid value {}.{}'.format(arg_name, value, message) graphql-core-legacy-2.3.2/graphql/validation/rules/base.py000066400000000000000000000005021365661746200235670ustar00rootroot00000000000000from ...language.visitor import Visitor # Necessary for static type checking if False: # flake8: noqa from ..validation import ValidationContext class ValidationRule(Visitor): __slots__ = ("context",) def __init__(self, context): # type: (ValidationContext) -> None self.context = context graphql-core-legacy-2.3.2/graphql/validation/rules/default_values_of_correct_type.py000066400000000000000000000046241365661746200311370ustar00rootroot00000000000000from ...error import GraphQLError from ...language.printer import print_ast from ...type.definition import GraphQLNonNull from ...utils.is_valid_literal_value import is_valid_literal_value from .base import ValidationRule # Necessary for static type checking if False: # flake8: noqa from ...language.ast import Document, OperationDefinition, SelectionSet from typing import List, Union class DefaultValuesOfCorrectType(ValidationRule): def enter_VariableDefinition(self, node, key, parent, path, ancestors): name = node.variable.name.value default_value = node.default_value type = self.context.get_input_type() if isinstance(type, GraphQLNonNull) and default_value: self.context.report_error( GraphQLError( self.default_for_non_null_arg_message(name, type, type.of_type), [default_value], ) ) if type and default_value: errors = is_valid_literal_value(type, default_value) if errors: self.context.report_error( GraphQLError( self.bad_value_for_default_arg_message( name, type, print_ast(default_value), errors ), [default_value], ) ) return False def enter_SelectionSet( self, node, # type: SelectionSet key, # type: str parent, # type: OperationDefinition path, # type: List[Union[int, str]] ancestors, # type: List[Union[List[OperationDefinition], Document]] ): # type: (...) -> bool return False def enter_FragmentDefinition(self, node, key, parent, path, ancestors): return False @staticmethod def default_for_non_null_arg_message(var_name, type, guess_type): return ( u'Variable "${}" of type "{}" is required and will not use the default value. ' u'Perhaps you meant to use type "{}".'.format(var_name, type, guess_type) ) @staticmethod def bad_value_for_default_arg_message(var_name, type, value, verbose_errors): message = (u"\n" + u"\n".join(verbose_errors)) if verbose_errors else u"" return u'Variable "${}" of type "{}" has invalid default value: {}.{}'.format( var_name, type, value, message ) graphql-core-legacy-2.3.2/graphql/validation/rules/fields_on_correct_type.py000066400000000000000000000116301365661746200274050ustar00rootroot00000000000000from collections import Counter from ...error import GraphQLError from ...pyutils.ordereddict import OrderedDict from ...type.definition import GraphQLInterfaceType, GraphQLObjectType, GraphQLUnionType from ...utils.quoted_or_list import quoted_or_list from ...utils.suggestion_list import suggestion_list from .base import ValidationRule # Necessary for static type checking if False: # flake8: noqa from ...language.ast import Field, InlineFragment from typing import Any, List, Union try: # Python 2 from itertools import izip # type: ignore except ImportError: # Python 3 izip = zip def _undefined_field_message(field_name, type, suggested_types, suggested_fields): message = 'Cannot query field "{}" on type "{}".'.format(field_name, type) if suggested_types: suggestions = quoted_or_list(suggested_types) message += " Did you mean to use an inline fragment on {}?".format(suggestions) elif suggested_fields: suggestions = quoted_or_list(suggested_fields) message += " Did you mean {}?".format(suggestions) return message class OrderedCounter(Counter, OrderedDict): pass class FieldsOnCorrectType(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 __typenamme """ def enter_Field( self, node, # type: Field key, # type: int parent, # type: Union[List[Union[Field, InlineFragment]], List[Field]] path, # type: List[Union[int, str]] ancestors, # type: List[Any] ): # type: (...) -> None parent_type = self.context.get_parent_type() if not parent_type: return field_def = self.context.get_field_def() if not field_def: # This field doesn't exist, lets look for suggestions. schema = self.context.get_schema() field_name = node.name.value # First determine if there are any suggested types to condition on. suggested_type_names = get_suggested_type_names( schema, parent_type, field_name ) # if there are no suggested types perhaps it was a typo? suggested_field_names = ( [] if suggested_type_names else get_suggested_field_names(schema, parent_type, field_name) ) # report an error including helpful suggestions. self.context.report_error( GraphQLError( _undefined_field_message( field_name, parent_type.name, suggested_type_names, suggested_field_names, ), [node], ) ) def get_suggested_type_names(schema, output_type, field_name): """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, starting with Interfaces.""" if isinstance(output_type, (GraphQLInterfaceType, GraphQLUnionType)): suggested_object_types = [] interface_usage_count = OrderedDict() for possible_type in schema.get_possible_types(output_type): if not possible_type.fields.get(field_name): return # This object type defines this field. suggested_object_types.append(possible_type.name) for possible_interface in possible_type.interfaces: if not possible_interface.fields.get(field_name): continue # This interface type defines this field. interface_usage_count[possible_interface.name] = ( interface_usage_count.get(possible_interface.name, 0) + 1 ) # Suggest interface types based on how common they are. suggested_interface_types = sorted( list(interface_usage_count.keys()), key=lambda k: interface_usage_count[k], reverse=True, ) # Suggest both interface and object types. suggested_interface_types.extend(suggested_object_types) return suggested_interface_types # Otherwise, must be an Object type, which does not have possible fields. return [] def get_suggested_field_names(schema, graphql_type, field_name): """For the field name provided, determine if there are any similar field names that may be the result of a typo.""" if isinstance(graphql_type, (GraphQLInterfaceType, GraphQLObjectType)): possible_field_names = list(graphql_type.fields.keys()) return suggestion_list(field_name, possible_field_names) # Otherwise, must be a Union type, which does not define fields. return [] graphql-core-legacy-2.3.2/graphql/validation/rules/fragments_on_composite_types.py000066400000000000000000000036171365661746200306570ustar00rootroot00000000000000from ...error import GraphQLError from ...language.printer import print_ast from ...type.definition import is_composite_type from .base import ValidationRule # Necessary for static type checking if False: # flake8: noqa from ...language.ast import Field, InlineFragment from typing import Any, List, Union class FragmentsOnCompositeTypes(ValidationRule): def enter_InlineFragment( self, node, # type: InlineFragment key, # type: int parent, # type: Union[List[Union[Field, InlineFragment]], List[InlineFragment]] path, # type: List[Union[int, str]] ancestors, # type: List[Any] ): # type: (...) -> None type = self.context.get_type() if node.type_condition and type and not is_composite_type(type): self.context.report_error( GraphQLError( self.inline_fragment_on_non_composite_error_message( print_ast(node.type_condition) ), [node.type_condition], ) ) def enter_FragmentDefinition(self, node, key, parent, path, ancestors): type = self.context.get_type() if type and not is_composite_type(type): self.context.report_error( GraphQLError( self.fragment_on_non_composite_error_message( node.name.value, print_ast(node.type_condition) ), [node.type_condition], ) ) @staticmethod def inline_fragment_on_non_composite_error_message(type): return 'Fragment cannot condition on non composite type "{}".'.format(type) @staticmethod def fragment_on_non_composite_error_message(frag_name, type): return 'Fragment "{}" cannot condition on non composite type "{}".'.format( frag_name, type ) graphql-core-legacy-2.3.2/graphql/validation/rules/known_argument_names.py000066400000000000000000000057041365661746200271070ustar00rootroot00000000000000from ...error import GraphQLError from ...language import ast from ...utils.quoted_or_list import quoted_or_list from ...utils.suggestion_list import suggestion_list from .base import ValidationRule # Necessary for static type checking if False: # flake8: noqa from ...language.ast import Argument from typing import Any, List, Union def _unknown_arg_message(arg_name, field_name, type, suggested_args): message = 'Unknown argument "{}" on field "{}" of type "{}".'.format( arg_name, field_name, type ) if suggested_args: message += " Did you mean {}?".format(quoted_or_list(suggested_args)) return message def _unknown_directive_arg_message(arg_name, directive_name, suggested_args): message = 'Unknown argument "{}" on directive "@{}".'.format( arg_name, directive_name ) if suggested_args: message += " Did you mean {}?".format(quoted_or_list(suggested_args)) return message class KnownArgumentNames(ValidationRule): def enter_Argument( self, node, # type: Argument key, # type: int parent, # type: List[Argument] path, # type: List[Union[int, str]] ancestors, # type: List[Any] ): # type: (...) -> None argument_of = ancestors[-1] if isinstance(argument_of, ast.Field): field_def = self.context.get_field_def() if not field_def: return field_arg_def = field_def.args.get(node.name.value) if not field_arg_def: parent_type = self.context.get_parent_type() assert parent_type self.context.report_error( GraphQLError( _unknown_arg_message( node.name.value, argument_of.name.value, parent_type.name, suggestion_list( node.name.value, (arg_name for arg_name in field_def.args.keys()), ), ), [node], ) ) elif isinstance(argument_of, ast.Directive): directive = self.context.get_directive() if not directive: return directive_arg_def = directive.args.get(node.name.value) if not directive_arg_def: self.context.report_error( GraphQLError( _unknown_directive_arg_message( node.name.value, directive.name, suggestion_list( node.name.value, (arg_name for arg_name in directive.args.keys()), ), ), [node], ) ) graphql-core-legacy-2.3.2/graphql/validation/rules/known_directives.py000066400000000000000000000070531365661746200262420ustar00rootroot00000000000000from ...error import GraphQLError from ...language import ast from ...type.directives import DirectiveLocation from .base import ValidationRule class KnownDirectives(ValidationRule): def enter_Directive(self, node, key, parent, path, ancestors): directive_def = next( ( definition for definition in self.context.get_schema().get_directives() if definition.name == node.name.value ), None, ) if not directive_def: return self.context.report_error( GraphQLError(self.unknown_directive_message(node.name.value), [node]) ) candidate_location = get_directive_location_for_ast_path(ancestors) if not candidate_location: self.context.report_error( GraphQLError( self.misplaced_directive_message(node.name.value, node.type), [node] ) ) elif candidate_location not in directive_def.locations: self.context.report_error( GraphQLError( self.misplaced_directive_message( node.name.value, candidate_location ), [node], ) ) @staticmethod def unknown_directive_message(directive_name): return 'Unknown directive "{}".'.format(directive_name) @staticmethod def misplaced_directive_message(directive_name, location): return 'Directive "{}" may not be used on "{}".'.format( directive_name, location ) _operation_definition_map = { "query": DirectiveLocation.QUERY, "mutation": DirectiveLocation.MUTATION, "subscription": DirectiveLocation.SUBSCRIPTION, } def get_directive_location_for_ast_path(ancestors): applied_to = ancestors[-1] if isinstance(applied_to, ast.OperationDefinition): return _operation_definition_map.get(applied_to.operation) elif isinstance(applied_to, ast.Field): return DirectiveLocation.FIELD elif isinstance(applied_to, ast.FragmentSpread): return DirectiveLocation.FRAGMENT_SPREAD elif isinstance(applied_to, ast.InlineFragment): return DirectiveLocation.INLINE_FRAGMENT elif isinstance(applied_to, ast.FragmentDefinition): return DirectiveLocation.FRAGMENT_DEFINITION elif isinstance(applied_to, ast.SchemaDefinition): return DirectiveLocation.SCHEMA elif isinstance(applied_to, ast.ScalarTypeDefinition): return DirectiveLocation.SCALAR elif isinstance(applied_to, ast.ObjectTypeDefinition): return DirectiveLocation.OBJECT elif isinstance(applied_to, ast.FieldDefinition): return DirectiveLocation.FIELD_DEFINITION elif isinstance(applied_to, ast.InterfaceTypeDefinition): return DirectiveLocation.INTERFACE elif isinstance(applied_to, ast.UnionTypeDefinition): return DirectiveLocation.UNION elif isinstance(applied_to, ast.EnumTypeDefinition): return DirectiveLocation.ENUM elif isinstance(applied_to, ast.EnumValueDefinition): return DirectiveLocation.ENUM_VALUE elif isinstance(applied_to, ast.InputObjectTypeDefinition): return DirectiveLocation.INPUT_OBJECT elif isinstance(applied_to, ast.InputValueDefinition): parent_node = ancestors[-3] return ( DirectiveLocation.INPUT_FIELD_DEFINITION if isinstance(parent_node, ast.InputObjectTypeDefinition) else DirectiveLocation.ARGUMENT_DEFINITION ) graphql-core-legacy-2.3.2/graphql/validation/rules/known_fragment_names.py000066400000000000000000000011041365661746200270560ustar00rootroot00000000000000from ...error import GraphQLError from .base import ValidationRule class KnownFragmentNames(ValidationRule): def enter_FragmentSpread(self, node, key, parent, path, ancestors): fragment_name = node.name.value fragment = self.context.get_fragment(fragment_name) if not fragment: self.context.report_error( GraphQLError(self.unknown_fragment_message(fragment_name), [node.name]) ) @staticmethod def unknown_fragment_message(fragment_name): return 'Unknown fragment "{}".'.format(fragment_name) graphql-core-legacy-2.3.2/graphql/validation/rules/known_type_names.py000066400000000000000000000026321365661746200262430ustar00rootroot00000000000000from ...error import GraphQLError from ...utils.quoted_or_list import quoted_or_list from ...utils.suggestion_list import suggestion_list from .base import ValidationRule # Necessary for static type checking if False: # flake8: noqa from ...language.ast import NamedType from typing import Any def _unknown_type_message(type, suggested_types): message = 'Unknown type "{}".'.format(type) if suggested_types: message += " Perhaps you meant {}?".format(quoted_or_list(suggested_types)) return message class KnownTypeNames(ValidationRule): def enter_ObjectTypeDefinition(self, node, *args): return False def enter_InterfaceTypeDefinition(self, node, *args): return False def enter_UnionTypeDefinition(self, node, *args): return False def enter_InputObjectTypeDefinition(self, node, *args): return False def enter_NamedType(self, node, *args): # type: (NamedType, *Any) -> None schema = self.context.get_schema() type_name = node.name.value type = schema.get_type(type_name) if not type: self.context.report_error( GraphQLError( _unknown_type_message( type_name, suggestion_list(type_name, list(schema.get_type_map().keys())), ), [node], ) ) graphql-core-legacy-2.3.2/graphql/validation/rules/lone_anonymous_operation.py000066400000000000000000000027621365661746200300140ustar00rootroot00000000000000from ...error import GraphQLError from ...language import ast from .base import ValidationRule # Necessary for static type checking if False: # flake8: noqa from ..validation import ValidationContext from ...language.ast import Document, OperationDefinition from typing import Any, List, Optional, Union class LoneAnonymousOperation(ValidationRule): __slots__ = ("operation_count",) def __init__(self, context): # type: (ValidationContext) -> None self.operation_count = 0 super(LoneAnonymousOperation, self).__init__(context) def enter_Document(self, node, key, parent, path, ancestors): # type: (Document, Optional[Any], Optional[Any], List, List) -> None self.operation_count = sum( 1 for definition in node.definitions if isinstance(definition, ast.OperationDefinition) ) def enter_OperationDefinition( self, node, # type: OperationDefinition key, # type: int parent, # type: List[OperationDefinition] path, # type: List[Union[int, str]] ancestors, # type: List[Document] ): # type: (...) -> None if not node.name and self.operation_count > 1: self.context.report_error( GraphQLError(self.anonymous_operation_not_alone_message(), [node]) ) @staticmethod def anonymous_operation_not_alone_message(): return "This anonymous operation must be the only defined operation." graphql-core-legacy-2.3.2/graphql/validation/rules/no_fragment_cycles.py000066400000000000000000000055321365661746200265260ustar00rootroot00000000000000from ...error import GraphQLError from .base import ValidationRule # Necessary for static type checking if False: # flake8: noqa from ..validation import ValidationContext from ...language.ast import Document, OperationDefinition, FragmentSpread from typing import List, Union, Dict, Set class NoFragmentCycles(ValidationRule): __slots__ = "errors", "visited_frags", "spread_path", "spread_path_index_by_name" def __init__(self, context): # type: (ValidationContext) -> None super(NoFragmentCycles, self).__init__(context) self.errors = [] # type: List[GraphQLError] self.visited_frags = set() # type: Set[str] self.spread_path = [] # type: List[FragmentSpread] self.spread_path_index_by_name = {} # type: Dict[str, int] def enter_OperationDefinition( self, node, # type: OperationDefinition key, # type: int parent, # type: List[OperationDefinition] path, # type: List[Union[int, str]] ancestors, # type: List[Document] ): # type: (...) -> bool return False def enter_FragmentDefinition(self, node, key, parent, path, ancestors): if node.name.value not in self.visited_frags: self.detect_cycle_recursive(node) return False def detect_cycle_recursive(self, fragment): fragment_name = fragment.name.value self.visited_frags.add(fragment_name) spread_nodes = self.context.get_fragment_spreads(fragment.selection_set) if not spread_nodes: return self.spread_path_index_by_name[fragment_name] = len(self.spread_path) for spread_node in spread_nodes: spread_name = spread_node.name.value cycle_index = self.spread_path_index_by_name.get(spread_name) if cycle_index is None: self.spread_path.append(spread_node) if spread_name not in self.visited_frags: spread_fragment = self.context.get_fragment(spread_name) if spread_fragment: self.detect_cycle_recursive(spread_fragment) self.spread_path.pop() else: cycle_path = self.spread_path[cycle_index:] self.context.report_error( GraphQLError( self.cycle_error_message( spread_name, [s.name.value for s in cycle_path] ), cycle_path + [spread_node], ) ) self.spread_path_index_by_name[fragment_name] = None @staticmethod def cycle_error_message(fragment_name, spread_names): via = " via {}".format(", ".join(spread_names)) if spread_names else "" return 'Cannot spread fragment "{}" within itself{}.'.format(fragment_name, via) graphql-core-legacy-2.3.2/graphql/validation/rules/no_undefined_variables.py000066400000000000000000000042231365661746200273460ustar00rootroot00000000000000from ...error import GraphQLError from .base import ValidationRule # Necessary for static type checking if False: # flake8: noqa from ..validation import ValidationContext from ...language.ast import Document, OperationDefinition from typing import List, Union, Set class NoUndefinedVariables(ValidationRule): __slots__ = ("defined_variable_names",) def __init__(self, context): # type: (ValidationContext) -> None self.defined_variable_names = set() # type: Set[str] super(NoUndefinedVariables, self).__init__(context) @staticmethod def undefined_var_message(var_name, op_name=None): if op_name: return 'Variable "${}" is not defined by operation "{}".'.format( var_name, op_name ) return 'Variable "${}" is not defined.'.format(var_name) def enter_OperationDefinition( self, operation, # type: OperationDefinition key, # type: int parent, # type: List[OperationDefinition] path, # type: List[Union[int, str]] ancestors, # type: List[Document] ): # type: (...) -> None self.defined_variable_names = set() def leave_OperationDefinition( self, operation, # type: OperationDefinition key, # type: int parent, # type: List[OperationDefinition] path, # type: List[str] ancestors, # type: List[Document] ): # type: (...) -> None usages = self.context.get_recursive_variable_usages(operation) for variable_usage in usages: node = variable_usage.node var_name = node.name.value if var_name not in self.defined_variable_names: self.context.report_error( GraphQLError( self.undefined_var_message( var_name, operation.name and operation.name.value ), [node, operation], ) ) def enter_VariableDefinition(self, node, key, parent, path, ancestors): self.defined_variable_names.add(node.variable.name.value) graphql-core-legacy-2.3.2/graphql/validation/rules/no_unused_fragments.py000066400000000000000000000042671365661746200267360ustar00rootroot00000000000000from ...error import GraphQLError from .base import ValidationRule # Necessary for static type checking if False: # flake8: noqa from ..validation import ValidationContext from ...language.ast import Document, OperationDefinition, FragmentDefinition from typing import List, Union, Any, Optional class NoUnusedFragments(ValidationRule): __slots__ = ( "fragment_definitions", "operation_definitions", "fragment_adjacencies", "spread_names", ) def __init__(self, context): # type: (ValidationContext) -> None super(NoUnusedFragments, self).__init__(context) self.operation_definitions = [] # type: List[OperationDefinition] self.fragment_definitions = [] # type: List[FragmentDefinition] def enter_OperationDefinition( self, node, # type: OperationDefinition key, # type: int parent, # type: List[OperationDefinition] path, # type: List[Union[int, str]] ancestors, # type: List[Document] ): # type: (...) -> bool self.operation_definitions.append(node) return False def enter_FragmentDefinition(self, node, key, parent, path, ancestors): self.fragment_definitions.append(node) return False def leave_Document(self, node, key, parent, path, ancestors): # type: (Document, Optional[Any], Optional[Any], List, List) -> None fragment_names_used = set() for operation in self.operation_definitions: fragments = self.context.get_recursively_referenced_fragments(operation) for fragment in fragments: fragment_names_used.add(fragment.name.value) for fragment_definition in self.fragment_definitions: if fragment_definition.name.value not in fragment_names_used: self.context.report_error( GraphQLError( self.unused_fragment_message(fragment_definition.name.value), [fragment_definition], ) ) @staticmethod def unused_fragment_message(fragment_name): return 'Fragment "{}" is never used.'.format(fragment_name) graphql-core-legacy-2.3.2/graphql/validation/rules/no_unused_variables.py000066400000000000000000000045031365661746200267110ustar00rootroot00000000000000from ...error import GraphQLError from .base import ValidationRule # Necessary for static type checking if False: # flake8: noqa from ..validation import ValidationContext from ...language.ast import Document, OperationDefinition, VariableDefinition from typing import List, Union class NoUnusedVariables(ValidationRule): __slots__ = "variable_definitions" def __init__(self, context): # type: (ValidationContext) -> None self.variable_definitions = [] # type: List[VariableDefinition] super(NoUnusedVariables, self).__init__(context) def enter_OperationDefinition( self, node, # type: OperationDefinition key, # type: int parent, # type: List[OperationDefinition] path, # type: List[Union[int, str]] ancestors, # type: List[Document] ): # type: (...) -> None self.variable_definitions = [] def leave_OperationDefinition( self, operation, # type: OperationDefinition key, # type: int parent, # type: List[OperationDefinition] path, # type: List[str] ancestors, # type: List[Document] ): # type: (...) -> None variable_name_used = set() usages = self.context.get_recursive_variable_usages(operation) op_name = operation.name and operation.name.value or None for variable_usage in usages: variable_name_used.add(variable_usage.node.name.value) for variable_definition in self.variable_definitions: if variable_definition.variable.name.value not in variable_name_used: self.context.report_error( GraphQLError( self.unused_variable_message( variable_definition.variable.name.value, op_name ), [variable_definition], ) ) def enter_VariableDefinition(self, node, key, parent, path, ancestors): self.variable_definitions.append(node) @staticmethod def unused_variable_message(variable_name, op_name): if op_name: return 'Variable "${}" is never used in operation "{}".'.format( variable_name, op_name ) return 'Variable "${}" is never used.'.format(variable_name) graphql-core-legacy-2.3.2/graphql/validation/rules/overlapping_fields_can_be_merged.py000066400000000000000000000726661365661746200313670ustar00rootroot00000000000000import itertools from collections import OrderedDict from typing import cast from ...error import GraphQLError from ...language import ast from ...language.printer import print_ast from ...pyutils.pair_set import PairSet from ...type.definition import ( GraphQLInterfaceType, GraphQLList, GraphQLNonNull, GraphQLObjectType, GraphQLOutputType, get_named_type, is_leaf_type, is_list_type, is_non_null_type, ) from ...utils.type_comparators import is_equal_type from ...utils.type_from_ast import type_from_ast from .base import ValidationRule # Necessary for static type checking if False: # flake8: noqa from ..validation import ValidationContext from ...language.ast import ( Node, OperationDefinition, Field, Argument, InlineFragment, SelectionSet, ) from ...type.definition import GraphQLField from typing import List, Union, Any, Optional, Dict, Tuple class OverlappingFieldsCanBeMerged(ValidationRule): __slots__ = ("_compared_fragments", "_cached_fields_and_fragment_names") def __init__(self, context): # type: (ValidationContext) -> None super(OverlappingFieldsCanBeMerged, self).__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_fragments = 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 = ( {} ) # type: Dict[SelectionSet, Tuple[Dict[str, List[Tuple[Union[GraphQLInterfaceType, GraphQLObjectType, None], Field, GraphQLField]]], List[str]]] def leave_SelectionSet( self, node, # type: SelectionSet key, # type: str parent, # type: Union[Field, InlineFragment, OperationDefinition] path, # type: List[Union[int, str]] ancestors, # type: List[Any] ): # type: (...) -> None # Note: we validate on the reverse traversal so deeper conflicts will be # caught first, for correct calculation of mutual exclusivity and for # clearer error messages. # field_map = _collect_field_asts_and_defs( # self.context, # self.context.get_parent_type(), # node # ) # conflicts = _find_conflicts(self.context, False, field_map, self.compared_set) conflicts = _find_conflicts_within_selection_set( self.context, self._cached_fields_and_fragment_names, self._compared_fragments, self.context.get_parent_type(), node, ) for (reason_name, reason), fields1, fields2 in conflicts: self.context.report_error( GraphQLError( self.fields_conflict_message(reason_name, reason), list(fields1) + list(fields2), ) ) @staticmethod def same_type(type1, type2): return is_equal_type(type1, type2) # return type1.is_same_type(type2) @classmethod def fields_conflict_message(cls, reason_name, reason): return ( 'Fields "{}" conflict because {}. ' "Use different aliases on the fields to fetch both if this was " "intentional." ).format(reason_name, cls.reason_message(reason)) @classmethod def reason_message(cls, reason): if isinstance(reason, list): return " and ".join( 'subfields "{}" conflict because {}'.format( reason_name, cls.reason_message(sub_reason) ) for reason_name, sub_reason in reason ) return reason # 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, # type: ValidationContext cached_fields_and_fragment_names, # type: Dict[SelectionSet, Tuple[Dict[str, List[Tuple[Union[GraphQLInterfaceType, GraphQLObjectType, None], Field, GraphQLField]]], List[str]]] compared_fragments, # type: PairSet parent_type, # type: Union[GraphQLInterfaceType, GraphQLObjectType, None] selection_set, # type: SelectionSet ): # type: (...) -> List[Tuple[Tuple[str, str], List[Node], List[Node]]] """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 = [] # type: List[Tuple[Tuple[str, str], List[Node], List[Node]]] field_map, fragment_names = _get_fields_and_fragments_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_fragments, field_map, ) # (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_fragments, 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_fragments, False, fragment_name, other_fragment_name, ) return conflicts def _collect_conflicts_between_fields_and_fragment( context, # type: ValidationContext conflicts, # type: List[Tuple[Tuple[str, str], List[Node], List[Node]]] cached_fields_and_fragment_names, # type: Dict[SelectionSet, Tuple[Dict[str, List[Tuple[Union[GraphQLInterfaceType, GraphQLObjectType, None], Field, GraphQLField]]], List[str]]] compared_fragments, # type: PairSet are_mutually_exclusive, # type: bool field_map, # type: Dict[str, List[Tuple[Union[GraphQLInterfaceType, GraphQLObjectType, None], Field, GraphQLField]]] fragment_name, # type: str ): fragment = context.get_fragment(fragment_name) if not fragment: return None field_map2, fragment_names2 = _get_referenced_fields_and_fragment_names( context, cached_fields_and_fragment_names, fragment ) # (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_fragments, 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 fragment_name2 in fragment_names2: _collect_conflicts_between_fields_and_fragment( context, conflicts, cached_fields_and_fragment_names, compared_fragments, are_mutually_exclusive, field_map, fragment_name2, ) # Collect all conflicts found between two fragments, including via spreading in # any nested fragments def _collect_conflicts_between_fragments( context, # type: ValidationContext conflicts, # type: List[Tuple[Tuple[str, str], List[Node], List[Node]]] cached_fields_and_fragment_names, # type: Dict[SelectionSet, Tuple[Dict[str, List[Tuple[Union[GraphQLInterfaceType, GraphQLObjectType, None], Field, GraphQLField]]], List[str]]] compared_fragments, # type: PairSet are_mutually_exclusive, # type: bool fragment_name1, # type: str fragment_name2, # type: str ): fragment1 = context.get_fragment(fragment_name1) fragment2 = context.get_fragment(fragment_name2) if not fragment1 or not fragment2: return None # No need to compare a fragment to itself. if fragment1 == fragment2: return None # Memoize so two fragments are not compared for conflicts more than once. if compared_fragments.has(fragment_name1, fragment_name2, are_mutually_exclusive): return None compared_fragments.add(fragment_name1, fragment_name2, are_mutually_exclusive) field_map1, fragment_names1 = _get_referenced_fields_and_fragment_names( context, cached_fields_and_fragment_names, fragment1 ) field_map2, 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_fragments, 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 _fragment_name2 in fragment_names2: _collect_conflicts_between_fragments( context, conflicts, cached_fields_and_fragment_names, compared_fragments, are_mutually_exclusive, fragment_name1, _fragment_name2, ) # (G) Then collect conflicts between the second fragment and any nested # fragments spread in the first fragment. for _fragment_name1 in fragment_names1: _collect_conflicts_between_fragments( context, conflicts, cached_fields_and_fragment_names, compared_fragments, are_mutually_exclusive, _fragment_name1, fragment_name2, ) def _find_conflicts_between_sub_selection_sets( context, # type: ValidationContext cached_fields_and_fragment_names, # type: Dict[SelectionSet, Tuple[Dict[str, List[Tuple[Union[GraphQLInterfaceType, GraphQLObjectType, None], Field, GraphQLField]]], List[str]]] compared_fragments, # type: PairSet are_mutually_exclusive, # type: bool parent_type1, # type: Union[GraphQLInterfaceType, GraphQLObjectType, None] selection_set1, # type: SelectionSet parent_type2, # type: Union[GraphQLInterfaceType, GraphQLObjectType, None] selection_set2, # type: SelectionSet ): # type: (...) -> List[Tuple[Tuple[str, str], List[Node], List[Node]]] """Find all conflicts found between two selection sets. Includes those found via spreading in fragments. Called when determining if conflicts exist between the sub-fields of two overlapping fields. """ conflicts = [] # type: List[Tuple[Tuple[str, str], List[Node], List[Node]]] field_map1, fragment_names1 = _get_fields_and_fragments_names( context, cached_fields_and_fragment_names, parent_type1, selection_set1 ) field_map2, fragment_names2 = _get_fields_and_fragments_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_fragments, 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. for fragment_name2 in fragment_names2: _collect_conflicts_between_fields_and_fragment( context, conflicts, cached_fields_and_fragment_names, compared_fragments, 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. for fragment_name1 in fragment_names1: _collect_conflicts_between_fields_and_fragment( context, conflicts, cached_fields_and_fragment_names, compared_fragments, 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_fragments, are_mutually_exclusive, fragment_name1, fragment_name2, ) return conflicts def _collect_conflicts_within( context, # type: ValidationContext conflicts, # type: List[Tuple[Tuple[str, str], List[Node], List[Node]]] cached_fields_and_fragment_names, # type: Dict[SelectionSet, Tuple[Dict[str, List[Tuple[Union[GraphQLInterfaceType, GraphQLObjectType, None], Field, GraphQLField]]], List[str]]] compared_fragments, # type: PairSet field_map, # type: Dict[str, List[Tuple[Union[GraphQLInterfaceType, GraphQLObjectType, None], Field, GraphQLField]]] ): # type: (...) -> None """Collect all Conflicts "within" one collection of fields.""" # 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 list(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. for i, field in enumerate(fields): for other_field in fields[i + 1 :]: # within one collection is never mutually exclusive conflict = _find_conflict( context, cached_fields_and_fragment_names, compared_fragments, False, response_name, field, other_field, ) if conflict: conflicts.append(conflict) def _collect_conflicts_between( context, # type: ValidationContext conflicts, # type: List[Tuple[Tuple[str, str], List[Node], List[Node]]] cached_fields_and_fragment_names, # type: Dict[SelectionSet, Tuple[Dict[str, List[Tuple[Union[GraphQLInterfaceType, GraphQLObjectType, None], Field, GraphQLField]]], List[str]]] compared_fragments, # type: PairSet parent_fields_are_mutually_exclusive, # type: bool field_map1, # type: Dict[str, List[Tuple[Union[GraphQLInterfaceType, GraphQLObjectType, None], Field, GraphQLField]]] field_map2, # type: Dict[str, List[Tuple[Union[GraphQLInterfaceType, GraphQLObjectType, None], Field, GraphQLField]]] ): # type: (...) -> None """Collect all Conflicts between two collections of fields. This is similar to, but different from the `collect_conflicts_within` function above. This check assumes that `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 list(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_fragments, parent_fields_are_mutually_exclusive, response_name, field1, field2, ) if conflict: conflicts.append(conflict) def _find_conflict( context, # type: ValidationContext cached_fields_and_fragment_names, # type: Dict[SelectionSet, Tuple[Dict[str, List[Tuple[Union[GraphQLInterfaceType, GraphQLObjectType, None], Field, GraphQLField]]], List[str]]] compared_fragments, # type: PairSet parent_fields_are_mutually_exclusive, # type: bool response_name, # type: str field1, # type: Tuple[Union[GraphQLInterfaceType, GraphQLObjectType, None], Field, GraphQLField] field2, # type: Tuple[Union[GraphQLInterfaceType, GraphQLObjectType, None], Field, GraphQLField] ): # type: (...) -> Optional[Tuple[Tuple[str, str], List[Node], List[Node]]] """Determines if there is a conflict between two particular fields.""" parent_type1, ast1, def1 = field1 parent_type2, ast2, 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 isinstance(parent_type1, GraphQLObjectType) and isinstance(parent_type2, GraphQLObjectType) ) # The return type for each field. type1 = def1 and def1.type type2 = def2 and def2.type if not are_mutually_exclusive: # Two aliases must refer to the same field. name1 = ast1.name.value name2 = ast2.name.value if name1 != name2: return ( (response_name, "{} and {} are different fields".format(name1, name2)), [ast1], [ast2], ) # Two field calls must have the same arguments. if not _same_arguments(ast1.arguments, ast2.arguments): return (response_name, "they have differing arguments"), [ast1], [ast2] if type1 and type2 and do_types_conflict(type1, type2): return ( ( response_name, "they return conflicting types {} and {}".format(type1, type2), ), [ast1], [ast2], ) # 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 = ast1.selection_set selection_set2 = ast2.selection_set if selection_set1 and selection_set2: conflicts = _find_conflicts_between_sub_selection_sets( # type: ignore context, cached_fields_and_fragment_names, compared_fragments, are_mutually_exclusive, get_named_type(type1), # type: ignore selection_set1, get_named_type(type2), # type: ignore selection_set2, ) return _subfield_conflicts(conflicts, response_name, ast1, ast2) return None def _get_fields_and_fragments_names( context, # type: ValidationContext cached_fields_and_fragment_names, # type: Dict[SelectionSet, Tuple[Dict[str, List[Tuple[Union[GraphQLInterfaceType, GraphQLObjectType, None], Field, GraphQLField]]], List[str]]] parent_type, # type: Union[GraphQLInterfaceType, GraphQLObjectType, None] selection_set, # type: SelectionSet ): # type: (...) -> Tuple[Dict[str, List[Tuple[Union[GraphQLInterfaceType, GraphQLObjectType, None], Field, GraphQLField]]], List[str]] cached = cached_fields_and_fragment_names.get(selection_set) if not cached: ast_and_defs = ( OrderedDict() ) # type: Dict[str, List[Tuple[Union[GraphQLInterfaceType, GraphQLObjectType, None], Field, GraphQLField]]] fragment_names = OrderedDict() # type: Dict[str, bool] _collect_fields_and_fragment_names( context, parent_type, selection_set, ast_and_defs, fragment_names ) cached = (ast_and_defs, list(fragment_names.keys())) cached_fields_and_fragment_names[selection_set] = cached return cached def _get_referenced_fields_and_fragment_names( context, # ValidationContext cached_fields_and_fragment_names, # type: Dict[SelectionSet, Tuple[Dict[str, List[Tuple[Union[GraphQLInterfaceType, GraphQLObjectType, None], Field, GraphQLField]]], List[str]]] fragment, # type: InlineFragment ): # type: (...) -> Tuple[Dict[str, List[Tuple[Union[GraphQLInterfaceType, GraphQLObjectType, None], Field, GraphQLField]]], List[str]] """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 AST if possible. cached = cached_fields_and_fragment_names.get(fragment.selection_set) if cached: return cached fragment_type = type_from_ast( context.get_schema(), fragment.type_condition # type: ignore ) return _get_fields_and_fragments_names( context, cached_fields_and_fragment_names, fragment_type, # type: ignore fragment.selection_set, ) def _collect_fields_and_fragment_names( context, # type: ValidationContext parent_type, # type: Union[GraphQLInterfaceType, GraphQLObjectType, None] selection_set, # type: SelectionSet ast_and_defs, # type: Dict[str, List[Tuple[Union[GraphQLInterfaceType, GraphQLObjectType, None], Field, GraphQLField]]] fragment_names, # type: Dict[str, bool] ): # type: (...) -> None for selection in selection_set.selections: if isinstance(selection, ast.Field): field_name = selection.name.value if isinstance(parent_type, (GraphQLObjectType, GraphQLInterfaceType)): field_def = parent_type.fields.get(field_name) else: field_def = None response_name = selection.alias.value if selection.alias else field_name if not ast_and_defs.get(response_name): ast_and_defs[response_name] = [] # type: ignore ast_and_defs[response_name].append((parent_type, selection, field_def)) elif isinstance(selection, ast.FragmentSpread): fragment_names[selection.name.value] = True elif isinstance(selection, ast.InlineFragment): type_condition = selection.type_condition if type_condition: inline_fragment_type = type_from_ast( context.get_schema(), selection.type_condition # type: ignore ) else: inline_fragment_type = parent_type # type: ignore _collect_fields_and_fragment_names( context, inline_fragment_type, # type: ignore selection.selection_set, ast_and_defs, fragment_names, ) def _subfield_conflicts( conflicts, # type: List[Tuple[Tuple[str, str], List[Node], List[Node]]] response_name, # type: str ast1, # type: Node ast2, # type: Node ): # type: (...) -> Optional[Tuple[Tuple[str, str], List[Node], List[Node]]] """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]), # type: ignore list(itertools.chain([ast1], *[conflict[1] for conflict in conflicts])), list(itertools.chain([ast2], *[conflict[2] for conflict in conflicts])), ) return None def do_types_conflict(type1, type2): # type: (GraphQLOutputType, 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 _same_value(value1, value2): # type: (Optional[Node], Optional[Node]) -> bool if not value1 and not value2: return True if not value1 or not value2: return False return print_ast(value1) == print_ast(value2) def _same_arguments(arguments1, arguments2): # type: (Optional[List[Argument]], Optional[List[Argument]]) -> bool # Check to see if they are empty arguments or nones. If they are, we can # bail out early. if not arguments1 and not arguments2: return True if not arguments1: return False if not arguments2: return False if len(arguments1) != len(arguments2): return False arguments2_values_to_arg = {a.name.value: a for a in arguments2} for argument1 in arguments1: argument2 = arguments2_values_to_arg.get(argument1.name.value) if not argument2: return False if not _same_value(argument1.value, argument2.value): return False return True graphql-core-legacy-2.3.2/graphql/validation/rules/possible_fragment_spreads.py000066400000000000000000000047611365661746200301140ustar00rootroot00000000000000from ...error import GraphQLError from ...utils.type_comparators import do_types_overlap from ...utils.type_from_ast import type_from_ast from .base import ValidationRule # Necessary for static type checking if False: # flake8: noqa from ...language.ast import Field, InlineFragment from typing import Any, List, Union class PossibleFragmentSpreads(ValidationRule): def enter_InlineFragment( self, node, # type: InlineFragment key, # type: int parent, # type: List[Union[Field, InlineFragment]] path, # type: List[Union[int, str]] ancestors, # type: List[Any] ): # type: (...) -> None frag_type = self.context.get_type() parent_type = self.context.get_parent_type() schema = self.context.get_schema() if ( frag_type and parent_type and not do_types_overlap(schema, frag_type, parent_type) # type: ignore ): self.context.report_error( GraphQLError( self.type_incompatible_anon_spread_message(parent_type, frag_type), [node], ) ) def enter_FragmentSpread(self, node, key, parent, path, ancestors): frag_name = node.name.value frag_type = self.get_fragment_type(self.context, frag_name) parent_type = self.context.get_parent_type() schema = self.context.get_schema() if ( frag_type and parent_type and not do_types_overlap(schema, frag_type, parent_type) ): self.context.report_error( GraphQLError( self.type_incompatible_spread_message( frag_name, parent_type, frag_type ), [node], ) ) @staticmethod def get_fragment_type(context, name): frag = context.get_fragment(name) return frag and type_from_ast(context.get_schema(), frag.type_condition) @staticmethod def type_incompatible_spread_message(frag_name, parent_type, frag_type): return "Fragment {} cannot be spread here as objects of type {} can never be of type {}".format( frag_name, parent_type, frag_type ) @staticmethod def type_incompatible_anon_spread_message(parent_type, frag_type): return "Fragment cannot be spread here as objects of type {} can never be of type {}".format( parent_type, frag_type ) graphql-core-legacy-2.3.2/graphql/validation/rules/provided_non_null_arguments.py000066400000000000000000000047621365661746200304760ustar00rootroot00000000000000from ...error import GraphQLError from ...type.definition import GraphQLNonNull from .base import ValidationRule # Necessary for static type checking if False: # flake8: noqa from ...language.ast import Field, InlineFragment from typing import Any, List, Optional, Union class ProvidedNonNullArguments(ValidationRule): def leave_Field( self, node, # type: Field key, # type: int parent, # type: Union[List[Union[Field, InlineFragment]], List[Field]] path, # type: List[Union[int, str]] ancestors, # type: List[Any] ): # type: (...) -> Optional[Any] field_def = self.context.get_field_def() if not field_def: return False arg_asts = node.arguments or [] arg_ast_map = {arg.name.value: arg for arg in arg_asts} for arg_name, arg_def in field_def.args.items(): arg_ast = arg_ast_map.get(arg_name, None) if not arg_ast and isinstance(arg_def.type, GraphQLNonNull): self.context.report_error( GraphQLError( self.missing_field_arg_message( node.name.value, arg_name, arg_def.type ), [node], ) ) return None def leave_Directive(self, node, key, parent, path, ancestors): directive_def = self.context.get_directive() if not directive_def: return False arg_asts = node.arguments or [] arg_ast_map = {arg.name.value: arg for arg in arg_asts} for arg_name, arg_def in directive_def.args.items(): arg_ast = arg_ast_map.get(arg_name, None) if not arg_ast and isinstance(arg_def.type, GraphQLNonNull): self.context.report_error( GraphQLError( self.missing_directive_arg_message( node.name.value, arg_name, arg_def.type ), [node], ) ) @staticmethod def missing_field_arg_message(name, arg_name, type): return 'Field "{}" argument "{}" of type "{}" is required but not provided.'.format( name, arg_name, type ) @staticmethod def missing_directive_arg_message(name, arg_name, type): return 'Directive "{}" argument "{}" of type "{}" is required but not provided.'.format( name, arg_name, type ) graphql-core-legacy-2.3.2/graphql/validation/rules/scalar_leafs.py000066400000000000000000000030721365661746200253010ustar00rootroot00000000000000from ...error import GraphQLError from ...type.definition import get_named_type, is_leaf_type from .base import ValidationRule # Necessary for static type checking if False: # flake8: noqa from ...language.ast import Field, InlineFragment from typing import Any, List, Union class ScalarLeafs(ValidationRule): def enter_Field( self, node, # type: Field key, # type: int parent, # type: Union[List[Union[Field, InlineFragment]], List[Field]] path, # type: List[Union[int, str]] ancestors, # type: List[Any] ): # type: (...) -> None type = self.context.get_type() if not type: return if is_leaf_type(get_named_type(type)): if node.selection_set: self.context.report_error( GraphQLError( self.no_subselection_allowed_message(node.name.value, type), [node.selection_set], ) ) elif not node.selection_set: self.context.report_error( GraphQLError( self.required_subselection_message(node.name.value, type), [node] ) ) @staticmethod def no_subselection_allowed_message(field, type): return 'Field "{}" of type "{}" must not have a sub selection.'.format( field, type ) @staticmethod def required_subselection_message(field, type): return 'Field "{}" of type "{}" must have a sub selection.'.format(field, type) graphql-core-legacy-2.3.2/graphql/validation/rules/unique_argument_names.py000066400000000000000000000033661365661746200272630ustar00rootroot00000000000000from ...error import GraphQLError from .base import ValidationRule # Necessary for static type checking if False: # flake8: noqa from ..validation import ValidationContext from ...language.ast import Field, InlineFragment, Argument, Name from typing import Any, List, Union, Dict class UniqueArgumentNames(ValidationRule): __slots__ = ("known_arg_names",) def __init__(self, context): # type: (ValidationContext) -> None super(UniqueArgumentNames, self).__init__(context) self.known_arg_names = {} # type: Dict[str, Name] def enter_Field( self, node, # type: Field key, # type: int parent, # type: Union[List[Union[Field, InlineFragment]], List[Field]] path, # type: List[Union[int, str]] ancestors, # type: List[Any] ): # type: (...) -> None self.known_arg_names = {} def enter_Directive(self, node, key, parent, path, ancestors): self.known_arg_names = {} def enter_Argument( self, node, # type: Argument key, # type: int parent, # type: List[Argument] path, # type: List[Union[int, str]] ancestors, # type: List[Any] ): # type: (...) -> bool arg_name = node.name.value if arg_name in self.known_arg_names: self.context.report_error( GraphQLError( self.duplicate_arg_message(arg_name), [self.known_arg_names[arg_name], node.name], ) ) else: self.known_arg_names[arg_name] = node.name return False @staticmethod def duplicate_arg_message(field): return 'There can only be one argument named "{}".'.format(field) graphql-core-legacy-2.3.2/graphql/validation/rules/unique_fragment_names.py000066400000000000000000000030211365661746200272300ustar00rootroot00000000000000from ...error import GraphQLError from .base import ValidationRule # Necessary for static type checking if False: # flake8: noqa from ..validation import ValidationContext from ...language.ast import Document, OperationDefinition, Name from typing import List, Union, Dict class UniqueFragmentNames(ValidationRule): __slots__ = ("known_fragment_names",) def __init__(self, context): # type: (ValidationContext) -> None super(UniqueFragmentNames, self).__init__(context) self.known_fragment_names = {} # type: Dict[str, Name] def enter_OperationDefinition( self, node, # type: OperationDefinition key, # type: int parent, # type: List[OperationDefinition] path, # type: List[Union[int, str]] ancestors, # type: List[Document] ): # type: (...) -> bool return False def enter_FragmentDefinition(self, node, key, parent, path, ancestors): fragment_name = node.name.value if fragment_name in self.known_fragment_names: self.context.report_error( GraphQLError( self.duplicate_fragment_name_message(fragment_name), [self.known_fragment_names[fragment_name], node.name], ) ) else: self.known_fragment_names[fragment_name] = node.name return False @staticmethod def duplicate_fragment_name_message(field): return 'There can only be one fragment named "{}".'.format(field) graphql-core-legacy-2.3.2/graphql/validation/rules/unique_input_field_names.py000066400000000000000000000041221365661746200277320ustar00rootroot00000000000000from ...error import GraphQLError from .base import ValidationRule # Necessary for static type checking if False: # flake8: noqa from ..validation import ValidationContext from ...language.ast import Argument, ObjectValue, ObjectField, Name from typing import Any, List, Union, Dict class UniqueInputFieldNames(ValidationRule): __slots__ = "known_names", "known_names_stack" def __init__(self, context): # type: (ValidationContext) -> None super(UniqueInputFieldNames, self).__init__(context) self.known_names = {} # type: Dict[str, Name] self.known_names_stack = [] # type: List[Dict[str, Name]] def enter_ObjectValue( self, node, # type: ObjectValue key, # type: str parent, # type: Argument path, # type: List[Union[int, str]] ancestors, # type: List[Any] ): # type: (...) -> None self.known_names_stack.append(self.known_names) self.known_names = {} def leave_ObjectValue( self, node, # type: ObjectValue key, # type: str parent, # type: Argument path, # type: List[Union[int, str]] ancestors, # type: List[Any] ): # type: (...) -> None self.known_names = self.known_names_stack.pop() def enter_ObjectField( self, node, # type: ObjectField key, # type: int parent, # type: List[ObjectField] path, # type: List[Union[int, str]] ancestors, # type: List[Any] ): # type: (...) -> bool field_name = node.name.value if field_name in self.known_names: self.context.report_error( GraphQLError( self.duplicate_input_field_message(field_name), [self.known_names[field_name], node.name], ) ) else: self.known_names[field_name] = node.name return False @staticmethod def duplicate_input_field_message(field_name): return 'There can only be one input field named "{}".'.format(field_name) graphql-core-legacy-2.3.2/graphql/validation/rules/unique_operation_names.py000066400000000000000000000032361365661746200274350ustar00rootroot00000000000000from ...error import GraphQLError from .base import ValidationRule # Necessary for static type checking if False: # flake8: noqa from ..validation import ValidationContext from ...language.ast import Document, OperationDefinition, Name from typing import Any, List, Optional, Union, Dict class UniqueOperationNames(ValidationRule): __slots__ = ("known_operation_names",) def __init__(self, context): # type: (ValidationContext) -> None super(UniqueOperationNames, self).__init__(context) self.known_operation_names = {} # type: Dict[str, Name] def enter_OperationDefinition( self, node, # type: OperationDefinition key, # type: int parent, # type: List[OperationDefinition] path, # type: List[Union[int, str]] ancestors, # type: List[Document] ): # type: (...) -> Optional[Any] operation_name = node.name if not operation_name: return None if operation_name.value in self.known_operation_names: self.context.report_error( GraphQLError( self.duplicate_operation_name_message(operation_name.value), [self.known_operation_names[operation_name.value], operation_name], ) ) else: self.known_operation_names[operation_name.value] = operation_name return False def enter_FragmentDefinition(self, node, key, parent, path, ancestors): return False @staticmethod def duplicate_operation_name_message(operation_name): return 'There can only be one operation named "{}".'.format(operation_name) graphql-core-legacy-2.3.2/graphql/validation/rules/unique_variable_names.py000066400000000000000000000030521365661746200272160ustar00rootroot00000000000000from ...error import GraphQLError from .base import ValidationRule # Necessary for static type checking if False: # flake8: noqa from ..validation import ValidationContext from ...language.ast import Document, OperationDefinition from typing import List, Union, Dict class UniqueVariableNames(ValidationRule): __slots__ = ("known_variable_names",) def __init__(self, context): # type: (ValidationContext) -> None super(UniqueVariableNames, self).__init__(context) self.known_variable_names = {} # type: Dict[str, str] def enter_OperationDefinition( self, node, # type: OperationDefinition key, # type: int parent, # type: List[OperationDefinition] path, # type: List[Union[int, str]] ancestors, # type: List[Document] ): # type: (...) -> None self.known_variable_names = {} def enter_VariableDefinition(self, node, key, parent, path, ancestors): variable_name = node.variable.name.value if variable_name in self.known_variable_names: self.context.report_error( GraphQLError( self.duplicate_variable_message(variable_name), [self.known_variable_names[variable_name], node.variable.name], ) ) else: self.known_variable_names[variable_name] = node.variable.name @staticmethod def duplicate_variable_message(operation_name): return 'There can be only one variable named "{}".'.format(operation_name) graphql-core-legacy-2.3.2/graphql/validation/rules/variables_are_input_types.py000066400000000000000000000016501365661746200301240ustar00rootroot00000000000000from ...error import GraphQLError from ...language.printer import print_ast from ...type.definition import is_input_type from ...utils.type_from_ast import type_from_ast from .base import ValidationRule class VariablesAreInputTypes(ValidationRule): def enter_VariableDefinition(self, node, key, parent, path, ancestors): type = type_from_ast(self.context.get_schema(), node.type) if type and not is_input_type(type): self.context.report_error( GraphQLError( self.non_input_type_on_variable_message( node.variable.name.value, print_ast(node.type) ), [node.type], ) ) @staticmethod def non_input_type_on_variable_message(variable_name, type_name): return 'Variable "${}" cannot be non-input type "{}".'.format( variable_name, type_name ) graphql-core-legacy-2.3.2/graphql/validation/rules/variables_in_allowed_position.py000066400000000000000000000063361365661746200307610ustar00rootroot00000000000000from ...error import GraphQLError from ...type.definition import GraphQLNonNull from ...utils.type_comparators import is_type_sub_type_of from ...utils.type_from_ast import type_from_ast from .base import ValidationRule # Necessary for static type checking if False: # flake8: noqa from ..validation import ValidationContext from ...language.ast import Document, OperationDefinition, VariableDefinition from typing import List, Union, Dict, Any class VariablesInAllowedPosition(ValidationRule): __slots__ = "var_def_map" def __init__(self, context): # type: (ValidationContext) -> None super(VariablesInAllowedPosition, self).__init__(context) self.var_def_map = {} # type: Dict[str, VariableDefinition] def enter_OperationDefinition( self, node, # type: OperationDefinition key, # type: int parent, # type: List[OperationDefinition] path, # type: List[Union[int, str]] ancestors, # type: List[Document] ): # type: (...) -> None self.var_def_map = {} def leave_OperationDefinition( self, operation, # type: OperationDefinition key, # type: int parent, # type: List[OperationDefinition] path, # type: List[str] ancestors, # type: List[Document] ): # type: (...) -> None usages = self.context.get_recursive_variable_usages(operation) for usage in usages: node = usage.node type = usage.type var_name = node.name.value var_def = self.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.get_schema() var_type = type_from_ast(schema, var_def.type) if var_type and not is_type_sub_type_of( schema, self.effective_type(var_type, var_def), type ): self.context.report_error( GraphQLError( self.bad_var_pos_message(var_name, var_type, type), [var_def, node], ) ) def enter_VariableDefinition( self, node, # type: VariableDefinition key, # type: int parent, # type: Any path, # type: List[str] ancestors, # type: List[Document] ): self.var_def_map[node.variable.name.value] = node @staticmethod def effective_type(var_type, var_def): if not var_def.default_value or isinstance(var_type, GraphQLNonNull): return var_type return GraphQLNonNull(var_type) @staticmethod def bad_var_pos_message(var_name, var_type, expected_type): return 'Variable "{}" of type "{}" used in position expecting type "{}".'.format( var_name, var_type, expected_type ) graphql-core-legacy-2.3.2/graphql/validation/tests/000077500000000000000000000000001365661746200223165ustar00rootroot00000000000000graphql-core-legacy-2.3.2/graphql/validation/tests/__init__.py000066400000000000000000000000001365661746200244150ustar00rootroot00000000000000graphql-core-legacy-2.3.2/graphql/validation/tests/test_arguments_of_correct_type.py000066400000000000000000000511171365661746200312070ustar00rootroot00000000000000from graphql.language.location import SourceLocation from graphql.validation.rules import ArgumentsOfCorrectType from .utils import expect_fails_rule, expect_passes_rule def bad_value(arg_name, type_name, value, line, column, errors=None): if not errors: errors = [u'Expected type "{}", found {}.'.format(type_name, value)] return { "message": ArgumentsOfCorrectType.bad_value_message( arg_name, type_name, value, errors ), "locations": [SourceLocation(line, column)], } # noinspection PyMethodMayBeStatic class TestValidValues(object): def test_good_int_value(self): expect_passes_rule( ArgumentsOfCorrectType, """ { complicatedArgs { intArgField(intArg: 2) } } """, ) def test_good_boolean_value(self): expect_passes_rule( ArgumentsOfCorrectType, """ { complicatedArgs { booleanArgField(booleanArg: true) } } """, ) def test_good_string_value(self): expect_passes_rule( ArgumentsOfCorrectType, """ { complicatedArgs { stringArgField(stringArg: "foo") } } """, ) def test_good_float_value(self): expect_passes_rule( ArgumentsOfCorrectType, """ { complicatedArgs { floatArgField(floatArg: 1.1) } } """, ) def test_int_into_float(self): expect_passes_rule( ArgumentsOfCorrectType, """ { complicatedArgs { floatArgField(floatArg: 1) } } """, ) def test_int_into_id(self): expect_passes_rule( ArgumentsOfCorrectType, """ { complicatedArgs { idArgField(idArg: 1) } } """, ) def test_string_into_id(self): expect_passes_rule( ArgumentsOfCorrectType, """ { complicatedArgs { idArgField(idArg: "someIdString") } } """, ) def test_good_enum_value(self): expect_passes_rule( ArgumentsOfCorrectType, """ { dog { doesKnowCommand(dogCommand: SIT) } } """, ) # noinspection PyMethodMayBeStatic class TestInvalidStringValues(object): def test_int_into_string(self): expect_fails_rule( ArgumentsOfCorrectType, """ { complicatedArgs { stringArgField(stringArg: 1) } } """, [bad_value("stringArg", "String", "1", 4, 43)], ) def test_float_into_string(self): expect_fails_rule( ArgumentsOfCorrectType, """ { complicatedArgs { stringArgField(stringArg: 1.0) } } """, [bad_value("stringArg", "String", "1.0", 4, 43)], ) def test_bool_into_string(self): expect_fails_rule( ArgumentsOfCorrectType, """ { complicatedArgs { stringArgField(stringArg: true) } } """, [bad_value("stringArg", "String", "true", 4, 43)], ) def test_unquoted_string_into_string(self): expect_fails_rule( ArgumentsOfCorrectType, """ { complicatedArgs { stringArgField(stringArg: BAR) } } """, [bad_value("stringArg", "String", "BAR", 4, 43)], ) # noinspection PyMethodMayBeStatic class TestInvalidIntValues(object): def test_string_into_int(self): expect_fails_rule( ArgumentsOfCorrectType, """ { complicatedArgs { intArgField(intArg: "3") } } """, [bad_value("intArg", "Int", '"3"', 4, 37)], ) def test_big_int_into_int(self): expect_fails_rule( ArgumentsOfCorrectType, """ { complicatedArgs { intArgField(intArg: 829384293849283498239482938) } } """, [bad_value("intArg", "Int", "829384293849283498239482938", 4, 37)], ) def test_unquoted_string_into_int(self): expect_fails_rule( ArgumentsOfCorrectType, """ { complicatedArgs { intArgField(intArg: FOO) } } """, [bad_value("intArg", "Int", "FOO", 4, 37)], ) def test_simple_float_into_int(self): expect_fails_rule( ArgumentsOfCorrectType, """ { complicatedArgs { intArgField(intArg: 3.0) } } """, [bad_value("intArg", "Int", "3.0", 4, 37)], ) def test_float_into_int(self): expect_fails_rule( ArgumentsOfCorrectType, """ { complicatedArgs { intArgField(intArg: 3.333) } } """, [bad_value("intArg", "Int", "3.333", 4, 37)], ) # noinspection PyMethodMayBeStatic class TestInvalidFloatValues(object): def test_string_into_float(self): expect_fails_rule( ArgumentsOfCorrectType, """ { complicatedArgs { floatArgField(floatArg: "3.333") } } """, [bad_value("floatArg", "Float", '"3.333"', 4, 41)], ) def test_boolean_into_float(self): expect_fails_rule( ArgumentsOfCorrectType, """ { complicatedArgs { floatArgField(floatArg: true) } } """, [bad_value("floatArg", "Float", "true", 4, 41)], ) def test_unquoted_into_float(self): expect_fails_rule( ArgumentsOfCorrectType, """ { complicatedArgs { floatArgField(floatArg: FOO) } } """, [bad_value("floatArg", "Float", "FOO", 4, 41)], ) # noinspection PyMethodMayBeStatic class TestInvalidBooleanValues(object): def test_int_into_boolean(self): expect_fails_rule( ArgumentsOfCorrectType, """ { complicatedArgs { booleanArgField(booleanArg: 2) } } """, [bad_value("booleanArg", "Boolean", "2", 4, 45)], ) def test_float_into_boolean(self): expect_fails_rule( ArgumentsOfCorrectType, """ { complicatedArgs { booleanArgField(booleanArg: 1.0) } } """, [bad_value("booleanArg", "Boolean", "1.0", 4, 45)], ) def test_string_into_boolean(self): expect_fails_rule( ArgumentsOfCorrectType, """ { complicatedArgs { booleanArgField(booleanArg: "true") } } """, [bad_value("booleanArg", "Boolean", '"true"', 4, 45)], ) def test_unquoted_into_boolean(self): expect_fails_rule( ArgumentsOfCorrectType, """ { complicatedArgs { booleanArgField(booleanArg: TRUE) } } """, [bad_value("booleanArg", "Boolean", "TRUE", 4, 45)], ) # noinspection PyMethodMayBeStatic class TestInvalidIDValues(object): def test_float_into_id(self): expect_fails_rule( ArgumentsOfCorrectType, """ { complicatedArgs { idArgField(idArg: 1.0) } } """, [bad_value("idArg", "ID", "1.0", 4, 35)], ) def test_boolean_into_id(self): expect_fails_rule( ArgumentsOfCorrectType, """ { complicatedArgs { idArgField(idArg: true) } } """, [bad_value("idArg", "ID", "true", 4, 35)], ) def test_unquoted_into_id(self): expect_fails_rule( ArgumentsOfCorrectType, """ { complicatedArgs { idArgField(idArg: SOMETHING) } } """, [bad_value("idArg", "ID", "SOMETHING", 4, 35)], ) # noinspection PyMethodMayBeStatic class TestInvalidEnumValues(object): def test_int_into_enum(self): expect_fails_rule( ArgumentsOfCorrectType, """ { dog { doesKnowCommand(dogCommand: 2) } } """, [bad_value("dogCommand", "DogCommand", "2", 4, 45)], ) def test_float_into_enum(self): expect_fails_rule( ArgumentsOfCorrectType, """ { dog { doesKnowCommand(dogCommand: 1.0) } } """, [bad_value("dogCommand", "DogCommand", "1.0", 4, 45)], ) def test_string_into_enum(self): expect_fails_rule( ArgumentsOfCorrectType, """ { dog { doesKnowCommand(dogCommand: "SIT") } } """, [bad_value("dogCommand", "DogCommand", '"SIT"', 4, 45)], ) def test_boolean_into_enum(self): expect_fails_rule( ArgumentsOfCorrectType, """ { dog { doesKnowCommand(dogCommand: true) } } """, [bad_value("dogCommand", "DogCommand", "true", 4, 45)], ) def test_unknown_enum_value_into_enum(self): expect_fails_rule( ArgumentsOfCorrectType, """ { dog { doesKnowCommand(dogCommand: JUGGLE) } } """, [bad_value("dogCommand", "DogCommand", "JUGGLE", 4, 45)], ) def test_different_case_enum_value_into_enum(self): expect_fails_rule( ArgumentsOfCorrectType, """ { dog { doesKnowCommand(dogCommand: sit) } } """, [bad_value("dogCommand", "DogCommand", "sit", 4, 45)], ) # noinspection PyMethodMayBeStatic class TestValidListValues(object): def test_good_list_value(self): expect_passes_rule( ArgumentsOfCorrectType, """ { complicatedArgs { stringListArgField(stringListArg: ["one", "two"]) } } """, ) def test_empty_list_value(self): expect_passes_rule( ArgumentsOfCorrectType, """ { complicatedArgs { stringListArgField(stringListArg: []) } } """, ) def test_single_value_into_list(self): expect_passes_rule( ArgumentsOfCorrectType, """ { complicatedArgs { stringListArgField(stringListArg: "one") } } """, ) # noinspection PyMethodMayBeStatic class TestInvalidListValues(object): def test_incorrect_item_type(self): expect_fails_rule( ArgumentsOfCorrectType, """ { complicatedArgs { stringListArgField(stringListArg: ["one", 2]) } } """, [ bad_value( "stringListArg", "String", '["one", 2]', 4, 51, ['In element #1: Expected type "String", found 2.'], ) ], ) def test_single_value_of_incorrect_type(self): expect_fails_rule( ArgumentsOfCorrectType, """ { complicatedArgs { stringListArgField(stringListArg: 1) } } """, [bad_value("stringListArg", "String", "1", 4, 51)], ) # noinspection PyMethodMayBeStatic class TestValidNonNullableValues(object): def test_arg_on_optional_arg(self): expect_passes_rule( ArgumentsOfCorrectType, """ { dog { isHousetrained(atOtherHomes: true) } } """, ) def test_no_arg_on_optional_arg(self): expect_passes_rule( ArgumentsOfCorrectType, """ { dog { isHousetrained } } """, ) def test_multiple_args(self): expect_passes_rule( ArgumentsOfCorrectType, """ { complicatedArgs { multipleReqs(req1: 1, req2: 2) } } """, ) def test_multiple_args_reverse_order(self): expect_passes_rule( ArgumentsOfCorrectType, """ { complicatedArgs { multipleReqs(req2: 2, req1: 1) } } """, ) def test_no_args_on_multiple_optional(self): expect_passes_rule( ArgumentsOfCorrectType, """ { complicatedArgs { multipleOpts } } """, ) def test_one_arg_on_multiple_optional(self): expect_passes_rule( ArgumentsOfCorrectType, """ { complicatedArgs { multipleOpts(opt1: 1) } } """, ) def test_second_arg_on_multiple_optional(self): expect_passes_rule( ArgumentsOfCorrectType, """ { complicatedArgs { multipleOpts(opt2: 1) } } """, ) def test_multiple_reqs_and_one_opt_on_mixed_list(self): expect_passes_rule( ArgumentsOfCorrectType, """ { complicatedArgs { multipleOpts(req1: 3, req2: 4, opt1: 5) } } """, ) def test_all_reqs_and_opts_on_mixed_list(self): expect_passes_rule( ArgumentsOfCorrectType, """ { complicatedArgs { multipleOpts(req1: 3, req2: 4, opt1: 5, opt2: 6) } } """, ) # noinspection PyMethodMayBeStatic class TestInvalidNonNullableValues(object): def test_incorrect_value_type(self): expect_fails_rule( ArgumentsOfCorrectType, """ { complicatedArgs { multipleOptsAndReq(req2: "two", req1: "one") } } """, [ bad_value("req2", "Int", '"two"', 4, 42), bad_value("req1", "Int", '"one"', 4, 55), ], ) def test_incorrect_value_and_missing_argument(self): expect_fails_rule( ArgumentsOfCorrectType, """ { complicatedArgs { multipleReqs(req1: "one") } } """, [bad_value("req1", "Int", '"one"', 4, 36)], ) # noinspection PyMethodMayBeStatic class TestValidInputObjectValue(object): def test_optional_arg_despite_required_field_in_type(self): expect_passes_rule( ArgumentsOfCorrectType, """ { complicatedArgs { complexArgField } } """, ) def test_partial_object_only_required(self): expect_passes_rule( ArgumentsOfCorrectType, """ { complicatedArgs { complexArgField(complexArg: { requiredField: true }) } } """, ) def test_partial_object_required_field_can_be_falsey(self): expect_passes_rule( ArgumentsOfCorrectType, """ { complicatedArgs { complexArgField(complexArg: { requiredField: false }) } } """, ) def test_partial_object_including_required(self): expect_passes_rule( ArgumentsOfCorrectType, """ { complicatedArgs { complexArgField(complexArg: { requiredField: false, intField: 4 }) } } """, ) def test_full_object(self): expect_passes_rule( ArgumentsOfCorrectType, """ { complicatedArgs { complexArgField(complexArg: { requiredField: true, intField: 4, stringField: "foo", booleanField: false, stringListField: ["one", "two"] }) } } """, ) def test_full_object_with_fields_in_different_order(self): expect_passes_rule( ArgumentsOfCorrectType, """ { complicatedArgs { complexArgField(complexArg: { stringListField: ["one", "two"] booleanField: false, requiredField: true, stringField: "foo", intField: 4, }) } } """, ) # noinspection PyMethodMayBeStatic class TestInvalidInputObjectValue(object): def test_partial_object_missing_required(self): expect_fails_rule( ArgumentsOfCorrectType, """ { complicatedArgs { complexArgField(complexArg: { intField: 4 }) } } """, [ bad_value( "complexArg", "ComplexInput", "{intField: 4}", 4, 45, ['In field "requiredField": Expected "Boolean!", found null.'], ) ], ) def test_partial_object_invalid_field_type(self): expect_fails_rule( ArgumentsOfCorrectType, """ { complicatedArgs { complexArgField(complexArg: { stringListField: ["one", 2], requiredField: true }) } } """, [ bad_value( "complexArg", "ComplexInput", '{stringListField: ["one", 2], requiredField: true}', 4, 45, [ 'In field "stringListField": In element #1: Expected type "String", found 2.' ], ) ], ) def test_partial_object_unknown_field_arg(self): expect_fails_rule( ArgumentsOfCorrectType, """ { complicatedArgs { complexArgField(complexArg: { requiredField: true unknownField: "value", }) } } """, [ bad_value( "complexArg", "ComplexInput", '{requiredField: true, unknownField: "value"}', 4, 45, ['In field "unknownField": Unknown field.'], ) ], ) # noinspection PyMethodMayBeStatic class TestDirectiveArguments(object): def test_with_directives_of_valid_types(self): expect_passes_rule( ArgumentsOfCorrectType, """ { dog @include(if: true) { name } human @skip(if: false) { name } } """, ) def test_with_directive_with_incorrect_types(self): expect_fails_rule( ArgumentsOfCorrectType, """ { dog @include(if: "yes") { name @skip(if: ENUM) } } """, [ bad_value("if", "Boolean", '"yes"', 3, 30), bad_value("if", "Boolean", "ENUM", 4, 32), ], ) graphql-core-legacy-2.3.2/graphql/validation/tests/test_default_values_of_correct_type.py000066400000000000000000000070421365661746200322030ustar00rootroot00000000000000from graphql.language.location import SourceLocation from graphql.validation.rules import DefaultValuesOfCorrectType from .utils import expect_fails_rule, expect_passes_rule def default_for_non_null_arg(var_name, type_name, guess_type_name, line, column): return { "message": DefaultValuesOfCorrectType.default_for_non_null_arg_message( var_name, type_name, guess_type_name ), "locations": [SourceLocation(line, column)], } def bad_value(var_name, type_name, value, line, column, errors=None): if not errors: errors = ['Expected type "{}", found {}.'.format(type_name, value)] return { "message": DefaultValuesOfCorrectType.bad_value_for_default_arg_message( var_name, type_name, value, errors ), "locations": [SourceLocation(line, column)], } def test_variables_with_no_default_values(): return expect_passes_rule( DefaultValuesOfCorrectType, """ query NullableValues($a: Int, $b: String, $c: ComplexInput) { dog { name } } """, ) def test_required_variables_without_default_values(): expect_passes_rule( DefaultValuesOfCorrectType, """ query RequiredValues($a: Int!, $b: String!) { dog { name } } """, ) def test_variables_with_valid_default_values(): expect_passes_rule( DefaultValuesOfCorrectType, """ query WithDefaultValues( $a: Int = 1, $b: String = "ok", $c: ComplexInput = { requiredField: true, intField: 3 } ) { dog { name } } """, ) def test_no_required_variables_with_default_values(): expect_fails_rule( DefaultValuesOfCorrectType, """ query UnreachableDefaultValues($a: Int! = 3, $b: String! = "default") { dog { name } } """, [ default_for_non_null_arg("a", "Int!", "Int", 2, 47), default_for_non_null_arg("b", "String!", "String", 2, 64), ], ) def test_variables_with_invalid_default_values(): expect_fails_rule( DefaultValuesOfCorrectType, """ query InvalidDefaultValues( $a: Int = "one", $b: String = 4, $c: ComplexInput = "notverycomplex" ) { dog { name } } """, [ bad_value("a", "Int", '"one"', 3, 19), bad_value("b", "String", "4", 4, 22), bad_value( "c", "ComplexInput", '"notverycomplex"', 5, 28, ['Expected "ComplexInput", found not an object.'], ), ], ) def test_variables_missing_required_field(): expect_fails_rule( DefaultValuesOfCorrectType, """ query MissingRequiredField($a: ComplexInput = {intField: 3}) { dog { name } } """, [ bad_value( "a", "ComplexInput", "{intField: 3}", 2, 51, ['In field "requiredField": Expected "Boolean!", found null.'], ) ], ) def test_list_variables_with_invalid_item(): expect_fails_rule( DefaultValuesOfCorrectType, """ query invalidItem($a: [String] = ["one", 2]) { dog { name } } """, [ bad_value( "a", "[String]", '["one", 2]', 2, 38, ['In element #1: Expected type "String", found 2.'], ) ], ) graphql-core-legacy-2.3.2/graphql/validation/tests/test_fields_on_correct_type.py000066400000000000000000000157361365661746200304670ustar00rootroot00000000000000from graphql.language.location import SourceLocation from graphql.validation.rules.fields_on_correct_type import ( FieldsOnCorrectType, _undefined_field_message, ) from .utils import expect_fails_rule, expect_passes_rule def undefined_field(field, gql_type, suggested_types, suggested_fields, line, column): return { "message": _undefined_field_message( field, gql_type, suggested_types, suggested_fields ), "locations": [SourceLocation(line, column)], } def test_object_field_selection(): expect_passes_rule( FieldsOnCorrectType, """ fragment objectFieldSelection on Dog { __typename name } """, ) def test_aliased_object_field_selection(): expect_passes_rule( FieldsOnCorrectType, """ fragment aliasedObjectFieldSelection on Dog { tn : __typename otherName : name } """, ) def test_interface_field_selection(): expect_passes_rule( FieldsOnCorrectType, """ fragment interfaceFieldSelection on Pet { __typename name } """, ) def test_aliased_interface_field_selection(): expect_passes_rule( FieldsOnCorrectType, """ fragment interfaceFieldSelection on Pet { otherName : name } """, ) def test_lying_alias_selection(): expect_passes_rule( FieldsOnCorrectType, """ fragment lyingAliasSelection on Dog { name : nickname } """, ) def test_ignores_fields_on_unknown_type(): expect_passes_rule( FieldsOnCorrectType, """ fragment unknownSelection on UnknownType { unknownField } """, ) def test_reports_errors_when_type_is_known_again(): expect_fails_rule( FieldsOnCorrectType, """ fragment typeKnownAgain on Pet { unknown_pet_field { ... on Cat { unknown_cat_field } } }, """, [ undefined_field("unknown_pet_field", "Pet", [], [], 3, 9), undefined_field("unknown_cat_field", "Cat", [], [], 5, 13), ], ) def test_field_not_defined_on_fragment(): expect_fails_rule( FieldsOnCorrectType, """ fragment fieldNotDefined on Dog { meowVolume } """, [undefined_field("meowVolume", "Dog", [], ["barkVolume"], 3, 9)], ) def test_ignores_deeply_unknown_field(): expect_fails_rule( FieldsOnCorrectType, """ fragment deepFieldNotDefined on Dog { unknown_field { deeper_unknown_field } } """, [undefined_field("unknown_field", "Dog", [], [], 3, 9)], ) def test_sub_field_not_defined(): expect_fails_rule( FieldsOnCorrectType, """ fragment subFieldNotDefined on Human { pets { unknown_field } } """, [undefined_field("unknown_field", "Pet", [], [], 4, 11)], ) def test_field_not_defined_on_inline_fragment(): expect_fails_rule( FieldsOnCorrectType, """ fragment fieldNotDefined on Pet { ... on Dog { meowVolume } } """, [undefined_field("meowVolume", "Dog", [], ["barkVolume"], 4, 11)], ) def test_aliased_field_target_not_defined(): expect_fails_rule( FieldsOnCorrectType, """ fragment aliasedFieldTargetNotDefined on Dog { volume : mooVolume } """, [undefined_field("mooVolume", "Dog", [], ["barkVolume"], 3, 9)], ) def test_aliased_lying_field_target_not_defined(): expect_fails_rule( FieldsOnCorrectType, """ fragment aliasedLyingFieldTargetNotDefined on Dog { barkVolume : kawVolume } """, [undefined_field("kawVolume", "Dog", [], ["barkVolume"], 3, 9)], ) def test_not_defined_on_interface(): expect_fails_rule( FieldsOnCorrectType, """ fragment notDefinedOnInterface on Pet { tailLength } """, [undefined_field("tailLength", "Pet", [], [], 3, 9)], ) def test_defined_on_implementors_but_not_on_interface(): expect_fails_rule( FieldsOnCorrectType, """ fragment definedOnImplementorsButNotInterface on Pet { nickname } """, [undefined_field("nickname", "Pet", ["Dog", "Cat"], ["name"], 3, 9)], ) def test_meta_field_selection_on_union(): expect_passes_rule( FieldsOnCorrectType, """ fragment directFieldSelectionOnUnion on CatOrDog { __typename } """, ) def test_direct_field_selection_on_union(): expect_fails_rule( FieldsOnCorrectType, """ fragment directFieldSelectionOnUnion on CatOrDog { directField } """, [undefined_field("directField", "CatOrDog", [], [], 3, 9)], ) def test_defined_on_implementors_queried_on_union(): expect_fails_rule( FieldsOnCorrectType, """ fragment definedOnImplementorsQueriedOnUnion on CatOrDog { name } """, [ undefined_field( "name", "CatOrDog", ["Being", "Pet", "Canine", "Dog", "Cat"], [], 3, 9 ) ], ) def test_valid_field_in_inline_fragment(): expect_passes_rule( FieldsOnCorrectType, """ fragment objectFieldSelection on Pet { ... on Dog { name } ... { name } } """, ) def test_fields_correct_type_no_suggestion(): message = _undefined_field_message("f", "T", [], []) assert message == 'Cannot query field "f" on type "T".' def test_works_with_no_small_numbers_of_type_suggestion(): message = _undefined_field_message("f", "T", ["A", "B"], []) assert message == ( 'Cannot query field "f" on type "T". ' + 'Did you mean to use an inline fragment on "A" or "B"?' ) def test_works_with_no_small_numbers_of_field_suggestion(): message = _undefined_field_message("f", "T", [], ["z", "y"]) assert message == ( 'Cannot query field "f" on type "T". ' + 'Did you mean "z" or "y"?' ) def test_only_shows_one_set_of_suggestions_at_a_time_preferring_types(): message = _undefined_field_message("f", "T", ["A", "B"], ["z", "y"]) assert message == ( 'Cannot query field "f" on type "T". ' + 'Did you mean to use an inline fragment on "A" or "B"?' ) def test_limits_lots_of_type_suggestions(): message = _undefined_field_message("f", "T", ["A", "B", "C", "D", "E", "F"], []) assert message == ( 'Cannot query field "f" on type "T". ' + 'Did you mean to use an inline fragment on "A", "B", "C", "D" or "E"?' ) def test_limits_lots_of_field_suggestions(): message = _undefined_field_message("f", "T", [], ["z", "y", "x", "w", "v", "u"]) assert message == ( 'Cannot query field "f" on type "T". ' + 'Did you mean "z", "y", "x", "w" or "v"?' ) graphql-core-legacy-2.3.2/graphql/validation/tests/test_fragments_on_composite_types.py000066400000000000000000000055101365661746200317200ustar00rootroot00000000000000from graphql.language.location import SourceLocation from graphql.validation.rules import FragmentsOnCompositeTypes from .utils import expect_fails_rule, expect_passes_rule def fragment_on_non_composite_error(frag_name, type_name, line, column): return { "message": FragmentsOnCompositeTypes.fragment_on_non_composite_error_message( frag_name, type_name ), "locations": [SourceLocation(line, column)], } def inline_fragment_on_non_composite_error(type_name, line, column): return { "message": FragmentsOnCompositeTypes.inline_fragment_on_non_composite_error_message( type_name ), "locations": [SourceLocation(line, column)], } def test_object_is_valid_fragment_type(): expect_passes_rule( FragmentsOnCompositeTypes, """ fragment validFragment on Dog { barks } """, ) def test_interface_is_valid_fragment_type(): expect_passes_rule( FragmentsOnCompositeTypes, """ fragment validFragment on Pet { name } """, ) def test_object_is_valid_inline_fragment_type(): expect_passes_rule( FragmentsOnCompositeTypes, """ fragment validFragment on Pet { ... on Dog { barks } } """, ) def test_inline_fragment_without_type_is_valid(): expect_passes_rule( FragmentsOnCompositeTypes, """ fragment validFragment on Pet { ... { name } } """, ) def test_union_is_valid_fragment_type(): expect_passes_rule( FragmentsOnCompositeTypes, """ fragment validFragment on CatOrDog { __typename } """, ) def test_scalar_is_invalid_fragment_type(): expect_fails_rule( FragmentsOnCompositeTypes, """ fragment scalarFragment on Boolean { bad } """, [fragment_on_non_composite_error("scalarFragment", "Boolean", 2, 34)], ) def test_enum_is_invalid_fragment_type(): expect_fails_rule( FragmentsOnCompositeTypes, """ fragment scalarFragment on FurColor { bad } """, [fragment_on_non_composite_error("scalarFragment", "FurColor", 2, 34)], ) def test_input_object_is_invalid_fragment_type(): expect_fails_rule( FragmentsOnCompositeTypes, """ fragment inputFragment on ComplexInput { stringField } """, [fragment_on_non_composite_error("inputFragment", "ComplexInput", 2, 33)], ) def test_scalar_is_invalid_inline_fragment_type(): expect_fails_rule( FragmentsOnCompositeTypes, """ fragment invalidFragment on Pet { ... on String { barks } } """, [inline_fragment_on_non_composite_error("String", 3, 16)], ) graphql-core-legacy-2.3.2/graphql/validation/tests/test_known_argument_names.py000066400000000000000000000073011365661746200301510ustar00rootroot00000000000000from graphql.language.location import SourceLocation from graphql.validation.rules.known_argument_names import ( KnownArgumentNames, _unknown_arg_message, _unknown_directive_arg_message, ) from .utils import expect_fails_rule, expect_passes_rule def unknown_arg(arg_name, field_name, type_name, suggested_args, line, column): return { "message": _unknown_arg_message( arg_name, field_name, type_name, suggested_args ), "locations": [SourceLocation(line, column)], } def unknown_directive_arg(arg_name, directive_name, suggested_args, line, column): return { "message": _unknown_directive_arg_message( arg_name, directive_name, suggested_args ), "locations": [SourceLocation(line, column)], } def test_single_arg_is_known(): expect_passes_rule( KnownArgumentNames, """ fragment argOnRequiredArg on Dog { doesKnowCommand(dogCommand: SIT) } """, ) def test_multiple_args_are_known(): expect_passes_rule( KnownArgumentNames, """ fragment multipleArgs on ComplicatedArgs { multipleReqs(req1: 1, req2: 2) } """, ) def test_ignore_args_of_unknown_fields(): expect_passes_rule( KnownArgumentNames, """ fragment argOnUnknownField on Dog { unknownField(unknownArg: SIT) } """, ) def test_multiple_args_in_reverse_order_are_known(): expect_passes_rule( KnownArgumentNames, """ fragment multipleArgsReverseOrder on ComplicatedArgs { multipleReqs(req2: 2, req1: 1) } """, ) def test_no_args_on_optional_arg(): expect_passes_rule( KnownArgumentNames, """ fragment noArgOnOptionalArg on Dog { isHousetrained } """, ) def test_args_are_known_deeply(): expect_passes_rule( KnownArgumentNames, """ { dog { doesKnowCommand(dogCommand: SIT) } human { pet { ... on Dog { doesKnowCommand(dogCommand: SIT) } } } } """, ) def test_directive_args_are_known(): expect_passes_rule( KnownArgumentNames, """ { dog @skip(if: true) } """, ) def test_undirective_args_are_invalid(): expect_fails_rule( KnownArgumentNames, """ { dog @skip(unless: true) } """, [unknown_directive_arg("unless", "skip", [], 3, 19)], ) def test_invalid_arg_name(): expect_fails_rule( KnownArgumentNames, """ fragment invalidArgName on Dog { doesKnowCommand(unknown: true) } """, [unknown_arg("unknown", "doesKnowCommand", "Dog", [], 3, 25)], ) def test_unknown_args_amongst_known_args(): expect_fails_rule( KnownArgumentNames, """ fragment oneGoodArgOneInvalidArg on Dog { doesKnowCommand(whoknows: 1, dogCommand: SIT, unknown: true) } """, [ unknown_arg("whoknows", "doesKnowCommand", "Dog", [], 3, 25), unknown_arg("unknown", "doesKnowCommand", "Dog", [], 3, 55), ], ) def test_unknown_args_deeply(): expect_fails_rule( KnownArgumentNames, """ { dog { doesKnowCommand(unknown: true) } human { pet { ... on Dog { doesKnowCommand(unknown: true) } } } } """, [ unknown_arg("unknown", "doesKnowCommand", "Dog", [], 4, 27), unknown_arg("unknown", "doesKnowCommand", "Dog", [], 9, 31), ], ) graphql-core-legacy-2.3.2/graphql/validation/tests/test_known_directives.py000066400000000000000000000121211365661746200273010ustar00rootroot00000000000000from graphql.language.location import SourceLocation from graphql.validation.rules import KnownDirectives from .utils import expect_fails_rule, expect_passes_rule def unknown_directive(directive_name, line, column): return { "message": KnownDirectives.unknown_directive_message(directive_name), "locations": [SourceLocation(line, column)], } def misplaced_directive(directive_name, placement, line, column): return { "message": KnownDirectives.misplaced_directive_message( directive_name, placement ), "locations": [SourceLocation(line, column)], } def test_with_no_directives(): expect_passes_rule( KnownDirectives, """ query Foo { name ...Frag } fragment Frag on Dog { name } """, ) def test_with_known_directives(): expect_passes_rule( KnownDirectives, """ { dog @include(if: true) { name } human @skip(if: false) { name } } """, ) def test_with_unknown_directive(): expect_fails_rule( KnownDirectives, """ { dog @unknown(directive: "value") { name } } """, [unknown_directive("unknown", 3, 13)], ) def test_with_many_unknown_directives(): expect_fails_rule( KnownDirectives, """ { dog @unknown(directive: "value") { name } human @unknown(directive: "value") { name pets @unknown(directive: "value") { name } } } """, [ unknown_directive("unknown", 3, 13), unknown_directive("unknown", 6, 15), unknown_directive("unknown", 8, 16), ], ) def test_with_well_placed_directives(): expect_passes_rule( KnownDirectives, """ query Foo @onQuery{ name @include(if: true) ...Frag @include(if: true) skippedField @skip(if: true) ...SkippedFrag @skip(if: true) } mutation Bar @onMutation { someField } """, ) def test_with_misplaced_directives(): expect_fails_rule( KnownDirectives, """ query Foo @include(if: true) { name @onQuery ...Frag @onQuery } mutation Bar @onQuery { someField } """, [ misplaced_directive("include", "QUERY", 2, 17), misplaced_directive("onQuery", "FIELD", 3, 14), misplaced_directive("onQuery", "FRAGMENT_SPREAD", 4, 17), misplaced_directive("onQuery", "MUTATION", 7, 20), ], ) # within schema language def test_within_schema_language_with_well_placed_directives(): expect_passes_rule( KnownDirectives, """ type MyObj implements MyInterface @onObject { myField(myArg: Int @onArgumentDefinition): String @onFieldDefinition } scalar MyScalar @onScalar interface MyInterface @onInterface { myField(myArg: Int @onArgumentDefinition): String @onFieldDefinition } union MyUnion @onUnion = MyObj | Other enum MyEnum @onEnum { MY_VALUE @onEnumValue } input MyInput @onInputObject { myField: Int @onInputFieldDefinition } schema @OnSchema { query: MyQuery } """, ) def test_within_schema_language_with_misplaced_directives(): expect_fails_rule( KnownDirectives, """ 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 } """, [ misplaced_directive("onInterface", "OBJECT", 2, 43), misplaced_directive("onInputFieldDefinition", "ARGUMENT_DEFINITION", 3, 30), misplaced_directive("onInputFieldDefinition", "FIELD_DEFINITION", 3, 63), misplaced_directive("onEnum", "SCALAR", 6, 25), misplaced_directive("onObject", "INTERFACE", 8, 31), misplaced_directive("onInputFieldDefinition", "ARGUMENT_DEFINITION", 9, 30), misplaced_directive("onInputFieldDefinition", "FIELD_DEFINITION", 9, 63), misplaced_directive("onEnumValue", "UNION", 12, 23), misplaced_directive("onScalar", "ENUM", 14, 21), misplaced_directive("onUnion", "ENUM_VALUE", 15, 20), misplaced_directive("onEnum", "INPUT_OBJECT", 18, 23), misplaced_directive( "onArgumentDefinition", "INPUT_FIELD_DEFINITION", 19, 24 ), misplaced_directive("onObject", "SCHEMA", 22, 16), ], ) graphql-core-legacy-2.3.2/graphql/validation/tests/test_known_fragment_names.py000066400000000000000000000026531365661746200301370ustar00rootroot00000000000000from graphql.language.location import SourceLocation from graphql.validation.rules import KnownFragmentNames from .utils import expect_fails_rule, expect_passes_rule def undefined_fragment(fragment_name, line, column): return { "message": KnownFragmentNames.unknown_fragment_message(fragment_name), "locations": [SourceLocation(line, column)], } def test_known_fragment_names_are_valid(): expect_passes_rule( KnownFragmentNames, """ { 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 test_unknown_fragment_names_are_invalid(): expect_fails_rule( KnownFragmentNames, """ { human(id: 4) { ...UnknownFragment1 ... on Human { ...UnknownFragment2 } } } fragment HumanFields on Human { name ...UnknownFragment3 } """, [ undefined_fragment("UnknownFragment1", 4, 16), undefined_fragment("UnknownFragment2", 6, 20), undefined_fragment("UnknownFragment3", 12, 12), ], ) graphql-core-legacy-2.3.2/graphql/validation/tests/test_known_type_names.py000066400000000000000000000033061365661746200273110ustar00rootroot00000000000000from graphql.language.location import SourceLocation from graphql.validation.rules.known_type_names import ( KnownTypeNames, _unknown_type_message, ) from .utils import expect_fails_rule, expect_passes_rule def unknown_type(type_name, suggested_types, line, column): return { "message": _unknown_type_message(type_name, suggested_types), "locations": [SourceLocation(line, column)], } def test_known_type_names_are_valid(): expect_passes_rule( KnownTypeNames, """ query Foo($var: String, $required: [String!]!) { user(id: 4) { pets { ... on Pet { name }, ...PetFields, ... { name } } } } fragment PetFields on Pet { name } """, ) def test_unknown_type_names_are_invalid(): expect_fails_rule( KnownTypeNames, """ query Foo($var: JumbledUpLetters) { user(id: 4) { name pets { ... on Badger { name }, ...PetFields, ... { name } } } } fragment PetFields on Peettt { name } """, [ unknown_type("JumbledUpLetters", [], 2, 23), unknown_type("Badger", [], 5, 25), unknown_type("Peettt", ["Pet"], 8, 29), ], ) def test_ignores_type_definitions(): expect_fails_rule( KnownTypeNames, """ type NotInTheSchema { field: FooBar } interface FooBar { field: NotInTheSchema } union U = A | B input Blob { field: UnknownType } query Foo($var: NotInTheSchema) { user(id: $var) { id } } """, [unknown_type("NotInTheSchema", [], 12, 23)], ) graphql-core-legacy-2.3.2/graphql/validation/tests/test_lone_anonymous_operation.py000066400000000000000000000034041365661746200310550ustar00rootroot00000000000000from graphql.language.location import SourceLocation from graphql.validation.rules import LoneAnonymousOperation from .utils import expect_fails_rule, expect_passes_rule def anon_not_alone(line, column): return { "message": LoneAnonymousOperation.anonymous_operation_not_alone_message(), "locations": [SourceLocation(line, column)], } def test_no_operations(): expect_passes_rule( LoneAnonymousOperation, """ fragment fragA on Type { field } """, ) def test_one_anon_operation(): expect_passes_rule( LoneAnonymousOperation, """ { field } """, ) def test_multiple_named_operation(): expect_passes_rule( LoneAnonymousOperation, """ query Foo { field } query Bar { field } """, ) def test_anon_operation_with_fragment(): expect_passes_rule( LoneAnonymousOperation, """ { ...Foo } fragment Foo on Type { field } """, ) def test_multiple_anon_operations(): expect_fails_rule( LoneAnonymousOperation, """ { fieldA } { fieldB } """, [anon_not_alone(2, 7), anon_not_alone(5, 7)], ) def test_anon_operation_with_a_mutation(): expect_fails_rule( LoneAnonymousOperation, """ { fieldA } mutation Foo { fieldB } """, [anon_not_alone(2, 7)], ) def test_anon_operation_with_a_subscription(): expect_fails_rule( LoneAnonymousOperation, """ { fieldA } subscription Foo { fieldB } """, [anon_not_alone(2, 7)], ) graphql-core-legacy-2.3.2/graphql/validation/tests/test_no_fragment_cycles.py000066400000000000000000000130441365661746200275720ustar00rootroot00000000000000from graphql.language.location import SourceLocation as L from graphql.validation.rules import NoFragmentCycles from .utils import expect_fails_rule, expect_passes_rule def cycle_error_message(fragment_name, spread_names, *locations): return { "message": NoFragmentCycles.cycle_error_message(fragment_name, spread_names), "locations": list(locations), } def test_single_reference_is_valid(): expect_passes_rule( NoFragmentCycles, """ fragment fragA on Dog { ...fragB } fragment fragB on Dog { name } """, ) def test_spreading_twice_is_not_circular(): expect_passes_rule( NoFragmentCycles, """ fragment fragA on Dog { ...fragB, ...fragB } fragment fragB on Dog { name } """, ) def test_spreading_twice_indirectly_is_not_circular(): expect_passes_rule( NoFragmentCycles, """ fragment fragA on Dog { ...fragB, ...fragC } fragment fragB on Dog { ...fragC } fragment fragC on Dog { name } """, ) def test_double_spread_within_abstract_types(): expect_passes_rule( NoFragmentCycles, """ fragment nameFragment on Pet { ... on Dog { name } ... on Cat { name } } fragment spreadsInAnon on Pet { ... on Dog { ...nameFragment } ... on Cat { ...nameFragment } } """, ) def test_does_not_raise_false_positive_on_unknown_fragment(): expect_passes_rule( NoFragmentCycles, """ fragment nameFragment on Pet { ...UnknownFragment } """, ) def test_spreading_recursively_within_field_fails(): expect_fails_rule( NoFragmentCycles, """ fragment fragA on Human { relatives { ...fragA } }, """, [cycle_error_message("fragA", [], L(2, 43))], ) def test_no_spreading_itself_directly(): expect_fails_rule( NoFragmentCycles, """ fragment fragA on Dog { ...fragA } """, [cycle_error_message("fragA", [], L(2, 29))], ) def test_no_spreading_itself_directly_within_inline_fragment(): expect_fails_rule( NoFragmentCycles, """ fragment fragA on Pet { ... on Dog { ...fragA } } """, [cycle_error_message("fragA", [], L(4, 13))], ) def test_no_spreading_itself_indirectly(): expect_fails_rule( NoFragmentCycles, """ fragment fragA on Dog { ...fragB } fragment fragB on Dog { ...fragA } """, [cycle_error_message("fragA", ["fragB"], L(2, 29), L(3, 29))], ) def test_no_spreading_itself_indirectly_reports_opposite_order(): expect_fails_rule( NoFragmentCycles, """ fragment fragB on Dog { ...fragA } fragment fragA on Dog { ...fragB } """, [cycle_error_message("fragB", ["fragA"], L(2, 29), L(3, 29))], ) def test_no_spreading_itself_indirectly_within_inline_fragment(): expect_fails_rule( NoFragmentCycles, """ fragment fragA on Pet { ... on Dog { ...fragB } } fragment fragB on Pet { ... on Dog { ...fragA } } """, [cycle_error_message("fragA", ["fragB"], L(4, 13), L(9, 13))], ) def test_no_spreading_itself_deeply(): expect_fails_rule( NoFragmentCycles, """ 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 } """, [ cycle_error_message( "fragA", ["fragB", "fragC", "fragO", "fragP"], L(2, 29), L(3, 29), L(4, 29), L(8, 29), L(9, 29), ), cycle_error_message( "fragO", ["fragP", "fragX", "fragY", "fragZ"], L(8, 29), L(9, 39), L(5, 29), L(6, 29), L(7, 29), ), ], ) def test_no_spreading_itself_deeply_two_paths(): expect_fails_rule( NoFragmentCycles, """ fragment fragA on Dog { ...fragB, ...fragC } fragment fragB on Dog { ...fragA } fragment fragC on Dog { ...fragA } """, [ cycle_error_message("fragA", ["fragB"], L(2, 29), L(3, 29)), cycle_error_message("fragA", ["fragC"], L(2, 39), L(4, 29)), ], ) def test_no_spreading_itself_deeply_two_paths_alt_reverse_order(): expect_fails_rule( NoFragmentCycles, """ fragment fragA on Dog { ...fragC } fragment fragB on Dog { ...fragC } fragment fragC on Dog { ...fragA, ...fragB } """, [ cycle_error_message("fragA", ["fragC"], L(2, 29), L(4, 29)), cycle_error_message("fragC", ["fragB"], L(4, 39), L(3, 29)), ], ) def test_no_spreading_itself_deeply_and_immediately(): expect_fails_rule( NoFragmentCycles, """ fragment fragA on Dog { ...fragB } fragment fragB on Dog { ...fragB, ...fragC } fragment fragC on Dog { ...fragA, ...fragB } """, [ cycle_error_message("fragB", [], L(3, 29)), cycle_error_message( "fragA", ["fragB", "fragC"], L(2, 29), L(3, 39), L(4, 29) ), cycle_error_message("fragB", ["fragC"], L(3, 39), L(4, 39)), ], ) graphql-core-legacy-2.3.2/graphql/validation/tests/test_no_undefined_variables.py000066400000000000000000000162101365661746200304140ustar00rootroot00000000000000from graphql.language.location import SourceLocation from graphql.validation.rules import NoUndefinedVariables from .utils import expect_fails_rule, expect_passes_rule def undefined_var(var_name, l1, c1, op_name, l2, c2): return { "message": NoUndefinedVariables.undefined_var_message(var_name, op_name), "locations": [SourceLocation(l1, c1), SourceLocation(l2, c2)], } def test_all_varriables_defined(): expect_passes_rule( NoUndefinedVariables, """ query Foo($a: String, $b: String, $c: String) { field(a: $a, b: $b, c: $c) } """, ) def test_all_variables_deeply_defined(): expect_passes_rule( NoUndefinedVariables, """ query Foo($a: String, $b: String, $c: String) { field(a: $a) { field(b: $b) { field(c: $c) } } } """, ) def test_all_variables_deeply_in_inline_fragments_defined(): expect_passes_rule( NoUndefinedVariables, """ query Foo($a: String, $b: String, $c: String) { ... on Type { field(a: $a) { field(b: $b) { ... on Type { field(c: $c) } } } } } """, ) def test_all_variables_in_fragments_deeply_defined(): expect_passes_rule( NoUndefinedVariables, """ 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 test_variable_within_single_fragment_defined_in_multiple_operations(): expect_passes_rule( NoUndefinedVariables, """ query Foo($a: String) { ...FragA } query Bar($a: String) { ...FragA } fragment FragA on Type { field(a: $a) } """, ) def test_variable_within_fragments_defined_in_operations(): expect_passes_rule( NoUndefinedVariables, """ 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 test_variable_within_recursive_fragment_defined(): expect_passes_rule( NoUndefinedVariables, """ query Foo($a: String) { ...FragA } fragment FragA on Type { field(a: $a) { ...FragA } } """, ) def test_variable_not_defined(): expect_fails_rule( NoUndefinedVariables, """ query Foo($a: String, $b: String, $c: String) { field(a: $a, b: $b, c: $c, d: $d) } """, [undefined_var("d", 3, 39, "Foo", 2, 7)], ) def variable_not_defined_by_unnamed_query(): expect_fails_rule( NoUndefinedVariables, """ { field(a: $a) } """, [undefined_var("a", 3, 18, "", 2, 7)], ) def test_multiple_variables_not_defined(): expect_fails_rule( NoUndefinedVariables, """ query Foo($b: String) { field(a: $a, b: $b, c: $c) } """, [ undefined_var("a", 3, 18, "Foo", 2, 7), undefined_var("c", 3, 32, "Foo", 2, 7), ], ) def test_variable_in_fragment_not_defined_by_unnamed_query(): expect_fails_rule( NoUndefinedVariables, """ { ...FragA } fragment FragA on Type { field(a: $a) } """, [undefined_var("a", 6, 18, "", 2, 7)], ) def test_variable_in_fragment_not_defined_by_operation(): expect_fails_rule( NoUndefinedVariables, """ 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) } """, [undefined_var("c", 16, 18, "Foo", 2, 7)], ) def test_multiple_variables_in_fragments_not_defined(): expect_fails_rule( NoUndefinedVariables, """ 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) } """, [ undefined_var("a", 6, 18, "Foo", 2, 7), undefined_var("c", 16, 18, "Foo", 2, 7), ], ) def test_single_variable_in_fragment_not_defined_by_multiple_operations(): expect_fails_rule( NoUndefinedVariables, """ query Foo($a: String) { ...FragAB } query Bar($a: String) { ...FragAB } fragment FragAB on Type { field(a: $a, b: $b) } """, [ undefined_var("b", 9, 25, "Foo", 2, 7), undefined_var("b", 9, 25, "Bar", 5, 7), ], ) def test_variables_in_fragment_not_defined_by_multiple_operations(): expect_fails_rule( NoUndefinedVariables, """ query Foo($b: String) { ...FragAB } query Bar($a: String) { ...FragAB } fragment FragAB on Type { field(a: $a, b: $b) } """, [ undefined_var("a", 9, 18, "Foo", 2, 7), undefined_var("b", 9, 25, "Bar", 5, 7), ], ) def test_variable_in_fragment_used_by_other_operation(): expect_fails_rule( NoUndefinedVariables, """ query Foo($b: String) { ...FragA } query Bar($a: String) { ...FragB } fragment FragA on Type { field(a: $a) } fragment FragB on Type { field(b: $b) } """, [ undefined_var("a", 9, 18, "Foo", 2, 7), undefined_var("b", 12, 18, "Bar", 5, 7), ], ) def test_multiple_undefined_variables_produce_multiple_errors(): expect_fails_rule( NoUndefinedVariables, """ 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) } """, [ undefined_var("a", 9, 19, "Foo", 2, 7), undefined_var("a", 11, 19, "Foo", 2, 7), undefined_var("c", 14, 19, "Foo", 2, 7), undefined_var("b", 9, 26, "Bar", 5, 7), undefined_var("b", 11, 26, "Bar", 5, 7), undefined_var("c", 14, 19, "Bar", 5, 7), ], ) graphql-core-legacy-2.3.2/graphql/validation/tests/test_no_unused_fragments.py000066400000000000000000000057671365661746200300130ustar00rootroot00000000000000from graphql.language.location import SourceLocation from graphql.validation.rules import NoUnusedFragments from .utils import expect_fails_rule, expect_passes_rule def unused_fragment(fragment_name, line, column): return { "message": NoUnusedFragments.unused_fragment_message(fragment_name), "locations": [SourceLocation(line, column)], } def test_all_fragment_names_are_used(): expect_passes_rule( NoUnusedFragments, """ { human(id: 4) { ...HumanFields1 ... on Human { ...HumanFields2 } } } fragment HumanFields1 on Human { name ...HumanFields3 } fragment HumanFields2 on Human { name } fragment HumanFields3 on Human { name } """, ) def test_all_fragment_names_are_used_by_multiple_operations(): expect_passes_rule( NoUnusedFragments, """ 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 test_contains_unknown_fragments(): expect_fails_rule( NoUnusedFragments, """ 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 } """, [unused_fragment("Unused1", 22, 7), unused_fragment("Unused2", 25, 7)], ) def test_contains_unknown_fragments_with_ref_cycle(): expect_fails_rule( NoUnusedFragments, """ 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 } """, [unused_fragment("Unused1", 22, 7), unused_fragment("Unused2", 26, 7)], ) def test_contains_unknown_and_undefined_fragments(): expect_fails_rule( NoUnusedFragments, """ query Foo { human(id: 4) { ...bar } } fragment foo on Human { name } """, [unused_fragment("foo", 7, 7)], ) graphql-core-legacy-2.3.2/graphql/validation/tests/test_no_unused_variables.py000066400000000000000000000111041365661746200277530ustar00rootroot00000000000000from graphql.language.location import SourceLocation from graphql.validation.rules import NoUnusedVariables from .utils import expect_fails_rule, expect_passes_rule def unused_variable(variable_name, op_name, line, column): return { "message": NoUnusedVariables.unused_variable_message(variable_name, op_name), "locations": [SourceLocation(line, column)], } def test_uses_all_variables(): expect_passes_rule( NoUnusedVariables, """ query ($a: String, $b: String, $c: String) { field(a: $a, b: $b, c: $c) } """, ) def test_uses_all_variables_deeply(): expect_passes_rule( NoUnusedVariables, """ query Foo($a: String, $b: String, $c: String) { field(a: $a) { field(b: $b) { field(c: $c) } } } """, ) def test_uses_all_variables_deeply_in_inline_fragments(): expect_passes_rule( NoUnusedVariables, """ query Foo($a: String, $b: String, $c: String) { ... on Type { field(a: $a) { field(b: $b) { ... on Type { field(c: $c) } } } } } """, ) def test_uses_all_variables_in_fragment(): expect_passes_rule( NoUnusedVariables, """ 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 test_variable_used_by_fragment_in_multiple_operations(): expect_passes_rule( NoUnusedVariables, """ 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 test_variable_used_by_recursive_fragment(): expect_passes_rule( NoUnusedVariables, """ query Foo($a: String) { ...FragA } fragment FragA on Type { field(a: $a) { ...FragA } } """, ) def test_variable_not_used(): expect_fails_rule( NoUnusedVariables, """ query ($a: String, $b: String, $c: String) { field(a: $a, b: $b) } """, [unused_variable("c", None, 2, 38)], ) def test_multiple_variables_not_used(): expect_fails_rule( NoUnusedVariables, """ query Foo($a: String, $b: String, $c: String) { field(b: $b) } """, [unused_variable("a", "Foo", 2, 17), unused_variable("c", "Foo", 2, 41)], ) def test_variable_not_used_in_fragments(): expect_fails_rule( NoUnusedVariables, """ 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 } """, [unused_variable("c", "Foo", 2, 41)], ) def test_multiple_variables_not_used_in_fragments(): expect_fails_rule( NoUnusedVariables, """ 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 } """, [unused_variable("a", "Foo", 2, 17), unused_variable("c", "Foo", 2, 41)], ) def test_variable_not_used_by_unreferenced_fragment(): expect_fails_rule( NoUnusedVariables, """ query Foo($b: String) { ...FragA } fragment FragA on Type { field(a: $a) } fragment FragB on Type { field(b: $b) } """, [unused_variable("b", "Foo", 2, 17)], ) def test_variable_not_used_by_fragment_used_by_other_operation(): expect_fails_rule( NoUnusedVariables, """ query Foo($b: String) { ...FragA } query Bar($a: String) { ...FragB } fragment FragA on Type { field(a: $a) } fragment FragB on Type { field(b: $b) } """, [unused_variable("b", "Foo", 2, 17), unused_variable("a", "Bar", 5, 17)], ) graphql-core-legacy-2.3.2/graphql/validation/tests/test_overlapping_fields_can_be_merged.py000066400000000000000000000544521365661746200324270ustar00rootroot00000000000000from graphql.language.location import SourceLocation as L from graphql.type.definition import ( GraphQLArgument, GraphQLField, GraphQLInterfaceType, GraphQLList, GraphQLNonNull, GraphQLObjectType, ) from graphql.type.scalars import GraphQLID, GraphQLInt, GraphQLString from graphql.type.schema import GraphQLSchema from graphql.validation.rules import OverlappingFieldsCanBeMerged from .utils import ( expect_fails_rule, expect_fails_rule_with_schema, expect_passes_rule, expect_passes_rule_with_schema, ) def fields_conflict(reason_name, reason, *locations): return { "message": OverlappingFieldsCanBeMerged.fields_conflict_message( reason_name, reason ), "locations": list(locations), } def test_unique_fields(): expect_passes_rule( OverlappingFieldsCanBeMerged, """ fragment uniqueFields on Dog { name nickname } """, ) def test_identical_fields(): expect_passes_rule( OverlappingFieldsCanBeMerged, """ fragment mergeIdenticalFields on Dog { name name } """, ) def test_identical_fields_with_identical_args(): expect_passes_rule( OverlappingFieldsCanBeMerged, """ fragment mergeIdenticalFieldsWithIdenticalArgs on Dog { doesKnowCommand(dogCommand: SIT) doesKnowCommand(dogCommand: SIT) } """, ) def test_identical_fields_with_identical_directives(): expect_passes_rule( OverlappingFieldsCanBeMerged, """ fragment mergeSameFieldsWithSameDirectives on Dog { name @include(if: true) name @include(if: true) } """, ) def test_different_args_with_different_aliases(): expect_passes_rule( OverlappingFieldsCanBeMerged, """ fragment differentArgsWithDifferentAliases on Dog { knowsSit: doesKnowCommand(dogCommand: SIT) knowsDown: doesKnowCommand(dogCommand: DOWN) } """, ) def test_different_directives_with_different_aliases(): expect_passes_rule( OverlappingFieldsCanBeMerged, """ fragment differentDirectivesWithDifferentAliases on Dog { nameIfTrue: name @include(if: true) nameIfFalse: name @include(if: false) } """, ) def test_different_skip_or_include_directives_accepted(): expect_passes_rule( OverlappingFieldsCanBeMerged, """ fragment differentDirectivesWithDifferentAliases on Dog { name @include(if: true) name @include(if: false) } """, ) def test_same_aliases_with_different_field_targets(): expect_fails_rule( OverlappingFieldsCanBeMerged, """ fragment sameAliasesWithDifferentFieldTargets on Dog { fido: name fido: nickname } """, [ fields_conflict( "fido", "name and nickname are different fields", L(3, 9), L(4, 9) ) ], sort_list=False, ) def test_same_aliases_allowed_on_nonoverlapping_fields(): expect_passes_rule( OverlappingFieldsCanBeMerged, """ fragment sameAliasesWithDifferentFieldTargets on Pet { ... on Dog { name } ... on Cat { name: nickname } } """, ) def test_alias_masking_direct_field_access(): expect_fails_rule( OverlappingFieldsCanBeMerged, """ fragment aliasMaskingDirectFieldAccess on Dog { name: nickname name } """, [ fields_conflict( "name", "nickname and name are different fields", L(3, 9), L(4, 9) ) ], sort_list=False, ) def test_diferent_args_second_adds_an_argument(): expect_fails_rule( OverlappingFieldsCanBeMerged, """ fragment conflictingArgs on Dog { doesKnowCommand doesKnowCommand(dogCommand: HEEL) } """, [ fields_conflict( "doesKnowCommand", "they have differing arguments", L(3, 9), L(4, 9) ) ], sort_list=False, ) def test_diferent_args_second_missing_an_argument(): expect_fails_rule( OverlappingFieldsCanBeMerged, """ fragment conflictingArgs on Dog { doesKnowCommand(dogCommand: SIT) doesKnowCommand } """, [ fields_conflict( "doesKnowCommand", "they have differing arguments", L(3, 9), L(4, 9) ) ], sort_list=False, ) def test_conflicting_args(): expect_fails_rule( OverlappingFieldsCanBeMerged, """ fragment conflictingArgs on Dog { doesKnowCommand(dogCommand: SIT) doesKnowCommand(dogCommand: HEEL) } """, [ fields_conflict( "doesKnowCommand", "they have differing arguments", L(3, 9), L(4, 9) ) ], sort_list=False, ) def test_allows_different_args_where_no_conflict_is_possible(): expect_passes_rule( OverlappingFieldsCanBeMerged, """ fragment conflictingArgs on Pet { ... on Dog { name(surname: true) } ... on Cat { name } } """, ) def test_encounters_conflict_in_fragments(): expect_fails_rule( OverlappingFieldsCanBeMerged, """ { ...A ...B } fragment A on Type { x: a } fragment B on Type { x: b } """, [fields_conflict("x", "a and b are different fields", L(7, 9), L(10, 9))], sort_list=False, ) def test_reports_each_conflict_once(): expect_fails_rule( OverlappingFieldsCanBeMerged, """ { f1 { ...A ...B } f2 { ...B ...A } f3 { ...A ...B x: c } } fragment A on Type { x: a } fragment B on Type { x: b } """, [ fields_conflict("x", "a and b are different fields", L(18, 9), L(21, 9)), fields_conflict("x", "c and a are different fields", L(14, 11), L(18, 9)), fields_conflict("x", "c and b are different fields", L(14, 11), L(21, 9)), ], sort_list=False, ) def test_deep_conflict(): expect_fails_rule( OverlappingFieldsCanBeMerged, """ { field { x: a } field { x: b } } """, [ fields_conflict( "field", [("x", "a and b are different fields")], L(3, 9), L(4, 13), L(6, 9), L(7, 13), ) ], sort_list=False, ) def test_deep_conflict_with_multiple_issues(): expect_fails_rule( OverlappingFieldsCanBeMerged, """ { field { x: a y: c } field { x: b y: d } } """, [ fields_conflict( "field", [ ("x", "a and b are different fields"), ("y", "c and d are different fields"), ], L(3, 9), L(4, 11), L(5, 11), L(7, 9), L(8, 11), L(9, 11), ) ], sort_list=False, ) def test_very_deep_conflict(): expect_fails_rule( OverlappingFieldsCanBeMerged, """ { field { deepField { x: a } }, field { deepField { x: b } } } """, [ fields_conflict( "field", [["deepField", [["x", "a and b are different fields"]]]], L(3, 9), L(4, 13), L(5, 17), L(8, 9), L(9, 13), L(10, 17), ) ], sort_list=False, ) def test_reports_deep_conflict_to_nearest_common_ancestor(): expect_fails_rule( OverlappingFieldsCanBeMerged, """ { field { deepField { x: a } deepField { x: b } }, field { deepField { y } } } """, [ fields_conflict( "deepField", [("x", "a and b are different fields")], L(4, 13), L(5, 17), L(7, 13), L(8, 17), ) ], sort_list=False, ) def test_reports_deep_conflict_to_nearest_common_ancestor_in_fragments(): expect_fails_rule( OverlappingFieldsCanBeMerged, """ { field { ...F }, field { ...F } } fragment F on T { deepField { deeperField { x: a } deeperField { x: b } } deepField { deeperField { y } } } """, [ fields_conflict( "deeperField", [("x", "a and b are different fields")], L(12, 11), L(13, 13), L(15, 11), L(16, 13), ) ], sort_list=False, ) def test_reports_deep_conflict_in_nested_fragments(): expect_fails_rule( OverlappingFieldsCanBeMerged, """ { 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 } """, [ fields_conflict( "field", [ ("x", "a and b are different fields"), ("y", "c and d are different fields"), ], L(3, 9), L(11, 9), L(15, 9), L(6, 9), L(22, 9), L(18, 9), ) ], sort_list=False, ) def test_ignores_unknown_fragments(): expect_passes_rule( OverlappingFieldsCanBeMerged, """ { field ...Unknown ...Known } fragment Known on T { field ...OtherUnknown } """, ) SomeBox = GraphQLInterfaceType( "SomeBox", fields=lambda: { "deepBox": GraphQLField(SomeBox), "unrelatedField": GraphQLField(GraphQLString), }, resolve_type=lambda *_: StringBox, ) StringBox = GraphQLObjectType( "StringBox", fields=lambda: { "scalar": GraphQLField(GraphQLString), "deepBox": GraphQLField(StringBox), "unrelatedField": GraphQLField(GraphQLString), "listStringBox": GraphQLField(GraphQLList(StringBox)), "stringBox": GraphQLField(StringBox), "intBox": GraphQLField(IntBox), }, interfaces=[SomeBox], ) IntBox = GraphQLObjectType( "IntBox", fields=lambda: { "scalar": GraphQLField(GraphQLInt), "deepBox": GraphQLField(IntBox), "unrelatedField": GraphQLField(GraphQLString), "listStringBox": GraphQLField(GraphQLList(StringBox)), "stringBox": GraphQLField(StringBox), "intBox": GraphQLField(IntBox), }, interfaces=[SomeBox], ) NonNullStringBox1 = GraphQLInterfaceType( "NonNullStringBox1", {"scalar": GraphQLField(GraphQLNonNull(GraphQLString))}, resolve_type=lambda *_: StringBox, ) NonNullStringBox1Impl = GraphQLObjectType( "NonNullStringBox1Impl", { "scalar": GraphQLField(GraphQLNonNull(GraphQLString)), "deepBox": GraphQLField(StringBox), "unrelatedField": GraphQLField(GraphQLString), }, interfaces=[SomeBox, NonNullStringBox1], ) NonNullStringBox2 = GraphQLInterfaceType( "NonNullStringBox2", {"scalar": GraphQLField(GraphQLNonNull(GraphQLString))}, resolve_type=lambda *_: StringBox, ) NonNullStringBox2Impl = GraphQLObjectType( "NonNullStringBox2Impl", { "scalar": GraphQLField(GraphQLNonNull(GraphQLString)), "unrelatedField": GraphQLField(GraphQLString), "deepBox": GraphQLField(StringBox), }, interfaces=[SomeBox, NonNullStringBox2], ) Connection = GraphQLObjectType( "Connection", { "edges": GraphQLField( GraphQLList( GraphQLObjectType( "Edge", { "node": GraphQLField( GraphQLObjectType( "Node", { "id": GraphQLField(GraphQLID), "name": GraphQLField(GraphQLString), }, ) ) }, ) ) ) }, ) schema = GraphQLSchema( GraphQLObjectType( "QueryRoot", {"someBox": GraphQLField(SomeBox), "connection": GraphQLField(Connection)}, ), types=[IntBox, StringBox, NonNullStringBox1Impl, NonNullStringBox2Impl], ) def test_conflicting_return_types_which_potentially_overlap(): expect_fails_rule_with_schema( schema, OverlappingFieldsCanBeMerged, """ { someBox { ...on IntBox { scalar } ...on NonNullStringBox1 { scalar } } } """, [ fields_conflict( "scalar", "they return conflicting types Int and String!", L(5, 17), L(8, 17), ) ], sort_list=False, ) def test_compatible_return_shapes_on_different_return_types(): # In this case `deepBox` returns `SomeBox` in the first usage, and # `StringBox` in the second usage. These return types are not the same! # however this is valid because the return *shapes* are compatible. expect_passes_rule_with_schema( schema, OverlappingFieldsCanBeMerged, """ { someBox { ... on SomeBox { deepBox { unrelatedField } } ... on StringBox { deepBox { unrelatedField } } } } """, ) def test_disallows_differing_return_types_despite_no_overlap(): expect_fails_rule_with_schema( schema, OverlappingFieldsCanBeMerged, """ { someBox { ... on IntBox { scalar } ... on StringBox { scalar } } } """, [ fields_conflict( "scalar", "they return conflicting types Int and String", L(5, 15), L(8, 15), ) ], sort_list=False, ) def test_reports_correctly_when_a_non_exclusive_follows_an_exclusive(): expect_fails_rule_with_schema( schema, OverlappingFieldsCanBeMerged, """ { 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 } """, [ fields_conflict( "other", [("scalar", "scalar and unrelatedField are different fields")], L(31, 11), L(39, 11), L(34, 11), L(42, 11), ) ], sort_list=False, ) def test_disallows_differing_return_type_nullability_despite_no_overlap(): expect_fails_rule_with_schema( schema, OverlappingFieldsCanBeMerged, """ { someBox { ... on NonNullStringBox1 { scalar } ... on StringBox { scalar } } } """, [ fields_conflict( "scalar", "they return conflicting types String! and String", L(5, 15), L(8, 15), ) ], sort_list=False, ) def test_disallows_differing_return_type_list_despite_no_overlap_1(): expect_fails_rule_with_schema( schema, OverlappingFieldsCanBeMerged, """ { someBox { ... on IntBox { box: listStringBox { scalar } } ... on StringBox { box: stringBox { scalar } } } } """, [ fields_conflict( "box", "they return conflicting types [StringBox] and StringBox", L(5, 15), L(10, 15), ) ], sort_list=False, ) def test_disallows_differing_return_type_list_despite_no_overlap_2(): expect_fails_rule_with_schema( schema, OverlappingFieldsCanBeMerged, """ { someBox { ... on IntBox { box: stringBox { scalar } } ... on StringBox { box: listStringBox { scalar } } } } """, [ fields_conflict( "box", "they return conflicting types StringBox and [StringBox]", L(5, 15), L(10, 15), ) ], sort_list=False, ) def test_disallows_differing_subfields(): expect_fails_rule_with_schema( schema, OverlappingFieldsCanBeMerged, """ { someBox { ... on IntBox { box: stringBox { val: scalar val: unrelatedField } } ... on StringBox { box: stringBox { val: scalar } } } } """, [ fields_conflict( "val", "scalar and unrelatedField are different fields", L(6, 17), L(7, 17), ) ], sort_list=False, ) def test_disallows_differing_deep_return_types_despite_no_overlap(): expect_fails_rule_with_schema( schema, OverlappingFieldsCanBeMerged, """ { someBox { ... on IntBox { box: stringBox { scalar } } ... on StringBox { box: intBox { scalar } } } } """, [ fields_conflict( "box", [["scalar", "they return conflicting types String and Int"]], L(5, 15), L(6, 17), L(10, 15), L(11, 17), ) ], sort_list=False, ) def test_allows_non_conflicting_overlaping_types(): expect_passes_rule_with_schema( schema, OverlappingFieldsCanBeMerged, """ { someBox { ... on IntBox { scalar: unrelatedField } ... on StringBox { scalar } } } """, ) def test_same_wrapped_scalar_return_types(): expect_passes_rule_with_schema( schema, OverlappingFieldsCanBeMerged, """ { someBox { ...on NonNullStringBox1 { scalar } ...on NonNullStringBox2 { scalar } } } """, ) def test_allows_inline_typeless_fragments(): expect_passes_rule_with_schema( schema, OverlappingFieldsCanBeMerged, """ { a ... { a } } """, ) def test_compares_deep_types_including_list(): expect_fails_rule_with_schema( schema, OverlappingFieldsCanBeMerged, """ { connection { ...edgeID edges { node { id: name } } } } fragment edgeID on Connection { edges { node { id } } } """, [ fields_conflict( "edges", [["node", [["id", "name and id are different fields"]]]], L(5, 13), L(6, 17), L(7, 21), L(14, 9), L(15, 13), L(16, 17), ) ], sort_list=False, ) def test_ignores_unknown_types(): expect_passes_rule_with_schema( schema, OverlappingFieldsCanBeMerged, """ { boxUnion { ...on UnknownType { scalar } ...on NonNullStringBox2 { scalar } } } """, ) def test_error_message_contains_hint_for_alias_conflict(): error = OverlappingFieldsCanBeMerged.fields_conflict_message( "x", "a and b are different fields" ) hint = ( 'Fields "x" conflict because a and b are different fields. ' "Use different aliases on the fields to fetch both " "if this was intentional." ) assert error == hint graphql-core-legacy-2.3.2/graphql/validation/tests/test_possible_fragment_spreads.py000066400000000000000000000153451365661746200311630ustar00rootroot00000000000000from graphql.language.location import SourceLocation from graphql.validation.rules import PossibleFragmentSpreads from .utils import expect_fails_rule, expect_passes_rule def error(frag_name, parent_type, frag_type, line, column): return { "message": PossibleFragmentSpreads.type_incompatible_spread_message( frag_name, parent_type, frag_type ), "locations": [SourceLocation(line, column)], } def error_anon(parent_type, frag_type, line, column): return { "message": PossibleFragmentSpreads.type_incompatible_anon_spread_message( parent_type, frag_type ), "locations": [SourceLocation(line, column)], } def test_same_object(): expect_passes_rule( PossibleFragmentSpreads, """ fragment objectWithinObject on Dog { ...dogFragment } fragment dogFragment on Dog { barkVolume } """, ) def test_same_object_inline_frag(): expect_passes_rule( PossibleFragmentSpreads, """ fragment objectWithinObjectAnon on Dog { ... on Dog { barkVolume } } """, ) def test_object_into_implemented_interface(): expect_passes_rule( PossibleFragmentSpreads, """ fragment objectWithinInterface on Pet { ...dogFragment } fragment dogFragment on Dog { barkVolume } """, ) def test_object_into_containing_union(): expect_passes_rule( PossibleFragmentSpreads, """ fragment objectWithinUnion on CatOrDog { ...dogFragment } fragment dogFragment on Dog { barkVolume } """, ) def test_union_into_contained_object(): expect_passes_rule( PossibleFragmentSpreads, """ fragment unionWithinObject on Dog { ...catOrDogFragment } fragment catOrDogFragment on CatOrDog { __typename } """, ) def test_union_into_overlapping_interface(): expect_passes_rule( PossibleFragmentSpreads, """ fragment unionWithinInterface on Pet { ...catOrDogFragment } fragment catOrDogFragment on CatOrDog { __typename } """, ) def test_union_into_overlapping_union(): expect_passes_rule( PossibleFragmentSpreads, """ fragment unionWithinUnion on DogOrHuman { ...catOrDogFragment } fragment catOrDogFragment on CatOrDog { __typename } """, ) def test_interface_into_implemented_object(): expect_passes_rule( PossibleFragmentSpreads, """ fragment interfaceWithinObject on Dog { ...petFragment } fragment petFragment on Pet { name } """, ) def test_interface_into_overlapping_interface(): expect_passes_rule( PossibleFragmentSpreads, """ fragment interfaceWithinInterface on Pet { ...beingFragment } fragment beingFragment on Being { name } """, ) def test_interface_into_overlapping_interface_in_inline_fragment(): expect_passes_rule( PossibleFragmentSpreads, """ fragment interfaceWithinInterface on Pet { ... on Being { name } } """, ) def test_interface_into_overlapping_union(): expect_passes_rule( PossibleFragmentSpreads, """ fragment interfaceWithinUnion on CatOrDog { ...petFragment } fragment petFragment on Pet { name } """, ) def test_different_object_into_object(): expect_fails_rule( PossibleFragmentSpreads, """ fragment invalidObjectWithinObject on Cat { ...dogFragment } fragment dogFragment on Dog { barkVolume } """, [error("dogFragment", "Cat", "Dog", 2, 51)], ) def test_different_object_into_object_in_inline_fragment(): expect_fails_rule( PossibleFragmentSpreads, """ fragment invalidObjectWithinObjectAnon on Cat { ... on Dog { barkVolume } } """, [error_anon("Cat", "Dog", 3, 9)], ) def test_object_into_not_implementing_interface(): expect_fails_rule( PossibleFragmentSpreads, """ fragment invalidObjectWithinInterface on Pet { ...humanFragment } fragment humanFragment on Human { pets { name } } """, [error("humanFragment", "Pet", "Human", 2, 54)], ) def test_object_into_not_containing_union(): expect_fails_rule( PossibleFragmentSpreads, """ fragment invalidObjectWithinUnion on CatOrDog { ...humanFragment } fragment humanFragment on Human { pets { name } } """, [error("humanFragment", "CatOrDog", "Human", 2, 55)], ) def test_union_into_not_contained_object(): expect_fails_rule( PossibleFragmentSpreads, """ fragment invalidUnionWithinObject on Human { ...catOrDogFragment } fragment catOrDogFragment on CatOrDog { __typename } """, [error("catOrDogFragment", "Human", "CatOrDog", 2, 52)], ) def test_union_into_non_overlapping_interface(): expect_fails_rule( PossibleFragmentSpreads, """ fragment invalidUnionWithinInterface on Pet { ...humanOrAlienFragment } fragment humanOrAlienFragment on HumanOrAlien { __typename } """, [error("humanOrAlienFragment", "Pet", "HumanOrAlien", 2, 53)], ) def test_union_into_non_overlapping_union(): expect_fails_rule( PossibleFragmentSpreads, """ fragment invalidUnionWithinUnion on CatOrDog { ...humanOrAlienFragment } fragment humanOrAlienFragment on HumanOrAlien { __typename } """, [error("humanOrAlienFragment", "CatOrDog", "HumanOrAlien", 2, 54)], ) def test_interface_into_non_implementing_object(): expect_fails_rule( PossibleFragmentSpreads, """ fragment invalidInterfaceWithinObject on Cat { ...intelligentFragment } fragment intelligentFragment on Intelligent { iq } """, [error("intelligentFragment", "Cat", "Intelligent", 2, 54)], ) def test_interface_into_non_overlapping_interface(): expect_fails_rule( PossibleFragmentSpreads, """ fragment invalidInterfaceWithinInterface on Pet { ...intelligentFragment } fragment intelligentFragment on Intelligent { iq } """, [error("intelligentFragment", "Pet", "Intelligent", 3, 9)], ) def test_interface_into_non_overlapping_interface_in_inline_fragment(): expect_fails_rule( PossibleFragmentSpreads, """ fragment invalidInterfaceWithinInterfaceAnon on Pet { ...on Intelligent { iq } } """, [error_anon("Pet", "Intelligent", 3, 9)], ) def test_interface_into_non_overlapping_union(): expect_fails_rule( PossibleFragmentSpreads, """ fragment invalidInterfaceWithinUnion on HumanOrAlien { ...petFragment } fragment petFragment on Pet { name } """, [error("petFragment", "HumanOrAlien", "Pet", 2, 62)], ) graphql-core-legacy-2.3.2/graphql/validation/tests/test_provided_non_null_arguments.py000066400000000000000000000112621365661746200315360ustar00rootroot00000000000000from graphql.language.location import SourceLocation from graphql.validation.rules import ProvidedNonNullArguments from .utils import expect_fails_rule, expect_passes_rule def missing_field_arg(field_name, arg_name, type_name, line, column): return { "message": ProvidedNonNullArguments.missing_field_arg_message( field_name, arg_name, type_name ), "locations": [SourceLocation(line, column)], } def missing_directive_arg(directive_name, arg_name, type_name, line, column): return { "message": ProvidedNonNullArguments.missing_directive_arg_message( directive_name, arg_name, type_name ), "locations": [SourceLocation(line, column)], } def test_ignores_unknown_arguments(): expect_passes_rule( ProvidedNonNullArguments, """ { dog { isHousetrained(unknownArgument: true) } }""", ) def test_arg_on_optional_arg(): expect_passes_rule( ProvidedNonNullArguments, """ { dog { isHousetrained(atOtherHomes: true) } }""", ) def test_no_arg_on_optional_arg(): expect_passes_rule( ProvidedNonNullArguments, """ { dog { isHousetrained } }""", ) def test_multiple_args(): expect_passes_rule( ProvidedNonNullArguments, """ { complicatedArgs { multipleReqs(req1: 1, req2: 2) } } """, ) def test_multiple_args_reverse_order(): expect_passes_rule( ProvidedNonNullArguments, """ { complicatedArgs { multipleReqs(req2: 2, req1: 1) } } """, ) def test_no_args_on_multiple_optional(): expect_passes_rule( ProvidedNonNullArguments, """ { complicatedArgs { multipleOpts } } """, ) def test_one_arg_on_multiple_optional(): expect_passes_rule( ProvidedNonNullArguments, """ { complicatedArgs { multipleOpts(opt1: 1) } } """, ) def test_second_arg_on_multiple_optional(): expect_passes_rule( ProvidedNonNullArguments, """ { complicatedArgs { multipleOpts(opt2: 1) } } """, ) def test_multiple_reqs_on_mixed_list(): expect_passes_rule( ProvidedNonNullArguments, """ { complicatedArgs { multipleOptAndReq(req1: 3, req2: 4) } } """, ) def test_multiple_reqs_and_one_opt_on_mixed_list(): expect_passes_rule( ProvidedNonNullArguments, """ { complicatedArgs { multipleOptAndReq(req1: 3, req2: 4, opt1: 5) } } """, ) def test_all_reqs_and_opts_on_mixed_list(): expect_passes_rule( ProvidedNonNullArguments, """ { complicatedArgs { multipleOptAndReq(req1: 3, req2: 4, opt1: 5, opt2: 6) } } """, ) def test_missing_one_non_nullable_argument(): expect_fails_rule( ProvidedNonNullArguments, """ { complicatedArgs { multipleReqs(req2: 2) } } """, [missing_field_arg("multipleReqs", "req1", "Int!", 4, 13)], ) def test_missing_multiple_non_nullable_arguments(): expect_fails_rule( ProvidedNonNullArguments, """ { complicatedArgs { multipleReqs } } """, [ missing_field_arg("multipleReqs", "req1", "Int!", 4, 13), missing_field_arg("multipleReqs", "req2", "Int!", 4, 13), ], ) def test_incorrect_value_and_missing_argument(): expect_fails_rule( ProvidedNonNullArguments, """ { complicatedArgs { multipleReqs(req1: "one") } } """, [missing_field_arg("multipleReqs", "req2", "Int!", 4, 13)], ) def test_ignore_unknown_directives(): expect_passes_rule( ProvidedNonNullArguments, """ { dog @unknown } """, ) def test_with_directives_of_valid_type(): expect_passes_rule( ProvidedNonNullArguments, """ { dog @include(if: true) { name } human @skip(if: false) { name } } """, ) def test_with_directive_with_missing_types(): expect_fails_rule( ProvidedNonNullArguments, """ { dog @include { name @skip } } """, [ missing_directive_arg("include", "if", "Boolean!", 3, 13), missing_directive_arg("skip", "if", "Boolean!", 4, 18), ], ) graphql-core-legacy-2.3.2/graphql/validation/tests/test_scalar_leafs.py000066400000000000000000000056461365661746200263610ustar00rootroot00000000000000from graphql.language.location import SourceLocation from graphql.validation.rules import ScalarLeafs from .utils import expect_fails_rule, expect_passes_rule def no_scalar_subselection(field, type, line, column): return { "message": ScalarLeafs.no_subselection_allowed_message(field, type), "locations": [SourceLocation(line, column)], } def missing_obj_subselection(field, type, line, column): return { "message": ScalarLeafs.required_subselection_message(field, type), "locations": [SourceLocation(line, column)], } def test_valid_scalar_selection(): expect_passes_rule( ScalarLeafs, """ fragment scalarSelection on Dog { barks } """, ) def test_object_type_missing_selection(): expect_fails_rule( ScalarLeafs, """ query directQueryOnObjectWithoutSubFields { human } """, [missing_obj_subselection("human", "Human", 3, 9)], ) def test_interface_type_missing_selection(): expect_fails_rule( ScalarLeafs, """ { human { pets } } """, [missing_obj_subselection("pets", "[Pet]", 3, 17)], ) def test_valid_scalar_selection_with_args(): expect_passes_rule( ScalarLeafs, """ fragment scalarSelectionWithArgs on Dog { doesKnowCommand(dogCommand: SIT) } """, ) def test_scalar_selection_not_allowed_on_boolean(): expect_fails_rule( ScalarLeafs, """ fragment scalarSelectionsNotAllowedOnBoolean on Dog { barks { sinceWhen } } """, [no_scalar_subselection("barks", "Boolean", 3, 15)], ) def test_scalar_selection_not_allowed_on_enum(): expect_fails_rule( ScalarLeafs, """ fragment scalarSelectionsNotAllowedOnEnum on Cat { furColor { inHexdec } } """, [no_scalar_subselection("furColor", "FurColor", 3, 18)], ) def test_scalar_selection_not_allowed_with_args(): expect_fails_rule( ScalarLeafs, """ fragment scalarSelectionsNotAllowedWithArgs on Dog { doesKnowCommand(dogCommand: SIT) { sinceWhen } } """, [no_scalar_subselection("doesKnowCommand", "Boolean", 3, 42)], ) def test_scalar_selection_not_allowed_with_directives(): expect_fails_rule( ScalarLeafs, """ fragment scalarSelectionsNotAllowedWithDirectives on Dog { name @include(if: true) { isAlsoHumanName } } """, [no_scalar_subselection("name", "String", 3, 33)], ) def test_scalar_selection_not_allowed_with_directives_and_args(): expect_fails_rule( ScalarLeafs, """ fragment scalarSelectionsNotAllowedWithDirectivesAndArgs on Dog { doesKnowCommand(dogCommand: SIT) @include(if: true) { sinceWhen } } """, [no_scalar_subselection("doesKnowCommand", "Boolean", 3, 61)], ) graphql-core-legacy-2.3.2/graphql/validation/tests/test_unique_argument_names.py000066400000000000000000000057241365661746200303320ustar00rootroot00000000000000from graphql.language.location import SourceLocation from graphql.validation.rules import UniqueArgumentNames from .utils import expect_fails_rule, expect_passes_rule def duplicate_arg(arg_name, l1, c1, l2, c2): return { "message": UniqueArgumentNames.duplicate_arg_message(arg_name), "locations": [SourceLocation(l1, c1), SourceLocation(l2, c2)], } def test_no_arguments_on_field(): expect_passes_rule( UniqueArgumentNames, """ { field } """, ) def test_no_arguments_on_directive(): expect_passes_rule( UniqueArgumentNames, """ { field } """, ) def test_argument_on_field(): expect_passes_rule( UniqueArgumentNames, """ { field(arg: "value") } """, ) def test_argument_on_directive(): expect_passes_rule( UniqueArgumentNames, """ { field @directive(arg: "value") } """, ) def test_same_field_two_arguments(): expect_passes_rule( UniqueArgumentNames, """ { one: field(arg: "value") two: field(arg: "value") } """, ) def test_same_argument_on_field_and_directive(): expect_passes_rule( UniqueArgumentNames, """ { field(arg: "value") @directive(arg: "value") } """, ) def test_same_argument_two_directives(): expect_passes_rule( UniqueArgumentNames, """ { field @directive1(arg: "value") @directive2(arg: "value") } """, ) def test_multiple_field_arguments(): expect_passes_rule( UniqueArgumentNames, """ { field(arg1: "value", arg2: "value", arg3: "value") } """, ) def test_multiple_directive_arguments(): expect_passes_rule( UniqueArgumentNames, """ { field @directive(arg1: "value", arg2: "value", arg3: "value") } """, ) def test_duplicate_field_arguments(): expect_fails_rule( UniqueArgumentNames, """ { field(arg1: "value", arg1: "value") } """, [duplicate_arg("arg1", 3, 13, 3, 28)], ) def test_many_duplicate_field_arguments(): expect_fails_rule( UniqueArgumentNames, """ { field(arg1: "value", arg1: "value", arg1: "value") } """, [duplicate_arg("arg1", 3, 13, 3, 28), duplicate_arg("arg1", 3, 13, 3, 43)], ) def test_duplicate_directive_arguments(): expect_fails_rule( UniqueArgumentNames, """ { field @directive(arg1: "value", arg1: "value") } """, [duplicate_arg("arg1", 3, 24, 3, 39)], ) def test_many_duplicate_directive_arguments(): expect_fails_rule( UniqueArgumentNames, """ { field @directive(arg1: "value", arg1: "value", arg1: "value") } """, [duplicate_arg("arg1", 3, 24, 3, 39), duplicate_arg("arg1", 3, 24, 3, 54)], ) graphql-core-legacy-2.3.2/graphql/validation/tests/test_unique_fragment_names.py000066400000000000000000000041161365661746200303050ustar00rootroot00000000000000from graphql.language.location import SourceLocation from graphql.validation.rules import UniqueFragmentNames from .utils import expect_fails_rule, expect_passes_rule def duplicate_fragment(fragment_name, l1, c1, l2, c2): return { "message": UniqueFragmentNames.duplicate_fragment_name_message(fragment_name), "locations": [SourceLocation(l1, c1), SourceLocation(l2, c2)], } def test_no_fragments(): expect_passes_rule( UniqueFragmentNames, """ { field } """, ) def test_one_fragment(): expect_passes_rule( UniqueFragmentNames, """ { ...fragA } fragment fragA on Type { field } """, ) def test_many_fragments(): expect_passes_rule( UniqueFragmentNames, """ { ...fragA ...fragB ...fragC } fragment fragA on Type { fieldA } fragment fragB on Type { fieldB } fragment fragC on Type { fieldC } """, ) def test_inline_fragments(): expect_passes_rule( UniqueFragmentNames, """ { ...on Type { fieldA } ...on Type { fieldB } } """, ) def test_fragment_operation_same_name(): expect_passes_rule( UniqueFragmentNames, """ query Foo { ...Foo } fragment Foo on Type { field } """, ) def test_fragments_same_name(): expect_fails_rule( UniqueFragmentNames, """ { ...fragA } fragment fragA on Type { fieldA } fragment fragA on Type { fieldB } """, [duplicate_fragment("fragA", 5, 18, 8, 18)], ) def test_fragments_same_name_no_ref(): expect_fails_rule( UniqueFragmentNames, """ fragment fragA on Type { fieldA } fragment fragA on Type { fieldB } """, [duplicate_fragment("fragA", 2, 18, 5, 18)], ) graphql-core-legacy-2.3.2/graphql/validation/tests/test_unique_input_field_names.py000066400000000000000000000034031365661746200310020ustar00rootroot00000000000000from graphql.language.location import SourceLocation as L from graphql.validation.rules import UniqueInputFieldNames from .utils import expect_fails_rule, expect_passes_rule def duplicate_field(name, l1, l2): return { "message": UniqueInputFieldNames.duplicate_input_field_message(name), "locations": [l1, l2], } def test_input_object_with_fields(): expect_passes_rule( UniqueInputFieldNames, """ { field(arg: { f: true }) } """, ) def test_same_input_object_within_two_args(): expect_passes_rule( UniqueInputFieldNames, """ { field(arg1: { f: true }, arg2: { f: true }) } """, ) def test_multiple_input_object_fields(): expect_passes_rule( UniqueInputFieldNames, """ { field(arg: { f1: "value", f2: "value", f3: "value" }) } """, ) def test_it_allows_for_nested_input_objects_with_similar_fields(): expect_passes_rule( UniqueInputFieldNames, """ { field(arg: { deep: { deep: { id: 1 } id: 1 } id: 1 }) } """, ) def test_duplicate_input_object_fields(): expect_fails_rule( UniqueInputFieldNames, """ { field(arg: { f1: "value", f1: "value" }) } """, [duplicate_field("f1", L(3, 22), L(3, 35))], ) def test_many_duplicate_input_object_fields(): expect_fails_rule( UniqueInputFieldNames, """ { field(arg: { f1: "value", f1: "value", f1: "value" }) } """, [ duplicate_field("f1", L(3, 22), L(3, 35)), duplicate_field("f1", L(3, 22), L(3, 48)), ], ) graphql-core-legacy-2.3.2/graphql/validation/tests/test_unique_operation_names.py000066400000000000000000000044611365661746200305050ustar00rootroot00000000000000from graphql.language.location import SourceLocation from graphql.validation.rules import UniqueOperationNames from .utils import expect_fails_rule, expect_passes_rule def duplicate_op(op_name, l1, c1, l2, c2): return { "message": UniqueOperationNames.duplicate_operation_name_message(op_name), "locations": [SourceLocation(l1, c1), SourceLocation(l2, c2)], } def test_no_operations(): expect_passes_rule( UniqueOperationNames, """ fragment fragA on Type { field } """, ) def test_one_anon_operation(): expect_passes_rule( UniqueOperationNames, """ { field } """, ) def test_one_named_operation(): expect_passes_rule( UniqueOperationNames, """ query Foo { field } """, ) def test_multiple_operations(): expect_passes_rule( UniqueOperationNames, """ query Foo { field } query Bar { field } """, ) def test_multiple_operations_of_different_types(): expect_passes_rule( UniqueOperationNames, """ query Foo { field } mutation Bar { field } subscription Baz { field } """, ) def test_fragment_and_operation_named_the_same(): expect_passes_rule( UniqueOperationNames, """ query Foo { ...Foo } fragment Foo on Type { field } """, ) def test_multiple_operations_of_same_name(): expect_fails_rule( UniqueOperationNames, """ query Foo { fieldA } query Foo { fieldB } """, [duplicate_op("Foo", 2, 13, 5, 13)], ) def test_multiple_ops_of_same_name_of_different_types_mutation(): expect_fails_rule( UniqueOperationNames, """ query Foo { fieldA } mutation Foo { fieldB } """, [duplicate_op("Foo", 2, 13, 5, 16)], ) def test_multiple_ops_of_same_name_of_different_types_subscription(): expect_fails_rule( UniqueOperationNames, """ query Foo { fieldA } subscription Foo { fieldB } """, [duplicate_op("Foo", 2, 13, 5, 20)], ) graphql-core-legacy-2.3.2/graphql/validation/tests/test_unique_variable_names.py000066400000000000000000000020631365661746200302660ustar00rootroot00000000000000from graphql.language.location import SourceLocation from graphql.validation.rules import UniqueVariableNames from .utils import expect_fails_rule, expect_passes_rule def duplicate_var(op_name, l1, c1, l2, c2): return { "message": UniqueVariableNames.duplicate_variable_message(op_name), "locations": [SourceLocation(l1, c1), SourceLocation(l2, c2)], } def test_unique_variable_names(): expect_passes_rule( UniqueVariableNames, """ query A($x: Int, $y: String) { __typename } query B($x: String, $y: Int) { __typename } """, ) def test_duplicate_variable_names(): expect_fails_rule( UniqueVariableNames, """ query A($x: Int, $x: Int, $x: String) { __typename } query B($x: String, $x: Int) { __typename } query C($x: Int, $x: Int) { __typename } """, [ duplicate_var("x", 2, 16, 2, 25), duplicate_var("x", 2, 16, 2, 34), duplicate_var("x", 3, 16, 3, 28), duplicate_var("x", 4, 16, 4, 25), ], ) graphql-core-legacy-2.3.2/graphql/validation/tests/test_validation.py000066400000000000000000000026351365661746200260670ustar00rootroot00000000000000from graphql import parse, validate from graphql.utils.type_info import TypeInfo from graphql.validation.rules import specified_rules from graphql.validation.validation import visit_using_rules from .utils import test_schema def expect_valid(schema, query_string): errors = validate(schema, parse(query_string)) assert not errors def test_it_validates_queries(): expect_valid( test_schema, """ query { catOrDog { ... on Cat { furColor } ... on Dog { isHousetrained } } } """, ) def test_validates_using_a_custom_type_info(): type_info = TypeInfo(test_schema, lambda *_: None) ast = parse( """ query { catOrDog { ... on Cat { furColor } ... on Dog { isHousetrained } } } """ ) errors = visit_using_rules(test_schema, type_info, ast, specified_rules) assert len(errors) == 3 assert ( errors[0].message == 'Cannot query field "catOrDog" on type "QueryRoot". Did you mean "catOrDog"?' ) assert ( errors[1].message == 'Cannot query field "furColor" on type "Cat". Did you mean "furColor"?' ) assert ( errors[2].message == 'Cannot query field "isHousetrained" on type "Dog". Did you mean "isHousetrained"?' ) graphql-core-legacy-2.3.2/graphql/validation/tests/test_variables_are_input_types.py000066400000000000000000000021051365661746200311670ustar00rootroot00000000000000from graphql.language.location import SourceLocation from graphql.validation.rules import VariablesAreInputTypes from .utils import expect_fails_rule, expect_passes_rule def non_input_type_on_variable(variable_name, type_name, line, col): return { "message": VariablesAreInputTypes.non_input_type_on_variable_message( variable_name, type_name ), "locations": [SourceLocation(line, col)], } def test_input_types_are_valid(): expect_passes_rule( VariablesAreInputTypes, """ query Foo($a: String, $b: [Boolean!]!, $c: ComplexInput) { field(a: $a, b: $b, c: $c) } """, ) def test_output_types_are_invalid(): expect_fails_rule( VariablesAreInputTypes, """ query Foo($a: Dog, $b: [[CatOrDog!]]!, $c: Pet) { field(a: $a, b: $b, c: $c) } """, [ non_input_type_on_variable("a", "Dog", 2, 21), non_input_type_on_variable("b", "[[CatOrDog!]]!", 2, 30), non_input_type_on_variable("c", "Pet", 2, 50), ], ) graphql-core-legacy-2.3.2/graphql/validation/tests/test_variables_in_allowed_position.py000066400000000000000000000177031365661746200320300ustar00rootroot00000000000000from graphql.language.location import SourceLocation from graphql.validation.rules import VariablesInAllowedPosition from .utils import expect_fails_rule, expect_passes_rule def test_boolean_boolean(): expect_passes_rule( VariablesInAllowedPosition, """ query Query($booleanArg: Boolean) { complicatedArgs { booleanArgField(booleanArg: $booleanArg) } } """, ) def test_boolean_boolean_in_fragment(): expect_passes_rule( VariablesInAllowedPosition, """ fragment booleanArgFrag on ComplicatedArgs { booleanArgField(booleanArg: $booleanArg) } query Query($booleanArg: Boolean) { complicatedArgs { ...booleanArgFrag } } """, ) expect_passes_rule( VariablesInAllowedPosition, """ query Query($booleanArg: Boolean) { complicatedArgs { ...booleanArgFrag } } fragment booleanArgFrag on ComplicatedArgs { booleanArgField(booleanArg: $booleanArg) } """, ) def test_non_null_boolean_boolean(): expect_passes_rule( VariablesInAllowedPosition, """ query Query($nonNullBooleanArg: Boolean!) { complicatedArgs { booleanArgField(booleanArg: $nonNullBooleanArg) } } """, ) def test_non_null_boolean_to_boolean_within_fragment(): expect_passes_rule( VariablesInAllowedPosition, """ fragment booleanArgFrag on ComplicatedArgs { booleanArgField(booleanArg: $nonNullBooleanArg) } query Query($nonNullBooleanArg: Boolean!) { complicatedArgs { ...booleanArgFrag } } """, ) def test_int_non_null_int_with_default(): expect_passes_rule( VariablesInAllowedPosition, """ query Query($intArg: Int = 1) { complicatedArgs { nonNullIntArgField(nonNullIntArg: $intArg) } } """, ) def test_string_string(): expect_passes_rule( VariablesInAllowedPosition, """ query Query($stringListVar: [String]) { complicatedArgs { stringListArgField(stringListArg: $stringListVar) } } """, ) def test_non_null_string_string(): expect_passes_rule( VariablesInAllowedPosition, """ query Query($stringListVar: [String!]) { complicatedArgs { stringListArgField(stringListArg: $stringListVar) } } """, ) def test_string_string_item_position(): expect_passes_rule( VariablesInAllowedPosition, """ query Query($stringVar: String) { complicatedArgs { stringListArgField(stringListArg: [$stringVar]) } } """, ) def test_non_null_string_string_item_positiion(): expect_passes_rule( VariablesInAllowedPosition, """ query Query($stringVar: String!) { complicatedArgs { stringListArgField(stringListArg: [$stringVar]) } } """, ) def test_complex_input_complex_input(): expect_passes_rule( VariablesInAllowedPosition, """ query Query($complexVar: ComplexInput) { complicatedArgs { complexArgField(complexArg: $complexVar) } } """, ) def test_complex_input_complex_input_in_field_position(): expect_passes_rule( VariablesInAllowedPosition, """ query Query($boolVar: Boolean = false) { complicatedArgs { complexArgField(complexArg: {requiredArg: $boolVar}) } } """, ) def test_boolean_non_null_boolean_in_directive(): expect_passes_rule( VariablesInAllowedPosition, """ query Query($boolVar: Boolean!) { dog @include(if: $boolVar) } """, ) def test_boolean_non_null_boolean_in_directive_with_default(): expect_passes_rule( VariablesInAllowedPosition, """ query Query($boolVar: Boolean = false) { dog @include(if: $boolVar) } """, ) def test_int_non_null_int(): expect_fails_rule( VariablesInAllowedPosition, """ query Query($intArg: Int) { complicatedArgs { nonNullIntArgField(nonNullIntArg: $intArg) } } """, [ { "message": VariablesInAllowedPosition.bad_var_pos_message( "intArg", "Int", "Int!" ), "locations": [SourceLocation(4, 45), SourceLocation(2, 19)], } ], ) def test_int_non_null_int_within_fragment(): expect_fails_rule( VariablesInAllowedPosition, """ fragment nonNullIntArgFieldFrag on ComplicatedArgs { nonNullIntArgField(nonNullIntArg: $intArg) } query Query($intArg: Int) { complicatedArgs { ...nonNullIntArgFieldFrag } } """, [ { "message": VariablesInAllowedPosition.bad_var_pos_message( "intArg", "Int", "Int!" ), "locations": [SourceLocation(5, 19), SourceLocation(3, 43)], } ], ) def test_int_non_null_int_within_nested_fragment(): expect_fails_rule( VariablesInAllowedPosition, """ fragment outerFrag on ComplicatedArgs { ...nonNullIntArgFieldFrag } fragment nonNullIntArgFieldFrag on ComplicatedArgs { nonNullIntArgField(nonNullIntArg: $intArg) } query Query($intArg: Int) { complicatedArgs { ...outerFrag } } """, [ { "message": VariablesInAllowedPosition.bad_var_pos_message( "intArg", "Int", "Int!" ), "locations": [SourceLocation(8, 19), SourceLocation(6, 43)], } ], ) def test_string_over_boolean(): expect_fails_rule( VariablesInAllowedPosition, """ query Query($stringVar: String) { complicatedArgs { booleanArgField(booleanArg: $stringVar) } } """, [ { "message": VariablesInAllowedPosition.bad_var_pos_message( "stringVar", "String", "Boolean" ), "locations": [SourceLocation(2, 19), SourceLocation(4, 39)], } ], ) def test_string_string_fail(): expect_fails_rule( VariablesInAllowedPosition, """ query Query($stringVar: String) { complicatedArgs { stringListArgField(stringListArg: $stringVar) } } """, [ { "message": VariablesInAllowedPosition.bad_var_pos_message( "stringVar", "String", "[String]" ), "locations": [SourceLocation(2, 19), SourceLocation(4, 45)], } ], ) def test_boolean_non_null_boolean_in_directive(): expect_fails_rule( VariablesInAllowedPosition, """ query Query($boolVar: Boolean) { dog @include(if: $boolVar) } """, [ { "message": VariablesInAllowedPosition.bad_var_pos_message( "boolVar", "Boolean", "Boolean!" ), "locations": [SourceLocation(2, 19), SourceLocation(3, 26)], } ], ) def test_string_non_null_boolean_in_directive(): expect_fails_rule( VariablesInAllowedPosition, """ query Query($stringVar: String) { dog @include(if: $stringVar) } """, [ { "message": VariablesInAllowedPosition.bad_var_pos_message( "stringVar", "String", "Boolean!" ), "locations": [SourceLocation(2, 19), SourceLocation(3, 26)], } ], ) graphql-core-legacy-2.3.2/graphql/validation/tests/utils.py000066400000000000000000000232271365661746200240360ustar00rootroot00000000000000from graphql.error import format_error from graphql.language.parser import parse from graphql.type import ( GraphQLArgument, GraphQLBoolean, GraphQLEnumType, GraphQLEnumValue, GraphQLField, GraphQLFloat, GraphQLID, GraphQLInputObjectField, GraphQLInputObjectType, GraphQLInt, GraphQLInterfaceType, GraphQLList, GraphQLNonNull, GraphQLObjectType, GraphQLSchema, GraphQLString, GraphQLUnionType, ) from graphql.type.directives import ( DirectiveLocation, GraphQLDirective, GraphQLIncludeDirective, GraphQLSkipDirective, ) from graphql.validation import validate Being = GraphQLInterfaceType( "Being", {"name": GraphQLField(GraphQLString, {"surname": GraphQLArgument(GraphQLBoolean)})}, ) Pet = GraphQLInterfaceType( "Pet", {"name": GraphQLField(GraphQLString, {"surname": GraphQLArgument(GraphQLBoolean)})}, ) Canine = GraphQLInterfaceType( "Canine", {"name": GraphQLField(GraphQLString, {"surname": GraphQLArgument(GraphQLBoolean)})}, ) DogCommand = GraphQLEnumType( "DogCommand", { "SIT": GraphQLEnumValue(0), "HEEL": GraphQLEnumValue(1), "DOWN": GraphQLEnumValue(2), }, ) Dog = GraphQLObjectType( "Dog", { "name": GraphQLField( GraphQLString, {"surname": GraphQLArgument(GraphQLBoolean)} ), "nickname": GraphQLField(GraphQLString), "barkVolume": GraphQLField(GraphQLInt), "barks": GraphQLField(GraphQLBoolean), "doesKnowCommand": GraphQLField( GraphQLBoolean, {"dogCommand": GraphQLArgument(DogCommand)} ), "isHousetrained": GraphQLField( GraphQLBoolean, args={"atOtherHomes": GraphQLArgument(GraphQLBoolean, default_value=True)}, ), "isAtLocation": GraphQLField( GraphQLBoolean, args={"x": GraphQLArgument(GraphQLInt), "y": GraphQLArgument(GraphQLInt)}, ), }, interfaces=[Being, Pet, Canine], is_type_of=lambda: None, ) Cat = GraphQLObjectType( "Cat", lambda: { "furColor": GraphQLField(FurColor), "name": GraphQLField( GraphQLString, {"surname": GraphQLArgument(GraphQLBoolean)} ), "nickname": GraphQLField(GraphQLString), }, interfaces=[Being, Pet], is_type_of=lambda: None, ) CatOrDog = GraphQLUnionType("CatOrDog", [Dog, Cat]) Intelligent = GraphQLInterfaceType("Intelligent", {"iq": GraphQLField(GraphQLInt)}) Human = GraphQLObjectType( name="Human", interfaces=[Being, Intelligent], is_type_of=lambda: None, fields={ "name": GraphQLField( GraphQLString, {"surname": GraphQLArgument(GraphQLBoolean)} ), "pets": GraphQLField(GraphQLList(Pet)), "iq": GraphQLField(GraphQLInt), }, ) Alien = GraphQLObjectType( name="Alien", is_type_of=lambda *args: True, interfaces=[Being, Intelligent], fields={ "iq": GraphQLField(GraphQLInt), "name": GraphQLField( GraphQLString, {"surname": GraphQLArgument(GraphQLBoolean)} ), "numEyes": GraphQLField(GraphQLInt), }, ) DogOrHuman = GraphQLUnionType("DogOrHuman", [Dog, Human]) HumanOrAlien = GraphQLUnionType("HumanOrAlien", [Human, Alien]) FurColor = GraphQLEnumType( "FurColor", { "BROWN": GraphQLEnumValue(0), "BLACK": GraphQLEnumValue(1), "TAN": GraphQLEnumValue(2), "SPOTTED": GraphQLEnumValue(3), }, ) ComplexInput = GraphQLInputObjectType( "ComplexInput", { "requiredField": GraphQLInputObjectField(GraphQLNonNull(GraphQLBoolean)), "intField": GraphQLInputObjectField(GraphQLInt), "stringField": GraphQLInputObjectField(GraphQLString), "booleanField": GraphQLInputObjectField(GraphQLBoolean), "stringListField": GraphQLInputObjectField(GraphQLList(GraphQLString)), }, ) ComplicatedArgs = GraphQLObjectType( "ComplicatedArgs", { "intArgField": GraphQLField( GraphQLString, {"intArg": GraphQLArgument(GraphQLInt)} ), "nonNullIntArgField": GraphQLField( GraphQLString, {"nonNullIntArg": GraphQLArgument(GraphQLNonNull(GraphQLInt))}, ), "stringArgField": GraphQLField( GraphQLString, {"stringArg": GraphQLArgument(GraphQLString)} ), "booleanArgField": GraphQLField( GraphQLString, {"booleanArg": GraphQLArgument(GraphQLBoolean)} ), "enumArgField": GraphQLField( GraphQLString, {"enumArg": GraphQLArgument(FurColor)} ), "floatArgField": GraphQLField( GraphQLString, {"floatArg": GraphQLArgument(GraphQLFloat)} ), "idArgField": GraphQLField( GraphQLString, {"idArg": GraphQLArgument(GraphQLID)} ), "stringListArgField": GraphQLField( GraphQLString, {"stringListArg": GraphQLArgument(GraphQLList(GraphQLString))}, ), "complexArgField": GraphQLField( GraphQLString, {"complexArg": GraphQLArgument(ComplexInput)} ), "multipleReqs": GraphQLField( GraphQLString, { "req1": GraphQLArgument(GraphQLNonNull(GraphQLInt)), "req2": GraphQLArgument(GraphQLNonNull(GraphQLInt)), }, ), "multipleOpts": GraphQLField( GraphQLString, { "opt1": GraphQLArgument(GraphQLInt, 0), "opt2": GraphQLArgument(GraphQLInt, 0), }, ), "multipleOptsAndReq": GraphQLField( GraphQLString, { "req1": GraphQLArgument(GraphQLNonNull(GraphQLInt)), "req2": GraphQLArgument(GraphQLNonNull(GraphQLInt)), "opt1": GraphQLArgument(GraphQLInt, 0), "opt2": GraphQLArgument(GraphQLInt, 0), }, ), }, ) QueryRoot = GraphQLObjectType( "QueryRoot", { "human": GraphQLField(Human, {"id": GraphQLArgument(GraphQLID)}), "dog": GraphQLField(Dog), "pet": GraphQLField(Pet), "alien": GraphQLField(Alien), "catOrDog": GraphQLField(CatOrDog), "humanOrAlien": GraphQLField(HumanOrAlien), "complicatedArgs": GraphQLField(ComplicatedArgs), }, ) test_schema = GraphQLSchema( query=QueryRoot, directives=[ GraphQLIncludeDirective, GraphQLSkipDirective, GraphQLDirective(name="onQuery", locations=[DirectiveLocation.QUERY]), GraphQLDirective(name="onMutation", locations=[DirectiveLocation.MUTATION]), GraphQLDirective( name="onSubscription", locations=[DirectiveLocation.SUBSCRIPTION] ), GraphQLDirective(name="onField", locations=[DirectiveLocation.FIELD]), GraphQLDirective( name="onFragmentDefinition", locations=[DirectiveLocation.FRAGMENT_DEFINITION], ), GraphQLDirective( name="onFragmentSpread", locations=[DirectiveLocation.FRAGMENT_SPREAD] ), GraphQLDirective( name="onInlineFragment", locations=[DirectiveLocation.INLINE_FRAGMENT] ), GraphQLDirective(name="OnSchema", locations=[DirectiveLocation.SCHEMA]), GraphQLDirective(name="onScalar", locations=[DirectiveLocation.SCALAR]), GraphQLDirective(name="onObject", locations=[DirectiveLocation.OBJECT]), GraphQLDirective( name="onFieldDefinition", locations=[DirectiveLocation.FIELD_DEFINITION] ), GraphQLDirective( name="onArgumentDefinition", locations=[DirectiveLocation.ARGUMENT_DEFINITION], ), GraphQLDirective(name="onInterface", locations=[DirectiveLocation.INTERFACE]), GraphQLDirective(name="onUnion", locations=[DirectiveLocation.UNION]), GraphQLDirective(name="onEnum", locations=[DirectiveLocation.ENUM]), GraphQLDirective(name="onEnumValue", locations=[DirectiveLocation.ENUM_VALUE]), GraphQLDirective( name="onInputObject", locations=[DirectiveLocation.INPUT_OBJECT] ), GraphQLDirective( name="onInputFieldDefinition", locations=[DirectiveLocation.INPUT_FIELD_DEFINITION], ), ], types=[Cat, Dog, Human, Alien], ) def expect_valid(schema, rules, query): errors = validate(schema, parse(query), rules) assert errors == [], "Error: %s, Should validate" % errors def sort_lists(value): if isinstance(value, dict): new_mapping = [] for k, v in value.items(): new_mapping.append((k, sort_lists(v))) return sorted(new_mapping) elif isinstance(value, list): return sorted(map(sort_lists, value)) return value def expect_invalid(schema, rules, query, expected_errors, sort_list=True): errors = validate(schema, parse(query), rules) assert errors, "Should not validate" for error in expected_errors: error["locations"] = [ {"line": loc.line, "column": loc.column} for loc in error["locations"] ] if sort_list: assert sort_lists(list(map(format_error, errors))) == sort_lists( expected_errors ) else: assert list(map(format_error, errors)) == expected_errors def expect_passes_rule(rule, query): return expect_valid(test_schema, [rule], query) def expect_fails_rule(rule, query, errors, sort_list=True): return expect_invalid(test_schema, [rule], query, errors, sort_list) def expect_fails_rule_with_schema(schema, rule, query, errors, sort_list=True): return expect_invalid(schema, [rule], query, errors, sort_list) def expect_passes_rule_with_schema(schema, rule, query): return expect_valid(schema, [rule], query) graphql-core-legacy-2.3.2/graphql/validation/validation.py000066400000000000000000000162041365661746200236630ustar00rootroot00000000000000from ..language.ast import FragmentDefinition, FragmentSpread, OperationDefinition from ..language.visitor import ParallelVisitor, TypeInfoVisitor, Visitor, visit from ..type import GraphQLSchema from ..utils.type_info import TypeInfo from .rules import specified_rules # Necessary for static type checking if False: # flake8: noqa from typing import List, Union, Optional, Dict, Set, Any, Type from ..language.ast import Document, SelectionSet, Node from ..error import GraphQLError from .rules.base import ValidationRule from ..type.definition import ( GraphQLObjectType, GraphQLInterfaceType, GraphQLField, GraphQLArgument, GraphQLType, GraphQLInputObjectType, ) def validate(schema, ast, rules=specified_rules): # type: (GraphQLSchema, Document, List[Type[ValidationRule]]) -> List assert schema, "Must provide schema" assert ast, "Must provide document" assert isinstance(schema, GraphQLSchema) type_info = TypeInfo(schema) return visit_using_rules(schema, type_info, ast, rules) def visit_using_rules(schema, type_info, ast, rules): # type: (GraphQLSchema, TypeInfo, Document, List[Type[ValidationRule]]) -> List context = ValidationContext(schema, ast, type_info) visitors = [rule(context) for rule in rules] visit(ast, TypeInfoVisitor(type_info, ParallelVisitor(visitors))) return context.get_errors() class VariableUsage(object): __slots__ = "node", "type" def __init__(self, node, type): self.node = node self.type = type class UsageVisitor(Visitor): __slots__ = "usages", "type_info" def __init__(self, usages, type_info): # type: (List[VariableUsage], TypeInfo) -> None self.usages = usages self.type_info = type_info def enter_VariableDefinition(self, node, key, parent, path, ancestors): return False def enter_Variable(self, node, key, parent, path, ancestors): usage = VariableUsage(node, type=self.type_info.get_input_type()) self.usages.append(usage) class ValidationContext(object): __slots__ = ( "_schema", "_ast", "_type_info", "_errors", "_fragments", "_fragment_spreads", "_recursively_referenced_fragments", "_variable_usages", "_recursive_variable_usages", ) def __init__(self, schema, ast, type_info): # type: (GraphQLSchema, Document, TypeInfo) -> None self._schema = schema self._ast = ast self._type_info = type_info self._errors = [] # type: List[GraphQLError] self._fragments = None # type: Optional[Dict[str, FragmentDefinition]] self._fragment_spreads = {} # type: Dict[Node, List[FragmentSpread]] self._recursively_referenced_fragments = ( {} ) # type: Dict[OperationDefinition, List[FragmentSpread]] self._variable_usages = {} # type: Dict[Node, List[VariableUsage]] self._recursive_variable_usages = ( {} ) # type: Dict[OperationDefinition, List[VariableUsage]] def report_error(self, error): self._errors.append(error) def get_errors(self): # type: () -> List return self._errors def get_schema(self): # type: () -> GraphQLSchema return self._schema def get_variable_usages(self, node): # type: (OperationDefinition) -> List[VariableUsage] usages = self._variable_usages.get(node) if usages is None: usages = [] sub_visitor = UsageVisitor(usages, self._type_info) visit(node, TypeInfoVisitor(self._type_info, sub_visitor)) self._variable_usages[node] = usages return usages def get_recursive_variable_usages(self, operation): # type: (OperationDefinition) -> List[VariableUsage] assert isinstance(operation, OperationDefinition) usages = self._recursive_variable_usages.get(operation) if usages is None: usages = self.get_variable_usages(operation) fragments = self.get_recursively_referenced_fragments(operation) for fragment in fragments: usages.extend(self.get_variable_usages(fragment)) self._recursive_variable_usages[operation] = usages return usages def get_recursively_referenced_fragments(self, operation): # type: (OperationDefinition) -> List assert isinstance(operation, OperationDefinition) fragments = self._recursively_referenced_fragments.get(operation) if not fragments: fragments = [] collected_names = set() # type: Set[str] nodes_to_visit = [operation.selection_set] while nodes_to_visit: node = nodes_to_visit.pop() spreads = self.get_fragment_spreads(node) for spread in spreads: frag_name = spread.name.value if frag_name not in collected_names: collected_names.add(frag_name) fragment = self.get_fragment(frag_name) if fragment: fragments.append(fragment) nodes_to_visit.append(fragment.selection_set) self._recursively_referenced_fragments[operation] = fragments return fragments def get_fragment_spreads(self, node): # type: (SelectionSet) -> List[FragmentSpread] spreads = self._fragment_spreads.get(node) if not spreads: spreads = [] sets_to_visit = [node] while sets_to_visit: _set = sets_to_visit.pop() for selection in _set.selections: if isinstance(selection, FragmentSpread): spreads.append(selection) elif selection.selection_set: sets_to_visit.append(selection.selection_set) self._fragment_spreads[node] = spreads return spreads def get_ast(self): return self._ast def get_fragment(self, name): fragments = self._fragments if fragments is None: self._fragments = fragments = {} for statement in self.get_ast().definitions: if isinstance(statement, FragmentDefinition): fragments[statement.name.value] = statement return fragments.get(name) def get_type(self): # type: () -> Optional[GraphQLType] return self._type_info.get_type() def get_parent_type(self): # type: () -> Union[GraphQLInterfaceType, GraphQLObjectType, None] return self._type_info.get_parent_type() def get_input_type(self): # type: () -> Optional[GraphQLInputObjectType] return self._type_info.get_input_type() # type: ignore def get_field_def(self): # type: () -> Optional[GraphQLField] return self._type_info.get_field_def() def get_directive(self): # type: () -> Optional[Any] return self._type_info.get_directive() def get_argument(self): # type: () -> Optional[GraphQLArgument] return self._type_info.get_argument() graphql-core-legacy-2.3.2/scripts/000077500000000000000000000000001365661746200170535ustar00rootroot00000000000000graphql-core-legacy-2.3.2/scripts/ast.ast000066400000000000000000000055601365661746200203610ustar00rootroot00000000000000# Mini-language for AST definition. # All AST nodes extend AstNode. # All AST nodes are visible. # All AST fields have a getter and a setter and are a constructor argument. # We have concrete types (code T) and unions (code U). # S for singular field, P for plural, ? for nullable. # O for option in a union. # Scalar type ontology: string, boolean # Location tracking for Identifier is probably useful for error messages. U Definition O OperationDefinition O FragmentDefinition T Document P Definition definitions T OperationDefinition S OperationKind operation S? Name name P? VariableDefinition variableDefinitions P? Directive directives S SelectionSet selectionSet T VariableDefinition S Variable variable S Type type S? Value defaultValue T SelectionSet P Selection selections U Selection O Field O FragmentSpread O InlineFragment T Field S? Name alias S Name name P? Argument arguments P? Directive directives S? SelectionSet selectionSet T Argument S Name name S Value value T FragmentSpread S Name name P? Directive directives T InlineFragment S NamedType typeCondition P? Directive directives S SelectionSet selectionSet T FragmentDefinition S Name name S NamedType typeCondition P? Directive directives S SelectionSet selectionSet U Value O Variable O IntValue O FloatValue O StringValue O BooleanValue O EnumValue O ArrayValue O ObjectValue T Variable S Name name T IntValue S string value T FloatValue S string value T StringValue S string value T BooleanValue S boolean value T EnumValue S string value T ArrayValue P Value values T ObjectValue P ObjectField fields T ObjectField S Name name S Value value T Directive S Name name P? Argument arguments U Type O NamedType O ListType O NonNullType T NamedType S Name name T ListType S Type type T NonNullType # JS version prohibits nesting nonnull in nonnull, we can't because we # can't support multiple unions. Fix? S Type type T Name S string value # Implementation of Schema Parser AST Types # This is not included in libgraphqlparser. # Generated from https://github.com/graphql/graphql-js/blob/master/src/language/ast.js @ 3f1f9f5 U TypeDefinition O ObjectTypeDefinition O InterfaceTypeDefinition O UnionTypeDefinition O ScalarTypeDefinition O EnumTypeDefinition O InputObjectTypeDefinition O TypeExtensionDefinition T ObjectTypeDefinition S Name name P? NamedType interfaces P FieldDefinition fields T FieldDefinition S Name name P InputValueDefinition arguments S Type type T InputValueDefinition S Name name S Type type S? Value defaultValue T InterfaceTypeDefinition S Name name P FieldDefinition fields T UnionTypeDefinition S Name name P NamedType types T ScalarTypeDefinition S Name name T EnumTypeDefinition S Name name P EnumValueDefinition values T EnumValueDefinition S Name name T InputObjectTypeDefinition S Name name P InputValueDefinition fields T TypeExtensionDefinition S ObjectTypeDefinition definition graphql-core-legacy-2.3.2/scripts/casing.py000066400000000000000000000013521365661746200206720ustar00rootroot00000000000000# Copyright (c) 2015, Facebook, Inc. # All rights reserved. # # This source code is licensed under the BSD-style license found in the # LICENSE file in the root directory of this source tree. An additional grant # of patent rights can be found in the PATENTS file in the same directory. def title(s): """Capitalize the first character of s.""" return s[0].capitalize() + s[1:] def camel(s): """Lowercase the first character of s.""" return s[0].lower() + s[1:] def snake(s): """Convert from title or camelCase to snake_case.""" if len(s) < 2: return s.lower() out = s[0].lower() for c in s[1:]: if c.isupper(): out += "_" c = c.lower() out += c return out graphql-core-legacy-2.3.2/scripts/fb_ast.py000066400000000000000000000044041365661746200206650ustar00rootroot00000000000000#!/usr/bin/env python # Copyright (c) 2015, Facebook, Inc. # All rights reserved. # # This source code is licensed under the BSD-style license found in the # LICENSE file in the root directory of this source tree. An additional grant # of patent rights can be found in the PATENTS file in the same directory. from importlib import import_module def load_lang(lang): return import_module(lang).Printer() def print_ast(lang_module, input_file): lang_module.start_file() line = input_file.readline() while line: line = line.strip() if line.startswith("#") or not line: line = input_file.readline() continue code, rest = line.split(None, 1) if code[0] == "T": lang_module.start_type(rest) field_line = input_file.readline().strip() while field_line: if field_line.startswith("#"): field_line = input_file.readline().strip() continue field_kind, field_type, field_name = field_line.split() nullable = len(field_kind) > 1 and field_kind[1] == "?" if field_kind[0] == "S": plural = False elif field_kind[0] == "P": plural = True else: raise Exception("Unknown field kind: " + field_kind) lang_module.field(field_type, field_name, nullable, plural) field_line = input_file.readline().strip() lang_module.end_type(rest) elif code[0] == "U": lang_module.start_union(rest) field_line = input_file.readline().strip() while field_line: option_code, option_type = field_line.split() if option_code != "O": raise Exception("Unknown code in union: " + option_code) lang_module.union_option(option_type) field_line = input_file.readline().strip() lang_module.end_union(rest) line = input_file.readline() lang_module.end_file() if __name__ == "__main__": import sys lang = sys.argv[1] filename = sys.argv[2] lang_module = load_lang(lang) print_ast(lang_module, open(filename, "r")) graphql-core-legacy-2.3.2/scripts/generate_ast.py000066400000000000000000000120041365661746200220630ustar00rootroot00000000000000from casing import snake if __name__ == "__main__": import os.path import sys import subprocess project_root = os.path.join(os.path.dirname(__file__), "..") with open(os.path.join(project_root, "graphql/core/language/ast.py"), "w") as fp: process = subprocess.Popen( ["python", "./fb_ast.py", "generate_ast", "./ast.ast"], stdout=fp, cwd=os.path.join(project_root, "scripts"), env={"PYTHONPATH": "."}, ) sys.exit(process.wait()) # Fix inconsistencies between libgraphqlparser and graphql-js REMAP_TYPES = {"ArrayValue": "ListValue"} def remap_type(typename): return REMAP_TYPES.get(typename, typename) class Printer(object): def __init__(self): self._current_union = None self._parent_types = {} self._fields = [] def start_file(self): print( """# This is autogenerated code. DO NOT change this manually. # Run scripts/generate_ast.py to generate this file. class Node(object): __slots__ = ()""" ) def end_file(self): pass def start_type(self, name): name = remap_type(name) parent_type = self._parent_types.get(name, "Node") print( """ class {name}({parent_type}):""".format( name=name, parent_type=parent_type ) ) def field(self, type, name, nullable, plural): type = remap_type(type) self._fields.append((type, name, nullable, plural)) def end_type(self, typename): typename = remap_type(typename) self._print_slots() self._print_fields() self._print_ctor() self._print_comparator(typename) self._print_repr(typename) self._print_copy(typename) self._print_hash() self._fields = [] def _print_fields(self): fields = ", ".join( "'" + snake(name) + "'" for (type, name, nullable, plural) in self._fields ) print(""" _fields = ({},)""".format(fields)) def _print_slots(self): slots = ", ".join( "'" + snake(name) + "'" for (type, name, nullable, plural) in self._fields ) print(""" __slots__ = ('loc', {slots},)""".format(slots=slots)) def _print_ctor(self): fields = [field for field in self._fields if not field[2]] + [ field for field in self._fields if field[2] ] ctor_args = ", ".join( snake(name) + ("=None" if nullable else "") for (type, name, nullable, plural) in fields ) print( """ def __init__(self, {ctor_args}, loc=None): self.loc = loc""".format( ctor_args=ctor_args ) ) for type, name, nullable, plural in self._fields: print(""" self.{name} = {name}""".format(name=snake(name))) def _print_comparator(self, typename): print( """ def __eq__(self, other): return ( self is other or ( isinstance(other, {typename}) and self.loc == other.loc and""".format( typename=typename ) ) print( " and\n".join( """ self.{name} == other.{name}""".format( name=snake(name) ) for type, name, nullable, plural in self._fields ) ) print(" )") print(" )") def _print_copy(self, typename): fields = [field for field in self._fields if not field[2]] + [ field for field in self._fields if field[2] ] args = "\n".join( """ self.{},""".format(snake(name)) for (type, name, nullable, plural) in fields ) print( """ def __copy__(self): return type(self)( {} self.loc )""".format( args ) ) def _print_repr(self, typename): print( """ def __repr__(self): return ('{typename}(' """.rstrip().format( typename=typename ) ) first = True for type, name, nullable, plural in self._fields: print( " '{comma}{name}={{self.{name}!r}}'".format( comma=", " if not first else "", name=snake(name) ) ) first = False print(""" ')').format(self=self)""") def _print_hash(self): print( """ def __hash__(self): return id(self)""" ) def start_union(self, name): self._current_union = name print( """ class {name}(Node): __slots__ = ()""".format( name=name ) ) def union_option(self, option): option = remap_type(option) self._parent_types[option] = self._current_union def end_union(self, name): self._current_union = None graphql-core-legacy-2.3.2/setup.cfg000066400000000000000000000003241365661746200172040ustar00rootroot00000000000000[coverage:run] omit=graphql/backend/quiver_cloud.py,tests,*/tests/* [coverage:report] omit=graphql/backend/quiver_cloud.py,tests,*/tests/* [bdist_wheel] universal=1 [mypy-graphql.*.tests.*] ignore_errors=true graphql-core-legacy-2.3.2/setup.py000066400000000000000000000054261365661746200171050ustar00rootroot00000000000000from setuptools import setup, find_packages from setuptools.command.test import test as TestCommand import sys import ast import re _version_re = re.compile(r"VERSION\s+=\s+(.*)") with open("graphql/__init__.py", "rb") as f: version = ast.literal_eval(_version_re.search(f.read().decode("utf-8")).group(1)) with open("README.md", "rb") as freadme: readme = freadme.read().decode("utf-8") path_copy = sys.path[:] sys.path.append("graphql") try: from pyutils.version import get_version version = get_version(version) except Exception: version = ".".join([str(v) for v in version]) sys.path[:] = path_copy install_requires = ["six>=1.10.0", "promise>=2.3,<3", "rx>=1.6,<2"] tests_requires = [ "six==1.14.0", "pyannotate==1.2.0", "pytest==4.6.10", "pytest-django==3.9.0", "pytest-cov==2.8.1", "coveralls==1.11.1", "cython==0.29.17", "gevent==1.5.0", "pytest-benchmark==3.2.3", "pytest-mock==2.0.0", ] class PyTest(TestCommand): def finalize_options(self): TestCommand.finalize_options(self) self.test_args = ["graphql", "-vrsx"] self.test_suite = True def run_tests(self): # import here, cause outside the eggs aren't loaded import pytest errno = pytest.main(self.test_args) sys.exit(errno) setup( name="graphql-core", version=version, description="GraphQL implementation for Python", long_description=readme, long_description_content_type="text/markdown", url="https://github.com/graphql-python/graphql-core-legacy", download_url="https://github.com/graphql-python/graphql-core-legacy/releases", author="Syrus Akbary, Jake Heinz, Taeho Kim", author_email="me@syrusakbary.com", license="MIT", classifiers=[ "Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "Topic :: Software Development :: Libraries", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: Implementation :: PyPy", "License :: OSI Approved :: MIT License", "Topic :: Database :: Front-Ends", "Topic :: Internet :: WWW/HTTP", ], keywords="api graphql protocol rest", packages=find_packages(exclude=["tests", "tests_py35", "tests.*", "tests_py35.*"]), install_requires=install_requires, tests_require=tests_requires, cmdclass={"test": PyTest}, extras_require={"gevent": ["gevent>=1.1"], "test": tests_requires}, package_data={"graphql": ["py.typed"]}, ) graphql-core-legacy-2.3.2/tests/000077500000000000000000000000001365661746200165265ustar00rootroot00000000000000graphql-core-legacy-2.3.2/tests/__init__.py000066400000000000000000000000001365661746200206250ustar00rootroot00000000000000graphql-core-legacy-2.3.2/tests/starwars/000077500000000000000000000000001365661746200203745ustar00rootroot00000000000000graphql-core-legacy-2.3.2/tests/starwars/__init__.py000066400000000000000000000000001365661746200224730ustar00rootroot00000000000000graphql-core-legacy-2.3.2/tests/starwars/starwars_fixtures.py000066400000000000000000000031361365661746200245500ustar00rootroot00000000000000from collections import namedtuple Human = namedtuple("Human", "id name friends appearsIn homePlanet") 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 ) humanData = {"1000": luke, "1001": vader, "1002": han, "1003": leia, "1004": tarkin} Droid = namedtuple("Droid", "id name friends appearsIn primaryFunction") 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", ) droidData = {"2000": threepio, "2001": artoo} def getCharacter(id): return humanData.get(id) or droidData.get(id) def getFriends(character): return map(getCharacter, character.friends) def getHero(episode): if episode == 5: return luke return artoo def getHuman(id): return humanData.get(id) def getDroid(id): return droidData.get(id) graphql-core-legacy-2.3.2/tests/starwars/starwars_schema.py000066400000000000000000000105031365661746200241330ustar00rootroot00000000000000from graphql.type import ( GraphQLArgument, GraphQLEnumType, GraphQLEnumValue, GraphQLField, GraphQLInterfaceType, GraphQLList, GraphQLNonNull, GraphQLObjectType, GraphQLSchema, GraphQLString, ) from .starwars_fixtures import getDroid, getFriends, getHero, getHuman episodeEnum = GraphQLEnumType( "Episode", description="One of the films in the Star Wars Trilogy", values={ "NEWHOPE": GraphQLEnumValue(4, description="Released in 1977."), "EMPIRE": GraphQLEnumValue(5, description="Released in 1980."), "JEDI": GraphQLEnumValue(6, description="Released in 1983."), }, ) characterInterface = GraphQLInterfaceType( "Character", description="A character in the Star Wars Trilogy", fields=lambda: { "id": GraphQLField( GraphQLNonNull(GraphQLString), description="The id of the character." ), "name": GraphQLField(GraphQLString, description="The name of the character."), "friends": GraphQLField( GraphQLList(characterInterface), description="The friends of the character, or an empty list if they have none.", ), "appearsIn": GraphQLField( GraphQLList(episodeEnum), description="Which movies they appear in." ), }, resolve_type=lambda character, info: humanType if getHuman(character.id) else droidType, ) humanType = GraphQLObjectType( "Human", description="A humanoid creature in the Star Wars universe.", fields=lambda: { "id": GraphQLField( GraphQLNonNull(GraphQLString), description="The id of the human." ), "name": GraphQLField(GraphQLString, description="The name of the human."), "friends": GraphQLField( GraphQLList(characterInterface), description="The friends of the human, or an empty list if they have none.", resolver=lambda human, *_: getFriends(human), ), "appearsIn": GraphQLField( GraphQLList(episodeEnum), description="Which movies they appear in." ), "homePlanet": GraphQLField( GraphQLString, description="The home planet of the human, or null if unknown.", ), }, interfaces=[characterInterface], ) droidType = GraphQLObjectType( "Droid", description="A mechanical creature in the Star Wars universe.", fields=lambda: { "id": GraphQLField( GraphQLNonNull(GraphQLString), description="The id of the droid." ), "name": GraphQLField(GraphQLString, description="The name of the droid."), "friends": GraphQLField( GraphQLList(characterInterface), description="The friends of the droid, or an empty list if they have none.", resolver=lambda droid, info, **args: getFriends(droid), ), "appearsIn": GraphQLField( GraphQLList(episodeEnum), description="Which movies they appear in." ), "primaryFunction": GraphQLField( GraphQLString, description="The primary function of the droid." ), }, interfaces=[characterInterface], ) queryType = GraphQLObjectType( "Query", fields=lambda: { "hero": GraphQLField( characterInterface, args={ "episode": GraphQLArgument( description="If omitted, returns the hero of the whole saga. If " "provided, returns the hero of that particular episode.", type_=episodeEnum, ) }, resolver=lambda root, info, **args: getHero(args.get("episode")), ), "human": GraphQLField( humanType, args={ "id": GraphQLArgument( description="id of the human", type_=GraphQLNonNull(GraphQLString) ) }, resolver=lambda root, info, **args: getHuman(args["id"]), ), "droid": GraphQLField( droidType, args={ "id": GraphQLArgument( description="id of the droid", type_=GraphQLNonNull(GraphQLString) ) }, resolver=lambda root, info, **args: getDroid(args["id"]), ), }, ) StarWarsSchema = GraphQLSchema(query=queryType, types=[humanType, droidType]) graphql-core-legacy-2.3.2/tests/starwars/test_introspection.py000066400000000000000000000213441365661746200247110ustar00rootroot00000000000000from graphql import graphql from graphql.error import format_error from graphql.pyutils.contain_subset import contain_subset from .starwars_schema import StarWarsSchema def test_allows_querying_the_schema_for_types(): query = """ query IntrospectionTypeQuery { __schema { types { name } } } """ expected = { "__schema": { "types": [ {"name": "Query"}, {"name": "Episode"}, {"name": "Character"}, {"name": "String"}, {"name": "Human"}, {"name": "Droid"}, {"name": "__Schema"}, {"name": "__Type"}, {"name": "__TypeKind"}, {"name": "Boolean"}, {"name": "__Field"}, {"name": "__InputValue"}, {"name": "__EnumValue"}, {"name": "__Directive"}, {"name": "__DirectiveLocation"}, ] } } result = graphql(StarWarsSchema, query) assert not result.errors assert contain_subset(result.data, expected) def test_allows_querying_the_schema_for_query_type(): query = """ query IntrospectionQueryTypeQuery { __schema { queryType { name } } } """ expected = {"__schema": {"queryType": {"name": "Query"}}} result = graphql(StarWarsSchema, query) assert not result.errors assert contain_subset(result.data, expected) def test_allows_querying_the_schema_for_a_specific_type(): query = """ query IntrospectionDroidTypeQuery { __type(name: "Droid") { name } } """ expected = {"__type": {"name": "Droid"}} result = graphql(StarWarsSchema, query) assert not result.errors assert contain_subset(result.data, expected) def test_allows_querying_the_schema_for_an_object_kind(): query = """ query IntrospectionDroidKindQuery { __type(name: "Droid") { name kind } } """ expected = {"__type": {"name": "Droid", "kind": "OBJECT"}} result = graphql(StarWarsSchema, query) assert not result.errors assert contain_subset(result.data, expected) def test_allows_querying_the_schema_for_an_interface_kind(): query = """ query IntrospectionCharacterKindQuery { __type(name: "Character") { name kind } } """ expected = {"__type": {"name": "Character", "kind": "INTERFACE"}} result = graphql(StarWarsSchema, query) assert not result.errors assert contain_subset(result.data, expected) def test_allows_querying_the_schema_for_object_fields(): query = """ query IntrospectionDroidFieldsQuery { __type(name: "Droid") { name fields { name type { name kind } } } } """ expected = { "__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": "primaryFunction", "type": {"name": "String", "kind": "SCALAR"}, }, ], } } result = graphql(StarWarsSchema, query) assert not result.errors assert contain_subset(result.data, expected) def test_allows_querying_the_schema_for_nested_object_fields(): query = """ query IntrospectionDroidNestedFieldsQuery { __type(name: "Droid") { name fields { name type { name kind ofType { name kind } } } } } """ expected = { "__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": "primaryFunction", "type": {"name": "String", "kind": "SCALAR", "ofType": None}, }, ], } } result = graphql(StarWarsSchema, query) assert not result.errors assert contain_subset(result.data, expected) def test_allows_querying_the_schema_for_field_args(): query = """ query IntrospectionQueryTypeQuery { __schema { queryType { fields { name args { name description type { name kind ofType { name kind } } defaultValue } } } } } """ expected = { "__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, } ], }, ] } } } result = graphql(StarWarsSchema, query) assert not result.errors assert contain_subset(result.data, expected) def test_allows_querying_the_schema_for_documentation(): query = """ query IntrospectionDroidDescriptionQuery { __type(name: "Droid") { name description } } """ expected = { "__type": { "name": "Droid", "description": "A mechanical creature in the Star Wars universe.", } } result = graphql(StarWarsSchema, query) assert not result.errors assert contain_subset(result.data, expected) graphql-core-legacy-2.3.2/tests/starwars/test_query.py000066400000000000000000000157021365661746200231570ustar00rootroot00000000000000from graphql import graphql from graphql.error import format_error from .starwars_schema import StarWarsSchema def test_hero_name_query(): query = """ query HeroNameQuery { hero { name } } """ expected = {"hero": {"name": "R2-D2"}} result = graphql(StarWarsSchema, query) assert not result.errors assert result.data == expected def test_hero_name_and_friends_query(): query = """ query HeroNameAndFriendsQuery { hero { id name friends { name } } } """ expected = { "hero": { "id": "2001", "name": "R2-D2", "friends": [ {"name": "Luke Skywalker"}, {"name": "Han Solo"}, {"name": "Leia Organa"}, ], } } result = graphql(StarWarsSchema, query) assert not result.errors assert result.data == expected def test_nested_query(): query = """ query NestedQuery { hero { name friends { name appearsIn friends { name } } } } """ expected = { "hero": { "name": "R2-D2", "friends": [ { "name": "Luke Skywalker", "appearsIn": ["NEWHOPE", "EMPIRE", "JEDI"], "friends": [ {"name": "Han Solo"}, {"name": "Leia Organa"}, {"name": "C-3PO"}, {"name": "R2-D2"}, ], }, { "name": "Han Solo", "appearsIn": ["NEWHOPE", "EMPIRE", "JEDI"], "friends": [ {"name": "Luke Skywalker"}, {"name": "Leia Organa"}, {"name": "R2-D2"}, ], }, { "name": "Leia Organa", "appearsIn": ["NEWHOPE", "EMPIRE", "JEDI"], "friends": [ {"name": "Luke Skywalker"}, {"name": "Han Solo"}, {"name": "C-3PO"}, {"name": "R2-D2"}, ], }, ], } } result = graphql(StarWarsSchema, query) assert not result.errors assert result.data == expected def test_fetch_luke_query(): query = """ query FetchLukeQuery { human(id: "1000") { name } } """ expected = {"human": {"name": "Luke Skywalker"}} result = graphql(StarWarsSchema, query) assert not result.errors assert result.data == expected def test_fetch_some_id_query(): query = """ query FetchSomeIDQuery($someId: String!) { human(id: $someId) { name } } """ params = {"someId": "1000"} expected = {"human": {"name": "Luke Skywalker"}} result = graphql(StarWarsSchema, query, variable_values=params) assert not result.errors assert result.data == expected def test_fetch_some_id_query2(): query = """ query FetchSomeIDQuery($someId: String!) { human(id: $someId) { name } } """ params = {"someId": "1002"} expected = {"human": {"name": "Han Solo"}} result = graphql(StarWarsSchema, query, variable_values=params) assert not result.errors assert result.data == expected def test_invalid_id_query(): query = """ query humanQuery($id: String!) { human(id: $id) { name } } """ params = {"id": "not a valid id"} expected = {"human": None} result = graphql(StarWarsSchema, query, variable_values=params) assert not result.errors assert result.data == expected def test_fetch_luke_aliased(): query = """ query FetchLukeAliased { luke: human(id: "1000") { name } } """ expected = {"luke": {"name": "Luke Skywalker"}} result = graphql(StarWarsSchema, query) assert not result.errors assert result.data == expected def test_fetch_luke_and_leia_aliased(): query = """ query FetchLukeAndLeiaAliased { luke: human(id: "1000") { name } leia: human(id: "1003") { name } } """ expected = {"luke": {"name": "Luke Skywalker"}, "leia": {"name": "Leia Organa"}} result = graphql(StarWarsSchema, query) assert not result.errors assert result.data == expected def test_duplicate_fields(): query = """ query DuplicateFields { luke: human(id: "1000") { name homePlanet } leia: human(id: "1003") { name homePlanet } } """ expected = { "luke": {"name": "Luke Skywalker", "homePlanet": "Tatooine"}, "leia": {"name": "Leia Organa", "homePlanet": "Alderaan"}, } result = graphql(StarWarsSchema, query) assert not result.errors assert result.data == expected def test_use_fragment(): query = """ query UseFragment { luke: human(id: "1000") { ...HumanFragment } leia: human(id: "1003") { ...HumanFragment } } fragment HumanFragment on Human { name homePlanet } """ expected = { "luke": {"name": "Luke Skywalker", "homePlanet": "Tatooine"}, "leia": {"name": "Leia Organa", "homePlanet": "Alderaan"}, } result = graphql(StarWarsSchema, query) assert not result.errors assert result.data == expected def test_check_type_of_r2(): query = """ query CheckTypeOfR2 { hero { __typename name } } """ expected = {"hero": {"__typename": "Droid", "name": "R2-D2"}} result = graphql(StarWarsSchema, query) assert not result.errors assert result.data == expected def test_check_type_of_luke(): query = """ query CheckTypeOfLuke { hero(episode: EMPIRE) { __typename name } } """ expected = {"hero": {"__typename": "Human", "name": "Luke Skywalker"}} result = graphql(StarWarsSchema, query) assert not result.errors assert result.data == expected def test_parse_error(): query = """ qeury """ result = graphql(StarWarsSchema, query) assert result.invalid formatted_error = format_error(result.errors[0]) assert formatted_error["locations"] == [{"column": 9, "line": 2}] assert ( 'Syntax Error GraphQL (2:9) Unexpected Name "qeury"' in formatted_error["message"] ) assert result.data is None graphql-core-legacy-2.3.2/tests/starwars/test_validation.py000066400000000000000000000043031365661746200241370ustar00rootroot00000000000000from graphql.language.parser import parse from graphql.language.source import Source from graphql.validation import validate from .starwars_schema import StarWarsSchema def validation_errors(query): source = Source(query, "StarWars.graphql") ast = parse(source) return validate(StarWarsSchema, ast) def test_nested_query_with_fragment(): query = """ query NestedQueryWithFragment { hero { ...NameAndAppearances friends { ...NameAndAppearances friends { ...NameAndAppearances } } } } fragment NameAndAppearances on Character { name appearsIn } """ assert not validation_errors(query) def test_non_existent_fields(): query = """ query HeroSpaceshipQuery { hero { favoriteSpaceship } } """ assert validation_errors(query) def test_require_fields_on_object(): query = """ query HeroNoFieldsQuery { hero } """ assert validation_errors(query) def test_disallows_fields_on_scalars(): query = """ query HeroFieldsOnScalarQuery { hero { name { firstCharacterOfName } } } """ assert validation_errors(query) def test_disallows_object_fields_on_interfaces(): query = """ query DroidFieldOnCharacter { hero { name primaryFunction } } """ assert validation_errors(query) def test_allows_object_fields_in_fragments(): query = """ query DroidFieldInFragment { hero { name ...DroidFields } } fragment DroidFields on Droid { primaryFunction } """ assert not validation_errors(query) def test_allows_object_fields_in_inline_fragments(): query = """ query DroidFieldInFragment { hero { name ...DroidFields } } fragment DroidFields on Droid { primaryFunction } """ assert not validation_errors(query) graphql-core-legacy-2.3.2/tests_py35/000077500000000000000000000000001365661746200174065ustar00rootroot00000000000000graphql-core-legacy-2.3.2/tests_py35/__init__.py000066400000000000000000000000001365661746200215050ustar00rootroot00000000000000graphql-core-legacy-2.3.2/tests_py35/core_execution/000077500000000000000000000000001365661746200224215ustar00rootroot00000000000000graphql-core-legacy-2.3.2/tests_py35/core_execution/__init__.py000066400000000000000000000000241365661746200245260ustar00rootroot00000000000000__author__ = "jake" graphql-core-legacy-2.3.2/tests_py35/core_execution/test_asyncio_executor.py000066400000000000000000000055621365661746200274250ustar00rootroot00000000000000import asyncio from graphql.error import format_error from graphql.execution import execute from graphql.language.parser import parse from graphql.execution.executors.asyncio import AsyncioExecutor from graphql.type import GraphQLSchema, GraphQLObjectType, GraphQLField, GraphQLString def test_asyncio_py35_executor(): ast = parse("query Example { a, b, c }") async def resolver(context, *_): await asyncio.sleep(0.001) return "hey" async def resolver_2(context, *_): await asyncio.sleep(0.003) return "hey2" def resolver_3(context, *_): return "hey3" Type = GraphQLObjectType( "Type", { "a": GraphQLField(GraphQLString, resolver=resolver), "b": GraphQLField(GraphQLString, resolver=resolver_2), "c": GraphQLField(GraphQLString, resolver=resolver_3), }, ) result = execute(GraphQLSchema(Type), ast, executor=AsyncioExecutor()) assert not result.errors assert result.data == {"a": "hey", "b": "hey2", "c": "hey3"} def test_asyncio_py35_executor_return_promise(): ast = parse("query Example { a, b, c }") async def resolver(context, *_): await asyncio.sleep(0.001) return "hey" async def resolver_2(context, *_): await asyncio.sleep(0.003) return "hey2" def resolver_3(context, *_): return "hey3" Type = GraphQLObjectType( "Type", { "a": GraphQLField(GraphQLString, resolver=resolver), "b": GraphQLField(GraphQLString, resolver=resolver_2), "c": GraphQLField(GraphQLString, resolver=resolver_3), }, ) loop = asyncio.get_event_loop() async def do_exec(): result = await execute( GraphQLSchema(Type), ast, executor=AsyncioExecutor(loop), return_promise=True, ) assert not result.errors assert result.data == {"a": "hey", "b": "hey2", "c": "hey3"} loop.run_until_complete(do_exec()) def test_asyncio_py35_executor_with_error(): ast = parse("query Example { a, b }") async def resolver(context, *_): await asyncio.sleep(0.001) return "hey" async def resolver_2(context, *_): await asyncio.sleep(0.003) raise Exception("resolver_2 failed!") Type = GraphQLObjectType( "Type", { "a": GraphQLField(GraphQLString, resolver=resolver), "b": GraphQLField(GraphQLString, resolver=resolver_2), }, ) result = execute(GraphQLSchema(Type), ast, executor=AsyncioExecutor()) formatted_errors = list(map(format_error, result.errors)) assert formatted_errors == [ { "locations": [{"line": 1, "column": 20}], "path": ["b"], "message": "resolver_2 failed!", } ] assert result.data == {"a": "hey", "b": None} graphql-core-legacy-2.3.2/tox.ini000066400000000000000000000014211365661746200166750ustar00rootroot00000000000000[tox] envlist = py{27,35,36,37,py38,py,py3},pre-commit,mypy,docs [testenv] install_command = python -m pip install --ignore-installed {opts} {packages} deps = .[test] commands = py{27,py}: pytest graphql tests {posargs} py{35,36,38,py3}: pytest graphql tests tests_py35 {posargs} py{37}: pytest graphql tests tests_py35 {posargs: --cov-report=term-missing --cov=graphql} [testenv:pre-commit] basepython=python3.8 deps = pre-commit==1.21.0 setenv = LC_CTYPE=en_US.UTF-8 commands = pre-commit {posargs:run --all-files} [testenv:mypy] basepython=python3.8 deps = mypy==0.770 commands = mypy graphql --ignore-missing-imports [testenv:docs] changedir = docs deps = sphinx commands = sphinx-build -W -b html -d {envtmpdir}/doctrees . {envtmpdir}/html