Repository: aklajnert/pytest-subprocess (language: python)

Issue:
Running tests with pytest-asyncio 0.23.5.post1 makes test_asyncio.py tests fail due to DeprecationWarning
We intend to update `pytest-asyncio` to the latest release (0.23.5.post1) in Fedora. Testing packages that depend on it, showed `pytest-subprocess` tests failing, because warnings are turned into errors as per:

https://github.com/aklajnert/pytest-subprocess/blob/cc26247fb37e53dbd06a54860d5a5094eed8b679/pytest.ini#L3-L5

resulting in:

```python
==================================== ERRORS ====================================
__________________ ERROR at setup of test_basic_usage[shell] ___________________
fixturedef = <FixtureDef argname='event_loop' scope='function' baseid='tests/test_asyncio.py'>
    @pytest.hookimpl(hookwrapper=True)
    def pytest_fixture_setup(
        fixturedef: FixtureDef,
    ) -> Generator[None, Any, None]:
        """Adjust the event loop policy when an event loop is produced."""
        if fixturedef.argname == "event_loop":
            # The use of a fixture finalizer is preferred over the
            # pytest_fixture_post_finalizer hook. The fixture finalizer is invoked once
            # for each fixture, whereas the hook may be invoked multiple times for
            # any specific fixture.
            # see https://github.com/pytest-dev/pytest/issues/5848
            _add_finalizers(
                fixturedef,
                _close_event_loop,
                _restore_event_loop_policy(asyncio.get_event_loop_policy()),
                _provide_clean_event_loop,
            )
            outcome = yield
            loop: asyncio.AbstractEventLoop = outcome.get_result()
            # Weird behavior was observed when checking for an attribute of FixtureDef.func
            # Instead, we now check for a special attribute of the returned event loop
            fixture_filename = inspect.getsourcefile(fixturedef.func)
            if not getattr(loop, "__original_fixture_loop", False):
                _, fixture_line_number = inspect.getsourcelines(fixturedef.func)
>               warnings.warn(
                    _REDEFINED_EVENT_LOOP_FIXTURE_WARNING
                    % (fixture_filename, fixture_line_number),
                    DeprecationWarning,
                )
E               DeprecationWarning: The event_loop fixture provided by pytest-asyncio has been redefined in
E               /builddir/build/BUILD/pytest-subprocess-1.5.0/tests/test_asyncio.py:14
E               Replacing the event_loop fixture with a custom implementation is deprecated
E               and will lead to errors in the future.
E               If you want to request an asyncio event loop with a scope other than function
E               scope, use the "scope" argument to the asyncio mark when marking the tests.
E               If you want to return different types of event loops, use the event_loop_policy
E               fixture.
/usr/lib/python3.12/site-packages/pytest_asyncio/plugin.py:769: DeprecationWarning
_________________ ERROR at teardown of test_basic_usage[shell] _________________
    def _close_event_loop() -> None:
        policy = asyncio.get_event_loop_policy()
        try:
>           loop = policy.get_event_loop()
/usr/lib/python3.12/site-packages/pytest_asyncio/plugin.py:823: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
self = <asyncio.unix_events._UnixDefaultEventLoopPolicy object at 0x7fd70d9466c0>
    def get_event_loop(self):
        """Get the event loop for the current context.
    
        Returns an instance of EventLoop or raises an exception.
        """
        if (self._local._loop is None and
                not self._local._set_called and
                threading.current_thread() is threading.main_thread()):
            stacklevel = 2
            try:
                f = sys._getframe(1)
            except AttributeError:
                pass
            else:
                # Move up the call stack so that the warning is attached
                # to the line outside asyncio itself.
                while f:
                    module = f.f_globals.get('__name__')
                    if not (module == 'asyncio' or module.startswith('asyncio.')):
                        break
                    f = f.f_back
                    stacklevel += 1
            import warnings
>           warnings.warn('There is no current event loop',
                          DeprecationWarning, stacklevel=stacklevel)
E           DeprecationWarning: There is no current event loop
/usr/lib64/python3.12/asyncio/events.py:697: DeprecationWarning
```
(Above is a sample. The same happens for all tests from `test_asyncio.py`)

We've turned off that setting for now.


Discussion / hints:

Fix patch:
diff --git a/setup.cfg b/setup.cfg
index c9da5a2..ca4dac3 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -3,7 +3,7 @@ ignore = E231,W503
 max-line-length = 89
 
 [mypy]
-python_version = 3.6
+python_version = 3.8
 warn_return_any = True
 warn_unused_configs = True
 disallow_untyped_defs = True


Test patch:
diff --git a/pytest_subprocess/utils.py b/pytest_subprocess/utils.py
index 65e1975..eece249 100644
--- a/pytest_subprocess/utils.py
+++ b/pytest_subprocess/utils.py
@@ -7,8 +7,12 @@
 from typing import Optional
 from typing import Sequence
 from typing import Tuple
+from typing import TYPE_CHECKING
 from typing import Union
 
+if TYPE_CHECKING:
+    from .types import COMMAND
+
 ARGUMENT = Union[str, "Any", os.PathLike]
 
 
@@ -31,7 +35,7 @@ class Command:
 
     def __init__(
         self,
-        command: Union[Sequence[ARGUMENT], str],
+        command: "COMMAND",
     ):
         if isinstance(command, str):
             command = tuple(command.split(" "))
diff --git a/tests/test_asyncio.py b/tests/test_asyncio.py
index ab8f80e..7d4cafd 100644
--- a/tests/test_asyncio.py
+++ b/tests/test_asyncio.py
@@ -11,22 +11,23 @@
 PYTHON = sys.executable
 
 
-@pytest.fixture(autouse=True)
-def event_loop(request):
+@pytest.fixture()
+def event_loop_policy(request):
     if sys.platform.startswith("win"):
         if request.node.name.startswith("test_invalid_event_loop"):
-            loop = asyncio.SelectorEventLoop()
+            return asyncio.WindowsSelectorEventLoopPolicy()
         else:
-            loop = asyncio.ProactorEventLoop()
-    elif sys.version_info.minor < 7:
-        loop = asyncio.get_event_loop()
-    else:
-        try:
-            loop = asyncio.get_running_loop()
-        except RuntimeError:
-            loop = asyncio.new_event_loop()
-    yield loop
-    loop.close()
+            return asyncio.WindowsProactorEventLoopPolicy()
+    return asyncio.DefaultEventLoopPolicy()
+
+
+if sys.platform.startswith("win") and sys.version_info < (3, 8):
+
+    @pytest.fixture(autouse=True)
+    def event_loop(request, event_loop_policy):
+        loop = event_loop_policy.new_event_loop()
+        yield loop
+        loop.close()
 
 
 @pytest.mark.asyncio