In general I assume disk I/O is slow enough (even on SSD) to care about blocking the event loop and delegating the calls to a thread. But I've been wrong about this before. For example, a call to stat is technically blocking, but the overhead of delegating it to a thread is actually more expensive (on my Framework 13) and blocks the loop longer than just doing the call outright in the main thread.
At some places where there were no better alternatives, framework utilizes sync functions under the hood, such as some databases.
Overall there are also places where functions are async running in sync bodies, but they're not running on main thread.
asyncio.to_thread[0] as a quick workaround, just keep track of your thread count. Obviously frameworks and libraries with asyncio support should be chosen whenever possible.
> Overall there are also places where functions are async running in sync bodies, but they're not running on main thread.
That would be a design mistake, as functions have colors[1] with async/await. That's currently my biggest gripe in the python ecosystem, apart from modules maintaining their own hidden state.
[0]: https://docs.python.org/3/library/asyncio-task.html#asyncio....
[1]: https://journal.stuffwithstuff.com/2015/02/01/what-color-is-...