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 use anyio.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'})

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