17db96d56Sopenharmony_ci:mod:`!contextlib` --- Utilities for :keyword:`!with`\ -statement contexts
27db96d56Sopenharmony_ci==========================================================================
37db96d56Sopenharmony_ci
47db96d56Sopenharmony_ci.. module:: contextlib
57db96d56Sopenharmony_ci   :synopsis: Utilities for with-statement contexts.
67db96d56Sopenharmony_ci
77db96d56Sopenharmony_ci**Source code:** :source:`Lib/contextlib.py`
87db96d56Sopenharmony_ci
97db96d56Sopenharmony_ci--------------
107db96d56Sopenharmony_ci
117db96d56Sopenharmony_ciThis module provides utilities for common tasks involving the :keyword:`with`
127db96d56Sopenharmony_cistatement. For more information see also :ref:`typecontextmanager` and
137db96d56Sopenharmony_ci:ref:`context-managers`.
147db96d56Sopenharmony_ci
157db96d56Sopenharmony_ci
167db96d56Sopenharmony_ciUtilities
177db96d56Sopenharmony_ci---------
187db96d56Sopenharmony_ci
197db96d56Sopenharmony_ciFunctions and classes provided:
207db96d56Sopenharmony_ci
217db96d56Sopenharmony_ci.. class:: AbstractContextManager
227db96d56Sopenharmony_ci
237db96d56Sopenharmony_ci   An :term:`abstract base class` for classes that implement
247db96d56Sopenharmony_ci   :meth:`object.__enter__` and :meth:`object.__exit__`. A default
257db96d56Sopenharmony_ci   implementation for :meth:`object.__enter__` is provided which returns
267db96d56Sopenharmony_ci   ``self`` while :meth:`object.__exit__` is an abstract method which by default
277db96d56Sopenharmony_ci   returns ``None``. See also the definition of :ref:`typecontextmanager`.
287db96d56Sopenharmony_ci
297db96d56Sopenharmony_ci   .. versionadded:: 3.6
307db96d56Sopenharmony_ci
317db96d56Sopenharmony_ci
327db96d56Sopenharmony_ci.. class:: AbstractAsyncContextManager
337db96d56Sopenharmony_ci
347db96d56Sopenharmony_ci   An :term:`abstract base class` for classes that implement
357db96d56Sopenharmony_ci   :meth:`object.__aenter__` and :meth:`object.__aexit__`. A default
367db96d56Sopenharmony_ci   implementation for :meth:`object.__aenter__` is provided which returns
377db96d56Sopenharmony_ci   ``self`` while :meth:`object.__aexit__` is an abstract method which by default
387db96d56Sopenharmony_ci   returns ``None``. See also the definition of
397db96d56Sopenharmony_ci   :ref:`async-context-managers`.
407db96d56Sopenharmony_ci
417db96d56Sopenharmony_ci   .. versionadded:: 3.7
427db96d56Sopenharmony_ci
437db96d56Sopenharmony_ci
447db96d56Sopenharmony_ci.. decorator:: contextmanager
457db96d56Sopenharmony_ci
467db96d56Sopenharmony_ci   This function is a :term:`decorator` that can be used to define a factory
477db96d56Sopenharmony_ci   function for :keyword:`with` statement context managers, without needing to
487db96d56Sopenharmony_ci   create a class or separate :meth:`__enter__` and :meth:`__exit__` methods.
497db96d56Sopenharmony_ci
507db96d56Sopenharmony_ci   While many objects natively support use in with statements, sometimes a
517db96d56Sopenharmony_ci   resource needs to be managed that isn't a context manager in its own right,
527db96d56Sopenharmony_ci   and doesn't implement a ``close()`` method for use with ``contextlib.closing``
537db96d56Sopenharmony_ci
547db96d56Sopenharmony_ci   An abstract example would be the following to ensure correct resource
557db96d56Sopenharmony_ci   management::
567db96d56Sopenharmony_ci
577db96d56Sopenharmony_ci      from contextlib import contextmanager
587db96d56Sopenharmony_ci
597db96d56Sopenharmony_ci      @contextmanager
607db96d56Sopenharmony_ci      def managed_resource(*args, **kwds):
617db96d56Sopenharmony_ci          # Code to acquire resource, e.g.:
627db96d56Sopenharmony_ci          resource = acquire_resource(*args, **kwds)
637db96d56Sopenharmony_ci          try:
647db96d56Sopenharmony_ci              yield resource
657db96d56Sopenharmony_ci          finally:
667db96d56Sopenharmony_ci              # Code to release resource, e.g.:
677db96d56Sopenharmony_ci              release_resource(resource)
687db96d56Sopenharmony_ci
697db96d56Sopenharmony_ci   The function can then be used like this::
707db96d56Sopenharmony_ci
717db96d56Sopenharmony_ci      >>> with managed_resource(timeout=3600) as resource:
727db96d56Sopenharmony_ci      ...     # Resource is released at the end of this block,
737db96d56Sopenharmony_ci      ...     # even if code in the block raises an exception
747db96d56Sopenharmony_ci
757db96d56Sopenharmony_ci   The function being decorated must return a :term:`generator`-iterator when
767db96d56Sopenharmony_ci   called. This iterator must yield exactly one value, which will be bound to
777db96d56Sopenharmony_ci   the targets in the :keyword:`with` statement's :keyword:`!as` clause, if any.
787db96d56Sopenharmony_ci
797db96d56Sopenharmony_ci   At the point where the generator yields, the block nested in the :keyword:`with`
807db96d56Sopenharmony_ci   statement is executed.  The generator is then resumed after the block is exited.
817db96d56Sopenharmony_ci   If an unhandled exception occurs in the block, it is reraised inside the
827db96d56Sopenharmony_ci   generator at the point where the yield occurred.  Thus, you can use a
837db96d56Sopenharmony_ci   :keyword:`try`...\ :keyword:`except`...\ :keyword:`finally` statement to trap
847db96d56Sopenharmony_ci   the error (if any), or ensure that some cleanup takes place. If an exception is
857db96d56Sopenharmony_ci   trapped merely in order to log it or to perform some action (rather than to
867db96d56Sopenharmony_ci   suppress it entirely), the generator must reraise that exception. Otherwise the
877db96d56Sopenharmony_ci   generator context manager will indicate to the :keyword:`!with` statement that
887db96d56Sopenharmony_ci   the exception has been handled, and execution will resume with the statement
897db96d56Sopenharmony_ci   immediately following the :keyword:`!with` statement.
907db96d56Sopenharmony_ci
917db96d56Sopenharmony_ci   :func:`contextmanager` uses :class:`ContextDecorator` so the context managers
927db96d56Sopenharmony_ci   it creates can be used as decorators as well as in :keyword:`with` statements.
937db96d56Sopenharmony_ci   When used as a decorator, a new generator instance is implicitly created on
947db96d56Sopenharmony_ci   each function call (this allows the otherwise "one-shot" context managers
957db96d56Sopenharmony_ci   created by :func:`contextmanager` to meet the requirement that context
967db96d56Sopenharmony_ci   managers support multiple invocations in order to be used as decorators).
977db96d56Sopenharmony_ci
987db96d56Sopenharmony_ci   .. versionchanged:: 3.2
997db96d56Sopenharmony_ci      Use of :class:`ContextDecorator`.
1007db96d56Sopenharmony_ci
1017db96d56Sopenharmony_ci
1027db96d56Sopenharmony_ci.. decorator:: asynccontextmanager
1037db96d56Sopenharmony_ci
1047db96d56Sopenharmony_ci   Similar to :func:`~contextlib.contextmanager`, but creates an
1057db96d56Sopenharmony_ci   :ref:`asynchronous context manager <async-context-managers>`.
1067db96d56Sopenharmony_ci
1077db96d56Sopenharmony_ci   This function is a :term:`decorator` that can be used to define a factory
1087db96d56Sopenharmony_ci   function for :keyword:`async with` statement asynchronous context managers,
1097db96d56Sopenharmony_ci   without needing to create a class or separate :meth:`__aenter__` and
1107db96d56Sopenharmony_ci   :meth:`__aexit__` methods. It must be applied to an :term:`asynchronous
1117db96d56Sopenharmony_ci   generator` function.
1127db96d56Sopenharmony_ci
1137db96d56Sopenharmony_ci   A simple example::
1147db96d56Sopenharmony_ci
1157db96d56Sopenharmony_ci      from contextlib import asynccontextmanager
1167db96d56Sopenharmony_ci
1177db96d56Sopenharmony_ci      @asynccontextmanager
1187db96d56Sopenharmony_ci      async def get_connection():
1197db96d56Sopenharmony_ci          conn = await acquire_db_connection()
1207db96d56Sopenharmony_ci          try:
1217db96d56Sopenharmony_ci              yield conn
1227db96d56Sopenharmony_ci          finally:
1237db96d56Sopenharmony_ci              await release_db_connection(conn)
1247db96d56Sopenharmony_ci
1257db96d56Sopenharmony_ci      async def get_all_users():
1267db96d56Sopenharmony_ci          async with get_connection() as conn:
1277db96d56Sopenharmony_ci              return conn.query('SELECT ...')
1287db96d56Sopenharmony_ci
1297db96d56Sopenharmony_ci   .. versionadded:: 3.7
1307db96d56Sopenharmony_ci
1317db96d56Sopenharmony_ci   Context managers defined with :func:`asynccontextmanager` can be used
1327db96d56Sopenharmony_ci   either as decorators or with :keyword:`async with` statements::
1337db96d56Sopenharmony_ci
1347db96d56Sopenharmony_ci     import time
1357db96d56Sopenharmony_ci     from contextlib import asynccontextmanager
1367db96d56Sopenharmony_ci
1377db96d56Sopenharmony_ci     @asynccontextmanager
1387db96d56Sopenharmony_ci     async def timeit():
1397db96d56Sopenharmony_ci         now = time.monotonic()
1407db96d56Sopenharmony_ci         try:
1417db96d56Sopenharmony_ci             yield
1427db96d56Sopenharmony_ci         finally:
1437db96d56Sopenharmony_ci             print(f'it took {time.monotonic() - now}s to run')
1447db96d56Sopenharmony_ci
1457db96d56Sopenharmony_ci     @timeit()
1467db96d56Sopenharmony_ci     async def main():
1477db96d56Sopenharmony_ci         # ... async code ...
1487db96d56Sopenharmony_ci
1497db96d56Sopenharmony_ci   When used as a decorator, a new generator instance is implicitly created on
1507db96d56Sopenharmony_ci   each function call. This allows the otherwise "one-shot" context managers
1517db96d56Sopenharmony_ci   created by :func:`asynccontextmanager` to meet the requirement that context
1527db96d56Sopenharmony_ci   managers support multiple invocations in order to be used as decorators.
1537db96d56Sopenharmony_ci
1547db96d56Sopenharmony_ci  .. versionchanged:: 3.10
1557db96d56Sopenharmony_ci     Async context managers created with :func:`asynccontextmanager` can
1567db96d56Sopenharmony_ci     be used as decorators.
1577db96d56Sopenharmony_ci
1587db96d56Sopenharmony_ci
1597db96d56Sopenharmony_ci.. function:: closing(thing)
1607db96d56Sopenharmony_ci
1617db96d56Sopenharmony_ci   Return a context manager that closes *thing* upon completion of the block.  This
1627db96d56Sopenharmony_ci   is basically equivalent to::
1637db96d56Sopenharmony_ci
1647db96d56Sopenharmony_ci      from contextlib import contextmanager
1657db96d56Sopenharmony_ci
1667db96d56Sopenharmony_ci      @contextmanager
1677db96d56Sopenharmony_ci      def closing(thing):
1687db96d56Sopenharmony_ci          try:
1697db96d56Sopenharmony_ci              yield thing
1707db96d56Sopenharmony_ci          finally:
1717db96d56Sopenharmony_ci              thing.close()
1727db96d56Sopenharmony_ci
1737db96d56Sopenharmony_ci   And lets you write code like this::
1747db96d56Sopenharmony_ci
1757db96d56Sopenharmony_ci      from contextlib import closing
1767db96d56Sopenharmony_ci      from urllib.request import urlopen
1777db96d56Sopenharmony_ci
1787db96d56Sopenharmony_ci      with closing(urlopen('https://www.python.org')) as page:
1797db96d56Sopenharmony_ci          for line in page:
1807db96d56Sopenharmony_ci              print(line)
1817db96d56Sopenharmony_ci
1827db96d56Sopenharmony_ci   without needing to explicitly close ``page``.  Even if an error occurs,
1837db96d56Sopenharmony_ci   ``page.close()`` will be called when the :keyword:`with` block is exited.
1847db96d56Sopenharmony_ci
1857db96d56Sopenharmony_ci
1867db96d56Sopenharmony_ci.. function:: aclosing(thing)
1877db96d56Sopenharmony_ci
1887db96d56Sopenharmony_ci   Return an async context manager that calls the ``aclose()`` method of *thing*
1897db96d56Sopenharmony_ci   upon completion of the block.  This is basically equivalent to::
1907db96d56Sopenharmony_ci
1917db96d56Sopenharmony_ci      from contextlib import asynccontextmanager
1927db96d56Sopenharmony_ci
1937db96d56Sopenharmony_ci      @asynccontextmanager
1947db96d56Sopenharmony_ci      async def aclosing(thing):
1957db96d56Sopenharmony_ci          try:
1967db96d56Sopenharmony_ci              yield thing
1977db96d56Sopenharmony_ci          finally:
1987db96d56Sopenharmony_ci              await thing.aclose()
1997db96d56Sopenharmony_ci
2007db96d56Sopenharmony_ci   Significantly, ``aclosing()`` supports deterministic cleanup of async
2017db96d56Sopenharmony_ci   generators when they happen to exit early by :keyword:`break` or an
2027db96d56Sopenharmony_ci   exception.  For example::
2037db96d56Sopenharmony_ci
2047db96d56Sopenharmony_ci      from contextlib import aclosing
2057db96d56Sopenharmony_ci
2067db96d56Sopenharmony_ci      async with aclosing(my_generator()) as values:
2077db96d56Sopenharmony_ci          async for value in values:
2087db96d56Sopenharmony_ci              if value == 42:
2097db96d56Sopenharmony_ci                  break
2107db96d56Sopenharmony_ci
2117db96d56Sopenharmony_ci   This pattern ensures that the generator's async exit code is executed in
2127db96d56Sopenharmony_ci   the same context as its iterations (so that exceptions and context
2137db96d56Sopenharmony_ci   variables work as expected, and the exit code isn't run after the
2147db96d56Sopenharmony_ci   lifetime of some task it depends on).
2157db96d56Sopenharmony_ci
2167db96d56Sopenharmony_ci   .. versionadded:: 3.10
2177db96d56Sopenharmony_ci
2187db96d56Sopenharmony_ci
2197db96d56Sopenharmony_ci.. _simplifying-support-for-single-optional-context-managers:
2207db96d56Sopenharmony_ci
2217db96d56Sopenharmony_ci.. function:: nullcontext(enter_result=None)
2227db96d56Sopenharmony_ci
2237db96d56Sopenharmony_ci   Return a context manager that returns *enter_result* from ``__enter__``, but
2247db96d56Sopenharmony_ci   otherwise does nothing. It is intended to be used as a stand-in for an
2257db96d56Sopenharmony_ci   optional context manager, for example::
2267db96d56Sopenharmony_ci
2277db96d56Sopenharmony_ci      def myfunction(arg, ignore_exceptions=False):
2287db96d56Sopenharmony_ci          if ignore_exceptions:
2297db96d56Sopenharmony_ci              # Use suppress to ignore all exceptions.
2307db96d56Sopenharmony_ci              cm = contextlib.suppress(Exception)
2317db96d56Sopenharmony_ci          else:
2327db96d56Sopenharmony_ci              # Do not ignore any exceptions, cm has no effect.
2337db96d56Sopenharmony_ci              cm = contextlib.nullcontext()
2347db96d56Sopenharmony_ci          with cm:
2357db96d56Sopenharmony_ci              # Do something
2367db96d56Sopenharmony_ci
2377db96d56Sopenharmony_ci   An example using *enter_result*::
2387db96d56Sopenharmony_ci
2397db96d56Sopenharmony_ci      def process_file(file_or_path):
2407db96d56Sopenharmony_ci          if isinstance(file_or_path, str):
2417db96d56Sopenharmony_ci              # If string, open file
2427db96d56Sopenharmony_ci              cm = open(file_or_path)
2437db96d56Sopenharmony_ci          else:
2447db96d56Sopenharmony_ci              # Caller is responsible for closing file
2457db96d56Sopenharmony_ci              cm = nullcontext(file_or_path)
2467db96d56Sopenharmony_ci
2477db96d56Sopenharmony_ci          with cm as file:
2487db96d56Sopenharmony_ci              # Perform processing on the file
2497db96d56Sopenharmony_ci
2507db96d56Sopenharmony_ci   It can also be used as a stand-in for
2517db96d56Sopenharmony_ci   :ref:`asynchronous context managers <async-context-managers>`::
2527db96d56Sopenharmony_ci
2537db96d56Sopenharmony_ci       async def send_http(session=None):
2547db96d56Sopenharmony_ci           if not session:
2557db96d56Sopenharmony_ci               # If no http session, create it with aiohttp
2567db96d56Sopenharmony_ci               cm = aiohttp.ClientSession()
2577db96d56Sopenharmony_ci           else:
2587db96d56Sopenharmony_ci               # Caller is responsible for closing the session
2597db96d56Sopenharmony_ci               cm = nullcontext(session)
2607db96d56Sopenharmony_ci
2617db96d56Sopenharmony_ci           async with cm as session:
2627db96d56Sopenharmony_ci               # Send http requests with session
2637db96d56Sopenharmony_ci
2647db96d56Sopenharmony_ci   .. versionadded:: 3.7
2657db96d56Sopenharmony_ci
2667db96d56Sopenharmony_ci   .. versionchanged:: 3.10
2677db96d56Sopenharmony_ci      :term:`asynchronous context manager` support was added.
2687db96d56Sopenharmony_ci
2697db96d56Sopenharmony_ci
2707db96d56Sopenharmony_ci
2717db96d56Sopenharmony_ci.. function:: suppress(*exceptions)
2727db96d56Sopenharmony_ci
2737db96d56Sopenharmony_ci   Return a context manager that suppresses any of the specified exceptions
2747db96d56Sopenharmony_ci   if they occur in the body of a :keyword:`!with` statement and then
2757db96d56Sopenharmony_ci   resumes execution with the first statement following the end of the
2767db96d56Sopenharmony_ci   :keyword:`!with` statement.
2777db96d56Sopenharmony_ci
2787db96d56Sopenharmony_ci   As with any other mechanism that completely suppresses exceptions, this
2797db96d56Sopenharmony_ci   context manager should be used only to cover very specific errors where
2807db96d56Sopenharmony_ci   silently continuing with program execution is known to be the right
2817db96d56Sopenharmony_ci   thing to do.
2827db96d56Sopenharmony_ci
2837db96d56Sopenharmony_ci   For example::
2847db96d56Sopenharmony_ci
2857db96d56Sopenharmony_ci       from contextlib import suppress
2867db96d56Sopenharmony_ci
2877db96d56Sopenharmony_ci       with suppress(FileNotFoundError):
2887db96d56Sopenharmony_ci           os.remove('somefile.tmp')
2897db96d56Sopenharmony_ci
2907db96d56Sopenharmony_ci       with suppress(FileNotFoundError):
2917db96d56Sopenharmony_ci           os.remove('someotherfile.tmp')
2927db96d56Sopenharmony_ci
2937db96d56Sopenharmony_ci   This code is equivalent to::
2947db96d56Sopenharmony_ci
2957db96d56Sopenharmony_ci       try:
2967db96d56Sopenharmony_ci           os.remove('somefile.tmp')
2977db96d56Sopenharmony_ci       except FileNotFoundError:
2987db96d56Sopenharmony_ci           pass
2997db96d56Sopenharmony_ci
3007db96d56Sopenharmony_ci       try:
3017db96d56Sopenharmony_ci           os.remove('someotherfile.tmp')
3027db96d56Sopenharmony_ci       except FileNotFoundError:
3037db96d56Sopenharmony_ci           pass
3047db96d56Sopenharmony_ci
3057db96d56Sopenharmony_ci   This context manager is :ref:`reentrant <reentrant-cms>`.
3067db96d56Sopenharmony_ci
3077db96d56Sopenharmony_ci   .. versionadded:: 3.4
3087db96d56Sopenharmony_ci
3097db96d56Sopenharmony_ci
3107db96d56Sopenharmony_ci.. function:: redirect_stdout(new_target)
3117db96d56Sopenharmony_ci
3127db96d56Sopenharmony_ci   Context manager for temporarily redirecting :data:`sys.stdout` to
3137db96d56Sopenharmony_ci   another file or file-like object.
3147db96d56Sopenharmony_ci
3157db96d56Sopenharmony_ci   This tool adds flexibility to existing functions or classes whose output
3167db96d56Sopenharmony_ci   is hardwired to stdout.
3177db96d56Sopenharmony_ci
3187db96d56Sopenharmony_ci   For example, the output of :func:`help` normally is sent to *sys.stdout*.
3197db96d56Sopenharmony_ci   You can capture that output in a string by redirecting the output to an
3207db96d56Sopenharmony_ci   :class:`io.StringIO` object. The replacement stream is returned from the
3217db96d56Sopenharmony_ci   ``__enter__`` method and so is available as the target of the
3227db96d56Sopenharmony_ci   :keyword:`with` statement::
3237db96d56Sopenharmony_ci
3247db96d56Sopenharmony_ci        with redirect_stdout(io.StringIO()) as f:
3257db96d56Sopenharmony_ci            help(pow)
3267db96d56Sopenharmony_ci        s = f.getvalue()
3277db96d56Sopenharmony_ci
3287db96d56Sopenharmony_ci   To send the output of :func:`help` to a file on disk, redirect the output
3297db96d56Sopenharmony_ci   to a regular file::
3307db96d56Sopenharmony_ci
3317db96d56Sopenharmony_ci        with open('help.txt', 'w') as f:
3327db96d56Sopenharmony_ci            with redirect_stdout(f):
3337db96d56Sopenharmony_ci                help(pow)
3347db96d56Sopenharmony_ci
3357db96d56Sopenharmony_ci   To send the output of :func:`help` to *sys.stderr*::
3367db96d56Sopenharmony_ci
3377db96d56Sopenharmony_ci        with redirect_stdout(sys.stderr):
3387db96d56Sopenharmony_ci            help(pow)
3397db96d56Sopenharmony_ci
3407db96d56Sopenharmony_ci   Note that the global side effect on :data:`sys.stdout` means that this
3417db96d56Sopenharmony_ci   context manager is not suitable for use in library code and most threaded
3427db96d56Sopenharmony_ci   applications. It also has no effect on the output of subprocesses.
3437db96d56Sopenharmony_ci   However, it is still a useful approach for many utility scripts.
3447db96d56Sopenharmony_ci
3457db96d56Sopenharmony_ci   This context manager is :ref:`reentrant <reentrant-cms>`.
3467db96d56Sopenharmony_ci
3477db96d56Sopenharmony_ci   .. versionadded:: 3.4
3487db96d56Sopenharmony_ci
3497db96d56Sopenharmony_ci
3507db96d56Sopenharmony_ci.. function:: redirect_stderr(new_target)
3517db96d56Sopenharmony_ci
3527db96d56Sopenharmony_ci   Similar to :func:`~contextlib.redirect_stdout` but redirecting
3537db96d56Sopenharmony_ci   :data:`sys.stderr` to another file or file-like object.
3547db96d56Sopenharmony_ci
3557db96d56Sopenharmony_ci   This context manager is :ref:`reentrant <reentrant-cms>`.
3567db96d56Sopenharmony_ci
3577db96d56Sopenharmony_ci   .. versionadded:: 3.5
3587db96d56Sopenharmony_ci
3597db96d56Sopenharmony_ci
3607db96d56Sopenharmony_ci.. function:: chdir(path)
3617db96d56Sopenharmony_ci
3627db96d56Sopenharmony_ci   Non parallel-safe context manager to change the current working directory.
3637db96d56Sopenharmony_ci   As this changes a global state, the working directory, it is not suitable
3647db96d56Sopenharmony_ci   for use in most threaded or async contexts. It is also not suitable for most
3657db96d56Sopenharmony_ci   non-linear code execution, like generators, where the program execution is
3667db96d56Sopenharmony_ci   temporarily relinquished -- unless explicitly desired, you should not yield
3677db96d56Sopenharmony_ci   when this context manager is active.
3687db96d56Sopenharmony_ci
3697db96d56Sopenharmony_ci   This is a simple wrapper around :func:`~os.chdir`, it changes the current
3707db96d56Sopenharmony_ci   working directory upon entering and restores the old one on exit.
3717db96d56Sopenharmony_ci
3727db96d56Sopenharmony_ci   This context manager is :ref:`reentrant <reentrant-cms>`.
3737db96d56Sopenharmony_ci
3747db96d56Sopenharmony_ci   .. versionadded:: 3.11
3757db96d56Sopenharmony_ci
3767db96d56Sopenharmony_ci
3777db96d56Sopenharmony_ci.. class:: ContextDecorator()
3787db96d56Sopenharmony_ci
3797db96d56Sopenharmony_ci   A base class that enables a context manager to also be used as a decorator.
3807db96d56Sopenharmony_ci
3817db96d56Sopenharmony_ci   Context managers inheriting from ``ContextDecorator`` have to implement
3827db96d56Sopenharmony_ci   ``__enter__`` and ``__exit__`` as normal. ``__exit__`` retains its optional
3837db96d56Sopenharmony_ci   exception handling even when used as a decorator.
3847db96d56Sopenharmony_ci
3857db96d56Sopenharmony_ci   ``ContextDecorator`` is used by :func:`contextmanager`, so you get this
3867db96d56Sopenharmony_ci   functionality automatically.
3877db96d56Sopenharmony_ci
3887db96d56Sopenharmony_ci   Example of ``ContextDecorator``::
3897db96d56Sopenharmony_ci
3907db96d56Sopenharmony_ci      from contextlib import ContextDecorator
3917db96d56Sopenharmony_ci
3927db96d56Sopenharmony_ci      class mycontext(ContextDecorator):
3937db96d56Sopenharmony_ci          def __enter__(self):
3947db96d56Sopenharmony_ci              print('Starting')
3957db96d56Sopenharmony_ci              return self
3967db96d56Sopenharmony_ci
3977db96d56Sopenharmony_ci          def __exit__(self, *exc):
3987db96d56Sopenharmony_ci              print('Finishing')
3997db96d56Sopenharmony_ci              return False
4007db96d56Sopenharmony_ci
4017db96d56Sopenharmony_ci   The class can then be used like this::
4027db96d56Sopenharmony_ci
4037db96d56Sopenharmony_ci      >>> @mycontext()
4047db96d56Sopenharmony_ci      ... def function():
4057db96d56Sopenharmony_ci      ...     print('The bit in the middle')
4067db96d56Sopenharmony_ci      ...
4077db96d56Sopenharmony_ci      >>> function()
4087db96d56Sopenharmony_ci      Starting
4097db96d56Sopenharmony_ci      The bit in the middle
4107db96d56Sopenharmony_ci      Finishing
4117db96d56Sopenharmony_ci
4127db96d56Sopenharmony_ci      >>> with mycontext():
4137db96d56Sopenharmony_ci      ...     print('The bit in the middle')
4147db96d56Sopenharmony_ci      ...
4157db96d56Sopenharmony_ci      Starting
4167db96d56Sopenharmony_ci      The bit in the middle
4177db96d56Sopenharmony_ci      Finishing
4187db96d56Sopenharmony_ci
4197db96d56Sopenharmony_ci   This change is just syntactic sugar for any construct of the following form::
4207db96d56Sopenharmony_ci
4217db96d56Sopenharmony_ci      def f():
4227db96d56Sopenharmony_ci          with cm():
4237db96d56Sopenharmony_ci              # Do stuff
4247db96d56Sopenharmony_ci
4257db96d56Sopenharmony_ci   ``ContextDecorator`` lets you instead write::
4267db96d56Sopenharmony_ci
4277db96d56Sopenharmony_ci      @cm()
4287db96d56Sopenharmony_ci      def f():
4297db96d56Sopenharmony_ci          # Do stuff
4307db96d56Sopenharmony_ci
4317db96d56Sopenharmony_ci   It makes it clear that the ``cm`` applies to the whole function, rather than
4327db96d56Sopenharmony_ci   just a piece of it (and saving an indentation level is nice, too).
4337db96d56Sopenharmony_ci
4347db96d56Sopenharmony_ci   Existing context managers that already have a base class can be extended by
4357db96d56Sopenharmony_ci   using ``ContextDecorator`` as a mixin class::
4367db96d56Sopenharmony_ci
4377db96d56Sopenharmony_ci      from contextlib import ContextDecorator
4387db96d56Sopenharmony_ci
4397db96d56Sopenharmony_ci      class mycontext(ContextBaseClass, ContextDecorator):
4407db96d56Sopenharmony_ci          def __enter__(self):
4417db96d56Sopenharmony_ci              return self
4427db96d56Sopenharmony_ci
4437db96d56Sopenharmony_ci          def __exit__(self, *exc):
4447db96d56Sopenharmony_ci              return False
4457db96d56Sopenharmony_ci
4467db96d56Sopenharmony_ci   .. note::
4477db96d56Sopenharmony_ci      As the decorated function must be able to be called multiple times, the
4487db96d56Sopenharmony_ci      underlying context manager must support use in multiple :keyword:`with`
4497db96d56Sopenharmony_ci      statements. If this is not the case, then the original construct with the
4507db96d56Sopenharmony_ci      explicit :keyword:`!with` statement inside the function should be used.
4517db96d56Sopenharmony_ci
4527db96d56Sopenharmony_ci   .. versionadded:: 3.2
4537db96d56Sopenharmony_ci
4547db96d56Sopenharmony_ci
4557db96d56Sopenharmony_ci.. class:: AsyncContextDecorator
4567db96d56Sopenharmony_ci
4577db96d56Sopenharmony_ci   Similar to :class:`ContextDecorator` but only for asynchronous functions.
4587db96d56Sopenharmony_ci
4597db96d56Sopenharmony_ci   Example of ``AsyncContextDecorator``::
4607db96d56Sopenharmony_ci
4617db96d56Sopenharmony_ci      from asyncio import run
4627db96d56Sopenharmony_ci      from contextlib import AsyncContextDecorator
4637db96d56Sopenharmony_ci
4647db96d56Sopenharmony_ci      class mycontext(AsyncContextDecorator):
4657db96d56Sopenharmony_ci          async def __aenter__(self):
4667db96d56Sopenharmony_ci              print('Starting')
4677db96d56Sopenharmony_ci              return self
4687db96d56Sopenharmony_ci
4697db96d56Sopenharmony_ci          async def __aexit__(self, *exc):
4707db96d56Sopenharmony_ci              print('Finishing')
4717db96d56Sopenharmony_ci              return False
4727db96d56Sopenharmony_ci
4737db96d56Sopenharmony_ci   The class can then be used like this::
4747db96d56Sopenharmony_ci
4757db96d56Sopenharmony_ci      >>> @mycontext()
4767db96d56Sopenharmony_ci      ... async def function():
4777db96d56Sopenharmony_ci      ...     print('The bit in the middle')
4787db96d56Sopenharmony_ci      ...
4797db96d56Sopenharmony_ci      >>> run(function())
4807db96d56Sopenharmony_ci      Starting
4817db96d56Sopenharmony_ci      The bit in the middle
4827db96d56Sopenharmony_ci      Finishing
4837db96d56Sopenharmony_ci
4847db96d56Sopenharmony_ci      >>> async def function():
4857db96d56Sopenharmony_ci      ...    async with mycontext():
4867db96d56Sopenharmony_ci      ...         print('The bit in the middle')
4877db96d56Sopenharmony_ci      ...
4887db96d56Sopenharmony_ci      >>> run(function())
4897db96d56Sopenharmony_ci      Starting
4907db96d56Sopenharmony_ci      The bit in the middle
4917db96d56Sopenharmony_ci      Finishing
4927db96d56Sopenharmony_ci
4937db96d56Sopenharmony_ci   .. versionadded:: 3.10
4947db96d56Sopenharmony_ci
4957db96d56Sopenharmony_ci
4967db96d56Sopenharmony_ci.. class:: ExitStack()
4977db96d56Sopenharmony_ci
4987db96d56Sopenharmony_ci   A context manager that is designed to make it easy to programmatically
4997db96d56Sopenharmony_ci   combine other context managers and cleanup functions, especially those
5007db96d56Sopenharmony_ci   that are optional or otherwise driven by input data.
5017db96d56Sopenharmony_ci
5027db96d56Sopenharmony_ci   For example, a set of files may easily be handled in a single with
5037db96d56Sopenharmony_ci   statement as follows::
5047db96d56Sopenharmony_ci
5057db96d56Sopenharmony_ci      with ExitStack() as stack:
5067db96d56Sopenharmony_ci          files = [stack.enter_context(open(fname)) for fname in filenames]
5077db96d56Sopenharmony_ci          # All opened files will automatically be closed at the end of
5087db96d56Sopenharmony_ci          # the with statement, even if attempts to open files later
5097db96d56Sopenharmony_ci          # in the list raise an exception
5107db96d56Sopenharmony_ci
5117db96d56Sopenharmony_ci   The :meth:`__enter__` method returns the :class:`ExitStack` instance, and
5127db96d56Sopenharmony_ci   performs no additional operations.
5137db96d56Sopenharmony_ci
5147db96d56Sopenharmony_ci   Each instance maintains a stack of registered callbacks that are called in
5157db96d56Sopenharmony_ci   reverse order when the instance is closed (either explicitly or implicitly
5167db96d56Sopenharmony_ci   at the end of a :keyword:`with` statement). Note that callbacks are *not*
5177db96d56Sopenharmony_ci   invoked implicitly when the context stack instance is garbage collected.
5187db96d56Sopenharmony_ci
5197db96d56Sopenharmony_ci   This stack model is used so that context managers that acquire their
5207db96d56Sopenharmony_ci   resources in their ``__init__`` method (such as file objects) can be
5217db96d56Sopenharmony_ci   handled correctly.
5227db96d56Sopenharmony_ci
5237db96d56Sopenharmony_ci   Since registered callbacks are invoked in the reverse order of
5247db96d56Sopenharmony_ci   registration, this ends up behaving as if multiple nested :keyword:`with`
5257db96d56Sopenharmony_ci   statements had been used with the registered set of callbacks. This even
5267db96d56Sopenharmony_ci   extends to exception handling - if an inner callback suppresses or replaces
5277db96d56Sopenharmony_ci   an exception, then outer callbacks will be passed arguments based on that
5287db96d56Sopenharmony_ci   updated state.
5297db96d56Sopenharmony_ci
5307db96d56Sopenharmony_ci   This is a relatively low level API that takes care of the details of
5317db96d56Sopenharmony_ci   correctly unwinding the stack of exit callbacks. It provides a suitable
5327db96d56Sopenharmony_ci   foundation for higher level context managers that manipulate the exit
5337db96d56Sopenharmony_ci   stack in application specific ways.
5347db96d56Sopenharmony_ci
5357db96d56Sopenharmony_ci   .. versionadded:: 3.3
5367db96d56Sopenharmony_ci
5377db96d56Sopenharmony_ci   .. method:: enter_context(cm)
5387db96d56Sopenharmony_ci
5397db96d56Sopenharmony_ci      Enters a new context manager and adds its :meth:`__exit__` method to
5407db96d56Sopenharmony_ci      the callback stack. The return value is the result of the context
5417db96d56Sopenharmony_ci      manager's own :meth:`__enter__` method.
5427db96d56Sopenharmony_ci
5437db96d56Sopenharmony_ci      These context managers may suppress exceptions just as they normally
5447db96d56Sopenharmony_ci      would if used directly as part of a :keyword:`with` statement.
5457db96d56Sopenharmony_ci
5467db96d56Sopenharmony_ci      .. versionchanged:: 3.11
5477db96d56Sopenharmony_ci         Raises :exc:`TypeError` instead of :exc:`AttributeError` if *cm*
5487db96d56Sopenharmony_ci         is not a context manager.
5497db96d56Sopenharmony_ci
5507db96d56Sopenharmony_ci   .. method:: push(exit)
5517db96d56Sopenharmony_ci
5527db96d56Sopenharmony_ci      Adds a context manager's :meth:`__exit__` method to the callback stack.
5537db96d56Sopenharmony_ci
5547db96d56Sopenharmony_ci      As ``__enter__`` is *not* invoked, this method can be used to cover
5557db96d56Sopenharmony_ci      part of an :meth:`__enter__` implementation with a context manager's own
5567db96d56Sopenharmony_ci      :meth:`__exit__` method.
5577db96d56Sopenharmony_ci
5587db96d56Sopenharmony_ci      If passed an object that is not a context manager, this method assumes
5597db96d56Sopenharmony_ci      it is a callback with the same signature as a context manager's
5607db96d56Sopenharmony_ci      :meth:`__exit__` method and adds it directly to the callback stack.
5617db96d56Sopenharmony_ci
5627db96d56Sopenharmony_ci      By returning true values, these callbacks can suppress exceptions the
5637db96d56Sopenharmony_ci      same way context manager :meth:`__exit__` methods can.
5647db96d56Sopenharmony_ci
5657db96d56Sopenharmony_ci      The passed in object is returned from the function, allowing this
5667db96d56Sopenharmony_ci      method to be used as a function decorator.
5677db96d56Sopenharmony_ci
5687db96d56Sopenharmony_ci   .. method:: callback(callback, /, *args, **kwds)
5697db96d56Sopenharmony_ci
5707db96d56Sopenharmony_ci      Accepts an arbitrary callback function and arguments and adds it to
5717db96d56Sopenharmony_ci      the callback stack.
5727db96d56Sopenharmony_ci
5737db96d56Sopenharmony_ci      Unlike the other methods, callbacks added this way cannot suppress
5747db96d56Sopenharmony_ci      exceptions (as they are never passed the exception details).
5757db96d56Sopenharmony_ci
5767db96d56Sopenharmony_ci      The passed in callback is returned from the function, allowing this
5777db96d56Sopenharmony_ci      method to be used as a function decorator.
5787db96d56Sopenharmony_ci
5797db96d56Sopenharmony_ci   .. method:: pop_all()
5807db96d56Sopenharmony_ci
5817db96d56Sopenharmony_ci      Transfers the callback stack to a fresh :class:`ExitStack` instance
5827db96d56Sopenharmony_ci      and returns it. No callbacks are invoked by this operation - instead,
5837db96d56Sopenharmony_ci      they will now be invoked when the new stack is closed (either
5847db96d56Sopenharmony_ci      explicitly or implicitly at the end of a :keyword:`with` statement).
5857db96d56Sopenharmony_ci
5867db96d56Sopenharmony_ci      For example, a group of files can be opened as an "all or nothing"
5877db96d56Sopenharmony_ci      operation as follows::
5887db96d56Sopenharmony_ci
5897db96d56Sopenharmony_ci         with ExitStack() as stack:
5907db96d56Sopenharmony_ci             files = [stack.enter_context(open(fname)) for fname in filenames]
5917db96d56Sopenharmony_ci             # Hold onto the close method, but don't call it yet.
5927db96d56Sopenharmony_ci             close_files = stack.pop_all().close
5937db96d56Sopenharmony_ci             # If opening any file fails, all previously opened files will be
5947db96d56Sopenharmony_ci             # closed automatically. If all files are opened successfully,
5957db96d56Sopenharmony_ci             # they will remain open even after the with statement ends.
5967db96d56Sopenharmony_ci             # close_files() can then be invoked explicitly to close them all.
5977db96d56Sopenharmony_ci
5987db96d56Sopenharmony_ci   .. method:: close()
5997db96d56Sopenharmony_ci
6007db96d56Sopenharmony_ci      Immediately unwinds the callback stack, invoking callbacks in the
6017db96d56Sopenharmony_ci      reverse order of registration. For any context managers and exit
6027db96d56Sopenharmony_ci      callbacks registered, the arguments passed in will indicate that no
6037db96d56Sopenharmony_ci      exception occurred.
6047db96d56Sopenharmony_ci
6057db96d56Sopenharmony_ci.. class:: AsyncExitStack()
6067db96d56Sopenharmony_ci
6077db96d56Sopenharmony_ci   An :ref:`asynchronous context manager <async-context-managers>`, similar
6087db96d56Sopenharmony_ci   to :class:`ExitStack`, that supports combining both synchronous and
6097db96d56Sopenharmony_ci   asynchronous context managers, as well as having coroutines for
6107db96d56Sopenharmony_ci   cleanup logic.
6117db96d56Sopenharmony_ci
6127db96d56Sopenharmony_ci   The :meth:`close` method is not implemented, :meth:`aclose` must be used
6137db96d56Sopenharmony_ci   instead.
6147db96d56Sopenharmony_ci
6157db96d56Sopenharmony_ci   .. coroutinemethod:: enter_async_context(cm)
6167db96d56Sopenharmony_ci
6177db96d56Sopenharmony_ci      Similar to :meth:`enter_context` but expects an asynchronous context
6187db96d56Sopenharmony_ci      manager.
6197db96d56Sopenharmony_ci
6207db96d56Sopenharmony_ci      .. versionchanged:: 3.11
6217db96d56Sopenharmony_ci         Raises :exc:`TypeError` instead of :exc:`AttributeError` if *cm*
6227db96d56Sopenharmony_ci         is not an asynchronous context manager.
6237db96d56Sopenharmony_ci
6247db96d56Sopenharmony_ci   .. method:: push_async_exit(exit)
6257db96d56Sopenharmony_ci
6267db96d56Sopenharmony_ci      Similar to :meth:`push` but expects either an asynchronous context manager
6277db96d56Sopenharmony_ci      or a coroutine function.
6287db96d56Sopenharmony_ci
6297db96d56Sopenharmony_ci   .. method:: push_async_callback(callback, /, *args, **kwds)
6307db96d56Sopenharmony_ci
6317db96d56Sopenharmony_ci      Similar to :meth:`callback` but expects a coroutine function.
6327db96d56Sopenharmony_ci
6337db96d56Sopenharmony_ci   .. coroutinemethod:: aclose()
6347db96d56Sopenharmony_ci
6357db96d56Sopenharmony_ci      Similar to :meth:`close` but properly handles awaitables.
6367db96d56Sopenharmony_ci
6377db96d56Sopenharmony_ci   Continuing the example for :func:`asynccontextmanager`::
6387db96d56Sopenharmony_ci
6397db96d56Sopenharmony_ci      async with AsyncExitStack() as stack:
6407db96d56Sopenharmony_ci          connections = [await stack.enter_async_context(get_connection())
6417db96d56Sopenharmony_ci              for i in range(5)]
6427db96d56Sopenharmony_ci          # All opened connections will automatically be released at the end of
6437db96d56Sopenharmony_ci          # the async with statement, even if attempts to open a connection
6447db96d56Sopenharmony_ci          # later in the list raise an exception.
6457db96d56Sopenharmony_ci
6467db96d56Sopenharmony_ci   .. versionadded:: 3.7
6477db96d56Sopenharmony_ci
6487db96d56Sopenharmony_ciExamples and Recipes
6497db96d56Sopenharmony_ci--------------------
6507db96d56Sopenharmony_ci
6517db96d56Sopenharmony_ciThis section describes some examples and recipes for making effective use of
6527db96d56Sopenharmony_cithe tools provided by :mod:`contextlib`.
6537db96d56Sopenharmony_ci
6547db96d56Sopenharmony_ci
6557db96d56Sopenharmony_ciSupporting a variable number of context managers
6567db96d56Sopenharmony_ci^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6577db96d56Sopenharmony_ci
6587db96d56Sopenharmony_ciThe primary use case for :class:`ExitStack` is the one given in the class
6597db96d56Sopenharmony_cidocumentation: supporting a variable number of context managers and other
6607db96d56Sopenharmony_cicleanup operations in a single :keyword:`with` statement. The variability
6617db96d56Sopenharmony_cimay come from the number of context managers needed being driven by user
6627db96d56Sopenharmony_ciinput (such as opening a user specified collection of files), or from
6637db96d56Sopenharmony_cisome of the context managers being optional::
6647db96d56Sopenharmony_ci
6657db96d56Sopenharmony_ci    with ExitStack() as stack:
6667db96d56Sopenharmony_ci        for resource in resources:
6677db96d56Sopenharmony_ci            stack.enter_context(resource)
6687db96d56Sopenharmony_ci        if need_special_resource():
6697db96d56Sopenharmony_ci            special = acquire_special_resource()
6707db96d56Sopenharmony_ci            stack.callback(release_special_resource, special)
6717db96d56Sopenharmony_ci        # Perform operations that use the acquired resources
6727db96d56Sopenharmony_ci
6737db96d56Sopenharmony_ciAs shown, :class:`ExitStack` also makes it quite easy to use :keyword:`with`
6747db96d56Sopenharmony_cistatements to manage arbitrary resources that don't natively support the
6757db96d56Sopenharmony_cicontext management protocol.
6767db96d56Sopenharmony_ci
6777db96d56Sopenharmony_ci
6787db96d56Sopenharmony_ciCatching exceptions from ``__enter__`` methods
6797db96d56Sopenharmony_ci^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6807db96d56Sopenharmony_ci
6817db96d56Sopenharmony_ciIt is occasionally desirable to catch exceptions from an ``__enter__``
6827db96d56Sopenharmony_cimethod implementation, *without* inadvertently catching exceptions from
6837db96d56Sopenharmony_cithe :keyword:`with` statement body or the context manager's ``__exit__``
6847db96d56Sopenharmony_cimethod. By using :class:`ExitStack` the steps in the context management
6857db96d56Sopenharmony_ciprotocol can be separated slightly in order to allow this::
6867db96d56Sopenharmony_ci
6877db96d56Sopenharmony_ci   stack = ExitStack()
6887db96d56Sopenharmony_ci   try:
6897db96d56Sopenharmony_ci       x = stack.enter_context(cm)
6907db96d56Sopenharmony_ci   except Exception:
6917db96d56Sopenharmony_ci       # handle __enter__ exception
6927db96d56Sopenharmony_ci   else:
6937db96d56Sopenharmony_ci       with stack:
6947db96d56Sopenharmony_ci           # Handle normal case
6957db96d56Sopenharmony_ci
6967db96d56Sopenharmony_ciActually needing to do this is likely to indicate that the underlying API
6977db96d56Sopenharmony_cishould be providing a direct resource management interface for use with
6987db96d56Sopenharmony_ci:keyword:`try`/:keyword:`except`/:keyword:`finally` statements, but not
6997db96d56Sopenharmony_ciall APIs are well designed in that regard. When a context manager is the
7007db96d56Sopenharmony_cionly resource management API provided, then :class:`ExitStack` can make it
7017db96d56Sopenharmony_cieasier to handle various situations that can't be handled directly in a
7027db96d56Sopenharmony_ci:keyword:`with` statement.
7037db96d56Sopenharmony_ci
7047db96d56Sopenharmony_ci
7057db96d56Sopenharmony_ciCleaning up in an ``__enter__`` implementation
7067db96d56Sopenharmony_ci^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
7077db96d56Sopenharmony_ci
7087db96d56Sopenharmony_ciAs noted in the documentation of :meth:`ExitStack.push`, this
7097db96d56Sopenharmony_cimethod can be useful in cleaning up an already allocated resource if later
7107db96d56Sopenharmony_cisteps in the :meth:`__enter__` implementation fail.
7117db96d56Sopenharmony_ci
7127db96d56Sopenharmony_ciHere's an example of doing this for a context manager that accepts resource
7137db96d56Sopenharmony_ciacquisition and release functions, along with an optional validation function,
7147db96d56Sopenharmony_ciand maps them to the context management protocol::
7157db96d56Sopenharmony_ci
7167db96d56Sopenharmony_ci   from contextlib import contextmanager, AbstractContextManager, ExitStack
7177db96d56Sopenharmony_ci
7187db96d56Sopenharmony_ci   class ResourceManager(AbstractContextManager):
7197db96d56Sopenharmony_ci
7207db96d56Sopenharmony_ci       def __init__(self, acquire_resource, release_resource, check_resource_ok=None):
7217db96d56Sopenharmony_ci           self.acquire_resource = acquire_resource
7227db96d56Sopenharmony_ci           self.release_resource = release_resource
7237db96d56Sopenharmony_ci           if check_resource_ok is None:
7247db96d56Sopenharmony_ci               def check_resource_ok(resource):
7257db96d56Sopenharmony_ci                   return True
7267db96d56Sopenharmony_ci           self.check_resource_ok = check_resource_ok
7277db96d56Sopenharmony_ci
7287db96d56Sopenharmony_ci       @contextmanager
7297db96d56Sopenharmony_ci       def _cleanup_on_error(self):
7307db96d56Sopenharmony_ci           with ExitStack() as stack:
7317db96d56Sopenharmony_ci               stack.push(self)
7327db96d56Sopenharmony_ci               yield
7337db96d56Sopenharmony_ci               # The validation check passed and didn't raise an exception
7347db96d56Sopenharmony_ci               # Accordingly, we want to keep the resource, and pass it
7357db96d56Sopenharmony_ci               # back to our caller
7367db96d56Sopenharmony_ci               stack.pop_all()
7377db96d56Sopenharmony_ci
7387db96d56Sopenharmony_ci       def __enter__(self):
7397db96d56Sopenharmony_ci           resource = self.acquire_resource()
7407db96d56Sopenharmony_ci           with self._cleanup_on_error():
7417db96d56Sopenharmony_ci               if not self.check_resource_ok(resource):
7427db96d56Sopenharmony_ci                   msg = "Failed validation for {!r}"
7437db96d56Sopenharmony_ci                   raise RuntimeError(msg.format(resource))
7447db96d56Sopenharmony_ci           return resource
7457db96d56Sopenharmony_ci
7467db96d56Sopenharmony_ci       def __exit__(self, *exc_details):
7477db96d56Sopenharmony_ci           # We don't need to duplicate any of our resource release logic
7487db96d56Sopenharmony_ci           self.release_resource()
7497db96d56Sopenharmony_ci
7507db96d56Sopenharmony_ci
7517db96d56Sopenharmony_ciReplacing any use of ``try-finally`` and flag variables
7527db96d56Sopenharmony_ci^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
7537db96d56Sopenharmony_ci
7547db96d56Sopenharmony_ciA pattern you will sometimes see is a ``try-finally`` statement with a flag
7557db96d56Sopenharmony_civariable to indicate whether or not the body of the ``finally`` clause should
7567db96d56Sopenharmony_cibe executed. In its simplest form (that can't already be handled just by
7577db96d56Sopenharmony_ciusing an ``except`` clause instead), it looks something like this::
7587db96d56Sopenharmony_ci
7597db96d56Sopenharmony_ci   cleanup_needed = True
7607db96d56Sopenharmony_ci   try:
7617db96d56Sopenharmony_ci       result = perform_operation()
7627db96d56Sopenharmony_ci       if result:
7637db96d56Sopenharmony_ci           cleanup_needed = False
7647db96d56Sopenharmony_ci   finally:
7657db96d56Sopenharmony_ci       if cleanup_needed:
7667db96d56Sopenharmony_ci           cleanup_resources()
7677db96d56Sopenharmony_ci
7687db96d56Sopenharmony_ciAs with any ``try`` statement based code, this can cause problems for
7697db96d56Sopenharmony_cidevelopment and review, because the setup code and the cleanup code can end
7707db96d56Sopenharmony_ciup being separated by arbitrarily long sections of code.
7717db96d56Sopenharmony_ci
7727db96d56Sopenharmony_ci:class:`ExitStack` makes it possible to instead register a callback for
7737db96d56Sopenharmony_ciexecution at the end of a ``with`` statement, and then later decide to skip
7747db96d56Sopenharmony_ciexecuting that callback::
7757db96d56Sopenharmony_ci
7767db96d56Sopenharmony_ci   from contextlib import ExitStack
7777db96d56Sopenharmony_ci
7787db96d56Sopenharmony_ci   with ExitStack() as stack:
7797db96d56Sopenharmony_ci       stack.callback(cleanup_resources)
7807db96d56Sopenharmony_ci       result = perform_operation()
7817db96d56Sopenharmony_ci       if result:
7827db96d56Sopenharmony_ci           stack.pop_all()
7837db96d56Sopenharmony_ci
7847db96d56Sopenharmony_ciThis allows the intended cleanup up behaviour to be made explicit up front,
7857db96d56Sopenharmony_cirather than requiring a separate flag variable.
7867db96d56Sopenharmony_ci
7877db96d56Sopenharmony_ciIf a particular application uses this pattern a lot, it can be simplified
7887db96d56Sopenharmony_cieven further by means of a small helper class::
7897db96d56Sopenharmony_ci
7907db96d56Sopenharmony_ci   from contextlib import ExitStack
7917db96d56Sopenharmony_ci
7927db96d56Sopenharmony_ci   class Callback(ExitStack):
7937db96d56Sopenharmony_ci       def __init__(self, callback, /, *args, **kwds):
7947db96d56Sopenharmony_ci           super().__init__()
7957db96d56Sopenharmony_ci           self.callback(callback, *args, **kwds)
7967db96d56Sopenharmony_ci
7977db96d56Sopenharmony_ci       def cancel(self):
7987db96d56Sopenharmony_ci           self.pop_all()
7997db96d56Sopenharmony_ci
8007db96d56Sopenharmony_ci   with Callback(cleanup_resources) as cb:
8017db96d56Sopenharmony_ci       result = perform_operation()
8027db96d56Sopenharmony_ci       if result:
8037db96d56Sopenharmony_ci           cb.cancel()
8047db96d56Sopenharmony_ci
8057db96d56Sopenharmony_ciIf the resource cleanup isn't already neatly bundled into a standalone
8067db96d56Sopenharmony_cifunction, then it is still possible to use the decorator form of
8077db96d56Sopenharmony_ci:meth:`ExitStack.callback` to declare the resource cleanup in
8087db96d56Sopenharmony_ciadvance::
8097db96d56Sopenharmony_ci
8107db96d56Sopenharmony_ci   from contextlib import ExitStack
8117db96d56Sopenharmony_ci
8127db96d56Sopenharmony_ci   with ExitStack() as stack:
8137db96d56Sopenharmony_ci       @stack.callback
8147db96d56Sopenharmony_ci       def cleanup_resources():
8157db96d56Sopenharmony_ci           ...
8167db96d56Sopenharmony_ci       result = perform_operation()
8177db96d56Sopenharmony_ci       if result:
8187db96d56Sopenharmony_ci           stack.pop_all()
8197db96d56Sopenharmony_ci
8207db96d56Sopenharmony_ciDue to the way the decorator protocol works, a callback function
8217db96d56Sopenharmony_cideclared this way cannot take any parameters. Instead, any resources to
8227db96d56Sopenharmony_cibe released must be accessed as closure variables.
8237db96d56Sopenharmony_ci
8247db96d56Sopenharmony_ci
8257db96d56Sopenharmony_ciUsing a context manager as a function decorator
8267db96d56Sopenharmony_ci^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
8277db96d56Sopenharmony_ci
8287db96d56Sopenharmony_ci:class:`ContextDecorator` makes it possible to use a context manager in
8297db96d56Sopenharmony_ciboth an ordinary ``with`` statement and also as a function decorator.
8307db96d56Sopenharmony_ci
8317db96d56Sopenharmony_ciFor example, it is sometimes useful to wrap functions or groups of statements
8327db96d56Sopenharmony_ciwith a logger that can track the time of entry and time of exit.  Rather than
8337db96d56Sopenharmony_ciwriting both a function decorator and a context manager for the task,
8347db96d56Sopenharmony_ciinheriting from :class:`ContextDecorator` provides both capabilities in a
8357db96d56Sopenharmony_cisingle definition::
8367db96d56Sopenharmony_ci
8377db96d56Sopenharmony_ci    from contextlib import ContextDecorator
8387db96d56Sopenharmony_ci    import logging
8397db96d56Sopenharmony_ci
8407db96d56Sopenharmony_ci    logging.basicConfig(level=logging.INFO)
8417db96d56Sopenharmony_ci
8427db96d56Sopenharmony_ci    class track_entry_and_exit(ContextDecorator):
8437db96d56Sopenharmony_ci        def __init__(self, name):
8447db96d56Sopenharmony_ci            self.name = name
8457db96d56Sopenharmony_ci
8467db96d56Sopenharmony_ci        def __enter__(self):
8477db96d56Sopenharmony_ci            logging.info('Entering: %s', self.name)
8487db96d56Sopenharmony_ci
8497db96d56Sopenharmony_ci        def __exit__(self, exc_type, exc, exc_tb):
8507db96d56Sopenharmony_ci            logging.info('Exiting: %s', self.name)
8517db96d56Sopenharmony_ci
8527db96d56Sopenharmony_ciInstances of this class can be used as both a context manager::
8537db96d56Sopenharmony_ci
8547db96d56Sopenharmony_ci    with track_entry_and_exit('widget loader'):
8557db96d56Sopenharmony_ci        print('Some time consuming activity goes here')
8567db96d56Sopenharmony_ci        load_widget()
8577db96d56Sopenharmony_ci
8587db96d56Sopenharmony_ciAnd also as a function decorator::
8597db96d56Sopenharmony_ci
8607db96d56Sopenharmony_ci    @track_entry_and_exit('widget loader')
8617db96d56Sopenharmony_ci    def activity():
8627db96d56Sopenharmony_ci        print('Some time consuming activity goes here')
8637db96d56Sopenharmony_ci        load_widget()
8647db96d56Sopenharmony_ci
8657db96d56Sopenharmony_ciNote that there is one additional limitation when using context managers
8667db96d56Sopenharmony_cias function decorators: there's no way to access the return value of
8677db96d56Sopenharmony_ci:meth:`__enter__`. If that value is needed, then it is still necessary to use
8687db96d56Sopenharmony_cian explicit ``with`` statement.
8697db96d56Sopenharmony_ci
8707db96d56Sopenharmony_ci.. seealso::
8717db96d56Sopenharmony_ci
8727db96d56Sopenharmony_ci   :pep:`343` - The "with" statement
8737db96d56Sopenharmony_ci      The specification, background, and examples for the Python :keyword:`with`
8747db96d56Sopenharmony_ci      statement.
8757db96d56Sopenharmony_ci
8767db96d56Sopenharmony_ci.. _single-use-reusable-and-reentrant-cms:
8777db96d56Sopenharmony_ci
8787db96d56Sopenharmony_ciSingle use, reusable and reentrant context managers
8797db96d56Sopenharmony_ci---------------------------------------------------
8807db96d56Sopenharmony_ci
8817db96d56Sopenharmony_ciMost context managers are written in a way that means they can only be
8827db96d56Sopenharmony_ciused effectively in a :keyword:`with` statement once. These single use
8837db96d56Sopenharmony_cicontext managers must be created afresh each time they're used -
8847db96d56Sopenharmony_ciattempting to use them a second time will trigger an exception or
8857db96d56Sopenharmony_ciotherwise not work correctly.
8867db96d56Sopenharmony_ci
8877db96d56Sopenharmony_ciThis common limitation means that it is generally advisable to create
8887db96d56Sopenharmony_cicontext managers directly in the header of the :keyword:`with` statement
8897db96d56Sopenharmony_ciwhere they are used (as shown in all of the usage examples above).
8907db96d56Sopenharmony_ci
8917db96d56Sopenharmony_ciFiles are an example of effectively single use context managers, since
8927db96d56Sopenharmony_cithe first :keyword:`with` statement will close the file, preventing any
8937db96d56Sopenharmony_cifurther IO operations using that file object.
8947db96d56Sopenharmony_ci
8957db96d56Sopenharmony_ciContext managers created using :func:`contextmanager` are also single use
8967db96d56Sopenharmony_cicontext managers, and will complain about the underlying generator failing
8977db96d56Sopenharmony_cito yield if an attempt is made to use them a second time::
8987db96d56Sopenharmony_ci
8997db96d56Sopenharmony_ci    >>> from contextlib import contextmanager
9007db96d56Sopenharmony_ci    >>> @contextmanager
9017db96d56Sopenharmony_ci    ... def singleuse():
9027db96d56Sopenharmony_ci    ...     print("Before")
9037db96d56Sopenharmony_ci    ...     yield
9047db96d56Sopenharmony_ci    ...     print("After")
9057db96d56Sopenharmony_ci    ...
9067db96d56Sopenharmony_ci    >>> cm = singleuse()
9077db96d56Sopenharmony_ci    >>> with cm:
9087db96d56Sopenharmony_ci    ...     pass
9097db96d56Sopenharmony_ci    ...
9107db96d56Sopenharmony_ci    Before
9117db96d56Sopenharmony_ci    After
9127db96d56Sopenharmony_ci    >>> with cm:
9137db96d56Sopenharmony_ci    ...     pass
9147db96d56Sopenharmony_ci    ...
9157db96d56Sopenharmony_ci    Traceback (most recent call last):
9167db96d56Sopenharmony_ci        ...
9177db96d56Sopenharmony_ci    RuntimeError: generator didn't yield
9187db96d56Sopenharmony_ci
9197db96d56Sopenharmony_ci
9207db96d56Sopenharmony_ci.. _reentrant-cms:
9217db96d56Sopenharmony_ci
9227db96d56Sopenharmony_ciReentrant context managers
9237db96d56Sopenharmony_ci^^^^^^^^^^^^^^^^^^^^^^^^^^
9247db96d56Sopenharmony_ci
9257db96d56Sopenharmony_ciMore sophisticated context managers may be "reentrant". These context
9267db96d56Sopenharmony_cimanagers can not only be used in multiple :keyword:`with` statements,
9277db96d56Sopenharmony_cibut may also be used *inside* a :keyword:`!with` statement that is already
9287db96d56Sopenharmony_ciusing the same context manager.
9297db96d56Sopenharmony_ci
9307db96d56Sopenharmony_ci:class:`threading.RLock` is an example of a reentrant context manager, as are
9317db96d56Sopenharmony_ci:func:`suppress`, :func:`redirect_stdout`, and :func:`chdir`. Here's a very
9327db96d56Sopenharmony_cisimple example of reentrant use::
9337db96d56Sopenharmony_ci
9347db96d56Sopenharmony_ci    >>> from contextlib import redirect_stdout
9357db96d56Sopenharmony_ci    >>> from io import StringIO
9367db96d56Sopenharmony_ci    >>> stream = StringIO()
9377db96d56Sopenharmony_ci    >>> write_to_stream = redirect_stdout(stream)
9387db96d56Sopenharmony_ci    >>> with write_to_stream:
9397db96d56Sopenharmony_ci    ...     print("This is written to the stream rather than stdout")
9407db96d56Sopenharmony_ci    ...     with write_to_stream:
9417db96d56Sopenharmony_ci    ...         print("This is also written to the stream")
9427db96d56Sopenharmony_ci    ...
9437db96d56Sopenharmony_ci    >>> print("This is written directly to stdout")
9447db96d56Sopenharmony_ci    This is written directly to stdout
9457db96d56Sopenharmony_ci    >>> print(stream.getvalue())
9467db96d56Sopenharmony_ci    This is written to the stream rather than stdout
9477db96d56Sopenharmony_ci    This is also written to the stream
9487db96d56Sopenharmony_ci
9497db96d56Sopenharmony_ciReal world examples of reentrancy are more likely to involve multiple
9507db96d56Sopenharmony_cifunctions calling each other and hence be far more complicated than this
9517db96d56Sopenharmony_ciexample.
9527db96d56Sopenharmony_ci
9537db96d56Sopenharmony_ciNote also that being reentrant is *not* the same thing as being thread safe.
9547db96d56Sopenharmony_ci:func:`redirect_stdout`, for example, is definitely not thread safe, as it
9557db96d56Sopenharmony_cimakes a global modification to the system state by binding :data:`sys.stdout`
9567db96d56Sopenharmony_cito a different stream.
9577db96d56Sopenharmony_ci
9587db96d56Sopenharmony_ci
9597db96d56Sopenharmony_ci.. _reusable-cms:
9607db96d56Sopenharmony_ci
9617db96d56Sopenharmony_ciReusable context managers
9627db96d56Sopenharmony_ci^^^^^^^^^^^^^^^^^^^^^^^^^
9637db96d56Sopenharmony_ci
9647db96d56Sopenharmony_ciDistinct from both single use and reentrant context managers are "reusable"
9657db96d56Sopenharmony_cicontext managers (or, to be completely explicit, "reusable, but not
9667db96d56Sopenharmony_cireentrant" context managers, since reentrant context managers are also
9677db96d56Sopenharmony_cireusable). These context managers support being used multiple times, but
9687db96d56Sopenharmony_ciwill fail (or otherwise not work correctly) if the specific context manager
9697db96d56Sopenharmony_ciinstance has already been used in a containing with statement.
9707db96d56Sopenharmony_ci
9717db96d56Sopenharmony_ci:class:`threading.Lock` is an example of a reusable, but not reentrant,
9727db96d56Sopenharmony_cicontext manager (for a reentrant lock, it is necessary to use
9737db96d56Sopenharmony_ci:class:`threading.RLock` instead).
9747db96d56Sopenharmony_ci
9757db96d56Sopenharmony_ciAnother example of a reusable, but not reentrant, context manager is
9767db96d56Sopenharmony_ci:class:`ExitStack`, as it invokes *all* currently registered callbacks
9777db96d56Sopenharmony_ciwhen leaving any with statement, regardless of where those callbacks
9787db96d56Sopenharmony_ciwere added::
9797db96d56Sopenharmony_ci
9807db96d56Sopenharmony_ci    >>> from contextlib import ExitStack
9817db96d56Sopenharmony_ci    >>> stack = ExitStack()
9827db96d56Sopenharmony_ci    >>> with stack:
9837db96d56Sopenharmony_ci    ...     stack.callback(print, "Callback: from first context")
9847db96d56Sopenharmony_ci    ...     print("Leaving first context")
9857db96d56Sopenharmony_ci    ...
9867db96d56Sopenharmony_ci    Leaving first context
9877db96d56Sopenharmony_ci    Callback: from first context
9887db96d56Sopenharmony_ci    >>> with stack:
9897db96d56Sopenharmony_ci    ...     stack.callback(print, "Callback: from second context")
9907db96d56Sopenharmony_ci    ...     print("Leaving second context")
9917db96d56Sopenharmony_ci    ...
9927db96d56Sopenharmony_ci    Leaving second context
9937db96d56Sopenharmony_ci    Callback: from second context
9947db96d56Sopenharmony_ci    >>> with stack:
9957db96d56Sopenharmony_ci    ...     stack.callback(print, "Callback: from outer context")
9967db96d56Sopenharmony_ci    ...     with stack:
9977db96d56Sopenharmony_ci    ...         stack.callback(print, "Callback: from inner context")
9987db96d56Sopenharmony_ci    ...         print("Leaving inner context")
9997db96d56Sopenharmony_ci    ...     print("Leaving outer context")
10007db96d56Sopenharmony_ci    ...
10017db96d56Sopenharmony_ci    Leaving inner context
10027db96d56Sopenharmony_ci    Callback: from inner context
10037db96d56Sopenharmony_ci    Callback: from outer context
10047db96d56Sopenharmony_ci    Leaving outer context
10057db96d56Sopenharmony_ci
10067db96d56Sopenharmony_ciAs the output from the example shows, reusing a single stack object across
10077db96d56Sopenharmony_cimultiple with statements works correctly, but attempting to nest them
10087db96d56Sopenharmony_ciwill cause the stack to be cleared at the end of the innermost with
10097db96d56Sopenharmony_cistatement, which is unlikely to be desirable behaviour.
10107db96d56Sopenharmony_ci
10117db96d56Sopenharmony_ciUsing separate :class:`ExitStack` instances instead of reusing a single
10127db96d56Sopenharmony_ciinstance avoids that problem::
10137db96d56Sopenharmony_ci
10147db96d56Sopenharmony_ci    >>> from contextlib import ExitStack
10157db96d56Sopenharmony_ci    >>> with ExitStack() as outer_stack:
10167db96d56Sopenharmony_ci    ...     outer_stack.callback(print, "Callback: from outer context")
10177db96d56Sopenharmony_ci    ...     with ExitStack() as inner_stack:
10187db96d56Sopenharmony_ci    ...         inner_stack.callback(print, "Callback: from inner context")
10197db96d56Sopenharmony_ci    ...         print("Leaving inner context")
10207db96d56Sopenharmony_ci    ...     print("Leaving outer context")
10217db96d56Sopenharmony_ci    ...
10227db96d56Sopenharmony_ci    Leaving inner context
10237db96d56Sopenharmony_ci    Callback: from inner context
10247db96d56Sopenharmony_ci    Leaving outer context
10257db96d56Sopenharmony_ci    Callback: from outer context
1026