Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 33.9k
gh-131591: Implement PEP 768#131937
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Uh oh!
There was an error while loading. Please reload this page.
gh-131591: Implement PEP 768 #131937
Changes from all commits
6f6b4cd9b86022af8410019ef7ae444453c1d3ad3ceeec1f6fd993e396798c3075ca6545e73c5ed2f3256076548a9d3ea9e235e62d51dda038a4d51a98898d997b557f6dec59d273c5bc9a21464af17445c0b8b9c8779cd68890427f7aa8bfbecfdbfa98f645b4cb000dd7797b8a05039344d1d9368d38166f4d6d2539668e04fdd0c2b27580856d3f01d8d3cca28c5727a02f6ec528cf7e396340bda7c780561b2ab5d703a5f0046346063b442b1c3a4ed238514d6e72d3ece9130bb8373d4c4bccc8a890ab65fffd340f247e7533c4c41c18c2e64139b2344306a7335003a880fab7509051058db68e325cc4860557de06dd75307c340e190963756516356e6cb8fb8b3ffa9File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -90,6 +90,63 @@ If you encounter :exc:`NameError`\s or pickling errors coming out of | ||
| New features | ||
| ============ | ||
| .. _whatsnew314-pep678: | ||
| PEP 768: Safe external debugger interface for CPython | ||
| ----------------------------------------------------- | ||
| :pep:`768` introduces a zero-overhead debugging interface that allows debuggers and profilers | ||
| to safely attach to running Python processes. This is a significant enhancement to Python's | ||
| debugging capabilities allowing debuggers to forego unsafe alternatives. | ||
| The new interface provides safe execution points for attaching debugger code without modifying | ||
| the interpreter's normal execution path or adding runtime overhead. This enables tools to | ||
| inspect and interact with Python applications in real-time without stopping or restarting | ||
| them — a crucial capability for high-availability systems and production environments. | ||
| For convenience, CPython implements this interface through the :mod:`sys` module with a | ||
| :func:`sys.remote_exec` function:: | ||
| sys.remote_exec(pid, script_path) | ||
| This function allows sending Python code to be executed in a target process at the next safe | ||
| execution point. However, tool authors can also implement the protocol directly as described | ||
| in the PEP, which details the underlying mechanisms used to safely attach to running processes. | ||
| Here's a simple example that inspects object types in a running Python process: | ||
pablogsal marked this conversation as resolved. Show resolvedHide resolvedUh oh!There was an error while loading. Please reload this page. | ||
| .. code-block:: python | ||
| import os | ||
| import sys | ||
| import tempfile | ||
| # Create a temporary script | ||
| with tempfile.NamedTemporaryFile(mode='w', suffix='.py', delete=False) as f: | ||
| script_path = f.name | ||
| f.write(f"import my_debugger; my_debugger.connect({os.getpid()})") | ||
| try: | ||
| # Execute in process with PID 1234 | ||
| print("Behold! An offering:") | ||
| sys.remote_exec(1234, script_path) | ||
| finally: | ||
| os.unlink(script_path) | ||
Comment on lines +128 to +133 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this example correct? Unlinking the file immediately contradicts with the function docs. Contributor There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That example is definitely racy. | ||
| The debugging interface has been carefully designed with security in mind and includes several | ||
| mechanisms to control access: | ||
| * A :envvar:`PYTHON_DISABLE_REMOTE_DEBUG` environment variable. | ||
| * A :option:`-X disable-remote-debug` command-line option. | ||
| * A :option:`--without-remote-debug` configure flag to completely disable the feature at build time. | ||
| A key implementation detail is that the interface piggybacks on the interpreter's existing evaluation | ||
| loop and safe points, ensuring zero overhead during normal execution while providing a reliable way | ||
| for external processes to coordinate debugging operations. | ||
| See :pep:`768` for more details. | ||
| (Contributed by Pablo Galindo Salgado, Matt Wozniski, and Ivona Stojanovic in :gh:`131591`.) | ||
pablogsal marked this conversation as resolved. Show resolvedHide resolvedUh oh!There was an error while loading. Please reload this page. | ||
| .. _whatsnew314-pep758: | ||
| PEP 758 – Allow except and except* expressions without parentheses | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -73,6 +73,7 @@ typedef struct _Py_DebugOffsets{ | ||
| uint64_t id; | ||
| uint64_t next; | ||
| uint64_t threads_head; | ||
| uint64_t threads_main; | ||
pablogsal marked this conversation as resolved. Show resolvedHide resolvedUh oh!There was an error while loading. Please reload this page. | ||
| uint64_t gc; | ||
| uint64_t imports_modules; | ||
| uint64_t sysdict; | ||
| @@ -206,6 +207,15 @@ typedef struct _Py_DebugOffsets{ | ||
| uint64_t gi_iframe; | ||
| uint64_t gi_frame_state; | ||
| } gen_object; | ||
| struct _debugger_support{ | ||
| uint64_t eval_breaker; | ||
| uint64_t remote_debugger_support; | ||
| uint64_t remote_debugging_enabled; | ||
| uint64_t debugger_pending_call; | ||
| uint64_t debugger_script_path; | ||
| uint64_t debugger_script_path_size; | ||
| } debugger_support; | ||
| } _Py_DebugOffsets; | ||
| @@ -223,6 +233,7 @@ typedef struct _Py_DebugOffsets{ | ||
| .id = offsetof(PyInterpreterState, id), \ | ||
| .next = offsetof(PyInterpreterState, next), \ | ||
| .threads_head = offsetof(PyInterpreterState, threads.head), \ | ||
| .threads_main = offsetof(PyInterpreterState, threads.main), \ | ||
| .gc = offsetof(PyInterpreterState, gc), \ | ||
| .imports_modules = offsetof(PyInterpreterState, imports.modules), \ | ||
| .sysdict = offsetof(PyInterpreterState, sysdict), \ | ||
| @@ -326,6 +337,14 @@ typedef struct _Py_DebugOffsets{ | ||
| .gi_iframe = offsetof(PyGenObject, gi_iframe), \ | ||
| .gi_frame_state = offsetof(PyGenObject, gi_frame_state), \ | ||
| }, \ | ||
| .debugger_support ={\ | ||
| .eval_breaker = offsetof(PyThreadState, eval_breaker), \ | ||
| .remote_debugger_support = offsetof(PyThreadState, remote_debugger_support), \ | ||
| .remote_debugging_enabled = offsetof(PyInterpreterState, config.remote_debug), \ | ||
| .debugger_pending_call = offsetof(_PyRemoteDebuggerSupport, debugger_pending_call), \ | ||
| .debugger_script_path = offsetof(_PyRemoteDebuggerSupport, debugger_script_path), \ | ||
| .debugger_script_path_size = MAX_SCRIPT_PATH_SIZE, \ | ||
| }, \ | ||
| } | ||
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Uh oh!
There was an error while loading. Please reload this page.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Uh oh!
There was an error while loading. Please reload this page.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.