title: Wait for async function to complete
body: <p>My question is more or less like <a href="https://stackoverflow.com/questions/56689198/runtimeerror-task-got-future-future-pending-attached-to-a-different-loop">this</a>, which is really an X-Y problem leading back to <a href="https://stackoverflow.com/questions/55147976/run-and-wait-for-asynchronous-function-from-a-synchronous-one-using-python-async">this</a>. This is, however, not a duplicate, because my use case is slightly different and the linked threads don't answer my question.</p>
  
  <p>I am porting a set of synchronous programs from Java to Python. These programs interact with an asynchronous library. In Java, I could block and wait for this library's asynchronous functions to return a value and then do things with that value.</p>
  
  <p>Here's a code sample to illustrate the problem.</p>
  
  <pre><code>def do_work_sync_1(arg1, arg2, arg3):
      # won't even run because await has to be called from an async function
      value = await do_work_async(arg1, arg2, arg3)
  
  def do_work_sync_2(arg1, arg2, arg3):
      # throws "Loop already running" error because the async library referenced in do_work_async is already using my event loop
      event_loop = asyncio.get_event_loop()
      event_loop.run_until_complete(do_work_async(arg1, arg2, arg3))
  
  def do_work_sync_3(arg1, arg2, arg3):
      # throws "got Future attached to a different loop" because the do_work_async refers back to the asynchronous library, which is stubbornly attached to my main loop
      thread_pool = ThreadPoolExecutor()
      future = thread_pool.submit(asyncio.run, do_work_async(arg1, arg2, arg3)
      result = future.result()
  
  def do_work_sync_4(arg1, arg2, arg3):
      # just hangs forever
      event_loop = asyncio.get_event_loop()
      future = asyncio.run_coroutine_threadsafe(do_work_async(arg1, arg2, arg3), event_loop)
      return_value = future.result()
  
  async def do_work_async(arg1, arg2, arg3):
      value_1 = await async_lib.do_something(arg1)
      value_2 = await async_lib.do_something_else(arg2, arg3)
  
      return value_1 + value_2
  </code></pre>
  
  <p>Python appears to be trying very hard to keep me from blocking anything, anywhere. <code>await</code> can only be used from <code>async def</code> functions, which in their turn must be <code>await</code>ed. There doesn't seem to be a built-in way to keep <code>async def</code>/<code>await</code> from spreading through my code like a virus.</p>
  
  <p><code>Task</code>s and <code>Future</code>s don't have any built-in blocking or <code>wait_until_complete</code> mechanisms unless I want to loop on <code>Task.done()</code>, which seems really bad.</p>
  
  <p>I tried <code>asyncio.get_event_loop().run_until_complete()</code>, but that produces an error: <code>This event loop is already running.</code> <a href="https://stackoverflow.com/questions/50279536/how-can-i-deal-with-this-event-loop-is-already-running-error-on-a-nested-funct">Apparently I'm not supposed to do that for anything except <code>main()</code>.</a></p>
  
  <p><a href="https://stackoverflow.com/questions/55147976/run-and-wait-for-asynchronous-function-from-a-synchronous-one-using-python-async">The second linked question above</a> suggests using a separate thread and wrapping the async function in that. I tested this with a few simple functions and it seems to work as a general concept. The problem here is that my asynchronous library keeps a reference to the main thread's event loop and throws an error when I try to refer to it from the new thread: <code>got Future &lt;Future pending&gt; attached to a different loop</code>.</p>
  
  <p>I considered moving all references to the asynchronous library into a separate thread, but I realized that I still can't block in the new thread, and I'd have to create a <em>third</em> thread for blocking calls, which would bring me back to the <code>Future attached to a different loop</code> error.</p>
  
  <p>I'm pretty much out of ideas here. Is there a way to block and wait for an async function to return, or am I really being forced to convert my entire program to <code>async</code>/<code>await</code>? (If it's the latter, an explanation would be nice. I don't get it.)</p>