Technical info

The Vulcan API is asynchronous (using asyncio) and works using coroutines. All the code presented in this documentation needs to be placed inside a coroutine block (except imports, obviously).

A sample coroutine block looks as follows:

import asyncio

async def main():
    # asynchronous code goes here

if __name__ == "__main__":
    loop = asyncio.get_event_loop()

Data fetching

All data getting methods are asynchronous.

There are three return types of those methods:

  • object - applies to methods returning a single object (e.g. the currently selected student, the today’s lucky number, the server date-time)

  • list - applies to get_students(). The list is either read from the server or the in-memory cache.

  • AsyncIterator - applies to all other data fetching methods. The returned iterator may be used like this:

    grades = await
    # with a for loop
    async for grade in grades:
    # convert to a list
    grades = [grade async for grade in grades]
    for grade in grades:


You cannot re-use the AsyncIterator (once iterated through). As it is asynchronous, you also cannot use the next() method on it.


As all HTTP requests are also async, the API uses aiohttp’s sessions, which need to be opened and closed when needed.

Upon creation, the Vulcan object creates a session, which needs to be closed before the program terminates.

client = Vulcan(keystore, account)
# use the client here
await client.close()

It is also possible to use a context manager to handle session opening and closing automatically.

client = Vulcan(keystore, account)
async with client:
    # use the client here


Be aware that every with block creates and closes a new session. As per the aiohttp docs, it is recommended to group multiple requests to use with a single session, so it’s best not to use a separate with block for every single request.