mvg icon indicating copy to clipboard operation
mvg copied to clipboard

RuntimeError: asyncio.run() cannot be called from a running event loop

Open adamgdoura6 opened this issue 1 year ago • 1 comments

I am running this script

from mvg import MvgApi, TransportType

station = MvgApi.station('Universität, München')
if station:
    mvgapi = MvgApi(station['id'])
    departures = mvgapi.departures(
        limit=3,
        offset=5,
        transport_types=[TransportType.UBAHN])
    print(station, departures)

and it fails at this line station = MvgApi.station('Universität, München')

with the following error:

---------------------------------------------------------------------------
RuntimeError                              Traceback (most recent call last)
Cell In[1], line 3
      1 from mvg import MvgApi, TransportType
----> 3 station = MvgApi.station('Universität, München')
      4 if station:
      5     mvgapi = MvgApi(station['id'])

File ~\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.12_qbz5n2kfra8p0\LocalCache\local-packages\Python312\site-packages\mvg\mvgapi.py:286, in MvgApi.station(query)
    268 @staticmethod
    269 def station(query: str) -> dict[str, str] | None:
    270     """Find a station by station name and place or global station id.
    271 
    272     :param name: name, place ('Universität, München') or global station id (e.g. 'de:09162:70')
   (...)
    284         }
    285     """
--> 286     return asyncio.run(MvgApi.station_async(query))

File C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.12_3.12.2544.0_x64__qbz5n2kfra8p0\Lib\asyncio\runners.py:191, in run(main, debug, loop_factory)
    161 """Execute the coroutine and return the result.
    162 
    163 This function runs the passed coroutine, taking care of
   (...)
    187     asyncio.run(main())
    188 """
    189 if events._get_running_loop() is not None:
    190     # fail fast with short traceback
--> 191     raise RuntimeError(
    192         "asyncio.run() cannot be called from a running event loop")
    194 with Runner(debug=debug, loop_factory=loop_factory) as runner:
    195     return runner.run(main)

RuntimeError: asyncio.run() cannot be called from a running event loop

Any Clue where the error could be?

adamgdoura6 avatar Apr 05 '25 09:04 adamgdoura6

I have a similar situation.

While the demo script runs succesfully for me I cannot integrate the API calls into some Flask application. Flask seems to introduce it's own async context and I am getting the error as described above. But also when I try to create a background thread to isolate Flask-threads from the threads that execute the mvg api I get the above errors.

Thus I ran out of ideas how to use this API for my application.

Update: I checked the source and found lines like this: https://github.com/mondbaron/mvg/blob/main/src/mvg/mvgapi.py#L457 The result is that even synchronous function calls from the API require the async context within the library. Or in other words: the API creates it's own asynchronous context regardless how it is being called. But that is a problem when used with other async frameworks or libraries.

Update 2: Investigating on asyncio my suspicion seems confirmed. From https://medium.com/@pgjones/understanding-asyncio-a6592a517def:

With Asyncio the yield must be explicitly coded, by using the await keyword to await something that is asynchronous from within something that is asynchronous. Additionally anything that is asynchronous must also be explicitly marked as such, using the async keyword. This causes an immediate headache as most existing code does not do this, and hence Asyncio does not work with this code. It then causes a second headache in that now everything bar the main function must be asynchronous if anything is asynchronous.

It is a challenge to mix synchronous with asynchronous code. Especially if the event loop has already been taken by some code, other code is difficult to handle. Thus I suggest there should be two separate modules - one completely synchronous while the other is completely asynchronous. The current mix is dysfunctional.

HiranChaudhuri avatar May 26 '25 15:05 HiranChaudhuri