📁 Async pathlib for Python
Project description
📁 Async pathlib for Python
aiopath
is a complete implementation of Python's pathlib
that is compatible with asyncio
and Python's async/await
syntax. All I/O performed by aiopath
is asynchronous and awaitable.
aiopath
takes advantage of Python type annotations, and it also takes advantage of libaio
on Linux.
Use case
If you're writing asynchronous code and want to take advantage of pathlib
's conveniences, but don't want to mix blocking and non-blocking I/O, then you can reach for aiopath
.
As an example, if you're writing an asynchronous scraper, you might want to make several concurrent requests to websites, and then write the results of those requests to secondary storage:
from typing import List
from asyncio import run, gather, Future
from aiohttp import ClientSession
from aiopath import AsyncPath
async def save_page(url: str, name: str):
async with ClientSession() as session:
response = await session.get(url)
content: str = await response.text()
path = AsyncPath(name)
if not await path.exists():
await path.write_text(content)
urls: List[str] = [
'https://example.com',
'https://github.com/alexdelorenzo/aiopath',
'https://alexdelorenzo.dev'
]
scrapers = (save_page(url, f"{index}.html") for index, url in enumerate(urls))
tasks = gather(*scrapers)
run(main())
If you used pathlib
instead of aiopath
in the example above, tasks would block upon writing to the disk, and tasks that make network connections would be forced to pause while other tasks write to the disk.
By using aiopath
, all I/O is non-blocking, and your script can simultaneously write to the disk and perform network operations at once.
Usage
aiopath.Path
has the same API as pathlib.Path
, and aiopath.AsyncPurePath
has the same API as pathlib.PurePath
.
With aiopath
, methods that perform I/O are asynchronous and awaitable, and methods that are overriden from pathlib
that returned iterators now return async generators.
To run the following examples with top-level await
expressions, launch an asynchronous Python REPL using python3 -m asyncio
.
Basic
All of pathlib.Path
's methods that perform synchronous I/O are reimplemented as asynchronous methods. PurePath
methods are not asynchronous because they don't perform I/O.
import tempfile
from pathlib import Path
from aiopath import AsyncPath
with tempfile.NamedTemporaryFile() as temp:
path = Path(temp.name)
apath = AsyncPath(temp.name)
# check existence
## sync
assert path.exists()
## async
assert await apath.exists()
# check if file
## sync
assert path.is_file()
## async
assert await apath.is_file()
# touch
path.touch()
await apath.touch()
# read and write text
text = "example"
await apath.write_text(text)
assert text == await apath.read_text()
assert not path.exists()
assert not await apath.exists()
You can convert pathlib.Path
objects to aiopath.AsyncPath
objects, and vice versa:
from pathlib import Path
from aiopath import AsyncPath
home: Path = Path.home()
ahome: AsyncPath = AsyncPath(home)
path: Path = Path(ahome)
assert isinstance(home, Path)
assert isinstance(ahome, AsyncPath)
assert isinstance(path, Path)
assert str(home) == str(ahome) == str(path)
Opening a file
You can get an asynchronous file-like object handle by using asynchronous context managers.
import tempfile
from aiopath import AsyncPath
text: str = 'example'
with tempfile.NamedTemporaryFile() as temp:
apath = AsyncPath(temp.name)
async with apath.open(mode='w') as afile:
await afile.write(text)
result: str = await apath.read_text()
assert result == text
Globbing
aiopath
implements pathlib
globbing using async I/O and async generators.
from typing import List
from aiopath import AsyncPath
home: AsyncPath = await AsyncPath.home()
async for path in home.glob('*'):
assert isinstance(path, AsyncPath)
print(path)
downloads: AsyncPath = home / 'Downloads'
if await downloads.exists():
# this might take a while
paths: List[AsyncPath] = \
[path async for path in downloads.glob('**/*')]
Installation
Dependencies
- A POSIX compliant OS, or Windows
- Python 3.7+
requirements.txt
Linux dependencies
If you're using a 4.18 or newer kernel and have libaio
installed, aiopath
will use it via aiofile
. You can install libaio
on Debian/Ubuntu like so:
$ sudo apt install libaio1
PyPI
$ python3 -m pip install aiopath
GitHub
$ python3 -m pip install -r requirements.txt
$ python3 setup.py install
Support
Want to support this project and other open-source projects like it?
License
See LICENSE
. If you'd like to use this project with a different license, please get in touch.
Credit
See CREDIT.md
.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Hashes for aiopath-0.4.3-py2.py3-none-any.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 7c878745d1ea649b9ea36ec93672372720c05a34a8786202f5f5124335fc630e |
|
MD5 | 21e0eb28e2cef0cdf3c85ff095c8d5ff |
|
BLAKE2b-256 | cd61a0563f77d1d773ac8b5ae93c26d6bc80036bd1ae016ff996c6d6f10f2fd8 |