https://github.com/python/cpython/commit/5c1321731403031d933ca469977e4bb3859c8680
commit: 5c1321731403031d933ca469977e4bb3859c8680
branch: main
author: Eduardo Villalpando Mello <[email protected]>
committer: chris-eibl <[email protected]>
date: 2026-06-08T17:25:43Z
summary:
gh-148932: Fix `profiling.sampling` on Windows virtual environments (#150541)
files:
A Misc/NEWS.d/next/Library/2026-05-27-23-47-31.gh-issue-148932.Y1xmvA.rst
M Doc/library/profiling.sampling.rst
M Lib/profiling/sampling/sample.py
diff --git a/Doc/library/profiling.sampling.rst
b/Doc/library/profiling.sampling.rst
index 39b6ea4e31cde72..aeb1a429b58515a 100644
--- a/Doc/library/profiling.sampling.rst
+++ b/Doc/library/profiling.sampling.rst
@@ -387,11 +387,6 @@ This requires one of:
On Windows, the profiler requires administrative privileges or the
``SeDebugPrivilege`` privilege to read another process's memory.
-*Note*: On Windows, ``python -m profiling.sampling`` fails inside a virtual
-environment because the venv's ``python.exe`` is just a launcher shim that
-re-executes the base interpreter as a child process. The shim itself isn't
-a Python process and has no ``PyRuntime`` section to attach to. Instead,
-run it from the global Python installation.
Version compatibility
---------------------
diff --git a/Lib/profiling/sampling/sample.py b/Lib/profiling/sampling/sample.py
index 2d379e1e16a35e3..50ccc57566d70d3 100644
--- a/Lib/profiling/sampling/sample.py
+++ b/Lib/profiling/sampling/sample.py
@@ -50,9 +50,38 @@ def _pause_threads(unwinder, blocking):
# Maximum number of consecutive identical samples to keep before flushing.
MAX_PENDING_SAMPLES = 8192
+
+def _resolve_python_pid(pid):
+ """On Windows, if pid is a venvlauncher process, return the child Python
PID.
+
+ The venvlauncher (used as python.exe in venvs) spawns the real Python
+ interpreter as a child process via CreateProcessW. The RemoteUnwinder
+ needs the child's PID, not the launcher's.
+
+ Returns the original pid if not on Windows, not a venv launcher,
+ or no child process is found.
+ """
+ if os.name != "nt" or sys.prefix == sys.base_prefix:
+ return pid
+ try:
+ children = _remote_debugging.get_child_pids(pid, recursive=False)
+ python_children = [
+ child for child in children
+ if _remote_debugging.is_python_process(child)
+ ]
+ if len(python_children) == 1:
+ return python_children[0]
+ except (OSError, RuntimeError) as err:
+ raise SystemExit(
+ f"Failed to initialize profiler from virtualenv: {err}\n"
+ f"Try running with the base interpreter: {sys._base_executable}"
+ ) from err
+ return pid
+
+
class SampleProfiler:
def __init__(self, pid, sample_interval_usec, all_threads, *,
mode=PROFILING_MODE_WALL, native=False, gc=True, opcodes=False,
skip_non_matching_threads=True, collect_stats=False, blocking=False):
- self.pid = pid
+ self.pid = _resolve_python_pid(pid)
self.sample_interval_usec = sample_interval_usec
self.all_threads = all_threads
self.mode = mode # Store mode for later use
@@ -61,10 +90,6 @@ def __init__(self, pid, sample_interval_usec, all_threads,
*, mode=PROFILING_MOD
try:
self.unwinder = self._new_unwinder(native, gc, opcodes,
skip_non_matching_threads)
except RuntimeError as err:
- if os.name == "nt" and sys.executable.endswith("python.exe"):
- raise SystemExit(
- "Running profiling.sampling from virtualenv on Windows
platform is not supported"
- ) from err
raise SystemExit(err) from err
# Track sample intervals and total sample count
self.sample_intervals = deque(maxlen=100)
diff --git
a/Misc/NEWS.d/next/Library/2026-05-27-23-47-31.gh-issue-148932.Y1xmvA.rst
b/Misc/NEWS.d/next/Library/2026-05-27-23-47-31.gh-issue-148932.Y1xmvA.rst
new file mode 100644
index 000000000000000..a0b7a9740cd518d
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2026-05-27-23-47-31.gh-issue-148932.Y1xmvA.rst
@@ -0,0 +1 @@
+Fix ``profiling.sampling`` on Windows virtual environments to resolve the
actual Python PID from a virtual environment shim.
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]