GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — bpo-31861: Add operator.aiter and operator.anext by jab · Pull Request #8895 · python/cpython

bpo-31861: Add operator.aiter and operator.anext #8895

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

Sign up for GitHub

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
jab wants to merge 4 commits into python:master from jab:aiter

Uh oh!

There was an error while loading. Please reload this page.

Closed

bpo-31861: Add operator.aiter and operator.anext #8895

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
4 commits
Select commit Hold shift + click to select a range
44b2a60
bpo-31861: Add operator.aiter and operator.anext
jab Aug 24, 2018
142523b
address comments from first review
jab Sep 7, 2018
3ebce05
Address new review comments + rebase
jab Nov 30, 2020
2f8df99
improve tests
jab Dec 4, 2020
File filter
Filter by extension

Clear filters
Conversations
Failed to load comments.
Loading

Uh oh!

There was an error while loading. Please reload this page.

Jump to
Jump to file
Failed to load files.
Loading

Uh oh!

There was an error while loading. Please reload this page.

Diff view
Diff view

There are no files selected for viewing

70 changes: 62 additions & 8 deletions 70 Lib/operator.py
Show comments
View file
Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,15 @@
This is the pure Python implementation of the module.
"""

__all__ = ['abs', 'add', 'and_', 'attrgetter', 'concat', 'contains', 'countOf',
'delitem', 'eq', 'floordiv', 'ge', 'getitem', 'gt', 'iadd', 'iand',
'iconcat', 'ifloordiv', 'ilshift', 'imatmul', 'imod', 'imul',
'index', 'indexOf', 'inv', 'invert', 'ior', 'ipow', 'irshift',
'is_', 'is_not', 'isub', 'itemgetter', 'itruediv', 'ixor', 'le',
'length_hint', 'lshift', 'lt', 'matmul', 'methodcaller', 'mod',
'mul', 'ne', 'neg', 'not_', 'or_', 'pos', 'pow', 'rshift',
'setitem', 'sub', 'truediv', 'truth', 'xor']
__all__ = [
'abs', 'add', 'aiter', 'anext', 'and_', 'attrgetter', 'concat', 'contains',
'countOf', 'delitem', 'eq', 'floordiv', 'ge', 'getitem', 'gt', 'iadd',
'iand', 'iconcat', 'ifloordiv', 'ilshift', 'imatmul', 'imod', 'imul',
'index', 'indexOf', 'inv', 'invert', 'ior', 'ipow', 'irshift', 'is_',
'is_not', 'isub', 'itemgetter', 'itruediv', 'ixor', 'le', 'length_hint',
'lshift', 'lt', 'matmul', 'methodcaller', 'mod', 'mul', 'ne', 'neg', 'not_',
'or_', 'pos', 'pow', 'rshift', 'setitem', 'sub', 'truediv', 'truth', 'xor',
]

from builtins import abs as _abs

Expand Down Expand Up @@ -404,6 +405,59 @@ def ixor(a, b):
return a


# Asynchronous Iterator Operations ********************************************#


_NOT_PROVIDED = object() # sentinel object to detect when a kwarg was not given


def aiter(obj, sentinel=_NOT_PROVIDED):
"""aiter(async_iterable) -> async_iterator
aiter(async_callable, sentinel) -> async_iterator

Like the iter() builtin but for async iterables and callables.
"""
from collections.abc import AsyncIterable, AsyncIterator
if sentinel is _NOT_PROVIDED:
if not isinstance(obj, AsyncIterable):
raise TypeError(f'aiter expected an AsyncIterable, got {type(obj)}')
ait = type(obj).__aiter__(obj)
if not isinstance(ait, AsyncIterator):
raise TypeError(f'obj.__aiter__() returned non-AsyncIterator: {type(ait)}')
return ait

if not callable(obj):
raise TypeError(f'aiter expected an async callable, got {type(obj)}')

async def ait():
while True:
value = await obj()
if value == sentinel:
break
yield value

return ait()


async def anext(async_iterator, default=_NOT_PROVIDED):
"""anext(async_iterator[, default])

Return the next item from the async iterator.
If default is given and the iterator is exhausted,
it is returned instead of raising StopAsyncIteration.
"""
from collections.abc import AsyncIterator
if not isinstance(async_iterator, AsyncIterator):
raise TypeError(f'anext expected an AsyncIterator, got {type(async_iterator)}')
anxt = type(async_iterator).__anext__
try:
return await anxt(async_iterator)
except StopAsyncIteration:
if default is _NOT_PROVIDED:
raise
return default


try:
from _operator import *
except ImportError:
Expand Down
81 changes: 81 additions & 0 deletions 81 Lib/test/test_asyncgen.py
Show comments
View file
Open in desktop
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import inspect
import operator
import types
import unittest

Expand Down Expand Up @@ -372,6 +373,86 @@ def tearDown(self):
self.loop = None
asyncio.set_event_loop_policy(None)

def test_async_gen_operator_anext(self):
async def gen():
yield 1
yield 2
g = gen()
async def consume():
results = []
results.append(await operator.anext(g))
results.append(await operator.anext(g))
results.append(await operator.anext(g, 'buckle my shoe'))
return results
res = self.loop.run_until_complete(consume())
self.assertEqual(res, [1, 2, 'buckle my shoe'])
with self.assertRaises(StopAsyncIteration):
self.loop.run_until_complete(consume())

def test_async_gen_operator_aiter(self):
async def gen():
yield 1
yield 2
g = gen()
async def consume():
return [i async for i in operator.aiter(g)]
res = self.loop.run_until_complete(consume())
self.assertEqual(res, [1, 2])

def test_async_gen_operator_aiter_class(self):
results = []
loop = self.loop
class Gen:
async def __aiter__(self):
Comment thread
jab marked this conversation as resolved.
Resolved

Uh oh!

There was an error while loading. Please reload this page.

yield 1
await asyncio.sleep(0.01)
yield 2
g = Gen()
async def consume():
ait = operator.aiter(g)
while True:
try:
results.append(await operator.anext(ait))
except StopAsyncIteration:
break
self.loop.run_until_complete(consume())
self.assertEqual(results, [1, 2])

def test_async_gen_operator_aiter_2_arg(self):
async def gen():
yield 1
yield 2
yield None
g = gen()
async def foo():
return await operator.anext(g)
async def consume():
return [i async for i in operator.aiter(foo, None)]
res = self.loop.run_until_complete(consume())
self.assertEqual(res, [1, 2])

def test_operator_anext_bad_args(self):
self._test_bad_args(operator.anext)

def test_operator_aiter_bad_args(self):
self._test_bad_args(operator.aiter)

def _test_bad_args(self, afn):
async def gen():
yield 1
async def call_with_no_args():
await afn()
async def call_with_3_args():
await afn(gen(), 1, 2)
async def call_with_bad_args():
await afn(1, gen())
with self.assertRaises(TypeError):
self.loop.run_until_complete(call_with_no_args())
with self.assertRaises(TypeError):
self.loop.run_until_complete(call_with_3_args())
with self.assertRaises(TypeError):
self.loop.run_until_complete(call_with_bad_args())

async def to_list(self, gen):
res = []
async for i in gen:
Expand Down
1 change: 1 addition & 0 deletions 1 Misc/NEWS.d/next/Library/2018-08-24-01-08-09.bpo-31861.-q9RKJ.rst
Show comments
View file
Open in desktop
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add the operator.aiter and operator.anext functions. Patch by Josh Bronson.
Add this suggestion to a batch that can be applied as a single commit. This suggestion is invalid because no changes were made to the code. Suggestions cannot be applied while the pull request is closed. Suggestions cannot be applied while viewing a subset of changes. Only one suggestion per line can be applied in a batch. Add this suggestion to a batch that can be applied as a single commit. Applying suggestions on deleted lines is not supported. You must change the existing code in this line in order to create a valid suggestion. Outdated suggestions cannot be applied. This suggestion has been applied or marked resolved. Suggestions cannot be applied from pending reviews. Suggestions cannot be applied on multi-line comments. Suggestions cannot be applied while the pull request is queued to merge. Suggestion cannot be applied right now. Please check back later.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.