Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,10 @@ tests =
flake8>=3.0.0
mypy>=0.910,<1.9
# https://github.com/pytest-dev/pytest-asyncio/issues/706
# BACK COMAPAT: pytest-asyncio 0.21.2
# FROM: python 3
# TO: python 3.7
# URL: https://github.com/cylc/cylc-flow/pull/6726
pytest-asyncio>=0.21.2,!=0.23.*
Comment on lines +121 to 125
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can't drop 0.21 support just yet, because it's the last version to support Python 3.7 :(

pytest-cov>=2.8.0
pytest-xdist>=2
Expand Down
5 changes: 3 additions & 2 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
from typing import List, Optional, Tuple

import pytest
import pytest_asyncio

from cylc.flow import LOG, flags
from cylc.flow.cfgspec.glbl_cfg import glbl_cfg
Expand All @@ -40,7 +41,7 @@ def before_each():
GraphNodeParser.get_inst().clear()


@pytest.fixture(scope='module')
@pytest_asyncio.fixture(scope='module')
def mod_monkeypatch():
"""A module-scoped version of the monkeypatch fixture."""
from _pytest.monkeypatch import MonkeyPatch
Expand Down Expand Up @@ -160,7 +161,7 @@ def _log_scan(log, items):
return _log_scan


@pytest.fixture(scope='session')
@pytest_asyncio.fixture(scope='session')
def port_range():
return glbl_cfg().get(['scheduler', 'run hosts', 'ports'])

Expand Down
72 changes: 37 additions & 35 deletions tests/integration/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
)

import pytest
import pytest_asyncio

from cylc.flow.config import WorkflowConfig
from cylc.flow.id import Tokens
Expand Down Expand Up @@ -112,15 +113,15 @@ def _pytest_passed(request: pytest.FixtureRequest) -> bool:
))


@pytest.fixture(scope='session')
@pytest_asyncio.fixture(scope='session')
def run_dir():
"""The cylc run directory for this host."""
path = Path(get_cylc_run_dir())
path.mkdir(exist_ok=True)
yield path


@pytest.fixture(scope='session')
@pytest_asyncio.fixture(scope='session')
def ses_test_dir(request, run_dir):
"""The root run dir for test flows in this test session."""
timestamp = get_current_time_string(use_basic_format=True)
Expand All @@ -131,7 +132,7 @@ def ses_test_dir(request, run_dir):
_rm_if_empty(path)


@pytest.fixture(scope='module')
@pytest_asyncio.fixture(scope='module')
def mod_test_dir(request, ses_test_dir):
"""The root run dir for test flows in this test module."""
path = Path(
Expand Down Expand Up @@ -163,7 +164,7 @@ def test_dir(request, mod_test_dir):
_rm_if_empty(path)


@pytest.fixture(scope='module')
@pytest_asyncio.fixture(scope='module')
def mod_flow(run_dir, mod_test_dir):
"""A function for creating module-level flows."""
yield partial(_make_flow, run_dir, mod_test_dir)
Expand All @@ -175,7 +176,7 @@ def flow(run_dir, test_dir):
yield partial(_make_flow, run_dir, test_dir)


@pytest.fixture(scope='module')
@pytest_asyncio.fixture(scope='module')
def mod_scheduler():
"""Return a Scheduler object for a flow.

Expand All @@ -197,7 +198,7 @@ def scheduler():
yield _scheduler


@pytest.fixture(scope='module')
@pytest_asyncio.fixture(scope='module')
def mod_start():
"""Start a scheduler but don't set it running (module scope)."""
return partial(_start_flow, None)
Expand All @@ -209,7 +210,7 @@ def start(caplog: pytest.LogCaptureFixture):
return partial(_start_flow, caplog)


@pytest.fixture(scope='module')
@pytest_asyncio.fixture(scope='module')
def mod_run():
"""Start a scheduler and set it running (module scope)."""
return partial(_run_flow, None)
Expand All @@ -235,7 +236,7 @@ def one_conf():
}


@pytest.fixture(scope='module')
@pytest_asyncio.fixture(scope='module')
def mod_one_conf():
return {
'scheduler': {
Expand All @@ -257,36 +258,37 @@ def one(one_conf, flow, scheduler):
return schd


@pytest.fixture(scope='module')
@pytest_asyncio.fixture(scope='module')
def mod_one(mod_one_conf, mod_flow, mod_scheduler):
id_ = mod_flow(mod_one_conf)
schd = mod_scheduler(id_)
return schd


@pytest.fixture(scope='module')
def event_loop():
"""This fixture defines the event loop used for each test.

The default scoping for this fixture is "function" which means that all
async fixtures must have "function" scoping.

Defining `event_loop` as a module scoped fixture opens the door to
module scoped fixtures but means all tests in a module will run in the same
event loop. This is fine, it's actually an efficiency win but also
something to be aware of.

See: https://github.com/pytest-dev/pytest-asyncio/issues/171

"""
loop = asyncio.get_event_loop_policy().new_event_loop()
yield loop
# gracefully exit async generators
loop.run_until_complete(loop.shutdown_asyncgens())
# cancel any tasks still running in this event loop
for task in asyncio.all_tasks(loop):
task.cancel()
loop.close()
if pytest_asyncio.__version__.startswith('0.21'):
# BACK COMPAT: event_loop
# FROM: python 3
# TO: python 3.7
# URL: https://github.com/cylc/cylc-flow/pull/6726
@pytest_asyncio.fixture(scope='module')
def event_loop():
"""This fixture defines the event loop used for each test.
The default scoping for this fixture is "function" which means that all
async fixtures must have "function" scoping.
Defining `event_loop` as a module scoped fixture opens the door to
module scoped fixtures but means all tests in a module will run in the
same event loop. This is fine, it's actually an efficiency win but also
something to be aware of.
See: https://github.com/pytest-dev/pytest-asyncio/issues/171
"""
loop = asyncio.get_event_loop_policy().new_event_loop()
yield loop
# gracefully exit async generators
loop.run_until_complete(loop.shutdown_asyncgens())
# cancel any tasks still running in this event loop
for task in asyncio.all_tasks(loop):
task.cancel()
loop.close()
Comment on lines +268 to +291
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can get rid of this soon.



@pytest.fixture
Expand Down Expand Up @@ -382,7 +384,7 @@ def _validate(id_: Union[str, Path], **kwargs) -> WorkflowConfig:
return _validate


@pytest.fixture(scope='module')
@pytest_asyncio.fixture(scope='module')
def mod_validate(run_dir):
"""Provides a function for validating workflow configurations.

Expand Down Expand Up @@ -465,7 +467,7 @@ def run_job_cmd(
return _disable_polling


@pytest.fixture(scope='module')
@pytest_asyncio.fixture(scope='module')
def mod_workflow_source(mod_flow, tmp_path_factory):
"""Create a workflow source directory.

Expand Down Expand Up @@ -686,7 +688,7 @@ def complete():
return _complete


@pytest.fixture(scope='module')
@pytest_asyncio.fixture(scope='module')
def mod_complete():
return _complete

Expand Down
5 changes: 4 additions & 1 deletion tests/integration/network/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,19 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.

"""Test cylc.flow.client.WorkflowRuntimeClient."""

import json
from unittest.mock import Mock

import pytest
import pytest_asyncio

from cylc.flow.exceptions import ClientError
from cylc.flow.network.client import WorkflowRuntimeClient
from cylc.flow.network.server import PB_METHOD_MAP


@pytest.fixture(scope='module')
@pytest_asyncio.fixture(scope='module')
async def harness(mod_flow, mod_scheduler, mod_run, mod_one_conf):
id_ = mod_flow(mod_one_conf)
schd = mod_scheduler(id_)
Expand Down
6 changes: 4 additions & 2 deletions tests/integration/network/test_graphql.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,11 @@

"""Test the top-level (root) GraphQL queries."""

import pytest
from typing import TYPE_CHECKING

import pytest
import pytest_asyncio

from cylc.flow.id import Tokens
from cylc.flow.network.client import WorkflowRuntimeClient

Expand Down Expand Up @@ -68,7 +70,7 @@ def job_db_row():
]


@pytest.fixture(scope='module')
@pytest_asyncio.fixture(scope='module')
async def harness(mod_flow, mod_scheduler, mod_run):
flow_def = {
'scheduler': {
Expand Down
3 changes: 2 additions & 1 deletion tests/integration/network/test_resolvers.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from unittest.mock import Mock

import pytest
import pytest_asyncio

from cylc.flow.data_store_mgr import EDGES, TASK_PROXIES
from cylc.flow.id import Tokens
Expand Down Expand Up @@ -50,7 +51,7 @@ def node_args():
}


@pytest.fixture(scope='module')
@pytest_asyncio.fixture(scope='module')
async def mock_flow(
mod_flow: Callable[..., str],
mod_scheduler: Callable[..., Scheduler],
Expand Down
9 changes: 5 additions & 4 deletions tests/integration/network/test_scan.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
from typing import List

import pytest
import pytest_asyncio

from cylc.flow.network.scan import (
filter_name,
Expand Down Expand Up @@ -81,7 +82,7 @@ def make_src(name):
make_src(name)


@pytest.fixture(scope='session')
@pytest_asyncio.fixture(scope='session')
def sample_run_dir():
tmp_path = Path(TemporaryDirectory().name)
tmp_path.mkdir()
Expand Down Expand Up @@ -111,7 +112,7 @@ def badly_messed_up_cylc_run_dir(
return tmp_path


@pytest.fixture(scope='session')
@pytest_asyncio.fixture(scope='session')
def run_dir_with_symlinks():
tmp_path = Path(TemporaryDirectory().name)
tmp_path.mkdir()
Expand All @@ -133,7 +134,7 @@ def run_dir_with_symlinks():
rmtree(tmp_path)


@pytest.fixture(scope='session')
@pytest_asyncio.fixture(scope='session')
def run_dir_with_nasty_symlinks():
tmp_path = Path(TemporaryDirectory().name)
tmp_path.mkdir()
Expand All @@ -148,7 +149,7 @@ def run_dir_with_nasty_symlinks():
rmtree(tmp_path)


@pytest.fixture(scope='session')
@pytest_asyncio.fixture(scope='session')
def nested_dir():
tmp_path = Path(TemporaryDirectory().name)
tmp_path.mkdir()
Expand Down
3 changes: 2 additions & 1 deletion tests/integration/network/test_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from typing import Callable

import pytest
import pytest_asyncio

from cylc.flow import __version__ as CYLC_VERSION
from cylc.flow.network.server import PB_METHOD_MAP
Expand All @@ -31,7 +32,7 @@
from async_timeout import timeout


@pytest.fixture(scope='module')
@pytest_asyncio.fixture(scope='module')
async def myflow(mod_flow, mod_scheduler, mod_run, mod_one_conf):
id_ = mod_flow(mod_one_conf)
schd = mod_scheduler(id_)
Expand Down
3 changes: 2 additions & 1 deletion tests/integration/network/test_zmq.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.

import pytest
import pytest_asyncio
import zmq

from cylc.flow.exceptions import CylcError
Expand All @@ -23,7 +24,7 @@
from .key_setup import setup_keys


@pytest.fixture(scope='module')
@pytest_asyncio.fixture(scope='module')
def myflow(mod_flow, mod_one_conf):
return mod_flow(mod_one_conf)

Expand Down
4 changes: 3 additions & 1 deletion tests/integration/run_modes/test_simulation.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@

import logging
from pathlib import Path

import pytest
from pytest import param
import pytest_asyncio

from cylc.flow import commands
from cylc.flow.cycling.iso8601 import ISO8601Point
Expand Down Expand Up @@ -88,7 +90,7 @@ def _run_simjob(schd, point, task):
return _run_simjob


@pytest.fixture(scope='module')
@pytest_asyncio.fixture(scope='module')
async def sim_time_check_setup(
mod_flow, mod_scheduler, mod_start, mod_one_conf,
):
Expand Down
3 changes: 2 additions & 1 deletion tests/integration/scripts/test_list.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"""Test the "cylc list" command."""

import pytest
import pytest_asyncio

from cylc.flow.exceptions import InputError
from cylc.flow.option_parsers import Options
Expand All @@ -29,7 +30,7 @@
ListOptions = Options(get_option_parser())


@pytest.fixture(scope='module')
@pytest_asyncio.fixture(scope='module')
async def cylc_list(mod_flow, mod_scheduler, mod_start):
id_ = mod_flow(
{
Expand Down
Loading
Loading