From 2db2b5ea9cc689644bc7bc93f27a3e154228848a Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Wed, 30 Oct 2024 16:48:02 -0400 Subject: [PATCH] [3.13] gh-124872: Refine contextvars documentation (GH-124773) (#125233) [3.13] gh-124872: Refine contextvars documentation * Add definitions for "context", "current context", and "context management protocol". * Update related definitions to be consistent with the new definitions. * Restructure the documentation for the `contextvars.Context` class to prepare for adding context manager support, and for consistency with the definitions. * Use `testcode` and `testoutput` to test the `Context.run` example. (cherry-picked from commit 99400930ac1d4e5e10a5ae30f8202d8bc2661e39) Co-authored-by: Carol Willing --- Doc/glossary.rst | 40 ++++++-- Doc/library/contextvars.rst | 98 +++++++++++++------ ...-10-10-02-56-24.gh-issue-124872.0mDDOq.rst | 3 + 3 files changed, 102 insertions(+), 39 deletions(-) create mode 100644 Misc/NEWS.d/next/Documentation/2024-10-10-02-56-24.gh-issue-124872.0mDDOq.rst diff --git a/Doc/glossary.rst b/Doc/glossary.rst index 3c931a7c2a9..5c56c419514 100644 --- a/Doc/glossary.rst +++ b/Doc/glossary.rst @@ -260,19 +260,33 @@ Glossary advanced mathematical feature. If you're not aware of a need for them, it's almost certain you can safely ignore them. + context + This term has different meanings depending on where and how it is used. + Some common meanings: + + * The temporary state or environment established by a :term:`context + manager` via a :keyword:`with` statement. + * The collection of key­value bindings associated with a particular + :class:`contextvars.Context` object and accessed via + :class:`~contextvars.ContextVar` objects. Also see :term:`context + variable`. + * A :class:`contextvars.Context` object. Also see :term:`current + context`. + + context management protocol + The :meth:`~object.__enter__` and :meth:`~object.__exit__` methods called + by the :keyword:`with` statement. See :pep:`343`. + context manager - An object which controls the environment seen in a :keyword:`with` - statement by defining :meth:`~object.__enter__` and :meth:`~object.__exit__` methods. - See :pep:`343`. + An object which implements the :term:`context management protocol` and + controls the environment seen in a :keyword:`with` statement. See + :pep:`343`. context variable - A variable which can have different values depending on its context. - This is similar to Thread-Local Storage in which each execution - thread may have a different value for a variable. However, with context - variables, there may be several contexts in one execution thread and the - main usage for context variables is to keep track of variables in + A variable whose value depends on which context is the :term:`current + context`. Values are accessed via :class:`contextvars.ContextVar` + objects. Context variables are primarily used to isolate state between concurrent asynchronous tasks. - See :mod:`contextvars`. contiguous .. index:: C-contiguous, Fortran contiguous @@ -306,6 +320,14 @@ Glossary is used when necessary to distinguish this implementation from others such as Jython or IronPython. + current context + The :term:`context` (:class:`contextvars.Context` object) that is + currently used by :class:`~contextvars.ContextVar` objects to access (get + or set) the values of :term:`context variables `. Each + thread has its own current context. Frameworks for executing asynchronous + tasks (see :mod:`asyncio`) associate each task with a context which + becomes the current context whenever the task starts or resumes execution. + decorator A function returning another function, usually applied as a function transformation using the ``@wrapper`` syntax. Common examples for diff --git a/Doc/library/contextvars.rst b/Doc/library/contextvars.rst index 2a79dfe8f81..2b1fb9fdd29 100644 --- a/Doc/library/contextvars.rst +++ b/Doc/library/contextvars.rst @@ -144,51 +144,89 @@ Manual Context Management To get a copy of the current context use the :func:`~contextvars.copy_context` function. - Every thread will have a different top-level :class:`~contextvars.Context` - object. This means that a :class:`ContextVar` object behaves in a similar - fashion to :func:`threading.local` when values are assigned in different - threads. + Each thread has its own effective stack of :class:`!Context` objects. The + :term:`current context` is the :class:`!Context` object at the top of the + current thread's stack. All :class:`!Context` objects in the stacks are + considered to be *entered*. + + *Entering* a context, which can be done by calling its :meth:`~Context.run` + method, makes the context the current context by pushing it onto the top of + the current thread's context stack. + + *Exiting* from the current context, which can be done by returning from the + callback passed to the :meth:`~Context.run` method, restores the current + context to what it was before the context was entered by popping the context + off the top of the context stack. + + Since each thread has its own context stack, :class:`ContextVar` objects + behave in a similar fashion to :func:`threading.local` when values are + assigned in different threads. + + Attempting to enter an already entered context, including contexts entered in + other threads, raises a :exc:`RuntimeError`. + + After exiting a context, it can later be re-entered (from any thread). + + Any changes to :class:`ContextVar` values via the :meth:`ContextVar.set` + method are recorded in the current context. The :meth:`ContextVar.get` + method returns the value associated with the current context. Exiting a + context effectively reverts any changes made to context variables while the + context was entered (if needed, the values can be restored by re-entering the + context). Context implements the :class:`collections.abc.Mapping` interface. .. method:: run(callable, *args, **kwargs) - Execute ``callable(*args, **kwargs)`` code in the context object - the *run* method is called on. Return the result of the execution - or propagate an exception if one occurred. + Enters the Context, executes ``callable(*args, **kwargs)``, then exits the + Context. Returns *callable*'s return value, or propagates an exception if + one occurred. - Any changes to any context variables that *callable* makes will - be contained in the context object:: + Example: - var = ContextVar('var') - var.set('spam') + .. testcode:: - def main(): - # 'var' was set to 'spam' before - # calling 'copy_context()' and 'ctx.run(main)', so: - # var.get() == ctx[var] == 'spam' + import contextvars - var.set('ham') + var = contextvars.ContextVar('var') + var.set('spam') + print(var.get()) # 'spam' - # Now, after setting 'var' to 'ham': - # var.get() == ctx[var] == 'ham' + ctx = contextvars.copy_context() - ctx = copy_context() + def main(): + # 'var' was set to 'spam' before + # calling 'copy_context()' and 'ctx.run(main)', so: + print(var.get()) # 'spam' + print(ctx[var]) # 'spam' - # Any changes that the 'main' function makes to 'var' - # will be contained in 'ctx'. - ctx.run(main) + var.set('ham') - # The 'main()' function was run in the 'ctx' context, - # so changes to 'var' are contained in it: - # ctx[var] == 'ham' + # Now, after setting 'var' to 'ham': + print(var.get()) # 'ham' + print(ctx[var]) # 'ham' - # However, outside of 'ctx', 'var' is still set to 'spam': - # var.get() == 'spam' + # Any changes that the 'main' function makes to 'var' + # will be contained in 'ctx'. + ctx.run(main) - The method raises a :exc:`RuntimeError` when called on the same - context object from more than one OS thread, or when called - recursively. + # The 'main()' function was run in the 'ctx' context, + # so changes to 'var' are contained in it: + print(ctx[var]) # 'ham' + + # However, outside of 'ctx', 'var' is still set to 'spam': + print(var.get()) # 'spam' + + .. testoutput:: + :hide: + + spam + spam + spam + ham + ham + ham + spam .. method:: copy() diff --git a/Misc/NEWS.d/next/Documentation/2024-10-10-02-56-24.gh-issue-124872.0mDDOq.rst b/Misc/NEWS.d/next/Documentation/2024-10-10-02-56-24.gh-issue-124872.0mDDOq.rst new file mode 100644 index 00000000000..69a5c764d05 --- /dev/null +++ b/Misc/NEWS.d/next/Documentation/2024-10-10-02-56-24.gh-issue-124872.0mDDOq.rst @@ -0,0 +1,3 @@ +Added definitions for :term:`context`, :term:`current context`, and +:term:`context management protocol`, updated related definitions to be +consistent, and expanded the documentation for :class:`contextvars.Context`.