2016-06-25 4 views
10

Per PEP-492 Я пытаюсь реализовать асинхронный итератор, чтобы я мог сделать, например,Реализация асинхронного итератора

async for foo in bar: 
    ... 

Вот тривиальный пример, похожий на тот, в документации, с очень простым тестом конкретизации и асинхронной итерация:

import pytest 

class TestImplementation: 
    def __aiter__(self): 
     return self 
    async def __anext__(self): 
     raise StopAsyncIteration 


@pytest.mark.asyncio # note use of pytest-asyncio marker 
async def test_async_for(): 
    async for _ in TestImplementation(): 
     pass 

Однако, когда я исполняю свой набор тестов, я вижу :

=================================== FAILURES =================================== 
________________________________ test_async_for ________________________________ 

    @pytest.mark.asyncio 
    async def test_async_for(): 
>  async for _ in TestImplementation(): 
E  TypeError: 'async for' received an invalid object from __aiter__: TestImplementation 

...: TypeError 
===================== 1 failed, ... passed in 2.89 seconds ====================== 

Почему мой TestImplementation являются недействительными? Насколько я могу сказать, что это соответствует протоколу:

  1. Объект должен реализовать метод __aiter__ ... возвращая асинхронный объект итератора.
  2. Асинхронный объект итератора должен реализовать метод __anext__ ... возвращающий ожидаемый.
  3. Чтобы остановить итерацию __anext__, необходимо поднять StopAsyncIteration исключение.

Это неудача с последней выпущенными версиями Python (3.5.1), py.test (2.9.2) и pytest-asyncio (0.4.1).

+13

После почти 3 лет вы наконец [задали вопрос] (http://stackoverflow.com/users/3001761/jonrsharpe?tab=questions). Kudos –

+6

@BhargavRao Я чувствовал себя как 2076: 1 был оправа; o) – jonrsharpe

+0

Работает для меня с pytest 2.9.2. Какую версию ты используешь? –

ответ

21

Если вы читали a little further down the documentation он упоминает, что (курсив мой):

PEP 492 был принят в CPython 3.5.0 с __aiter__ определяются как метод , который должен был вернуться awaitable разрешающего асинхронный итератор.

В 3.5.2 (поскольку PEP 492 принимается на временной основе) протокол __aiter__ был обновлен, чтобы возвращать асинхронные итераторы напрямую.

Поэтому для версий до 3.5.2 (выпущено 2016/6/27) документация немного не в порядке, как написать рабочий асинхронный итератор. Фиксированная версия для 3.5.0 и 3.5.1 выглядит следующим образом:

class TestImplementation: 
    async def __aiter__(self): 
    #^note 
     return self 
    async def __anext__(self): 
     raise StopAsyncIteration 

Это было введено на закрытие bug #27243 и немного яснее в data model documentation, который также предполагает способ написания обратной совместимости кода.

+10

Через 3 года вы должны были ответить на свой вопрос :) –

+2

@PadraicCunningham некоторые привычки трудно сломать ... – jonrsharpe

+5

@Padraic [В следующий раз jon задает вопрос, держитесь подальше от него] (https: // www. youtube.com/watch?v=4F4qzPbcFiA);) –

Смежные вопросы