diff --git a/poetry.lock b/poetry.lock index 1b0fabbd..d468ac5d 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 2.1.3 and should not be changed by hand. +# This file is automatically @generated by Poetry 2.2.0 and should not be changed by hand. [[package]] name = "alabaster" @@ -39,6 +39,76 @@ files = [ {file = "alabaster-1.0.0.tar.gz", hash = "sha256:c00dca57bca26fa62a6d7d0a9fcce65f3e026e9bfe33e9c538fd3fbb2144fd9e"}, ] +[[package]] +name = "anyio" +version = "3.7.1" +description = "High level compatibility layer for multiple asynchronous event loop implementations" +optional = false +python-versions = ">=3.7" +groups = ["test"] +markers = "python_version == \"3.7\"" +files = [ + {file = "anyio-3.7.1-py3-none-any.whl", hash = "sha256:91dee416e570e92c64041bd18b900d1d6fa78dff7048769ce5ac5ddad004fbb5"}, + {file = "anyio-3.7.1.tar.gz", hash = "sha256:44a3c9aba0f5defa43261a8b3efb97891f2bd7d804e0e1f56419befa1adfc780"}, +] + +[package.dependencies] +exceptiongroup = {version = "*", markers = "python_version < \"3.11\""} +idna = ">=2.8" +sniffio = ">=1.1" +typing-extensions = {version = "*", markers = "python_version < \"3.8\""} + +[package.extras] +doc = ["Sphinx", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme (>=1.2.2)", "sphinxcontrib-jquery"] +test = ["anyio[trio]", "coverage[toml] (>=4.5)", "hypothesis (>=4.0)", "mock (>=4) ; python_version < \"3.8\"", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (>=0.17) ; python_version < \"3.12\" and platform_python_implementation == \"CPython\" and platform_system != \"Windows\""] +trio = ["trio (<0.22)"] + +[[package]] +name = "anyio" +version = "4.5.2" +description = "High level compatibility layer for multiple asynchronous event loop implementations" +optional = false +python-versions = ">=3.8" +groups = ["test"] +markers = "python_version == \"3.8\"" +files = [ + {file = "anyio-4.5.2-py3-none-any.whl", hash = "sha256:c011ee36bc1e8ba40e5a81cb9df91925c218fe9b778554e0b56a21e1b5d4716f"}, + {file = "anyio-4.5.2.tar.gz", hash = "sha256:23009af4ed04ce05991845451e11ef02fc7c5ed29179ac9a420e5ad0ac7ddc5b"}, +] + +[package.dependencies] +exceptiongroup = {version = ">=1.0.2", markers = "python_version < \"3.11\""} +idna = ">=2.8" +sniffio = ">=1.1" +typing-extensions = {version = ">=4.1", markers = "python_version < \"3.11\""} + +[package.extras] +doc = ["Sphinx (>=7.4,<8.0)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"] +test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "truststore (>=0.9.1) ; python_version >= \"3.10\"", "uvloop (>=0.21.0b1) ; platform_python_implementation == \"CPython\" and platform_system != \"Windows\""] +trio = ["trio (>=0.26.1)"] + +[[package]] +name = "anyio" +version = "4.10.0" +description = "High-level concurrency and networking framework on top of asyncio or Trio" +optional = false +python-versions = ">=3.9" +groups = ["test"] +markers = "python_version >= \"3.9\"" +files = [ + {file = "anyio-4.10.0-py3-none-any.whl", hash = "sha256:60e474ac86736bbfd6f210f7a61218939c318f43f9972497381f1c5e930ed3d1"}, + {file = "anyio-4.10.0.tar.gz", hash = "sha256:3f3fae35c96039744587aa5b8371e7e8e603c0702999535961dd336026973ba6"}, +] + +[package.dependencies] +exceptiongroup = {version = ">=1.0.2", markers = "python_version < \"3.11\""} +idna = ">=2.8" +sniffio = ">=1.1" +typing_extensions = {version = ">=4.5", markers = "python_version < \"3.13\""} + +[package.extras] +trio = ["trio (>=0.26.1)"] + [[package]] name = "babel" version = "2.14.0" @@ -793,7 +863,7 @@ version = "3.10" description = "Internationalized Domain Names in Applications (IDNA)" optional = false python-versions = ">=3.6" -groups = ["doc"] +groups = ["doc", "test"] files = [ {file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"}, {file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"}, @@ -2027,6 +2097,18 @@ files = [ {file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"}, ] +[[package]] +name = "sniffio" +version = "1.3.1" +description = "Sniff out which async library your code is running under" +optional = false +python-versions = ">=3.7" +groups = ["test"] +files = [ + {file = "sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2"}, + {file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"}, +] + [[package]] name = "snowballstemmer" version = "3.0.1" @@ -2700,7 +2782,7 @@ files = [ {file = "typing_extensions-4.14.0-py3-none-any.whl", hash = "sha256:a1514509136dd0b477638fc68d6a91497af5076466ad0fa6c338e44e359944af"}, {file = "typing_extensions-4.14.0.tar.gz", hash = "sha256:8676b788e32f02ab42d9e7c61324048ae4c6d844a399eebace3d4979d75ceef4"}, ] -markers = {main = "python_version == \"3.9\"", lint = "python_version >= \"3.9\"", test = "python_version >= \"3.9\" and python_version < \"3.11\""} +markers = {main = "python_version == \"3.9\"", lint = "python_version >= \"3.9\"", test = "python_version >= \"3.9\" and python_version < \"3.13\""} [[package]] name = "urllib3" @@ -2866,4 +2948,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.1" python-versions = "^3.7" -content-hash = "3a799a01d8f5813c295459d99bcfb2bed3ac5a8a0b25f89115755e996bbd219b" +content-hash = "12ce0a9707cba570a9f059f45620953ab92bb65551f96663fd7956e295b3c32e" diff --git a/pyproject.toml b/pyproject.toml index c5c1ca31..f69d9e9d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -52,6 +52,7 @@ typing-extensions = [ optional = true [tool.poetry.group.test.dependencies] +anyio = { version = ">= 3.7.1" } pytest = [ { version = "^8.3", python = ">=3.8" }, { version = "^7.4", python = "<3.8" } @@ -321,7 +322,7 @@ addopts = "--benchmark-disable" # Deactivate default name pattern for test classes (we use pytest_describe). python_classes = "PyTest*" # Handle all async fixtures and tests automatically by asyncio, -asyncio_mode = "auto" +asyncio_mode = "strict" # Set a timeout in seconds for aborting tests that run too long. timeout = "100" # Ignore config options not (yet) available in older Python versions. diff --git a/tests/conftest.py b/tests/conftest.py index afb04855..ca76b236 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -20,3 +20,8 @@ def pytest_collection_modifyitems(config, items): for item in items: if "slow" in item.keywords: item.add_marker(skip_slow) + + +@pytest.fixture +def anyio_backend(): + return "asyncio" diff --git a/tests/execution/test_abstract.py b/tests/execution/test_abstract.py index ddb01345..3df9e1cd 100644 --- a/tests/execution/test_abstract.py +++ b/tests/execution/test_abstract.py @@ -22,14 +22,14 @@ def sync_and_async(spec): """Decorator for running a test synchronously and asynchronously.""" - return pytest.mark.asyncio( + return pytest.mark.anyio( pytest.mark.parametrize("sync", [True, False], ids=("sync", "async"))(spec) ) def access_variants(spec): """Decorator for tests with dict and object access, including inheritance.""" - return pytest.mark.asyncio( + return pytest.mark.anyio( pytest.mark.parametrize("access", ["dict", "object", "inheritance"])(spec) ) diff --git a/tests/execution/test_customize.py b/tests/execution/test_customize.py index bf1859a2..27688eb4 100644 --- a/tests/execution/test_customize.py +++ b/tests/execution/test_customize.py @@ -6,6 +6,8 @@ from graphql.language import parse from graphql.type import GraphQLField, GraphQLObjectType, GraphQLSchema, GraphQLString +pytestmark = pytest.mark.anyio + try: anext # noqa: B018 except NameError: # pragma: no cover (Python < 3.10) @@ -78,7 +80,6 @@ def execute_field( def describe_customize_subscription(): - @pytest.mark.asyncio async def uses_a_custom_subscribe_field_resolver(): schema = GraphQLSchema( query=GraphQLObjectType("Query", {"foo": GraphQLField(GraphQLString)}), @@ -107,7 +108,6 @@ async def custom_foo(): await subscription.aclose() - @pytest.mark.asyncio async def uses_a_custom_execution_context_class(): class TestExecutionContext(ExecutionContext): def __init__(self, *args, **kwargs): diff --git a/tests/execution/test_defer.py b/tests/execution/test_defer.py index 1fcfa25c..13a3099d 100644 --- a/tests/execution/test_defer.py +++ b/tests/execution/test_defer.py @@ -36,6 +36,8 @@ GraphQLString, ) +pytestmark = pytest.mark.anyio + friend_type = GraphQLObjectType( "Friend", { @@ -549,7 +551,6 @@ def can_print_stream_items_record(): str(record) == "StreamItemsRecord(stream_record=StreamRecord(path=['bar']))" ) - @pytest.mark.asyncio async def can_defer_fragments_containing_scalar_types(): document = parse( """ @@ -579,7 +580,6 @@ async def can_defer_fragments_containing_scalar_types(): }, ] - @pytest.mark.asyncio async def can_disable_defer_using_if_argument(): document = parse( """ @@ -598,7 +598,6 @@ async def can_disable_defer_using_if_argument(): assert result == {"data": {"hero": {"id": "1", "name": "Luke"}}} - @pytest.mark.asyncio async def does_not_disable_defer_with_null_if_argument(): document = parse( """ @@ -628,7 +627,6 @@ async def does_not_disable_defer_with_null_if_argument(): }, ] - @pytest.mark.asyncio async def throws_an_error_for_defer_directive_with_non_string_label(): document = parse( """ @@ -649,7 +647,6 @@ async def throws_an_error_for_defer_directive_with_non_string_label(): ], } - @pytest.mark.asyncio async def can_defer_fragments_on_the_top_level_query_field(): document = parse( """ @@ -678,7 +675,6 @@ async def can_defer_fragments_on_the_top_level_query_field(): }, ] - @pytest.mark.asyncio async def can_defer_fragments_with_errors_on_the_top_level_query_field(): document = parse( """ @@ -719,7 +715,6 @@ async def can_defer_fragments_with_errors_on_the_top_level_query_field(): }, ] - @pytest.mark.asyncio async def can_defer_a_fragment_within_an_already_deferred_fragment(): document = parse( """ @@ -771,7 +766,6 @@ async def can_defer_a_fragment_within_an_already_deferred_fragment(): }, ] - @pytest.mark.asyncio async def can_defer_a_fragment_that_is_also_not_deferred_with_deferred_first(): document = parse( """ @@ -790,7 +784,6 @@ async def can_defer_a_fragment_that_is_also_not_deferred_with_deferred_first(): assert result == {"data": {"hero": {"name": "Luke"}}} - @pytest.mark.asyncio async def can_defer_a_fragment_that_is_also_not_deferred_with_non_deferred_first(): document = parse( """ @@ -809,7 +802,6 @@ async def can_defer_a_fragment_that_is_also_not_deferred_with_non_deferred_first assert result == {"data": {"hero": {"name": "Luke"}}} - @pytest.mark.asyncio async def can_defer_an_inline_fragment(): document = parse( """ @@ -838,7 +830,6 @@ async def can_defer_an_inline_fragment(): }, ] - @pytest.mark.asyncio async def does_not_emit_empty_defer_fragments(): document = parse( """ @@ -858,7 +849,6 @@ async def does_not_emit_empty_defer_fragments(): assert result == {"data": {"hero": {}}} - @pytest.mark.asyncio async def emits_children_of_empty_defer_fragments(): document = parse( """ @@ -888,7 +878,6 @@ async def emits_children_of_empty_defer_fragments(): }, ] - @pytest.mark.asyncio async def separately_emits_defer_fragments_different_labels_varying_fields(): document = parse( """ @@ -925,7 +914,6 @@ async def separately_emits_defer_fragments_different_labels_varying_fields(): }, ] - @pytest.mark.asyncio async def separately_emits_defer_fragments_different_labels_varying_subfields(): document = parse( """ @@ -965,7 +953,6 @@ async def separately_emits_defer_fragments_different_labels_varying_subfields(): }, ] - @pytest.mark.asyncio async def separately_emits_defer_fragments_different_labels_var_subfields_async(): document = parse( """ @@ -1017,7 +1004,6 @@ async def resolve(value): }, ] - @pytest.mark.asyncio async def separately_emits_defer_fragments_var_subfields_same_prio_diff_level(): document = parse( """ @@ -1056,7 +1042,6 @@ async def separately_emits_defer_fragments_var_subfields_same_prio_diff_level(): }, ] - @pytest.mark.asyncio async def separately_emits_nested_defer_frags_var_subfields_same_prio_diff_level(): document = parse( """ @@ -1093,7 +1078,6 @@ async def separately_emits_nested_defer_frags_var_subfields_same_prio_diff_level }, ] - @pytest.mark.asyncio async def can_deduplicate_multiple_defers_on_the_same_object(): document = parse( """ @@ -1145,7 +1129,6 @@ async def can_deduplicate_multiple_defers_on_the_same_object(): }, ] - @pytest.mark.asyncio async def deduplicates_fields_present_in_the_initial_payload(): document = parse( """ @@ -1211,7 +1194,6 @@ async def deduplicates_fields_present_in_the_initial_payload(): }, ] - @pytest.mark.asyncio async def deduplicates_fields_present_in_a_parent_defer_payload(): document = parse( """ @@ -1263,7 +1245,6 @@ async def deduplicates_fields_present_in_a_parent_defer_payload(): }, ] - @pytest.mark.asyncio async def deduplicates_fields_with_deferred_fragments_at_multiple_levels(): document = parse( """ @@ -1358,7 +1339,6 @@ async def deduplicates_fields_with_deferred_fragments_at_multiple_levels(): }, ] - @pytest.mark.asyncio async def deduplicates_fields_from_deferred_fragments_branches_same_level(): document = parse( """ @@ -1409,7 +1389,6 @@ async def deduplicates_fields_from_deferred_fragments_branches_same_level(): }, ] - @pytest.mark.asyncio async def deduplicates_fields_from_deferred_fragments_branches_multi_levels(): document = parse( """ @@ -1462,7 +1441,6 @@ async def deduplicates_fields_from_deferred_fragments_branches_multi_levels(): }, ] - @pytest.mark.asyncio async def nulls_cross_defer_boundaries_null_first(): document = parse( """ @@ -1929,7 +1907,6 @@ async def resolve_nested_object(_info): assert result == {"data": {"hero": {"nestedObject": {"name": "foo"}}}} - @pytest.mark.asyncio async def handles_errors_thrown_in_deferred_fragments(): document = parse( """ @@ -1971,7 +1948,6 @@ async def handles_errors_thrown_in_deferred_fragments(): }, ] - @pytest.mark.asyncio async def handles_non_nullable_errors_thrown_in_deferred_fragments(): document = parse( """ @@ -2014,7 +1990,6 @@ async def handles_non_nullable_errors_thrown_in_deferred_fragments(): }, ] - @pytest.mark.asyncio async def handles_non_nullable_errors_thrown_outside_deferred_fragments(): document = parse( """ @@ -2045,7 +2020,6 @@ async def handles_non_nullable_errors_thrown_outside_deferred_fragments(): ], } - @pytest.mark.asyncio async def handles_async_non_nullable_errors_thrown_in_deferred_fragments(): document = parse( """ @@ -2088,7 +2062,6 @@ async def handles_async_non_nullable_errors_thrown_in_deferred_fragments(): }, ] - @pytest.mark.asyncio async def returns_payloads_in_correct_order(): document = parse( """ @@ -2140,7 +2113,6 @@ async def returns_payloads_in_correct_order(): }, ] - @pytest.mark.asyncio async def returns_payloads_from_synchronous_data_in_correct_order(): document = parse( """ @@ -2192,7 +2164,6 @@ async def returns_payloads_from_synchronous_data_in_correct_order(): }, ] - @pytest.mark.asyncio async def filters_deferred_payloads_when_list_item_from_async_iterable_nulled(): document = parse( """ @@ -2226,7 +2197,6 @@ async def filters_deferred_payloads_when_list_item_from_async_iterable_nulled(): ], } - @pytest.mark.asyncio async def original_execute_function_throws_error_if_deferred_and_all_is_sync(): document = parse( """ @@ -2244,7 +2214,6 @@ async def original_execute_function_throws_error_if_deferred_and_all_is_sync(): " multiple payloads (due to @defer or @stream directive)" ) - @pytest.mark.asyncio async def original_execute_function_throws_error_if_deferred_and_not_all_is_sync(): document = parse( """ diff --git a/tests/execution/test_executor.py b/tests/execution/test_executor.py index e2d2db1f..d176872a 100644 --- a/tests/execution/test_executor.py +++ b/tests/execution/test_executor.py @@ -28,6 +28,8 @@ ResponsePath, ) +pytestmark = pytest.mark.anyio + def describe_execute_handles_basic_execution_tasks(): def accepts_positional_arguments(): @@ -42,7 +44,6 @@ def accepts_positional_arguments(): assert result == ({"a": "rootValue"}, None) - @pytest.mark.asyncio async def executes_arbitrary_code(): # noinspection PyMethodMayBeStatic,PyMethodMayBeStatic class Data: @@ -376,7 +377,6 @@ def resolve(_obj, _info, **args): assert len(resolved_args) == 1 assert resolved_args[0] == {"numArg": 123, "stringArg": "foo"} - @pytest.mark.asyncio async def nulls_out_error_subtrees(): document = parse( """ @@ -865,7 +865,6 @@ def resolves_to_an_error_if_schema_does_not_support_operation(): ], ) - @pytest.mark.asyncio async def correct_field_ordering_despite_execution_order(): schema = GraphQLSchema( GraphQLObjectType( @@ -981,7 +980,6 @@ def does_not_include_arguments_that_were_not_set(): None, ) - @pytest.mark.asyncio async def fails_when_is_type_of_check_is_not_met(): class Special: value: str diff --git a/tests/execution/test_lists.py b/tests/execution/test_lists.py index 083c437c..8aae173a 100644 --- a/tests/execution/test_lists.py +++ b/tests/execution/test_lists.py @@ -17,6 +17,8 @@ ) from graphql.utilities import build_schema +pytestmark = pytest.mark.anyio + class Data: def __init__(self, value): @@ -172,7 +174,6 @@ async def _list_field( assert is_awaitable(result) return await result - @pytest.mark.asyncio async def accepts_an_async_generator_as_a_list_value(): async def list_field(): yield "two" @@ -184,7 +185,6 @@ async def list_field(): None, ) - @pytest.mark.asyncio async def accepts_a_custom_async_iterable_as_a_list_value(): class ListField: def __aiter__(self): @@ -203,7 +203,6 @@ async def __anext__(self): None, ) - @pytest.mark.asyncio async def handles_an_async_generator_that_throws(): async def list_field(): yield "two" @@ -215,7 +214,6 @@ async def list_field(): [{"message": "bad", "locations": [(1, 3)], "path": ["listField"]}], ) - @pytest.mark.asyncio async def handles_an_async_generator_where_intermediate_value_triggers_an_error(): async def list_field(): yield "two" @@ -233,7 +231,6 @@ async def list_field(): ], ) - @pytest.mark.asyncio @pytest.mark.filterwarnings("ignore:.* was never awaited:RuntimeWarning") async def handles_errors_from_complete_value_in_async_iterables(): async def list_field(): @@ -251,7 +248,6 @@ async def list_field(): ], ) - @pytest.mark.asyncio async def handles_async_functions_from_complete_value_in_async_iterables(): async def resolve(data: _IndexData, _info: GraphQLResolveInfo) -> int: return data.index @@ -261,7 +257,6 @@ async def resolve(data: _IndexData, _info: GraphQLResolveInfo) -> int: None, ) - @pytest.mark.asyncio async def handles_single_async_functions_from_complete_value_in_async_iterables(): async def resolve(data: _IndexData, _info: GraphQLResolveInfo) -> int: return data.index @@ -271,7 +266,6 @@ async def resolve(data: _IndexData, _info: GraphQLResolveInfo) -> int: None, ) - @pytest.mark.asyncio async def handles_async_errors_from_complete_value_in_async_iterables(): async def resolve(data: _IndexData, _info: GraphQLResolveInfo) -> int: index = data.index @@ -290,7 +284,6 @@ async def resolve(data: _IndexData, _info: GraphQLResolveInfo) -> int: ], ) - @pytest.mark.asyncio async def handles_nulls_yielded_by_async_generator(): async def list_field(): yield 1 @@ -324,7 +317,6 @@ def execute_query(list_value: Any) -> Any: return result - @pytest.mark.asyncio async def contains_values(): list_field = [1, 2] assert await _complete(list_field, "[Int]") == ({"listField": [1, 2]}, None) @@ -332,7 +324,6 @@ async def contains_values(): assert await _complete(list_field, "[Int!]") == ({"listField": [1, 2]}, None) assert await _complete(list_field, "[Int!]!") == ({"listField": [1, 2]}, None) - @pytest.mark.asyncio async def contains_null(): list_field = [1, None, 2] errors = [ @@ -353,7 +344,6 @@ async def contains_null(): assert await _complete(list_field, "[Int!]") == ({"listField": None}, errors) assert await _complete(list_field, "[Int!]!") == (None, errors) - @pytest.mark.asyncio async def returns_null(): list_field = None errors = [ @@ -368,7 +358,6 @@ async def returns_null(): assert await _complete(list_field, "[Int!]") == ({"listField": None}, None) assert await _complete(list_field, "[Int!]!") == (None, errors) - @pytest.mark.asyncio async def contains_error(): list_field = [1, RuntimeError("bad"), 2] errors = [ @@ -395,7 +384,6 @@ async def contains_error(): errors, ) - @pytest.mark.asyncio async def results_in_errors(): list_field = RuntimeError("bad") errors = [ diff --git a/tests/execution/test_map_async_iterable.py b/tests/execution/test_map_async_iterable.py index eb3cddb8..4acab183 100644 --- a/tests/execution/test_map_async_iterable.py +++ b/tests/execution/test_map_async_iterable.py @@ -2,6 +2,9 @@ from graphql.execution import map_async_iterable +pytestmark = pytest.mark.anyio + + try: # pragma: no cover anext # noqa: B018 except NameError: # pragma: no cover (Python < 3.10) @@ -22,7 +25,6 @@ async def throw(_x: int) -> int: def describe_map_async_iterable(): - @pytest.mark.asyncio async def maps_over_async_generator(): async def source(): yield 1 @@ -37,7 +39,6 @@ async def source(): with pytest.raises(StopAsyncIteration): assert await anext(doubles) - @pytest.mark.asyncio async def maps_over_async_iterable(): items = [1, 2, 3] @@ -58,7 +59,6 @@ async def __anext__(self): assert not items assert values == [2, 4, 6] - @pytest.mark.asyncio async def compatible_with_async_for(): async def source(): yield 1 @@ -71,7 +71,6 @@ async def source(): assert values == [2, 4, 6] - @pytest.mark.asyncio async def allows_returning_early_from_mapped_async_generator(): async def source(): yield 1 @@ -92,7 +91,6 @@ async def source(): with pytest.raises(StopAsyncIteration): await anext(doubles) - @pytest.mark.asyncio async def allows_returning_early_from_mapped_async_iterable(): items = [1, 2, 3] @@ -120,7 +118,6 @@ async def __anext__(self): with pytest.raises(StopAsyncIteration): await anext(doubles) - @pytest.mark.asyncio async def allows_throwing_errors_through_async_iterable(): items = [1, 2, 3] @@ -151,7 +148,6 @@ async def __anext__(self): with pytest.raises(StopAsyncIteration): await anext(doubles) - @pytest.mark.asyncio async def allows_throwing_errors_with_traceback_through_async_iterables(): class Iterable: def __aiter__(self): @@ -178,7 +174,6 @@ async def __anext__(self): with pytest.raises(StopAsyncIteration): await anext(one) - @pytest.mark.asyncio async def does_not_map_over_thrown_errors(): async def source(): yield 1 @@ -193,7 +188,6 @@ async def source(): assert str(exc_info.value) == "Goodbye" - @pytest.mark.asyncio async def does_not_map_over_externally_thrown_errors(): async def source(): yield 1 @@ -207,7 +201,6 @@ async def source(): assert str(exc_info.value) == "Goodbye" - @pytest.mark.asyncio async def iterable_is_closed_when_mapped_iterable_is_closed(): class Iterable: def __init__(self): @@ -231,7 +224,6 @@ async def aclose(self): with pytest.raises(StopAsyncIteration): await anext(doubles) - @pytest.mark.asyncio async def iterable_is_closed_on_callback_error(): class Iterable: def __init__(self): @@ -254,7 +246,6 @@ async def aclose(self): with pytest.raises(StopAsyncIteration): await anext(doubles) - @pytest.mark.asyncio async def iterable_exits_on_callback_error(): exited = False @@ -273,7 +264,6 @@ async def iterable(): with pytest.raises(StopAsyncIteration): await anext(doubles) - @pytest.mark.asyncio async def mapped_iterable_is_closed_when_iterable_cannot_be_closed(): class Iterable: def __aiter__(self): @@ -288,7 +278,6 @@ async def __anext__(self): with pytest.raises(StopAsyncIteration): await anext(doubles) - @pytest.mark.asyncio async def ignores_that_iterable_cannot_be_closed_on_callback_error(): class Iterable: def __aiter__(self): diff --git a/tests/execution/test_middleware.py b/tests/execution/test_middleware.py index 50159995..3faab298 100644 --- a/tests/execution/test_middleware.py +++ b/tests/execution/test_middleware.py @@ -7,6 +7,8 @@ from graphql.language.parser import parse from graphql.type import GraphQLField, GraphQLObjectType, GraphQLSchema, GraphQLString +pytestmark = pytest.mark.anyio + def describe_middleware(): def describe_with_manager(): @@ -91,7 +93,6 @@ def capitalize_middleware(next_, *args, **kwargs): assert result.data == {"first": "Eno", "second": "Owt"} # type: ignore - @pytest.mark.asyncio async def single_async_function(): doc = parse("{ first second }") @@ -201,7 +202,6 @@ def resolve(self, next_, *args, **kwargs): ) assert result.data == {"field": "devloseR"} # type: ignore - @pytest.mark.asyncio async def with_async_function_and_object(): doc = parse("{ field }") @@ -238,7 +238,6 @@ async def resolve(self, next_, *args, **kwargs): result = await awaitable_result assert result.data == {"field": "devloseR"} - @pytest.mark.asyncio async def subscription_simple(): async def bar_resolve(_obj, _info): yield "bar" diff --git a/tests/execution/test_mutations.py b/tests/execution/test_mutations.py index b03004de..e88d7e74 100644 --- a/tests/execution/test_mutations.py +++ b/tests/execution/test_mutations.py @@ -20,6 +20,8 @@ GraphQLSchema, ) +pytestmark = pytest.mark.anyio + # noinspection PyPep8Naming class NumberHolder: @@ -107,7 +109,6 @@ async def promise_to_get_the_number(holder: NumberHolder, _info) -> int: def describe_execute_handles_mutation_execution_ordering(): - @pytest.mark.asyncio async def evaluates_mutations_serially(): document = parse( """ @@ -155,7 +156,6 @@ def does_not_include_illegal_mutation_fields_in_output(): result = execute_sync(schema=schema, document=document) assert result == ({}, None) - @pytest.mark.asyncio async def evaluates_mutations_correctly_in_presence_of_a_failed_mutation(): document = parse( """ @@ -212,7 +212,6 @@ async def evaluates_mutations_correctly_in_presence_of_a_failed_mutation(): ], ) - @pytest.mark.asyncio async def mutation_fields_with_defer_do_not_block_next_mutation(): document = parse( """ @@ -254,7 +253,6 @@ async def mutation_fields_with_defer_do_not_block_next_mutation(): }, ] - @pytest.mark.asyncio async def mutation_inside_of_a_fragment(): document = parse( """ @@ -280,7 +278,6 @@ async def mutation_inside_of_a_fragment(): None, ) - @pytest.mark.asyncio async def mutation_with_defer_is_not_executed_serially(): document = parse( """ diff --git a/tests/execution/test_nonnull.py b/tests/execution/test_nonnull.py index 6c98eb67..84a51a03 100644 --- a/tests/execution/test_nonnull.py +++ b/tests/execution/test_nonnull.py @@ -17,6 +17,8 @@ ) from graphql.utilities import build_schema +pytestmark = pytest.mark.anyio + sync_error = RuntimeError("sync") sync_non_null_error = RuntimeError("syncNonNull") promise_error = RuntimeError("promise") @@ -126,12 +128,10 @@ def describe_nulls_a_nullable_field(): } """ - @pytest.mark.asyncio async def returns_null(): result = await execute_sync_and_async(query, NullingData()) assert result == ({"sync": None}, None) - @pytest.mark.asyncio async def throws(): result = await execute_sync_and_async(query, ThrowingData()) assert result == ( @@ -154,7 +154,6 @@ def describe_nulls_a_returned_object_that_contains_a_non_null_field(): } """ - @pytest.mark.asyncio async def that_returns_null(): result = await execute_sync_and_async(query, NullingData()) assert result == ( @@ -169,7 +168,6 @@ async def that_returns_null(): ], ) - @pytest.mark.asyncio async def that_throws(): result = await execute_sync_and_async(query, ThrowingData()) assert result == ( @@ -215,14 +213,12 @@ def describe_nulls_a_complex_tree_of_nullable_fields_each(): }, } - @pytest.mark.asyncio async def returns_null(): result = await cast( "Awaitable[ExecutionResult]", execute_query(query, NullingData()) ) assert result == (data, None) - @pytest.mark.asyncio async def throws(): result = await cast( "Awaitable[ExecutionResult]", execute_query(query, ThrowingData()) @@ -349,7 +345,6 @@ def describe_nulls_first_nullable_after_long_chain_of_non_null_fields(): "anotherPromiseNest": None, } - @pytest.mark.asyncio async def returns_null(): result = await cast( "Awaitable[ExecutionResult]", execute_query(query, NullingData()) @@ -412,7 +407,6 @@ async def returns_null(): ], ) - @pytest.mark.asyncio async def throws(): result = await cast( "Awaitable[ExecutionResult]", execute_query(query, ThrowingData()) @@ -478,7 +472,6 @@ def describe_nulls_the_top_level_if_non_nullable_field(): } """ - @pytest.mark.asyncio async def returns_null(): result = await execute_sync_and_async(query, NullingData()) await asyncio.sleep(0) # strangely needed to get coverage on Python 3.11 @@ -494,7 +487,6 @@ async def returns_null(): ], ) - @pytest.mark.asyncio async def throws(): result = await execute_sync_and_async(query, ThrowingData()) await asyncio.sleep(0) # strangely needed to get coverage on Python 3.11 diff --git a/tests/execution/test_parallel.py b/tests/execution/test_parallel.py index 82b23855..a94a5d44 100644 --- a/tests/execution/test_parallel.py +++ b/tests/execution/test_parallel.py @@ -17,6 +17,8 @@ GraphQLString, ) +pytestmark = pytest.mark.anyio + class Barrier: """Barrier that makes progress only after a certain number of waits.""" @@ -33,7 +35,6 @@ async def wait(self) -> bool: def describe_parallel_execution(): - @pytest.mark.asyncio async def resolve_single_field(): # make sure that the special case of resolving a single field works async def resolve(*_args): @@ -54,7 +55,6 @@ async def resolve(*_args): assert result == ({"foo": True}, None) - @pytest.mark.asyncio async def resolve_fields_in_parallel(): barrier = Barrier(2) @@ -80,7 +80,6 @@ async def resolve(*_args): assert result == ({"foo": True, "bar": True}, None) - @pytest.mark.asyncio async def resolve_single_element_list(): # make sure that the special case of resolving a single element list works async def resolve(*_args): @@ -99,7 +98,6 @@ async def resolve(*_args): assert result == ({"foo": [True]}, None) - @pytest.mark.asyncio async def resolve_list_in_parallel(): barrier = Barrier(2) @@ -129,7 +127,6 @@ async def resolve_list(*args): assert result == ({"foo": [True, True]}, None) - @pytest.mark.asyncio async def resolve_is_type_of_in_parallel(): FooType = GraphQLInterfaceType("Foo", {"foo": GraphQLField(GraphQLString)}) @@ -201,7 +198,6 @@ def describe_cancel_on_exception(): These tests are specifically targeted at the Python asyncio implementation. """ - @pytest.mark.asyncio async def cancel_selection_sets(): barrier = Barrier(2) completed = False @@ -244,7 +240,6 @@ async def fail(*_args): await asyncio.sleep(0) assert not completed - @pytest.mark.asyncio async def cancel_lists(): barrier = Barrier(2) completed = False @@ -290,7 +285,6 @@ async def resolve_list(*args): await asyncio.sleep(0) assert not completed - @pytest.mark.asyncio async def cancel_async_iterators(): barrier = Barrier(2) completed = False @@ -337,7 +331,6 @@ async def resolve_iterator(*args): await asyncio.sleep(0) assert not completed - @pytest.mark.asyncio async def cancel_type_resolver(): FooType = GraphQLInterfaceType("Foo", {"foo": GraphQLField(GraphQLString)}) diff --git a/tests/execution/test_stream.py b/tests/execution/test_stream.py index a52e0d87..ed543c08 100644 --- a/tests/execution/test_stream.py +++ b/tests/execution/test_stream.py @@ -25,6 +25,9 @@ GraphQLString, ) +pytestmark = pytest.mark.anyio + + try: # pragma: no cover anext # noqa: B018 except NameError: # pragma: no cover (Python < 3.10) @@ -216,7 +219,6 @@ def can_print_stream_record(): record = StreamRecord(Path(None, "bar", "Bar"), "foo") assert str(record) == "StreamRecord(path=['bar'], label='foo')" - @pytest.mark.asyncio async def can_stream_a_list_field(): document = parse("{ scalarList @stream(initialCount: 1) }") result = await complete( @@ -236,7 +238,6 @@ async def can_stream_a_list_field(): }, ] - @pytest.mark.asyncio async def can_use_default_value_of_initial_count(): document = parse("{ scalarList @stream }") result = await complete( @@ -257,7 +258,6 @@ async def can_use_default_value_of_initial_count(): }, ] - @pytest.mark.asyncio async def negative_values_of_initial_count_throw_field_errors(): document = parse("{ scalarList @stream(initialCount: -2) }") result = await complete( @@ -274,7 +274,6 @@ async def negative_values_of_initial_count_throw_field_errors(): ], } - @pytest.mark.asyncio async def non_integer_values_of_initial_count_throw_field_errors(): document = parse("{ scalarList @stream(initialCount: 1.5) }") result = await complete(document, {"scalarList": ["apple", "half of a banana"]}) @@ -289,7 +288,6 @@ async def non_integer_values_of_initial_count_throw_field_errors(): ], } - @pytest.mark.asyncio async def returns_label_from_stream_directive(): document = parse( '{ scalarList @stream(initialCount: 1, label: "scalar-stream") }' @@ -313,7 +311,6 @@ async def returns_label_from_stream_directive(): }, ] - @pytest.mark.asyncio async def throws_an_error_for_stream_directive_with_non_string_label(): document = parse("{ scalarList @stream(initialCount: 1, label: 42) }") result = await complete(document, {"scalarList": ["some apples"]}) @@ -328,7 +325,6 @@ async def throws_an_error_for_stream_directive_with_non_string_label(): ], } - @pytest.mark.asyncio async def can_disable_stream_using_if_argument(): document = parse("{ scalarList @stream(initialCount: 0, if: false) }") result = await complete( @@ -336,7 +332,6 @@ async def can_disable_stream_using_if_argument(): ) assert result == {"data": {"scalarList": ["apple", "banana", "coconut"]}} - @pytest.mark.asyncio async def does_not_disable_stream_with_null_if_argument(): document = parse( "query ($shouldStream: Boolean)" @@ -358,7 +353,6 @@ async def does_not_disable_stream_with_null_if_argument(): }, ] - @pytest.mark.asyncio async def can_stream_multi_dimensional_lists(): document = parse("{ scalarListList @stream(initialCount: 1) }") result = await complete( @@ -390,7 +384,6 @@ async def can_stream_multi_dimensional_lists(): }, ] - @pytest.mark.asyncio async def can_stream_a_field_that_returns_a_list_of_awaitables(): document = parse( """ @@ -428,7 +421,6 @@ async def await_friend(f): }, ] - @pytest.mark.asyncio async def can_stream_in_correct_order_with_list_of_awaitables(): document = parse( """ @@ -469,7 +461,6 @@ async def await_friend(f): }, ] - @pytest.mark.asyncio async def can_stream_a_field_that_returns_a_list_with_nested_async_fields(): document = parse( """ @@ -514,7 +505,6 @@ async def get_id(f): }, ] - @pytest.mark.asyncio async def handles_error_in_list_of_awaitables_before_initial_count_reached(): document = parse( """ @@ -560,7 +550,6 @@ async def await_friend(f, i): }, ] - @pytest.mark.asyncio async def handles_error_in_list_of_awaitables_after_initial_count_reached(): document = parse( """ @@ -615,7 +604,6 @@ async def await_friend(f, i): }, ] - @pytest.mark.asyncio async def can_stream_a_field_that_returns_an_async_iterable(): document = parse( """ @@ -654,7 +642,6 @@ async def friend_list(_info): {"completed": [{"id": "0"}], "hasNext": False}, ] - @pytest.mark.asyncio async def can_stream_a_field_that_returns_an_async_iterable_with_initial_count(): document = parse( """ @@ -690,7 +677,6 @@ async def friend_list(_info): {"completed": [{"id": "0"}], "hasNext": False}, ] - @pytest.mark.asyncio async def negative_initial_count_throw_error_on_field_returning_async_iterable(): document = parse( """ @@ -718,7 +704,6 @@ async def friend_list(_info): "data": {"friendList": None}, } - @pytest.mark.asyncio async def can_handle_concurrent_calls_to_next_without_waiting(): document = parse( """ @@ -766,7 +751,6 @@ async def friend_list(_info): {"done": True, "value": None}, ] - @pytest.mark.asyncio async def handles_error_in_async_iterable_before_initial_count_is_reached(): document = parse( """ @@ -795,7 +779,6 @@ async def friend_list(_info): "data": {"friendList": None}, } - @pytest.mark.asyncio async def handles_error_in_async_iterable_after_initial_count_is_reached(): document = parse( """ @@ -836,7 +819,6 @@ async def friend_list(_info): }, ] - @pytest.mark.asyncio async def handles_null_for_non_null_list_items_after_initial_count_is_reached(): document = parse( """ @@ -875,7 +857,6 @@ async def handles_null_for_non_null_list_items_after_initial_count_is_reached(): }, ] - @pytest.mark.asyncio async def handles_null_for_non_null_async_items_after_initial_count_is_reached(): document = parse( """ @@ -919,7 +900,6 @@ async def friend_list(_info): }, ] - @pytest.mark.asyncio async def handles_error_thrown_in_complete_value_after_initial_count_is_reached(): document = parse( """ @@ -958,7 +938,6 @@ async def scalar_list(_info): }, ] - @pytest.mark.asyncio async def handles_async_error_in_complete_value_after_initial_count_is_reached(): document = parse( """ @@ -1014,7 +993,6 @@ def get_friends(_info): }, ] - @pytest.mark.asyncio async def handles_nested_async_error_in_complete_value_after_initial_count(): document = parse( """ @@ -1069,7 +1047,6 @@ def get_friends(_info): }, ] - @pytest.mark.asyncio async def handles_async_error_in_complete_value_after_initial_count_non_null(): document = parse( """ @@ -1119,7 +1096,6 @@ def get_friends(_info): }, ] - @pytest.mark.asyncio async def handles_nested_async_error_in_complete_value_after_initial_non_null(): document = parse( """ @@ -1170,7 +1146,6 @@ def get_friends(_info): }, ] - @pytest.mark.asyncio async def handles_async_error_in_complete_value_after_initial_from_async_iterable(): document = parse( """ @@ -1227,7 +1202,6 @@ async def get_friends(_info): {"completed": [{"id": "0"}], "hasNext": False}, ] - @pytest.mark.asyncio async def handles_async_error_in_complete_value_from_async_generator_non_null(): document = parse( """ @@ -1276,7 +1250,6 @@ async def get_friends(_info): }, ] - @pytest.mark.asyncio async def handles_async_errors_in_complete_value_after_initial_count_no_aclose(): # Handles async errors thrown by complete_value after initialCount is reached # from async iterable for a non-nullable list when the async iterable does @@ -1337,7 +1310,6 @@ async def __anext__(self): }, ] - @pytest.mark.asyncio async def handles_async_errors_in_complete_value_after_initial_count_slow_aclose(): # Handles async errors thrown by completeValue after initialCount is reached # from async iterable for a non-nullable list when the async iterable provides @@ -1406,7 +1378,6 @@ async def aclose(self): ] assert async_iterable.finished - @pytest.mark.asyncio async def filters_payloads_that_are_nulled(): document = parse( """ @@ -1449,7 +1420,6 @@ async def friend_list(_info): "data": {"nestedObject": None}, } - @pytest.mark.asyncio async def filters_payloads_that_are_nulled_by_a_later_synchronous_error(): document = parse( """ @@ -1489,7 +1459,6 @@ async def friend_list(_info): "data": {"nestedObject": None}, } - @pytest.mark.asyncio @pytest.mark.filterwarnings("ignore:.* was never awaited:RuntimeWarning") async def does_not_filter_payloads_when_null_error_is_in_a_different_path(): document = parse( @@ -1558,7 +1527,6 @@ async def friend_list(_info): {"completed": [{"id": "1"}], "hasNext": False}, ] - @pytest.mark.asyncio @pytest.mark.filterwarnings("ignore:.* was never awaited:RuntimeWarning") async def filters_stream_payloads_that_are_nulled_in_a_deferred_payload(): document = parse( @@ -1626,7 +1594,6 @@ async def friend_list(_info): }, ] - @pytest.mark.asyncio async def filters_defer_payloads_that_are_nulled_in_a_stream_response(): document = parse( """ @@ -1682,7 +1649,6 @@ async def friend_list(_info): ] @pytest.mark.timeout(1) - @pytest.mark.asyncio async def returns_iterator_and_ignores_error_when_stream_payloads_are_filtered(): finished = False @@ -1767,7 +1733,6 @@ async def iterable(_info): assert finished - @pytest.mark.asyncio async def handles_awaitables_from_complete_value_after_initial_count_is_reached(): document = parse( """ @@ -1815,7 +1780,6 @@ async def get_friends(_info): {"completed": [{"id": "0"}], "hasNext": False}, ] - @pytest.mark.asyncio async def handles_overlapping_deferred_and_non_deferred_streams(): document = parse( """ @@ -1869,7 +1833,6 @@ async def get_nested_friend_list(_info): {"completed": [{"id": "0"}], "hasNext": False}, ] - @pytest.mark.asyncio async def returns_payloads_properly_when_parent_deferred_slower_than_stream(): resolve_slow_field = Event() @@ -1945,7 +1908,6 @@ async def get_friends(_info): await anext(iterator) @pytest.mark.timeout(1) - @pytest.mark.asyncio async def can_defer_fields_that_are_resolved_after_async_iterable_is_complete(): resolve_slow_field = Event() resolve_iterable = Event() @@ -2022,7 +1984,6 @@ async def get_friends(_info): with pytest.raises(StopAsyncIteration): await anext(iterator) - @pytest.mark.asyncio async def can_defer_fields_that_are_resolved_before_async_iterable_is_complete(): resolve_slow_field = Event() resolve_iterable = Event() @@ -2102,7 +2063,6 @@ async def get_friends(_info): with pytest.raises(StopAsyncIteration): await anext(iterator) - @pytest.mark.asyncio async def finishes_async_iterable_when_finished_generator_is_closed(): finished = False @@ -2147,7 +2107,6 @@ async def iterable(_info): assert finished - @pytest.mark.asyncio async def finishes_async_iterable_when_underlying_iterator_has_no_close_method(): class Iterable: def __init__(self): @@ -2196,7 +2155,6 @@ async def __anext__(self): assert iterable.index == 4 - @pytest.mark.asyncio async def finishes_async_iterable_when_error_is_raised_in_finished_generator(): finished = False diff --git a/tests/execution/test_subscribe.py b/tests/execution/test_subscribe.py index 3c3cba60..08e65142 100644 --- a/tests/execution/test_subscribe.py +++ b/tests/execution/test_subscribe.py @@ -36,6 +36,8 @@ from ..fixtures import cleanup from ..utils.assert_equal_awaitables_or_values import assert_equal_awaitables_or_values +pytestmark = pytest.mark.anyio + try: from typing import TypedDict except ImportError: # Python < 3.8 @@ -198,7 +200,6 @@ def subscribe_with_bad_args( # Check all error cases when initializing the subscription. def describe_subscription_initialization_phase(): - @pytest.mark.asyncio async def accepts_positional_arguments(): document = parse( """ @@ -218,7 +219,6 @@ async def empty_async_iterable(_info): await anext(ai) await ai.aclose() # type: ignore - @pytest.mark.asyncio async def accepts_multiple_subscription_fields_defined_in_schema(): schema = GraphQLSchema( query=DummyQueryType, @@ -243,7 +243,6 @@ async def foo_generator(_info): await subscription.aclose() # type: ignore - @pytest.mark.asyncio async def accepts_type_definition_with_sync_subscribe_function(): async def foo_generator(_obj, _info): yield {"foo": "FooValue"} @@ -263,7 +262,6 @@ async def foo_generator(_obj, _info): await subscription.aclose() # type: ignore - @pytest.mark.asyncio async def accepts_type_definition_with_async_subscribe_function(): async def foo_generator(_obj, _info): await asyncio.sleep(0) @@ -291,7 +289,6 @@ async def subscribe_fn(obj, info): await subscription.aclose() # type: ignore - @pytest.mark.asyncio async def should_only_resolve_the_first_field_of_invalid_multi_field(): did_resolve = {"foo": False, "bar": False} @@ -326,7 +323,6 @@ async def subscribe_bar(_obj, _info): # pragma: no cover await subscription.aclose() # type: ignore - @pytest.mark.asyncio async def resolves_to_an_error_if_schema_does_not_support_subscriptions(): schema = GraphQLSchema(query=DummyQueryType) document = parse("subscription { unknownField }") @@ -344,7 +340,6 @@ async def resolves_to_an_error_if_schema_does_not_support_subscriptions(): ], ) - @pytest.mark.asyncio async def resolves_to_an_error_for_unknown_subscription_field(): schema = GraphQLSchema( query=DummyQueryType, @@ -365,7 +360,6 @@ async def resolves_to_an_error_for_unknown_subscription_field(): ], ) - @pytest.mark.asyncio async def should_pass_through_unexpected_errors_thrown_in_subscribe(): schema = GraphQLSchema( query=DummyQueryType, @@ -376,7 +370,6 @@ async def should_pass_through_unexpected_errors_thrown_in_subscribe(): with pytest.raises(AttributeError): subscribe_with_bad_args(schema=schema, document={}) # type: ignore - @pytest.mark.asyncio async def throws_an_error_if_subscribe_does_not_return_an_iterator(): expected_result = ( None, @@ -405,7 +398,6 @@ async def async_fn(obj, info): del result cleanup() - @pytest.mark.asyncio async def resolves_to_an_error_for_subscription_resolver_errors(): expected_result = ( None, @@ -447,7 +439,6 @@ async def reject_with_error(*args): assert is_awaitable(result) assert await result == expected_result - @pytest.mark.asyncio async def resolves_to_an_error_if_variables_were_wrong_type(): schema = GraphQLSchema( query=DummyQueryType, @@ -492,7 +483,6 @@ async def resolves_to_an_error_if_variables_were_wrong_type(): # Once a subscription returns a valid AsyncIterator, it can still yield errors. def describe_subscription_publish_phase(): - @pytest.mark.asyncio async def produces_a_payload_for_multiple_subscribe_in_same_subscription(): pubsub = SimplePubSub() @@ -527,7 +517,6 @@ async def produces_a_payload_for_multiple_subscribe_in_same_subscription(): assert await payload1 == (expected_payload, None) assert await payload2 == (expected_payload, None) - @pytest.mark.asyncio async def produces_a_payload_when_queried_fields_are_async(): pubsub = SimplePubSub() subscription = create_subscription(pubsub, {"asyncResolver": True}) @@ -564,7 +553,6 @@ async def produces_a_payload_when_queried_fields_are_async(): with pytest.raises(StopAsyncIteration): await anext(subscription) - @pytest.mark.asyncio async def produces_a_payload_per_subscription_event(): pubsub = SimplePubSub() subscription = create_subscription(pubsub) @@ -643,7 +631,6 @@ async def produces_a_payload_per_subscription_event(): with pytest.raises(StopAsyncIteration): assert await anext(subscription) - @pytest.mark.asyncio async def subscribe_function_returns_errors_with_defer(): pubsub = SimplePubSub() subscription = create_subscription(pubsub, {"shouldDefer": True}) @@ -707,7 +694,6 @@ async def subscribe_function_returns_errors_with_defer(): with pytest.raises(StopAsyncIteration): assert await anext(subscription) - @pytest.mark.asyncio async def subscribe_function_returns_errors_with_stream(): pubsub = SimplePubSub() subscription = create_subscription(pubsub, {"shouldStream": True}) @@ -788,7 +774,6 @@ async def subscribe_function_returns_errors_with_stream(): with pytest.raises(StopAsyncIteration): assert await anext(subscription) - @pytest.mark.asyncio async def produces_a_payload_when_there_are_multiple_events(): pubsub = SimplePubSub() subscription = create_subscription(pubsub) @@ -844,7 +829,6 @@ async def produces_a_payload_when_there_are_multiple_events(): None, ) - @pytest.mark.asyncio async def should_not_trigger_when_subscription_is_already_done(): pubsub = SimplePubSub() subscription = create_subscription(pubsub) @@ -895,7 +879,6 @@ async def should_not_trigger_when_subscription_is_already_done(): with pytest.raises(StopAsyncIteration): await payload - @pytest.mark.asyncio async def should_not_trigger_when_subscription_is_thrown(): pubsub = SimplePubSub() subscription = create_subscription(pubsub) @@ -936,7 +919,6 @@ async def should_not_trigger_when_subscription_is_thrown(): with pytest.raises(StopAsyncIteration): await payload - @pytest.mark.asyncio async def event_order_is_correct_for_multiple_publishes(): pubsub = SimplePubSub() subscription = create_subscription(pubsub) @@ -992,7 +974,6 @@ async def event_order_is_correct_for_multiple_publishes(): None, ) - @pytest.mark.asyncio async def should_handle_error_during_execution_of_source_event(): async def generate_messages(_obj, _info): yield "Hello" @@ -1040,7 +1021,6 @@ def resolve_message(message, _info): # Subsequent events are still executed. assert await anext(subscription) == ({"newMessage": "Bonjour"}, None) - @pytest.mark.asyncio async def should_pass_through_error_thrown_in_source_event_stream(): async def generate_messages(_obj, _info): yield "Hello" @@ -1077,7 +1057,6 @@ def resolve_message(message, _info): with pytest.raises(StopAsyncIteration): await anext(subscription) - @pytest.mark.asyncio async def should_work_with_sync_resolve_function(): async def generate_messages(_obj, _info): yield "Hello" @@ -1105,7 +1084,6 @@ def resolve_message(message, _info): assert await anext(subscription) == ({"newMessage": "Hello"}, None) - @pytest.mark.asyncio async def should_work_with_async_resolve_function(): async def generate_messages(_obj, _info): await asyncio.sleep(0) @@ -1135,7 +1113,6 @@ async def resolve_message(message, _info): assert await anext(subscription) == ({"newMessage": "Hello"}, None) - @pytest.mark.asyncio async def should_work_with_custom_async_iterator(): class MessageGenerator: resolved: List[str] = [] @@ -1185,7 +1162,6 @@ async def resolve(cls, message, _info) -> str: await subscription.aclose() # type: ignore - @pytest.mark.asyncio async def should_close_custom_async_iterator(): class MessageGenerator: closed: bool = False diff --git a/tests/execution/test_sync.py b/tests/execution/test_sync.py index af2faf28..f49084b2 100644 --- a/tests/execution/test_sync.py +++ b/tests/execution/test_sync.py @@ -9,6 +9,8 @@ from ..fixtures import cleanup +pytestmark = pytest.mark.anyio + def describe_execute_synchronously_when_possible(): def _resolve_sync(root_value, _info): @@ -52,7 +54,6 @@ def does_not_return_an_awaitable_if_mutation_fields_are_all_synchronous(): None, ) - @pytest.mark.asyncio async def returns_an_awaitable_if_any_field_is_asynchronous(): doc = "query Example { syncField, asyncField }" result = execute(schema, parse(doc), "rootValue") @@ -81,7 +82,6 @@ def does_not_throw_if_not_encountering_async_execution_with_check_sync(): None, ) - @pytest.mark.asyncio @pytest.mark.filterwarnings("ignore:.* was never awaited:RuntimeWarning") async def throws_if_encountering_async_execution_with_check_sync(): doc = "query Example { syncField, asyncField }" @@ -94,7 +94,6 @@ async def throws_if_encountering_async_execution_with_check_sync(): del exc_info cleanup() - @pytest.mark.asyncio @pytest.mark.filterwarnings("ignore:.* was never awaited:RuntimeWarning") async def throws_if_encountering_async_operation_without_check_sync(): doc = "query Example { syncField, asyncField }" @@ -113,7 +112,6 @@ async def throws_if_encountering_async_operation_without_check_sync(): del result cleanup() - @pytest.mark.asyncio async def throws_if_encountering_async_iterable_execution_with_check_sync(): doc = """ query Example { @@ -132,7 +130,6 @@ async def throws_if_encountering_async_iterable_execution_with_check_sync(): del exc_info cleanup() - @pytest.mark.asyncio async def throws_if_encountering_async_iterable_execution_without_check_sync(): doc = """ query Example { @@ -187,7 +184,6 @@ def does_not_throw_if_not_encountering_async_operation_with_check_sync(): None, ) - @pytest.mark.asyncio @pytest.mark.filterwarnings("ignore:.* was never awaited:RuntimeWarning") async def throws_if_encountering_async_operation_with_check_sync(): doc = "query Example { syncField, asyncField }" @@ -198,7 +194,6 @@ async def throws_if_encountering_async_operation_with_check_sync(): del exc_info cleanup() - @pytest.mark.asyncio @pytest.mark.filterwarnings("ignore:.* was never awaited:RuntimeWarning") async def throws_if_encountering_async_operation_without_check_sync(): doc = "query Example { syncField, asyncField }" diff --git a/tests/pyutils/test_async_reduce.py b/tests/pyutils/test_async_reduce.py index 0ac606c8..9561d9aa 100644 --- a/tests/pyutils/test_async_reduce.py +++ b/tests/pyutils/test_async_reduce.py @@ -4,6 +4,8 @@ from graphql.pyutils import async_reduce, is_awaitable +pytestmark = pytest.mark.anyio + def describe_async_reduce(): def works_like_reduce_for_lists_of_ints(): @@ -17,7 +19,6 @@ def callback(accumulator, current_value): assert result == 42 assert result == reduce(callback, values, initial_value) - @pytest.mark.asyncio async def works_with_sync_values_and_sync_initial_value(): def callback(accumulator, current_value): return accumulator + "-" + current_value @@ -27,7 +28,6 @@ def callback(accumulator, current_value): assert not is_awaitable(result) assert result == "foo-bar-baz" - @pytest.mark.asyncio async def works_with_async_initial_value(): async def async_initial_value(): return "foo" @@ -40,7 +40,6 @@ def callback(accumulator, current_value): assert is_awaitable(result) assert await result == "foo-bar-baz" - @pytest.mark.asyncio async def works_with_async_callback(): async def async_callback(accumulator, current_value): return accumulator + "-" + current_value @@ -50,7 +49,6 @@ async def async_callback(accumulator, current_value): assert is_awaitable(result) assert await result == "foo-bar-baz" - @pytest.mark.asyncio async def works_with_async_callback_and_async_initial_value(): async def async_initial_value(): return 1 / 8 diff --git a/tests/pyutils/test_gather_with_cancel.py b/tests/pyutils/test_gather_with_cancel.py index d4832d80..f1a66ada 100644 --- a/tests/pyutils/test_gather_with_cancel.py +++ b/tests/pyutils/test_gather_with_cancel.py @@ -7,6 +7,8 @@ from graphql.pyutils import gather_with_cancel, is_awaitable +pytestmark = pytest.mark.anyio + class Controller: def reset(self, wait=False): @@ -52,7 +54,6 @@ def __await__(self): def describe_gather_with_cancel(): @with_all_types_of_awaitables - @pytest.mark.asyncio async def gathers_all_values(type_of_awaitable: str): factory = awaitable_factories[type_of_awaitable] values = list(range(3)) @@ -73,7 +74,6 @@ async def gathers_all_values(type_of_awaitable: str): assert awaited == values @with_all_types_of_awaitables - @pytest.mark.asyncio async def raises_on_exception(type_of_awaitable: str): factory = awaitable_factories[type_of_awaitable] values = list(range(4)) @@ -96,7 +96,6 @@ async def raises_on_exception(type_of_awaitable: str): assert controller.returned == values[:-1] @with_all_types_of_awaitables - @pytest.mark.asyncio async def cancels_on_exception(type_of_awaitable: str): factory = awaitable_factories[type_of_awaitable] values = list(range(4)) diff --git a/tests/pyutils/test_inspect.py b/tests/pyutils/test_inspect.py index 94c62b48..57efce30 100644 --- a/tests/pyutils/test_inspect.py +++ b/tests/pyutils/test_inspect.py @@ -18,6 +18,8 @@ GraphQLString, ) +pytestmark = pytest.mark.anyio + inspect_module = import_module(inspect.__module__) @@ -139,7 +141,6 @@ def test_generator(): assert inspect(test_generator) == "" assert inspect(test_generator()) == "" - @pytest.mark.asyncio async def inspect_coroutine(): async def test_coroutine(): pass diff --git a/tests/pyutils/test_is_awaitable.py b/tests/pyutils/test_is_awaitable.py index b05f01af..dff0f0dd 100644 --- a/tests/pyutils/test_is_awaitable.py +++ b/tests/pyutils/test_is_awaitable.py @@ -6,6 +6,8 @@ from graphql.pyutils import is_awaitable +pytestmark = pytest.mark.anyio + def describe_is_awaitable(): def declines_the_none_value(): @@ -67,7 +69,6 @@ async def some_async_function(): assert not isawaitable(some_async_function) assert not is_awaitable(some_async_function) - @pytest.mark.asyncio async def recognizes_a_coroutine_object(): async def some_async_function(): return True @@ -84,6 +85,7 @@ async def some_async_function(): python_version >= (3, 11), reason="Generator-based coroutines not supported any more since Python 3.11", ) + @pytest.mark.parametrize("anyio_backend", ["asyncio"], indirect=True) async def recognizes_an_old_style_coroutine(): # pragma: no cover @asyncio.coroutine # type: ignore def some_function(): @@ -93,7 +95,6 @@ def some_function(): assert is_awaitable(some_old_style_coroutine) assert is_awaitable(some_old_style_coroutine) - @pytest.mark.asyncio async def recognizes_a_future_object(): async def some_async_function(): return True @@ -106,7 +107,6 @@ async def some_async_function(): assert await some_future is True - @pytest.mark.asyncio async def declines_an_async_generator(): async def some_async_generator_function(): yield True diff --git a/tests/pyutils/test_simple_pub_sub.py b/tests/pyutils/test_simple_pub_sub.py index f0a88dcb..02141bc3 100644 --- a/tests/pyutils/test_simple_pub_sub.py +++ b/tests/pyutils/test_simple_pub_sub.py @@ -4,9 +4,10 @@ from graphql.pyutils import SimplePubSub, is_awaitable +pytestmark = pytest.mark.anyio + def describe_simple_pub_sub(): - @pytest.mark.asyncio async def subscribe_async_iterator_mock(): pubsub = SimplePubSub() iterator = pubsub.get_subscriber() @@ -50,7 +51,6 @@ async def subscribe_async_iterator_mock(): with pytest.raises(StopAsyncIteration): await iterator.__anext__() - @pytest.mark.asyncio async def iterator_aclose_empties_push_queue(): pubsub = SimplePubSub() assert not pubsub.subscribers @@ -68,7 +68,6 @@ async def iterator_aclose_empties_push_queue(): assert iterator.pull_queue.qsize() == 0 assert not iterator.listening - @pytest.mark.asyncio async def iterator_aclose_empties_pull_queue(): pubsub = SimplePubSub() assert not pubsub.subscribers @@ -85,7 +84,6 @@ async def iterator_aclose_empties_pull_queue(): assert iterator.pull_queue.qsize() == 0 assert not iterator.listening - @pytest.mark.asyncio async def iterator_aclose_is_idempotent(): pubsub = SimplePubSub() iterator = pubsub.get_subscriber() diff --git a/tests/test_star_wars_query.py b/tests/test_star_wars_query.py index bb1008b8..b9a223db 100644 --- a/tests/test_star_wars_query.py +++ b/tests/test_star_wars_query.py @@ -4,10 +4,11 @@ from .star_wars_schema import star_wars_schema as schema +pytestmark = pytest.mark.anyio + def describe_star_wars_query_tests(): def describe_basic_queries(): - @pytest.mark.asyncio async def correctly_identifies_r2_d2_as_hero_of_the_star_wars_saga(): source = """ query HeroNameQuery { @@ -19,7 +20,6 @@ async def correctly_identifies_r2_d2_as_hero_of_the_star_wars_saga(): result = await graphql(schema=schema, source=source) assert result == ({"hero": {"name": "R2-D2"}}, None) - @pytest.mark.asyncio async def accepts_positional_arguments_to_graphql(): source = """ query HeroNameQuery { @@ -34,7 +34,6 @@ async def accepts_positional_arguments_to_graphql(): sync_result = graphql_sync(schema, source) assert sync_result == result - @pytest.mark.asyncio async def allows_us_to_query_for_the_id_and_friends_of_r2_d2(): source = """ query HeroNameAndFriendsQuery { @@ -64,7 +63,6 @@ async def allows_us_to_query_for_the_id_and_friends_of_r2_d2(): ) def describe_nested_queries(): - @pytest.mark.asyncio async def allows_us_to_query_for_the_friends_of_friends_of_r2_d2(): source = """ query NestedQuery { @@ -122,7 +120,6 @@ async def allows_us_to_query_for_the_friends_of_friends_of_r2_d2(): ) def describe_using_ids_and_query_parameters_to_refetch_objects(): - @pytest.mark.asyncio async def allows_us_to_query_for_r2_d2_directly_using_his_id(): source = """ query { @@ -134,7 +131,6 @@ async def allows_us_to_query_for_r2_d2_directly_using_his_id(): result = await graphql(schema=schema, source=source) assert result == ({"droid": {"name": "R2-D2"}}, None) - @pytest.mark.asyncio async def allows_us_to_query_characters_directly_using_their_id(): source = """ query FetchLukeAndC3POQuery { @@ -152,7 +148,6 @@ async def allows_us_to_query_characters_directly_using_their_id(): None, ) - @pytest.mark.asyncio async def allows_creating_a_generic_query_to_fetch_luke_using_his_id(): source = """ query FetchSomeIDQuery($someId: String!) { @@ -167,7 +162,6 @@ async def allows_creating_a_generic_query_to_fetch_luke_using_his_id(): ) assert result == ({"human": {"name": "Luke Skywalker"}}, None) - @pytest.mark.asyncio async def allows_creating_a_generic_query_to_fetch_han_using_his_id(): source = """ query FetchSomeIDQuery($someId: String!) { @@ -182,7 +176,6 @@ async def allows_creating_a_generic_query_to_fetch_han_using_his_id(): ) assert result == ({"human": {"name": "Han Solo"}}, None) - @pytest.mark.asyncio async def generic_query_that_gets_null_back_when_passed_invalid_id(): source = """ query humanQuery($id: String!) { @@ -198,7 +191,6 @@ async def generic_query_that_gets_null_back_when_passed_invalid_id(): assert result == ({"human": None}, None) def describe_using_aliases_to_change_the_key_in_the_response(): - @pytest.mark.asyncio async def allows_us_to_query_for_luke_changing_his_key_with_an_alias(): source = """ query FetchLukeAliased { @@ -210,7 +202,6 @@ async def allows_us_to_query_for_luke_changing_his_key_with_an_alias(): result = await graphql(schema=schema, source=source) assert result == ({"luke": {"name": "Luke Skywalker"}}, None) - @pytest.mark.asyncio async def query_for_luke_and_leia_using_two_root_fields_and_an_alias(): source = """ query FetchLukeAndLeiaAliased { @@ -229,7 +220,6 @@ async def query_for_luke_and_leia_using_two_root_fields_and_an_alias(): ) def describe_uses_fragments_to_express_more_complex_queries(): - @pytest.mark.asyncio async def allows_us_to_query_using_duplicated_content(): source = """ query DuplicateFields { @@ -252,7 +242,6 @@ async def allows_us_to_query_using_duplicated_content(): None, ) - @pytest.mark.asyncio async def allows_us_to_use_a_fragment_to_avoid_duplicating_content(): source = """ query UseFragment { @@ -278,7 +267,6 @@ async def allows_us_to_use_a_fragment_to_avoid_duplicating_content(): ) def describe_using_typename_to_find_the_type_of_an_object(): - @pytest.mark.asyncio async def allows_us_to_verify_that_r2_d2_is_a_droid(): source = """ query CheckTypeOfR2 { @@ -291,7 +279,6 @@ async def allows_us_to_verify_that_r2_d2_is_a_droid(): result = await graphql(schema=schema, source=source) assert result == ({"hero": {"__typename": "Droid", "name": "R2-D2"}}, None) - @pytest.mark.asyncio async def allows_us_to_verify_that_luke_is_a_human(): source = """ query CheckTypeOfLuke { @@ -308,7 +295,6 @@ async def allows_us_to_verify_that_luke_is_a_human(): ) def describe_reporting_errors_raised_in_resolvers(): - @pytest.mark.asyncio async def correctly_reports_error_on_accessing_secret_backstory(): source = """ query HeroNameQuery { @@ -330,7 +316,6 @@ async def correctly_reports_error_on_accessing_secret_backstory(): ], ) - @pytest.mark.asyncio async def correctly_reports_error_on_accessing_backstory_in_a_list(): source = """ query HeroNameQuery { @@ -374,7 +359,6 @@ async def correctly_reports_error_on_accessing_backstory_in_a_list(): ], ) - @pytest.mark.asyncio async def correctly_reports_error_on_accessing_through_an_alias(): source = """ query HeroNameQuery { diff --git a/tests/test_user_registry.py b/tests/test_user_registry.py index 0cb2b5b9..f8b14cb7 100644 --- a/tests/test_user_registry.py +++ b/tests/test_user_registry.py @@ -32,6 +32,8 @@ ) from graphql.pyutils import SimplePubSub, SimplePubSubIterator, is_awaitable +pytestmark = pytest.mark.anyio + class User(NamedTuple): """A simple user object class.""" @@ -219,7 +221,6 @@ def context(): def describe_query(): - @pytest.mark.asyncio async def query_user(context): user = await context["registry"].create( firstName="John", lastName="Doe", tweets=42, verified=True @@ -251,7 +252,6 @@ async def query_user(context): def describe_mutation(): - @pytest.mark.asyncio async def create_user(context): received = {} @@ -303,7 +303,6 @@ def receive(msg): "User 0": {"user": user, "mutation": MutationEnum.CREATED.value}, } - @pytest.mark.asyncio async def update_user(context): received = {} @@ -359,7 +358,6 @@ def receive(msg): "User 0": {"user": user, "mutation": MutationEnum.UPDATED.value}, } - @pytest.mark.asyncio async def delete_user(context): received = {} @@ -401,7 +399,6 @@ def receive(msg): def describe_subscription(): - @pytest.mark.asyncio async def subscribe_to_user_mutations(context): query = """ subscription ($userId: ID!) { diff --git a/tests/utils/test_assert_equal_awaitables_or_values.py b/tests/utils/test_assert_equal_awaitables_or_values.py index 3e60fbcb..bb700701 100644 --- a/tests/utils/test_assert_equal_awaitables_or_values.py +++ b/tests/utils/test_assert_equal_awaitables_or_values.py @@ -2,6 +2,8 @@ from . import assert_equal_awaitables_or_values +pytestmark = pytest.mark.anyio + def describe_assert_equal_awaitables_or_values(): def throws_when_given_unequal_values(): @@ -15,7 +17,6 @@ def does_not_throw_when_given_equal_values(): == test_value ) - @pytest.mark.asyncio async def does_not_throw_when_given_equal_awaitables(): async def test_value(): return {"test": "test"} @@ -27,7 +28,6 @@ async def test_value(): == await test_value() ) - @pytest.mark.asyncio async def throws_when_given_unequal_awaitables(): async def test_value(value): return value @@ -37,7 +37,6 @@ async def test_value(value): test_value({}), test_value({}), test_value({"test": "test"}) ) - @pytest.mark.asyncio async def throws_when_given_mixture_of_equal_values_and_awaitables(): async def test_value(): return {"test": "test"} diff --git a/tox.ini b/tox.ini index 685389e6..3644d750 100644 --- a/tox.ini +++ b/tox.ini @@ -41,8 +41,8 @@ commands = [testenv] deps = + anyio>=3.7.1 pytest>=7.4,<9 - pytest-asyncio>=0.21.1,<1 pytest-benchmark>=4,<6 pytest-cov>=4.1,<7 pytest-describe>=2.2,<3