Skip to content

Commit 1bb5210

Browse files
committed
Merge branch 'pythongh-119333-99633-docs' into HEAD
2 parents cea403f + b16f493 commit 1bb5210

File tree

5 files changed

+132
-52
lines changed

5 files changed

+132
-52
lines changed

Doc/c-api/contextvars.rst

+13-7
Original file line numberDiff line numberDiff line change
@@ -122,18 +122,24 @@ Context object management functions:
122122
.. c:type:: PyContextEvent
123123
124124
Enumeration of possible context object watcher events:
125-
- ``Py_CONTEXT_EVENT_ENTER``
126-
- ``Py_CONTEXT_EVENT_EXIT``
125+
126+
- ``Py_CONTEXT_EVENT_ENTER``: A context has been entered, causing the
127+
:term:`current context` to switch to it. The object passed to the watch
128+
callback is the now-current :class:`contextvars.Context` object. Each
129+
enter event will eventually have a corresponding exit event for the same
130+
context object after any subsequently entered contexts have themselves been
131+
exited.
132+
- ``Py_CONTEXT_EVENT_EXIT``: A context is about to be exited, which will
133+
cause the :term:`current context` to switch back to what it was before the
134+
context was entered. The object passed to the watch callback is the
135+
still-current :class:`contextvars.Context` object.
127136
128137
.. versionadded:: 3.14
129138
130139
.. c:type:: void (*PyContext_WatchCallback)(PyContextEvent event, PyObject* ctx)
131140
132-
Type of a context object watcher callback function.
133-
If *event* is ``Py_CONTEXT_EVENT_ENTER``, then the callback is invoked
134-
after *ctx* has been set as the current context for the current thread.
135-
Otherwise, the callback is invoked before the deactivation of *ctx* as the current context
136-
and the restoration of the previous contex object for the current thread.
141+
Context object watcher callback function. The object passed to the callback
142+
is event-specific; see :c:type:`PyContextEvent` for details.
137143
138144
Any pending exception is cleared before the callback is called and restored
139145
after the callback returns.

Doc/glossary.rst

+31-9
Original file line numberDiff line numberDiff line change
@@ -243,19 +243,33 @@ Glossary
243243
advanced mathematical feature. If you're not aware of a need for them,
244244
it's almost certain you can safely ignore them.
245245

246+
context
247+
This term has different meanings depending on where and how it is used.
248+
Some common meanings:
249+
250+
* The temporary state or environment established by a :term:`context
251+
manager` via a :keyword:`with` statement.
252+
* The collection of key­value bindings associated with a particular
253+
:class:`contextvars.Context` object and accessed via
254+
:class:`~contextvars.ContextVar` objects. Also see :term:`context
255+
variable`.
256+
* A :class:`contextvars.Context` object. Also see :term:`current
257+
context`.
258+
259+
context management protocol
260+
The :meth:`~object.__enter__` and :meth:`~object.__exit__` methods called
261+
by the :keyword:`with` statement. See :pep:`343`.
262+
246263
context manager
247-
An object which controls the environment seen in a :keyword:`with`
248-
statement by defining :meth:`~object.__enter__` and :meth:`~object.__exit__` methods.
249-
See :pep:`343`.
264+
An object which implements the :term:`context management protocol` and
265+
controls the environment seen in a :keyword:`with` statement. See
266+
:pep:`343`.
250267

251268
context variable
252-
A variable which can have different values depending on its context.
253-
This is similar to Thread-Local Storage in which each execution
254-
thread may have a different value for a variable. However, with context
255-
variables, there may be several contexts in one execution thread and the
256-
main usage for context variables is to keep track of variables in
269+
A variable whose value depends on which context is the :term:`current
270+
context`. Values are accessed via :class:`contextvars.ContextVar`
271+
objects. Context variables are primarily used to isolate state between
257272
concurrent asynchronous tasks.
258-
See :mod:`contextvars`.
259273

260274
contiguous
261275
.. index:: C-contiguous, Fortran contiguous
@@ -289,6 +303,14 @@ Glossary
289303
is used when necessary to distinguish this implementation from others
290304
such as Jython or IronPython.
291305

306+
current context
307+
The :term:`context` (:class:`contextvars.Context` object) that is
308+
currently used by :class:`~contextvars.ContextVar` objects to access (get
309+
or set) the values of :term:`context variables <context variable>`. Each
310+
thread has its own current context. Frameworks for executing asynchronous
311+
tasks (see :mod:`asyncio`) associate each task with a context which
312+
becomes the current context whenever the task starts or resumes execution.
313+
292314
decorator
293315
A function returning another function, usually applied as a function
294316
transformation using the ``@wrapper`` syntax. Common examples for

Doc/library/contextvars.rst

+68-30
Original file line numberDiff line numberDiff line change
@@ -144,51 +144,89 @@ Manual Context Management
144144
To get a copy of the current context use the
145145
:func:`~contextvars.copy_context` function.
146146

147-
Every thread will have a different top-level :class:`~contextvars.Context`
148-
object. This means that a :class:`ContextVar` object behaves in a similar
149-
fashion to :func:`threading.local` when values are assigned in different
150-
threads.
147+
Each thread has its own effective stack of :class:`!Context` objects. The
148+
:term:`current context` is the :class:`!Context` object at the top of the
149+
current thread's stack. All :class:`!Context` objects in the stacks are
150+
considered to be *entered*.
151+
152+
*Entering* a context, which can be done by calling its :meth:`~Context.run`
153+
method, makes the context the current context by pushing it onto the top of
154+
the current thread's context stack.
155+
156+
*Exiting* from the current context, which can be done by returning from the
157+
callback passed to the :meth:`~Context.run` method, restores the current
158+
context to what it was before the context was entered by popping the context
159+
off the top of the context stack.
160+
161+
Since each thread has its own context stack, :class:`ContextVar` objects
162+
behave in a similar fashion to :func:`threading.local` when values are
163+
assigned in different threads.
164+
165+
Attempting to enter an already entered context, including contexts entered in
166+
other threads, raises a :exc:`RuntimeError`.
167+
168+
After exiting a context, it can later be re-entered (from any thread).
169+
170+
Any changes to :class:`ContextVar` values via the :meth:`ContextVar.set`
171+
method are recorded in the current context. The :meth:`ContextVar.get`
172+
method returns the value associated with the current context. Exiting a
173+
context effectively reverts any changes made to context variables while the
174+
context was entered (if needed, the values can be restored by re-entering the
175+
context).
151176

152177
Context implements the :class:`collections.abc.Mapping` interface.
153178

154179
.. method:: run(callable, *args, **kwargs)
155180

156-
Execute ``callable(*args, **kwargs)`` code in the context object
157-
the *run* method is called on. Return the result of the execution
158-
or propagate an exception if one occurred.
181+
Enters the Context, executes ``callable(*args, **kwargs)``, then exits the
182+
Context. Returns *callable*'s return value, or propagates an exception if
183+
one occurred.
184+
185+
Example:
186+
187+
.. testcode::
188+
189+
import contextvars
159190

160-
Any changes to any context variables that *callable* makes will
161-
be contained in the context object::
191+
var = contextvars.ContextVar('var')
192+
var.set('spam')
193+
print(var.get()) # 'spam'
162194

163-
var = ContextVar('var')
164-
var.set('spam')
195+
ctx = contextvars.copy_context()
165196

166-
def main():
167-
# 'var' was set to 'spam' before
168-
# calling 'copy_context()' and 'ctx.run(main)', so:
169-
# var.get() == ctx[var] == 'spam'
197+
def main():
198+
# 'var' was set to 'spam' before
199+
# calling 'copy_context()' and 'ctx.run(main)', so:
200+
print(var.get()) # 'spam'
201+
print(ctx[var]) # 'spam'
170202

171-
var.set('ham')
203+
var.set('ham')
172204

173-
# Now, after setting 'var' to 'ham':
174-
# var.get() == ctx[var] == 'ham'
205+
# Now, after setting 'var' to 'ham':
206+
print(var.get()) # 'ham'
207+
print(ctx[var]) # 'ham'
175208

176-
ctx = copy_context()
209+
# Any changes that the 'main' function makes to 'var'
210+
# will be contained in 'ctx'.
211+
ctx.run(main)
177212

178-
# Any changes that the 'main' function makes to 'var'
179-
# will be contained in 'ctx'.
180-
ctx.run(main)
213+
# The 'main()' function was run in the 'ctx' context,
214+
# so changes to 'var' are contained in it:
215+
print(ctx[var]) # 'ham'
181216

182-
# The 'main()' function was run in the 'ctx' context,
183-
# so changes to 'var' are contained in it:
184-
# ctx[var] == 'ham'
217+
# However, outside of 'ctx', 'var' is still set to 'spam':
218+
print(var.get()) # 'spam'
185219

186-
# However, outside of 'ctx', 'var' is still set to 'spam':
187-
# var.get() == 'spam'
220+
.. testoutput::
221+
:hide:
188222

189-
The method raises a :exc:`RuntimeError` when called on the same
190-
context object from more than one OS thread, or when called
191-
recursively.
223+
spam
224+
spam
225+
spam
226+
ham
227+
ham
228+
ham
229+
spam
192230

193231
.. method:: copy()
194232

Include/cpython/context.h

+17-6
Original file line numberDiff line numberDiff line change
@@ -28,15 +28,26 @@ PyAPI_FUNC(int) PyContext_Enter(PyObject *);
2828
PyAPI_FUNC(int) PyContext_Exit(PyObject *);
2929

3030
typedef enum {
31-
Py_CONTEXT_EVENT_ENTER,
32-
Py_CONTEXT_EVENT_EXIT,
31+
/*
32+
* A context has been entered, causing the "current context" to switch to
33+
* it. The object passed to the watch callback is the now-current
34+
* contextvars.Context object. Each enter event will eventually have a
35+
* corresponding exit event for the same context object after any
36+
* subsequently entered contexts have themselves been exited.
37+
*/
38+
Py_CONTEXT_EVENT_ENTER,
39+
/*
40+
* A context is about to be exited, which will cause the "current context"
41+
* to switch back to what it was before the context was entered. The
42+
* object passed to the watch callback is the still-current
43+
* contextvars.Context object.
44+
*/
45+
Py_CONTEXT_EVENT_EXIT,
3346
} PyContextEvent;
3447

3548
/*
36-
* Callback to be invoked when a context object is entered or exited.
37-
*
38-
* The callback is invoked with the event and a reference to
39-
* the context after its entered and before its exited.
49+
* Context object watcher callback function. The object passed to the callback
50+
* is event-specific; see PyContextEvent for details.
4051
*
4152
* Any pending exception is cleared before the callback is called and restored
4253
* after the callback returns.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Added definitions for :term:`context`, :term:`current context`, and
2+
:term:`context management protocol`, updated related definitions to be
3+
consistent, and expanded the documentation for :class:`contextvars.Context`.

0 commit comments

Comments
 (0)