|
11 | 11 | from pathlib import Path
|
12 | 12 | from subprocess import CompletedProcess, Popen
|
13 | 13 | from threading import Event
|
14 |
| -from typing import Any, Dict, List, Match, NoReturn, Optional, Tuple, cast |
| 14 | +from typing import Any, Dict, List, Match, NoReturn, Optional, cast |
15 | 15 |
|
16 | 16 | from granulate_utils.linux.elf import get_elf_id
|
17 | 17 | from granulate_utils.linux.ns import get_process_nspid, is_running_in_init_pid, run_in_ns
|
@@ -94,43 +94,43 @@ def _add_versions_to_stacks(
|
94 | 94 |
|
95 | 95 |
|
96 | 96 | class PythonMetadata(ApplicationMetadata):
|
97 |
| - _PYTHON_VERSION_TIMEOUT = 3 |
98 |
| - |
99 |
| - def _run_process_python(self, process: Process, args: List[str]) -> Tuple[str, str]: |
100 |
| - if not is_process_basename_matching(process, application_identifiers._PYTHON_BIN_RE): |
101 |
| - # TODO: for dynamic executables, find the python binary that works with the loaded libpython, and |
102 |
| - # check it instead. For static executables embedding libpython - :shrug: |
103 |
| - raise NotImplementedError |
104 |
| - |
105 |
| - python_path = f"/proc/{get_process_nspid(process.pid)}/exe" |
106 |
| - |
107 |
| - def _run_python_process_in_ns() -> "CompletedProcess[bytes]": |
108 |
| - return run_process( |
109 |
| - [ |
110 |
| - python_path, |
111 |
| - ] |
112 |
| - + args, |
113 |
| - stop_event=self._stop_event, |
114 |
| - timeout=self._PYTHON_VERSION_TIMEOUT, |
115 |
| - ) |
116 |
| - |
117 |
| - cp = run_in_ns(["pid", "mnt"], _run_python_process_in_ns, process.pid) |
118 |
| - return cp.stdout.decode().strip(), cp.stderr.decode().strip() |
| 97 | + _PYTHON_TIMEOUT = 3 |
119 | 98 |
|
120 | 99 | def _get_python_version(self, process: Process) -> Optional[str]:
|
121 | 100 | try:
|
122 |
| - stdout, stderr = self._run_process_python(process, ["-V"]) |
123 |
| - if stdout: |
124 |
| - return stdout |
125 |
| - # Python 2 prints -V to stderr, so return that instead. |
126 |
| - return stderr |
| 101 | + if is_process_basename_matching(process, application_identifiers._PYTHON_BIN_RE): |
| 102 | + version_arg = "-V" |
| 103 | + prefix = "" |
| 104 | + elif is_process_basename_matching(process, r"^uwsgi$"): |
| 105 | + version_arg = "--python-version" |
| 106 | + # for compatibility, we add this prefix (to match python -V) |
| 107 | + prefix = "Python " |
| 108 | + else: |
| 109 | + # TODO: for dynamic executables, find the python binary that works with the loaded libpython, and |
| 110 | + # check it instead. For static executables embedding libpython - :shrug: |
| 111 | + raise NotImplementedError |
| 112 | + |
| 113 | + # Python 2 prints -V to stderr, so try that as well. |
| 114 | + return prefix + self.get_exe_version_cached(process, version_arg=version_arg, try_stderr=True) |
127 | 115 | except Exception:
|
128 | 116 | return None
|
129 | 117 |
|
130 | 118 | def _get_sys_maxunicode(self, process: Process) -> Optional[str]:
|
131 | 119 | try:
|
132 |
| - stdout, stderr = self._run_process_python(process, ["-S", "-c", "import sys; print(sys.maxunicode)"]) |
133 |
| - return stdout |
| 120 | + if not is_process_basename_matching(process, application_identifiers._PYTHON_BIN_RE): |
| 121 | + # see same raise above |
| 122 | + raise NotImplementedError |
| 123 | + |
| 124 | + python_path = f"/proc/{get_process_nspid(process.pid)}/exe" |
| 125 | + |
| 126 | + def _run_python_process_in_ns() -> "CompletedProcess[bytes]": |
| 127 | + return run_process( |
| 128 | + [python_path, "-S", "-c", "import sys; print(sys.maxunicode)"], |
| 129 | + stop_event=self._stop_event, |
| 130 | + timeout=self._PYTHON_TIMEOUT, |
| 131 | + ) |
| 132 | + |
| 133 | + return run_in_ns(["pid", "mnt"], _run_python_process_in_ns, process.pid).stdout.decode().strip() |
134 | 134 | except Exception:
|
135 | 135 | return None
|
136 | 136 |
|
|
0 commit comments