diff --git a/.coveragerc b/.coveragerc new file mode 100644 index 0000000..87df271 --- /dev/null +++ b/.coveragerc @@ -0,0 +1,2 @@ +[report] +omit = */tests/* diff --git a/.travis.yml b/.travis.yml index 4a129cb..c59b86e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,27 +1,23 @@ language: python sudo: false -matrix: - include: - - python: pypy - env: TOX_ENV=pypy - - python: '2.7' - env: TOX_ENV=py27 - - python: '3.5' - env: TOX_ENV=py35 - - python: '3.6' - env: TOX_ENV=py36 - - python: '3.6' - env: TOX_ENV=import-order,flake8 -cache: - directories: - - $HOME/.cache/pip - - $TRAVIS_BUILD_DIR/.tox +python: + - 2.7 + - 3.5 + - 3.6 + - 3.7 + # - 3.8 +cache: pip + install: -- pip install tox coveralls + - pip install tox-travis + script: -- tox -e $TOX_ENV -- --cov=flask_graphql + - tox + after_success: -- coveralls + - pip install coveralls + - coveralls + deploy: provider: pypi user: syrusakbary diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..9525b09 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,49 @@ +# Contributing + +Thanks for helping to make flask-graphql awesome! + +We welcome all kinds of contributions: + +- Bug fixes +- Documentation improvements +- New features +- Refactoring & tidying + + +## Getting started + +If you have a specific contribution in mind, be sure to check the [issues](https://github.com/graphql-python/flask-graphql/issues) and [projects](https://github.com/graphql-python/flask-graphql/projects) in progress - someone could already be working on something similar and you can help out. + + +## Project setup + +After cloning this repo, ensure dependencies are installed by running: + +```sh +make dev-setup +``` + +## Running tests + +After developing, the full test suite can be evaluated by running: + +```sh +make tests +``` + +## Development on Conda + +In order to run `tox` command on conda, you must create a new env (e.g. `flask-grapqhl-dev`) with the following command: + +```sh +conda create -n flask-grapqhl-dev python=3.8 +``` + +Then activate the environment with `conda activate flask-grapqhl-dev` and install [tox-conda](https://github.com/tox-dev/tox-conda): + +```sh +conda install -c conda-forge tox-conda +``` + +Uncomment the `requires = tox-conda` line on `tox.ini` file and that's it! Run `tox` and you will see all the environments being created and all passing tests. :rocket: + diff --git a/MANIFEST.in b/MANIFEST.in index 497302a..29c54bf 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,3 +1,14 @@ +include LICENSE include README.md +include CONTRIBUTING.md + recursive-include flask_graphql/static * recursive-include flask_graphql/templates * +recursive-include tests *.py + +include Makefile + +include .coveragerc +include tox.ini + +global-exclude *.py[co] __pycache__ diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..a6f33e3 --- /dev/null +++ b/Makefile @@ -0,0 +1,5 @@ +dev-setup: + python pip install -e ".[test]" + +tests: + py.test tests --cov=flask_graphql -vv \ No newline at end of file diff --git a/README.md b/README.md index 8c918ae..48f5ea8 100644 --- a/README.md +++ b/README.md @@ -39,3 +39,6 @@ class UserRootValue(GraphQLView): return request.user ``` + +## Contributing +See [CONTRIBUTING.md](contributing.md) diff --git a/README.rst b/README.rst deleted file mode 100644 index a2c5ef7..0000000 --- a/README.rst +++ /dev/null @@ -1,63 +0,0 @@ -Flask-GraphQL -============= - -|Build Status| |Coverage Status| |PyPI version| - -Adds GraphQL support to your Flask application. - -Usage ------ - -Just use the ``GraphQLView`` view from ``flask_graphql`` - -.. code:: python - - from flask_graphql import GraphQLView - - app.add_url_rule('/graphql', view_func=GraphQLView.as_view('graphql', schema=schema, graphiql=True)) - - # Optional, for adding batch query support (used in Apollo-Client) - app.add_url_rule('/graphql/batch', view_func=GraphQLView.as_view('graphql', schema=schema, batch=True)) - -This will add ``/graphql`` and ``/graphiql`` endpoints to your app. - -Supported options -~~~~~~~~~~~~~~~~~ - -- ``schema``: The ``GraphQLSchema`` object that you want the view to - execute when it gets a valid request. -- ``context``: A value to pass as the ``context`` to the ``graphql()`` - function. -- ``root_value``: The ``root_value`` you want to provide to - ``executor.execute``. -- ``pretty``: Whether or not you want the response to be pretty printed - JSON. -- ``executor``: The ``Executor`` that you want to use to execute - queries. -- ``graphiql``: If ``True``, may present - `GraphiQL `__ when loaded - directly from a browser (a useful tool for debugging and - exploration). -- ``graphiql_template``: Inject a Jinja template string to customize - GraphiQL. -- ``batch``: Set the GraphQL view as batch (for using in - `Apollo-Client `__ - or - `ReactRelayNetworkLayer `__) - -You can also subclass ``GraphQLView`` and overwrite -``get_root_value(self, request)`` to have a dynamic root value per -request. - -.. code:: python - - class UserRootValue(GraphQLView): - def get_root_value(self, request): - return request.user - -.. |Build Status| image:: https://travis-ci.org/graphql-python/flask-graphql.svg?branch=master - :target: https://travis-ci.org/graphql-python/flask-graphql -.. |Coverage Status| image:: https://coveralls.io/repos/graphql-python/flask-graphql/badge.svg?branch=master&service=github - :target: https://coveralls.io/github/graphql-python/flask-graphql?branch=master -.. |PyPI version| image:: https://badge.fury.io/py/flask-graphql.svg - :target: https://badge.fury.io/py/flask-graphql diff --git a/flask_graphql/graphqlview.py b/flask_graphql/graphqlview.py index e38e1ab..25e382f 100644 --- a/flask_graphql/graphqlview.py +++ b/flask_graphql/graphqlview.py @@ -2,12 +2,12 @@ from flask import Response, request from flask.views import View - -from graphql.type.schema import GraphQLSchema from graphql_server import (HttpQueryError, default_format_error, encode_execution_results, json_encode, load_json_body, run_http_query) +from graphql.type.schema import GraphQLSchema + from .render_graphiql import render_graphiql diff --git a/setup.py b/setup.py index 0e2d779..a851be7 100644 --- a/setup.py +++ b/setup.py @@ -1,16 +1,29 @@ from setuptools import setup, find_packages -required_packages = [ - "graphql-core>=2.3,<3", +install_requires = [ "flask>=0.7.0", + "graphql-core>=2.3,<3", "graphql-server-core>=1.1,<2", ] +tests_requires = [ + 'pytest>=2.7.2', + 'pytest-cov==2.8.1', + 'pytest-flask>=0.10.0', +] + +dev_requires = [ + 'flake8==3.7.9', + 'isort<4.0.0', + 'check-manifest>=0.40,<1', +] + tests_requires + setup( name="Flask-GraphQL", version="2.0.1", description="Adds GraphQL support to your Flask application", - long_description=open("README.rst").read(), + long_description=open("README.md").read(), + long_description_content_type="text/markdown", url="https://github.com/graphql-python/flask-graphql", download_url="https://github.com/graphql-python/flask-graphql/releases", author="Syrus Akbary", @@ -23,8 +36,6 @@ "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.3", - "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", @@ -33,8 +44,12 @@ ], keywords="api graphql protocol rest flask", packages=find_packages(exclude=["tests"]), - install_requires=required_packages, - tests_require=["pytest>=2.7.3"], + install_requires=install_requires, + tests_require=tests_requires, + extras_require={ + 'test': tests_requires, + 'dev': dev_requires, + }, include_package_data=True, zip_safe=False, platforms="any", diff --git a/tests/test_graphiqlview.py b/tests/test_graphiqlview.py index fd7469a..aa92202 100644 --- a/tests/test_graphiqlview.py +++ b/tests/test_graphiqlview.py @@ -6,16 +6,29 @@ @pytest.fixture def app(): - return create_app(graphiql=True) + # import app factory pattern + app = create_app(graphiql=True) + # pushes an application context manually + ctx = app.app_context() + ctx.push() + return app -def test_graphiql_is_enabled(client): - response = client.get(url_for('graphql'), headers={'Accept': 'text/html'}) + +@pytest.fixture +def client(app): + return app.test_client() + + +def test_graphiql_is_enabled(app, client): + with app.test_request_context(): + response = client.get(url_for('graphql', externals=False), headers={'Accept': 'text/html'}) assert response.status_code == 200 -def test_graphiql_renders_pretty(client): - response = client.get(url_for('graphql', query='{test}'), headers={'Accept': 'text/html'}) +def test_graphiql_renders_pretty(app, client): + with app.test_request_context(): + response = client.get(url_for('graphql', query='{test}'), headers={'Accept': 'text/html'}) assert response.status_code == 200 pretty_response = ( '{\n' @@ -28,12 +41,14 @@ def test_graphiql_renders_pretty(client): assert pretty_response in response.data.decode('utf-8') -def test_graphiql_default_title(client): - response = client.get(url_for('graphql'), headers={'Accept': 'text/html'}) +def test_graphiql_default_title(app, client): + with app.test_request_context(): + response = client.get(url_for('graphql'), headers={'Accept': 'text/html'}) assert 'GraphiQL' in response.data.decode('utf-8') @pytest.mark.parametrize('app', [create_app(graphiql=True, graphiql_html_title="Awesome")]) def test_graphiql_custom_title(app, client): - response = client.get(url_for('graphql'), headers={'Accept': 'text/html'}) + with app.test_request_context(): + response = client.get(url_for('graphql'), headers={'Accept': 'text/html'}) assert 'Awesome' in response.data.decode('utf-8') diff --git a/tests/test_graphqlview.py b/tests/test_graphqlview.py index 71b4df6..3e49e55 100644 --- a/tests/test_graphqlview.py +++ b/tests/test_graphqlview.py @@ -16,12 +16,24 @@ @pytest.fixture -def app(): - return create_app() +def app(request): + # import app factory pattern + app = create_app() + # pushes an application context manually + ctx = app.app_context() + ctx.push() + return app -def url_string(**url_params): - string = url_for('graphql') + +@pytest.fixture +def client(app): + return app.test_client() + + +def url_string(app, **url_params): + with app.test_request_context(): + string = url_for('graphql') if url_params: string += '?' + urlencode(url_params) @@ -33,12 +45,16 @@ def response_json(response): return json.loads(response.data.decode()) -j = lambda **kwargs: json.dumps(kwargs) -jl = lambda **kwargs: json.dumps([kwargs]) +def json_dump_kwarg(**kwargs): + return json.dumps(kwargs) + + +def json_dump_kwarg_list(**kwargs): + return json.dumps([kwargs]) -def test_allows_get_with_query_param(client): - response = client.get(url_string(query='{test}')) +def test_allows_get_with_query_param(app, client): + response = client.get(url_string(app, query='{test}')) assert response.status_code == 200 assert response_json(response) == { @@ -46,8 +62,9 @@ def test_allows_get_with_query_param(client): } -def test_allows_get_with_variable_values(client): +def test_allows_get_with_variable_values(app, client): response = client.get(url_string( + app, query='query helloWho($who: String){ test(who: $who) }', variables=json.dumps({'who': "Dolly"}) )) @@ -58,8 +75,9 @@ def test_allows_get_with_variable_values(client): } -def test_allows_get_with_operation_name(client): +def test_allows_get_with_operation_name(app, client): response = client.get(url_string( + app, query=''' query helloYou { test(who: "You"), ...shared } query helloWorld { test(who: "World"), ...shared } @@ -80,8 +98,9 @@ def test_allows_get_with_operation_name(client): } -def test_reports_validation_errors(client): +def test_reports_validation_errors(app, client): response = client.get(url_string( + app, query='{ test, unknownOne, unknownTwo }' )) @@ -100,8 +119,9 @@ def test_reports_validation_errors(client): } -def test_errors_when_missing_operation_name(client): +def test_errors_when_missing_operation_name(app, client): response = client.get(url_string( + app, query=''' query TestQuery { test } mutation TestMutation { writeTest { test } } @@ -118,8 +138,9 @@ def test_errors_when_missing_operation_name(client): } -def test_errors_when_sending_a_mutation_via_get(client): +def test_errors_when_sending_a_mutation_via_get(app, client): response = client.get(url_string( + app, query=''' mutation TestMutation { writeTest { test } } ''' @@ -134,8 +155,9 @@ def test_errors_when_sending_a_mutation_via_get(client): } -def test_errors_when_selecting_a_mutation_within_a_get(client): +def test_errors_when_selecting_a_mutation_within_a_get(app, client): response = client.get(url_string( + app, query=''' query TestQuery { test } mutation TestMutation { writeTest { test } } @@ -153,8 +175,9 @@ def test_errors_when_selecting_a_mutation_within_a_get(client): } -def test_allows_mutation_to_exist_within_a_get(client): +def test_allows_mutation_to_exist_within_a_get(app, client): response = client.get(url_string( + app, query=''' query TestQuery { test } mutation TestMutation { writeTest { test } } @@ -168,8 +191,8 @@ def test_allows_mutation_to_exist_within_a_get(client): } -def test_allows_post_with_json_encoding(client): - response = client.post(url_string(), data=j(query='{test}'), content_type='application/json') +def test_allows_post_with_json_encoding(app, client): + response = client.post(url_string(app), data=json_dump_kwarg(query='{test}'), content_type='application/json') assert response.status_code == 200 assert response_json(response) == { @@ -177,8 +200,8 @@ def test_allows_post_with_json_encoding(client): } -def test_allows_sending_a_mutation_via_post(client): - response = client.post(url_string(), data=j(query='mutation TestMutation { writeTest { test } }'), content_type='application/json') +def test_allows_sending_a_mutation_via_post(app, client): + response = client.post(url_string(app), data=json_dump_kwarg(query='mutation TestMutation { writeTest { test } }'), content_type='application/json') assert response.status_code == 200 assert response_json(response) == { @@ -186,8 +209,8 @@ def test_allows_sending_a_mutation_via_post(client): } -def test_allows_post_with_url_encoding(client): - response = client.post(url_string(), data=urlencode(dict(query='{test}')), content_type='application/x-www-form-urlencoded') +def test_allows_post_with_url_encoding(app, client): + response = client.post(url_string(app), data=urlencode(dict(query='{test}')), content_type='application/x-www-form-urlencoded') assert response.status_code == 200 assert response_json(response) == { @@ -208,8 +231,8 @@ def test_allows_post_with_url_encoding(client): # } -def test_supports_post_json_query_with_string_variables(client): - response = client.post(url_string(), data=j( +def test_supports_post_json_query_with_string_variables(app, client): + response = client.post(url_string(app), data=json_dump_kwarg( query='query helloWho($who: String){ test(who: $who) }', variables=json.dumps({'who': "Dolly"}) ), content_type='application/json') @@ -220,8 +243,8 @@ def test_supports_post_json_query_with_string_variables(client): } -def test_supports_post_json_query_with_json_variables(client): - response = client.post(url_string(), data=j( +def test_supports_post_json_query_with_json_variables(app, client): + response = client.post(url_string(app), data=json_dump_kwarg( query='query helloWho($who: String){ test(who: $who) }', variables={'who': "Dolly"} ), content_type='application/json') @@ -232,8 +255,8 @@ def test_supports_post_json_query_with_json_variables(client): } -def test_supports_post_url_encoded_query_with_string_variables(client): - response = client.post(url_string(), data=urlencode(dict( +def test_supports_post_url_encoded_query_with_string_variables(app, client): + response = client.post(url_string(app), data=urlencode(dict( query='query helloWho($who: String){ test(who: $who) }', variables=json.dumps({'who': "Dolly"}) )), content_type='application/x-www-form-urlencoded') @@ -244,10 +267,11 @@ def test_supports_post_url_encoded_query_with_string_variables(client): } -def test_supports_post_json_quey_with_get_variable_values(client): +def test_supports_post_json_quey_with_get_variable_values(app, client): response = client.post(url_string( + app, variables=json.dumps({'who': "Dolly"}) - ), data=j( + ), data=json_dump_kwarg( query='query helloWho($who: String){ test(who: $who) }', ), content_type='application/json') @@ -257,8 +281,9 @@ def test_supports_post_json_quey_with_get_variable_values(client): } -def test_post_url_encoded_query_with_get_variable_values(client): +def test_post_url_encoded_query_with_get_variable_values(app, client): response = client.post(url_string( + app, variables=json.dumps({'who': "Dolly"}) ), data=urlencode(dict( query='query helloWho($who: String){ test(who: $who) }', @@ -270,8 +295,9 @@ def test_post_url_encoded_query_with_get_variable_values(client): } -def test_supports_post_raw_text_query_with_get_variable_values(client): +def test_supports_post_raw_text_query_with_get_variable_values(app, client): response = client.post(url_string( + app, variables=json.dumps({'who': "Dolly"}) ), data='query helloWho($who: String){ test(who: $who) }', @@ -284,8 +310,8 @@ def test_supports_post_raw_text_query_with_get_variable_values(client): } -def test_allows_post_with_operation_name(client): - response = client.post(url_string(), data=j( +def test_allows_post_with_operation_name(app, client): + response = client.post(url_string(app), data=json_dump_kwarg( query=''' query helloYou { test(who: "You"), ...shared } query helloWorld { test(who: "World"), ...shared } @@ -306,8 +332,9 @@ def test_allows_post_with_operation_name(client): } -def test_allows_post_with_get_operation_name(client): +def test_allows_post_with_get_operation_name(app, client): response = client.post(url_string( + app, operationName='helloWorld' ), data=''' query helloYou { test(who: "You"), ...shared } @@ -330,7 +357,7 @@ def test_allows_post_with_get_operation_name(client): @pytest.mark.parametrize('app', [create_app(pretty=True)]) def test_supports_pretty_printing(app, client): - response = client.get(url_string(query='{test}')) + response = client.get(url_string(app, query='{test}')) assert response.data.decode() == ( '{\n' @@ -343,15 +370,15 @@ def test_supports_pretty_printing(app, client): @pytest.mark.parametrize('app', [create_app(pretty=False)]) def test_not_pretty_by_default(app, client): - response = client.get(url_string(query='{test}')) + response = client.get(url_string(app, query='{test}')) assert response.data.decode() == ( '{"data":{"test":"Hello World"}}' ) -def test_supports_pretty_printing_by_request(client): - response = client.get(url_string(query='{test}', pretty='1')) +def test_supports_pretty_printing_by_request(app, client): + response = client.get(url_string(app, query='{test}', pretty='1')) assert response.data.decode() == ( '{\n' @@ -362,8 +389,8 @@ def test_supports_pretty_printing_by_request(client): ) -def test_handles_field_errors_caught_by_graphql(client): - response = client.get(url_string(query='{thrower}')) +def test_handles_field_errors_caught_by_graphql(app, client): + response = client.get(url_string(app, query='{thrower}')) assert response.status_code == 200 assert response_json(response) == { 'data': None, @@ -371,8 +398,8 @@ def test_handles_field_errors_caught_by_graphql(client): } -def test_handles_syntax_errors_caught_by_graphql(client): - response = client.get(url_string(query='syntaxerror')) +def test_handles_syntax_errors_caught_by_graphql(app, client): + response = client.get(url_string(app, query='syntaxerror')) assert response.status_code == 400 assert response_json(response) == { 'errors': [{'locations': [{'column': 1, 'line': 1}], @@ -381,8 +408,8 @@ def test_handles_syntax_errors_caught_by_graphql(client): } -def test_handles_errors_caused_by_a_lack_of_query(client): - response = client.get(url_string()) +def test_handles_errors_caused_by_a_lack_of_query(app, client): + response = client.get(url_string(app)) assert response.status_code == 400 assert response_json(response) == { @@ -390,8 +417,8 @@ def test_handles_errors_caused_by_a_lack_of_query(client): } -def test_handles_batch_correctly_if_is_disabled(client): - response = client.post(url_string(), data='[]', content_type='application/json') +def test_handles_batch_correctly_if_is_disabled(app, client): + response = client.post(url_string(app), data='[]', content_type='application/json') assert response.status_code == 400 assert response_json(response) == { @@ -399,8 +426,8 @@ def test_handles_batch_correctly_if_is_disabled(client): } -def test_handles_incomplete_json_bodies(client): - response = client.post(url_string(), data='{"query":', content_type='application/json') +def test_handles_incomplete_json_bodies(app, client): + response = client.post(url_string(app), data='{"query":', content_type='application/json') assert response.status_code == 400 assert response_json(response) == { @@ -408,8 +435,9 @@ def test_handles_incomplete_json_bodies(client): } -def test_handles_plain_post_text(client): +def test_handles_plain_post_text(app, client): response = client.post(url_string( + app, variables=json.dumps({'who': "Dolly"}) ), data='query helloWho($who: String){ test(who: $who) }', @@ -421,8 +449,9 @@ def test_handles_plain_post_text(client): } -def test_handles_poorly_formed_variables(client): +def test_handles_poorly_formed_variables(app, client): response = client.get(url_string( + app, query='query helloWho($who: String){ test(who: $who) }', variables='who:You' )) @@ -432,8 +461,8 @@ def test_handles_poorly_formed_variables(client): } -def test_handles_unsupported_http_methods(client): - response = client.put(url_string(query='{test}')) +def test_handles_unsupported_http_methods(app, client): + response = client.put(url_string(app, query='{test}')) assert response.status_code == 405 assert response.headers['Allow'] in ['GET, POST', 'HEAD, GET, POST, OPTIONS'] assert response_json(response) == { @@ -441,8 +470,8 @@ def test_handles_unsupported_http_methods(client): } -def test_passes_request_into_request_context(client): - response = client.get(url_string(query='{request}', q='testing')) +def test_passes_request_into_request_context(app, client): + response = client.get(url_string(app, query='{request}', q='testing')) assert response.status_code == 200 assert response_json(response) == { @@ -453,8 +482,8 @@ def test_passes_request_into_request_context(client): @pytest.mark.parametrize('app', [create_app(get_context_value=lambda:"CUSTOM CONTEXT")]) -def test_supports_pretty_printing_with_custom_context(app, client): - response = client.get(url_string(query='{context}')) +def test_passes_custom_context_into_context(app, client): + response = client.get(url_string(app, query='{context}')) assert response.status_code == 200 assert response_json(response) == { @@ -464,10 +493,10 @@ def test_supports_pretty_printing_with_custom_context(app, client): } -def test_post_multipart_data(client): +def test_post_multipart_data(app, client): query = 'mutation TestMutation { writeTest { test } }' response = client.post( - url_string(), + url_string(app), data={ 'query': query, 'file': (StringIO(), 'text1.txt'), @@ -482,8 +511,8 @@ def test_post_multipart_data(client): @pytest.mark.parametrize('app', [create_app(batch=True)]) def test_batch_allows_post_with_json_encoding(app, client): response = client.post( - url_string(), - data=jl( + url_string(app), + data=json_dump_kwarg_list( # id=1, query='{test}' ), @@ -500,8 +529,8 @@ def test_batch_allows_post_with_json_encoding(app, client): @pytest.mark.parametrize('app', [create_app(batch=True)]) def test_batch_supports_post_json_query_with_json_variables(app, client): response = client.post( - url_string(), - data=jl( + url_string(app), + data=json_dump_kwarg_list( # id=1, query='query helloWho($who: String){ test(who: $who) }', variables={'who': "Dolly"} @@ -519,8 +548,8 @@ def test_batch_supports_post_json_query_with_json_variables(app, client): @pytest.mark.parametrize('app', [create_app(batch=True)]) def test_batch_allows_post_with_operation_name(app, client): response = client.post( - url_string(), - data=jl( + url_string(app), + data=json_dump_kwarg_list( # id=1, query=''' query helloYou { test(who: "You"), ...shared } diff --git a/tox.ini b/tox.ini index 303a459..fb4b51e 100644 --- a/tox.ini +++ b/tox.ini @@ -1,31 +1,32 @@ [tox] -envlist = flake8,import-order,py35,py27,py33,py34,py36,py37,pypy -skipsdist = true +envlist = + py{27,35,36,37} + flake8,import-order,manifest +; requires = tox-conda [testenv] +passenv = * setenv = PYTHONPATH = {toxinidir} -deps = - pytest>=2.7.2 - pytest-flask>=0.10.0 - graphql-core>=2.1,<3 - graphql-server-core>=1.1,<2 - Flask>=0.10.0 - pytest-cov -commands = - py{py,27,34,35,36,37}: py.test tests {posargs} +install_command = python -m pip install --ignore-installed {opts} {packages} +deps = -e.[test] +commands = + pytest --cov=flask_graphql tests {posargs} [testenv:flake8] basepython=python3.6 -deps = flake8 +deps = -e.[dev] commands = flake8 flask_graphql [testenv:import-order] basepython=python3.6 -deps = - isort - graphql-core>=2.1 - Flask>=0.10.0 +deps = -e.[dev] commands = isort --check-only flask_graphql/ -rc + +[testenv:manifest] +basepython = python3.6 +deps = -e.[dev] +commands = + check-manifest -v \ No newline at end of file