Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Coroutine in python between 3.4 and 3.5, How can I keep backwords compatibility?

I'm on developing python chatting bot framework with asyncio. But I watch PEP-492 and there is new syntax, async/await and finally it accepted.

I like async/await syntax and I want to use it. but I worry about 3.4 backwords compatibility.

If I use new syntax in my code, someone can use it in 3.4?

For example, I write some code like this,

import asyncio

class ChatBot:
    def __init__(self, loop):
        self.loop = loop

    async def connect(self):
        self.reader, self.writer = await asyncio.open_connect(HOST, PORT, loop=self.loop)

    async def read():
        return await self.reader.read()

    async def run(self):
        running = True
        while running:
            try:
                await self.connect()
                line = await self.read()
                if not line:
                    continue
                await self.parse(line)
            except BotInternalError as e:
                if e.stop:
                    running = False
                    break
            except:
                pass

    async def parse(self, msg):
        if msg.startswith('PING'):
            self.pong()
        elif msg.startswith('ERROR'):
            self.error()
        else:
            await self.some_work(msg)

    async def some_work(self, msg):
        # some looooooooong works
        self.send(msg)

    def send(self, msg):
        self.writer.write(msg)

Than, I can use it with this source in py35

loop = asyncio.get_event_loop()  # I don't know it really needed in py35.
bot = ChatBot(loop)
asyncio.run_until_complete(bot.run())

But, py34 don't have await syntax. If I uploaded above source at PyPI without version constraint and someone installed it on py34, It'll work fine? How can I keep it?

like image 803
item4 Avatar asked May 12 '15 12:05

item4


People also ask

Are Python 3 versions backwards compatible?

Python 3 is not backwards compatible with Python 2, so your code may need to be adapted. Please start migrating your existing your existing Python 2 code to Python 3.

Does Python support backwards compatibility?

The Python language does not generally provide backward compatibility.

What is async and await in Python?

The async keyword is used to create a Python coroutine. The await keyword suspends execution of a coroutine until it completes and returns the result data. The await keywords only works within an async function.

What is async for in Python?

asyncio is used as a foundation for multiple Python asynchronous frameworks that provide high-performance network and web-servers, database connection libraries, distributed task queues, etc. asyncio is often a perfect fit for IO-bound and high-level structured network code.


1 Answers

If you need to support Python 3.4 in your code, you'll need to use the old @asyncio.coroutine/yield from style syntax. There's no way to support the async/await syntax without running 3.5; you'll get a SyntaxError at compilation time on 3.4 or lower.

The only thing that takes advantage of the new features you can do in a backwards-compatible way is add the various __a*__ methods to your classes where appropriate (__aiter__, __aenter__, __aexit__, etc.), using the yield from coroutine syntax. That way, your objects can support async with/async for statements, so that users of your library running Python 3.5 could take advantage of the new features.

For example, this class can be used with async with, but won't break when run on Python 3.4:

import asyncio

class Test:
    def __enter__(self):
        return self

    def __exit__(self, *args):
        print("arg")

    @asyncio.coroutine
    def __aenter__(self):
        yield from self.init_state()
        return self

    @asyncio.coroutine
    def init_state(self):
        yield from asyncio.sleep(2) # Pretend this is real initialization

    @asyncio.coroutine
    def __aexit__(self, *args):
        return self.__exit__(self, *args)

On Python 3.5:

import asyncio
from test import Test

async def main():
    print("entering with")
    async with Test() as t:
        print("in here")

loop = asyncio.get_event_loop()
loop.run_until_complete(main())

On Python 3.4

import asyncio
from test import Test

@asyncio.coroutine
def oldmain():
    print("entering with")
    with Test() as t:
        yield from t.init_state()
        print("in here")

loop = asyncio.get_event_loop()
loop.run_until_complete(oldmain())

This probably isn't useful if you're writing an application that uses asyncio, but if you're developing a library or framework intended to be used by other developers, it's worth doing.

like image 51
dano Avatar answered Sep 19 '22 15:09

dano