in practice calling loop.run_until_complete from a non-async function called from an async function is basically the same thing as awaiting the non-async function
what this means in practice is that a synchronous abstraction layer can become async by using loop.run_until_complete while the loop is already running