I maintain a simple abstract middleware caching library for python and it was a trick issue how to support combinations of sync/async app code and sync/async actual caching backends with async introduction in Python. In the end the answer was an automatic runtime AST transformation for all cases. Ugh. The same approach I use in validation library to parse requests for different web frameworks. But it's a specific case and could not be generalized.
It's the opposite of fun situation.