On 5/8/19 11:05 AM, Zac Medico wrote: > On 5/7/19 1:01 PM, Zac Medico wrote: >> On 5/7/19 7:55 AM, Alec Warner wrote: >> >>> Also curious why we are not implementing enter and exit so we can avoid >>> unbalanced pairs by using context managers. >>> >>> e.g. in match(), we could likely write: >>> >>> with self.dbapi.lock(): >>> # try to match >>> update_pkgindex = self._populate_local() >>> if update_pkgindex: >>> self._pkgindex_write(update_pkgindex) >>> >>> If the block raises an exception, __exit__ is still called, so we can >>> eliminate the finally: blocks and replace them with a careful __exit__ >>> implementation? >>> >>> -A >> >> Yeah, the reference counted lock class could have a method that returns >> a context manager which increments/decrements the lock count. The >> context manager can be implemented with the contextlib.contextmanager >> decorator like this: >> >> @contextlib.contextmanager >> def contextmanager(self): >> self.lock() >> try: >> yield self >> finally: >> self.unlock() >> > > Since we really don't want asynchronous code to block waiting for a > lock, we really should use a (python3.5+ only) asynchronous context manager: > > https://www.python.org/dev/peps/pep-0492/#asynchronous-context-managers-and-async-with > > Given that python2.7 is scheduled for retirement in 2020 > (https://pythonclock.org/), maybe it's time to drop support for > python3.4 and earlier.
Adapting the sample code provided in PEP 492, we can do something like this for compatibility with older versions of python: from portage.util.futures.compat_coroutine @compat_coroutine.coroutine def async_with(mgr, async_func): aexit = type(mgr).__aexit__ aenter = type(mgr).__aenter__(mgr) aenter_result = (yield aenter) try: return_value = (yield async_func(aenter_result)) except: if not (yield aexit(mgr, *sys.exc_info()): raise else: yield aexit(mgr, None, None, None) compat_coroutine.coroutine_return(return_value) -- Thanks, Zac
signature.asc
Description: OpenPGP digital signature