Package: aiopath
📁 Asyncpathlibfor Pythonaiopathis a complete implementation of Python'spathlibthat's compatible withasyncio,trio, and theasync/awaitsyntax.All I/O performed byaiopathis asynchronous andawaitable.Check out📂 app_pathsfor an example of library that usesaiopath, as well as thepycleanscript here.Use caseIf you're writing asynchronous Python code and want to take advantage ofpathlib's conveniences, but don't want to mix blocking andnon-blocking I/O, then you can reach foraiopath.For example, if you're writing an asyncweb scrapingscript, you might want to make several concurrent requests to websites and save the responses to persistent storage:fromasyncioimportrun,gatherfromaiohttpimportClientSessionfromaiopathimportAsyncPathasyncdefsave_page(url:str,name:str):path=AsyncPath(name)ifawaitpath.exists():returnasyncwithClientSession()assession,session.get(url)asresponse:content:bytes=awaitresponse.read()awaitpath.write_bytes(content)asyncdefmain():urls=['https://example.com','https://github.com/alexdelorenzo/aiopath','https://alexdelorenzo.dev','https://dupebot.firstbyte.dev']tasks=(save_page(url,f'{index}.html')forindex,urlinenumerate(urls))awaitgather(*tasks)run(main())If you usedpathlibinstead ofaiopath, tasks accessing the disk would block the event loop, and async tasks accessing the network would suspend until the event loop was unblocked.By usingaiopath, the script can access the network and disk concurrently.Implementationaiopathis a direct reimplementation ofCPython'spathlib.pyand shares some of its code.aiopath's class hierarchydirectly matches the one frompathlib, wherePathinherits fromPurePath,AsyncPathinherits fromAsyncPurePath, and so on.Withaiopath, methods that perform I/O are asynchronous and awaitable, and methods that perform I/O and return iterators inpathlibnow returnasync generators.aiopathgoes one step further, and wrapsos.scandir()andDirEntryto makeAsyncPath.glob()completely async.aiopathis typed with Pythontype annotations, and if using theaiofileback end, it takes advantage oflibaiofor async I/O on Linux.Usageaiopath's API directly matchespathlib, so check out the standard library documentation forPurePathandPath.Running examplesTo run the following examples with top-levelawaitexpressions,launch an asynchronous Python REPLusingpython3 -m asyncioor anIPython shell.You'll also need to installasynctempfilevia PyPI, like sopython3 -m pip install asynctempfile.ReplacingpathlibAll ofpathlib.Path's methods that perform synchronous I/O are reimplemented as asynchronous methods.PurePathmethods are not asynchronous because they don't perform I/O.frompathlibimportPathfromasynctempfileimportNamedTemporaryFilefromaiopathimportAsyncPathasyncwithNamedTemporaryFile()astemp:path=Path(temp.name)apath=AsyncPath(temp.name)# check existence## syncassertpath.exists()## asyncassertawaitapath.exists()# check if file## syncassertpath.is_file()## asyncassertawaitapath.is_file()# touchpath.touch()awaitapath.touch()# PurePath methods are not asyncassertpath.is_absolute()==apath.is_absolute()assertpath.as_uri()==apath.as_uri()# read and write texttext:str='example'awaitapath.write_text(text)assertawaitapath.read_text()==textassertnotpath.exists()assertnotawaitapath.exists()You can convertpathlib.Pathobjects toaiopath.AsyncPathobjects, and vice versa:frompathlibimportPathfromaiopathimportAsyncPathhome:Path=Path.home()ahome:AsyncPath=AsyncPath(home)path:Path=Path(ahome)assertisinstance(home,Path)assertisinstance(ahome,AsyncPath)assertisinstance(path,Path)# AsyncPath and Path objects can point to the same fileassertstr(home)==str(ahome)==str(path)# AsyncPath and Path objects are equivalentasserthome==ahomeAsyncPathis a subclass ofPathandPurePath, and a subclass ofAsyncPurePath:frompathlibimportPath,PurePathfromaiopathimportAsyncPath,AsyncPurePathassertissubclass(AsyncPath,Path)assertissubclass(AsyncPath,PurePath)assertissubclass(AsyncPath,AsyncPurePath)assertissubclass(AsyncPurePath,PurePath)path:AsyncPath=awaitAsyncPath.home()assertisinstance(path,Path)assertisinstance(path,PurePath)assertisinstance(path,AsyncPurePath)Check out the test files in thetestsdirectoryfor more examples of howaiopathcompares topathlib.Opening a fileYou can get an asynchronousfile-like object handleby usingasynchronous context managers.AsyncPath.open()'s async context manager yields ananyio.AsyncFileobject.fromasynctempfileimportNamedTemporaryFilefromaiopathimportAsyncPathtext:str='example'# you can access a file with async context managersasyncwithNamedTemporaryFile()astemp:path=AsyncPath(temp.name)asyncwithpath.open(mode='w')asfile:awaitfile.write(text)asyncwithpath.open(mode='r')asfile:result:str=awaitfile.read()assertresult==text# or you can use the read/write convenience methodsasyncwithNamedTemporaryFile()astemp:path=AsyncPath(temp.name)awaitpath.write_text(text)result:str=awaitpath.read_text()assertresult==textcontent:bytes=text.encode()awaitpath.write_bytes(content)result:bytes=awaitpath.read_bytes()assertresult==contentGlobbingaiopathimplementspathlibglobbingusing async I/O and async generators.fromaiopathimportAsyncPathhome:AsyncPath=awaitAsyncPath.home()asyncforpathinhome.glob('*'):assertisinstance(path,AsyncPath)print(path)downloads:AsyncPath=home/'Downloads'ifawaitdownloads.exists():# this might take a whilepaths:list[AsyncPath]=\[pathasyncforpathindownloads.glob('**/*')]InstallationDependenciesA POSIX compliant OS, or WindowsPython 3.7+requirements.txtPyPI$python3-mpipinstallaiopathPython 3.9 and olderaiopathfor Python 3.9 and older is available on PyPI under versions0.5.xand lower.Python 3.10 and neweraiopathfor Python 3.10 and newer is available on PyPI under versions0.6.xand higher.GitHubDownload a release archive for your Python version fromthe releases page.Then to install, run:$python3-mpipinstall-rrequirements.txt
$python3setup.pyinstallPython 3.9 and olderaiopathfor Python 3.9 and older is developed on thePython-3.9branch.Python 3.10 and neweraiopathfor Python 3.10 and newer is developed on thePython-3.10branch.SupportWant to support this project andother open-source projectslike it?LicenseSeeLICENSE. If you'd like to use this project with a different license, please get in touch.CreditSeeCREDIT.md.