diff --git a/.bumpversion.cfg b/.bumpversion.cfg index 181bd7cd..bf8ac5ad 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = 3.0.0 +current_version = 3.0.6 commit = False tag = False @@ -8,8 +8,8 @@ search = version = "{current_version}" replace = version = "{new_version}" [bumpversion:file:docs/conf.py] -search = version = release = u'{current_version}' -replace = version = release = u'{new_version}' +search = version = release = '{current_version}' +replace = version = release = '{new_version}' [bumpversion:file:README.md] search = The current version {current_version} diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 00000000..4e2678d4 --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,25 @@ +name: Code quality + +on: [push, pull_request] + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + + - name: Set up Python 3.8 + uses: actions/setup-python@v2 + with: + python-version: 3.8 + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install tox + + - name: Run code quality tests with tox + run: tox + env: + TOXENV: black,flake8,mypy,docs,manifest diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 00000000..7f2b0201 --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,29 @@ +name: Publish + +on: + push: + tags: + - 'v*' + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + + - name: Set up Python 3.8 + uses: actions/setup-python@v2 + with: + python-version: 3.8 + + - name: Build wheel and source tarball + run: | + pip install wheel + python setup.py sdist bdist_wheel + + - name: Publish a Python distribution to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 + with: + user: __token__ + password: ${{ secrets.PYPI_TOKEN }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 00000000..09278c14 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,27 @@ +name: Tests + +on: [push, pull_request] + +jobs: + build: + runs-on: ubuntu-latest + + strategy: + matrix: + python: ['3.6', '3.7', '3.8', '3.9', '3.10', 'pypy3'] + + steps: + - uses: actions/checkout@v2 + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install tox tox-gh-actions + + - name: Run unit tests with tox + run: tox diff --git a/.gitignore b/.gitignore index 2b424f04..6b51313b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,25 +1,24 @@ -.cache +.cache/ .coverage -.env -.env.bak -.idea -.mypy_cache -.pytest_cache -.tox -.venv -.venv.bak -.vs +.env*/ +.idea/ +.mypy_cache/ +.pytest_cache/ +.tox/ +.venv*/ +.vs/ -build -dist -docs/_build -pip-wheel-metadata -wheels +build/ +dist/ +docs/_build/ +htmlcov/ +pip-wheel-metadata/ +wheels/ -play +play/ -__pycache__ +__pycache__/ *.cover *.egg diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 31e679e2..00000000 --- a/.travis.yml +++ /dev/null @@ -1,43 +0,0 @@ -language: python -matrix: - include: - - name: Code quality tests - env: TOXENV=black,flake8,mypy,docs - python: 3.7 - dist: xenial - sudo: true - - name: Unit tests with Python 3.8 - env: TOXENV=py38 - python: 3.8 - dist: xenial - sudo: true - - name: Unit tests with Python 3.7 - env: TOXENV=py37 - python: 3.7 - dist: xenial - sudo: true - - name: Unit tests with Python 3.6 - env: TOXENV=py36 - python: 3.6 -cache: - directories: - - "$HOME/.cache/pip" - - "$TRAVIS_BUILD_DIR/.tox" -install: - - pip install "poetry>=1.0.0b8" - - poetry install -script: - - tox -e $TOXENV -- --cov-report term-missing --cov=graphql -after_success: - - codecov -deploy: - provider: pypi - distributions: sdist bdist_wheel - on: - branch: master - tags: true - python: 3.7 - skip_existing: true - user: mvanlonden - password: - secure: BjKsrn6rww8EEevU2VspVOFqrX/O09Yh8Xbjg+m6/yHmKDsX7kh+U3smgtOXGneKvnu6pLqXJS+gqGDi/u8OJfa8zrYyLlOXMEjPg0kWMl+w+s8E6BtEbOJ1qghS00kqk8xQeMK1YcfJLzztHt4g1VQM0C/y1kMub+Q8nz6KWHifgiSxcud7G/y8TrSYHcm74XWiY0U1zStUfx4z9Zftjr4MRFG9igXXLYCvGYoHOo0Ji4/6Ssgr3lX7GMT7glgBgrv5DmFpCWkVSuHrdyA7x32+O2XU8hLtGGPVoRWFhxc3cQ/QR4VrzCDauZMMOQG3c8dHoXz2T3dgsf9vN6XAB2HiaC1G2E3sI9C44hlUWxl3/5arZ0P4pq1MTRZaX2P6jU+cgyzWyuJ6f3bM2sYo0xOswhG1uP85iVWa2NlJIxmL8NMSoHlDtRLGWxMdqA6Vprn/Jn93AOkywa810ZCuSbgJEHS4ukJYVqE13mmwhL6Ocy9dZDvYGpYro05MlzDUvA8nN5HPuGdXYDRJFMfmBAkMlO0zWd+AtPx3CydFcs2bI5gKmANCfA5fdUot+xWAndMjJB89W0lCgl9b5N9LMxGL//erRbn7PDANB7xNcBrcDaV857lvUJsf2x5P0CE0NOHgEMW7SXZe6rPQZ+9fB+KEhN2RAFG/iIxRlNa+5kM= diff --git a/MANIFEST.in b/MANIFEST.in index 819733a0..35b6025e 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -9,7 +9,6 @@ include .coveragerc include .editorconfig include .flake8 -include codecov.yml include mypy.ini include tox.ini @@ -18,7 +17,7 @@ include pyproject.toml graft src/graphql graft tests -recursive-include docs *.rst conf.py Makefile make.bat *.jpg *.png *.gif +recursive-include docs *.txt *.rst conf.py Makefile make.bat *.jpg *.png *.gif prune docs/_build global-exclude *.py[co] __pycache__ diff --git a/README.md b/README.md index 8866930f..5c0ff64f 100644 --- a/README.md +++ b/README.md @@ -5,24 +5,22 @@ the JavaScript reference implementation for [GraphQL](https://graphql.org/), a query language for APIs created by Facebook. [![PyPI version](https://badge.fury.io/py/graphql-core.svg)](https://badge.fury.io/py/graphql-core) -[![Documentation Status](https://readthedocs.org/projects/graphql-core-next/badge/)](https://graphql-core-next.readthedocs.io) -[![Build Status](https://travis-ci.com/graphql-python/graphql-core-next.svg?branch=master)](https://travis-ci.com/graphql-python/graphql-core-next) -[![Coverage Status](https://codecov.io/gh/graphql-python/graphql-core-next/branch/master/graph/badge.svg)](https://codecov.io/gh/graphql-python/graphql-core-next) -[![Dependency Updates](https://pyup.io/repos/github/graphql-python/graphql-core-next/shield.svg)](https://pyup.io/repos/github/graphql-python/graphql-core-next/) -[![Python 3 Status](https://pyup.io/repos/github/graphql-python/graphql-core-next/python-3-shield.svg)](https://pyup.io/repos/github/graphql-python/graphql-core-next/) +[![Documentation Status](https://readthedocs.org/projects/graphql-core-3/badge/)](https://graphql-core-3.readthedocs.io) +[![Build Status](https://travis-ci.com/graphql-python/graphql-core.svg?branch=master)](https://travis-ci.com/graphql-python/graphql-core) +[![Coverage Status](https://codecov.io/gh/graphql-python/graphql-core/branch/master/graph/badge.svg)](https://codecov.io/gh/graphql-python/graphql-core) +[![Dependency Updates](https://pyup.io/repos/github/graphql-python/graphql-core/shield.svg)](https://pyup.io/repos/github/graphql-python/graphql-core/) +[![Python 3 Status](https://pyup.io/repos/github/graphql-python/graphql-core/python-3-shield.svg)](https://pyup.io/repos/github/graphql-python/graphql-core/) [![Code Style](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/ambv/black) -The current version 3.0.0 of GraphQL-core is up-to-date -with GraphQL.js version 14.5.8. +The current version 3.0.6 of GraphQL-core is up-to-date with GraphQL.js version 14.7.0. -All parts of the API are covered by an extensive test suite -of currently 1990 unit tests. +All parts of the API are covered by an extensive test suite of nearly 2000 unit tests. ## Documentation A more detailed documentation for GraphQL-core 3 can be found at -[graphql-core-next.readthedocs.io](https://graphql-core-next.readthedocs.io/). +[graphql-core-3.readthedocs.io](https://graphql-core-3.readthedocs.io/). The documentation for GraphQL.js can be found at [graphql.org/graphql-js/](https://graphql.org/graphql-js/). @@ -172,7 +170,7 @@ in Python as closely as possible and to stay up-to-date with the latest developm GraphQL.js. GraphQL-core 3 (formerly known as GraphQL-core-next) has been created as a modern -alternative to [GraphQL-core 2](https://github.com/graphql-python/graphql-core), +alternative to [GraphQL-core 2](https://github.com/graphql-python/graphql-core-legacy), a prior work by Syrus Akbary, based on an older version of GraphQL.js and also targeting older Python versions. Some parts of GraphQL-core 3 have been inspired by GraphQL-core 2 or directly taken over with only slight modifications, but most of the @@ -192,11 +190,10 @@ Design goals for the GraphQL-core 3 library are: Some restrictions (mostly in line with the design goals): -* requires Python 3.6 or 3.7 +* requires Python 3.6 or newer * does not support some already deprecated methods and options of GraphQL.js * supports asynchronous operations only via async.io (does not support the additional executors in GraphQL-core) -* the benchmarks have not yet been ported to Python ## Integration with other libraries and roadmap @@ -214,17 +211,17 @@ Some restrictions (mostly in line with the design goals): * [Ariadne](https://github.com/mirumee/ariadne) is a Python library for implementing GraphQL servers using schema-first approach created by Mirumee Software. - Ariadne is already using GraphQL-core-next as its GraphQL implementation. + Ariadne is already using GraphQL-core 3 as its GraphQL implementation. * [Strawberry](https://github.com/strawberry-graphql/strawberry), created by Patrick Arminio, is a new GraphQL library for Python 3, inspired by dataclasses, - that is also using GraphQL-core-next as underpinning. + that is also using GraphQL-core 3 as underpinning. ## Changelog Changes are tracked as -[GitHub releases](https://github.com/graphql-python/graphql-core-next/releases). +[GitHub releases](https://github.com/graphql-python/graphql-core/releases). ## Credits and history @@ -246,5 +243,5 @@ and ported to many different programming languages. ## License GraphQL-core 3 is -[MIT-licensed](https://github.com/graphql-python/graphql-core-next/blob/master/LICENSE), +[MIT-licensed](https://github.com/graphql-python/graphql-core/blob/master/LICENSE), just like GraphQL.js. diff --git a/codecov.yml b/codecov.yml deleted file mode 100644 index c393a12b..00000000 --- a/codecov.yml +++ /dev/null @@ -1,10 +0,0 @@ -codecov: - notify: - require_ci_to_pass: yes - -comment: no -coverage: - status: - project: - default: - target: auto \ No newline at end of file diff --git a/docs/Makefile b/docs/Makefile index 8d77678a..d4bb2cbb 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -1,225 +1,20 @@ -# Makefile for Sphinx documentation +# Minimal makefile for Sphinx documentation # -# You can set these variables from the command line. -SPHINXOPTS = -SPHINXBUILD = sphinx-build -PAPER = +# You can set these variables from the command line, and also +# from the environment for the first two. +SPHINXOPTS ?= +SPHINXBUILD ?= sphinx-build +SOURCEDIR = . BUILDDIR = _build -# 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 +# Put it first so that "make" without argument is like "make 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 " applehelp to make an Apple Help Book" - @echo " devhelp to make HTML files and a Devhelp project" - @echo " epub to make an epub" - @echo " epub3 to make an epub3" - @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)" - @echo " dummy to check syntax errors of document sources" - -.PHONY: clean -clean: - rm -rf $(BUILDDIR)/* - -.PHONY: html -html: - $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html - @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." - -.PHONY: dirhtml -dirhtml: - $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml - @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." - -.PHONY: singlehtml -singlehtml: - $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml - @echo - @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." - -.PHONY: pickle -pickle: - $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle - @echo - @echo "Build finished; now you can process the pickle files." - -.PHONY: json -json: - $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json - @echo - @echo "Build finished; now you can process the JSON files." - -.PHONY: htmlhelp -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." - -.PHONY: qthelp -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-core.qhcp" - @echo "To view the help file:" - @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/GraphQL-core.qhc" - -.PHONY: applehelp -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." - -.PHONY: devhelp -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-core" - @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/GraphQL-core" - @echo "# devhelp" - -.PHONY: epub -epub: - $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub - @echo - @echo "Build finished. The epub file is in $(BUILDDIR)/epub." - -.PHONY: epub3 -epub3: - $(SPHINXBUILD) -b epub3 $(ALLSPHINXOPTS) $(BUILDDIR)/epub3 - @echo - @echo "Build finished. The epub3 file is in $(BUILDDIR)/epub3." - -.PHONY: latex -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)." - -.PHONY: latexpdf -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." - -.PHONY: latexpdfja -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." - -.PHONY: text -text: - $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text - @echo - @echo "Build finished. The text files are in $(BUILDDIR)/text." - -.PHONY: man -man: - $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man - @echo - @echo "Build finished. The manual pages are in $(BUILDDIR)/man." - -.PHONY: texinfo -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)." - -.PHONY: info -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." - -.PHONY: gettext -gettext: - $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale - @echo - @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." - -.PHONY: changes -changes: - $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes - @echo - @echo "The overview file is in $(BUILDDIR)/changes." - -.PHONY: linkcheck -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." - -.PHONY: doctest -doctest: - $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest - @echo "Testing of doctests in the sources finished, look at the " \ - "results in $(BUILDDIR)/doctest/output.txt." - -.PHONY: coverage -coverage: - $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage - @echo "Testing of coverage in the sources finished, look at the " \ - "results in $(BUILDDIR)/coverage/python.txt." - -.PHONY: xml -xml: - $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml - @echo - @echo "Build finished. The XML files are in $(BUILDDIR)/xml." + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) -.PHONY: pseudoxml -pseudoxml: - $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml - @echo - @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." +.PHONY: help Makefile -.PHONY: dummy -dummy: - $(SPHINXBUILD) -b dummy $(ALLSPHINXOPTS) $(BUILDDIR)/dummy - @echo - @echo "Build finished. Dummy builder generates no files." +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/conf.py b/docs/conf.py index 94876c08..a16b9375 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -50,18 +50,18 @@ master_doc = 'index' # General information about the project. -project = u'GraphQL-core 3' -copyright = u'2019, Christoph Zwerschke' -author = u'Christoph Zwerschke' +project = 'GraphQL-core 3' +copyright = '2021, Christoph Zwerschke' +author = 'Christoph Zwerschke' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. -# version = u'3.0' +# version = '3.0' # The full version, including alpha/beta/rc tags. -version = release = u'3.0.0' +version = release = '3.0.6' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. @@ -102,7 +102,8 @@ nitpick_ignore = [('py:class', t) for t in ( 'dict', 'list', 'object', 'tuple', 'Exception', 'TypeError', 'ValueError', - 'builtins.str', 'enum.Enum', 'typing.Generic', + 'builtins.str', 'enum.Enum', + 'typing.Callable', 'typing.Dict', 'typing.Generic', 'typing.List', 'graphql.pyutils.cached_property.CachedProperty', 'graphql.pyutils.path.Path', 'graphql.error.graphql_error.GraphQLError', @@ -121,6 +122,7 @@ 'graphql.type.definition.GraphQLType', 'graphql.type.definition.GraphQLWrappingType', 'graphql.validation.rules.ASTValidationRule', + 'graphql.validation.rules.SDLValidationRule', 'graphql.validation.rules.ValidationRule', 'graphql.validation.validation_context.ASTValidationContext', 'graphql.validation.rules.known_argument_names' @@ -178,7 +180,7 @@ # The name for this set of Sphinx documents. # " v documentation" by default. # -# html_title = u'GraphQL-core v3.0.0' +# html_title = 'GraphQL-core v3.0.0' # A shorter title for the navigation bar. Default is the same as html_title. # @@ -304,8 +306,8 @@ # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ - (master_doc, 'GraphQL-core-3.tex', u'GraphQL-core 3 Documentation', - u'Christoph Zwerschke', 'manual'), + (master_doc, 'GraphQL-core-3.tex', 'GraphQL-core 3 Documentation', + 'Christoph Zwerschke', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of @@ -340,7 +342,7 @@ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ - (master_doc, 'graphql-core', u'GraphQL-core 3 Documentation', + (master_doc, 'graphql-core', 'GraphQL-core 3 Documentation', [author], 1) ] @@ -355,7 +357,7 @@ # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ - (master_doc, 'GraphQL-core', u'GraphQL-core 3 Documentation', + (master_doc, 'GraphQL-core', 'GraphQL-core 3 Documentation', author, 'GraphQL-core 3', 'One line description of project.', 'Miscellaneous'), ] diff --git a/docs/intro.rst b/docs/intro.rst index 0a8058fc..3bd83837 100644 --- a/docs/intro.rst +++ b/docs/intro.rst @@ -84,8 +84,8 @@ in the current development or want to report issues or send pull requests. .. _GraphQL: https://graphql.org/ .. _GraphQL.js: https://github.com/graphql/graphql-js -.. _GraphQL-core-3: https://github.com/graphql-python/graphql-core-next -.. _GitHub repository of GraphQL-core 3: https://github.com/graphql-python/graphql-core-next +.. _GraphQL-core-3: https://github.com/graphql-python/graphql-core +.. _GitHub repository of GraphQL-core 3: https://github.com/graphql-python/graphql-core .. _Specification for GraphQL: https://facebook.github.io/graphql/ .. _Language: https://facebook.github.io/graphql/draft/#sec-Language .. _Type System: https://facebook.github.io/graphql/draft/#sec-Type-System diff --git a/docs/make.bat b/docs/make.bat index 7e316813..922152e9 100644 --- a/docs/make.bat +++ b/docs/make.bat @@ -1,64 +1,18 @@ @ECHO OFF +pushd %~dp0 + REM Command file for Sphinx documentation if "%SPHINXBUILD%" == "" ( set SPHINXBUILD=sphinx-build ) +set SOURCEDIR=. 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. epub3 to make an epub3 - 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 - echo. dummy to check syntax errors of document sources - 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% 1>NUL 2>NUL -if errorlevel 9009 goto sphinx_python -goto sphinx_ok - -:sphinx_python - -set SPHINXBUILD=python -m sphinx.__init__ -%SPHINXBUILD% 2> nul +%SPHINXBUILD% >NUL 2>NUL if errorlevel 9009 ( echo. echo.The 'sphinx-build' command was not found. Make sure you have Sphinx @@ -67,215 +21,15 @@ if errorlevel 9009 ( echo.may add the Sphinx directory to PATH. echo. echo.If you don't have Sphinx installed, grab it from - echo.https://www.sphinx-doc.org/ + echo.http://sphinx-doc.org/ exit /b 1 ) -:sphinx_ok +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% +goto end - -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-core.qhcp - echo.To view the help file: - echo.^> assistant -collectionFile %BUILDDIR%\qthelp\GraphQL-core.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" == "epub3" ( - %SPHINXBUILD% -b epub3 %ALLSPHINXOPTS% %BUILDDIR%/epub3 - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The epub3 file is in %BUILDDIR%/epub3. - 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 -) - -if "%1" == "dummy" ( - %SPHINXBUILD% -b dummy %ALLSPHINXOPTS% %BUILDDIR%/dummy - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. Dummy builder generates no files. - goto end -) +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% :end +popd diff --git a/docs/modules/error.rst b/docs/modules/error.rst index 3a0a58bd..e0e73bb8 100644 --- a/docs/modules/error.rst +++ b/docs/modules/error.rst @@ -7,6 +7,7 @@ Error .. autoexception:: GraphQLError :members: + :no-inherited-members: .. autoexception:: GraphQLSyntaxError diff --git a/docs/modules/validation.rst b/docs/modules/validation.rst index ba2b249c..7dbb8367 100644 --- a/docs/modules/validation.rst +++ b/docs/modules/validation.rst @@ -133,3 +133,13 @@ Spec Section: "Variables are Input Types" Spec Section: "All Variable Usages Are Allowed" .. autoclass:: VariablesInAllowedPositionRule + +SDL-specific validation rules + +.. autoclass:: LoneSchemaDefinitionRule +.. autoclass:: UniqueOperationTypesRule +.. autoclass:: UniqueTypeNamesRule +.. autoclass:: UniqueEnumValueNamesRule +.. autoclass:: UniqueFieldDefinitionNamesRule +.. autoclass:: UniqueDirectiveNamesRule +.. autoclass:: PossibleTypeExtensionsRule diff --git a/docs/usage/other.rst b/docs/usage/other.rst index 60c99386..fc58b3c5 100644 --- a/docs/usage/other.rst +++ b/docs/usage/other.rst @@ -22,4 +22,4 @@ GraphQL schemas and queries. We encourage you to explore the contents of the var code and tests of `GraphQL-core 3`_ in order to find all the functionality that is provided and understand it in detail. -.. _GraphQL-core 3: https://github.com/graphql-python/graphql-core-next +.. _GraphQL-core 3: https://github.com/graphql-python/graphql-core diff --git a/docs/usage/queries.rst b/docs/usage/queries.rst index 1f6d88f3..503075dd 100644 --- a/docs/usage/queries.rst +++ b/docs/usage/queries.rst @@ -28,7 +28,7 @@ Here is one way to use it:: """) print(result) - asyncio.get_event_loop().run_until_complete(query_artoo()) + asyncio.run(query_artoo()) In our query, we asked for the droid with the id 2001, which is R2-D2, and its primary function, Astromech. When everything has been implemented correctly as shown above, you diff --git a/docs/usage/validator.rst b/docs/usage/validator.rst index 347428b6..b5a28e27 100644 --- a/docs/usage/validator.rst +++ b/docs/usage/validator.rst @@ -31,7 +31,7 @@ In this case, we will get:: " Did you mean 'homePlanet'?", locations=[SourceLocation(line=5, column=9)]), GraphQLError( - "Field 'friends' of type '[Character]' must have a sub selection of subfields." + "Field 'friends' of type '[Character]' must have a selection of subfields." " Did you mean 'friends { ... }'?", locations=[SourceLocation(line=6, column=9)])] diff --git a/poetry.lock b/poetry.lock index d454da05..5b97389e 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,104 +1,137 @@ [[package]] -category = "dev" -description = "A configurable sidebar-enabled Sphinx theme" name = "alabaster" +version = "0.7.12" +description = "A configurable sidebar-enabled Sphinx theme" +category = "dev" optional = false python-versions = "*" -version = "0.7.12" [[package]] -category = "dev" -description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." name = "appdirs" +version = "1.4.4" +description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +category = "dev" optional = false python-versions = "*" -version = "1.4.3" [[package]] -category = "dev" -description = "Atomic file writes." -marker = "sys_platform == \"win32\"" name = "atomicwrites" +version = "1.4.0" +description = "Atomic file writes." +category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "1.3.0" [[package]] -category = "dev" -description = "Classes Without Boilerplate" name = "attrs" +version = "21.3.0" +description = "Classes Without Boilerplate" +category = "dev" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "19.3.0" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [package.extras] -azure-pipelines = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "pytest-azurepipelines"] -dev = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "sphinx", "pre-commit"] -docs = ["sphinx", "zope.interface"] -tests = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface"] +dev = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "furo", "sphinx", "sphinx-notfound-page", "pre-commit"] +docs = ["furo", "sphinx", "zope.interface", "sphinx-notfound-page"] +tests = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface"] +tests_no_zope = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins"] [[package]] -category = "dev" -description = "Internationalization utilities" name = "babel" +version = "2.9.1" +description = "Internationalization utilities" +category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "2.7.0" [package.dependencies] pytz = ">=2015.7" [[package]] -category = "dev" -description = "The uncompromising code formatter." name = "black" +version = "20.8b1" +description = "The uncompromising code formatter." +category = "dev" optional = false python-versions = ">=3.6" -version = "19.10b0" [package.dependencies] appdirs = "*" -attrs = ">=18.1.0" -click = ">=6.5" +click = ">=7.1.2" +dataclasses = {version = ">=0.6", markers = "python_version < \"3.7\""} +mypy-extensions = ">=0.4.3" pathspec = ">=0.6,<1" -regex = "*" -toml = ">=0.9.4" +regex = ">=2020.1.8" +toml = ">=0.10.1" typed-ast = ">=1.4.0" +typing-extensions = ">=3.7.4" [package.extras] +colorama = ["colorama (>=0.4.3)"] d = ["aiohttp (>=3.3.2)", "aiohttp-cors"] [[package]] +name = "black" +version = "21.12b0" +description = "The uncompromising code formatter." category = "dev" -description = "Version-bump your software with a single command!" -name = "bump2version" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -version = "0.5.11" +python-versions = ">=3.6.2" + +[package.dependencies] +click = ">=7.1.2" +dataclasses = {version = ">=0.6", markers = "python_version < \"3.7\""} +mypy-extensions = ">=0.4.3" +pathspec = ">=0.9.0,<1" +platformdirs = ">=2" +tomli = ">=0.2.6,<2.0.0" +typed-ast = {version = ">=1.4.2", markers = "python_version < \"3.8\" and implementation_name == \"cpython\""} +typing-extensions = [ + {version = ">=3.10.0.0", markers = "python_version < \"3.10\""}, + {version = "!=3.10.0.1", markers = "python_version >= \"3.10\""}, +] + +[package.extras] +colorama = ["colorama (>=0.4.3)"] +d = ["aiohttp (>=3.7.4)"] +jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] +python2 = ["typed-ast (>=1.4.3)"] +uvloop = ["uvloop (>=0.15.2)"] [[package]] +name = "bump2version" +version = "1.0.1" +description = "Version-bump your software with a single command!" category = "dev" -description = "Python package for providing Mozilla's CA Bundle." -name = "certifi" optional = false -python-versions = "*" -version = "2019.11.28" +python-versions = ">=3.5" [[package]] +name = "certifi" +version = "2021.10.8" +description = "Python package for providing Mozilla's CA Bundle." category = "dev" -description = "Universal encoding detector for Python 2 and 3" -name = "chardet" optional = false python-versions = "*" -version = "3.0.4" [[package]] +name = "charset-normalizer" +version = "2.0.9" +description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." category = "dev" -description = "Check MANIFEST.in in a Python source package for completeness" +optional = false +python-versions = ">=3.5.0" + +[package.extras] +unicode_backport = ["unicodedata2"] + +[[package]] name = "check-manifest" +version = "0.40" +description = "Check MANIFEST.in in a Python source package for completeness" +category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -version = "0.40" [package.dependencies] toml = "*" @@ -107,304 +140,352 @@ toml = "*" test = ["mock"] [[package]] -category = "dev" -description = "Composable command line interface toolkit" name = "click" +version = "8.0.3" +description = "Composable command line interface toolkit" +category = "dev" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "7.0" +python-versions = ">=3.6" + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} +importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} [[package]] -category = "dev" -description = "Hosted coverage reports for Github, Bitbucket and Gitlab" name = "codecov" +version = "2.1.12" +description = "Hosted coverage reports for GitHub, Bitbucket and Gitlab" +category = "dev" optional = false -python-versions = "*" -version = "2.0.15" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [package.dependencies] coverage = "*" requests = ">=2.7.9" [[package]] -category = "dev" -description = "Cross-platform colored terminal text." -marker = "sys_platform == \"win32\"" name = "colorama" +version = "0.4.4" +description = "Cross-platform colored terminal text." +category = "dev" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "0.4.1" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [[package]] -category = "dev" -description = "Code coverage measurement for Python" name = "coverage" +version = "6.2" +description = "Code coverage measurement for Python" +category = "dev" optional = false -python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*, <4" -version = "4.5.4" +python-versions = ">=3.6" + +[package.dependencies] +tomli = {version = "*", optional = true, markers = "extra == \"toml\""} + +[package.extras] +toml = ["tomli"] [[package]] +name = "dataclasses" +version = "0.8" +description = "A backport of the dataclasses module for Python 3.6" category = "dev" -description = "Docutils -- Python Documentation Utilities" -name = "docutils" optional = false -python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" -version = "0.15.2" +python-versions = ">=3.6, <3.7" [[package]] +name = "distlib" +version = "0.3.4" +description = "Distribution utilities" category = "dev" -description = "Discover and load entry points from installed packages." -name = "entrypoints" optional = false -python-versions = ">=2.7" -version = "0.3" +python-versions = "*" [[package]] +name = "docutils" +version = "0.16" +description = "Docutils -- Python Documentation Utilities" category = "dev" -description = "A platform independent file lock." -name = "filelock" optional = false -python-versions = "*" -version = "3.0.12" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [[package]] +name = "filelock" +version = "3.4.1" +description = "A platform independent file lock." category = "dev" -description = "the modular source code checker: pep8, pyflakes and co" +optional = false +python-versions = ">=3.6" + +[package.extras] +docs = ["furo (>=2021.8.17b43)", "sphinx (>=4.1)", "sphinx-autodoc-typehints (>=1.12)"] +testing = ["covdefaults (>=1.2.0)", "coverage (>=4)", "pytest (>=4)", "pytest-cov", "pytest-timeout (>=1.4.2)"] + +[[package]] name = "flake8" +version = "4.0.1" +description = "the modular source code checker: pep8 pyflakes and co" +category = "dev" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "3.7.9" +python-versions = ">=3.6" [package.dependencies] -entrypoints = ">=0.3.0,<0.4.0" +importlib-metadata = {version = "<4.3", markers = "python_version < \"3.8\""} mccabe = ">=0.6.0,<0.7.0" -pycodestyle = ">=2.5.0,<2.6.0" -pyflakes = ">=2.1.0,<2.2.0" +pycodestyle = ">=2.8.0,<2.9.0" +pyflakes = ">=2.4.0,<2.5.0" [[package]] -category = "dev" -description = "Internationalized Domain Names in Applications (IDNA)" name = "idna" +version = "3.3" +description = "Internationalized Domain Names in Applications (IDNA)" +category = "dev" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "2.8" +python-versions = ">=3.5" [[package]] -category = "dev" -description = "Getting image size from png/jpeg/jpeg2000/gif file" name = "imagesize" +version = "1.3.0" +description = "Getting image size from png/jpeg/jpeg2000/gif file" +category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "1.1.0" [[package]] -category = "dev" -description = "Read metadata from Python packages" -marker = "python_version < \"3.8\"" name = "importlib-metadata" +version = "4.2.0" +description = "Read metadata from Python packages" +category = "dev" optional = false -python-versions = ">=2.7,!=3.0,!=3.1,!=3.2,!=3.3" -version = "0.23" +python-versions = ">=3.6" [package.dependencies] +typing-extensions = {version = ">=3.6.4", markers = "python_version < \"3.8\""} zipp = ">=0.5" [package.extras] -docs = ["sphinx", "rst.linker"] -testing = ["packaging", "importlib-resources"] +docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] +testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "packaging", "pep517", "pyfakefs", "flufl.flake8", "pytest-black (>=0.3.7)", "pytest-mypy", "importlib-resources (>=1.3)"] [[package]] +name = "importlib-resources" +version = "5.4.0" +description = "Read resources from Python packages" category = "dev" -description = "A very fast and expressive template engine." -name = "jinja2" optional = false -python-versions = "*" -version = "2.10.3" +python-versions = ">=3.6" [package.dependencies] -MarkupSafe = ">=0.23" +zipp = {version = ">=3.1.0", markers = "python_version < \"3.10\""} [package.extras] -i18n = ["Babel (>=0.8)"] +docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] +testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "pytest-black (>=0.3.7)", "pytest-mypy"] [[package]] +name = "iniconfig" +version = "1.1.1" +description = "iniconfig: brain-dead simple config-ini parsing" category = "dev" -description = "Safely add untrusted strings to HTML/XML markup." -name = "markupsafe" optional = false -python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*" -version = "1.1.1" +python-versions = "*" [[package]] +name = "jinja2" +version = "3.0.3" +description = "A very fast and expressive template engine." category = "dev" -description = "McCabe checker, plugin for flake8" -name = "mccabe" optional = false -python-versions = "*" -version = "0.6.1" +python-versions = ">=3.6" + +[package.dependencies] +MarkupSafe = ">=2.0" + +[package.extras] +i18n = ["Babel (>=2.7)"] [[package]] +name = "markupsafe" +version = "2.0.1" +description = "Safely add untrusted strings to HTML/XML markup." category = "dev" -description = "More routines for operating on iterables, beyond itertools" -name = "more-itertools" optional = false -python-versions = ">=3.5" -version = "8.0.0" +python-versions = ">=3.6" [[package]] +name = "mccabe" +version = "0.6.1" +description = "McCabe checker, plugin for flake8" category = "dev" -description = "Optional static typing for Python" +optional = false +python-versions = "*" + +[[package]] name = "mypy" +version = "0.930" +description = "Optional static typing for Python" +category = "dev" optional = false -python-versions = ">=3.5" -version = "0.750" +python-versions = ">=3.6" [package.dependencies] -mypy-extensions = ">=0.4.0,<0.5.0" -typed-ast = ">=1.4.0,<1.5.0" -typing-extensions = ">=3.7.4" +mypy-extensions = ">=0.4.3" +tomli = ">=1.1.0" +typed-ast = {version = ">=1.4.0,<2", markers = "python_version < \"3.8\""} +typing-extensions = ">=3.10" [package.extras] dmypy = ["psutil (>=4.0)"] +python2 = ["typed-ast (>=1.4.0,<2)"] [[package]] -category = "dev" -description = "Experimental type system extensions for programs checked with the mypy typechecker." name = "mypy-extensions" +version = "0.4.3" +description = "Experimental type system extensions for programs checked with the mypy typechecker." +category = "dev" optional = false python-versions = "*" -version = "0.4.3" [[package]] -category = "dev" -description = "Core utilities for Python packages" name = "packaging" +version = "21.3" +description = "Core utilities for Python packages" +category = "dev" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "19.2" +python-versions = ">=3.6" [package.dependencies] -pyparsing = ">=2.0.2" -six = "*" +pyparsing = ">=2.0.2,<3.0.5 || >3.0.5" [[package]] -category = "dev" -description = "Utility library for gitignore style pattern matching of file paths." name = "pathspec" +version = "0.9.0" +description = "Utility library for gitignore style pattern matching of file paths." +category = "dev" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "0.6.0" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" [[package]] +name = "platformdirs" +version = "2.4.0" +description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." category = "dev" -description = "plugin and hook calling mechanisms for python" +optional = false +python-versions = ">=3.6" + +[package.extras] +docs = ["Sphinx (>=4)", "furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx-autodoc-typehints (>=1.12)"] +test = ["appdirs (==1.4.4)", "pytest (>=6)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)"] + +[[package]] name = "pluggy" +version = "1.0.0" +description = "plugin and hook calling mechanisms for python" +category = "dev" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "0.13.1" +python-versions = ">=3.6" [package.dependencies] -[package.dependencies.importlib-metadata] -python = "<3.8" -version = ">=0.12" +importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} [package.extras] dev = ["pre-commit", "tox"] +testing = ["pytest", "pytest-benchmark"] [[package]] -category = "dev" -description = "library with cross-python path, ini-parsing, io, code, log facilities" name = "py" +version = "1.11.0" +description = "library with cross-python path, ini-parsing, io, code, log facilities" +category = "dev" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "1.8.0" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [[package]] -category = "dev" -description = "Get CPU info with pure Python 2 & 3" name = "py-cpuinfo" +version = "8.0.0" +description = "Get CPU info with pure Python 2 & 3" +category = "dev" optional = false python-versions = "*" -version = "5.0.0" [[package]] -category = "dev" -description = "Python style guide checker" name = "pycodestyle" +version = "2.8.0" +description = "Python style guide checker" +category = "dev" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "2.5.0" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [[package]] -category = "dev" -description = "passive checker of Python programs" name = "pyflakes" +version = "2.4.0" +description = "passive checker of Python programs" +category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "2.1.1" [[package]] -category = "dev" -description = "Pygments is a syntax highlighting package written in Python." name = "pygments" +version = "2.10.0" +description = "Pygments is a syntax highlighting package written in Python." +category = "dev" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -version = "2.5.2" +python-versions = ">=3.5" [[package]] -category = "dev" -description = "Python parsing module" name = "pyparsing" +version = "3.0.6" +description = "Python parsing module" +category = "dev" optional = false -python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" -version = "2.4.5" +python-versions = ">=3.6" + +[package.extras] +diagrams = ["jinja2", "railroad-diagrams"] [[package]] -category = "dev" -description = "pytest: simple powerful testing with Python" name = "pytest" +version = "6.2.5" +description = "pytest: simple powerful testing with Python" +category = "dev" optional = false -python-versions = ">=3.5" -version = "5.3.1" +python-versions = ">=3.6" [package.dependencies] -atomicwrites = ">=1.0" -attrs = ">=17.4.0" -colorama = "*" -more-itertools = ">=4.0.0" +atomicwrites = {version = ">=1.0", markers = "sys_platform == \"win32\""} +attrs = ">=19.2.0" +colorama = {version = "*", markers = "sys_platform == \"win32\""} +importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} +iniconfig = "*" packaging = "*" -pluggy = ">=0.12,<1.0" -py = ">=1.5.0" -wcwidth = "*" - -[package.dependencies.importlib-metadata] -python = "<3.8" -version = ">=0.12" +pluggy = ">=0.12,<2.0" +py = ">=1.8.2" +toml = "*" [package.extras] testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"] [[package]] -category = "dev" -description = "Pytest support for asyncio." name = "pytest-asyncio" +version = "0.16.0" +description = "Pytest support for asyncio." +category = "dev" optional = false -python-versions = ">= 3.5" -version = "0.10.0" +python-versions = ">= 3.6" [package.dependencies] -pytest = ">=3.0.6" +pytest = ">=5.4.0" [package.extras] -testing = ["async-generator (>=1.3)", "coverage", "hypothesis (>=3.64)"] +testing = ["coverage", "hypothesis (>=5.7.1)"] [[package]] -category = "dev" -description = "A ``py.test`` fixture for benchmarking code. It will group the tests into rounds that are calibrated to the chosen timer. See calibration_ and FAQ_." name = "pytest-benchmark" +version = "3.4.1" +description = "A ``pytest`` fixture for benchmarking code. It will group the tests into rounds that are calibrated to the chosen timer." +category = "dev" optional = false -python-versions = "*" -version = "3.2.2" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [package.dependencies] py-cpuinfo = "*" @@ -416,108 +497,99 @@ elasticsearch = ["elasticsearch"] histogram = ["pygal", "pygaljs"] [[package]] -category = "dev" -description = "Pytest plugin for measuring coverage." name = "pytest-cov" +version = "3.0.0" +description = "Pytest plugin for measuring coverage." +category = "dev" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "2.8.1" +python-versions = ">=3.6" [package.dependencies] -coverage = ">=4.4" -pytest = ">=3.6" +coverage = {version = ">=5.2.1", extras = ["toml"]} +pytest = ">=4.6" [package.extras] -testing = ["fields", "hunter", "process-tests (2.0.2)", "six", "virtualenv"] +testing = ["fields", "hunter", "process-tests", "six", "pytest-xdist", "virtualenv"] [[package]] -category = "dev" -description = "Describe-style plugin for pytest" name = "pytest-describe" +version = "2.0.1" +description = "Describe-style plugin for pytest" +category = "dev" optional = false python-versions = "*" -version = "0.12.0" [package.dependencies] -pytest = ">=2.6.0" +pytest = ">=4.0.0" [[package]] -category = "dev" -description = "World timezone definitions, modern and historical" name = "pytz" -optional = false -python-versions = "*" -version = "2019.3" - -[[package]] +version = "2021.3" +description = "World timezone definitions, modern and historical" category = "dev" -description = "YAML parser and emitter for Python" -name = "pyyaml" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "5.1.2" +python-versions = "*" [[package]] -category = "dev" -description = "Alternative regular expression module, to replace re." name = "regex" +version = "2021.11.10" +description = "Alternative regular expression module, to replace re." +category = "dev" optional = false python-versions = "*" -version = "2019.11.1" [[package]] -category = "dev" -description = "Python HTTP for Humans." name = "requests" +version = "2.26.0" +description = "Python HTTP for Humans." +category = "dev" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -version = "2.22.0" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" [package.dependencies] certifi = ">=2017.4.17" -chardet = ">=3.0.2,<3.1.0" -idna = ">=2.5,<2.9" -urllib3 = ">=1.21.1,<1.25.0 || >1.25.0,<1.25.1 || >1.25.1,<1.26" +charset-normalizer = {version = ">=2.0.0,<2.1.0", markers = "python_version >= \"3\""} +idna = {version = ">=2.5,<4", markers = "python_version >= \"3\""} +urllib3 = ">=1.21.1,<1.27" [package.extras] -security = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)"] -socks = ["PySocks (>=1.5.6,<1.5.7 || >1.5.7)", "win-inet-pton"] +socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton"] +use_chardet_on_py3 = ["chardet (>=3.0.2,<5)"] [[package]] -category = "dev" -description = "Python 2 and 3 compatibility utilities" name = "six" +version = "1.16.0" +description = "Python 2 and 3 compatibility utilities" +category = "dev" optional = false -python-versions = ">=2.6, !=3.0.*, !=3.1.*" -version = "1.13.0" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" [[package]] -category = "dev" -description = "This package provides 26 stemmers for 25 languages generated from Snowball algorithms." name = "snowballstemmer" +version = "2.2.0" +description = "This package provides 29 stemmers for 28 languages generated from Snowball algorithms." +category = "dev" optional = false python-versions = "*" -version = "2.0.0" [[package]] -category = "dev" -description = "Python documentation generator" name = "sphinx" +version = "2.4.5" +description = "Python documentation generator" +category = "dev" optional = false python-versions = ">=3.5" -version = "2.2.1" [package.dependencies] -Jinja2 = ">=2.3" -Pygments = ">=2.0" alabaster = ">=0.7,<0.8" babel = ">=1.3,<2.0 || >2.0" -colorama = ">=0.3.5" -docutils = ">=0.12" +colorama = {version = ">=0.3.5", markers = "sys_platform == \"win32\""} +docutils = ">=0.12,<0.18" imagesize = "*" +Jinja2 = ">=2.3" packaging = "*" +Pygments = ">=2.0" requests = ">=2.5.0" -setuptools = "*" snowballstemmer = ">=1.1" sphinxcontrib-applehelp = "*" sphinxcontrib-devhelp = "*" @@ -528,186 +600,198 @@ sphinxcontrib-serializinghtml = "*" [package.extras] docs = ["sphinxcontrib-websupport"] -test = ["pytest", "pytest-cov", "html5lib", "flake8 (>=3.5.0)", "flake8-import-order", "mypy (>=0.740)", "docutils-stubs"] +test = ["pytest (<5.3.3)", "pytest-cov", "html5lib", "flake8 (>=3.5.0)", "flake8-import-order", "mypy (>=0.761)", "docutils-stubs"] [[package]] -category = "dev" -description = "Read the Docs theme for Sphinx" name = "sphinx-rtd-theme" +version = "0.5.2" +description = "Read the Docs theme for Sphinx" +category = "dev" optional = false python-versions = "*" -version = "0.4.3" [package.dependencies] +docutils = "<0.17" sphinx = "*" +[package.extras] +dev = ["transifex-client", "sphinxcontrib-httpdomain", "bump2version"] + [[package]] -category = "dev" -description = "" name = "sphinxcontrib-applehelp" +version = "1.0.2" +description = "sphinxcontrib-applehelp is a sphinx extension which outputs Apple help books" +category = "dev" optional = false -python-versions = "*" -version = "1.0.1" +python-versions = ">=3.5" [package.extras] -test = ["pytest", "flake8", "mypy"] +lint = ["flake8", "mypy", "docutils-stubs"] +test = ["pytest"] [[package]] -category = "dev" -description = "" name = "sphinxcontrib-devhelp" +version = "1.0.2" +description = "sphinxcontrib-devhelp is a sphinx extension which outputs Devhelp document." +category = "dev" optional = false -python-versions = "*" -version = "1.0.1" +python-versions = ">=3.5" [package.extras] -test = ["pytest", "flake8", "mypy"] +lint = ["flake8", "mypy", "docutils-stubs"] +test = ["pytest"] [[package]] -category = "dev" -description = "" name = "sphinxcontrib-htmlhelp" +version = "2.0.0" +description = "sphinxcontrib-htmlhelp is a sphinx extension which renders HTML help files" +category = "dev" optional = false -python-versions = "*" -version = "1.0.2" +python-versions = ">=3.6" [package.extras] -test = ["pytest", "flake8", "mypy", "html5lib"] +lint = ["flake8", "mypy", "docutils-stubs"] +test = ["pytest", "html5lib"] [[package]] -category = "dev" -description = "A sphinx extension which renders display math in HTML via JavaScript" name = "sphinxcontrib-jsmath" +version = "1.0.1" +description = "A sphinx extension which renders display math in HTML via JavaScript" +category = "dev" optional = false python-versions = ">=3.5" -version = "1.0.1" [package.extras] test = ["pytest", "flake8", "mypy"] [[package]] -category = "dev" -description = "" name = "sphinxcontrib-qthelp" +version = "1.0.3" +description = "sphinxcontrib-qthelp is a sphinx extension which outputs QtHelp document." +category = "dev" optional = false -python-versions = "*" -version = "1.0.2" +python-versions = ">=3.5" [package.extras] -test = ["pytest", "flake8", "mypy"] +lint = ["flake8", "mypy", "docutils-stubs"] +test = ["pytest"] [[package]] -category = "dev" -description = "" name = "sphinxcontrib-serializinghtml" +version = "1.1.5" +description = "sphinxcontrib-serializinghtml is a sphinx extension which outputs \"serialized\" HTML files (json and pickle)." +category = "dev" optional = false -python-versions = "*" -version = "1.1.3" +python-versions = ">=3.5" [package.extras] -test = ["pytest", "flake8", "mypy"] +lint = ["flake8", "mypy", "docutils-stubs"] +test = ["pytest"] [[package]] -category = "dev" -description = "Python Library for Tom's Obvious, Minimal Language" name = "toml" +version = "0.10.2" +description = "Python Library for Tom's Obvious, Minimal Language" +category = "dev" optional = false -python-versions = "*" -version = "0.10.0" +python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" [[package]] +name = "tomli" +version = "1.2.3" +description = "A lil' TOML parser" category = "dev" -description = "tox is a generic virtualenv management and test command line tool" +optional = false +python-versions = ">=3.6" + +[[package]] name = "tox" +version = "3.24.5" +description = "tox is a generic virtualenv management and test command line tool" +category = "dev" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" -version = "3.14.1" [package.dependencies] -filelock = ">=3.0.0,<4" +colorama = {version = ">=0.4.1", markers = "platform_system == \"Windows\""} +filelock = ">=3.0.0" +importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} packaging = ">=14" -pluggy = ">=0.12.0,<1" -py = ">=1.4.17,<2" -six = ">=1.0.0,<2" +pluggy = ">=0.12.0" +py = ">=1.4.17" +six = ">=1.14.0" toml = ">=0.9.4" -virtualenv = ">=16.0.0" - -[package.dependencies.importlib-metadata] -python = "<3.8" -version = ">=0.12,<1" +virtualenv = ">=16.0.0,<20.0.0 || >20.0.0,<20.0.1 || >20.0.1,<20.0.2 || >20.0.2,<20.0.3 || >20.0.3,<20.0.4 || >20.0.4,<20.0.5 || >20.0.5,<20.0.6 || >20.0.6,<20.0.7 || >20.0.7" [package.extras] -docs = ["sphinx (>=2.0.0,<3)", "towncrier (>=18.5.0)", "pygments-github-lexers (>=0.0.5)", "sphinxcontrib-autoprogram (>=0.1.5)"] -testing = ["freezegun (>=0.3.11,<1)", "pathlib2 (>=2.3.3,<3)", "pytest (>=4.0.0,<6)", "pytest-cov (>=2.5.1,<3)", "pytest-mock (>=1.10.0,<2)", "pytest-xdist (>=1.22.2,<2)", "pytest-randomly (>=1.0.0,<4)", "flaky (>=3.4.0,<4)", "psutil (>=5.6.1,<6)"] +docs = ["pygments-github-lexers (>=0.0.5)", "sphinx (>=2.0.0)", "sphinxcontrib-autoprogram (>=0.1.5)", "towncrier (>=18.5.0)"] +testing = ["flaky (>=3.4.0)", "freezegun (>=0.3.11)", "pytest (>=4.0.0)", "pytest-cov (>=2.5.1)", "pytest-mock (>=1.10.0)", "pytest-randomly (>=1.0.0)", "psutil (>=5.6.1)", "pathlib2 (>=2.3.3)"] [[package]] -category = "dev" -description = "a fork of Python 2 and 3 ast modules with type comment support" name = "typed-ast" +version = "1.5.1" +description = "a fork of Python 2 and 3 ast modules with type comment support" +category = "dev" optional = false -python-versions = "*" -version = "1.4.0" +python-versions = ">=3.6" [[package]] -category = "dev" -description = "Backported and Experimental Type Hints for Python 3.5+" name = "typing-extensions" +version = "4.0.1" +description = "Backported and Experimental Type Hints for Python 3.6+" +category = "dev" optional = false -python-versions = "*" -version = "3.7.4.1" +python-versions = ">=3.6" [[package]] -category = "dev" -description = "HTTP library with thread-safe connection pooling, file post, and more." name = "urllib3" +version = "1.26.7" +description = "HTTP library with thread-safe connection pooling, file post, and more." +category = "dev" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, <4" -version = "1.25.7" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" [package.extras] brotli = ["brotlipy (>=0.6.0)"] secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"] -socks = ["PySocks (>=1.5.6,<1.5.7 || >1.5.7,<2.0)"] +socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] [[package]] -category = "dev" -description = "Virtual Python Environment builder" name = "virtualenv" +version = "20.11.2" +description = "Virtual Python Environment builder" +category = "dev" optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" -version = "16.7.8" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" -[package.extras] -docs = ["sphinx (>=1.8.0,<2)", "towncrier (>=18.5.0)", "sphinx-rtd-theme (>=0.4.2,<1)"] -testing = ["pytest (>=4.0.0,<5)", "coverage (>=4.5.0,<5)", "pytest-timeout (>=1.3.0,<2)", "six (>=1.10.0,<2)", "pytest-xdist", "pytest-localserver", "pypiserver", "mock", "xonsh"] +[package.dependencies] +distlib = ">=0.3.1,<1" +filelock = ">=3.2,<4" +importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} +importlib-resources = {version = ">=1.0", markers = "python_version < \"3.7\""} +platformdirs = ">=2,<3" +six = ">=1.9.0,<2" -[[package]] -category = "dev" -description = "Measures number of Terminal column cells of wide-character codes" -name = "wcwidth" -optional = false -python-versions = "*" -version = "0.1.7" +[package.extras] +docs = ["proselint (>=0.10.2)", "sphinx (>=3)", "sphinx-argparse (>=0.2.5)", "sphinx-rtd-theme (>=0.4.3)", "towncrier (>=21.3)"] +testing = ["coverage (>=4)", "coverage-enable-subprocess (>=1)", "flaky (>=3)", "pytest (>=4)", "pytest-env (>=0.6.2)", "pytest-freezegun (>=0.4.1)", "pytest-mock (>=2)", "pytest-randomly (>=1)", "pytest-timeout (>=1)", "packaging (>=20.0)"] [[package]] -category = "dev" -description = "Backport of pathlib-compatible object wrapper for zip files" -marker = "python_version < \"3.8\"" name = "zipp" +version = "3.6.0" +description = "Backport of pathlib-compatible object wrapper for zip files" +category = "dev" optional = false -python-versions = ">=2.7" -version = "0.6.0" - -[package.dependencies] -more-itertools = "*" +python-versions = ">=3.6" [package.extras] -docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"] -testing = ["pathlib2", "contextlib2", "unittest2"] +docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] +testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"] [metadata] -content-hash = "ac0977a16c085746b3ace9a34b024c40f8e044f5d1fa4d509c13c5e1c369784b" +lock-version = "1.1" python-versions = "^3.6" +content-hash = "c2389afcd078b045036109248d842643e90ad13e9930ced87c71b6c0dced239c" [metadata.files] alabaster = [ @@ -715,358 +799,418 @@ alabaster = [ {file = "alabaster-0.7.12.tar.gz", hash = "sha256:a661d72d58e6ea8a57f7a86e37d86716863ee5e92788398526d58b26a4e4dc02"}, ] appdirs = [ - {file = "appdirs-1.4.3-py2.py3-none-any.whl", hash = "sha256:d8b24664561d0d34ddfaec54636d502d7cea6e29c3eaf68f3df6180863e2166e"}, - {file = "appdirs-1.4.3.tar.gz", hash = "sha256:9e5896d1372858f8dd3344faf4e5014d21849c756c8d5701f78f8a103b372d92"}, + {file = "appdirs-1.4.4-py2.py3-none-any.whl", hash = "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128"}, + {file = "appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41"}, ] atomicwrites = [ - {file = "atomicwrites-1.3.0-py2.py3-none-any.whl", hash = "sha256:03472c30eb2c5d1ba9227e4c2ca66ab8287fbfbbda3888aa93dc2e28fc6811b4"}, - {file = "atomicwrites-1.3.0.tar.gz", hash = "sha256:75a9445bac02d8d058d5e1fe689654ba5a6556a1dfd8ce6ec55a0ed79866cfa6"}, + {file = "atomicwrites-1.4.0-py2.py3-none-any.whl", hash = "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"}, + {file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"}, ] attrs = [ - {file = "attrs-19.3.0-py2.py3-none-any.whl", hash = "sha256:08a96c641c3a74e44eb59afb61a24f2cb9f4d7188748e76ba4bb5edfa3cb7d1c"}, - {file = "attrs-19.3.0.tar.gz", hash = "sha256:f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72"}, + {file = "attrs-21.3.0-py2.py3-none-any.whl", hash = "sha256:8f7335278dedd26b58c38e006338242cc0977f06d51579b2b8b87b9b33bff66c"}, + {file = "attrs-21.3.0.tar.gz", hash = "sha256:50f3c9b216dc9021042f71b392859a773b904ce1a029077f58f6598272432045"}, ] babel = [ - {file = "Babel-2.7.0-py2.py3-none-any.whl", hash = "sha256:af92e6106cb7c55286b25b38ad7695f8b4efb36a90ba483d7f7a6628c46158ab"}, - {file = "Babel-2.7.0.tar.gz", hash = "sha256:e86135ae101e31e2c8ec20a4e0c5220f4eed12487d5cf3f78be7e98d3a57fc28"}, + {file = "Babel-2.9.1-py2.py3-none-any.whl", hash = "sha256:ab49e12b91d937cd11f0b67cb259a57ab4ad2b59ac7a3b41d6c06c0ac5b0def9"}, + {file = "Babel-2.9.1.tar.gz", hash = "sha256:bc0c176f9f6a994582230df350aa6e05ba2ebe4b3ac317eab29d9be5d2768da0"}, ] black = [ - {file = "black-19.10b0-py36-none-any.whl", hash = "sha256:1b30e59be925fafc1ee4565e5e08abef6b03fe455102883820fe5ee2e4734e0b"}, - {file = "black-19.10b0.tar.gz", hash = "sha256:c2edb73a08e9e0e6f65a0e6af18b059b8b1cdd5bef997d7a0b181df93dc81539"}, + {file = "black-20.8b1.tar.gz", hash = "sha256:1c02557aa099101b9d21496f8a914e9ed2222ef70336404eeeac8edba836fbea"}, + {file = "black-21.12b0-py3-none-any.whl", hash = "sha256:a615e69ae185e08fdd73e4715e260e2479c861b5740057fde6e8b4e3b7dd589f"}, + {file = "black-21.12b0.tar.gz", hash = "sha256:77b80f693a569e2e527958459634f18df9b0ba2625ba4e0c2d5da5be42e6f2b3"}, ] bump2version = [ - {file = "bump2version-0.5.11-py2.py3-none-any.whl", hash = "sha256:bfcc051498dda9fd9ac8634689f4516e1c20fdeeace3278932cc6e1248418b36"}, - {file = "bump2version-0.5.11.tar.gz", hash = "sha256:524bde030318fe2543038defe0f77739605636fef96924883813cb290cf79c1e"}, + {file = "bump2version-1.0.1-py2.py3-none-any.whl", hash = "sha256:37f927ea17cde7ae2d7baf832f8e80ce3777624554a653006c9144f8017fe410"}, + {file = "bump2version-1.0.1.tar.gz", hash = "sha256:762cb2bfad61f4ec8e2bdf452c7c267416f8c70dd9ecb1653fd0bbb01fa936e6"}, ] certifi = [ - {file = "certifi-2019.11.28-py2.py3-none-any.whl", hash = "sha256:017c25db2a153ce562900032d5bc68e9f191e44e9a0f762f373977de9df1fbb3"}, - {file = "certifi-2019.11.28.tar.gz", hash = "sha256:25b64c7da4cd7479594d035c08c2d809eb4aab3a26e5a990ea98cc450c320f1f"}, + {file = "certifi-2021.10.8-py2.py3-none-any.whl", hash = "sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569"}, + {file = "certifi-2021.10.8.tar.gz", hash = "sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872"}, ] -chardet = [ - {file = "chardet-3.0.4-py2.py3-none-any.whl", hash = "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"}, - {file = "chardet-3.0.4.tar.gz", hash = "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae"}, +charset-normalizer = [ + {file = "charset-normalizer-2.0.9.tar.gz", hash = "sha256:b0b883e8e874edfdece9c28f314e3dd5badf067342e42fb162203335ae61aa2c"}, + {file = "charset_normalizer-2.0.9-py3-none-any.whl", hash = "sha256:1eecaa09422db5be9e29d7fc65664e6c33bd06f9ced7838578ba40d58bdf3721"}, ] check-manifest = [ {file = "check-manifest-0.40.tar.gz", hash = "sha256:42de6eaab4ed149e60c9b367ada54f01a3b1e4d6846784f9b9710e770ff5572c"}, {file = "check_manifest-0.40-py2.py3-none-any.whl", hash = "sha256:78dd077f2c70dbac7cfcc9d12cbd423914e787ea4b5631de45aecd25b524e8e3"}, ] click = [ - {file = "Click-7.0-py2.py3-none-any.whl", hash = "sha256:2335065e6395b9e67ca716de5f7526736bfa6ceead690adf616d925bdc622b13"}, - {file = "Click-7.0.tar.gz", hash = "sha256:5b94b49521f6456670fdb30cd82a4eca9412788a93fa6dd6df72c94d5a8ff2d7"}, + {file = "click-8.0.3-py3-none-any.whl", hash = "sha256:353f466495adaeb40b6b5f592f9f91cb22372351c84caeb068132442a4518ef3"}, + {file = "click-8.0.3.tar.gz", hash = "sha256:410e932b050f5eed773c4cda94de75971c89cdb3155a72a0831139a79e5ecb5b"}, ] codecov = [ - {file = "codecov-2.0.15-py2.py3-none-any.whl", hash = "sha256:ae00d68e18d8a20e9c3288ba3875ae03db3a8e892115bf9b83ef20507732bed4"}, - {file = "codecov-2.0.15.tar.gz", hash = "sha256:8ed8b7c6791010d359baed66f84f061bba5bd41174bf324c31311e8737602788"}, + {file = "codecov-2.1.12-py2.py3-none-any.whl", hash = "sha256:585dc217dc3d8185198ceb402f85d5cb5dbfa0c5f350a5abcdf9e347776a5b47"}, + {file = "codecov-2.1.12-py3.8.egg", hash = "sha256:782a8e5352f22593cbc5427a35320b99490eb24d9dcfa2155fd99d2b75cfb635"}, + {file = "codecov-2.1.12.tar.gz", hash = "sha256:a0da46bb5025426da895af90938def8ee12d37fcbcbbbc15b6dc64cf7ebc51c1"}, ] colorama = [ - {file = "colorama-0.4.1-py2.py3-none-any.whl", hash = "sha256:f8ac84de7840f5b9c4e3347b3c1eaa50f7e49c2b07596221daec5edaabbd7c48"}, - {file = "colorama-0.4.1.tar.gz", hash = "sha256:05eed71e2e327246ad6b38c540c4a3117230b19679b875190486ddd2d721422d"}, + {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"}, + {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"}, ] coverage = [ - {file = "coverage-4.5.4-cp26-cp26m-macosx_10_12_x86_64.whl", hash = "sha256:eee64c616adeff7db37cc37da4180a3a5b6177f5c46b187894e633f088fb5b28"}, - {file = "coverage-4.5.4-cp27-cp27m-macosx_10_12_x86_64.whl", hash = "sha256:ef824cad1f980d27f26166f86856efe11eff9912c4fed97d3804820d43fa550c"}, - {file = "coverage-4.5.4-cp27-cp27m-macosx_10_13_intel.whl", hash = "sha256:9a334d6c83dfeadae576b4d633a71620d40d1c379129d587faa42ee3e2a85cce"}, - {file = "coverage-4.5.4-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:7494b0b0274c5072bddbfd5b4a6c6f18fbbe1ab1d22a41e99cd2d00c8f96ecfe"}, - {file = "coverage-4.5.4-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:826f32b9547c8091679ff292a82aca9c7b9650f9fda3e2ca6bf2ac905b7ce888"}, - {file = "coverage-4.5.4-cp27-cp27m-win32.whl", hash = "sha256:63a9a5fc43b58735f65ed63d2cf43508f462dc49857da70b8980ad78d41d52fc"}, - {file = "coverage-4.5.4-cp27-cp27m-win_amd64.whl", hash = "sha256:e2ede7c1d45e65e209d6093b762e98e8318ddeff95317d07a27a2140b80cfd24"}, - {file = "coverage-4.5.4-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:dd579709a87092c6dbee09d1b7cfa81831040705ffa12a1b248935274aee0437"}, - {file = "coverage-4.5.4-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:08907593569fe59baca0bf152c43f3863201efb6113ecb38ce7e97ce339805a6"}, - {file = "coverage-4.5.4-cp33-cp33m-macosx_10_10_x86_64.whl", hash = "sha256:6b62544bb68106e3f00b21c8930e83e584fdca005d4fffd29bb39fb3ffa03cb5"}, - {file = "coverage-4.5.4-cp34-cp34m-macosx_10_12_x86_64.whl", hash = "sha256:331cb5115673a20fb131dadd22f5bcaf7677ef758741312bee4937d71a14b2ef"}, - {file = "coverage-4.5.4-cp34-cp34m-manylinux1_i686.whl", hash = "sha256:bf1ef9eb901113a9805287e090452c05547578eaab1b62e4ad456fcc049a9b7e"}, - {file = "coverage-4.5.4-cp34-cp34m-manylinux1_x86_64.whl", hash = "sha256:386e2e4090f0bc5df274e720105c342263423e77ee8826002dcffe0c9533dbca"}, - {file = "coverage-4.5.4-cp34-cp34m-win32.whl", hash = "sha256:fa964bae817babece5aa2e8c1af841bebb6d0b9add8e637548809d040443fee0"}, - {file = "coverage-4.5.4-cp34-cp34m-win_amd64.whl", hash = "sha256:df6712284b2e44a065097846488f66840445eb987eb81b3cc6e4149e7b6982e1"}, - {file = "coverage-4.5.4-cp35-cp35m-macosx_10_12_x86_64.whl", hash = "sha256:efc89291bd5a08855829a3c522df16d856455297cf35ae827a37edac45f466a7"}, - {file = "coverage-4.5.4-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:e4ef9c164eb55123c62411f5936b5c2e521b12356037b6e1c2617cef45523d47"}, - {file = "coverage-4.5.4-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:ff37757e068ae606659c28c3bd0d923f9d29a85de79bf25b2b34b148473b5025"}, - {file = "coverage-4.5.4-cp35-cp35m-win32.whl", hash = "sha256:bf0a7aed7f5521c7ca67febd57db473af4762b9622254291fbcbb8cd0ba5e33e"}, - {file = "coverage-4.5.4-cp35-cp35m-win_amd64.whl", hash = "sha256:19e4df788a0581238e9390c85a7a09af39c7b539b29f25c89209e6c3e371270d"}, - {file = "coverage-4.5.4-cp36-cp36m-macosx_10_13_x86_64.whl", hash = "sha256:60851187677b24c6085248f0a0b9b98d49cba7ecc7ec60ba6b9d2e5574ac1ee9"}, - {file = "coverage-4.5.4-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:245388cda02af78276b479f299bbf3783ef0a6a6273037d7c60dc73b8d8d7755"}, - {file = "coverage-4.5.4-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:c0afd27bc0e307a1ffc04ca5ec010a290e49e3afbe841c5cafc5c5a80ecd81c9"}, - {file = "coverage-4.5.4-cp36-cp36m-win32.whl", hash = "sha256:6ba744056423ef8d450cf627289166da65903885272055fb4b5e113137cfa14f"}, - {file = "coverage-4.5.4-cp36-cp36m-win_amd64.whl", hash = "sha256:af7ed8a8aa6957aac47b4268631fa1df984643f07ef00acd374e456364b373f5"}, - {file = "coverage-4.5.4-cp37-cp37m-macosx_10_13_x86_64.whl", hash = "sha256:3a794ce50daee01c74a494919d5ebdc23d58873747fa0e288318728533a3e1ca"}, - {file = "coverage-4.5.4-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:0be0f1ed45fc0c185cfd4ecc19a1d6532d72f86a2bac9de7e24541febad72650"}, - {file = "coverage-4.5.4-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:eca2b7343524e7ba246cab8ff00cab47a2d6d54ada3b02772e908a45675722e2"}, - {file = "coverage-4.5.4-cp37-cp37m-win32.whl", hash = "sha256:93715dffbcd0678057f947f496484e906bf9509f5c1c38fc9ba3922893cda5f5"}, - {file = "coverage-4.5.4-cp37-cp37m-win_amd64.whl", hash = "sha256:23cc09ed395b03424d1ae30dcc292615c1372bfba7141eb85e11e50efaa6b351"}, - {file = "coverage-4.5.4-cp38-cp38-macosx_10_13_x86_64.whl", hash = "sha256:141f08ed3c4b1847015e2cd62ec06d35e67a3ac185c26f7635f4406b90afa9c5"}, - {file = "coverage-4.5.4.tar.gz", hash = "sha256:e07d9f1a23e9e93ab5c62902833bf3e4b1f65502927379148b6622686223125c"}, + {file = "coverage-6.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6dbc1536e105adda7a6312c778f15aaabe583b0e9a0b0a324990334fd458c94b"}, + {file = "coverage-6.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:174cf9b4bef0db2e8244f82059a5a72bd47e1d40e71c68ab055425172b16b7d0"}, + {file = "coverage-6.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:92b8c845527eae547a2a6617d336adc56394050c3ed8a6918683646328fbb6da"}, + {file = "coverage-6.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c7912d1526299cb04c88288e148c6c87c0df600eca76efd99d84396cfe00ef1d"}, + {file = "coverage-6.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d5d2033d5db1d58ae2d62f095e1aefb6988af65b4b12cb8987af409587cc0739"}, + {file = "coverage-6.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:3feac4084291642165c3a0d9eaebedf19ffa505016c4d3db15bfe235718d4971"}, + {file = "coverage-6.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:276651978c94a8c5672ea60a2656e95a3cce2a3f31e9fb2d5ebd4c215d095840"}, + {file = "coverage-6.2-cp310-cp310-win32.whl", hash = "sha256:f506af4f27def639ba45789fa6fde45f9a217da0be05f8910458e4557eed020c"}, + {file = "coverage-6.2-cp310-cp310-win_amd64.whl", hash = "sha256:3f7c17209eef285c86f819ff04a6d4cbee9b33ef05cbcaae4c0b4e8e06b3ec8f"}, + {file = "coverage-6.2-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:13362889b2d46e8d9f97c421539c97c963e34031ab0cb89e8ca83a10cc71ac76"}, + {file = "coverage-6.2-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:22e60a3ca5acba37d1d4a2ee66e051f5b0e1b9ac950b5b0cf4aa5366eda41d47"}, + {file = "coverage-6.2-cp311-cp311-win_amd64.whl", hash = "sha256:b637c57fdb8be84e91fac60d9325a66a5981f8086c954ea2772efe28425eaf64"}, + {file = "coverage-6.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f467bbb837691ab5a8ca359199d3429a11a01e6dfb3d9dcc676dc035ca93c0a9"}, + {file = "coverage-6.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2641f803ee9f95b1f387f3e8f3bf28d83d9b69a39e9911e5bfee832bea75240d"}, + {file = "coverage-6.2-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:1219d760ccfafc03c0822ae2e06e3b1248a8e6d1a70928966bafc6838d3c9e48"}, + {file = "coverage-6.2-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:9a2b5b52be0a8626fcbffd7e689781bf8c2ac01613e77feda93d96184949a98e"}, + {file = "coverage-6.2-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:8e2c35a4c1f269704e90888e56f794e2d9c0262fb0c1b1c8c4ee44d9b9e77b5d"}, + {file = "coverage-6.2-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:5d6b09c972ce9200264c35a1d53d43ca55ef61836d9ec60f0d44273a31aa9f17"}, + {file = "coverage-6.2-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:e3db840a4dee542e37e09f30859f1612da90e1c5239a6a2498c473183a50e781"}, + {file = "coverage-6.2-cp36-cp36m-win32.whl", hash = "sha256:4e547122ca2d244f7c090fe3f4b5a5861255ff66b7ab6d98f44a0222aaf8671a"}, + {file = "coverage-6.2-cp36-cp36m-win_amd64.whl", hash = "sha256:01774a2c2c729619760320270e42cd9e797427ecfddd32c2a7b639cdc481f3c0"}, + {file = "coverage-6.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:fb8b8ee99b3fffe4fd86f4c81b35a6bf7e4462cba019997af2fe679365db0c49"}, + {file = "coverage-6.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:619346d57c7126ae49ac95b11b0dc8e36c1dd49d148477461bb66c8cf13bb521"}, + {file = "coverage-6.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:0a7726f74ff63f41e95ed3a89fef002916c828bb5fcae83b505b49d81a066884"}, + {file = "coverage-6.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:cfd9386c1d6f13b37e05a91a8583e802f8059bebfccde61a418c5808dea6bbfa"}, + {file = "coverage-6.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:17e6c11038d4ed6e8af1407d9e89a2904d573be29d51515f14262d7f10ef0a64"}, + {file = "coverage-6.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c254b03032d5a06de049ce8bca8338a5185f07fb76600afff3c161e053d88617"}, + {file = "coverage-6.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:dca38a21e4423f3edb821292e97cec7ad38086f84313462098568baedf4331f8"}, + {file = "coverage-6.2-cp37-cp37m-win32.whl", hash = "sha256:600617008aa82032ddeace2535626d1bc212dfff32b43989539deda63b3f36e4"}, + {file = "coverage-6.2-cp37-cp37m-win_amd64.whl", hash = "sha256:bf154ba7ee2fd613eb541c2bc03d3d9ac667080a737449d1a3fb342740eb1a74"}, + {file = "coverage-6.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f9afb5b746781fc2abce26193d1c817b7eb0e11459510fba65d2bd77fe161d9e"}, + {file = "coverage-6.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:edcada2e24ed68f019175c2b2af2a8b481d3d084798b8c20d15d34f5c733fa58"}, + {file = "coverage-6.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:a9c8c4283e17690ff1a7427123ffb428ad6a52ed720d550e299e8291e33184dc"}, + {file = "coverage-6.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f614fc9956d76d8a88a88bb41ddc12709caa755666f580af3a688899721efecd"}, + {file = "coverage-6.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:9365ed5cce5d0cf2c10afc6add145c5037d3148585b8ae0e77cc1efdd6aa2953"}, + {file = "coverage-6.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:8bdfe9ff3a4ea37d17f172ac0dff1e1c383aec17a636b9b35906babc9f0f5475"}, + {file = "coverage-6.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:63c424e6f5b4ab1cf1e23a43b12f542b0ec2e54f99ec9f11b75382152981df57"}, + {file = "coverage-6.2-cp38-cp38-win32.whl", hash = "sha256:49dbff64961bc9bdd2289a2bda6a3a5a331964ba5497f694e2cbd540d656dc1c"}, + {file = "coverage-6.2-cp38-cp38-win_amd64.whl", hash = "sha256:9a29311bd6429be317c1f3fe4bc06c4c5ee45e2fa61b2a19d4d1d6111cb94af2"}, + {file = "coverage-6.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:03b20e52b7d31be571c9c06b74746746d4eb82fc260e594dc662ed48145e9efd"}, + {file = "coverage-6.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:215f8afcc02a24c2d9a10d3790b21054b58d71f4b3c6f055d4bb1b15cecce685"}, + {file = "coverage-6.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:a4bdeb0a52d1d04123b41d90a4390b096f3ef38eee35e11f0b22c2d031222c6c"}, + {file = "coverage-6.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c332d8f8d448ded473b97fefe4a0983265af21917d8b0cdcb8bb06b2afe632c3"}, + {file = "coverage-6.2-cp39-cp39-win32.whl", hash = "sha256:6e1394d24d5938e561fbeaa0cd3d356207579c28bd1792f25a068743f2d5b282"}, + {file = "coverage-6.2-cp39-cp39-win_amd64.whl", hash = "sha256:86f2e78b1eff847609b1ca8050c9e1fa3bd44ce755b2ec30e70f2d3ba3844644"}, + {file = "coverage-6.2-pp36.pp37.pp38-none-any.whl", hash = "sha256:5829192582c0ec8ca4a2532407bc14c2f338d9878a10442f5d03804a95fac9de"}, + {file = "coverage-6.2.tar.gz", hash = "sha256:e2cad8093172b7d1595b4ad66f24270808658e11acf43a8f95b41276162eb5b8"}, ] -docutils = [ - {file = "docutils-0.15.2-py2-none-any.whl", hash = "sha256:9e4d7ecfc600058e07ba661411a2b7de2fd0fafa17d1a7f7361cd47b1175c827"}, - {file = "docutils-0.15.2-py3-none-any.whl", hash = "sha256:6c4f696463b79f1fb8ba0c594b63840ebd41f059e92b31957c46b74a4599b6d0"}, - {file = "docutils-0.15.2.tar.gz", hash = "sha256:a2aeea129088da402665e92e0b25b04b073c04b2dce4ab65caaa38b7ce2e1a99"}, +dataclasses = [ + {file = "dataclasses-0.8-py3-none-any.whl", hash = "sha256:0201d89fa866f68c8ebd9d08ee6ff50c0b255f8ec63a71c16fda7af82bb887bf"}, + {file = "dataclasses-0.8.tar.gz", hash = "sha256:8479067f342acf957dc82ec415d355ab5edb7e7646b90dc6e2fd1d96ad084c97"}, +] +distlib = [ + {file = "distlib-0.3.4-py2.py3-none-any.whl", hash = "sha256:6564fe0a8f51e734df6333d08b8b94d4ea8ee6b99b5ed50613f731fd4089f34b"}, + {file = "distlib-0.3.4.zip", hash = "sha256:e4b58818180336dc9c529bfb9a0b58728ffc09ad92027a3f30b7cd91e3458579"}, ] -entrypoints = [ - {file = "entrypoints-0.3-py2.py3-none-any.whl", hash = "sha256:589f874b313739ad35be6e0cd7efde2a4e9b6fea91edcc34e58ecbb8dbe56d19"}, - {file = "entrypoints-0.3.tar.gz", hash = "sha256:c70dd71abe5a8c85e55e12c19bd91ccfeec11a6e99044204511f9ed547d48451"}, +docutils = [ + {file = "docutils-0.16-py2.py3-none-any.whl", hash = "sha256:0c5b78adfbf7762415433f5515cd5c9e762339e23369dbe8000d84a4bf4ab3af"}, + {file = "docutils-0.16.tar.gz", hash = "sha256:c2de3a60e9e7d07be26b7f2b00ca0309c207e06c100f9cc2a94931fc75a478fc"}, ] filelock = [ - {file = "filelock-3.0.12-py3-none-any.whl", hash = "sha256:929b7d63ec5b7d6b71b0fa5ac14e030b3f70b75747cef1b10da9b879fef15836"}, - {file = "filelock-3.0.12.tar.gz", hash = "sha256:18d82244ee114f543149c66a6e0c14e9c4f8a1044b5cdaadd0f82159d6a6ff59"}, + {file = "filelock-3.4.1-py3-none-any.whl", hash = "sha256:a4bc51381e01502a30e9f06dd4fa19a1712eab852b6fb0f84fd7cce0793d8ca3"}, + {file = "filelock-3.4.1.tar.gz", hash = "sha256:0f12f552b42b5bf60dba233710bf71337d35494fc8bdd4fd6d9f6d082ad45e06"}, ] flake8 = [ - {file = "flake8-3.7.9-py2.py3-none-any.whl", hash = "sha256:49356e766643ad15072a789a20915d3c91dc89fd313ccd71802303fd67e4deca"}, - {file = "flake8-3.7.9.tar.gz", hash = "sha256:45681a117ecc81e870cbf1262835ae4af5e7a8b08e40b944a8a6e6b895914cfb"}, + {file = "flake8-4.0.1-py2.py3-none-any.whl", hash = "sha256:479b1304f72536a55948cb40a32dce8bb0ffe3501e26eaf292c7e60eb5e0428d"}, + {file = "flake8-4.0.1.tar.gz", hash = "sha256:806e034dda44114815e23c16ef92f95c91e4c71100ff52813adf7132a6ad870d"}, ] idna = [ - {file = "idna-2.8-py2.py3-none-any.whl", hash = "sha256:ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c"}, - {file = "idna-2.8.tar.gz", hash = "sha256:c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407"}, + {file = "idna-3.3-py3-none-any.whl", hash = "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff"}, + {file = "idna-3.3.tar.gz", hash = "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d"}, ] imagesize = [ - {file = "imagesize-1.1.0-py2.py3-none-any.whl", hash = "sha256:3f349de3eb99145973fefb7dbe38554414e5c30abd0c8e4b970a7c9d09f3a1d8"}, - {file = "imagesize-1.1.0.tar.gz", hash = "sha256:f3832918bc3c66617f92e35f5d70729187676313caa60c187eb0f28b8fe5e3b5"}, + {file = "imagesize-1.3.0-py2.py3-none-any.whl", hash = "sha256:1db2f82529e53c3e929e8926a1fa9235aa82d0bd0c580359c67ec31b2fddaa8c"}, + {file = "imagesize-1.3.0.tar.gz", hash = "sha256:cd1750d452385ca327479d45b64d9c7729ecf0b3969a58148298c77092261f9d"}, ] importlib-metadata = [ - {file = "importlib_metadata-0.23-py2.py3-none-any.whl", hash = "sha256:d5f18a79777f3aa179c145737780282e27b508fc8fd688cb17c7a813e8bd39af"}, - {file = "importlib_metadata-0.23.tar.gz", hash = "sha256:aa18d7378b00b40847790e7c27e11673d7fed219354109d0e7b9e5b25dc3ad26"}, + {file = "importlib_metadata-4.2.0-py3-none-any.whl", hash = "sha256:057e92c15bc8d9e8109738a48db0ccb31b4d9d5cfbee5a8670879a30be66304b"}, + {file = "importlib_metadata-4.2.0.tar.gz", hash = "sha256:b7e52a1f8dec14a75ea73e0891f3060099ca1d8e6a462a4dff11c3e119ea1b31"}, +] +importlib-resources = [ + {file = "importlib_resources-5.4.0-py3-none-any.whl", hash = "sha256:33a95faed5fc19b4bc16b29a6eeae248a3fe69dd55d4d229d2b480e23eeaad45"}, + {file = "importlib_resources-5.4.0.tar.gz", hash = "sha256:d756e2f85dd4de2ba89be0b21dba2a3bbec2e871a42a3a16719258a11f87506b"}, +] +iniconfig = [ + {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, + {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"}, ] jinja2 = [ - {file = "Jinja2-2.10.3-py2.py3-none-any.whl", hash = "sha256:74320bb91f31270f9551d46522e33af46a80c3d619f4a4bf42b3164d30b5911f"}, - {file = "Jinja2-2.10.3.tar.gz", hash = "sha256:9fe95f19286cfefaa917656583d020be14e7859c6b0252588391e47db34527de"}, + {file = "Jinja2-3.0.3-py3-none-any.whl", hash = "sha256:077ce6014f7b40d03b47d1f1ca4b0fc8328a692bd284016f806ed0eaca390ad8"}, + {file = "Jinja2-3.0.3.tar.gz", hash = "sha256:611bb273cd68f3b993fabdc4064fc858c5b47a973cb5aa7999ec1ba405c87cd7"}, ] markupsafe = [ - {file = "MarkupSafe-1.1.1-cp27-cp27m-macosx_10_6_intel.whl", hash = "sha256:09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161"}, - {file = "MarkupSafe-1.1.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7"}, - {file = "MarkupSafe-1.1.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183"}, - {file = "MarkupSafe-1.1.1-cp27-cp27m-win32.whl", hash = "sha256:b2051432115498d3562c084a49bba65d97cf251f5a331c64a12ee7e04dacc51b"}, - {file = "MarkupSafe-1.1.1-cp27-cp27m-win_amd64.whl", hash = "sha256:98c7086708b163d425c67c7a91bad6e466bb99d797aa64f965e9d25c12111a5e"}, - {file = "MarkupSafe-1.1.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f"}, - {file = "MarkupSafe-1.1.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:43a55c2930bbc139570ac2452adf3d70cdbb3cfe5912c71cdce1c2c6bbd9c5d1"}, - {file = "MarkupSafe-1.1.1-cp34-cp34m-macosx_10_6_intel.whl", hash = "sha256:1027c282dad077d0bae18be6794e6b6b8c91d58ed8a8d89a89d59693b9131db5"}, - {file = "MarkupSafe-1.1.1-cp34-cp34m-manylinux1_i686.whl", hash = "sha256:62fe6c95e3ec8a7fad637b7f3d372c15ec1caa01ab47926cfdf7a75b40e0eac1"}, - {file = "MarkupSafe-1.1.1-cp34-cp34m-manylinux1_x86_64.whl", hash = "sha256:88e5fcfb52ee7b911e8bb6d6aa2fd21fbecc674eadd44118a9cc3863f938e735"}, - {file = "MarkupSafe-1.1.1-cp34-cp34m-win32.whl", hash = "sha256:ade5e387d2ad0d7ebf59146cc00c8044acbd863725f887353a10df825fc8ae21"}, - {file = "MarkupSafe-1.1.1-cp34-cp34m-win_amd64.whl", hash = "sha256:09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235"}, - {file = "MarkupSafe-1.1.1-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:79855e1c5b8da654cf486b830bd42c06e8780cea587384cf6545b7d9ac013a0b"}, - {file = "MarkupSafe-1.1.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f"}, - {file = "MarkupSafe-1.1.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:7c1699dfe0cf8ff607dbdcc1e9b9af1755371f92a68f706051cc8c37d447c905"}, - {file = "MarkupSafe-1.1.1-cp35-cp35m-win32.whl", hash = "sha256:6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1"}, - {file = "MarkupSafe-1.1.1-cp35-cp35m-win_amd64.whl", hash = "sha256:9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d"}, - {file = "MarkupSafe-1.1.1-cp36-cp36m-macosx_10_6_intel.whl", hash = "sha256:24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff"}, - {file = "MarkupSafe-1.1.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473"}, - {file = "MarkupSafe-1.1.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e"}, - {file = "MarkupSafe-1.1.1-cp36-cp36m-win32.whl", hash = "sha256:535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66"}, - {file = "MarkupSafe-1.1.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5"}, - {file = "MarkupSafe-1.1.1-cp37-cp37m-macosx_10_6_intel.whl", hash = "sha256:8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d"}, - {file = "MarkupSafe-1.1.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e"}, - {file = "MarkupSafe-1.1.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6"}, - {file = "MarkupSafe-1.1.1-cp37-cp37m-win32.whl", hash = "sha256:b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2"}, - {file = "MarkupSafe-1.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c"}, - {file = "MarkupSafe-1.1.1.tar.gz", hash = "sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f9081981fe268bd86831e5c75f7de206ef275defcb82bc70740ae6dc507aee51"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:0955295dd5eec6cb6cc2fe1698f4c6d84af2e92de33fbcac4111913cd100a6ff"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:0446679737af14f45767963a1a9ef7620189912317d095f2d9ffa183a4d25d2b"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:f826e31d18b516f653fe296d967d700fddad5901ae07c622bb3705955e1faa94"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:fa130dd50c57d53368c9d59395cb5526eda596d3ffe36666cd81a44d56e48872"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:905fec760bd2fa1388bb5b489ee8ee5f7291d692638ea5f67982d968366bef9f"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-win32.whl", hash = "sha256:6c4ca60fa24e85fe25b912b01e62cb969d69a23a5d5867682dd3e80b5b02581d"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b2f4bf27480f5e5e8ce285a8c8fd176c0b03e93dcc6646477d4630e83440c6a9"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0717a7390a68be14b8c793ba258e075c6f4ca819f15edfc2a3a027c823718567"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:6557b31b5e2c9ddf0de32a691f2312a32f77cd7681d8af66c2692efdbef84c18"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:49e3ceeabbfb9d66c3aef5af3a60cc43b85c33df25ce03d0031a608b0a8b2e3f"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:d7f9850398e85aba693bb640262d3611788b1f29a79f0c93c565694658f4071f"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:6a7fae0dd14cf60ad5ff42baa2e95727c3d81ded453457771d02b7d2b3f9c0c2"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:b7f2d075102dc8c794cbde1947378051c4e5180d52d276987b8d28a3bd58c17d"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-win32.whl", hash = "sha256:a30e67a65b53ea0a5e62fe23682cfe22712e01f453b95233b25502f7c61cb415"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:611d1ad9a4288cf3e3c16014564df047fe08410e628f89805e475368bd304914"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:be98f628055368795d818ebf93da628541e10b75b41c559fdf36d104c5787066"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:1d609f577dc6e1aa17d746f8bd3c31aa4d258f4070d61b2aa5c4166c1539de35"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7d91275b0245b1da4d4cfa07e0faedd5b0812efc15b702576d103293e252af1b"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:01a9b8ea66f1658938f65b93a85ebe8bc016e6769611be228d797c9d998dd298"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:47ab1e7b91c098ab893b828deafa1203de86d0bc6ab587b160f78fe6c4011f75"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:97383d78eb34da7e1fa37dd273c20ad4320929af65d156e35a5e2d89566d9dfb"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-win32.whl", hash = "sha256:023cb26ec21ece8dc3907c0e8320058b2e0cb3c55cf9564da612bc325bed5e64"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:984d76483eb32f1bcb536dc27e4ad56bba4baa70be32fa87152832cdd9db0833"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:2ef54abee730b502252bcdf31b10dacb0a416229b72c18b19e24a4509f273d26"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3c112550557578c26af18a1ccc9e090bfe03832ae994343cfdacd287db6a6ae7"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux1_i686.whl", hash = "sha256:53edb4da6925ad13c07b6d26c2a852bd81e364f95301c66e930ab2aef5b5ddd8"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:f5653a225f31e113b152e56f154ccbe59eeb1c7487b39b9d9f9cdb58e6c79dc5"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:4efca8f86c54b22348a5467704e3fec767b2db12fc39c6d963168ab1d3fc9135"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:ab3ef638ace319fa26553db0624c4699e31a28bb2a835c5faca8f8acf6a5a902"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:f8ba0e8349a38d3001fae7eadded3f6606f0da5d748ee53cc1dab1d6527b9509"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-win32.whl", hash = "sha256:10f82115e21dc0dfec9ab5c0223652f7197feb168c940f3ef61563fc2d6beb74"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:693ce3f9e70a6cf7d2fb9e6c9d8b204b6b39897a2c4a1aa65728d5ac97dcc1d8"}, + {file = "MarkupSafe-2.0.1.tar.gz", hash = "sha256:594c67807fb16238b30c44bdf74f36c02cdf22d1c8cda91ef8a0ed8dabf5620a"}, ] mccabe = [ {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"}, {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"}, ] -more-itertools = [ - {file = "more-itertools-8.0.0.tar.gz", hash = "sha256:53ff73f186307d9c8ef17a9600309154a6ae27f25579e80af4db8f047ba14bc2"}, - {file = "more_itertools-8.0.0-py3-none-any.whl", hash = "sha256:a0ea684c39bc4315ba7aae406596ef191fd84f873d2d2751f84d64e81a7a2d45"}, -] mypy = [ - {file = "mypy-0.750-cp35-cp35m-macosx_10_6_x86_64.whl", hash = "sha256:de9ec8dba773b78c49e7bec9a35c9b6fc5235682ad1fc2105752ae7c22f4b931"}, - {file = "mypy-0.750-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:3294821b5840d51a3cd7a2bb63b40fc3f901f6a3cfb3c6046570749c4c7ef279"}, - {file = "mypy-0.750-cp35-cp35m-win_amd64.whl", hash = "sha256:6992133c95a2847d309b4b0c899d7054adc60481df6f6b52bb7dee3d5fd157f7"}, - {file = "mypy-0.750-cp36-cp36m-macosx_10_6_x86_64.whl", hash = "sha256:41696a7d912ce16fdc7c141d87e8db5144d4be664a0c699a2b417d393994b0c2"}, - {file = "mypy-0.750-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:c87ac7233c629f305602f563db07f5221950fe34fe30af072ac838fa85395f78"}, - {file = "mypy-0.750-cp36-cp36m-win_amd64.whl", hash = "sha256:83fa87f556e60782c0fc3df1b37b7b4a840314ba1ac27f3e1a1e10cb37c89c17"}, - {file = "mypy-0.750-cp37-cp37m-macosx_10_6_x86_64.whl", hash = "sha256:30e123b24931f02c5d99307406658ac8f9cd6746f0d45a3dcac2fe5fbdd60939"}, - {file = "mypy-0.750-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:02d9bdd3398b636723ecb6c5cfe9773025a9ab7f34612c1cde5c7f2292e2d768"}, - {file = "mypy-0.750-cp37-cp37m-win_amd64.whl", hash = "sha256:088f758a50af31cf8b42688118077292370c90c89232c783ba7979f39ea16646"}, - {file = "mypy-0.750-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:4f42675fa278f3913340bb8c3371d191319704437758d7c4a8440346c293ecb2"}, - {file = "mypy-0.750-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:f385a0accf353ca1bca4bbf473b9d83ed18d923fdb809d3a70a385da23e25b6a"}, - {file = "mypy-0.750-cp38-cp38-win_amd64.whl", hash = "sha256:54d205ccce6ed930a8a2ccf48404896d456e8b87812e491cb907a355b1a9c640"}, - {file = "mypy-0.750-py3-none-any.whl", hash = "sha256:28e9fbc96d13397a7ddb7fad7b14f373f91b5cff538e0772e77c270468df083c"}, - {file = "mypy-0.750.tar.gz", hash = "sha256:6ecbd0e8e371333027abca0922b0c2c632a5b4739a0c61ffbd0733391e39144c"}, + {file = "mypy-0.930-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:221cc94dc6a801ccc2be7c0c9fd791c5e08d1fa2c5e1c12dec4eab15b2469871"}, + {file = "mypy-0.930-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:db3a87376a1380f396d465bed462e76ea89f838f4c5e967d68ff6ee34b785c31"}, + {file = "mypy-0.930-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:1d2296f35aae9802eeb1327058b550371ee382d71374b3e7d2804035ef0b830b"}, + {file = "mypy-0.930-cp310-cp310-win_amd64.whl", hash = "sha256:959319b9a3cafc33a8185f440a433ba520239c72e733bf91f9efd67b0a8e9b30"}, + {file = "mypy-0.930-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:45a4dc21c789cfd09b8ccafe114d6de66f0b341ad761338de717192f19397a8c"}, + {file = "mypy-0.930-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:1e689e92cdebd87607a041585f1dc7339aa2e8a9f9bad9ba7e6ece619431b20c"}, + {file = "mypy-0.930-cp36-cp36m-win_amd64.whl", hash = "sha256:ed4e0ea066bb12f56b2812a15ff223c57c0a44eca817ceb96b214bb055c7051f"}, + {file = "mypy-0.930-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a9d8dffefba634b27d650e0de2564379a1a367e2e08d6617d8f89261a3bf63b2"}, + {file = "mypy-0.930-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:b419e9721260161e70d054a15abbd50603c16f159860cfd0daeab647d828fc29"}, + {file = "mypy-0.930-cp37-cp37m-win_amd64.whl", hash = "sha256:601f46593f627f8a9b944f74fd387c9b5f4266b39abad77471947069c2fc7651"}, + {file = "mypy-0.930-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1ea7199780c1d7940b82dbc0a4e37722b4e3851264dbba81e01abecc9052d8a7"}, + {file = "mypy-0.930-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:70b197dd8c78fc5d2daf84bd093e8466a2b2e007eedaa85e792e513a820adbf7"}, + {file = "mypy-0.930-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:5feb56f8bb280468fe5fc8e6f56f48f99aa0df9eed3c507a11505ee4657b5380"}, + {file = "mypy-0.930-cp38-cp38-win_amd64.whl", hash = "sha256:2e9c5409e9cb81049bb03fa1009b573dea87976713e3898561567a86c4eaee01"}, + {file = "mypy-0.930-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:554873e45c1ca20f31ddf873deb67fa5d2e87b76b97db50669f0468ccded8fae"}, + {file = "mypy-0.930-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0feb82e9fa849affca7edd24713dbe809dce780ced9f3feca5ed3d80e40b777f"}, + {file = "mypy-0.930-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:bc1a0607ea03c30225347334af66b0af12eefba018a89a88c209e02b7065ea95"}, + {file = "mypy-0.930-cp39-cp39-win_amd64.whl", hash = "sha256:f9f665d69034b1fcfdbcd4197480d26298bbfb5d2dfe206245b6498addb34999"}, + {file = "mypy-0.930-py3-none-any.whl", hash = "sha256:bf4a44e03040206f7c058d1f5ba02ef2d1820720c88bc4285c7d9a4269f54173"}, + {file = "mypy-0.930.tar.gz", hash = "sha256:51426262ae4714cc7dd5439814676e0992b55bcc0f6514eccb4cf8e0678962c2"}, ] mypy-extensions = [ {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, ] packaging = [ - {file = "packaging-19.2-py2.py3-none-any.whl", hash = "sha256:d9551545c6d761f3def1677baf08ab2a3ca17c56879e70fecba2fc4dde4ed108"}, - {file = "packaging-19.2.tar.gz", hash = "sha256:28b924174df7a2fa32c1953825ff29c61e2f5e082343165438812f00d3a7fc47"}, + {file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"}, + {file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"}, ] pathspec = [ - {file = "pathspec-0.6.0.tar.gz", hash = "sha256:e285ccc8b0785beadd4c18e5708b12bb8fcf529a1e61215b3feff1d1e559ea5c"}, + {file = "pathspec-0.9.0-py2.py3-none-any.whl", hash = "sha256:7d15c4ddb0b5c802d161efc417ec1a2558ea2653c2e8ad9c19098201dc1c993a"}, + {file = "pathspec-0.9.0.tar.gz", hash = "sha256:e564499435a2673d586f6b2130bb5b95f04a3ba06f81b8f895b651a3c76aabb1"}, +] +platformdirs = [ + {file = "platformdirs-2.4.0-py3-none-any.whl", hash = "sha256:8868bbe3c3c80d42f20156f22e7131d2fb321f5bc86a2a345375c6481a67021d"}, + {file = "platformdirs-2.4.0.tar.gz", hash = "sha256:367a5e80b3d04d2428ffa76d33f124cf11e8fff2acdaa9b43d545f5c7d661ef2"}, ] pluggy = [ - {file = "pluggy-0.13.1-py2.py3-none-any.whl", hash = "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"}, - {file = "pluggy-0.13.1.tar.gz", hash = "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0"}, + {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"}, + {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"}, ] py = [ - {file = "py-1.8.0-py2.py3-none-any.whl", hash = "sha256:64f65755aee5b381cea27766a3a147c3f15b9b6b9ac88676de66ba2ae36793fa"}, - {file = "py-1.8.0.tar.gz", hash = "sha256:dc639b046a6e2cff5bbe40194ad65936d6ba360b52b3c3fe1d08a82dd50b5e53"}, + {file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"}, + {file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"}, ] py-cpuinfo = [ - {file = "py-cpuinfo-5.0.0.tar.gz", hash = "sha256:2cf6426f776625b21d1db8397d3297ef7acfa59018f02a8779123f3190f18500"}, + {file = "py-cpuinfo-8.0.0.tar.gz", hash = "sha256:5f269be0e08e33fd959de96b34cd4aeeeacac014dd8305f70eb28d06de2345c5"}, ] pycodestyle = [ - {file = "pycodestyle-2.5.0-py2.py3-none-any.whl", hash = "sha256:95a2219d12372f05704562a14ec30bc76b05a5b297b21a5dfe3f6fac3491ae56"}, - {file = "pycodestyle-2.5.0.tar.gz", hash = "sha256:e40a936c9a450ad81df37f549d676d127b1b66000a6c500caa2b085bc0ca976c"}, + {file = "pycodestyle-2.8.0-py2.py3-none-any.whl", hash = "sha256:720f8b39dde8b293825e7ff02c475f3077124006db4f440dcbc9a20b76548a20"}, + {file = "pycodestyle-2.8.0.tar.gz", hash = "sha256:eddd5847ef438ea1c7870ca7eb78a9d47ce0cdb4851a5523949f2601d0cbbe7f"}, ] pyflakes = [ - {file = "pyflakes-2.1.1-py2.py3-none-any.whl", hash = "sha256:17dbeb2e3f4d772725c777fabc446d5634d1038f234e77343108ce445ea69ce0"}, - {file = "pyflakes-2.1.1.tar.gz", hash = "sha256:d976835886f8c5b31d47970ed689944a0262b5f3afa00a5a7b4dc81e5449f8a2"}, + {file = "pyflakes-2.4.0-py2.py3-none-any.whl", hash = "sha256:3bb3a3f256f4b7968c9c788781e4ff07dce46bdf12339dcda61053375426ee2e"}, + {file = "pyflakes-2.4.0.tar.gz", hash = "sha256:05a85c2872edf37a4ed30b0cce2f6093e1d0581f8c19d7393122da7e25b2b24c"}, ] pygments = [ - {file = "Pygments-2.5.2-py2.py3-none-any.whl", hash = "sha256:2a3fe295e54a20164a9df49c75fa58526d3be48e14aceba6d6b1e8ac0bfd6f1b"}, - {file = "Pygments-2.5.2.tar.gz", hash = "sha256:98c8aa5a9f778fcd1026a17361ddaf7330d1b7c62ae97c3bb0ae73e0b9b6b0fe"}, + {file = "Pygments-2.10.0-py3-none-any.whl", hash = "sha256:b8e67fe6af78f492b3c4b3e2970c0624cbf08beb1e493b2c99b9fa1b67a20380"}, + {file = "Pygments-2.10.0.tar.gz", hash = "sha256:f398865f7eb6874156579fdf36bc840a03cab64d1cde9e93d68f46a425ec52c6"}, ] pyparsing = [ - {file = "pyparsing-2.4.5-py2.py3-none-any.whl", hash = "sha256:20f995ecd72f2a1f4bf6b072b63b22e2eb457836601e76d6e5dfcd75436acc1f"}, - {file = "pyparsing-2.4.5.tar.gz", hash = "sha256:4ca62001be367f01bd3e92ecbb79070272a9d4964dce6a48a82ff0b8bc7e683a"}, + {file = "pyparsing-3.0.6-py3-none-any.whl", hash = "sha256:04ff808a5b90911829c55c4e26f75fa5ca8a2f5f36aa3a51f68e27033341d3e4"}, + {file = "pyparsing-3.0.6.tar.gz", hash = "sha256:d9bdec0013ef1eb5a84ab39a3b3868911598afa494f5faa038647101504e2b81"}, ] pytest = [ - {file = "pytest-5.3.1-py3-none-any.whl", hash = "sha256:63344a2e3bce2e4d522fd62b4fdebb647c019f1f9e4ca075debbd13219db4418"}, - {file = "pytest-5.3.1.tar.gz", hash = "sha256:f67403f33b2b1d25a6756184077394167fe5e2f9d8bdaab30707d19ccec35427"}, + {file = "pytest-6.2.5-py3-none-any.whl", hash = "sha256:7310f8d27bc79ced999e760ca304d69f6ba6c6649c0b60fb0e04a4a77cacc134"}, + {file = "pytest-6.2.5.tar.gz", hash = "sha256:131b36680866a76e6781d13f101efb86cf674ebb9762eb70d3082b6f29889e89"}, ] pytest-asyncio = [ - {file = "pytest-asyncio-0.10.0.tar.gz", hash = "sha256:9fac5100fd716cbecf6ef89233e8590a4ad61d729d1732e0a96b84182df1daaf"}, - {file = "pytest_asyncio-0.10.0-py3-none-any.whl", hash = "sha256:d734718e25cfc32d2bf78d346e99d33724deeba774cc4afdf491530c6184b63b"}, + {file = "pytest-asyncio-0.16.0.tar.gz", hash = "sha256:7496c5977ce88c34379df64a66459fe395cd05543f0a2f837016e7144391fcfb"}, + {file = "pytest_asyncio-0.16.0-py3-none-any.whl", hash = "sha256:5f2a21273c47b331ae6aa5b36087047b4899e40f03f18397c0e65fa5cca54e9b"}, ] pytest-benchmark = [ - {file = "pytest-benchmark-3.2.2.tar.gz", hash = "sha256:4512c6805318d07926efcb3b39f7b98a10d035305a93edfd5329c86cbf9cfbf7"}, - {file = "pytest_benchmark-3.2.2-py2.py3-none-any.whl", hash = "sha256:ab851115ce022639173b9497d4a4183a1d8fe9cdcf8fab9d8a57607008aedd3d"}, + {file = "pytest-benchmark-3.4.1.tar.gz", hash = "sha256:40e263f912de5a81d891619032983557d62a3d85843f9a9f30b98baea0cd7b47"}, + {file = "pytest_benchmark-3.4.1-py2.py3-none-any.whl", hash = "sha256:36d2b08c4882f6f997fd3126a3d6dfd70f3249cde178ed8bbc0b73db7c20f809"}, ] pytest-cov = [ - {file = "pytest-cov-2.8.1.tar.gz", hash = "sha256:cc6742d8bac45070217169f5f72ceee1e0e55b0221f54bcf24845972d3a47f2b"}, - {file = "pytest_cov-2.8.1-py2.py3-none-any.whl", hash = "sha256:cdbdef4f870408ebdbfeb44e63e07eb18bb4619fae852f6e760645fa36172626"}, + {file = "pytest-cov-3.0.0.tar.gz", hash = "sha256:e7f0f5b1617d2210a2cabc266dfe2f4c75a8d32fb89eafb7ad9d06f6d076d470"}, + {file = "pytest_cov-3.0.0-py3-none-any.whl", hash = "sha256:578d5d15ac4a25e5f961c938b85a05b09fdaae9deef3bb6de9a6e766622ca7a6"}, ] pytest-describe = [ - {file = "pytest-describe-0.12.0.tar.gz", hash = "sha256:569bda96401fe512f4f345f33fd23fa4d718639d42afac62bc03254b5f2b3fdf"}, + {file = "pytest-describe-2.0.1.tar.gz", hash = "sha256:e5cbaa31169f0060348ad5ca0191027e5f1f41f3f27fdeef208365e09c55eb9a"}, + {file = "pytest_describe-2.0.1-py3-none-any.whl", hash = "sha256:ea347838bdf774b498ee7cb4a0b802a40be89e667a399fb63d860e3223bf4183"}, ] pytz = [ - {file = "pytz-2019.3-py2.py3-none-any.whl", hash = "sha256:1c557d7d0e871de1f5ccd5833f60fb2550652da6be2693c1e02300743d21500d"}, - {file = "pytz-2019.3.tar.gz", hash = "sha256:b02c06db6cf09c12dd25137e563b31700d3b80fcc4ad23abb7a315f2789819be"}, -] -pyyaml = [ - {file = "PyYAML-5.1.2-cp27-cp27m-win32.whl", hash = "sha256:5124373960b0b3f4aa7df1707e63e9f109b5263eca5976c66e08b1c552d4eaf8"}, - {file = "PyYAML-5.1.2-cp27-cp27m-win_amd64.whl", hash = "sha256:f81025eddd0327c7d4cfe9b62cf33190e1e736cc6e97502b3ec425f574b3e7a8"}, - {file = "PyYAML-5.1.2-cp34-cp34m-win32.whl", hash = "sha256:0113bc0ec2ad727182326b61326afa3d1d8280ae1122493553fd6f4397f33df9"}, - {file = "PyYAML-5.1.2-cp34-cp34m-win_amd64.whl", hash = "sha256:5ca4f10adbddae56d824b2c09668e91219bb178a1eee1faa56af6f99f11bf696"}, - {file = "PyYAML-5.1.2-cp35-cp35m-win32.whl", hash = "sha256:bf47c0607522fdbca6c9e817a6e81b08491de50f3766a7a0e6a5be7905961b41"}, - {file = "PyYAML-5.1.2-cp35-cp35m-win_amd64.whl", hash = "sha256:87ae4c829bb25b9fe99cf71fbb2140c448f534e24c998cc60f39ae4f94396a73"}, - {file = "PyYAML-5.1.2-cp36-cp36m-win32.whl", hash = "sha256:9de9919becc9cc2ff03637872a440195ac4241c80536632fffeb6a1e25a74299"}, - {file = "PyYAML-5.1.2-cp36-cp36m-win_amd64.whl", hash = "sha256:a5a85b10e450c66b49f98846937e8cfca1db3127a9d5d1e31ca45c3d0bef4c5b"}, - {file = "PyYAML-5.1.2-cp37-cp37m-win32.whl", hash = "sha256:b0997827b4f6a7c286c01c5f60384d218dca4ed7d9efa945c3e1aa623d5709ae"}, - {file = "PyYAML-5.1.2-cp37-cp37m-win_amd64.whl", hash = "sha256:7907be34ffa3c5a32b60b95f4d95ea25361c951383a894fec31be7252b2b6f34"}, - {file = "PyYAML-5.1.2-cp38-cp38m-win32.whl", hash = "sha256:7ec9b2a4ed5cad025c2278a1e6a19c011c80a3caaac804fd2d329e9cc2c287c9"}, - {file = "PyYAML-5.1.2-cp38-cp38m-win_amd64.whl", hash = "sha256:b631ef96d3222e62861443cc89d6563ba3eeb816eeb96b2629345ab795e53681"}, - {file = "PyYAML-5.1.2.tar.gz", hash = "sha256:01adf0b6c6f61bd11af6e10ca52b7d4057dd0be0343eb9283c878cf3af56aee4"}, + {file = "pytz-2021.3-py2.py3-none-any.whl", hash = "sha256:3672058bc3453457b622aab7a1c3bfd5ab0bdae451512f6cf25f64ed37f5b87c"}, + {file = "pytz-2021.3.tar.gz", hash = "sha256:acad2d8b20a1af07d4e4c9d2e9285c5ed9104354062f275f3fcd88dcef4f1326"}, ] regex = [ - {file = "regex-2019.11.1-cp27-none-win32.whl", hash = "sha256:604dc563a02a74d70ae1f55208ddc9bfb6d9f470f6d1a5054c4bd5ae58744ab1"}, - {file = "regex-2019.11.1-cp27-none-win_amd64.whl", hash = "sha256:5e00f65cc507d13ab4dfa92c1232d004fa202c1d43a32a13940ab8a5afe2fb96"}, - {file = "regex-2019.11.1-cp35-none-win32.whl", hash = "sha256:15454b37c5a278f46f7aa2d9339bda450c300617ca2fca6558d05d870245edc7"}, - {file = "regex-2019.11.1-cp35-none-win_amd64.whl", hash = "sha256:d2b302f8cdd82c8f48e9de749d1d17f85ce9a0f082880b9a4859f66b07037dc6"}, - {file = "regex-2019.11.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:b4e0406d822aa4993ac45072a584d57aa4931cf8288b5455bbf30c1d59dbad59"}, - {file = "regex-2019.11.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:7faf534c1841c09d8fefa60ccde7b9903c9b528853ecf41628689793290ca143"}, - {file = "regex-2019.11.1-cp36-none-win32.whl", hash = "sha256:7caf47e4a9ac6ef08cabd3442cc4ca3386db141fb3c8b2a7e202d0470028e910"}, - {file = "regex-2019.11.1-cp36-none-win_amd64.whl", hash = "sha256:e3d8dd0ec0ea280cf89026b0898971f5750a7bd92cb62c51af5a52abd020054a"}, - {file = "regex-2019.11.1-cp37-none-win32.whl", hash = "sha256:c31eaf28c6fe75ea329add0022efeed249e37861c19681960f99bbc7db981fb2"}, - {file = "regex-2019.11.1-cp37-none-win_amd64.whl", hash = "sha256:1ad40708c255943a227e778b022c6497c129ad614bb7a2a2f916e12e8a359ee7"}, - {file = "regex-2019.11.1-cp38-none-win32.whl", hash = "sha256:ec032cbfed59bd5a4b8eab943c310acfaaa81394e14f44454ad5c9eba4f24a74"}, - {file = "regex-2019.11.1-cp38-none-win_amd64.whl", hash = "sha256:c7393597191fc2043c744db021643549061e12abe0b3ff5c429d806de7b93b66"}, - {file = "regex-2019.11.1.tar.gz", hash = "sha256:720e34a539a76a1fedcebe4397290604cc2bdf6f81eca44adb9fb2ea071c0c69"}, + {file = "regex-2021.11.10-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9345b6f7ee578bad8e475129ed40123d265464c4cfead6c261fd60fc9de00bcf"}, + {file = "regex-2021.11.10-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:416c5f1a188c91e3eb41e9c8787288e707f7d2ebe66e0a6563af280d9b68478f"}, + {file = "regex-2021.11.10-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e0538c43565ee6e703d3a7c3bdfe4037a5209250e8502c98f20fea6f5fdf2965"}, + {file = "regex-2021.11.10-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7ee1227cf08b6716c85504aebc49ac827eb88fcc6e51564f010f11a406c0a667"}, + {file = "regex-2021.11.10-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6650f16365f1924d6014d2ea770bde8555b4a39dc9576abb95e3cd1ff0263b36"}, + {file = "regex-2021.11.10-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:30ab804ea73972049b7a2a5c62d97687d69b5a60a67adca07eb73a0ddbc9e29f"}, + {file = "regex-2021.11.10-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:68a067c11463de2a37157930d8b153005085e42bcb7ad9ca562d77ba7d1404e0"}, + {file = "regex-2021.11.10-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:162abfd74e88001d20cb73ceaffbfe601469923e875caf9118333b1a4aaafdc4"}, + {file = "regex-2021.11.10-cp310-cp310-win32.whl", hash = "sha256:98ba568e8ae26beb726aeea2273053c717641933836568c2a0278a84987b2a1a"}, + {file = "regex-2021.11.10-cp310-cp310-win_amd64.whl", hash = "sha256:780b48456a0f0ba4d390e8b5f7c661fdd218934388cde1a974010a965e200e12"}, + {file = "regex-2021.11.10-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:dba70f30fd81f8ce6d32ddeef37d91c8948e5d5a4c63242d16a2b2df8143aafc"}, + {file = "regex-2021.11.10-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e1f54b9b4b6c53369f40028d2dd07a8c374583417ee6ec0ea304e710a20f80a0"}, + {file = "regex-2021.11.10-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fbb9dc00e39f3e6c0ef48edee202f9520dafb233e8b51b06b8428cfcb92abd30"}, + {file = "regex-2021.11.10-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:666abff54e474d28ff42756d94544cdfd42e2ee97065857413b72e8a2d6a6345"}, + {file = "regex-2021.11.10-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5537f71b6d646f7f5f340562ec4c77b6e1c915f8baae822ea0b7e46c1f09b733"}, + {file = "regex-2021.11.10-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ed2e07c6a26ed4bea91b897ee2b0835c21716d9a469a96c3e878dc5f8c55bb23"}, + {file = "regex-2021.11.10-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ca5f18a75e1256ce07494e245cdb146f5a9267d3c702ebf9b65c7f8bd843431e"}, + {file = "regex-2021.11.10-cp36-cp36m-win32.whl", hash = "sha256:93a5051fcf5fad72de73b96f07d30bc29665697fb8ecdfbc474f3452c78adcf4"}, + {file = "regex-2021.11.10-cp36-cp36m-win_amd64.whl", hash = "sha256:b483c9d00a565633c87abd0aaf27eb5016de23fed952e054ecc19ce32f6a9e7e"}, + {file = "regex-2021.11.10-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:fff55f3ce50a3ff63ec8e2a8d3dd924f1941b250b0aac3d3d42b687eeff07a8e"}, + {file = "regex-2021.11.10-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e32d2a2b02ccbef10145df9135751abea1f9f076e67a4e261b05f24b94219e36"}, + {file = "regex-2021.11.10-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:53db2c6be8a2710b359bfd3d3aa17ba38f8aa72a82309a12ae99d3c0c3dcd74d"}, + {file = "regex-2021.11.10-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2207ae4f64ad3af399e2d30dde66f0b36ae5c3129b52885f1bffc2f05ec505c8"}, + {file = "regex-2021.11.10-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d5ca078bb666c4a9d1287a379fe617a6dccd18c3e8a7e6c7e1eb8974330c626a"}, + {file = "regex-2021.11.10-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dd33eb9bdcfbabab3459c9ee651d94c842bc8a05fabc95edf4ee0c15a072495e"}, + {file = "regex-2021.11.10-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:05b7d6d7e64efe309972adab77fc2af8907bb93217ec60aa9fe12a0dad35874f"}, + {file = "regex-2021.11.10-cp37-cp37m-win32.whl", hash = "sha256:e71255ba42567d34a13c03968736c5d39bb4a97ce98188fafb27ce981115beec"}, + {file = "regex-2021.11.10-cp37-cp37m-win_amd64.whl", hash = "sha256:07856afef5ffcc052e7eccf3213317fbb94e4a5cd8177a2caa69c980657b3cb4"}, + {file = "regex-2021.11.10-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ba05430e819e58544e840a68b03b28b6d328aff2e41579037e8bab7653b37d83"}, + {file = "regex-2021.11.10-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7f301b11b9d214f83ddaf689181051e7f48905568b0c7017c04c06dfd065e244"}, + {file = "regex-2021.11.10-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aaa4e0705ef2b73dd8e36eeb4c868f80f8393f5f4d855e94025ce7ad8525f50"}, + {file = "regex-2021.11.10-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:788aef3549f1924d5c38263104dae7395bf020a42776d5ec5ea2b0d3d85d6646"}, + {file = "regex-2021.11.10-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f8af619e3be812a2059b212064ea7a640aff0568d972cd1b9e920837469eb3cb"}, + {file = "regex-2021.11.10-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85bfa6a5413be0ee6c5c4a663668a2cad2cbecdee367630d097d7823041bdeec"}, + {file = "regex-2021.11.10-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f23222527b307970e383433daec128d769ff778d9b29343fb3496472dc20dabe"}, + {file = "regex-2021.11.10-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:da1a90c1ddb7531b1d5ff1e171b4ee61f6345119be7351104b67ff413843fe94"}, + {file = "regex-2021.11.10-cp38-cp38-win32.whl", hash = "sha256:0617383e2fe465732af4509e61648b77cbe3aee68b6ac8c0b6fe934db90be5cc"}, + {file = "regex-2021.11.10-cp38-cp38-win_amd64.whl", hash = "sha256:a3feefd5e95871872673b08636f96b61ebef62971eab044f5124fb4dea39919d"}, + {file = "regex-2021.11.10-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f7f325be2804246a75a4f45c72d4ce80d2443ab815063cdf70ee8fb2ca59ee1b"}, + {file = "regex-2021.11.10-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:537ca6a3586931b16a85ac38c08cc48f10fc870a5b25e51794c74df843e9966d"}, + {file = "regex-2021.11.10-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eef2afb0fd1747f33f1ee3e209bce1ed582d1896b240ccc5e2697e3275f037c7"}, + {file = "regex-2021.11.10-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:432bd15d40ed835a51617521d60d0125867f7b88acf653e4ed994a1f8e4995dc"}, + {file = "regex-2021.11.10-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b43c2b8a330a490daaef5a47ab114935002b13b3f9dc5da56d5322ff218eeadb"}, + {file = "regex-2021.11.10-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:962b9a917dd7ceacbe5cd424556914cb0d636001e393b43dc886ba31d2a1e449"}, + {file = "regex-2021.11.10-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fa8c626d6441e2d04b6ee703ef2d1e17608ad44c7cb75258c09dd42bacdfc64b"}, + {file = "regex-2021.11.10-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:3c5fb32cc6077abad3bbf0323067636d93307c9fa93e072771cf9a64d1c0f3ef"}, + {file = "regex-2021.11.10-cp39-cp39-win32.whl", hash = "sha256:3b5df18db1fccd66de15aa59c41e4f853b5df7550723d26aa6cb7f40e5d9da5a"}, + {file = "regex-2021.11.10-cp39-cp39-win_amd64.whl", hash = "sha256:83ee89483672b11f8952b158640d0c0ff02dc43d9cb1b70c1564b49abe92ce29"}, + {file = "regex-2021.11.10.tar.gz", hash = "sha256:f341ee2df0999bfdf7a95e448075effe0db212a59387de1a70690e4acb03d4c6"}, ] requests = [ - {file = "requests-2.22.0-py2.py3-none-any.whl", hash = "sha256:9cf5292fcd0f598c671cfc1e0d7d1a7f13bb8085e9a590f48c010551dc6c4b31"}, - {file = "requests-2.22.0.tar.gz", hash = "sha256:11e007a8a2aa0323f5a921e9e6a2d7e4e67d9877e85773fba9ba6419025cbeb4"}, + {file = "requests-2.26.0-py2.py3-none-any.whl", hash = "sha256:6c1246513ecd5ecd4528a0906f910e8f0f9c6b8ec72030dc9fd154dc1a6efd24"}, + {file = "requests-2.26.0.tar.gz", hash = "sha256:b8aa58f8cf793ffd8782d3d8cb19e66ef36f7aba4353eec859e74678b01b07a7"}, ] six = [ - {file = "six-1.13.0-py2.py3-none-any.whl", hash = "sha256:1f1b7d42e254082a9db6279deae68afb421ceba6158efa6131de7b3003ee93fd"}, - {file = "six-1.13.0.tar.gz", hash = "sha256:30f610279e8b2578cab6db20741130331735c781b56053c59c4076da27f06b66"}, + {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, + {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, ] snowballstemmer = [ - {file = "snowballstemmer-2.0.0-py2.py3-none-any.whl", hash = "sha256:209f257d7533fdb3cb73bdbd24f436239ca3b2fa67d56f6ff88e86be08cc5ef0"}, - {file = "snowballstemmer-2.0.0.tar.gz", hash = "sha256:df3bac3df4c2c01363f3dd2cfa78cce2840a79b9f1c2d2de9ce8d31683992f52"}, + {file = "snowballstemmer-2.2.0-py2.py3-none-any.whl", hash = "sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a"}, + {file = "snowballstemmer-2.2.0.tar.gz", hash = "sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1"}, ] sphinx = [ - {file = "Sphinx-2.2.1-py3-none-any.whl", hash = "sha256:52286a0b9d7caa31efee301ec4300dbdab23c3b05da1c9024b4e84896fb73d79"}, - {file = "Sphinx-2.2.1.tar.gz", hash = "sha256:31088dfb95359384b1005619827eaee3056243798c62724fd3fa4b84ee4d71bd"}, + {file = "Sphinx-2.4.5-py3-none-any.whl", hash = "sha256:02d7e9dc5f30caa42a682b26de408b755a55c7b07f356a30a3b6300bf7d4740e"}, + {file = "Sphinx-2.4.5.tar.gz", hash = "sha256:b00394e90463e7482c4cf59e7db1c8604baeca1468abfc062904dedc1cea6fcc"}, ] sphinx-rtd-theme = [ - {file = "sphinx_rtd_theme-0.4.3-py2.py3-none-any.whl", hash = "sha256:00cf895504a7895ee433807c62094cf1e95f065843bf3acd17037c3e9a2becd4"}, - {file = "sphinx_rtd_theme-0.4.3.tar.gz", hash = "sha256:728607e34d60456d736cc7991fd236afb828b21b82f956c5ea75f94c8414040a"}, + {file = "sphinx_rtd_theme-0.5.2-py2.py3-none-any.whl", hash = "sha256:4a05bdbe8b1446d77a01e20a23ebc6777c74f43237035e76be89699308987d6f"}, + {file = "sphinx_rtd_theme-0.5.2.tar.gz", hash = "sha256:32bd3b5d13dc8186d7a42fc816a23d32e83a4827d7d9882948e7b837c232da5a"}, ] sphinxcontrib-applehelp = [ - {file = "sphinxcontrib-applehelp-1.0.1.tar.gz", hash = "sha256:edaa0ab2b2bc74403149cb0209d6775c96de797dfd5b5e2a71981309efab3897"}, - {file = "sphinxcontrib_applehelp-1.0.1-py2.py3-none-any.whl", hash = "sha256:fb8dee85af95e5c30c91f10e7eb3c8967308518e0f7488a2828ef7bc191d0d5d"}, + {file = "sphinxcontrib-applehelp-1.0.2.tar.gz", hash = "sha256:a072735ec80e7675e3f432fcae8610ecf509c5f1869d17e2eecff44389cdbc58"}, + {file = "sphinxcontrib_applehelp-1.0.2-py2.py3-none-any.whl", hash = "sha256:806111e5e962be97c29ec4c1e7fe277bfd19e9652fb1a4392105b43e01af885a"}, ] sphinxcontrib-devhelp = [ - {file = "sphinxcontrib-devhelp-1.0.1.tar.gz", hash = "sha256:6c64b077937330a9128a4da74586e8c2130262f014689b4b89e2d08ee7294a34"}, - {file = "sphinxcontrib_devhelp-1.0.1-py2.py3-none-any.whl", hash = "sha256:9512ecb00a2b0821a146736b39f7aeb90759834b07e81e8cc23a9c70bacb9981"}, + {file = "sphinxcontrib-devhelp-1.0.2.tar.gz", hash = "sha256:ff7f1afa7b9642e7060379360a67e9c41e8f3121f2ce9164266f61b9f4b338e4"}, + {file = "sphinxcontrib_devhelp-1.0.2-py2.py3-none-any.whl", hash = "sha256:8165223f9a335cc1af7ffe1ed31d2871f325254c0423bc0c4c7cd1c1e4734a2e"}, ] sphinxcontrib-htmlhelp = [ - {file = "sphinxcontrib-htmlhelp-1.0.2.tar.gz", hash = "sha256:4670f99f8951bd78cd4ad2ab962f798f5618b17675c35c5ac3b2132a14ea8422"}, - {file = "sphinxcontrib_htmlhelp-1.0.2-py2.py3-none-any.whl", hash = "sha256:d4fd39a65a625c9df86d7fa8a2d9f3cd8299a3a4b15db63b50aac9e161d8eff7"}, + {file = "sphinxcontrib-htmlhelp-2.0.0.tar.gz", hash = "sha256:f5f8bb2d0d629f398bf47d0d69c07bc13b65f75a81ad9e2f71a63d4b7a2f6db2"}, + {file = "sphinxcontrib_htmlhelp-2.0.0-py2.py3-none-any.whl", hash = "sha256:d412243dfb797ae3ec2b59eca0e52dac12e75a241bf0e4eb861e450d06c6ed07"}, ] sphinxcontrib-jsmath = [ {file = "sphinxcontrib-jsmath-1.0.1.tar.gz", hash = "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8"}, {file = "sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl", hash = "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178"}, ] sphinxcontrib-qthelp = [ - {file = "sphinxcontrib-qthelp-1.0.2.tar.gz", hash = "sha256:79465ce11ae5694ff165becda529a600c754f4bc459778778c7017374d4d406f"}, - {file = "sphinxcontrib_qthelp-1.0.2-py2.py3-none-any.whl", hash = "sha256:513049b93031beb1f57d4daea74068a4feb77aa5630f856fcff2e50de14e9a20"}, + {file = "sphinxcontrib-qthelp-1.0.3.tar.gz", hash = "sha256:4c33767ee058b70dba89a6fc5c1892c0d57a54be67ddd3e7875a18d14cba5a72"}, + {file = "sphinxcontrib_qthelp-1.0.3-py2.py3-none-any.whl", hash = "sha256:bd9fc24bcb748a8d51fd4ecaade681350aa63009a347a8c14e637895444dfab6"}, ] sphinxcontrib-serializinghtml = [ - {file = "sphinxcontrib-serializinghtml-1.1.3.tar.gz", hash = "sha256:c0efb33f8052c04fd7a26c0a07f1678e8512e0faec19f4aa8f2473a8b81d5227"}, - {file = "sphinxcontrib_serializinghtml-1.1.3-py2.py3-none-any.whl", hash = "sha256:db6615af393650bf1151a6cd39120c29abaf93cc60db8c48eb2dddbfdc3a9768"}, + {file = "sphinxcontrib-serializinghtml-1.1.5.tar.gz", hash = "sha256:aa5f6de5dfdf809ef505c4895e51ef5c9eac17d0f287933eb49ec495280b6952"}, + {file = "sphinxcontrib_serializinghtml-1.1.5-py2.py3-none-any.whl", hash = "sha256:352a9a00ae864471d3a7ead8d7d79f5fc0b57e8b3f95e9867eb9eb28999b92fd"}, ] toml = [ - {file = "toml-0.10.0-py2.7.egg", hash = "sha256:f1db651f9657708513243e61e6cc67d101a39bad662eaa9b5546f789338e07a3"}, - {file = "toml-0.10.0-py2.py3-none-any.whl", hash = "sha256:235682dd292d5899d361a811df37e04a8828a5b1da3115886b73cf81ebc9100e"}, - {file = "toml-0.10.0.tar.gz", hash = "sha256:229f81c57791a41d65e399fc06bf0848bab550a9dfd5ed66df18ce5f05e73d5c"}, + {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, + {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, +] +tomli = [ + {file = "tomli-1.2.3-py3-none-any.whl", hash = "sha256:e3069e4be3ead9668e21cb9b074cd948f7b3113fd9c8bba083f48247aab8b11c"}, + {file = "tomli-1.2.3.tar.gz", hash = "sha256:05b6166bff487dc068d322585c7ea4ef78deed501cc124060e0f238e89a9231f"}, ] tox = [ - {file = "tox-3.14.1-py2.py3-none-any.whl", hash = "sha256:1d1368ac86e8332f79e2bcef9fefe2b077469f08449eadf0183759b34f3b2070"}, - {file = "tox-3.14.1.tar.gz", hash = "sha256:bcfa3e40abc1e9b70607b56adfd976fe7dc8286ad56aab44e3151daca7d2d0d0"}, + {file = "tox-3.24.5-py2.py3-none-any.whl", hash = "sha256:be3362472a33094bce26727f5f771ca0facf6dafa217f65875314e9a6600c95c"}, + {file = "tox-3.24.5.tar.gz", hash = "sha256:67e0e32c90e278251fea45b696d0fef3879089ccbe979b0c556d35d5a70e2993"}, ] typed-ast = [ - {file = "typed_ast-1.4.0-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:262c247a82d005e43b5b7f69aff746370538e176131c32dda9cb0f324d27141e"}, - {file = "typed_ast-1.4.0-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:71211d26ffd12d63a83e079ff258ac9d56a1376a25bc80b1cdcdf601b855b90b"}, - {file = "typed_ast-1.4.0-cp35-cp35m-win32.whl", hash = "sha256:630968c5cdee51a11c05a30453f8cd65e0cc1d2ad0d9192819df9978984529f4"}, - {file = "typed_ast-1.4.0-cp35-cp35m-win_amd64.whl", hash = "sha256:ffde2fbfad571af120fcbfbbc61c72469e72f550d676c3342492a9dfdefb8f12"}, - {file = "typed_ast-1.4.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:4e0b70c6fc4d010f8107726af5fd37921b666f5b31d9331f0bd24ad9a088e631"}, - {file = "typed_ast-1.4.0-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:bc6c7d3fa1325a0c6613512a093bc2a2a15aeec350451cbdf9e1d4bffe3e3233"}, - {file = "typed_ast-1.4.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:cc34a6f5b426748a507dd5d1de4c1978f2eb5626d51326e43280941206c209e1"}, - {file = "typed_ast-1.4.0-cp36-cp36m-win32.whl", hash = "sha256:d896919306dd0aa22d0132f62a1b78d11aaf4c9fc5b3410d3c666b818191630a"}, - {file = "typed_ast-1.4.0-cp36-cp36m-win_amd64.whl", hash = "sha256:354c16e5babd09f5cb0ee000d54cfa38401d8b8891eefa878ac772f827181a3c"}, - {file = "typed_ast-1.4.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:95bd11af7eafc16e829af2d3df510cecfd4387f6453355188342c3e79a2ec87a"}, - {file = "typed_ast-1.4.0-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:18511a0b3e7922276346bcb47e2ef9f38fb90fd31cb9223eed42c85d1312344e"}, - {file = "typed_ast-1.4.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:d7c45933b1bdfaf9f36c579671fec15d25b06c8398f113dab64c18ed1adda01d"}, - {file = "typed_ast-1.4.0-cp37-cp37m-win32.whl", hash = "sha256:d755f03c1e4a51e9b24d899561fec4ccaf51f210d52abdf8c07ee2849b212a36"}, - {file = "typed_ast-1.4.0-cp37-cp37m-win_amd64.whl", hash = "sha256:2b907eb046d049bcd9892e3076c7a6456c93a25bebfe554e931620c90e6a25b0"}, - {file = "typed_ast-1.4.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:fdc1c9bbf79510b76408840e009ed65958feba92a88833cdceecff93ae8fff66"}, - {file = "typed_ast-1.4.0-cp38-cp38-manylinux1_i686.whl", hash = "sha256:7954560051331d003b4e2b3eb822d9dd2e376fa4f6d98fee32f452f52dd6ebb2"}, - {file = "typed_ast-1.4.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:48e5b1e71f25cfdef98b013263a88d7145879fbb2d5185f2a0c79fa7ebbeae47"}, - {file = "typed_ast-1.4.0-cp38-cp38-win32.whl", hash = "sha256:1170afa46a3799e18b4c977777ce137bb53c7485379d9706af8a59f2ea1aa161"}, - {file = "typed_ast-1.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:838997f4310012cf2e1ad3803bce2f3402e9ffb71ded61b5ee22617b3a7f6b6e"}, - {file = "typed_ast-1.4.0.tar.gz", hash = "sha256:66480f95b8167c9c5c5c87f32cf437d585937970f3fc24386f313a4c97b44e34"}, + {file = "typed_ast-1.5.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5d8314c92414ce7481eee7ad42b353943679cf6f30237b5ecbf7d835519e1212"}, + {file = "typed_ast-1.5.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b53ae5de5500529c76225d18eeb060efbcec90ad5e030713fe8dab0fb4531631"}, + {file = "typed_ast-1.5.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:24058827d8f5d633f97223f5148a7d22628099a3d2efe06654ce872f46f07cdb"}, + {file = "typed_ast-1.5.1-cp310-cp310-win_amd64.whl", hash = "sha256:a6d495c1ef572519a7bac9534dbf6d94c40e5b6a608ef41136133377bba4aa08"}, + {file = "typed_ast-1.5.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:de4ecae89c7d8b56169473e08f6bfd2df7f95015591f43126e4ea7865928677e"}, + {file = "typed_ast-1.5.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:256115a5bc7ea9e665c6314ed6671ee2c08ca380f9d5f130bd4d2c1f5848d695"}, + {file = "typed_ast-1.5.1-cp36-cp36m-win_amd64.whl", hash = "sha256:7c42707ab981b6cf4b73490c16e9d17fcd5227039720ca14abe415d39a173a30"}, + {file = "typed_ast-1.5.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:71dcda943a471d826ea930dd449ac7e76db7be778fcd722deb63642bab32ea3f"}, + {file = "typed_ast-1.5.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:4f30a2bcd8e68adbb791ce1567fdb897357506f7ea6716f6bbdd3053ac4d9471"}, + {file = "typed_ast-1.5.1-cp37-cp37m-win_amd64.whl", hash = "sha256:ca9e8300d8ba0b66d140820cf463438c8e7b4cdc6fd710c059bfcfb1531d03fb"}, + {file = "typed_ast-1.5.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9caaf2b440efb39ecbc45e2fabde809cbe56272719131a6318fd9bf08b58e2cb"}, + {file = "typed_ast-1.5.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c9bcad65d66d594bffab8575f39420fe0ee96f66e23c4d927ebb4e24354ec1af"}, + {file = "typed_ast-1.5.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:591bc04e507595887160ed7aa8d6785867fb86c5793911be79ccede61ae96f4d"}, + {file = "typed_ast-1.5.1-cp38-cp38-win_amd64.whl", hash = "sha256:a80d84f535642420dd17e16ae25bb46c7f4c16ee231105e7f3eb43976a89670a"}, + {file = "typed_ast-1.5.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:38cf5c642fa808300bae1281460d4f9b7617cf864d4e383054a5ef336e344d32"}, + {file = "typed_ast-1.5.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5b6ab14c56bc9c7e3c30228a0a0b54b915b1579613f6e463ba6f4eb1382e7fd4"}, + {file = "typed_ast-1.5.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a2b8d7007f6280e36fa42652df47087ac7b0a7d7f09f9468f07792ba646aac2d"}, + {file = "typed_ast-1.5.1-cp39-cp39-win_amd64.whl", hash = "sha256:b6d17f37f6edd879141e64a5db17b67488cfeffeedad8c5cec0392305e9bc775"}, + {file = "typed_ast-1.5.1.tar.gz", hash = "sha256:484137cab8ecf47e137260daa20bafbba5f4e3ec7fda1c1e69ab299b75fa81c5"}, ] typing-extensions = [ - {file = "typing_extensions-3.7.4.1-py2-none-any.whl", hash = "sha256:910f4656f54de5993ad9304959ce9bb903f90aadc7c67a0bef07e678014e892d"}, - {file = "typing_extensions-3.7.4.1-py3-none-any.whl", hash = "sha256:cf8b63fedea4d89bab840ecbb93e75578af28f76f66c35889bd7065f5af88575"}, - {file = "typing_extensions-3.7.4.1.tar.gz", hash = "sha256:091ecc894d5e908ac75209f10d5b4f118fbdb2eb1ede6a63544054bb1edb41f2"}, + {file = "typing_extensions-4.0.1-py3-none-any.whl", hash = "sha256:7f001e5ac290a0c0401508864c7ec868be4e701886d5b573a9528ed3973d9d3b"}, + {file = "typing_extensions-4.0.1.tar.gz", hash = "sha256:4ca091dea149f945ec56afb48dae714f21e8692ef22a395223bcd328961b6a0e"}, ] urllib3 = [ - {file = "urllib3-1.25.7-py2.py3-none-any.whl", hash = "sha256:a8a318824cc77d1fd4b2bec2ded92646630d7fe8619497b142c84a9e6f5a7293"}, - {file = "urllib3-1.25.7.tar.gz", hash = "sha256:f3c5fd51747d450d4dcf6f923c81f78f811aab8205fda64b0aba34a4e48b0745"}, + {file = "urllib3-1.26.7-py2.py3-none-any.whl", hash = "sha256:c4fdf4019605b6e5423637e01bc9fe4daef873709a7973e195ceba0a62bbc844"}, + {file = "urllib3-1.26.7.tar.gz", hash = "sha256:4987c65554f7a2dbf30c18fd48778ef124af6fab771a377103da0585e2336ece"}, ] virtualenv = [ - {file = "virtualenv-16.7.8-py2.py3-none-any.whl", hash = "sha256:b57776b44f91511866594e477dd10e76a6eb44439cdd7f06dcd30ba4c5bd854f"}, - {file = "virtualenv-16.7.8.tar.gz", hash = "sha256:116655188441670978117d0ebb6451eb6a7526f9ae0796cc0dee6bd7356909b0"}, -] -wcwidth = [ - {file = "wcwidth-0.1.7-py2.py3-none-any.whl", hash = "sha256:f4ebe71925af7b40a864553f761ed559b43544f8f71746c2d756c7fe788ade7c"}, - {file = "wcwidth-0.1.7.tar.gz", hash = "sha256:3df37372226d6e63e1b1e1eda15c594bca98a22d33a23832a90998faa96bc65e"}, + {file = "virtualenv-20.11.2-py2.py3-none-any.whl", hash = "sha256:efd556cec612fd826dc7ef8ce26a6e4ba2395f494244919acd135fb5ceffa809"}, + {file = "virtualenv-20.11.2.tar.gz", hash = "sha256:7f9e9c2e878d92a434e760058780b8d67a7c5ec016a66784fe4b0d5e50a4eb5c"}, ] zipp = [ - {file = "zipp-0.6.0-py2.py3-none-any.whl", hash = "sha256:f06903e9f1f43b12d371004b4ac7b06ab39a44adc747266928ae6debfa7b3335"}, - {file = "zipp-0.6.0.tar.gz", hash = "sha256:3718b1cbcd963c7d4c5511a8240812904164b7f381b647143a89d3b98f9bcd8e"}, + {file = "zipp-3.6.0-py3-none-any.whl", hash = "sha256:9fe5ea21568a0a70e50f273397638d39b03353731e6cbbb3fd8502a33fec40bc"}, + {file = "zipp-3.6.0.tar.gz", hash = "sha256:71c644c5369f4a6e07636f0aa966270449561fcea2e3d6747b8d23efaa9d7832"}, ] diff --git a/pyproject.toml b/pyproject.toml index f7516807..2287c7d9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "graphql-core" -version = "3.0.0" +version = "3.0.6" description = """ GraphQL-core is a Python port of GraphQL.js, the JavaScript reference implementation for GraphQL.""" @@ -9,9 +9,9 @@ authors = [ "Christoph Zwerschke " ] readme = "README.md" -homepage = "https://github.com/graphql-python/graphql-core-next" -repository = "https://github.com/graphql-python/graphql-core-next" -documentation = "https://graphql-core-next.readthedocs.io/" +homepage = "https://github.com/graphql-python/graphql-core" +repository = "https://github.com/graphql-python/graphql-core" +documentation = "https://graphql-core-3.readthedocs.io/" keywords = ["graphql"] classifiers = [ "Development Status :: 5 - Production/Stable", @@ -20,7 +20,9 @@ classifiers = [ "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", - "Programming Language :: Python :: 3.8" + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", ] packages = [ { include = "graphql", from = "src" }, @@ -32,26 +34,26 @@ packages = [ python = "^3.6" [tool.poetry.dev-dependencies] -pytest = "^5.3" -pytest-asyncio = ">=0.10,<1" -pytest-benchmark = "^3.2" -pytest-cov = "^2.8" -pytest-describe = ">=0.12,<1" -pyyaml = "^5.1" -black = "19.10b0" -flake8 = "^3.7" -mypy = ">=0.750,<0.760" -codecov = "^2" -sphinx = "^2.2" +pytest = "^6.2" +pytest-asyncio = ">=0.16,<1" +pytest-benchmark = "^3.4" +pytest-cov = "^3.0" +pytest-describe = "^2.0" +black = [ + {version = "21.12b0", python = ">=3.6.2"}, + {version = "20.8b1", python = "<3.6.2"} +] +flake8 = "^4.0" +mypy = "0.930" +sphinx = "^2.4" sphinx_rtd_theme = ">=0.4,<1" -check-manifest = ">=0.40,<1" -bump2version = ">=0.5,<1" -tox = "^3.14" +check-manifest = "0.40" +bump2version = ">=1.0,<2" +tox = "^3.24" [tool.black] -target-version = ['py36', 'py37', 'py38'] +target-version = ['py36', 'py37', 'py38', 'py39', 'py310'] [build-system] -requires = ["poetry>=1.0.0b8"] +requires = ["poetry>=1,<2"] build-backend = "poetry.masonry.api" - diff --git a/setup.py b/setup.py index 3f41c272..4c15da3e 100644 --- a/setup.py +++ b/setup.py @@ -15,7 +15,7 @@ long_description=readme, long_description_content_type="text/markdown", keywords="graphql", - url="https://github.com/graphql-python/graphql-core-next", + url="https://github.com/graphql-python/graphql-core", author="Christoph Zwerschke", author_email="cito@online.de", license="MIT license", @@ -25,8 +25,12 @@ "Topic :: Software Development :: Libraries", "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", ], install_requires=[], python_requires=">=3.6,<4", diff --git a/src/graphql/__init__.py b/src/graphql/__init__.py index 7f3b929f..f7918208 100644 --- a/src/graphql/__init__.py +++ b/src/graphql/__init__.py @@ -33,7 +33,7 @@ - :mod:`graphql.execution`: The Execution phase of fulfilling a GraphQL request. - :mod:`graphql.error`: Creating and formatting GraphQL errors. - :mod:`graphql.utilities`: - Common useful computations upon the GraphQL language and type objects. + Common useful computations upon the GraphQL language and type objects. - :mod:`graphql.subscription`: Subscribe to data updates. """ @@ -285,6 +285,7 @@ # All validation rules in the GraphQL Specification. specified_rules, # Individual validation rules. + ExecutableDefinitionsRule, FieldsOnCorrectTypeRule, FragmentsOnCompositeTypesRule, KnownArgumentNamesRule, @@ -310,6 +311,14 @@ ValuesOfCorrectTypeRule, VariablesAreInputTypesRule, VariablesInAllowedPositionRule, + # SDL-specific validation rules + LoneSchemaDefinitionRule, + UniqueOperationTypesRule, + UniqueTypeNamesRule, + UniqueEnumValueNamesRule, + UniqueFieldDefinitionNamesRule, + UniqueDirectiveNamesRule, + PossibleTypeExtensionsRule, ) # Create, format, and print GraphQL errors. @@ -319,7 +328,7 @@ located_error, format_error, print_error, - INVALID, + INVALID, # deprecated in the next minor release ) # Utilities for operating on GraphQL type schema and parsed sources. @@ -390,6 +399,8 @@ find_dangerous_changes, ) +Undefined = INVALID # forward-compatible alias + # The GraphQL-core version info. __version__ = version __version_info__ = version_info @@ -606,6 +617,7 @@ "ASTValidationRule", "SDLValidationRule", "specified_rules", + "ExecutableDefinitionsRule", "FieldsOnCorrectTypeRule", "FragmentsOnCompositeTypesRule", "KnownArgumentNamesRule", @@ -631,6 +643,13 @@ "ValuesOfCorrectTypeRule", "VariablesAreInputTypesRule", "VariablesInAllowedPositionRule", + "LoneSchemaDefinitionRule", + "UniqueOperationTypesRule", + "UniqueTypeNamesRule", + "UniqueEnumValueNamesRule", + "UniqueFieldDefinitionNamesRule", + "UniqueDirectiveNamesRule", + "PossibleTypeExtensionsRule", "GraphQLError", "GraphQLSyntaxError", "located_error", @@ -671,4 +690,5 @@ "BreakingChangeType", "DangerousChange", "DangerousChangeType", + "Undefined", ] diff --git a/src/graphql/error/invalid.py b/src/graphql/error/invalid.py index b687c82a..b28d53ef 100644 --- a/src/graphql/error/invalid.py +++ b/src/graphql/error/invalid.py @@ -30,4 +30,7 @@ def __ne__(self, other): This singleton object is used to describe invalid or undefined values. It corresponds to the ``undefined`` value in GraphQL.js. + +Note: This will be considered deprecated in the next minor release. +Please use ``graphql.Undefined`` instead to create forward compatible code. """ diff --git a/src/graphql/execution/execute.py b/src/graphql/execution/execute.py index e72a7f19..520ed9dd 100644 --- a/src/graphql/execution/execute.py +++ b/src/graphql/execution/execute.py @@ -210,9 +210,7 @@ def __init__( self.type_resolver = type_resolver # type: ignore self.errors = errors self.middleware_manager = middleware_manager - self._subfields_cache: Dict[ - Tuple[GraphQLObjectType, int], Dict[str, List[FieldNode]] - ] = {} + self._subfields_cache: Dict[Tuple, Dict[str, List[FieldNode]]] = {} @classmethod def build( @@ -395,9 +393,7 @@ async def await_and_set_result(results, response_name, result): return awaited_results # noinspection PyTypeChecker - results = await_and_set_result( - cast(Awaitable, results), response_name, result - ) + results = await_and_set_result(results, response_name, result) elif isawaitable(result): # noinspection PyShadowingNames async def set_result(results, response_name, result): @@ -628,17 +624,13 @@ def resolve_field_value_or_error( async def await_result(): try: return await result - except GraphQLError as error: - return error except Exception as error: - return GraphQLError(str(error), original_error=error) + return error return await_result() return result - except GraphQLError as error: - return error except Exception as error: - return GraphQLError(str(error), original_error=error) + return error def complete_value_catching_error( self, @@ -792,7 +784,7 @@ def complete_list_value( info: GraphQLResolveInfo, path: Path, result: Iterable[Any], - ) -> AwaitableOrValue[Any]: + ) -> AwaitableOrValue[List[Any]]: """Complete a list value. Complete a list value by completing each item in the list with the inner type. @@ -887,7 +879,7 @@ async def await_complete_object_value(): result, ) if isawaitable(value): - return await value # type: ignore + return await value return value return await_complete_object_value() @@ -995,10 +987,20 @@ def collect_subfields( subfields are not repeatedly calculated, which saves overhead when resolving lists of values. """ - # Use id(field_nodes) as key, since a list cannot be hashed and - # (after conversion to a tuple) hashing nodes would be too slow: - cache_key = return_type, id(field_nodes) - sub_field_nodes = self._subfields_cache.get(cache_key) + cache = self._subfields_cache + # We cannot use the field_nodes themselves as key for the cache, since they + # are not hashable as a list. We also do not want to use the field_nodes + # themselves (converted to a tuple) as keys, since hashing them is slow. + # Therefore we use the ids of the field_nodes as keys. Note that we do not + # use the id of the list, since we want to hit the cache for all lists of + # the same nodes, not only for the same list of nodes. Also, the list id may + # even be reused, in which case we would get wrong results from the cache. + key = ( + (return_type, id(field_nodes[0])) + if len(field_nodes) == 1 # optimize most frequent case + else tuple((return_type, *map(id, field_nodes))) + ) + sub_field_nodes = cache.get(key) if sub_field_nodes is None: sub_field_nodes = {} visited_fragment_names: Set[str] = set() @@ -1011,7 +1013,7 @@ def collect_subfields( sub_field_nodes, visited_fragment_names, ) - self._subfields_cache[cache_key] = sub_field_nodes + cache[key] = sub_field_nodes return sub_field_nodes @@ -1112,7 +1114,7 @@ def default_type_resolver( is_type_of_result = type_.is_type_of(value, info) if isawaitable(is_type_of_result): - append_awaitable_results(cast(Awaitable, is_type_of_result)) + append_awaitable_results(is_type_of_result) append_awaitable_types(type_) elif is_type_of_result: return type_ @@ -1130,7 +1132,7 @@ async def get_type(): return None -def default_field_resolver(source, info, **args): +def default_field_resolver(source: Any, info: GraphQLResolveInfo, **args: Any) -> Any: """Default field resolver. If a resolve function is not given, then a default resolve behavior is used which diff --git a/src/graphql/language/visitor.py b/src/graphql/language/visitor.py index 10a3d9de..9ee9263e 100644 --- a/src/graphql/language/visitor.py +++ b/src/graphql/language/visitor.py @@ -124,7 +124,7 @@ def enter(self, node, key, parent, path, ancestors): # any other value: replace this node with the returned value return - def enter(self, node, key, parent, path, ancestors): + def leave(self, node, key, parent, path, ancestors): # The return value has the following meaning: # IDLE (None) or SKIP: no action # BREAK: stop visiting altogether @@ -174,7 +174,7 @@ def __init_subclass__(cls): raise AttributeError(f"Invalid AST node kind: {kind}") @classmethod - def get_visit_fn(cls, kind, is_leaving=False) -> Callable: + def get_visit_fn(cls, kind, is_leaving=False) -> Optional[Callable]: """Get the visit function for the given node kind and direction.""" method = "leave" if is_leaving else "enter" visit_fn = getattr(cls, f"{method}_{kind}", None) diff --git a/src/graphql/pyutils/event_emitter.py b/src/graphql/pyutils/event_emitter.py index 4d0a07b0..d91d8f8b 100644 --- a/src/graphql/pyutils/event_emitter.py +++ b/src/graphql/pyutils/event_emitter.py @@ -5,6 +5,11 @@ from collections import defaultdict +try: + from asyncio import run +except ImportError: # Python < 3.7 + run = None # type: ignore + __all__ = ["EventEmitter", "EventEmitterAsyncIterator"] @@ -44,7 +49,10 @@ class EventEmitterAsyncIterator: """ def __init__(self, event_emitter: EventEmitter, event_name: str) -> None: - self.queue: Queue = Queue(loop=cast(AbstractEventLoop, event_emitter.loop)) + if run: + self.queue: Queue = Queue() + else: # Python < 3.7 + self.queue = Queue(loop=cast(AbstractEventLoop, event_emitter.loop)) event_emitter.add_listener(event_name, self.queue.put) self.remove_listener = lambda: event_emitter.remove_listener( event_name, self.queue.put diff --git a/src/graphql/pyutils/suggestion_list.py b/src/graphql/pyutils/suggestion_list.py index 16c55c2f..94525362 100644 --- a/src/graphql/pyutils/suggestion_list.py +++ b/src/graphql/pyutils/suggestion_list.py @@ -18,7 +18,7 @@ def suggestion_list(input_: str, options: Collection[str]) -> List[str]: if distance <= threshold: options_by_distance[option] = distance - return sorted(options_by_distance, key=options_by_distance.get) + return sorted(options_by_distance, key=options_by_distance.get) # type: ignore def lexical_distance(a_str: str, b_str: str) -> int: diff --git a/src/graphql/subscription/map_async_iterator.py b/src/graphql/subscription/map_async_iterator.py index e89bf9ec..be6304ff 100644 --- a/src/graphql/subscription/map_async_iterator.py +++ b/src/graphql/subscription/map_async_iterator.py @@ -1,4 +1,4 @@ -from asyncio import Event, ensure_future, Future, wait +from asyncio import Event, ensure_future, Task, wait from concurrent.futures import FIRST_COMPLETED from inspect import isasyncgen, isawaitable from typing import AsyncIterable, Callable, Set @@ -42,7 +42,7 @@ async def __anext__(self): aclose = ensure_future(self._close_event.wait()) anext = ensure_future(self.iterator.__anext__()) - pending: Set[Future] = ( + pending: Set[Task] = ( await wait([aclose, anext], return_when=FIRST_COMPLETED) )[1] for task in pending: @@ -70,7 +70,7 @@ async def athrow(self, type_, value=None, traceback=None): if athrow: await athrow(type_, value, traceback) else: - self.is_closed = True + await self.aclose() if value is None: if traceback is None: raise type_ diff --git a/src/graphql/subscription/subscribe.py b/src/graphql/subscription/subscribe.py index d68cadbf..8362ded9 100644 --- a/src/graphql/subscription/subscribe.py +++ b/src/graphql/subscription/subscribe.py @@ -1,5 +1,5 @@ from inspect import isawaitable -from typing import Any, AsyncIterable, AsyncIterator, Awaitable, Dict, Union, cast +from typing import Any, AsyncIterable, AsyncIterator, Dict, Union from ..error import GraphQLError, located_error from ..execution.execute import ( @@ -81,7 +81,7 @@ async def map_source_to_response(payload) -> ExecutionResult: operation_name, field_resolver, ) - return await result if isawaitable(result) else result # type: ignore + return await result if isawaitable(result) else result return MapAsyncIterator(result_or_stream, map_source_to_response) @@ -95,7 +95,7 @@ async def create_source_event_stream( operation_name: str = None, field_resolver: GraphQLFieldResolver = None, ) -> Union[AsyncIterable[Any], ExecutionResult]: - """Create source even stream + """Create source event stream Implements the "CreateSourceEventStream" algorithm described in the GraphQL specification, resolving the subscription source event stream. @@ -162,7 +162,7 @@ async def create_source_event_stream( result = context.resolve_field_value_or_error( field_def, field_nodes, resolve_fn, root_value, info ) - event_stream = await cast(Awaitable, result) if isawaitable(result) else result + event_stream = await result if isawaitable(result) else result # If `event_stream` is an Error, rethrow a located error. if isinstance(event_stream, Exception): raise located_error(event_stream, field_nodes, path.as_list()) diff --git a/src/graphql/type/definition.py b/src/graphql/type/definition.py index 7a8a615d..20bf4ba9 100644 --- a/src/graphql/type/definition.py +++ b/src/graphql/type/definition.py @@ -593,7 +593,7 @@ def __init__( ast_node: InputValueDefinitionNode = None, ) -> None: if not is_input_type(type_): - raise TypeError(f"Argument type must be a GraphQL input type.") + raise TypeError("Argument type must be a GraphQL input type.") if description is not None and not is_description(description): raise TypeError("Argument description must be a string.") if out_name is not None and not isinstance(out_name, str): @@ -1324,7 +1324,7 @@ def __init__( ast_node: InputValueDefinitionNode = None, ) -> None: if not is_input_type(type_): - raise TypeError(f"Input field type must be a GraphQL input type.") + raise TypeError("Input field type must be a GraphQL input type.") if description is not None and not is_description(description): raise TypeError("Input field description must be a string.") if out_name is not None and not isinstance(out_name, str): diff --git a/src/graphql/type/validate.py b/src/graphql/type/validate.py index e623802b..a07910ed 100644 --- a/src/graphql/type/validate.py +++ b/src/graphql/type/validate.py @@ -201,7 +201,7 @@ def validate_types(self): # Ensure all provided types are in fact GraphQL type. if not is_named_type(type_): self.report_error( - f"Expected GraphQL named type but got: {inspect(type)}.", + f"Expected GraphQL named type but got: {inspect(type_)}.", type_.ast_node if type_ else None, ) continue @@ -256,7 +256,7 @@ def validate_fields(self, type_: Union[GraphQLObjectType, GraphQLInterfaceType]) if not is_output_type(field.type): self.report_error( f"The type of {type_.name}.{field_name}" - " must be Output Type but got: {inspect(field.type)}.", + f" must be Output Type but got: {inspect(field.type)}.", field.ast_node and field.ast_node.type, ) diff --git a/src/graphql/utilities/__init__.py b/src/graphql/utilities/__init__.py index ad0eb480..37599cab 100644 --- a/src/graphql/utilities/__init__.py +++ b/src/graphql/utilities/__init__.py @@ -5,7 +5,7 @@ """ # Produce the GraphQL query recommended for a full schema introspection. -from .get_introspection_query import get_introspection_query +from .introspection_query import get_introspection_query # Get the target Operation from a Document. from .get_operation_ast import get_operation_ast diff --git a/src/graphql/utilities/ast_from_value.py b/src/graphql/utilities/ast_from_value.py index 8f063717..7cc0aa39 100644 --- a/src/graphql/utilities/ast_from_value.py +++ b/src/graphql/utilities/ast_from_value.py @@ -1,5 +1,5 @@ import re -from typing import Any, Iterable, List, Mapping, Optional, cast +from typing import Any, Iterable, Mapping, Optional, cast from ..language import ( BooleanValueNode, @@ -14,7 +14,7 @@ StringValueNode, ValueNode, ) -from ..pyutils import inspect, is_nullish, is_invalid +from ..pyutils import FrozenList, inspect, is_nullish, is_invalid from ..type import ( GraphQLID, GraphQLInputType, @@ -71,8 +71,9 @@ def ast_from_value(value: Any, type_: GraphQLInputType) -> Optional[ValueNode]: type_ = cast(GraphQLList, type_) item_type = type_.of_type if isinstance(value, Iterable) and not isinstance(value, str): - value_nodes = [ast_from_value(item, item_type) for item in value] - return ListValueNode(values=value_nodes) + maybe_value_nodes = (ast_from_value(item, item_type) for item in value) + value_nodes = filter(None, maybe_value_nodes) + return ListValueNode(values=FrozenList(value_nodes)) return ast_from_value(value, item_type) # Populate the fields of the input object by creating ASTs from each value in the @@ -81,18 +82,17 @@ def ast_from_value(value: Any, type_: GraphQLInputType) -> Optional[ValueNode]: if value is None or not isinstance(value, Mapping): return None type_ = cast(GraphQLInputObjectType, type_) - field_nodes: List[ObjectFieldNode] = [] - append_node = field_nodes.append - for field_name, field in type_.fields.items(): - if field_name in value: - field_value = ast_from_value(value[field_name], field.type) - if field_value: - append_node( - ObjectFieldNode( - name=NameNode(value=field_name), value=field_value - ) - ) - return ObjectValueNode(fields=field_nodes) + field_items = ( + (field_name, ast_from_value(value[field_name], field.type)) + for field_name, field in type_.fields.items() + if field_name in value + ) + field_nodes = ( + ObjectFieldNode(name=NameNode(value=field_name), value=field_value) + for field_name, field_value in field_items + if field_value + ) + return ObjectValueNode(fields=FrozenList(field_nodes)) if is_leaf_type(type_): # Since value is an internally represented value, it must be serialized to an diff --git a/src/graphql/utilities/coerce_input_value.py b/src/graphql/utilities/coerce_input_value.py index 278cd85a..e57ce988 100644 --- a/src/graphql/utilities/coerce_input_value.py +++ b/src/graphql/utilities/coerce_input_value.py @@ -28,7 +28,7 @@ def default_on_error( ) -> None: error_prefix = "Invalid value " + inspect(invalid_value) if path: - error_prefix += f" at 'value{print_path_list(path)}': " + error_prefix += f" at 'value{print_path_list(path)}'" error.message = error_prefix + ": " + error.message raise error diff --git a/src/graphql/utilities/extend_schema.py b/src/graphql/utilities/extend_schema.py index b5b41e7d..917853a4 100644 --- a/src/graphql/utilities/extend_schema.py +++ b/src/graphql/utilities/extend_schema.py @@ -70,7 +70,7 @@ def extend_schema( assert_schema(schema) if not isinstance(document_ast, DocumentNode): - "Must provide valid Document AST" + raise TypeError("Must provide valid Document AST") if not (assume_valid or assume_valid_sdl): from ..validation.validate import assert_valid_sdl_extension diff --git a/src/graphql/utilities/introspection_from_schema.py b/src/graphql/utilities/introspection_from_schema.py index 818c6325..5a075ab4 100644 --- a/src/graphql/utilities/introspection_from_schema.py +++ b/src/graphql/utilities/introspection_from_schema.py @@ -3,7 +3,7 @@ from ..error import GraphQLError from ..language import parse from ..type import GraphQLSchema -from .get_introspection_query import get_introspection_query +from .introspection_query import get_introspection_query __all__ = ["introspection_from_schema"] diff --git a/src/graphql/utilities/get_introspection_query.py b/src/graphql/utilities/introspection_query.py similarity index 100% rename from src/graphql/utilities/get_introspection_query.py rename to src/graphql/utilities/introspection_query.py diff --git a/src/graphql/utilities/type_info.py b/src/graphql/utilities/type_info.py index 8dbd64a9..a5e04fc4 100644 --- a/src/graphql/utilities/type_info.py +++ b/src/graphql/utilities/type_info.py @@ -258,7 +258,7 @@ def leave_list_value(self): leave_object_field = leave_list_value - def leave_enum(self): + def leave_enum_value(self): self._enum_value = None diff --git a/src/graphql/validation/__init__.py b/src/graphql/validation/__init__.py index 664b05ca..048dc16d 100644 --- a/src/graphql/validation/__init__.py +++ b/src/graphql/validation/__init__.py @@ -95,6 +95,15 @@ # Spec Section: "All Variable Usages Are Allowed" from .rules.variables_in_allowed_position import VariablesInAllowedPositionRule +# SDL-specific validation rules +from .rules.lone_schema_definition import LoneSchemaDefinitionRule +from .rules.unique_operation_types import UniqueOperationTypesRule +from .rules.unique_type_names import UniqueTypeNamesRule +from .rules.unique_enum_value_names import UniqueEnumValueNamesRule +from .rules.unique_field_definition_names import UniqueFieldDefinitionNamesRule +from .rules.unique_directive_names import UniqueDirectiveNamesRule +from .rules.possible_type_extensions import PossibleTypeExtensionsRule + __all__ = [ "validate", "ASTValidationContext", @@ -130,4 +139,11 @@ "ValuesOfCorrectTypeRule", "VariablesAreInputTypesRule", "VariablesInAllowedPositionRule", + "LoneSchemaDefinitionRule", + "UniqueOperationTypesRule", + "UniqueTypeNamesRule", + "UniqueEnumValueNamesRule", + "UniqueFieldDefinitionNamesRule", + "UniqueDirectiveNamesRule", + "PossibleTypeExtensionsRule", ] diff --git a/src/graphql/validation/rules/known_argument_names.py b/src/graphql/validation/rules/known_argument_names.py index 178bca27..295b22b7 100644 --- a/src/graphql/validation/rules/known_argument_names.py +++ b/src/graphql/validation/rules/known_argument_names.py @@ -28,7 +28,7 @@ def unknown_directive_arg_message( arg_name: str, directive_name: str, suggested_args: List[str] ) -> str: hint = did_you_mean([f"'{s}'" for s in suggested_args]) - return f"Unknown argument '{arg_name}' on directive '@{directive_name}'. {hint}" + return f"Unknown argument '{arg_name}' on directive '@{directive_name}'.{hint}" class KnownArgumentNamesOnDirectivesRule(ASTValidationRule): diff --git a/src/graphql/validation/rules/known_directives.py b/src/graphql/validation/rules/known_directives.py index 6f54c151..8a3c5393 100644 --- a/src/graphql/validation/rules/known_directives.py +++ b/src/graphql/validation/rules/known_directives.py @@ -61,9 +61,7 @@ def enter_directive(self, node: DirectiveNode, _key, _parent, _path, ancestors): if candidate_location and candidate_location not in locations: self.report_error( GraphQLError( - misplaced_directive_message( - node.name.value, candidate_location.value - ), + misplaced_directive_message(name, candidate_location.value), node, ) ) diff --git a/src/graphql/validation/rules/possible_type_extensions.py b/src/graphql/validation/rules/possible_type_extensions.py index 5cc9b083..7bc89d5d 100644 --- a/src/graphql/validation/rules/possible_type_extensions.py +++ b/src/graphql/validation/rules/possible_type_extensions.py @@ -28,13 +28,13 @@ def extending_unknown_type_message(type_name: str, suggested_types: List[str]) - def extending_different_type_kind_message(type_name: str, kind: str) -> str: - return f"Cannot extend non-{kind} type {type_name}" + return f"Cannot extend non-{kind} type '{type_name}'." class PossibleTypeExtensionsRule(SDLValidationRule): """Possible type extension - A type extension is only valid if the type is defined and has the same kind. + A type extension is only valid if the type is defined and has the same kind. """ def __init__(self, context: SDLValidationContext) -> None: diff --git a/src/graphql/validation/rules/scalar_leafs.py b/src/graphql/validation/rules/scalar_leafs.py index 0c587fe4..a935deeb 100644 --- a/src/graphql/validation/rules/scalar_leafs.py +++ b/src/graphql/validation/rules/scalar_leafs.py @@ -12,15 +12,14 @@ def no_subselection_allowed_message(field_name: str, type_: str) -> str: return ( - f"Field '{field_name}' must not have a sub selection" + f"Field '{field_name}' must not have a selection" f" since type '{type_}' has no subfields." ) def required_subselection_message(field_name: str, type_: str) -> str: return ( - f"Field '{field_name}' of type '{type_}' must have a" - " sub selection of subfields." + f"Field '{field_name}' of type '{type_}' must have a selection of subfields." f" Did you mean '{field_name} {{ ... }}'?" ) diff --git a/src/graphql/validation/rules/unique_argument_names.py b/src/graphql/validation/rules/unique_argument_names.py index 494f56c5..b7fbfd90 100644 --- a/src/graphql/validation/rules/unique_argument_names.py +++ b/src/graphql/validation/rules/unique_argument_names.py @@ -8,7 +8,7 @@ def duplicate_arg_message(arg_name: str) -> str: - return f"There can only be one argument named '{arg_name}'." + return f"There can be only one argument named '{arg_name}'." class UniqueArgumentNamesRule(ASTValidationRule): diff --git a/src/graphql/validation/rules/unique_directives_per_location.py b/src/graphql/validation/rules/unique_directives_per_location.py index 8b170c7a..26f0e822 100644 --- a/src/graphql/validation/rules/unique_directives_per_location.py +++ b/src/graphql/validation/rules/unique_directives_per_location.py @@ -40,7 +40,7 @@ def __init__(self, context: Union[ValidationContext, SDLValidationContext]) -> N # Many different AST nodes may contain directives. Rather than listing them all, # just listen for entering any node, and check to see if it defines any directives. def enter(self, node: Node, *_args): - directives: List[DirectiveNode] = getattr(node, "directives", None) + directives = cast(List[DirectiveNode], getattr(node, "directives", None)) if directives: known_directives: Dict[str, DirectiveNode] = {} for directive in directives: diff --git a/src/graphql/validation/rules/unique_fragment_names.py b/src/graphql/validation/rules/unique_fragment_names.py index 03041613..44c8a1f3 100644 --- a/src/graphql/validation/rules/unique_fragment_names.py +++ b/src/graphql/validation/rules/unique_fragment_names.py @@ -8,7 +8,7 @@ def duplicate_fragment_name_message(frag_name: str) -> str: - return f"There can only be one fragment named '{frag_name}'." + return f"There can be only one fragment named '{frag_name}'." class UniqueFragmentNamesRule(ASTValidationRule): diff --git a/src/graphql/validation/rules/unique_input_field_names.py b/src/graphql/validation/rules/unique_input_field_names.py index 85e2e5c4..6d9effb1 100644 --- a/src/graphql/validation/rules/unique_input_field_names.py +++ b/src/graphql/validation/rules/unique_input_field_names.py @@ -8,7 +8,7 @@ def duplicate_input_field_message(field_name: str) -> str: - return f"There can only be one input field named '{field_name}'." + return f"There can be only one input field named '{field_name}'." class UniqueInputFieldNamesRule(ASTValidationRule): diff --git a/src/graphql/validation/rules/unique_operation_names.py b/src/graphql/validation/rules/unique_operation_names.py index 0a13ca62..d1efd8e8 100644 --- a/src/graphql/validation/rules/unique_operation_names.py +++ b/src/graphql/validation/rules/unique_operation_names.py @@ -8,7 +8,7 @@ def duplicate_operation_name_message(operation_name: str) -> str: - return f"There can only be one operation named '{operation_name}'." + return f"There can be only one operation named '{operation_name}'." class UniqueOperationNamesRule(ASTValidationRule): diff --git a/src/graphql/validation/rules/unique_operation_types.py b/src/graphql/validation/rules/unique_operation_types.py index 4a86de1b..7f2d7c8d 100644 --- a/src/graphql/validation/rules/unique_operation_types.py +++ b/src/graphql/validation/rules/unique_operation_types.py @@ -18,12 +18,12 @@ def duplicate_operation_type_message(operation: str) -> str: - return f"There can be only one '{operation}' type in schema." + return f"There can be only one {operation} type in schema." def existed_operation_type_message(operation: str) -> str: return ( - f"Type for '{operation}' already defined in the schema." + f"Type for {operation} already defined in the schema." " It cannot be redefined." ) diff --git a/src/graphql/validation/rules/values_of_correct_type.py b/src/graphql/validation/rules/values_of_correct_type.py index 0a19cfa3..339f99f2 100644 --- a/src/graphql/validation/rules/values_of_correct_type.py +++ b/src/graphql/validation/rules/values_of_correct_type.py @@ -32,6 +32,7 @@ __all__ = [ "ValuesOfCorrectTypeRule", "bad_value_message", + "bad_enum_value_message", "required_field_message", "unknown_field_message", ] @@ -63,7 +64,7 @@ def unknown_field_message( type_name: str, field_name: str, suggested_fields: Sequence[str] ) -> str: hint = did_you_mean(suggested_fields) - return f"Field '{field_name}'' is not defined by type {type_name}.{hint}" + return f"Field '{field_name}' is not defined by type {type_name}.{hint}" class ValuesOfCorrectTypeRule(ValidationRule): diff --git a/src/graphql/version.py b/src/graphql/version.py index ad308762..8766e7c7 100644 --- a/src/graphql/version.py +++ b/src/graphql/version.py @@ -4,9 +4,9 @@ __all__ = ["version", "version_info", "version_js", "version_info_js"] -version = "3.0.0" +version = "3.0.6" -version_js = "14.5.8" +version_js = "14.7.0" _re_version = re.compile(r"(\d+)\.(\d+)\.(\d+)(\D*)(\d*)") diff --git a/tests/benchmarks/test_introspection_from_schema.py b/tests/benchmarks/test_introspection_from_schema.py index 80c0195a..6da1e0f9 100644 --- a/tests/benchmarks/test_introspection_from_schema.py +++ b/tests/benchmarks/test_introspection_from_schema.py @@ -1,5 +1,5 @@ from graphql import build_schema, parse, execute -from graphql.utilities import get_introspection_query +from graphql.utilities import introspection_query # noinspection PyUnresolvedReferences from ..fixtures import big_schema_sdl # noqa: F401 @@ -7,6 +7,6 @@ def test_execute_introspection_query(benchmark, big_schema_sdl): # noqa: F811 schema = build_schema(big_schema_sdl, assume_valid=True) - query = parse(get_introspection_query()) + query = parse(introspection_query.get_introspection_query()) result = benchmark(lambda: execute(schema, query)) assert result.errors is None diff --git a/tests/benchmarks/test_validate_gql.py b/tests/benchmarks/test_validate_gql.py index 6b08d4b5..ea62f228 100644 --- a/tests/benchmarks/test_validate_gql.py +++ b/tests/benchmarks/test_validate_gql.py @@ -1,5 +1,5 @@ from graphql import build_schema, parse, validate -from graphql.utilities import get_introspection_query +from graphql.utilities import introspection_query # noinspection PyUnresolvedReferences from ..fixtures import big_schema_sdl # noqa: F401 @@ -7,6 +7,6 @@ def test_validate_introspection_query(benchmark, big_schema_sdl): # noqa: F811 schema = build_schema(big_schema_sdl, assume_valid=True) - query = parse(get_introspection_query()) + query = parse(introspection_query.get_introspection_query()) result = benchmark(lambda: validate(schema, query)) assert result == [] diff --git a/tests/error/test_invalid.py b/tests/error/test_invalid.py index 988a49cd..605cd5df 100644 --- a/tests/error/test_invalid.py +++ b/tests/error/test_invalid.py @@ -26,3 +26,8 @@ def only_equal_to_itself(): false_object = False assert INVALID != false_object assert not INVALID == false_object + + def forward_compatibility(): + from graphql import Undefined + + assert INVALID is Undefined diff --git a/tests/execution/test_resolve.py b/tests/execution/test_resolve.py index 189eb645..2e6607ce 100644 --- a/tests/execution/test_resolve.py +++ b/tests/execution/test_resolve.py @@ -1,4 +1,6 @@ from graphql import graphql_sync +from graphql.error import GraphQLError +from graphql.language import SourceLocation from graphql.type import ( GraphQLArgument, GraphQLField, @@ -165,3 +167,29 @@ def transforms_arguments_with_inputs_using_out_names(): }, None, ) + + def pass_error_from_resolver_wrapped_as_located_graphql_error(): + def resolve(_obj, _info): + raise ValueError("Some error") + + schema = _test_schema(GraphQLField(GraphQLString, resolve=resolve)) + result = graphql_sync(schema, "{ test }") + + assert result == ( + {"test": None}, + [{"message": "Some error", "locations": [(1, 3)], "path": ["test"]}], + ) + + assert result.errors is not None + error = result.errors[0] + assert isinstance(error, GraphQLError) + assert str(error) == "Some error\n\nGraphQL request:1:3\n1 | { test }\n | ^" + assert error.positions == [2] + locations = error.locations + assert locations == [(1, 3)] + location = locations[0] + assert isinstance(location, SourceLocation) + assert location == SourceLocation(1, 3) + original_error = error.original_error + assert isinstance(original_error, ValueError) + assert str(original_error) == "Some error" diff --git a/tests/execution/test_sync.py b/tests/execution/test_sync.py index 533c85b4..f16468f1 100644 --- a/tests/execution/test_sync.py +++ b/tests/execution/test_sync.py @@ -1,5 +1,4 @@ from inspect import isawaitable -from typing import Awaitable, cast from pytest import mark, raises # type: ignore @@ -56,7 +55,6 @@ async def returns_a_promise_if_any_field_is_asynchronous(): doc = "query Example { syncField, asyncField }" result = execute(schema, parse(doc), "rootValue") assert isawaitable(result) - result = cast(Awaitable, result) assert await result == ( {"syncField": "rootValue", "asyncField": "rootValue"}, None, diff --git a/tests/language/test_predicates.py b/tests/language/test_predicates.py index 8f96c9de..7e4c83f9 100644 --- a/tests/language/test_predicates.py +++ b/tests/language/test_predicates.py @@ -40,7 +40,7 @@ def check_definition_node(): assert is_definition_node(ExecutableDefinitionNode()) assert is_definition_node(TypeSystemDefinitionNode()) - def check_exectuable_definition_node(): + def check_executable_definition_node(): assert not is_executable_definition_node(Node()) assert not is_executable_definition_node(DocumentNode()) assert not is_executable_definition_node(DefinitionNode()) diff --git a/tests/language/test_schema_parser.py b/tests/language/test_schema_parser.py index 5c486b7d..4d1bdb6d 100644 --- a/tests/language/test_schema_parser.py +++ b/tests/language/test_schema_parser.py @@ -573,6 +573,11 @@ def union_fails_with_leading_double_pipe(): "union Hello = || Wo | Rld", "Expected Name, found |", (1, 16) ) + def union_fails_with_double_pipe(): + assert_syntax_error( + "union Hello = Wo || Rld", "Expected Name, found |", (1, 19) + ) + def union_fails_with_trailing_pipe(): assert_syntax_error( "union Hello = | Wo | Rld |", "Expected Name, found ", (1, 27) diff --git a/tests/pyutils/test_is_nullish.py b/tests/pyutils/test_is_nullish.py index dc298f22..db480dcb 100644 --- a/tests/pyutils/test_is_nullish.py +++ b/tests/pyutils/test_is_nullish.py @@ -4,22 +4,6 @@ from graphql.pyutils import is_nullish -class FakeNumpyArray: - def __eq__(self, other): - # Numpy arrays return an array when compared with another numpy array - # containing the pointwise equality of the two - if isinstance(other, FakeNumpyArray): - return FakeNumpyArray() - else: - return False - - def __bool__(self): - raise TypeError( - "The truth value of an array with more than one element is " - "ambiguous. Use a.any() or a.all()" - ) - - def describe_is_nullish(): def null_is_nullish(): assert is_nullish(None) is True diff --git a/tests/pyutils/test_suggesion_list.py b/tests/pyutils/test_suggestion_list.py similarity index 100% rename from tests/pyutils/test_suggesion_list.py rename to tests/pyutils/test_suggestion_list.py diff --git a/tests/subscription/test_subscribe.py b/tests/subscription/test_subscribe.py index 14773513..9f142300 100644 --- a/tests/subscription/test_subscribe.py +++ b/tests/subscription/test_subscribe.py @@ -128,7 +128,7 @@ def send_important_email(new_email): # Check all error cases when initializing the subscription. def describe_subscription_initialization_phase(): @mark.asyncio - async def accepts_an_object_with_named_properties_as_arguments(): + async def accepts_keyword_arguments(): document = parse( """ subscription { @@ -142,7 +142,9 @@ async def empty_async_iterator(_info): yield value await subscribe( - email_schema, document, {"importantEmail": empty_async_iterator} + schema=email_schema, + document=document, + root_value={"importantEmail": empty_async_iterator}, ) @mark.asyncio @@ -591,6 +593,160 @@ async def produces_a_payload_per_subscription_event(): with raises(StopAsyncIteration): assert await anext(subscription) + @mark.asyncio + async def produces_a_payload_when_there_are_multiple_events(): + pubsub = EventEmitter() + send_important_email, subscription = await create_subscription(pubsub) + payload = anext(subscription) + + # A new email arrives! + assert ( + send_important_email( + { + "from": "yuzhi@graphql.org", + "subject": "Alright", + "message": "Tests are good", + "unread": True, + } + ) + is True + ) + + assert await payload == ( + { + "importantEmail": { + "email": {"from": "yuzhi@graphql.org", "subject": "Alright"}, + "inbox": {"unread": 1, "total": 2}, + } + }, + None, + ) + + payload = anext(subscription) + + # A new email arrives! + assert ( + send_important_email( + { + "from": "yuzhi@graphql.org", + "subject": "Alright 2", + "message": "Tests are good 2", + "unread": True, + } + ) + is True + ) + + assert await payload == ( + { + "importantEmail": { + "email": {"from": "yuzhi@graphql.org", "subject": "Alright 2"}, + "inbox": {"unread": 2, "total": 3}, + } + }, + None, + ) + + @mark.asyncio + async def should_not_trigger_when_subscription_is_already_done(): + pubsub = EventEmitter() + send_important_email, subscription = await create_subscription(pubsub) + payload = anext(subscription) + + # A new email arrives! + assert ( + send_important_email( + { + "from": "yuzhi@graphql.org", + "subject": "Alright", + "message": "Tests are good", + "unread": True, + } + ) + is True + ) + + assert await payload == ( + { + "importantEmail": { + "email": {"from": "yuzhi@graphql.org", "subject": "Alright"}, + "inbox": {"unread": 1, "total": 2}, + } + }, + None, + ) + + payload = anext(subscription) + await subscription.aclose() + + # A new email arrives! + assert ( + send_important_email( + { + "from": "yuzhi@graphql.org", + "subject": "Alright 2", + "message": "Tests are good 2", + "unread": True, + } + ) + is False + ) + + with raises(StopAsyncIteration): + await payload + + @mark.asyncio + async def should_not_trigger_when_subscription_is_thrown(): + pubsub = EventEmitter() + send_important_email, subscription = await create_subscription(pubsub) + payload = anext(subscription) + + # A new email arrives! + assert ( + send_important_email( + { + "from": "yuzhi@graphql.org", + "subject": "Alright", + "message": "Tests are good", + "unread": True, + } + ) + is True + ) + + assert await payload == ( + { + "importantEmail": { + "email": {"from": "yuzhi@graphql.org", "subject": "Alright"}, + "inbox": {"unread": 1, "total": 2}, + } + }, + None, + ) + + payload = anext(subscription) + + # Throw error + with raises(RuntimeError) as exc_info: + await subscription.athrow(RuntimeError("ouch")) + assert str(exc_info.value) == "ouch" + + # A new email arrives! + assert ( + send_important_email( + { + "from": "yuzhi@graphql.org", + "subject": "Alright 2", + "message": "Tests are good 2", + "unread": True, + } + ) + is False + ) + + with raises(StopAsyncIteration): + await payload + @mark.asyncio async def event_order_is_correct_for_multiple_publishes(): pubsub = EventEmitter() diff --git a/tests/test_docs.py b/tests/test_docs.py index 5b5d3b6a..c313a047 100644 --- a/tests/test_docs.py +++ b/tests/test_docs.py @@ -134,11 +134,17 @@ def executing_queries(capsys): async_query = queries.pop(0) assert "asyncio" in async_query and "graphql_sync" not in async_query - exec(async_query, scope) - out, err = capsys.readouterr() - assert not err - assert "R2-D2" in out - assert out == expected_result(queries) + assert "asyncio.run" in async_query + try: # pragma: no cover + from asyncio import run # noqa: F401 + except ImportError: # Python < 3.7 + assert "ExecutionResult" in expected_result(queries) + else: # pragma: no cover + exec(async_query, scope) + out, err = capsys.readouterr() + assert not err + assert "R2-D2" in out + assert out == expected_result(queries) sync_query = queries.pop(0) assert "graphql_sync" in sync_query and "asyncio" not in sync_query diff --git a/tests/test_user_registry.py b/tests/test_user_registry.py index de4a8ed4..bdd94db8 100644 --- a/tests/test_user_registry.py +++ b/tests/test_user_registry.py @@ -8,6 +8,11 @@ from enum import Enum from typing import Any, Dict, List, NamedTuple, Optional +try: + from asyncio import create_task +except ImportError: # Python < 3.7 + create_task = None # type: ignore + from pytest import fixture, mark # type: ignore from graphql import ( @@ -51,7 +56,7 @@ class MutationEnum(Enum): class UserRegistry: - """"Simulation of a user registry with asynchronous database backend access.""" + """ "Simulation of a user registry with asynchronous database backend access.""" def __init__(self, **users) -> None: self._registry: Dict[str, User] = users @@ -506,9 +511,11 @@ async def receive_all(): if len(received_all) == 6: break - done, pending = await wait( - [mutate_users(), receive_one(), receive_all()], timeout=1 - ) + tasks = [ + create_task(task()) if create_task else task() + for task in (mutate_users, receive_one, receive_all) + ] + done, pending = await wait(tasks, timeout=1) assert not pending expected_data: List[Dict[str, Any]] = [ diff --git a/tests/type/test_definition.py b/tests/type/test_definition.py index 73240110..0638dd3f 100644 --- a/tests/type/test_definition.py +++ b/tests/type/test_definition.py @@ -732,7 +732,7 @@ def accepts_a_union_type_without_types(): union_type = GraphQLUnionType("SomeUnion", []) assert union_type.types == [] - def rejects_an_interface_type_with_an_incorrect_type_for_resolve_type(): + def rejects_a_union_type_with_an_incorrect_type_for_resolve_type(): with raises(TypeError) as exc_info: # noinspection PyTypeChecker GraphQLUnionType("SomeUnion", [], resolve_type={}) # type: ignore diff --git a/tests/type/test_enum.py b/tests/type/test_enum.py index f268eca7..0197c303 100644 --- a/tests/type/test_enum.py +++ b/tests/type/test_enum.py @@ -204,7 +204,7 @@ def does_not_accept_internal_value_in_place_of_enum_literal(): [{"message": "Expected type Color, found 1.", "locations": [(1, 23)]}], ) - def does_not_accept_internal_value_in_place_of_int(): + def does_not_accept_enum_literal_in_place_of_int(): result = execute_query("{ colorEnum(fromInt: GREEN) }") assert result == ( diff --git a/tests/type/test_schema.py b/tests/type/test_schema.py index 56dab555..c81a5119 100644 --- a/tests/type/test_schema.py +++ b/tests/type/test_schema.py @@ -268,7 +268,7 @@ def rejects_a_schema_which_redefines_a_built_in_type(): msg = str(exc_info.value) assert msg == ( "Schema must contain uniquely named types" - f" but contains multiple types named 'String'." + " but contains multiple types named 'String'." ) def rejects_a_schema_which_defines_an_object_twice(): @@ -282,7 +282,7 @@ def rejects_a_schema_which_defines_an_object_twice(): msg = str(exc_info.value) assert msg == ( "Schema must contain uniquely named types" - f" but contains multiple types named 'SameName'." + " but contains multiple types named 'SameName'." ) def rejects_a_schema_which_defines_fields_with_conflicting_types(): @@ -300,7 +300,7 @@ def rejects_a_schema_which_defines_fields_with_conflicting_types(): msg = str(exc_info.value) assert msg == ( "Schema must contain uniquely named types" - f" but contains multiple types named 'SameName'." + " but contains multiple types named 'SameName'." ) def describe_when_assumed_valid(): diff --git a/tests/type/test_serialization.py b/tests/type/test_serialization.py index de15cb92..9761945f 100644 --- a/tests/type/test_serialization.py +++ b/tests/type/test_serialization.py @@ -37,41 +37,41 @@ def serializes_output_as_int(): assert str(exc_info.value) == "Int cannot represent non-integer value: '-1.1'" # Maybe a safe JavaScript int, but bigger than 2^32, so not # representable as a GraphQL Int - with raises(Exception) as exc_info: + with raises(TypeError) as exc_info: GraphQLInt.serialize(9876504321) assert str(exc_info.value) == ( "Int cannot represent non 32-bit signed integer value: 9876504321" ) - with raises(Exception) as exc_info: + with raises(TypeError) as exc_info: GraphQLInt.serialize(-9876504321) assert str(exc_info.value) == ( "Int cannot represent non 32-bit signed integer value: -9876504321" ) # Too big to represent as an Int in JavaScript or GraphQL - with raises(Exception) as exc_info: + with raises(TypeError) as exc_info: GraphQLInt.serialize(1e100) assert str(exc_info.value) == ( "Int cannot represent non 32-bit signed integer value: 1e+100" ) - with raises(Exception) as exc_info: + with raises(TypeError) as exc_info: GraphQLInt.serialize(-1e100) assert str(exc_info.value) == ( "Int cannot represent non 32-bit signed integer value: -1e+100" ) - with raises(Exception) as exc_info: + with raises(TypeError) as exc_info: GraphQLInt.serialize("one") assert str(exc_info.value) == "Int cannot represent non-integer value: 'one'" # Doesn't represent number - with raises(Exception) as exc_info: + with raises(TypeError) as exc_info: GraphQLInt.serialize("") assert str(exc_info.value) == "Int cannot represent non-integer value: ''" - with raises(Exception) as exc_info: + with raises(TypeError) as exc_info: GraphQLInt.serialize(nan) assert str(exc_info.value) == "Int cannot represent non-integer value: nan" - with raises(Exception) as exc_info: + with raises(TypeError) as exc_info: GraphQLInt.serialize(inf) assert str(exc_info.value) == "Int cannot represent non-integer value: inf" - with raises(Exception) as exc_info: + with raises(TypeError) as exc_info: GraphQLInt.serialize([5]) assert str(exc_info.value) == "Int cannot represent non-integer value: [5]" @@ -87,21 +87,21 @@ def serializes_output_as_float(): assert GraphQLFloat.serialize(False) == 0 assert GraphQLFloat.serialize(True) == 1 - with raises(Exception) as exc_info: + with raises(TypeError) as exc_info: GraphQLFloat.serialize(nan) assert str(exc_info.value) == "Float cannot represent non numeric value: nan" - with raises(Exception) as exc_info: + with raises(TypeError) as exc_info: GraphQLFloat.serialize(inf) assert str(exc_info.value) == "Float cannot represent non numeric value: inf" - with raises(Exception) as exc_info: + with raises(TypeError) as exc_info: GraphQLFloat.serialize("one") assert str(exc_info.value) == ( "Float cannot represent non numeric value: 'one'" ) - with raises(Exception) as exc_info: + with raises(TypeError) as exc_info: GraphQLFloat.serialize("") assert str(exc_info.value) == "Float cannot represent non numeric value: ''" - with raises(Exception) as exc_info: + with raises(TypeError) as exc_info: GraphQLFloat.serialize([5]) assert str(exc_info.value) == "Float cannot represent non numeric value: [5]" @@ -118,15 +118,15 @@ def __str__(self): assert GraphQLString.serialize(StringableObjValue()) == "something useful" - with raises(Exception) as exc_info: + with raises(TypeError) as exc_info: GraphQLString.serialize(nan) assert str(exc_info.value) == "String cannot represent value: nan" - with raises(Exception) as exc_info: + with raises(TypeError) as exc_info: GraphQLString.serialize([1]) assert str(exc_info.value) == "String cannot represent value: [1]" - with raises(Exception) as exc_info: + with raises(TypeError) as exc_info: GraphQLString.serialize({}) assert str(exc_info.value) == "String cannot represent value: {}" @@ -136,31 +136,31 @@ def serializes_output_as_boolean(): assert GraphQLBoolean.serialize(True) is True assert GraphQLBoolean.serialize(False) is False - with raises(Exception) as exc_info: + with raises(TypeError) as exc_info: GraphQLBoolean.serialize(nan) assert str(exc_info.value) == ( "Boolean cannot represent a non boolean value: nan" ) - with raises(Exception) as exc_info: + with raises(TypeError) as exc_info: GraphQLBoolean.serialize("") assert str(exc_info.value) == ( "Boolean cannot represent a non boolean value: ''" ) - with raises(Exception) as exc_info: + with raises(TypeError) as exc_info: GraphQLBoolean.serialize("True") assert str(exc_info.value) == ( "Boolean cannot represent a non boolean value: 'True'" ) - with raises(Exception) as exc_info: + with raises(TypeError) as exc_info: GraphQLBoolean.serialize([False]) assert str(exc_info.value) == ( "Boolean cannot represent a non boolean value: [False]" ) - with raises(Exception) as exc_info: + with raises(TypeError) as exc_info: GraphQLBoolean.serialize({}) assert str(exc_info.value) == ( "Boolean cannot represent a non boolean value: {}" @@ -184,18 +184,18 @@ def __str__(self): obj_value = ObjValue(123) assert GraphQLID.serialize(obj_value) == "123" - with raises(Exception) as exc_info: + with raises(TypeError) as exc_info: GraphQLID.serialize(True) assert str(exc_info.value) == "ID cannot represent value: True" - with raises(Exception) as exc_info: + with raises(TypeError) as exc_info: GraphQLID.serialize(3.14) assert str(exc_info.value) == ("ID cannot represent value: 3.14") - with raises(Exception) as exc_info: + with raises(TypeError) as exc_info: GraphQLID.serialize({}) assert str(exc_info.value) == ("ID cannot represent value: {}") - with raises(Exception) as exc_info: + with raises(TypeError) as exc_info: GraphQLID.serialize(["abc"]) assert str(exc_info.value) == ("ID cannot represent value: ['abc']") diff --git a/tests/type/test_validation.py b/tests/type/test_validation.py index 79e540ef..6a15f114 100644 --- a/tests/type/test_validation.py +++ b/tests/type/test_validation.py @@ -1,4 +1,4 @@ -from functools import partial +from operator import attrgetter from typing import cast, List, Union from pytest import mark, raises # type: ignore @@ -84,9 +84,7 @@ def with_modifiers( not_input_types = with_modifiers([SomeObjectType, SomeUnionType, SomeInterfaceType]) -parametrize_type = partial( - mark.parametrize("type_", ids=lambda type_: type_.__class__.__name__) -) +get_name = attrgetter("__class__.__name__") def schema_with_field_type(type_): @@ -885,7 +883,7 @@ def _schema_with_object_field_of_type(field_type: GraphQLOutputType): types=[SomeObjectType], ) - @parametrize_type(output_types) + @mark.parametrize("type_", output_types, ids=get_name) def accepts_an_output_type_as_an_object_field_type(type_): schema = _schema_with_object_field_of_type(type_) assert validate_schema(schema) == [] @@ -898,7 +896,7 @@ def rejects_an_empty_object_field_type(): msg = str(exc_info.value) assert msg == "Field type must be an output type." - @parametrize_type(not_output_types) + @mark.parametrize("type_", not_output_types, ids=get_name) def rejects_a_non_output_type_as_an_object_field_type(type_): # invalid schema cannot be built with Python with raises(TypeError) as exc_info: @@ -906,7 +904,7 @@ def rejects_a_non_output_type_as_an_object_field_type(type_): msg = str(exc_info.value) assert msg == "Field type must be an output type." - @parametrize_type([int, float, str]) + @mark.parametrize("type_", [int, float, str], ids=get_name) def rejects_a_non_type_value_as_an_object_field_type(type_): # invalid schema cannot be built with Python with raises(TypeError) as exc_info: @@ -1172,7 +1170,7 @@ def _schema_with_interface_field_of_type(field_type: GraphQLOutputType): types=[BadImplementingType, SomeObjectType], ) - @parametrize_type(output_types) + @mark.parametrize("type_", output_types, ids=get_name) def accepts_an_output_type_as_an_interface_field_type(type_): schema = _schema_with_interface_field_of_type(type_) assert validate_schema(schema) == [] @@ -1185,7 +1183,7 @@ def rejects_an_empty_interface_field_type(): msg = str(exc_info.value) assert msg == "Field type must be an output type." - @parametrize_type(not_output_types) + @mark.parametrize("type_", not_output_types, ids=get_name) def rejects_a_non_output_type_as_an_interface_field_type(type_): # invalid schema cannot be built with Python with raises(TypeError) as exc_info: @@ -1193,7 +1191,7 @@ def rejects_a_non_output_type_as_an_interface_field_type(type_): msg = str(exc_info.value) assert msg == "Field type must be an output type." - @parametrize_type([int, float, str]) + @mark.parametrize("type_", [int, float, str], ids=get_name) def rejects_a_non_type_value_as_an_interface_field_type(type_): # invalid schema cannot be built with Python with raises(TypeError) as exc_info: @@ -1258,7 +1256,7 @@ def _schema_with_arg_of_type(arg_type: GraphQLInputType): GraphQLObjectType("Query", {"f": GraphQLField(BadObjectType)}) ) - @parametrize_type(input_types) + @mark.parametrize("type_", input_types, ids=get_name) def accepts_an_input_type_as_a_field_arg_type(type_): schema = _schema_with_arg_of_type(type_) assert validate_schema(schema) == [] @@ -1271,7 +1269,7 @@ def rejects_an_empty_field_arg_type(): msg = str(exc_info.value) assert msg == "Argument type must be a GraphQL input type." - @parametrize_type(not_input_types) + @mark.parametrize("type_", not_input_types, ids=get_name) def rejects_a_non_input_type_as_a_field_arg_type(type_): # invalid schema cannot be built with Python with raises(TypeError) as exc_info: @@ -1279,7 +1277,7 @@ def rejects_a_non_input_type_as_a_field_arg_type(type_): msg = str(exc_info.value) assert msg == "Argument type must be a GraphQL input type." - @parametrize_type([int, float, str]) + @mark.parametrize("type_", [int, float, str], ids=get_name) def rejects_a_non_type_value_as_a_field_arg_type(type_): # invalid schema cannot be built with Python with raises(TypeError) as exc_info: @@ -1325,8 +1323,8 @@ def _schema_with_input_field_of_type(input_field_type: GraphQLInputType): ) ) - @parametrize_type(input_types) - def accepts_an_input_type_as_an_input_fieldtype(type_): + @mark.parametrize("type_", input_types, ids=get_name) + def accepts_an_input_type_as_an_input_field_type(type_): schema = _schema_with_input_field_of_type(type_) assert validate_schema(schema) == [] @@ -1338,7 +1336,7 @@ def rejects_an_empty_input_field_type(): msg = str(exc_info.value) assert msg == "Input field type must be a GraphQL input type." - @parametrize_type(not_input_types) + @mark.parametrize("type_", not_input_types, ids=get_name) def rejects_a_non_input_type_as_an_input_field_type(type_): # invalid schema cannot be built with Python with raises(TypeError) as exc_info: @@ -1346,7 +1344,7 @@ def rejects_a_non_input_type_as_an_input_field_type(type_): msg = str(exc_info.value) assert msg == "Input field type must be a GraphQL input type." - @parametrize_type([int, float, str]) + @mark.parametrize("type_", [int, float, str], ids=get_name) def rejects_a_non_type_value_as_an_input_field_type(type_): # invalid schema cannot be built with Python with raises(TypeError) as exc_info: diff --git a/tests/utilities/test_ast_from_value.py b/tests/utilities/test_ast_from_value.py index ba41d24f..09855fbe 100644 --- a/tests/utilities/test_ast_from_value.py +++ b/tests/utilities/test_ast_from_value.py @@ -25,6 +25,7 @@ GraphQLInt, GraphQLList, GraphQLNonNull, + GraphQLScalarType, GraphQLString, ) from graphql.utilities import ast_from_value @@ -123,6 +124,36 @@ def converts_id_values_to_int_or_string_asts(): assert ast_from_value(INVALID, GraphQLString) is None + def converts_using_serialize_from_a_custom_scalar_type(): + pass_through_scalar = GraphQLScalarType( + "PassThroughScalar", + serialize=lambda value: value, + ) + + assert ast_from_value("value", pass_through_scalar) == StringValueNode( + value="value" + ) + + return_null_scalar = GraphQLScalarType( + "ReturnNullScalar", + serialize=lambda value: None, + ) + + assert ast_from_value("value", return_null_scalar) is None + + class SomeClass: + pass + + return_custom_class_scalar = GraphQLScalarType( + "ReturnCustomClassScalar", + serialize=lambda value: SomeClass(), + ) + + with raises(TypeError) as exc_info: + ast_from_value("value", return_custom_class_scalar) + msg = str(exc_info.value) + assert msg == "Cannot convert value to AST: " + def does_not_convert_non_null_values_to_null_value(): non_null_boolean = GraphQLNonNull(GraphQLBoolean) assert ast_from_value(None, non_null_boolean) is None @@ -162,12 +193,21 @@ def converts_list_singletons(): value="FOO" ) - def converts_input_objects(): - input_obj = GraphQLInputObjectType( - "MyInputObj", - {"foo": GraphQLInputField(GraphQLFloat), "bar": GraphQLInputField(my_enum)}, + def skips_invalid_list_items(): + ast = ast_from_value( + ["FOO", None, "BAR"], GraphQLList(GraphQLNonNull(GraphQLString)) + ) + + assert ast == ListValueNode( + values=[StringValueNode(value="FOO"), StringValueNode(value="BAR")] ) + input_obj = GraphQLInputObjectType( + "MyInputObj", + {"foo": GraphQLInputField(GraphQLFloat), "bar": GraphQLInputField(my_enum)}, + ) + + def converts_input_objects(): assert ast_from_value({"foo": 3, "bar": "HELLO"}, input_obj) == ObjectValueNode( fields=[ ObjectFieldNode( @@ -180,11 +220,6 @@ def converts_input_objects(): ) def converts_input_objects_with_explicit_nulls(): - input_obj = GraphQLInputObjectType( - "MyInputObj", - {"foo": GraphQLInputField(GraphQLFloat), "bar": GraphQLInputField(my_enum)}, - ) - assert ast_from_value({"foo": None}, input_obj) == ObjectValueNode( fields=[ObjectFieldNode(name=NameNode(value="foo"), value=NullValueNode())] ) diff --git a/tests/utilities/test_coerce_input_value.py b/tests/utilities/test_coerce_input_value.py index b368cc63..2f5a5883 100644 --- a/tests/utilities/test_coerce_input_value.py +++ b/tests/utilities/test_coerce_input_value.py @@ -338,6 +338,6 @@ def throw_error_with_path(): [None], GraphQLList(GraphQLNonNull(GraphQLInt)) ) assert exc_info.value.message == ( - "Invalid value None at 'value[0]': :" + "Invalid value None at 'value[0]':" " Expected non-nullable type Int! not to be None." ) diff --git a/tox.ini b/tox.ini index a53535e8..c47d35ad 100644 --- a/tox.ini +++ b/tox.ini @@ -1,46 +1,53 @@ [tox] -envlist = py{36,37,38}, black, flake8, mypy, docs, manifest +envlist = py3{6,7,8,9,10}, black, flake8, mypy, docs, manifest +isolated_build = true + +[gh-actions] +python = + 3.6: py36 + 3.7: py37 + 3.8: py38 + 3.9: py39 + 3.10: py310 [testenv:black] -basepython = python3.7 -deps = black==19.10b0 +basepython = python3.8 +deps = black==21.12b0 commands = - black src tests setup.py --check + black src tests setup.py -t py38 --check [testenv:flake8] -basepython = python3.7 -deps = flake8>=3.7,<4 +basepython = python3.8 +deps = flake8>=4,<5 commands = flake8 src tests setup.py [testenv:mypy] -basepython = python3.7 -deps = mypy>=0.750,<0.760 +basepython = python3.8 +deps = mypy==0.930 commands = mypy src tests [testenv:docs] -basepython = python3.7 +basepython = python3.8 deps = - sphinx>=2.2,<3 + sphinx>=2.4,<3 sphinx_rtd_theme>=0.4,<1 commands = sphinx-build -b html -nEW docs docs/_build/html [testenv:manifest] -basepython = python3.7 -deps = check-manifest>=0.40,<1 +basepython = python3.8 +deps = check-manifest==0.40 commands = check-manifest -v [testenv] -setenv = - PYTHONPATH = {toxinidir} deps = - pytest>=5.3,<5.4 - pytest-asyncio>=0.10,<1 - pytest-benchmark>=3.2,<4 - pytest-cov>=2.8,<3 - pytest-describe>=0.12,<1 + pytest>=6.2,<7 + pytest-asyncio>=0.16,<1 + pytest-benchmark>=3.4,<4 + pytest-cov>=3,<4 + pytest-describe>=2,<3 commands = pytest tests {posargs}