1
\$\begingroup\$

I have two functions which I would like to simplify. They have largely the same logic, but one is asynchronous and uses one await in a try block. I'd like to have the logic in one place, but could not figure out a clean way of doing that. Any suggestions?

from requests import get, HTTPError
# Dummy functions for external functionality
def sync_send(url):
 return get(url)
async def async_send(url):
 return get(url)
def next(url):
 if url is None:
 return
 try:
 response = sync_send(url)
 return response.json()
 except HTTPError as e:
 if e.response.status_code == 404:
 return
 else:
 raise
async def async_next(url):
 if url is None:
 return
 try:
 response = await async_send(url)
 return response.json()
 except HTTPError as e:
 if e.response.status_code == 404:
 return
 else:
 raise

So the point of this all is to provide a way of requesting for resources in an API two ways, sync and async. Despite the simple (synchronous) dummy functions, in async_next we use asynchronous IO to retrieve things. Other than that, the situation is exactly as it is here.


I have accepted that the if url is None cannot be refactored, and I currently think my only option is to make a more complex exception hierarchy, raising a dedicated 404 error to catch it without logic. Any other ideas?

Mast
13.8k12 gold badges57 silver badges127 bronze badges
asked Feb 11, 2020 at 21:36
\$\endgroup\$
2
  • \$\begingroup\$ What happened with passing the cond variable? \$\endgroup\$ Commented Feb 17, 2020 at 11:20
  • \$\begingroup\$ @Mast When asking this question I thought without further context it would be weird to assume that someone would pass in an empty URL. But when I thought about it again, it is better to have it as it is in the code. \$\endgroup\$ Commented Feb 17, 2020 at 11:24

1 Answer 1

1
\$\begingroup\$

Let's have async implementation:

async def async_next(url):
 if url is None:
 return
 try:
 response = await async_send(url)
 return response.json()
 except HTTPError as e:
 if e.response.status_code == 404:
 return
 else:
 raise

Then you can provide following sync bridge:

def next(url):
 return asyncio.run(async_next(url))

Or the following if the event loop is available and running:

def next(url):
 return loop.run_until_complete(async_next(url))

Note: check asyncio high level commands for more details

answered Feb 18, 2020 at 0:08
\$\endgroup\$
1
  • \$\begingroup\$ Thanks for the suggestion, though I'm not a fan of running the loop every time a synchronous call should be made. \$\endgroup\$ Commented Feb 18, 2020 at 7:04

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.