How do I write a sequence of promises in Python?

37,499

Solution 1

Here's a similar program using asyncio and the async/await syntax:

import asyncio
import random

async def alpha(x):
    await asyncio.sleep(0.2)
    return x + 1 

async def bravo(x):
    await asyncio.sleep(0.2)
    return random.randint(0, 1000) + x

async def charlie(x):
    if x % 2 == 0:
        return x
    raise ValueError(x, 'is odd')

async def run():
    try:
        number = await charlie(await bravo(await alpha(42)))
    except ValueError as exc:
        print('error:', exc.args[0])
    else:
        print('success:', number)

if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    loop.run_until_complete(run())
    loop.close()

EDIT: If you're interested in reactive streams, you might consider using aiostream.

Here's a simple example:

import asyncio
from aiostream import stream, pipe

async def main():
    # This stream computes 11² + 13² in 1.5 second
    xs = (
        stream.count(interval=0.1)      # Count from zero every 0.1 s
        | pipe.skip(10)                 # Skip the first 10 numbers
        | pipe.take(5)                  # Take the following 5
        | pipe.filter(lambda x: x % 2)  # Keep odd numbers
        | pipe.map(lambda x: x ** 2)    # Square the results
        | pipe.accumulate()             # Add the numbers together
    )
    print('11² + 13² = ', await xs)

if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    loop.run_until_complete(main())
    loop.close()

More examples in the documentation.

Disclaimer: I am the project maintainer.

Solution 2

You're in luck, Python 3.4 and above include asyncio, although the feature you are looking for (Future) is available in Python 3.5 and up.

From your own link about asyncio: "This version is only relevant for Python 3.3, which does not include asyncio in its stdlib."

Example:

import asyncio


async def some_coroutine():
    await asyncio.sleep(1)
    return 'done'


def process_result(future):
    print('Task returned:', future.result())


loop = asyncio.get_event_loop()
task = loop.create_task(some_coroutine())
task.add_done_callback(process_result)
loop.run_until_complete()
Share:
37,499
JP Ventura
Author by

JP Ventura

An independent and self-motivated professional with excellent research and and data-oriented development.

Updated on January 26, 2022

Comments

  • JP Ventura
    JP Ventura over 2 years

    Is it possible to write a sequence of promise (or tasks) using only Python 3.6.1 Standard Library?

    For example, a sequence promises in JavaScript is written as:

    const SLEEP_INTERVAL_IN_MILLISECONDS = 200;
    
    const alpha = function alpha (number) {
        return new Promise(function (resolve, reject) {
            const fulfill = function() {
                return resolve(number + 1);
            };
    
            return setTimeout(fulfill, SLEEP_INTERVAL_IN_MILLISECONDS);
        });
    };
    
    const bravo = function bravo (number) {
        return new Promise(function (resolve, reject) {
            const fulfill = function() {
                return resolve(Math.ceil(1000*Math.random()) + number);
            };
            return setTimeout(fulfill, SLEEP_INTERVAL_IN_MILLISECONDS);
        });
    };
    
    const charlie = function charlie (number) {
        return new Promise(function (resolve, reject) {
            return (number%2 == 0) ? reject(number) : resolve(number);
        });
    };
    
    function run() {
        return Promise.resolve(42)
            .then(alpha)
            .then(bravo)
            .then(charlie)
            .then((number) => {
                console.log('success: ' + number)
            })
            .catch((error) => {
                console.log('error: ' + error);
            });
    }
    
    run();
    

    Each function also returns a Promise with asynchronous processing result, that would be resolved/rejected by the immediately following promise.

    I am aware of libraries such as promises-2.01b and asyncio 3.4.3 and I am looking for a Python STL solution. Thus, if I need to import a non-STL library, I prefer using RxPython instead.

  • JP Ventura
    JP Ventura about 7 years
    How would you translate the previous JS example into Python 3.5 using Future?
  • JP Ventura
    JP Ventura about 7 years
    Cool! The only bad part is the telescopic method invocation. As hoping to write something more like a JS promise sequence or reactive observable stream. But this one already solves my problems :-)
  • Vincent
    Vincent about 7 years
    @JPVentura Yes, this line is a bit long but you can split it up by using extra variables. asyncio doesn't have a pipe syntax because it tries to be as close to synchronous programing as possible Also, see my edit about reactive streams.
  • Shlomi Schwartz
    Shlomi Schwartz over 5 years
    @Vincent, could you please have a look here: stackoverflow.com/questions/53466252/…
  • yota
    yota almost 3 years
    interesting ! but are calls to "callback" asynchronous ?
  • fontno
    fontno over 2 years
    Outside of the scared to try new things or just too lazy to learn (which is crazy for devs, but I see it all the time), how can you not love functional style stream pipes...