HTTP request for a single URL or list of URLs based on arguments provided
Clash Royale CLAN TAG#URR8PPP
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;
up vote
3
down vote
favorite
I have the following code that includes a simple class AioRequest
. I would like to be able to call an instance of this class directly with a single URL or a list of URLs and return the results.
request = AioRequest()
single_response = request('get', 'http://httpbin.org/get')
or
url_list = ['http://httpbin.org/get', 'http://google/some_json']
list_of_responses = request('get', url_list)
I'm wondering what the best practice is for two strategies I am using:
Determining if the argument is a list of URLs or a string with a single URL. Should it be two separate arguments like
__call__
or should I type check like__call__2
?I would like to use the
__call__
method as the main API for theAioRequest
instance, but is returning two different types based on the arguments given a good idea? Is is safe to rely on the user to determine the return type (example: give a single string get a single response, give a list of strings, get a list of responses)?
import asyncio
from aiohttp import ClientSession
from collections import namedtuple
Response = namedtuple(
"Response",
["url", "status_code", "json"]
)
class AioRequest:
def __init__(self, session=None):
self._loop = asyncio.get_event_loop()
self._session = session or ClientSession(loop=self._loop)
def __call__(self, method, url=None, url_list=None, **kwargs):
urls = url_list or
urls.append(url)
requests = [self._request(method, url, **kwargs)
for url in urls
if url is not None]
return self._run(*requests)
def __call__2(self, method, url_or_list_of, **kwargs):
if type(url_or_list_of) is str:
return self._run(method, url_or_list_of, **kwargs)
else:
requests = [self._request(method, url, **kwargs)
for url in url_or_list_of]
return self._run(*requests)
async def _request(self, method, url, **kwargs):
response = await self._session.request(method, url, **kwargs)
return Response(url, response.status, await response.json())
def _run(self, *tasks):
task_group = asyncio.gather(*tasks)
results = self._loop.run_until_complete(task_group) # results = list of responses
if len(results) == 1:
return results[0]
return results
def __del__(self):
self._session.close()
python object-oriented python-3.x duck-typing
add a comment |Â
up vote
3
down vote
favorite
I have the following code that includes a simple class AioRequest
. I would like to be able to call an instance of this class directly with a single URL or a list of URLs and return the results.
request = AioRequest()
single_response = request('get', 'http://httpbin.org/get')
or
url_list = ['http://httpbin.org/get', 'http://google/some_json']
list_of_responses = request('get', url_list)
I'm wondering what the best practice is for two strategies I am using:
Determining if the argument is a list of URLs or a string with a single URL. Should it be two separate arguments like
__call__
or should I type check like__call__2
?I would like to use the
__call__
method as the main API for theAioRequest
instance, but is returning two different types based on the arguments given a good idea? Is is safe to rely on the user to determine the return type (example: give a single string get a single response, give a list of strings, get a list of responses)?
import asyncio
from aiohttp import ClientSession
from collections import namedtuple
Response = namedtuple(
"Response",
["url", "status_code", "json"]
)
class AioRequest:
def __init__(self, session=None):
self._loop = asyncio.get_event_loop()
self._session = session or ClientSession(loop=self._loop)
def __call__(self, method, url=None, url_list=None, **kwargs):
urls = url_list or
urls.append(url)
requests = [self._request(method, url, **kwargs)
for url in urls
if url is not None]
return self._run(*requests)
def __call__2(self, method, url_or_list_of, **kwargs):
if type(url_or_list_of) is str:
return self._run(method, url_or_list_of, **kwargs)
else:
requests = [self._request(method, url, **kwargs)
for url in url_or_list_of]
return self._run(*requests)
async def _request(self, method, url, **kwargs):
response = await self._session.request(method, url, **kwargs)
return Response(url, response.status, await response.json())
def _run(self, *tasks):
task_group = asyncio.gather(*tasks)
results = self._loop.run_until_complete(task_group) # results = list of responses
if len(results) == 1:
return results[0]
return results
def __del__(self):
self._session.close()
python object-oriented python-3.x duck-typing
add a comment |Â
up vote
3
down vote
favorite
up vote
3
down vote
favorite
I have the following code that includes a simple class AioRequest
. I would like to be able to call an instance of this class directly with a single URL or a list of URLs and return the results.
request = AioRequest()
single_response = request('get', 'http://httpbin.org/get')
or
url_list = ['http://httpbin.org/get', 'http://google/some_json']
list_of_responses = request('get', url_list)
I'm wondering what the best practice is for two strategies I am using:
Determining if the argument is a list of URLs or a string with a single URL. Should it be two separate arguments like
__call__
or should I type check like__call__2
?I would like to use the
__call__
method as the main API for theAioRequest
instance, but is returning two different types based on the arguments given a good idea? Is is safe to rely on the user to determine the return type (example: give a single string get a single response, give a list of strings, get a list of responses)?
import asyncio
from aiohttp import ClientSession
from collections import namedtuple
Response = namedtuple(
"Response",
["url", "status_code", "json"]
)
class AioRequest:
def __init__(self, session=None):
self._loop = asyncio.get_event_loop()
self._session = session or ClientSession(loop=self._loop)
def __call__(self, method, url=None, url_list=None, **kwargs):
urls = url_list or
urls.append(url)
requests = [self._request(method, url, **kwargs)
for url in urls
if url is not None]
return self._run(*requests)
def __call__2(self, method, url_or_list_of, **kwargs):
if type(url_or_list_of) is str:
return self._run(method, url_or_list_of, **kwargs)
else:
requests = [self._request(method, url, **kwargs)
for url in url_or_list_of]
return self._run(*requests)
async def _request(self, method, url, **kwargs):
response = await self._session.request(method, url, **kwargs)
return Response(url, response.status, await response.json())
def _run(self, *tasks):
task_group = asyncio.gather(*tasks)
results = self._loop.run_until_complete(task_group) # results = list of responses
if len(results) == 1:
return results[0]
return results
def __del__(self):
self._session.close()
python object-oriented python-3.x duck-typing
I have the following code that includes a simple class AioRequest
. I would like to be able to call an instance of this class directly with a single URL or a list of URLs and return the results.
request = AioRequest()
single_response = request('get', 'http://httpbin.org/get')
or
url_list = ['http://httpbin.org/get', 'http://google/some_json']
list_of_responses = request('get', url_list)
I'm wondering what the best practice is for two strategies I am using:
Determining if the argument is a list of URLs or a string with a single URL. Should it be two separate arguments like
__call__
or should I type check like__call__2
?I would like to use the
__call__
method as the main API for theAioRequest
instance, but is returning two different types based on the arguments given a good idea? Is is safe to rely on the user to determine the return type (example: give a single string get a single response, give a list of strings, get a list of responses)?
import asyncio
from aiohttp import ClientSession
from collections import namedtuple
Response = namedtuple(
"Response",
["url", "status_code", "json"]
)
class AioRequest:
def __init__(self, session=None):
self._loop = asyncio.get_event_loop()
self._session = session or ClientSession(loop=self._loop)
def __call__(self, method, url=None, url_list=None, **kwargs):
urls = url_list or
urls.append(url)
requests = [self._request(method, url, **kwargs)
for url in urls
if url is not None]
return self._run(*requests)
def __call__2(self, method, url_or_list_of, **kwargs):
if type(url_or_list_of) is str:
return self._run(method, url_or_list_of, **kwargs)
else:
requests = [self._request(method, url, **kwargs)
for url in url_or_list_of]
return self._run(*requests)
async def _request(self, method, url, **kwargs):
response = await self._session.request(method, url, **kwargs)
return Response(url, response.status, await response.json())
def _run(self, *tasks):
task_group = asyncio.gather(*tasks)
results = self._loop.run_until_complete(task_group) # results = list of responses
if len(results) == 1:
return results[0]
return results
def __del__(self):
self._session.close()
python object-oriented python-3.x duck-typing
edited Jan 13 at 1:15
Jamalâ¦
30.1k11114225
30.1k11114225
asked Jan 13 at 0:12
JohnBoy
383
383
add a comment |Â
add a comment |Â
1 Answer
1
active
oldest
votes
up vote
1
down vote
__call__
really confuses me. Type checking is the way to go for readability. On top of that, if you need to accept new types later, all you need to do is add an if
statement.
In my opinion, if you absolutely want the brevity of __call__
, accepting multiple types of arguments is fine, and so is returning multiple types (as is the case with many builtin and standard library functions). It is important that you mention this in the documentation, though.
Some other questionable things:
Instead of comparing
type
directly, you can useisinstance
:if isinstance(url_or_list_of, str):
...url_or_list_of
is a somewhat unfriendly name for a public API. How abouturl_or_list_of_urls
?It's good that you provide a 'clean exit' method.
__del__
isn't the right method to override, however, since the implementation is CPython-specific, and it may never actually be called. Instead, try defining__enter__
and__exit__
:class AioRequest:
...
def __enter__(self):
return self
# This should be all in most cases,
# unless you want to do something with `self` before returning
...
def __exit__(self, exc_type, exc_value, exc_traceback):
self._session.close()You can then use
with
:with AioRequest() as request:
# __enter__ called
response = request( ... )
# __exit__ called
add a comment |Â
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
1
down vote
__call__
really confuses me. Type checking is the way to go for readability. On top of that, if you need to accept new types later, all you need to do is add an if
statement.
In my opinion, if you absolutely want the brevity of __call__
, accepting multiple types of arguments is fine, and so is returning multiple types (as is the case with many builtin and standard library functions). It is important that you mention this in the documentation, though.
Some other questionable things:
Instead of comparing
type
directly, you can useisinstance
:if isinstance(url_or_list_of, str):
...url_or_list_of
is a somewhat unfriendly name for a public API. How abouturl_or_list_of_urls
?It's good that you provide a 'clean exit' method.
__del__
isn't the right method to override, however, since the implementation is CPython-specific, and it may never actually be called. Instead, try defining__enter__
and__exit__
:class AioRequest:
...
def __enter__(self):
return self
# This should be all in most cases,
# unless you want to do something with `self` before returning
...
def __exit__(self, exc_type, exc_value, exc_traceback):
self._session.close()You can then use
with
:with AioRequest() as request:
# __enter__ called
response = request( ... )
# __exit__ called
add a comment |Â
up vote
1
down vote
__call__
really confuses me. Type checking is the way to go for readability. On top of that, if you need to accept new types later, all you need to do is add an if
statement.
In my opinion, if you absolutely want the brevity of __call__
, accepting multiple types of arguments is fine, and so is returning multiple types (as is the case with many builtin and standard library functions). It is important that you mention this in the documentation, though.
Some other questionable things:
Instead of comparing
type
directly, you can useisinstance
:if isinstance(url_or_list_of, str):
...url_or_list_of
is a somewhat unfriendly name for a public API. How abouturl_or_list_of_urls
?It's good that you provide a 'clean exit' method.
__del__
isn't the right method to override, however, since the implementation is CPython-specific, and it may never actually be called. Instead, try defining__enter__
and__exit__
:class AioRequest:
...
def __enter__(self):
return self
# This should be all in most cases,
# unless you want to do something with `self` before returning
...
def __exit__(self, exc_type, exc_value, exc_traceback):
self._session.close()You can then use
with
:with AioRequest() as request:
# __enter__ called
response = request( ... )
# __exit__ called
add a comment |Â
up vote
1
down vote
up vote
1
down vote
__call__
really confuses me. Type checking is the way to go for readability. On top of that, if you need to accept new types later, all you need to do is add an if
statement.
In my opinion, if you absolutely want the brevity of __call__
, accepting multiple types of arguments is fine, and so is returning multiple types (as is the case with many builtin and standard library functions). It is important that you mention this in the documentation, though.
Some other questionable things:
Instead of comparing
type
directly, you can useisinstance
:if isinstance(url_or_list_of, str):
...url_or_list_of
is a somewhat unfriendly name for a public API. How abouturl_or_list_of_urls
?It's good that you provide a 'clean exit' method.
__del__
isn't the right method to override, however, since the implementation is CPython-specific, and it may never actually be called. Instead, try defining__enter__
and__exit__
:class AioRequest:
...
def __enter__(self):
return self
# This should be all in most cases,
# unless you want to do something with `self` before returning
...
def __exit__(self, exc_type, exc_value, exc_traceback):
self._session.close()You can then use
with
:with AioRequest() as request:
# __enter__ called
response = request( ... )
# __exit__ called
__call__
really confuses me. Type checking is the way to go for readability. On top of that, if you need to accept new types later, all you need to do is add an if
statement.
In my opinion, if you absolutely want the brevity of __call__
, accepting multiple types of arguments is fine, and so is returning multiple types (as is the case with many builtin and standard library functions). It is important that you mention this in the documentation, though.
Some other questionable things:
Instead of comparing
type
directly, you can useisinstance
:if isinstance(url_or_list_of, str):
...url_or_list_of
is a somewhat unfriendly name for a public API. How abouturl_or_list_of_urls
?It's good that you provide a 'clean exit' method.
__del__
isn't the right method to override, however, since the implementation is CPython-specific, and it may never actually be called. Instead, try defining__enter__
and__exit__
:class AioRequest:
...
def __enter__(self):
return self
# This should be all in most cases,
# unless you want to do something with `self` before returning
...
def __exit__(self, exc_type, exc_value, exc_traceback):
self._session.close()You can then use
with
:with AioRequest() as request:
# __enter__ called
response = request( ... )
# __exit__ called
answered Jan 13 at 9:52
Daniel
4,1132836
4,1132836
add a comment |Â
add a comment |Â
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f185000%2fhttp-request-for-a-single-url-or-list-of-urls-based-on-arguments-provided%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password