-
Notifications
You must be signed in to change notification settings - Fork 160
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
0.25.1 regression Python 3.9 asyncio_mode="auto" # RuntimeError: There is no current event loop in thread 'MainThread' #1039
Comments
Log, if helps any: self = <tests.unit.test_model.TestModelState testMethod=test_apply_delta>
def test_apply_delta(self):
> model = Model()
tests/unit/test_model.py:72:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
juju/model/__init__.py:677: in __init__
self._watch_stopping = asyncio.Event()
/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/asyncio/locks.py:177: in __init__
self._loop = events.get_event_loop()
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <asyncio.unix_events._UnixDefaultEventLoopPolicy object at 0x105a521f0>
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()):
self.set_event_loop(self.new_event_loop())
if self._local._loop is None:
> raise RuntimeError('There is no current event loop in thread %r.'
% threading.current_thread().name)
E RuntimeError: There is no current event loop in thread 'MainThread'. |
My config, since the most likely cause is the change that fixed interleaved loop scopes:
I don't have custom loop_scope's in the tests, only this config. I do, however, have a mix of modern pytest tests (module-level Easy reproducer: git clone [email protected]:juju/python-libjuju.git
cd python-libjuju
# currently at a58645e
uvx -p 3.9 tox -e unit |
Thanks for the detailed report! |
#1250 - update type hints in juju/application.py, pyright is now happy - correct type hints for facade.Type - work around pytest-dev/pytest-asyncio#1039
Yes the test is synchronous, however it instantiates some code which in turn creates an |
Replace the asyncio.get_event_loop() followed by run_until_complete(...) call with the asyncio.run(...), because it makes the code cleaner and works even if the event loop in the main thread has been cleared. This fixes an issue with pytest-asyncio 0.25.2 which seems to clear the main thread event loop sometimes. The tests on sync_attachments and sync_objects used to fail if all tests were ran in the same pytest call, but if only those sync tests are selected (e.g. with `pytest -k test_sync`) then the tests used to pass. After this change they seem to pass on both cases. This might be the same issue as described in [1] (even if it is only for Python 3.9, but our issue happens with Python 3.12) or not. [1] pytest-dev/pytest-asyncio#1039
Also have received a similar traceback for this test definition: @pytest.mark.asyncio()
async def test_global_retry_config_disable_async():
s = SDK(retry_config=None)
with pytest.raises(
errors.APIError, match="API error occurred: Status 503"
) as exc_info:
await s.retries.retries_get_async(request_id=str(uuid.uuid4()), num_retries=2)
assert exc_info.value.status_code == 503
|
I found some time to dig into this. Let me outline my findings. As @dimaqq already mentioned, the failing test calls asyncio.Event() and only fails on Python 3.9. The implementation of the Event constructor in CPython 3.9 calls asyncio.get_event_loop() which is also seen in the stacktrace. In CPython 3.9 this function behaves differently depending on whether asyncio.set_event_loop() has been called or not: If set_event_loop has never been called before, get_event_loop will return a fresh loop. However, if set_event_loop has already been called on the current event loop policy, get_event_loop will raise the reported RuntimeError (see the docs). Later implementations of asyncio.Event() from CPython 3.10 onwards no longer call asyncio.get_event_loop(), which is why they don't produce the same error. Indeed, running the failing test "test_apply_delta" on its own causes the test to run successfully, whereas running the full test suite makes the test fail when pytest-asyncio v0.25.1 is installed. Therefore, I incrementally disabled tests from the test suite and found that Most importantly, the tests produce the same error even when pytest-asyncio is disabled with
Therefore, I conclude that this is not a pytest-asyncio bug. The issue in the test suite was simply overshadowed by bad behavior of pytest-asyncio in earlier versions. Changing line 70 of @bflad Your issue is likely a different one. The best way to solve it is to provide a minimal reproducible example in a separate issue. |
Happy new year.
0.25.1 was released recently and somehow it fails on Python 3.9 specifically.
In my case, asyncio_mode = "auto" is used, so maybe similar to #658, however I don't know if that's required for the regression.
Meanwhile, Python 3.8 is OK (0.25.x can't be used, 0.24 is used instead)
And Python 3.10, 3.11, 3.12, 3.13 are OK (with the new version)
Version resolution:
Run log: https://github.com/juju/python-libjuju/actions/runs/12423507633
Screenshot for the above:

I've manually validated that 0.25.0 works fine in my setup.
The text was updated successfully, but these errors were encountered: