Skip to content

[BUG] Test failures with fixture 'event_loop' not found w/ pytest-asyncio >= 1.0.0 #949

@sarahec

Description

@sarahec

What is the bug?

While building version 3.0.0 for nixpkgs, four tests fail:

=========================== short test summary info ============================
ERROR test_opensearchpy/test_async/test_transport.py::TestTransport::test_sniff_after_n_seconds
ERROR test_opensearchpy/test_async/test_transport.py::TestTransport::test_sniff_on_start_error_if_no_sniffed_hosts
ERROR test_opensearchpy/test_async/test_transport.py::TestTransport::test_sniff_on_start_waits_for_sniff_to_complete
ERROR test_opensearchpy/test_async/test_transport.py::TestTransport::test_sniff_on_start_close_unlocks_async_calls

Each of these fails with fixture 'event_loop' not found.

UPDATE: It's the latest pytest-async, see #949 (comment)

How can one reproduce the bug?

nix-build -A python3Packages.opensearch-py

What is the expected behavior?

It should build and test.

What is your host/environment?

Building for nix

Do you have any screenshots?

Log Running phase: pytestCheckPhase Executing pytestCheckPhase pytest flags: -m pytest --ignore-glob=test_opensearchpy/test_async/test_connection.py --ignore-glob=test_opensearchpy/test_async/test_server --ignore-glob=test_opensearchpy/test_server --ignore-glob=test_opensearchpy/test_server_secured -k not\ \(test_ca_certs_ssl_cert_dir\)\ and\ not\ \(test_no_ca_certs\)\ and\ not\ \(test_basicauth_in_request_session\)\ and\ not\ \(test_callable_in_request_session\) ============================= test session starts ============================== platform linux -- Python 3.13.6, pytest-8.4.1, pluggy-1.6.0 rootdir: /build/source configfile: setup.cfg plugins: asyncio-1.1.0, mock-3.14.1 asyncio: mode=Mode.AUTO, asyncio_default_fixture_loop_scope=None, asyncio_default_test_loop_scope=function collected 868 items / 4 deselected / 864 selected

test_opensearchpy/test_async/test_aiohttp.py ...ssss [ 0%]
test_opensearchpy/test_async/test_client.py ... [ 1%]
test_opensearchpy/test_async/test_helpers/test_document.py ............. [ 2%]
................................. [ 6%]
test_opensearchpy/test_async/test_helpers/test_faceted_search.py ....... [ 7%]
..................... [ 9%]
test_opensearchpy/test_async/test_helpers/test_index.py ............. [ 11%]
test_opensearchpy/test_async/test_helpers/test_mapping.py ........ [ 12%]
test_opensearchpy/test_async/test_helpers/test_search.py ............... [ 13%]
................... [ 16%]
test_opensearchpy/test_async/test_helpers/test_update_by_query.py ...... [ 16%]
.. [ 17%]
test_opensearchpy/test_async/test_http.py ...... [ 17%]
test_opensearchpy/test_async/test_http_connection.py ... [ 18%]
test_opensearchpy/test_async/test_plugins_client.py . [ 18%]
test_opensearchpy/test_async/test_server_secured/test_security_plugin.py s [ 18%]
ssssssssssss [ 19%]
test_opensearchpy/test_async/test_signer.py ............ [ 21%]
test_opensearchpy/test_async/test_transport.py ......................... [ 23%]
E..EEE.. [ 24%]
test_opensearchpy/test_cases.py ... [ 25%]
test_opensearchpy/test_client/test_cluster.py ... [ 25%]
test_opensearchpy/test_client/test_http.py ...... [ 26%]
test_opensearchpy/test_client/test_indices.py ..... [ 26%]
test_opensearchpy/test_client/test_overrides.py ............... [ 28%]
test_opensearchpy/test_client/test_plugins/test_alerting.py ............ [ 29%]
[ 29%]
test_opensearchpy/test_client/test_plugins/test_index_management.py .... [ 30%]
..... [ 31%]
test_opensearchpy/test_client/test_plugins/test_plugins_client.py . [ 31%]
test_opensearchpy/test_client/test_point_in_time.py .... [ 31%]
test_opensearchpy/test_client/test_remote_store.py . [ 31%]
test_opensearchpy/test_client/test_requests.py .. [ 31%]
test_opensearchpy/test_client/test_search_pipeline.py .. [ 32%]
test_opensearchpy/test_client/test_urllib3.py ... [ 32%]
test_opensearchpy/test_client/test_utils.py ................. [ 34%]
test_opensearchpy/test_connection/test_base_connection.py ............. [ 35%]
test_opensearchpy/test_connection/test_requests_http_connection.py ..... [ 36%]
........................................................................ [ 44%]
.... [ 45%]
test_opensearchpy/test_connection/test_urllib3_http_connection.py ...... [ 46%]
..................................................... [ 52%]
test_opensearchpy/test_connection_pool.py .............. [ 53%]
test_opensearchpy/test_exceptions.py .. [ 54%]
test_opensearchpy/test_helpers/test_actions.py .s........... [ 55%]
test_opensearchpy/test_helpers/test_aggs.py ............................ [ 58%]
.... [ 59%]
test_opensearchpy/test_helpers/test_analysis.py ........... [ 60%]
test_opensearchpy/test_helpers/test_document.py ........................ [ 63%]
....................... [ 65%]
test_opensearchpy/test_helpers/test_faceted_search.py .................. [ 68%]
.......... [ 69%]
test_opensearchpy/test_helpers/test_field.py ................... [ 71%]
test_opensearchpy/test_helpers/test_index.py .............. [ 73%]
test_opensearchpy/test_helpers/test_mapping.py ........ [ 73%]
test_opensearchpy/test_helpers/test_query.py ........................... [ 77%]
..................................... [ 81%]
test_opensearchpy/test_helpers/test_result.py ................. [ 83%]
test_opensearchpy/test_helpers/test_search.py .......................... [ 86%]
............ [ 87%]
test_opensearchpy/test_helpers/test_update_by_query.py ......... [ 88%]
test_opensearchpy/test_helpers/test_utils.py ........... [ 90%]
test_opensearchpy/test_helpers/test_validation.py .......... [ 91%]
test_opensearchpy/test_helpers/test_wrappers.py ........................ [ 93%]
. [ 94%]
test_opensearchpy/test_serializer.py .s..sssssssssss........ [ 96%]
test_opensearchpy/test_transport.py ............................ [100%]

==================================== ERRORS ====================================
__________ ERROR at setup of TestTransport.test_sniff_after_n_seconds __________
file /build/source/test_opensearchpy/test_async/test_transport.py, line 442
async def test_sniff_after_n_seconds(self, event_loop: Any) -> None:
t: Any = AsyncTransport(
[{"data": CLUSTER_NODES}],
connection_class=DummyConnection,
sniffer_timeout=5,
)
await t._async_call()

      for _ in range(4):
          await t.perform_request("GET", "/")
      assert 1 == len(t.connection_pool.connections)
      assert isinstance(t.get_connection(), DummyConnection)
      t.last_sniff = event_loop.time() - 5.1

      await t.perform_request("GET", "/")
      await t.sniffing_task  # Need to wait for the sniffing task to complete

      assert 1 == len(t.connection_pool.connections)
      assert "http://1.1.1.1:123" == t.get_connection().host
      assert event_loop.time() - 1 < t.last_sniff < event_loop.time() + 0.01

E fixture 'event_loop' not found

  available fixtures: _class_scoped_runner, _function_scoped_runner, _module_scoped_runner, _package_scoped_runner, _session_scoped_runner, cache, capfd, capfdbinary, caplog, capsys, capsysbinary, capteesys, class_mocker, doctest_namespace, event_loop_policy, mocker, module_mocker, monkeypatch, package_mocker, pytestconfig, record_property, record_testsuite_property, record_xml_attribute, recwarn, session_mocker, tmp_path, tmp_path_factory, tmpdir, tmpdir_factory, unused_tcp_port, unused_tcp_port_factory, unused_udp_port, unused_udp_port_factory
  use 'pytest --fixtures [testpath]' for help on them.

/build/source/test_opensearchpy/test_async/test_transport.py:442
_ ERROR at setup of TestTransport.test_sniff_on_start_error_if_no_sniffed_hosts _
file /build/source/test_opensearchpy/test_async/test_transport.py, line 496
async def test_sniff_on_start_error_if_no_sniffed_hosts(
self, event_loop: Any
) -> None:
t: Any = AsyncTransport(
[
{"data": ""},
{"data": ""},
{"data": ""},
],
connection_class=DummyConnection,
sniff_on_start=True,
)

      # If our initial sniffing attempt comes back
      # empty then we raise an error.
      with pytest.raises(TransportError) as e:
          await t._async_call()
      assert str(e.value) == "TransportError(N/A, 'Unable to sniff hosts.')"

E fixture 'event_loop' not found

  available fixtures: _class_scoped_runner, _function_scoped_runner, _module_scoped_runner, _package_scoped_runner, _session_scoped_runner, cache, capfd, capfdbinary, caplog, capsys, capsysbinary, capteesys, class_mocker, doctest_namespace, event_loop_policy, mocker, module_mocker, monkeypatch, package_mocker, pytestconfig, record_property, record_testsuite_property, record_xml_attribute, recwarn, session_mocker, tmp_path, tmp_path_factory, tmpdir, tmpdir_factory, unused_tcp_port, unused_tcp_port_factory, unused_udp_port, unused_udp_port_factory
  use 'pytest --fixtures [testpath]' for help on them.

/build/source/test_opensearchpy/test_async/test_transport.py:496
_ ERROR at setup of TestTransport.test_sniff_on_start_waits_for_sniff_to_complete _
file /build/source/test_opensearchpy/test_async/test_transport.py, line 515
async def test_sniff_on_start_waits_for_sniff_to_complete(
self, event_loop: Any
) -> None:
t: Any = AsyncTransport(
[
{"delay": 1, "data": ""},
{"delay": 1, "data": ""},
{"delay": 1, "data": CLUSTER_NODES},
],
connection_class=DummyConnection,
sniff_on_start=True,
)

      # Start the timer right before the first task
      # and have a bunch of tasks come in immediately.
      tasks = []
      start_time = event_loop.time()
      for _ in range(5):
          tasks.append(event_loop.create_task(t._async_call()))
          await asyncio.sleep(0)  # Yield to the loop

      assert t.sniffing_task is not None

      # Tasks streaming in later.
      for _ in range(5):
          tasks.append(event_loop.create_task(t._async_call()))
          await asyncio.sleep(0.1)

      # Now that all the API calls have come in we wait for
      # them all to resolve before
      await asyncio.gather(*tasks)
      end_time = event_loop.time()
      duration = end_time - start_time

      # All the tasks blocked on the sniff of each node
      # and then resolved immediately after.
      assert 1 <= duration < 2

E fixture 'event_loop' not found

  available fixtures: _class_scoped_runner, _function_scoped_runner, _module_scoped_runner, _package_scoped_runner, _session_scoped_runner, cache, capfd, capfdbinary, caplog, capsys, capsysbinary, capteesys, class_mocker, doctest_namespace, event_loop_policy, mocker, module_mocker, monkeypatch, package_mocker, pytestconfig, record_property, record_testsuite_property, record_xml_attribute, recwarn, session_mocker, tmp_path, tmp_path_factory, tmpdir, tmpdir_factory, unused_tcp_port, unused_tcp_port_factory, unused_udp_port, unused_udp_port_factory
  use 'pytest --fixtures [testpath]' for help on them.

/build/source/test_opensearchpy/test_async/test_transport.py:515
_ ERROR at setup of TestTransport.test_sniff_on_start_close_unlocks_async_calls _
file /build/source/test_opensearchpy/test_async/test_transport.py, line 553
async def test_sniff_on_start_close_unlocks_async_calls(
self, event_loop: Any
) -> None:
t: Any = AsyncTransport(
[
{"delay": 10, "data": CLUSTER_NODES},
],
connection_class=DummyConnection,
sniff_on_start=True,
)

      # Start making _async_calls() before we cancel
      tasks = []
      start_time = event_loop.time()
      for _ in range(3):
          tasks.append(event_loop.create_task(t._async_call()))
          await asyncio.sleep(0)

      # Close the transport while the sniffing task is active! :(
      await t.close()

      # Now we start waiting on all those _async_calls()
      await asyncio.gather(*tasks)
      end_time = event_loop.time()
      duration = end_time - start_time

      # A lot quicker than 10 seconds defined in 'delay'
      assert duration < 1

E fixture 'event_loop' not found

  available fixtures: _class_scoped_runner, _function_scoped_runner, _module_scoped_runner, _package_scoped_runner, _session_scoped_runner, cache, capfd, capfdbinary, caplog, capsys, capsysbinary, capteesys, class_mocker, doctest_namespace, event_loop_policy, mocker, module_mocker, monkeypatch, package_mocker, pytestconfig, record_property, record_testsuite_property, record_xml_attribute, recwarn, session_mocker, tmp_path, tmp_path_factory, tmpdir, tmpdir_factory, unused_tcp_port, unused_tcp_port_factory, unused_udp_port, unused_udp_port_factory
  use 'pytest --fixtures [testpath]' for help on them.

/build/source/test_opensearchpy/test_async/test_transport.py:553

Do you have any additional context?

Test environment:

  optional-dependencies.async = [ aiohttp ];

  nativeCheckInputs = [
    botocore
    mock
    pytest-asyncio
    pytest-mock
    pytestCheckHook
    pyyaml
    pytz
  ]

Are we perhaps missing a dependency? I've checked against setup.py and this seems right.

Update

There's an unclosed connection at the end of the test session, even after omitting these four tests (so it's not a matter of a connection being abandoned by the assert):

Log Unclosed client session client_session: source_traceback: Object created at (most recent call last): File "", line 198, in _run_module_as_main File "", line 88, in _run_code File "/nix/store/l9wxarvas1jpan9s1l0k1a5mx05g3qj6-python3.13-pytest-8.4.1/lib/python3.13/site-packages/pytest/__main__.py", line 9, in raise SystemExit(pytest.console_main()) File "/nix/store/l9wxarvas1jpan9s1l0k1a5mx05g3qj6-python3.13-pytest-8.4.1/lib/python3.13/site-packages/_pytest/config/__init__.py", line 201, in console_main code = main() File "/nix/store/l9wxarvas1jpan9s1l0k1a5mx05g3qj6-python3.13-pytest-8.4.1/lib/python3.13/site-packages/_pytest/config/__init__.py", line 175, in main ret: ExitCode | int = config.hook.pytest_cmdline_main(config=config) File "/nix/store/r3wzjxnpq41l7s3qbc239s63jakdv7q6-python3.13-pluggy-1.6.0/lib/python3.13/site-packages/pluggy/_hooks.py", line 512, in __call__ return self._hookexec(self.name, self._hookimpls.copy(), kwargs, firstresult) File "/nix/store/r3wzjxnpq41l7s3qbc239s63jakdv7q6-python3.13-pluggy-1.6.0/lib/python3.13/site-packages/pluggy/_manager.py", line 120, in _hookexec return self._inner_hookexec(hook_name, methods, kwargs, firstresult) File "/nix/store/r3wzjxnpq41l7s3qbc239s63jakdv7q6-python3.13-pluggy-1.6.0/lib/python3.13/site-packages/pluggy/_callers.py", line 121, in _multicall res = hook_impl.function(*args) File "/nix/store/l9wxarvas1jpan9s1l0k1a5mx05g3qj6-python3.13-pytest-8.4.1/lib/python3.13/site-packages/_pytest/main.py", line 336, in pytest_cmdline_main return wrap_session(config, _main) File "/nix/store/l9wxarvas1jpan9s1l0k1a5mx05g3qj6-python3.13-pytest-8.4.1/lib/python3.13/site-packages/_pytest/main.py", line 289, in wrap_session session.exitstatus = doit(config, session) or 0 File "/nix/store/l9wxarvas1jpan9s1l0k1a5mx05g3qj6-python3.13-pytest-8.4.1/lib/python3.13/site-packages/_pytest/main.py", line 343, in _main config.hook.pytest_runtestloop(session=session) File "/nix/store/r3wzjxnpq41l7s3qbc239s63jakdv7q6-python3.13-pluggy-1.6.0/lib/python3.13/site-packages/pluggy/_hooks.py", line 512, in __call__ return self._hookexec(self.name, self._hookimpls.copy(), kwargs, firstresult) File "/nix/store/r3wzjxnpq41l7s3qbc239s63jakdv7q6-python3.13-pluggy-1.6.0/lib/python3.13/site-packages/pluggy/_manager.py", line 120, in _hookexec return self._inner_hookexec(hook_name, methods, kwargs, firstresult) File "/nix/store/r3wzjxnpq41l7s3qbc239s63jakdv7q6-python3.13-pluggy-1.6.0/lib/python3.13/site-packages/pluggy/_callers.py", line 121, in _multicall res = hook_impl.function(*args) File "/nix/store/l9wxarvas1jpan9s1l0k1a5mx05g3qj6-python3.13-pytest-8.4.1/lib/python3.13/site-packages/_pytest/main.py", line 367, in pytest_runtestloop item.config.hook.pytest_runtest_protocol(item=item, nextitem=nextitem) File "/nix/store/r3wzjxnpq41l7s3qbc239s63jakdv7q6-python3.13-pluggy-1.6.0/lib/python3.13/site-packages/pluggy/_hooks.py", line 512, in __call__ return self._hookexec(self.name, self._hookimpls.copy(), kwargs, firstresult) File "/nix/store/r3wzjxnpq41l7s3qbc239s63jakdv7q6-python3.13-pluggy-1.6.0/lib/python3.13/site-packages/pluggy/_manager.py", line 120, in _hookexec return self._inner_hookexec(hook_name, methods, kwargs, firstresult) File "/nix/store/r3wzjxnpq41l7s3qbc239s63jakdv7q6-python3.13-pluggy-1.6.0/lib/python3.13/site-packages/pluggy/_callers.py", line 121, in _multicall res = hook_impl.function(*args) File "/nix/store/l9wxarvas1jpan9s1l0k1a5mx05g3qj6-python3.13-pytest-8.4.1/lib/python3.13/site-packages/_pytest/runner.py", line 117, in pytest_runtest_protocol runtestprotocol(item, nextitem=nextitem) File "/nix/store/l9wxarvas1jpan9s1l0k1a5mx05g3qj6-python3.13-pytest-8.4.1/lib/python3.13/site-packages/_pytest/runner.py", line 136, in runtestprotocol reports.append(call_and_report(item, "call", log)) File "/nix/store/l9wxarvas1jpan9s1l0k1a5mx05g3qj6-python3.13-pytest-8.4.1/lib/python3.13/site-packages/_pytest/runner.py", line 245, in call_and_report call = CallInfo.from_call( File "/nix/store/l9wxarvas1jpan9s1l0k1a5mx05g3qj6-python3.13-pytest-8.4.1/lib/python3.13/site-packages/_pytest/runner.py", line 344, in from_call result: TResult | None = func() File "/nix/store/l9wxarvas1jpan9s1l0k1a5mx05g3qj6-python3.13-pytest-8.4.1/lib/python3.13/site-packages/_pytest/runner.py", line 246, in lambda: runtest_hook(item=item, **kwds), when=when, reraise=reraise File "/nix/store/r3wzjxnpq41l7s3qbc239s63jakdv7q6-python3.13-pluggy-1.6.0/lib/python3.13/site-packages/pluggy/_hooks.py", line 512, in __call__ return self._hookexec(self.name, self._hookimpls.copy(), kwargs, firstresult) File "/nix/store/r3wzjxnpq41l7s3qbc239s63jakdv7q6-python3.13-pluggy-1.6.0/lib/python3.13/site-packages/pluggy/_manager.py", line 120, in _hookexec return self._inner_hookexec(hook_name, methods, kwargs, firstresult) File "/nix/store/r3wzjxnpq41l7s3qbc239s63jakdv7q6-python3.13-pluggy-1.6.0/lib/python3.13/site-packages/pluggy/_callers.py", line 121, in _multicall res = hook_impl.function(*args) File "/nix/store/l9wxarvas1jpan9s1l0k1a5mx05g3qj6-python3.13-pytest-8.4.1/lib/python3.13/site-packages/_pytest/runner.py", line 178, in pytest_runtest_call item.runtest() File "/nix/store/l9wxarvas1jpan9s1l0k1a5mx05g3qj6-python3.13-pytest-8.4.1/lib/python3.13/site-packages/_pytest/unittest.py", line 332, in runtest testcase(result=self) File "/nix/store/iyff8129iampdw13nlfqalzhxy8y1hi9-python3-3.13.6/lib/python3.13/unittest/case.py", line 707, in __call__ return self.run(*args, **kwds) File "/nix/store/iyff8129iampdw13nlfqalzhxy8y1hi9-python3-3.13.6/lib/python3.13/unittest/async_case.py", line 135, in run return super().run(result) File "/nix/store/iyff8129iampdw13nlfqalzhxy8y1hi9-python3-3.13.6/lib/python3.13/unittest/case.py", line 647, in run self._callSetUp() File "/nix/store/iyff8129iampdw13nlfqalzhxy8y1hi9-python3-3.13.6/lib/python3.13/unittest/async_case.py", line 91, in _callSetUp self._callAsync(self.asyncSetUp) File "/nix/store/iyff8129iampdw13nlfqalzhxy8y1hi9-python3-3.13.6/lib/python3.13/unittest/async_case.py", line 108, in _callAsync return self._asyncioRunner.run( File "/nix/store/iyff8129iampdw13nlfqalzhxy8y1hi9-python3-3.13.6/lib/python3.13/asyncio/runners.py", line 118, in run return self._loop.run_until_complete(task) File "/nix/store/iyff8129iampdw13nlfqalzhxy8y1hi9-python3-3.13.6/lib/python3.13/asyncio/base_events.py", line 712, in run_until_complete self.run_forever() File "/nix/store/iyff8129iampdw13nlfqalzhxy8y1hi9-python3-3.13.6/lib/python3.13/asyncio/base_events.py", line 683, in run_forever self._run_once() File "/nix/store/iyff8129iampdw13nlfqalzhxy8y1hi9-python3-3.13.6/lib/python3.13/asyncio/base_events.py", line 2042, in _run_once handle._run() File "/nix/store/iyff8129iampdw13nlfqalzhxy8y1hi9-python3-3.13.6/lib/python3.13/asyncio/events.py", line 89, in _run self._context.run(self._callback, *self._args) File "/build/source/test_opensearchpy/test_async/test_server_secured/test_security_plugin.py", line 45, in asyncSetUp self.client = await get_test_client( File "/build/source/opensearchpy/_async/helpers/test.py", line 36, in get_test_client await client.cluster.health(wait_for_status="yellow") File "/build/source/opensearchpy/_async/client/cluster.py", line 129, in health return await self.transport.perform_request( File "/build/source/opensearchpy/_async/transport.py", line 391, in perform_request status, headers_response, data = await connection.perform_request( File "/build/source/opensearchpy/_async/http_aiohttp.py", line 245, in perform_request await self._create_aiohttp_session() File "/build/source/opensearchpy/_async/http_aiohttp.py", line 367, in _create_aiohttp_session self.session = aiohttp.ClientSession( Finished executing pytestCheckPhase

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workinguntriagedNeed triage

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions