Skip to content

Commit

Permalink
Sample code for the article on async iterators
Browse files Browse the repository at this point in the history
  • Loading branch information
lpozo committed Jul 15, 2024
1 parent c14b862 commit acb91e9
Show file tree
Hide file tree
Showing 10 changed files with 224 additions and 0 deletions.
3 changes: 3 additions & 0 deletions python-async-iterators/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Asynchronous Iterators and Iterables in Python

This folder provides the code examples for the Real Python tutorial [Asynchronous Iterators and Iterables in Python](https://realpython.com/python-async-iterator/).
17 changes: 17 additions & 0 deletions python-async-iterators/async_comp.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import asyncio


async def async_range(start, end):
for i in range(start, end):
await asyncio.sleep(0.2)
yield i


async def main():
number_list = [i async for i in async_range(0, 5)]
number_dict = {i: str(i) async for i in async_range(0, 5)}
print(number_list)
print(number_dict)


asyncio.run(main())
27 changes: 27 additions & 0 deletions python-async-iterators/async_range_v1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import asyncio


class AsyncRange:
def __init__(self, start, end):
self.start = start
self.end = end

def __aiter__(self):
return self

async def __anext__(self):
if self.start < self.end:
await asyncio.sleep(0.5)
value = self.start
self.start += 1
return value
else:
raise StopAsyncIteration


async def main():
async for i in AsyncRange(0, 5):
print(i)


asyncio.run(main())
19 changes: 19 additions & 0 deletions python-async-iterators/async_range_v2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import asyncio


class AsyncRange:
def __init__(self, start, end):
self.data = range(start, end)

async def __aiter__(self):
for i in self.data:
await asyncio.sleep(0.5)
yield i


async def main():
async for i in AsyncRange(0, 5):
print(i)


asyncio.run(main())
15 changes: 15 additions & 0 deletions python-async-iterators/async_range_v3.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import asyncio


async def async_range(start, end):
for i in range(start, end):
await asyncio.sleep(0.5)
yield i


async def main():
async for i in async_range(0, 5):
print(i)


asyncio.run(main())
23 changes: 23 additions & 0 deletions python-async-iterators/compress.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import asyncio
from pathlib import Path

import aiofiles
from zipstream import AioZipStream


async def stream_generator(files):
async_zipstream = AioZipStream(files)
async for chunk in async_zipstream.stream():
yield chunk


async def main(directory, zip_name="output.zip"):
files = [{"file": file} for file in directory.iterdir()]

async with aiofiles.open(zip_name, mode="wb") as z:
async for chunk in stream_generator(files):
await z.write(chunk)


directory = Path()
asyncio.run(main(directory))
39 changes: 39 additions & 0 deletions python-async-iterators/counter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import asyncio
from random import randint


class AsyncCounterIterator:
def __init__(self, name="", end=5):
self.counter = 0
self.name = name
self.end = end

def __aiter__(self):
return self

async def __anext__(self):
if self.counter >= self.end:
raise StopAsyncIteration
self.counter += 1
await asyncio.sleep(randint(1, 3) / 10)
return self.counter


async def task(iterator):
async for item in iterator:
print(item, f"from iterator {iterator.name}")


async def main():
# This code runs sequentially:
# await task(AsyncCounterIterator("#1"))
# await task(AsyncCounterIterator("#2"))

# This is concurrent:
await asyncio.gather(
task(AsyncCounterIterator("#1")),
task(AsyncCounterIterator("#2")),
)


asyncio.run(main())
22 changes: 22 additions & 0 deletions python-async-iterators/inf_integers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import asyncio


async def async_inf_integers(start=0):
current = start
while True:
yield current
current += 1
await asyncio.sleep(0.5)


async def main(stop=5):
generator = async_inf_integers()
while True:
number = await anext(generator)
# Process the number here...
print(number)
if number == stop - 1:
break


asyncio.run(main(20))
27 changes: 27 additions & 0 deletions python-async-iterators/large_file_iterable.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import asyncio

import aiofiles


class AsyncFileIterable:
def __init__(self, filename, chunk_size=1024):
self.filename = filename
self.chunk_size = chunk_size

async def __aiter__(self):
async with aiofiles.open(self.filename, mode="rb") as file:
while True:
chunk = await file.read(self.chunk_size)
if not chunk:
break
yield chunk


async def main():
async for chunk in AsyncFileIterable("large-file.md"):
# Process the file chunk here...
await asyncio.sleep(0.2)
print(chunk.decode("utf-8"))


asyncio.run(main())
32 changes: 32 additions & 0 deletions python-async-iterators/large_file_iterator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import asyncio

import aiofiles


class AsyncFileIterator:
def __init__(self, filename, chunk_size=1024):
self.filename = filename
self.chunk_size = chunk_size
self.file = None

def __aiter__(self):
return self

async def __anext__(self):
if self.file is None:
self.file = await aiofiles.open(self.filename, mode="rb")
chunk = await self.file.read(self.chunk_size)
if not chunk:
await self.file.close()
raise StopAsyncIteration
return chunk


async def main():
async for chunk in AsyncFileIterator("large-file.md"):
# Process the file chunk here...
await asyncio.sleep(0.2)
print(chunk.decode("utf-8"))


asyncio.run(main())

0 comments on commit acb91e9

Please sign in to comment.