diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 8695b5a7..b19aaa26 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -18,7 +18,7 @@ jobs: - uses: actions/checkout@v3 - uses: actions/setup-python@v4 with: - python-version: "3.10" + python-version: "3.11" - run: pip install -r requirements.txt - run: pre-commit run --all-files - run: mypy kopf --strict @@ -38,7 +38,7 @@ jobs: fail-fast: false matrix: install-extras: [ "", "full-auth" ] - python-version: [ "3.7", "3.8", "3.9", "3.10" ] + python-version: [ "3.7", "3.8", "3.9", "3.10", "3.11" ] name: Python ${{ matrix.python-version }} ${{ matrix.install-extras }} runs-on: ubuntu-22.04 timeout-minutes: 5 # usually 2-3 mins @@ -108,7 +108,7 @@ jobs: - uses: actions/checkout@v3 - uses: actions/setup-python@v4 with: - python-version: "3.10" + python-version: "3.11" - uses: nolar/setup-k3d-k3s@v1 with: version: ${{ matrix.k3s }} diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index 1a3b25ef..994444cb 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -16,7 +16,7 @@ jobs: - uses: actions/checkout@v3 - uses: actions/setup-python@v4 with: - python-version: "3.10" + python-version: "3.11" - run: pip install --upgrade setuptools wheel twine - run: python setup.py sdist bdist_wheel - uses: pypa/gh-action-pypi-publish@release/v1 diff --git a/.github/workflows/thorough.yaml b/.github/workflows/thorough.yaml index 88f589b9..63c2933b 100644 --- a/.github/workflows/thorough.yaml +++ b/.github/workflows/thorough.yaml @@ -22,7 +22,7 @@ jobs: - uses: actions/checkout@v3 - uses: actions/setup-python@v4 with: - python-version: "3.10" + python-version: "3.11" - run: pip install -r requirements.txt - run: pre-commit run --all-files - run: mypy kopf --strict @@ -42,7 +42,7 @@ jobs: fail-fast: false matrix: install-extras: [ "", "full-auth" ] - python-version: [ "3.7", "3.8", "3.9", "3.10" ] + python-version: [ "3.7", "3.8", "3.9", "3.10", "3.11" ] name: Python ${{ matrix.python-version }} ${{ matrix.install-extras }} runs-on: ubuntu-22.04 timeout-minutes: 5 # usually 2-3 mins @@ -112,7 +112,7 @@ jobs: - uses: actions/checkout@v3 - uses: actions/setup-python@v4 with: - python-version: "3.10" + python-version: "3.11" - uses: nolar/setup-k3d-k3s@v1 with: version: ${{ matrix.k3s }} @@ -134,7 +134,7 @@ jobs: - uses: actions/checkout@v3 - uses: actions/setup-python@v4 with: - python-version: "3.10" + python-version: "3.11" - run: tools/install-minikube.sh - run: pip install -r requirements.txt -r examples/requirements.txt - run: pytest --color=yes --timeout=30 --only-e2e diff --git a/README.md b/README.md index 1d6a270a..836102b9 100644 --- a/README.md +++ b/README.md @@ -133,7 +133,7 @@ We assume that when the operator is executed in the cluster, it must be packaged into a docker image with a CI/CD tool of your preference. ```dockerfile -FROM python:3.7 +FROM python:3.11 ADD . /src RUN pip install kopf CMD kopf run /src/handlers.py --verbose diff --git a/docs/deployment.rst b/docs/deployment.rst index 6709ebc8..4569125b 100644 --- a/docs/deployment.rst +++ b/docs/deployment.rst @@ -10,13 +10,13 @@ But normally, the operators are usually deployed directly to the clusters. Docker image ============ -First of all, the operator must be packaged as a docker image with Python 3.7: +First of all, the operator must be packaged as a docker image with Python 3.7 or newer: .. code-block:: dockerfile :caption: Dockerfile :name: dockerfile - FROM python:3.7 + FROM python:3.11 ADD . /src RUN pip install kopf CMD kopf run /src/handlers.py --verbose diff --git a/kopf/_cogs/structs/diffs.py b/kopf/_cogs/structs/diffs.py index 7f6d6843..e3f76901 100644 --- a/kopf/_cogs/structs/diffs.py +++ b/kopf/_cogs/structs/diffs.py @@ -72,6 +72,10 @@ def __init__(self, __items: Iterable[DiffItem]): super().__init__() self._items = tuple(DiffItem(*item) for item in __items) + def __hash__(self) -> int: + # Hashes mark diffs as immutable to be usable as dataclasses' defaults in Python 3.11. + return hash(self._items) + def __repr__(self) -> str: return repr(self._items) diff --git a/pytest.ini b/pytest.ini index afd6b82b..da506c41 100644 --- a/pytest.ini +++ b/pytest.ini @@ -1,4 +1,6 @@ [pytest] +; The standalone `mock` instead of stdlib `unittest.mock` is only for AsyncMock in Python 3.7. +mock_use_standalone_module = true asyncio_mode = auto addopts = --strict-markers diff --git a/requirements.txt b/requirements.txt index 9ffe1391..ba49fef3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,7 +3,6 @@ -e . aresponses astpath[xpath] -asynctest certbuilder certvalidator codecov @@ -13,6 +12,9 @@ freezegun import-linter isort lxml +# Generally, `unittest.mock` is enough, but it lacks `AsyncMock` for Py 3.7. +# TODO: Once 3.7 is removed (Jun 2023), roll back to unittest.mock. +mock # Mypy requires typed-ast, which is broken on PyPy 3.7 (could work in PyPy 3.8). mypy==0.982; implementation_name == "cpython" pre-commit diff --git a/setup.py b/setup.py index 2bf8ab4c..8117f9cf 100644 --- a/setup.py +++ b/setup.py @@ -37,6 +37,7 @@ 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', 'Programming Language :: Python :: 3.10', + 'Programming Language :: Python :: 3.11', 'Programming Language :: Python :: 3 :: Only', 'Programming Language :: Python :: Implementation :: CPython', 'Programming Language :: Python :: Implementation :: PyPy', diff --git a/tests/admission/test_admission_server.py b/tests/admission/test_admission_server.py index 89b2b841..ff30c741 100644 --- a/tests/admission/test_admission_server.py +++ b/tests/admission/test_admission_server.py @@ -1,7 +1,7 @@ import contextlib -from unittest.mock import Mock import pytest +from mock import Mock import kopf from kopf._cogs.aiokits.aiovalues import Container diff --git a/tests/admission/test_serving_handler_selection.py b/tests/admission/test_serving_handler_selection.py index b704a8ac..cdf287b1 100644 --- a/tests/admission/test_serving_handler_selection.py +++ b/tests/admission/test_serving_handler_selection.py @@ -1,6 +1,5 @@ -from unittest.mock import Mock - import pytest +from mock import Mock import kopf from kopf._cogs.structs.ids import HandlerId diff --git a/tests/admission/test_serving_kwargs_passthrough.py b/tests/admission/test_serving_kwargs_passthrough.py index b93199ad..25fdc39d 100644 --- a/tests/admission/test_serving_kwargs_passthrough.py +++ b/tests/admission/test_serving_kwargs_passthrough.py @@ -1,6 +1,5 @@ -from unittest.mock import Mock - import pytest +from mock import Mock import kopf from kopf._core.engines.admission import serve_admission_request diff --git a/tests/apis/test_iterjsonlines.py b/tests/apis/test_iterjsonlines.py index 6b1be5a8..91dc10ac 100644 --- a/tests/apis/test_iterjsonlines.py +++ b/tests/apis/test_iterjsonlines.py @@ -1,4 +1,4 @@ -import asynctest +from mock import Mock from kopf._cogs.clients.api import iter_jsonlines @@ -8,7 +8,7 @@ async def iter_chunked(n: int): if False: # to make this function a generator yield b'' - content = asynctest.Mock(iter_chunked=iter_chunked) + content = Mock(iter_chunked=iter_chunked) lines = [] async for line in iter_jsonlines(content): lines.append(line) @@ -20,7 +20,7 @@ async def test_empty_chunk(): async def iter_chunked(n: int): yield b'' - content = asynctest.Mock(iter_chunked=iter_chunked) + content = Mock(iter_chunked=iter_chunked) lines = [] async for line in iter_jsonlines(content): lines.append(line) @@ -32,7 +32,7 @@ async def test_one_chunk_one_line(): async def iter_chunked(n: int): yield b'hello' - content = asynctest.Mock(iter_chunked=iter_chunked) + content = Mock(iter_chunked=iter_chunked) lines = [] async for line in iter_jsonlines(content): lines.append(line) @@ -44,7 +44,7 @@ async def test_one_chunk_two_lines(): async def iter_chunked(n: int): yield b'hello\nworld' - content = asynctest.Mock(iter_chunked=iter_chunked) + content = Mock(iter_chunked=iter_chunked) lines = [] async for line in iter_jsonlines(content): lines.append(line) @@ -56,7 +56,7 @@ async def test_one_chunk_empty_lines(): async def iter_chunked(n: int): yield b'\n\nhello\n\nworld\n\n' - content = asynctest.Mock(iter_chunked=iter_chunked) + content = Mock(iter_chunked=iter_chunked) lines = [] async for line in iter_jsonlines(content): lines.append(line) @@ -70,7 +70,7 @@ async def iter_chunked(n: int): yield b'o\n\nwor' yield b'ld\n\n' - content = asynctest.Mock(iter_chunked=iter_chunked) + content = Mock(iter_chunked=iter_chunked) lines = [] async for line in iter_jsonlines(content): lines.append(line) diff --git a/tests/basic-structs/test_memories.py b/tests/basic-structs/test_memories.py index 9f0c3f45..65406804 100644 --- a/tests/basic-structs/test_memories.py +++ b/tests/basic-structs/test_memories.py @@ -1,4 +1,4 @@ -from unittest.mock import Mock +from mock import Mock from kopf._cogs.structs.bodies import Body from kopf._cogs.structs.ephemera import Memo diff --git a/tests/causation/test_kwargs.py b/tests/causation/test_kwargs.py index 43fe6e6e..6ee55c85 100644 --- a/tests/causation/test_kwargs.py +++ b/tests/causation/test_kwargs.py @@ -1,9 +1,9 @@ import dataclasses import logging from typing import Type -from unittest.mock import Mock import pytest +from mock import Mock from kopf._cogs.configs.configuration import OperatorSettings from kopf._cogs.structs import diffs diff --git a/tests/conftest.py b/tests/conftest.py index 0534586b..790d7daf 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -8,12 +8,10 @@ import sys import time from typing import Set -from unittest.mock import Mock import aiohttp.web -import asynctest import pytest -import pytest_mock +from mock import AsyncMock, Mock import kopf from kopf._cogs.clients.auth import APIContext @@ -33,7 +31,6 @@ def pytest_configure(config): config.addinivalue_line('filterwarnings', 'error') # Warnings from the testing tools out of our control should not fail the tests. - config.addinivalue_line('filterwarnings', 'ignore:"@coroutine":DeprecationWarning:asynctest.mock') config.addinivalue_line('filterwarnings', 'ignore:The loop argument:DeprecationWarning:aiohttp') config.addinivalue_line('filterwarnings', 'ignore:The loop argument:DeprecationWarning:asyncio') config.addinivalue_line('filterwarnings', 'ignore:is deprecated, use current_thread:DeprecationWarning:threading') @@ -75,15 +72,6 @@ def _is_e2e(item): items[:] = etc + e2e -# Substitute the regular mock with the async-aware mock in the `mocker` fixture. -@pytest.fixture(scope='session', autouse=True) -def enforce_asyncio_mocker(pytestconfig): - pytest_mock.plugin.get_mock_module = lambda config: asynctest - pytest_mock.get_mock_module = pytest_mock.plugin.get_mock_module - fixture = pytest_mock.MockerFixture(pytestconfig) - assert fixture.mock_module is asynctest, "Mock replacement failed!" - - @pytest.fixture(params=[ ('kopf.dev', 'v1', 'kopfpeerings', True), ('zalando.org', 'v1', 'kopfpeerings', True), @@ -283,7 +271,7 @@ def test_me(resp_mocker): assert callback.call_count == 1 """ def resp_maker(*args, **kwargs): - actual_response = asynctest.MagicMock(*args, **kwargs) + actual_response = AsyncMock(*args, **kwargs) async def resp_mock_effect(request): nonlocal actual_response @@ -300,7 +288,7 @@ async def resp_mock_effect(request): response = await response return response - return asynctest.CoroutineMock(side_effect=resp_mock_effect) + return AsyncMock(side_effect=resp_mock_effect) return resp_maker diff --git a/tests/diffs/test_protocols.py b/tests/diffs/test_protocols.py index 862bcbd1..3eeb1064 100644 --- a/tests/diffs/test_protocols.py +++ b/tests/diffs/test_protocols.py @@ -53,3 +53,5 @@ def test_diff_comparison_to_the_same(): DiffItem(DiffOperation.REMOVE, ('key3',), 'old3', None), ]) assert d1 == d2 + assert hash(d1) == hash(d2) + assert d1 is not d2 diff --git a/tests/handling/conftest.py b/tests/handling/conftest.py index a9cec2b5..72d0fdc4 100644 --- a/tests/handling/conftest.py +++ b/tests/handling/conftest.py @@ -35,9 +35,9 @@ """ import dataclasses from typing import Callable -from unittest.mock import Mock import pytest +from mock import Mock import kopf from kopf._core.intents.causes import ChangingCause diff --git a/tests/handling/daemons/conftest.py b/tests/handling/daemons/conftest.py index 97dace52..623d0d43 100644 --- a/tests/handling/daemons/conftest.py +++ b/tests/handling/daemons/conftest.py @@ -1,10 +1,10 @@ import asyncio import contextlib import time -import unittest.mock import freezegun import pytest +from mock import MagicMock, patch import kopf from kopf._cogs.aiokits.aiotoggles import ToggleSet @@ -19,7 +19,7 @@ class DaemonDummy: def __init__(self): super().__init__() - self.mock = unittest.mock.MagicMock() + self.mock = MagicMock() self.kwargs = {} self.steps = { 'called': asyncio.Event(), @@ -107,8 +107,7 @@ def frozen_time(): with freezegun.freeze_time("2020-01-01 00:00:00") as frozen: # Use freezegun-supported time instead of system clocks -- for testing purposes only. # NB: Patch strictly after the time is frozen -- to use fake_time(), not real time(). - with unittest.mock.patch('time.monotonic', time.time), \ - unittest.mock.patch('time.perf_counter', time.time): + with patch('time.monotonic', time.time), patch('time.perf_counter', time.time): yield frozen diff --git a/tests/handling/subhandling/test_subhandling.py b/tests/handling/subhandling/test_subhandling.py index b83604fb..9b2832d2 100644 --- a/tests/handling/subhandling/test_subhandling.py +++ b/tests/handling/subhandling/test_subhandling.py @@ -1,8 +1,8 @@ import asyncio import logging -from unittest.mock import Mock import pytest +from mock import Mock import kopf from kopf._cogs.structs.ephemera import Memo diff --git a/tests/handling/test_parametrization.py b/tests/handling/test_parametrization.py index 4f73249a..df4209c2 100644 --- a/tests/handling/test_parametrization.py +++ b/tests/handling/test_parametrization.py @@ -1,5 +1,6 @@ import asyncio -from unittest.mock import Mock + +from mock import Mock import kopf from kopf._cogs.structs.ephemera import Memo diff --git a/tests/hierarchies/conftest.py b/tests/hierarchies/conftest.py index 20f2d3bc..8816c46d 100644 --- a/tests/hierarchies/conftest.py +++ b/tests/hierarchies/conftest.py @@ -1,6 +1,5 @@ -from unittest.mock import Mock - import pytest +from mock import Mock class CustomIterable: diff --git a/tests/hierarchies/test_owner_referencing.py b/tests/hierarchies/test_owner_referencing.py index 1e124960..e6b42b79 100644 --- a/tests/hierarchies/test_owner_referencing.py +++ b/tests/hierarchies/test_owner_referencing.py @@ -1,7 +1,7 @@ import copy -from unittest.mock import call import pytest +from mock import call import kopf from kopf._cogs.structs.bodies import Body, RawBody, RawMeta diff --git a/tests/invocations/test_callbacks.py b/tests/invocations/test_callbacks.py index da66fab8..175c5d6b 100644 --- a/tests/invocations/test_callbacks.py +++ b/tests/invocations/test_callbacks.py @@ -3,7 +3,7 @@ import traceback import pytest -from asynctest import MagicMock +from mock import Mock from kopf._cogs.structs.bodies import Body from kopf._cogs.structs.patches import Patch @@ -32,6 +32,14 @@ async def async_fn(*args, **kwargs): return _find_marker() +def sync_mock_fn(mock, *args, **kwargs): + return mock(*args, **kwargs) + + +async def async_mock_fn(mock, *args, **kwargs): + return mock(*args, **kwargs) + + def partials(fn, n): partial = fn for _ in range(n): @@ -79,8 +87,8 @@ async def wrapper(*args, wrapper=wrapper, **kwargs): fns = pytest.mark.parametrize( 'fn', [ - (sync_fn), - (async_fn), + (sync_mock_fn), + (async_mock_fn), ]) # Every combination of partials, sync & async wrappers possible. @@ -140,23 +148,23 @@ async def test_stacktrace_visibility(fn, expected): @fns async def test_result_returned(fn): - fn = MagicMock(fn, return_value=999) - result = await invoke(fn) + mock = Mock(return_value=999) + result = await invoke(fn, kwargs=dict(mock=mock)) assert result == 999 @fns async def test_explicit_args_passed_properly(fn): - fn = MagicMock(fn) - await invoke(fn, kwargs=dict(kw1=300, kw2=400)) + mock = Mock() + await invoke(fn, kwargs=dict(mock=mock, kw1=300, kw2=400)) - assert fn.called - assert fn.call_count == 1 + assert mock.called + assert mock.call_count == 1 - assert len(fn.call_args[0]) == 0 - assert len(fn.call_args[1]) >= 2 # also the magic kwargs - assert fn.call_args[1]['kw1'] == 300 - assert fn.call_args[1]['kw2'] == 400 + assert len(mock.call_args[0]) == 0 + assert len(mock.call_args[1]) >= 2 # also the magic kwargs + assert mock.call_args[1]['kw1'] == 300 + assert mock.call_args[1]['kw2'] == 400 @fns @@ -180,12 +188,12 @@ async def test_special_kwargs_added(fn, resource): new=object(), ) - fn = MagicMock(fn) - await invoke(fn, kwargsrc=cause) + mock = Mock() + await invoke(fn, kwargs=dict(mock=mock), kwargsrc=cause) - assert fn.called - assert fn.call_count == 1 + assert mock.called + assert mock.call_count == 1 # Only check that kwargs are passed at all. The exact kwargs per cause are tested separately. - assert 'logger' in fn.call_args[1] - assert 'resource' in fn.call_args[1] + assert 'logger' in mock.call_args[1] + assert 'resource' in mock.call_args[1] diff --git a/tests/persistence/test_states.py b/tests/persistence/test_states.py index c39daa1e..c0781bc7 100644 --- a/tests/persistence/test_states.py +++ b/tests/persistence/test_states.py @@ -1,8 +1,8 @@ import datetime -from unittest.mock import Mock import freezegun import pytest +from mock import Mock from kopf._cogs.configs.progress import SmartProgressStorage, StatusProgressStorage from kopf._cogs.structs.bodies import Body diff --git a/tests/reactor/conftest.py b/tests/reactor/conftest.py index 4db2d8cc..55aee5f9 100644 --- a/tests/reactor/conftest.py +++ b/tests/reactor/conftest.py @@ -2,7 +2,7 @@ import functools import pytest -from asynctest import CoroutineMock +from mock import AsyncMock from kopf._cogs.clients.watching import infinite_watch from kopf._core.reactor.queueing import watcher, worker as original_worker @@ -16,13 +16,13 @@ def _autouse_resp_mocker(resp_mocker): @pytest.fixture() def processor(): """ A mock for processor -- to be checked if the handler has been called. """ - return CoroutineMock() + return AsyncMock() @pytest.fixture() def worker_spy(mocker): """ Spy on the watcher: actually call it, but provide the mock-fields. """ - spy = CoroutineMock(spec=original_worker, wraps=original_worker) + spy = AsyncMock(spec=original_worker, wraps=original_worker) return mocker.patch('kopf._core.reactor.queueing.worker', spy) diff --git a/tests/reactor/test_queueing.py b/tests/reactor/test_queueing.py index 2bce4c0b..34bccfc9 100644 --- a/tests/reactor/test_queueing.py +++ b/tests/reactor/test_queueing.py @@ -74,9 +74,9 @@ async def test_watchevent_demultiplexing(worker_mock, timer, resource, processor # The processor must not be called by the watcher, only by the worker. # But the worker (even if mocked) must be called & awaited by the watcher. - assert not processor.awaited - assert not processor.called - assert worker_mock.awaited + assert processor.call_count == 0 + assert processor.await_count == 0 + assert worker_mock.await_count > 0 # Are the worker-streams created by the watcher? Populated as expected? # One stream per unique uid? All events are sequential? EOS marker appended? @@ -150,7 +150,7 @@ async def test_watchevent_batching(settings, resource, processor, timer, assert timer.seconds < settings.batching.batch_window * 2 # Was the processor called at all? Awaited as needed for async fns? - assert processor.awaited + assert processor.await_count > 0 # Was it called only once per uid? Only with the latest event? # Note: the calls can be in arbitrary order, not as we expect then. diff --git a/tests/registries/test_matching_of_callbacks.py b/tests/registries/test_matching_of_callbacks.py index e76cebd5..4aaff10c 100644 --- a/tests/registries/test_matching_of_callbacks.py +++ b/tests/registries/test_matching_of_callbacks.py @@ -1,7 +1,7 @@ import dataclasses -from unittest.mock import Mock import pytest +from mock import Mock from kopf._cogs.structs.bodies import Body from kopf._cogs.structs.dicts import parse_field diff --git a/tests/registries/test_matching_of_resources.py b/tests/registries/test_matching_of_resources.py index afa5d8ec..db09c9a1 100644 --- a/tests/registries/test_matching_of_resources.py +++ b/tests/registries/test_matching_of_resources.py @@ -1,4 +1,4 @@ -from unittest.mock import Mock +from mock import Mock from kopf._cogs.structs.references import Resource, Selector from kopf._core.intents.registries import _matches_resource diff --git a/tests/settings/test_executor.py b/tests/settings/test_executor.py index f1dd522b..5494f617 100644 --- a/tests/settings/test_executor.py +++ b/tests/settings/test_executor.py @@ -1,6 +1,7 @@ import concurrent.futures import threading -from unittest.mock import MagicMock + +from mock import MagicMock import kopf from kopf._core.actions.invocation import invoke diff --git a/tests/test_async.py b/tests/test_async.py index 03957f4e..14792cd7 100644 --- a/tests/test_async.py +++ b/tests/test_async.py @@ -21,8 +21,8 @@ async def test_async_mocks_are_enabled(timer, mocker): with timer as t: await asyncio.sleep(1.0) - assert p.called - assert p.awaited + assert p.call_count > 0 + assert p.await_count > 0 assert t.seconds < 0.01 # mocked sleep diff --git a/tests/timing/test_throttling.py b/tests/timing/test_throttling.py index 7d9e8e17..89abba6d 100644 --- a/tests/timing/test_throttling.py +++ b/tests/timing/test_throttling.py @@ -1,8 +1,8 @@ import asyncio import logging -from unittest.mock import call import pytest +from mock import call from kopf._core.actions.throttlers import Throttler, throttled diff --git a/tests/utilities/aiotasks/test_coro_cancellation.py b/tests/utilities/aiotasks/test_coro_cancellation.py index 51662d30..6d40d523 100644 --- a/tests/utilities/aiotasks/test_coro_cancellation.py +++ b/tests/utilities/aiotasks/test_coro_cancellation.py @@ -1,10 +1,9 @@ import asyncio import gc import warnings -from unittest.mock import Mock import pytest -from asynctest import CoroutineMock +from mock import AsyncMock, Mock from kopf._cogs.aiokits.aiotasks import cancel_coro @@ -14,7 +13,7 @@ async def f(mock): def factory(loop, coro_or_mock): - coro = coro_or_mock._mock_wraps if isinstance(coro_or_mock, CoroutineMock) else coro_or_mock + coro = coro_or_mock._mock_wraps if isinstance(coro_or_mock, AsyncMock) else coro_or_mock return asyncio.Task(coro, loop=loop) @@ -65,7 +64,7 @@ async def test_coro_is_awaited_via_a_task_with_no_warning(coromock_task_factory) with warnings.catch_warnings(record=True) as w: warnings.simplefilter('default') mock = Mock() - coro = CoroutineMock(wraps=f(mock)) + coro = AsyncMock(wraps=f(mock)) del coro.close await cancel_coro(coro) diff --git a/tests/utilities/aiotasks/test_scheduler.py b/tests/utilities/aiotasks/test_scheduler.py index 2670748c..4a5a933c 100644 --- a/tests/utilities/aiotasks/test_scheduler.py +++ b/tests/utilities/aiotasks/test_scheduler.py @@ -1,7 +1,7 @@ import asyncio -from unittest.mock import Mock import pytest +from mock import Mock from kopf._cogs.aiokits.aiotasks import Scheduler