asks
- An overview of the functions and kw/arguments.¶
asks
is heavily influenced by requests, and as such pretty much everything that works in requests
works in asks
.
So, if you’re familiar with the format you can pretty much skip to the distinctions regarding sessions
The examples here use the base one-request-functions for verbosity’s sake, but all of these functions are completely transferable to the Session
class as methods.
Warning!
If you don’t use a Session
you can easily max out your OS’s socket resources against highly performant servers (usually local to the machine or LAN). When using the base functions you’ll be creating a new connection for every request.
(Calling asks.get('https://some-url.io'))
really makes a temporary Session
.)
General HTTP methods¶
asks
supports get()
, head()
, post()
, put()
, delete()
, options()
, patch()
and request()
.
request
takes a HTTP method as a string for its first argument.
When using the basic functions they each require a URI:
import asks
async def blah():
a = await asks.get('https://example.com')
s = await asks.head('http://httpbin.org')
k = await asks.post('https://webservice.net:25000')
s = await asks.put('www.your-coat-on.net') # <- no scheme! Will fail!
# etc.
r = await asks.request('GET', 'http://httpbin.org/get')
A scheme must be supplied. Port can be set by providing it in the URI.
All functions / methods share the same set of args / keyword args, though not all are appropriate for every HTTP method.
Passing Queries¶
The params
and data
args take a dictionary and convert it in to a query string to be appended to to URL, or sent in the request body, respectively.
async def example():
r = await asks.get('www.example.com', params={'Elmo': 'wants data'})
# sends as request path:
b'?Elmo=wants+data'
async def example():
r = await asks.get('www.example.com', data={'Elmo': 'wants data'})
# sends in request body:
b'Elmo=wants+data'
You may also pass strings, asks
will attempt to format them correctly.
async def example():
r = await asks.post('www.example.com', params='Elmo wants data')
# sends as request path:
b'?Elmo%20wants%20data'
async def example():
r = await asks.post('www.example.com', data='Elmo wants data')
# sends in request body:
b'Elmo wants data'
Note: the data
arg is incompatible with the json
, multipart
and files
args.
Custom Headers¶
Add your own custom headers or overwrite the default headers by supplying your own dict to the headers
argument. Note that user headers set in this way will, if conflicting, take precedence.
async def example():
r = await asks.get('www.example.com',
headers={'Custom-Header': 'My value'})
Sending JSON¶
Pass Python dict
objects to the json
argument to send them as JSON in your request.
Note that if your workflow here involves opening a JSON file, you should use curio
’s aopen()
or trio
’s open_file()
to avoid stalling the program on disk reads.
dict_to_send = {'Data_1': 'Important thing',
'Data_2': 'Really important thing'}
async def example():
r = await asks.post('www.example.com', json=dict_to_send)
Note: the json
arg is incompatible with the data
, multipart
and files
args.
Sending Files (multipart/form-data)¶
Pass a dict
in the form {field: value}
(as many as you like) to the multipart
argument to
send a multipart/form-data
request.
To send files, send one of the following as value
:
- A
pathlib.Path
object:asks
will asyncronously open and read the file.- An already open binary file-like object. The
read()
method can be a normal function or a coroutine (remember a normal file may block!). You can useanyio.aopen
to get an async file object.- An
asks.multipart.MultipartData
object, which can be used to override the filename or the mime-type of the sent file.
Other values are converted to strings and sent directly.
async def send_file():
r = await asks.post('http://httpbin.org/post',
multipart={'file_1': Path('my_file.txt')})
pprint(r.json())
# if we wanted to send both an already open file and some random data:
from anyio import aopen
async def send_file_and_data():
async with await aopen('my_file.txt', 'rb') as my_file:
r = await asks.post('http://httpbin.org/post',
multipart={'file_1': my_file,
'some_data': 'I am multipart hear me roar',
'some_integer': 3})
# if we wanted to send some bytes as a file:
from asks.multipart import MultipartData
async def send_bytes():
r = await asks.post('http://httpbin.org/post',
multipart={'file_1':
MultipartData(b'some text',
mime_type='text/plain',
basename='my_file.txt')})
pprint(r.json())
# if we wanted to override metadata:
async def send_customized_file():
r = await asks.post('http://httpbin.org/post',
multipart={'file_1':
MultipartData(Path('my_file.txt'),
mime_type='text/plain',
basename='some_other_name.txt')})
pprint(r.json())
Note: the multipart
arg is incompatible with the data
, json
and files
args.
There is also the older files
API, but multipart
should be preferred over it. To use it, pass a dict
in the form {filename: filepath}
(as many as you like) and asks
will asyncronously get the file data, building a multipart-formatted HTTP body. You can also pass non-file paths if you wish to send arbitrary multipart body data sections.
async def send_file():
r = await asks.post('http://httpbin.org/post',
files={'file_1': 'my_file.txt'})
# if we wanted to send both a file and some random data:
async def send_file_and_data():
r = await asks.post('http://httpbin.org/post',
files={'file_1': 'my_file.txt',
'some_data': 'I am multipart hear me roar'})
Note: the files
arg is incompatible with the data
, json
and multipart
args.
Sending Cookies¶
Pass a dict
of cookie name(key) / value pairs to the cookies
arg to ship ‘em off.
async def example():
r = await asks.get('www.example.com',
cookies={'Cookie Monster': 'Yum'})
Cookie Interactions¶
By default asks
does not return sent cookies. To enable two-way cookie interactions, just pass persist_cookies=True
.
async def example():
r = await asks.get('www.example.com', persist_cookies=True)
Set Encoding¶
The default encoding is utf-8
. You may override this by supplying a different encoding, be it a standard encoding or a custom one you’ve registered locally.
async def example():
r = await asks.get('www.example.com', encoding='Latin-1')
Handy list of builtin encodings: https://gist.github.com/theelous3/7d6a3fe20a21966b809468fa336195e3
Limiting Redirects¶
You can limit the number of redirects by setting max_redirects
. By default, the number of redirects is 20
. asks
will not redirect on HEAD requests.
async def example():
r = await asks.get('www.httpbin.org/redirect/3', max_redirects=2)
Preventing Redirects¶
You can prevent asks
from automatically following redirects by setting follow_redirects
to False
. By default, asks
will automatically follow redirects until a non-redirect response or max_redirects
are encountered.
async def example():
r = await asks.get('www.httpbin.org/redirect/3', follow_redirects=False)
Set Timeout(s)¶
Don’t want to wait forever? Me neither. You may set a timeout with the timeout
arg. This limits the time allotted for the request.
async def example():
r = await asks.get('www.httpbin.org/redirect/3', timeout=1)
Note that the timeout
arg does not account for the time required to actually establish the connection. That is controlled by a second timeout, the connection_timeout
, which defaults to 60 seconds. It’s used in the exact same way as timeout
. For reasoning, read this.
There is a third timeout available for StreamResponse.body
iteration. See The Response Object
Retry limiting¶
You can set a maximum number of retries with retries
. This defaults to 1
, to catch sockets that die in the connection pool, or generally misbehave. There is no upper limit. Be careful :D
async def example():
r = await asks.get('www.beat_dead_horses.org/neverworks', retries=9999999)
Authing¶
Available off the bat, we have HTTP basic auth and HTTP digest auth.
To add auth in asks, you pass a tuple of ('username', 'password')
to the __init__
of an auth class. For example:
import asks
from asks import BasicAuth, DigestAuth
usr_pw = ('AzureDiamond', 'hunter2')
async def main():
r = await asks.get('https://some_protected.resource',
auth=BasicAuth(usr_pw))
r2 = await asks.get('https://other_protected.thingy',
auth=DigestAuth(usr_pw),
auth_off_domain=True)
Note: asks
will not pass auth along to connections that switch from HTTP to HTTPS, or off domain locations, unless you pass auth_off_domain=True
to the call.
Streaming response data¶
You can stream the body of a response by setting stream=True
, and iterating the response object’s .body
. An example of downloading a file:
import asks
import curio
async def main():
r = await asks.get('http://httpbin.org/image/png', stream=True)
async with curio.aopen('our_image.png', 'ab') as out_file:
async for bytechunk in r.body:
out_file.write(bytechunk)
curio.run(main())
It is important to note that if you do not iterate the .body
to completion, bad things may happen as the connection sits there and isn’t returned to the connection pool.
You can get around this by context-managering the .body
if there is a chance you might not iterate fully.
import asks
import curio
async def main():
r = await asks.get('http://httpbin.com/image/png', stream=True)
async with curio.aopen('our_image.png', 'wb') as out_file:
async with r.body: # Bam! Safe!
async for bytechunk in r.body:
await out_file.write(bytechunk)
curio.run(main())
This way, once you leave the async with
block, asks
will automatically ensure the underlying socket is handled properly. You may also call .body.close()
to manually close the stream.
The streaming body can also be used for streaming feeds and stuff of twitter and the like.
For some examples of how to use this, look here
Callbacks¶
Similar enough to streaming as seen above, but happens during the processing of the response body, before the response object is returned. Overall probably worse to use than streaming in every case but I’m sure someone will find a use for it.
The callback
argument lets you pass a function as a callback that will be run on each bytechunk of response body as the request is being processed.
For some examples of how to use this, look here