Tinche / aiofiles

File support for asyncio
Apache License 2.0
2.66k stars 150 forks source link

Detect if object is plain file or async file #92

Open ronf opened 3 years ago

ronf commented 3 years ago

Hello,

I'm writing an async library which accepts file object and tries to automatically detect whether they are plain file objects or objects opened with aiofiles, automatically adjusting the I/O calls to take into account whether to do await or not when accessing them. This was working fine with aiofiles version 0.4.0, but I recently attempted to upgrade to aiofiles 0.6.0 and it's no longer working.

I was relying on the function asyncio.iscoroutinefunction() of the file object's read() method as a means to do this. With aiofiles 0.4.0, this worked fine, and this call should properly detect both the old-style (@asyncio.coroutine) and new-style (async def) functions. However, in aiofiles 0.6.0, calling asyncio.iscoroutinefunction() on the wrapper's read() function returns False.

Tracing through the various bits of wrapper code, it appears that it is using the types.coroutine decorator on the function being wrapped, but somehow what that produces isn't recognized as a coroutine function by either asyncio.iscoroutinefunction() or inspect.iscoroutinefunction().

Any thoughts on how to get this to work with more recent versions of aiofiles?

Digging a bit deeper, the wrapped function returned has co_flags of 0x13f and the 0x20 bit is CO_GENERATOR, so it looks like I can work around this by testing for inspect.isgeneratorfunction(), which would be True for the aiofiles 0.6.0 read() wrapper but False for the standard OS file object read() function. However, that seems fragile. Any suggestions are welcome!