py2docfx 0.1.11rc1981066__py3-none-any.whl → 0.1.11rc1997820__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- py2docfx/__main__.py +24 -15
- py2docfx/convert_prepare/environment.py +13 -10
- py2docfx/convert_prepare/generate_document.py +6 -6
- py2docfx/convert_prepare/get_source.py +7 -7
- py2docfx/convert_prepare/git.py +10 -13
- py2docfx/convert_prepare/install_package.py +2 -2
- py2docfx/convert_prepare/pack.py +7 -10
- py2docfx/convert_prepare/package_info.py +3 -3
- py2docfx/convert_prepare/pip_utils.py +12 -14
- py2docfx/convert_prepare/post_process/merge_toc.py +3 -2
- py2docfx/convert_prepare/sphinx_caller.py +34 -12
- py2docfx/convert_prepare/tests/test_environment.py +0 -3
- py2docfx/convert_prepare/tests/test_generate_document.py +4 -2
- py2docfx/convert_prepare/tests/test_get_source.py +22 -14
- py2docfx/convert_prepare/tests/test_pack.py +6 -3
- py2docfx/convert_prepare/tests/test_params.py +0 -1
- py2docfx/convert_prepare/tests/test_sphinx_caller.py +10 -8
- py2docfx/convert_prepare/tests/test_subpackage.py +1 -0
- py2docfx/docfx_yaml/build_finished.py +1 -1
- py2docfx/docfx_yaml/logger.py +56 -55
- py2docfx/venv/venv1/Lib/site-packages/azure/identity/_credentials/authorization_code.py +1 -1
- py2docfx/venv/venv1/Lib/site-packages/azure/identity/_credentials/azd_cli.py +20 -14
- py2docfx/venv/venv1/Lib/site-packages/azure/identity/_credentials/azure_arc.py +1 -1
- py2docfx/venv/venv1/Lib/site-packages/azure/identity/_credentials/azure_cli.py +36 -14
- py2docfx/venv/venv1/Lib/site-packages/azure/identity/_credentials/azure_powershell.py +1 -1
- py2docfx/venv/venv1/Lib/site-packages/azure/identity/_credentials/chained.py +2 -2
- py2docfx/venv/venv1/Lib/site-packages/azure/identity/_credentials/default.py +4 -3
- py2docfx/venv/venv1/Lib/site-packages/azure/identity/_credentials/imds.py +2 -2
- py2docfx/venv/venv1/Lib/site-packages/azure/identity/_credentials/managed_identity.py +1 -1
- py2docfx/venv/venv1/Lib/site-packages/azure/identity/_internal/__init__.py +2 -0
- py2docfx/venv/venv1/Lib/site-packages/azure/identity/_internal/auth_code_redirect_handler.py +1 -1
- py2docfx/venv/venv1/Lib/site-packages/azure/identity/_internal/decorators.py +15 -7
- py2docfx/venv/venv1/Lib/site-packages/azure/identity/_internal/interactive.py +1 -1
- py2docfx/venv/venv1/Lib/site-packages/azure/identity/_internal/managed_identity_client.py +0 -1
- py2docfx/venv/venv1/Lib/site-packages/azure/identity/_internal/msal_client.py +1 -1
- py2docfx/venv/venv1/Lib/site-packages/azure/identity/_internal/msal_managed_identity_client.py +2 -1
- py2docfx/venv/venv1/Lib/site-packages/azure/identity/_internal/shared_token_cache.py +3 -3
- py2docfx/venv/venv1/Lib/site-packages/azure/identity/_internal/utils.py +17 -2
- py2docfx/venv/venv1/Lib/site-packages/azure/identity/_version.py +1 -1
- py2docfx/venv/venv1/Lib/site-packages/azure/identity/aio/_credentials/azd_cli.py +14 -11
- py2docfx/venv/venv1/Lib/site-packages/azure/identity/aio/_credentials/azure_cli.py +30 -12
- py2docfx/venv/venv1/Lib/site-packages/azure/identity/aio/_credentials/default.py +2 -2
- py2docfx/venv/venv1/Lib/site-packages/azure/identity/aio/_credentials/imds.py +3 -3
- py2docfx/venv/venv1/Lib/site-packages/azure/identity/aio/_credentials/managed_identity.py +1 -1
- py2docfx/venv/venv1/Lib/site-packages/azure/identity/aio/_internal/decorators.py +15 -7
- py2docfx/venv/venv1/Lib/site-packages/azure/identity/aio/_internal/managed_identity_client.py +1 -1
- py2docfx/venv/venv1/Lib/site-packages/cryptography/__about__.py +1 -1
- py2docfx/venv/venv1/Lib/site-packages/google/api/annotations_pb2.py +7 -4
- py2docfx/venv/venv1/Lib/site-packages/google/api/auth_pb2.py +6 -3
- py2docfx/venv/venv1/Lib/site-packages/google/api/backend_pb2.py +14 -7
- py2docfx/venv/venv1/Lib/site-packages/google/api/billing_pb2.py +6 -3
- py2docfx/venv/venv1/Lib/site-packages/google/api/client_pb2.py +47 -38
- py2docfx/venv/venv1/Lib/site-packages/google/api/config_change_pb2.py +6 -3
- py2docfx/venv/venv1/Lib/site-packages/google/api/consumer_pb2.py +6 -3
- py2docfx/venv/venv1/Lib/site-packages/google/api/context_pb2.py +6 -3
- py2docfx/venv/venv1/Lib/site-packages/google/api/control_pb2.py +6 -4
- py2docfx/venv/venv1/Lib/site-packages/google/api/distribution_pb2.py +7 -5
- py2docfx/venv/venv1/Lib/site-packages/google/api/documentation_pb2.py +6 -3
- py2docfx/venv/venv1/Lib/site-packages/google/api/endpoint_pb2.py +6 -3
- py2docfx/venv/venv1/Lib/site-packages/google/api/error_reason_pb2.py +6 -3
- py2docfx/venv/venv1/Lib/site-packages/google/api/field_behavior_pb2.py +8 -6
- py2docfx/venv/venv1/Lib/site-packages/google/api/field_info_pb2.py +6 -4
- py2docfx/venv/venv1/Lib/site-packages/google/api/http_pb2.py +7 -4
- py2docfx/venv/venv1/Lib/site-packages/google/api/httpbody_pb2.py +6 -4
- py2docfx/venv/venv1/Lib/site-packages/google/api/label_pb2.py +7 -4
- py2docfx/venv/venv1/Lib/site-packages/google/api/launch_stage_pb2.py +6 -3
- py2docfx/venv/venv1/Lib/site-packages/google/api/log_pb2.py +6 -4
- py2docfx/venv/venv1/Lib/site-packages/google/api/logging_pb2.py +6 -3
- py2docfx/venv/venv1/Lib/site-packages/google/api/metric_pb2.py +12 -9
- py2docfx/venv/venv1/Lib/site-packages/google/api/monitored_resource_pb2.py +15 -10
- py2docfx/venv/venv1/Lib/site-packages/google/api/monitoring_pb2.py +6 -3
- py2docfx/venv/venv1/Lib/site-packages/google/api/policy_pb2.py +7 -5
- py2docfx/venv/venv1/Lib/site-packages/google/api/quota_pb2.py +10 -7
- py2docfx/venv/venv1/Lib/site-packages/google/api/resource_pb2.py +7 -5
- py2docfx/venv/venv1/Lib/site-packages/google/api/routing_pb2.py +6 -4
- py2docfx/venv/venv1/Lib/site-packages/google/api/service_pb2.py +15 -12
- py2docfx/venv/venv1/Lib/site-packages/google/api/source_info_pb2.py +6 -4
- py2docfx/venv/venv1/Lib/site-packages/google/api/system_parameter_pb2.py +6 -3
- py2docfx/venv/venv1/Lib/site-packages/google/api/usage_pb2.py +6 -3
- py2docfx/venv/venv1/Lib/site-packages/google/api/visibility_pb2.py +7 -5
- py2docfx/venv/venv1/Lib/site-packages/google/cloud/extended_operations_pb2.py +6 -4
- py2docfx/venv/venv1/Lib/site-packages/google/cloud/location/locations_pb2.py +18 -13
- py2docfx/venv/venv1/Lib/site-packages/google/gapic/metadata/gapic_metadata_pb2.py +31 -26
- py2docfx/venv/venv1/Lib/site-packages/google/logging/type/http_request_pb2.py +6 -4
- py2docfx/venv/venv1/Lib/site-packages/google/logging/type/log_severity_pb2.py +6 -3
- py2docfx/venv/venv1/Lib/site-packages/google/longrunning/operations_grpc.py +2 -1
- py2docfx/venv/venv1/Lib/site-packages/google/longrunning/operations_grpc_pb2.py +11 -10
- py2docfx/venv/venv1/Lib/site-packages/google/longrunning/operations_pb2.py +20 -17
- py2docfx/venv/venv1/Lib/site-packages/google/longrunning/operations_pb2_grpc.py +1 -2
- py2docfx/venv/venv1/Lib/site-packages/google/longrunning/operations_proto.py +2 -1
- py2docfx/venv/venv1/Lib/site-packages/google/longrunning/operations_proto_pb2.py +22 -19
- py2docfx/venv/venv1/Lib/site-packages/google/rpc/code_pb2.py +6 -3
- py2docfx/venv/venv1/Lib/site-packages/google/rpc/context/attribute_context_pb2.py +20 -16
- py2docfx/venv/venv1/Lib/site-packages/google/rpc/context/audit_context_pb2.py +7 -5
- py2docfx/venv/venv1/Lib/site-packages/google/rpc/error_details_pb2.py +21 -19
- py2docfx/venv/venv1/Lib/site-packages/google/rpc/http_pb2.py +6 -3
- py2docfx/venv/venv1/Lib/site-packages/google/rpc/status_pb2.py +6 -4
- py2docfx/venv/venv1/Lib/site-packages/google/type/calendar_period_pb2.py +6 -3
- py2docfx/venv/venv1/Lib/site-packages/google/type/color_pb2.py +6 -4
- py2docfx/venv/venv1/Lib/site-packages/google/type/date_pb2.py +6 -3
- py2docfx/venv/venv1/Lib/site-packages/google/type/datetime_pb2.py +6 -4
- py2docfx/venv/venv1/Lib/site-packages/google/type/dayofweek_pb2.py +6 -3
- py2docfx/venv/venv1/Lib/site-packages/google/type/decimal_pb2.py +6 -3
- py2docfx/venv/venv1/Lib/site-packages/google/type/expr_pb2.py +6 -3
- py2docfx/venv/venv1/Lib/site-packages/google/type/fraction_pb2.py +6 -3
- py2docfx/venv/venv1/Lib/site-packages/google/type/interval_pb2.py +6 -4
- py2docfx/venv/venv1/Lib/site-packages/google/type/latlng_pb2.py +6 -3
- py2docfx/venv/venv1/Lib/site-packages/google/type/localized_text_pb2.py +6 -3
- py2docfx/venv/venv1/Lib/site-packages/google/type/money_pb2.py +6 -3
- py2docfx/venv/venv1/Lib/site-packages/google/type/month_pb2.py +6 -3
- py2docfx/venv/venv1/Lib/site-packages/google/type/phone_number_pb2.py +6 -3
- py2docfx/venv/venv1/Lib/site-packages/google/type/postal_address_pb2.py +6 -3
- py2docfx/venv/venv1/Lib/site-packages/google/type/quaternion_pb2.py +6 -3
- py2docfx/venv/venv1/Lib/site-packages/google/type/timeofday_pb2.py +6 -3
- py2docfx/venv/venv1/Lib/site-packages/psutil/__init__.py +122 -201
- py2docfx/venv/venv1/Lib/site-packages/psutil/_common.py +84 -128
- py2docfx/venv/venv1/Lib/site-packages/psutil/_psaix.py +24 -38
- py2docfx/venv/venv1/Lib/site-packages/psutil/_psbsd.py +44 -58
- py2docfx/venv/venv1/Lib/site-packages/psutil/_pslinux.py +170 -254
- py2docfx/venv/venv1/Lib/site-packages/psutil/_psosx.py +8 -16
- py2docfx/venv/venv1/Lib/site-packages/psutil/_psposix.py +13 -49
- py2docfx/venv/venv1/Lib/site-packages/psutil/_pssunos.py +41 -60
- py2docfx/venv/venv1/Lib/site-packages/psutil/_pswindows.py +75 -145
- py2docfx/venv/venv1/Lib/site-packages/psutil/tests/__init__.py +105 -193
- py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_aix.py +2 -2
- py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_bsd.py +27 -26
- py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_connections.py +16 -17
- py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_contracts.py +5 -19
- py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_linux.py +153 -211
- py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_memleaks.py +0 -6
- py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_misc.py +22 -207
- py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_osx.py +9 -4
- py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_posix.py +8 -15
- py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_process.py +104 -184
- py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_process_all.py +28 -36
- py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_scripts.py +240 -0
- py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_sunos.py +1 -1
- py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_system.py +44 -50
- py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_testutils.py +23 -33
- py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_unicode.py +8 -67
- py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_windows.py +32 -52
- {py2docfx-0.1.11rc1981066.dist-info → py2docfx-0.1.11rc1997820.dist-info}/METADATA +1 -1
- {py2docfx-0.1.11rc1981066.dist-info → py2docfx-0.1.11rc1997820.dist-info}/RECORD +145 -145
- py2docfx/venv/venv1/Lib/site-packages/psutil/_compat.py +0 -477
- {py2docfx-0.1.11rc1981066.dist-info → py2docfx-0.1.11rc1997820.dist-info}/WHEEL +0 -0
- {py2docfx-0.1.11rc1981066.dist-info → py2docfx-0.1.11rc1997820.dist-info}/top_level.txt +0 -0
@@ -4,15 +4,16 @@
|
|
4
4
|
|
5
5
|
"""Linux platform implementation."""
|
6
6
|
|
7
|
-
from __future__ import division
|
8
7
|
|
9
8
|
import base64
|
10
9
|
import collections
|
10
|
+
import enum
|
11
11
|
import errno
|
12
12
|
import functools
|
13
13
|
import glob
|
14
14
|
import os
|
15
15
|
import re
|
16
|
+
import resource
|
16
17
|
import socket
|
17
18
|
import struct
|
18
19
|
import sys
|
@@ -24,6 +25,7 @@ from . import _common
|
|
24
25
|
from . import _psposix
|
25
26
|
from . import _psutil_linux as cext
|
26
27
|
from . import _psutil_posix as cext_posix
|
28
|
+
from ._common import ENCODING
|
27
29
|
from ._common import NIC_DUPLEX_FULL
|
28
30
|
from ._common import NIC_DUPLEX_HALF
|
29
31
|
from ._common import NIC_DUPLEX_UNKNOWN
|
@@ -44,18 +46,6 @@ from ._common import parse_environ_block
|
|
44
46
|
from ._common import path_exists_strict
|
45
47
|
from ._common import supports_ipv6
|
46
48
|
from ._common import usage_percent
|
47
|
-
from ._compat import PY3
|
48
|
-
from ._compat import FileNotFoundError
|
49
|
-
from ._compat import PermissionError
|
50
|
-
from ._compat import ProcessLookupError
|
51
|
-
from ._compat import b
|
52
|
-
from ._compat import basestring
|
53
|
-
|
54
|
-
|
55
|
-
if PY3:
|
56
|
-
import enum
|
57
|
-
else:
|
58
|
-
enum = None
|
59
49
|
|
60
50
|
|
61
51
|
# fmt: off
|
@@ -69,6 +59,11 @@ __extra__all__ = [
|
|
69
59
|
"CONN_FIN_WAIT2", "CONN_TIME_WAIT", "CONN_CLOSE", "CONN_CLOSE_WAIT",
|
70
60
|
"CONN_LAST_ACK", "CONN_LISTEN", "CONN_CLOSING",
|
71
61
|
]
|
62
|
+
|
63
|
+
if hasattr(resource, "prlimit"):
|
64
|
+
__extra__all__.extend(
|
65
|
+
[x for x in dir(cext) if x.startswith('RLIM') and x.isupper()]
|
66
|
+
)
|
72
67
|
# fmt: on
|
73
68
|
|
74
69
|
|
@@ -78,8 +73,8 @@ __extra__all__ = [
|
|
78
73
|
|
79
74
|
|
80
75
|
POWER_SUPPLY_PATH = "/sys/class/power_supply"
|
81
|
-
HAS_PROC_SMAPS = os.path.exists(
|
82
|
-
HAS_PROC_SMAPS_ROLLUP = os.path.exists(
|
76
|
+
HAS_PROC_SMAPS = os.path.exists(f"/proc/{os.getpid()}/smaps")
|
77
|
+
HAS_PROC_SMAPS_ROLLUP = os.path.exists(f"/proc/{os.getpid()}/smaps_rollup")
|
83
78
|
HAS_PROC_IO_PRIORITY = hasattr(cext, "proc_ioprio_get")
|
84
79
|
HAS_CPU_AFFINITY = hasattr(cext, "proc_cpu_affinity_get")
|
85
80
|
|
@@ -102,29 +97,21 @@ LITTLE_ENDIAN = sys.byteorder == 'little'
|
|
102
97
|
# * https://lkml.org/lkml/2015/8/17/234
|
103
98
|
DISK_SECTOR_SIZE = 512
|
104
99
|
|
105
|
-
|
106
|
-
AF_LINK
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
)
|
111
|
-
AF_LINK = AddressFamily.AF_LINK
|
100
|
+
AddressFamily = enum.IntEnum(
|
101
|
+
'AddressFamily', {'AF_LINK': int(socket.AF_PACKET)}
|
102
|
+
)
|
103
|
+
AF_LINK = AddressFamily.AF_LINK
|
104
|
+
|
112
105
|
|
113
106
|
# ioprio_* constants http://linux.die.net/man/2/ioprio_get
|
114
|
-
|
107
|
+
class IOPriority(enum.IntEnum):
|
115
108
|
IOPRIO_CLASS_NONE = 0
|
116
109
|
IOPRIO_CLASS_RT = 1
|
117
110
|
IOPRIO_CLASS_BE = 2
|
118
111
|
IOPRIO_CLASS_IDLE = 3
|
119
|
-
else:
|
120
112
|
|
121
|
-
class IOPriority(enum.IntEnum):
|
122
|
-
IOPRIO_CLASS_NONE = 0
|
123
|
-
IOPRIO_CLASS_RT = 1
|
124
|
-
IOPRIO_CLASS_BE = 2
|
125
|
-
IOPRIO_CLASS_IDLE = 3
|
126
113
|
|
127
|
-
|
114
|
+
globals().update(IOPriority.__members__)
|
128
115
|
|
129
116
|
# See:
|
130
117
|
# https://github.com/torvalds/linux/blame/master/fs/proc/array.c
|
@@ -211,7 +198,7 @@ pcputimes = namedtuple('pcputimes',
|
|
211
198
|
|
212
199
|
def readlink(path):
|
213
200
|
"""Wrapper around os.readlink()."""
|
214
|
-
assert isinstance(path,
|
201
|
+
assert isinstance(path, str), path
|
215
202
|
path = os.readlink(path)
|
216
203
|
# readlink() might return paths containing null bytes ('\x00')
|
217
204
|
# resulting in "TypeError: must be encoded string without NULL
|
@@ -255,9 +242,9 @@ def is_storage_device(name):
|
|
255
242
|
name = name.replace('/', '!')
|
256
243
|
including_virtual = True
|
257
244
|
if including_virtual:
|
258
|
-
path = "/sys/block
|
245
|
+
path = f"/sys/block/{name}"
|
259
246
|
else:
|
260
|
-
path = "/sys/block
|
247
|
+
path = f"/sys/block/{name}/device"
|
261
248
|
return os.access(path, os.F_OK)
|
262
249
|
|
263
250
|
|
@@ -270,7 +257,7 @@ def set_scputimes_ntuple(procfs_path):
|
|
270
257
|
Used by cpu_times() function.
|
271
258
|
"""
|
272
259
|
global scputimes
|
273
|
-
with open_binary(
|
260
|
+
with open_binary(f"{procfs_path}/stat") as f:
|
274
261
|
values = f.readline().split()[1:]
|
275
262
|
fields = ['user', 'nice', 'system', 'idle', 'iowait', 'irq', 'softirq']
|
276
263
|
vlen = len(values)
|
@@ -290,62 +277,10 @@ try:
|
|
290
277
|
set_scputimes_ntuple("/proc")
|
291
278
|
except Exception as err: # noqa: BLE001
|
292
279
|
# Don't want to crash at import time.
|
293
|
-
debug("ignoring exception on import:
|
280
|
+
debug(f"ignoring exception on import: {err!r}")
|
294
281
|
scputimes = namedtuple('scputimes', 'user system idle')(0.0, 0.0, 0.0)
|
295
282
|
|
296
283
|
|
297
|
-
# =====================================================================
|
298
|
-
# --- prlimit
|
299
|
-
# =====================================================================
|
300
|
-
|
301
|
-
# Backport of resource.prlimit() for Python 2. Originally this was done
|
302
|
-
# in C, but CentOS-6 which we use to create manylinux wheels is too old
|
303
|
-
# and does not support prlimit() syscall. As such the resulting wheel
|
304
|
-
# would not include prlimit(), even when installed on newer systems.
|
305
|
-
# This is the only part of psutil using ctypes.
|
306
|
-
|
307
|
-
prlimit = None
|
308
|
-
try:
|
309
|
-
from resource import prlimit # python >= 3.4
|
310
|
-
except ImportError:
|
311
|
-
import ctypes
|
312
|
-
|
313
|
-
libc = ctypes.CDLL(None, use_errno=True)
|
314
|
-
|
315
|
-
if hasattr(libc, "prlimit"):
|
316
|
-
|
317
|
-
def prlimit(pid, resource_, limits=None):
|
318
|
-
class StructRlimit(ctypes.Structure):
|
319
|
-
_fields_ = [
|
320
|
-
('rlim_cur', ctypes.c_longlong),
|
321
|
-
('rlim_max', ctypes.c_longlong),
|
322
|
-
]
|
323
|
-
|
324
|
-
current = StructRlimit()
|
325
|
-
if limits is None:
|
326
|
-
# get
|
327
|
-
ret = libc.prlimit(pid, resource_, None, ctypes.byref(current))
|
328
|
-
else:
|
329
|
-
# set
|
330
|
-
new = StructRlimit()
|
331
|
-
new.rlim_cur = limits[0]
|
332
|
-
new.rlim_max = limits[1]
|
333
|
-
ret = libc.prlimit(
|
334
|
-
pid, resource_, ctypes.byref(new), ctypes.byref(current)
|
335
|
-
)
|
336
|
-
|
337
|
-
if ret != 0:
|
338
|
-
errno_ = ctypes.get_errno()
|
339
|
-
raise OSError(errno_, os.strerror(errno_))
|
340
|
-
return (current.rlim_cur, current.rlim_max)
|
341
|
-
|
342
|
-
|
343
|
-
if prlimit is not None:
|
344
|
-
__extra__all__.extend(
|
345
|
-
[x for x in dir(cext) if x.startswith('RLIM') and x.isupper()]
|
346
|
-
)
|
347
|
-
|
348
|
-
|
349
284
|
# =====================================================================
|
350
285
|
# --- system memory
|
351
286
|
# =====================================================================
|
@@ -389,14 +324,13 @@ def calculate_avail_vmem(mems):
|
|
389
324
|
slab_reclaimable = mems[b'SReclaimable:']
|
390
325
|
except KeyError as err:
|
391
326
|
debug(
|
392
|
-
"
|
393
|
-
"calculating available memory"
|
394
|
-
% err.args[0]
|
327
|
+
f"{err.args[0]} is missing from /proc/meminfo; using an"
|
328
|
+
" approximation for calculating available memory"
|
395
329
|
)
|
396
330
|
return fallback
|
397
331
|
try:
|
398
|
-
f = open_binary(
|
399
|
-
except
|
332
|
+
f = open_binary(f"{get_procfs_path()}/zoneinfo")
|
333
|
+
except OSError:
|
400
334
|
return fallback # kernel 2.6.13
|
401
335
|
|
402
336
|
watermark_low = 0
|
@@ -425,7 +359,7 @@ def virtual_memory():
|
|
425
359
|
"""
|
426
360
|
missing_fields = []
|
427
361
|
mems = {}
|
428
|
-
with open_binary(
|
362
|
+
with open_binary(f"{get_procfs_path()}/meminfo") as f:
|
429
363
|
for line in f:
|
430
364
|
fields = line.split()
|
431
365
|
mems[fields[0]] = int(fields[1]) * 1024
|
@@ -527,7 +461,7 @@ def virtual_memory():
|
|
527
461
|
|
528
462
|
# Warn about missing metrics which are set to 0.
|
529
463
|
if missing_fields:
|
530
|
-
msg = "
|
464
|
+
msg = "{} memory stats couldn't be determined and {} set to 0".format(
|
531
465
|
", ".join(missing_fields),
|
532
466
|
"was" if len(missing_fields) == 1 else "were",
|
533
467
|
)
|
@@ -551,7 +485,7 @@ def virtual_memory():
|
|
551
485
|
def swap_memory():
|
552
486
|
"""Return swap memory metrics."""
|
553
487
|
mems = {}
|
554
|
-
with open_binary(
|
488
|
+
with open_binary(f"{get_procfs_path()}/meminfo") as f:
|
555
489
|
for line in f:
|
556
490
|
fields = line.split()
|
557
491
|
mems[fields[0]] = int(fields[1]) * 1024
|
@@ -571,12 +505,12 @@ def swap_memory():
|
|
571
505
|
percent = usage_percent(used, total, round_=1)
|
572
506
|
# get pgin/pgouts
|
573
507
|
try:
|
574
|
-
f = open_binary("
|
575
|
-
except
|
508
|
+
f = open_binary(f"{get_procfs_path()}/vmstat")
|
509
|
+
except OSError as err:
|
576
510
|
# see https://github.com/giampaolo/psutil/issues/722
|
577
511
|
msg = (
|
578
512
|
"'sin' and 'sout' swap memory stats couldn't "
|
579
|
-
|
513
|
+
f"be determined and were set to 0 ({err})"
|
580
514
|
)
|
581
515
|
warnings.warn(msg, RuntimeWarning, stacklevel=2)
|
582
516
|
sin = sout = 0
|
@@ -617,7 +551,7 @@ def cpu_times():
|
|
617
551
|
"""
|
618
552
|
procfs_path = get_procfs_path()
|
619
553
|
set_scputimes_ntuple(procfs_path)
|
620
|
-
with open_binary(
|
554
|
+
with open_binary(f"{procfs_path}/stat") as f:
|
621
555
|
values = f.readline().split()
|
622
556
|
fields = values[1 : len(scputimes._fields) + 1]
|
623
557
|
fields = [float(x) / CLOCK_TICKS for x in fields]
|
@@ -631,7 +565,7 @@ def per_cpu_times():
|
|
631
565
|
procfs_path = get_procfs_path()
|
632
566
|
set_scputimes_ntuple(procfs_path)
|
633
567
|
cpus = []
|
634
|
-
with open_binary(
|
568
|
+
with open_binary(f"{procfs_path}/stat") as f:
|
635
569
|
# get rid of the first line which refers to system wide CPU stats
|
636
570
|
f.readline()
|
637
571
|
for line in f:
|
@@ -651,7 +585,7 @@ def cpu_count_logical():
|
|
651
585
|
except ValueError:
|
652
586
|
# as a second fallback we try to parse /proc/cpuinfo
|
653
587
|
num = 0
|
654
|
-
with open_binary(
|
588
|
+
with open_binary(f"{get_procfs_path()}/cpuinfo") as f:
|
655
589
|
for line in f:
|
656
590
|
if line.lower().startswith(b'processor'):
|
657
591
|
num += 1
|
@@ -661,7 +595,7 @@ def cpu_count_logical():
|
|
661
595
|
# try to parse /proc/stat as a last resort
|
662
596
|
if num == 0:
|
663
597
|
search = re.compile(r'cpu\d')
|
664
|
-
with open_text(
|
598
|
+
with open_text(f"{get_procfs_path()}/stat") as f:
|
665
599
|
for line in f:
|
666
600
|
line = line.split(' ')[0]
|
667
601
|
if search.match(line):
|
@@ -694,7 +628,7 @@ def cpu_count_cores():
|
|
694
628
|
# Method #2
|
695
629
|
mapping = {}
|
696
630
|
current_info = {}
|
697
|
-
with open_binary(
|
631
|
+
with open_binary(f"{get_procfs_path()}/cpuinfo") as f:
|
698
632
|
for line in f:
|
699
633
|
line = line.strip().lower()
|
700
634
|
if not line:
|
@@ -717,7 +651,7 @@ def cpu_count_cores():
|
|
717
651
|
|
718
652
|
def cpu_stats():
|
719
653
|
"""Return various CPU stats as a named tuple."""
|
720
|
-
with open_binary(
|
654
|
+
with open_binary(f"{get_procfs_path()}/stat") as f:
|
721
655
|
ctx_switches = None
|
722
656
|
interrupts = None
|
723
657
|
soft_interrupts = None
|
@@ -742,12 +676,12 @@ def cpu_stats():
|
|
742
676
|
|
743
677
|
def _cpu_get_cpuinfo_freq():
|
744
678
|
"""Return current CPU frequency from cpuinfo if available."""
|
745
|
-
|
746
|
-
|
747
|
-
|
748
|
-
|
749
|
-
|
750
|
-
|
679
|
+
with open_binary(f"{get_procfs_path()}/cpuinfo") as f:
|
680
|
+
return [
|
681
|
+
float(line.split(b':', 1)[1])
|
682
|
+
for line in f
|
683
|
+
if line.lower().startswith(b'cpu mhz')
|
684
|
+
]
|
751
685
|
|
752
686
|
|
753
687
|
if os.path.exists("/sys/devices/system/cpu/cpufreq/policy0") or os.path.exists(
|
@@ -778,9 +712,7 @@ if os.path.exists("/sys/devices/system/cpu/cpufreq/policy0") or os.path.exists(
|
|
778
712
|
# https://github.com/giampaolo/psutil/issues/1071
|
779
713
|
curr = bcat(pjoin(path, "cpuinfo_cur_freq"), fallback=None)
|
780
714
|
if curr is None:
|
781
|
-
online_path =
|
782
|
-
"/sys/devices/system/cpu/cpu{}/online".format(i)
|
783
|
-
)
|
715
|
+
online_path = f"/sys/devices/system/cpu/cpu{i}/online"
|
784
716
|
# if cpu core is offline, set to all zeroes
|
785
717
|
if cat(online_path, fallback=None) == "0\n":
|
786
718
|
ret.append(_common.scpufreq(0.0, 0.0, 0.0))
|
@@ -851,12 +783,12 @@ class NetConnections:
|
|
851
783
|
|
852
784
|
def get_proc_inodes(self, pid):
|
853
785
|
inodes = defaultdict(list)
|
854
|
-
for fd in os.listdir("
|
786
|
+
for fd in os.listdir(f"{self._procfs_path}/{pid}/fd"):
|
855
787
|
try:
|
856
|
-
inode = readlink("
|
788
|
+
inode = readlink(f"{self._procfs_path}/{pid}/fd/{fd}")
|
857
789
|
except (FileNotFoundError, ProcessLookupError):
|
858
790
|
# ENOENT == file which is gone in the meantime;
|
859
|
-
# os.stat(
|
791
|
+
# os.stat(f"/proc/{self.pid}") will be done later
|
860
792
|
# to force NSP (if it's the case)
|
861
793
|
continue
|
862
794
|
except OSError as err:
|
@@ -914,8 +846,7 @@ class NetConnections:
|
|
914
846
|
# no end-points connected
|
915
847
|
if not port:
|
916
848
|
return ()
|
917
|
-
|
918
|
-
ip = ip.encode('ascii')
|
849
|
+
ip = ip.encode('ascii')
|
919
850
|
if family == socket.AF_INET:
|
920
851
|
# see: https://github.com/giampaolo/psutil/issues/201
|
921
852
|
if LITTLE_ENDIAN:
|
@@ -939,9 +870,8 @@ class NetConnections:
|
|
939
870
|
except ValueError:
|
940
871
|
# see: https://github.com/giampaolo/psutil/issues/623
|
941
872
|
if not supports_ipv6():
|
942
|
-
raise _Ipv6UnsupportedError
|
943
|
-
|
944
|
-
raise
|
873
|
+
raise _Ipv6UnsupportedError from None
|
874
|
+
raise
|
945
875
|
return _common.addr(ip, port)
|
946
876
|
|
947
877
|
@staticmethod
|
@@ -958,10 +888,11 @@ class NetConnections:
|
|
958
888
|
line.split()[:10]
|
959
889
|
)
|
960
890
|
except ValueError:
|
961
|
-
|
962
|
-
"error while parsing
|
963
|
-
|
891
|
+
msg = (
|
892
|
+
f"error while parsing {file}; malformed line"
|
893
|
+
f" {lineno} {line!r}"
|
964
894
|
)
|
895
|
+
raise RuntimeError(msg) from None
|
965
896
|
if inode in inodes:
|
966
897
|
# # We assume inet sockets are unique, so we error
|
967
898
|
# # out if there are multiple references to the
|
@@ -999,11 +930,11 @@ class NetConnections:
|
|
999
930
|
if ' ' not in line:
|
1000
931
|
# see: https://github.com/giampaolo/psutil/issues/766
|
1001
932
|
continue
|
1002
|
-
|
1003
|
-
"error while parsing
|
1004
|
-
% (file, line)
|
933
|
+
msg = (
|
934
|
+
f"error while parsing {file}; malformed line {line!r}"
|
1005
935
|
)
|
1006
|
-
|
936
|
+
raise RuntimeError(msg) # noqa: B904
|
937
|
+
if inode in inodes: # noqa: SIM108
|
1007
938
|
# With UNIX sockets we can have a single inode
|
1008
939
|
# referencing many file descriptors.
|
1009
940
|
pairs = inodes[inode]
|
@@ -1023,11 +954,6 @@ class NetConnections:
|
|
1023
954
|
yield (fd, family, type_, path, raddr, status, pid)
|
1024
955
|
|
1025
956
|
def retrieve(self, kind, pid=None):
|
1026
|
-
if kind not in self.tmap:
|
1027
|
-
raise ValueError(
|
1028
|
-
"invalid %r kind argument; choose between %s"
|
1029
|
-
% (kind, ', '.join([repr(x) for x in self.tmap]))
|
1030
|
-
)
|
1031
957
|
self._procfs_path = get_procfs_path()
|
1032
958
|
if pid is not None:
|
1033
959
|
inodes = self.get_proc_inodes(pid)
|
@@ -1038,7 +964,7 @@ class NetConnections:
|
|
1038
964
|
inodes = self.get_all_inodes()
|
1039
965
|
ret = set()
|
1040
966
|
for proto_name, family, type_ in self.tmap[kind]:
|
1041
|
-
path = "
|
967
|
+
path = f"{self._procfs_path}/net/{proto_name}"
|
1042
968
|
if family in {socket.AF_INET, socket.AF_INET6}:
|
1043
969
|
ls = self.process_inet(
|
1044
970
|
path, family, type_, inodes, filter_pid=pid
|
@@ -1070,7 +996,7 @@ def net_io_counters():
|
|
1070
996
|
"""Return network I/O statistics for every network interface
|
1071
997
|
installed on the system as a dict of raw tuples.
|
1072
998
|
"""
|
1073
|
-
with open_text("
|
999
|
+
with open_text(f"{get_procfs_path()}/net/dev") as f:
|
1074
1000
|
lines = f.readlines()
|
1075
1001
|
retdict = {}
|
1076
1002
|
for line in lines[2:]:
|
@@ -1131,8 +1057,7 @@ def net_if_stats():
|
|
1131
1057
|
# https://github.com/giampaolo/psutil/issues/1279
|
1132
1058
|
if err.errno != errno.ENODEV:
|
1133
1059
|
raise
|
1134
|
-
|
1135
|
-
debug(err)
|
1060
|
+
debug(err)
|
1136
1061
|
else:
|
1137
1062
|
output_flags = ','.join(flags)
|
1138
1063
|
isup = 'running' in flags
|
@@ -1172,7 +1097,7 @@ def disk_io_counters(perdisk=False):
|
|
1172
1097
|
# See:
|
1173
1098
|
# https://www.kernel.org/doc/Documentation/iostats.txt
|
1174
1099
|
# https://www.kernel.org/doc/Documentation/ABI/testing/procfs-diskstats
|
1175
|
-
with open_text("
|
1100
|
+
with open_text(f"{get_procfs_path()}/diskstats") as f:
|
1176
1101
|
lines = f.readlines()
|
1177
1102
|
for line in lines:
|
1178
1103
|
fields = line.split()
|
@@ -1195,7 +1120,8 @@ def disk_io_counters(perdisk=False):
|
|
1195
1120
|
reads, rbytes, writes, wbytes = map(int, fields[3:])
|
1196
1121
|
rtime = wtime = reads_merged = writes_merged = busy_time = 0
|
1197
1122
|
else:
|
1198
|
-
|
1123
|
+
msg = f"not sure how to interpret line {line!r}"
|
1124
|
+
raise ValueError(msg)
|
1199
1125
|
yield (name, reads, writes, rbytes, wbytes, rtime, wtime,
|
1200
1126
|
reads_merged, writes_merged, busy_time)
|
1201
1127
|
# fmt: on
|
@@ -1215,16 +1141,16 @@ def disk_io_counters(perdisk=False):
|
|
1215
1141
|
wtime, reads_merged, writes_merged, busy_time)
|
1216
1142
|
# fmt: on
|
1217
1143
|
|
1218
|
-
if os.path.exists(
|
1144
|
+
if os.path.exists(f"{get_procfs_path()}/diskstats"):
|
1219
1145
|
gen = read_procfs()
|
1220
1146
|
elif os.path.exists('/sys/block'):
|
1221
1147
|
gen = read_sysfs()
|
1222
1148
|
else:
|
1223
|
-
|
1224
|
-
"
|
1225
|
-
"system"
|
1226
|
-
% get_procfs_path()
|
1149
|
+
msg = (
|
1150
|
+
f"{get_procfs_path()}/diskstats nor /sys/block are available on"
|
1151
|
+
" this system"
|
1227
1152
|
)
|
1153
|
+
raise NotImplementedError(msg)
|
1228
1154
|
|
1229
1155
|
retdict = {}
|
1230
1156
|
for entry in gen:
|
@@ -1270,7 +1196,7 @@ class RootFsDeviceFinder:
|
|
1270
1196
|
self.minor = os.minor(dev)
|
1271
1197
|
|
1272
1198
|
def ask_proc_partitions(self):
|
1273
|
-
with open_text("
|
1199
|
+
with open_text(f"{get_procfs_path()}/partitions") as f:
|
1274
1200
|
for line in f.readlines()[2:]:
|
1275
1201
|
fields = line.split()
|
1276
1202
|
if len(fields) < 4: # just for extra safety
|
@@ -1280,19 +1206,19 @@ class RootFsDeviceFinder:
|
|
1280
1206
|
name = fields[3]
|
1281
1207
|
if major == self.major and minor == self.minor:
|
1282
1208
|
if name: # just for extra safety
|
1283
|
-
return "/dev
|
1209
|
+
return f"/dev/{name}"
|
1284
1210
|
|
1285
1211
|
def ask_sys_dev_block(self):
|
1286
|
-
path = "/sys/dev/block
|
1212
|
+
path = f"/sys/dev/block/{self.major}:{self.minor}/uevent"
|
1287
1213
|
with open_text(path) as f:
|
1288
1214
|
for line in f:
|
1289
1215
|
if line.startswith("DEVNAME="):
|
1290
1216
|
name = line.strip().rpartition("DEVNAME=")[2]
|
1291
1217
|
if name: # just for extra safety
|
1292
|
-
return "/dev
|
1218
|
+
return f"/dev/{name}"
|
1293
1219
|
|
1294
1220
|
def ask_sys_class_block(self):
|
1295
|
-
needle = "
|
1221
|
+
needle = f"{self.major}:{self.minor}"
|
1296
1222
|
files = glob.iglob("/sys/class/block/*/dev")
|
1297
1223
|
for file in files:
|
1298
1224
|
try:
|
@@ -1304,24 +1230,24 @@ class RootFsDeviceFinder:
|
|
1304
1230
|
data = f.read().strip()
|
1305
1231
|
if data == needle:
|
1306
1232
|
name = os.path.basename(os.path.dirname(file))
|
1307
|
-
return "/dev
|
1233
|
+
return f"/dev/{name}"
|
1308
1234
|
|
1309
1235
|
def find(self):
|
1310
1236
|
path = None
|
1311
1237
|
if path is None:
|
1312
1238
|
try:
|
1313
1239
|
path = self.ask_proc_partitions()
|
1314
|
-
except
|
1240
|
+
except OSError as err:
|
1315
1241
|
debug(err)
|
1316
1242
|
if path is None:
|
1317
1243
|
try:
|
1318
1244
|
path = self.ask_sys_dev_block()
|
1319
|
-
except
|
1245
|
+
except OSError as err:
|
1320
1246
|
debug(err)
|
1321
1247
|
if path is None:
|
1322
1248
|
try:
|
1323
1249
|
path = self.ask_sys_class_block()
|
1324
|
-
except
|
1250
|
+
except OSError as err:
|
1325
1251
|
debug(err)
|
1326
1252
|
# We use exists() because the "/dev/*" part of the path is hard
|
1327
1253
|
# coded, so we want to be sure.
|
@@ -1334,7 +1260,7 @@ def disk_partitions(all=False):
|
|
1334
1260
|
fstypes = set()
|
1335
1261
|
procfs_path = get_procfs_path()
|
1336
1262
|
if not all:
|
1337
|
-
with open_text("
|
1263
|
+
with open_text(f"{procfs_path}/filesystems") as f:
|
1338
1264
|
for line in f:
|
1339
1265
|
line = line.strip()
|
1340
1266
|
if not line.startswith("nodev"):
|
@@ -1349,7 +1275,7 @@ def disk_partitions(all=False):
|
|
1349
1275
|
if procfs_path == "/proc" and os.path.isfile('/etc/mtab'):
|
1350
1276
|
mounts_path = os.path.realpath("/etc/mtab")
|
1351
1277
|
else:
|
1352
|
-
mounts_path = os.path.realpath("
|
1278
|
+
mounts_path = os.path.realpath(f"{procfs_path}/self/mounts")
|
1353
1279
|
|
1354
1280
|
retlist = []
|
1355
1281
|
partitions = cext.disk_partitions(mounts_path)
|
@@ -1392,7 +1318,7 @@ def sensors_temperatures():
|
|
1392
1318
|
# https://github.com/giampaolo/psutil/issues/971
|
1393
1319
|
# https://github.com/nicolargo/glances/issues/1060
|
1394
1320
|
basenames.extend(glob.glob('/sys/class/hwmon/hwmon*/device/temp*_*'))
|
1395
|
-
basenames = sorted(
|
1321
|
+
basenames = sorted({x.split('_')[0] for x in basenames})
|
1396
1322
|
|
1397
1323
|
# Only add the coretemp hwmon entries if they're not already in
|
1398
1324
|
# /sys/class/hwmon/
|
@@ -1401,7 +1327,7 @@ def sensors_temperatures():
|
|
1401
1327
|
basenames2 = glob.glob(
|
1402
1328
|
'/sys/devices/platform/coretemp.*/hwmon/hwmon*/temp*_*'
|
1403
1329
|
)
|
1404
|
-
repl = re.compile(
|
1330
|
+
repl = re.compile(r"/sys/devices/platform/coretemp.*/hwmon/")
|
1405
1331
|
for name in basenames2:
|
1406
1332
|
altname = repl.sub('/sys/class/hwmon/', name)
|
1407
1333
|
if altname not in basenames:
|
@@ -1413,7 +1339,7 @@ def sensors_temperatures():
|
|
1413
1339
|
current = float(bcat(path)) / 1000.0
|
1414
1340
|
path = os.path.join(os.path.dirname(base), 'name')
|
1415
1341
|
unit_name = cat(path).strip()
|
1416
|
-
except (
|
1342
|
+
except (OSError, ValueError):
|
1417
1343
|
# A lot of things can go wrong here, so let's just skip the
|
1418
1344
|
# whole entry. Sure thing is Linux's /sys/class/hwmon really
|
1419
1345
|
# is a stinky broken mess.
|
@@ -1452,15 +1378,15 @@ def sensors_temperatures():
|
|
1452
1378
|
current = float(bcat(path)) / 1000.0
|
1453
1379
|
path = os.path.join(base, 'type')
|
1454
1380
|
unit_name = cat(path).strip()
|
1455
|
-
except (
|
1381
|
+
except (OSError, ValueError) as err:
|
1456
1382
|
debug(err)
|
1457
1383
|
continue
|
1458
1384
|
|
1459
1385
|
trip_paths = glob.glob(base + '/trip_point*')
|
1460
|
-
trip_points =
|
1386
|
+
trip_points = {
|
1461
1387
|
'_'.join(os.path.basename(p).split('_')[0:3])
|
1462
1388
|
for p in trip_paths
|
1463
|
-
|
1389
|
+
}
|
1464
1390
|
critical = None
|
1465
1391
|
high = None
|
1466
1392
|
for trip_point in trip_points:
|
@@ -1508,11 +1434,11 @@ def sensors_fans():
|
|
1508
1434
|
# https://github.com/giampaolo/psutil/issues/971
|
1509
1435
|
basenames = glob.glob('/sys/class/hwmon/hwmon*/device/fan*_*')
|
1510
1436
|
|
1511
|
-
basenames = sorted(
|
1437
|
+
basenames = sorted({x.split("_")[0] for x in basenames})
|
1512
1438
|
for base in basenames:
|
1513
1439
|
try:
|
1514
1440
|
current = int(bcat(base + '_input'))
|
1515
|
-
except
|
1441
|
+
except OSError as err:
|
1516
1442
|
debug(err)
|
1517
1443
|
continue
|
1518
1444
|
unit_name = cat(os.path.join(os.path.dirname(base), 'name')).strip()
|
@@ -1554,7 +1480,7 @@ def sensors_battery():
|
|
1554
1480
|
# Get the first available battery. Usually this is "BAT0", except
|
1555
1481
|
# some rare exceptions:
|
1556
1482
|
# https://github.com/giampaolo/psutil/issues/1238
|
1557
|
-
root = os.path.join(POWER_SUPPLY_PATH,
|
1483
|
+
root = os.path.join(POWER_SUPPLY_PATH, min(bats))
|
1558
1484
|
|
1559
1485
|
# Base metrics.
|
1560
1486
|
energy_now = multi_bcat(root + "/energy_now", root + "/charge_now")
|
@@ -1631,14 +1557,15 @@ def users():
|
|
1631
1557
|
def boot_time():
|
1632
1558
|
"""Return the system boot time expressed in seconds since the epoch."""
|
1633
1559
|
global BOOT_TIME
|
1634
|
-
path =
|
1560
|
+
path = f"{get_procfs_path()}/stat"
|
1635
1561
|
with open_binary(path) as f:
|
1636
1562
|
for line in f:
|
1637
1563
|
if line.startswith(b'btime'):
|
1638
1564
|
ret = float(line.strip().split()[1])
|
1639
1565
|
BOOT_TIME = ret
|
1640
1566
|
return ret
|
1641
|
-
|
1567
|
+
msg = f"line 'btime' not found in {path}"
|
1568
|
+
raise RuntimeError(msg)
|
1642
1569
|
|
1643
1570
|
|
1644
1571
|
# =====================================================================
|
@@ -1648,7 +1575,8 @@ def boot_time():
|
|
1648
1575
|
|
1649
1576
|
def pids():
|
1650
1577
|
"""Returns a list of PIDs currently running on the system."""
|
1651
|
-
|
1578
|
+
path = get_procfs_path().encode(ENCODING)
|
1579
|
+
return [int(x) for x in os.listdir(path) if x.isdigit()]
|
1652
1580
|
|
1653
1581
|
|
1654
1582
|
def pid_exists(pid):
|
@@ -1670,7 +1598,7 @@ def pid_exists(pid):
|
|
1670
1598
|
# Note: already checked that this is faster than using a
|
1671
1599
|
# regular expr. Also (a lot) faster than doing
|
1672
1600
|
# 'return pid in pids()'
|
1673
|
-
path = "
|
1601
|
+
path = f"{get_procfs_path()}/{pid}/status"
|
1674
1602
|
with open_binary(path) as f:
|
1675
1603
|
for line in f:
|
1676
1604
|
if line.startswith(b"Tgid:"):
|
@@ -1678,8 +1606,9 @@ def pid_exists(pid):
|
|
1678
1606
|
# If tgid and pid are the same then we're
|
1679
1607
|
# dealing with a process PID.
|
1680
1608
|
return tgid == pid
|
1681
|
-
|
1682
|
-
|
1609
|
+
msg = f"'Tgid' line not found in {path}"
|
1610
|
+
raise ValueError(msg)
|
1611
|
+
except (OSError, ValueError):
|
1683
1612
|
return pid in pids()
|
1684
1613
|
|
1685
1614
|
|
@@ -1691,7 +1620,7 @@ def ppid_map():
|
|
1691
1620
|
procfs_path = get_procfs_path()
|
1692
1621
|
for pid in pids():
|
1693
1622
|
try:
|
1694
|
-
with open_binary("
|
1623
|
+
with open_binary(f"{procfs_path}/{pid}/stat") as f:
|
1695
1624
|
data = f.read()
|
1696
1625
|
except (FileNotFoundError, ProcessLookupError):
|
1697
1626
|
# Note: we should be able to access /stat for all processes
|
@@ -1706,28 +1635,27 @@ def ppid_map():
|
|
1706
1635
|
|
1707
1636
|
|
1708
1637
|
def wrap_exceptions(fun):
|
1709
|
-
"""Decorator which translates bare OSError and
|
1638
|
+
"""Decorator which translates bare OSError and OSError exceptions
|
1710
1639
|
into NoSuchProcess and AccessDenied.
|
1711
1640
|
"""
|
1712
1641
|
|
1713
1642
|
@functools.wraps(fun)
|
1714
1643
|
def wrapper(self, *args, **kwargs):
|
1644
|
+
pid, name = self.pid, self._name
|
1715
1645
|
try:
|
1716
1646
|
return fun(self, *args, **kwargs)
|
1717
|
-
except PermissionError:
|
1718
|
-
raise AccessDenied(
|
1719
|
-
except ProcessLookupError:
|
1647
|
+
except PermissionError as err:
|
1648
|
+
raise AccessDenied(pid, name) from err
|
1649
|
+
except ProcessLookupError as err:
|
1720
1650
|
self._raise_if_zombie()
|
1721
|
-
raise NoSuchProcess(
|
1722
|
-
except FileNotFoundError:
|
1651
|
+
raise NoSuchProcess(pid, name) from err
|
1652
|
+
except FileNotFoundError as err:
|
1723
1653
|
self._raise_if_zombie()
|
1724
1654
|
# /proc/PID directory may still exist, but the files within
|
1725
1655
|
# it may not, indicating the process is gone, see:
|
1726
1656
|
# https://github.com/giampaolo/psutil/issues/2418
|
1727
|
-
if not os.path.exists(
|
1728
|
-
|
1729
|
-
):
|
1730
|
-
raise NoSuchProcess(self.pid, self._name)
|
1657
|
+
if not os.path.exists(f"{self._procfs_path}/{pid}/stat"):
|
1658
|
+
raise NoSuchProcess(pid, name) from err
|
1731
1659
|
raise
|
1732
1660
|
|
1733
1661
|
return wrapper
|
@@ -1752,8 +1680,8 @@ class Process:
|
|
1752
1680
|
# it's empty. Instead of returning a "null" value we'll raise an
|
1753
1681
|
# exception.
|
1754
1682
|
try:
|
1755
|
-
data = bcat("
|
1756
|
-
except
|
1683
|
+
data = bcat(f"{self._procfs_path}/{self.pid}/stat")
|
1684
|
+
except OSError:
|
1757
1685
|
return False
|
1758
1686
|
else:
|
1759
1687
|
rpar = data.rfind(b')')
|
@@ -1768,7 +1696,7 @@ class Process:
|
|
1768
1696
|
"""Raise NSP if the process disappeared on us."""
|
1769
1697
|
# For those C function who do not raise NSP, possibly returning
|
1770
1698
|
# incorrect or incomplete result.
|
1771
|
-
os.stat(
|
1699
|
+
os.stat(f"{self._procfs_path}/{self.pid}")
|
1772
1700
|
|
1773
1701
|
@wrap_exceptions
|
1774
1702
|
@memoize_when_activated
|
@@ -1781,7 +1709,7 @@ class Process:
|
|
1781
1709
|
The return value is cached in case oneshot() ctx manager is
|
1782
1710
|
in use.
|
1783
1711
|
"""
|
1784
|
-
data = bcat("
|
1712
|
+
data = bcat(f"{self._procfs_path}/{self.pid}/stat")
|
1785
1713
|
# Process name is between parentheses. It can contain spaces and
|
1786
1714
|
# other parentheses. This is taken into account by looking for
|
1787
1715
|
# the first occurrence of "(" and the last occurrence of ")".
|
@@ -1816,13 +1744,13 @@ class Process:
|
|
1816
1744
|
The return value is cached in case oneshot() ctx manager is
|
1817
1745
|
in use.
|
1818
1746
|
"""
|
1819
|
-
with open_binary("
|
1747
|
+
with open_binary(f"{self._procfs_path}/{self.pid}/status") as f:
|
1820
1748
|
return f.read()
|
1821
1749
|
|
1822
1750
|
@wrap_exceptions
|
1823
1751
|
@memoize_when_activated
|
1824
1752
|
def _read_smaps_file(self):
|
1825
|
-
with open_binary("
|
1753
|
+
with open_binary(f"{self._procfs_path}/{self.pid}/smaps") as f:
|
1826
1754
|
return f.read().strip()
|
1827
1755
|
|
1828
1756
|
def oneshot_enter(self):
|
@@ -1837,28 +1765,25 @@ class Process:
|
|
1837
1765
|
|
1838
1766
|
@wrap_exceptions
|
1839
1767
|
def name(self):
|
1840
|
-
name = self._parse_stat_file()['name']
|
1841
|
-
if PY3:
|
1842
|
-
name = decode(name)
|
1843
1768
|
# XXX - gets changed later and probably needs refactoring
|
1844
|
-
return name
|
1769
|
+
return decode(self._parse_stat_file()['name'])
|
1845
1770
|
|
1846
1771
|
@wrap_exceptions
|
1847
1772
|
def exe(self):
|
1848
1773
|
try:
|
1849
|
-
return readlink("
|
1774
|
+
return readlink(f"{self._procfs_path}/{self.pid}/exe")
|
1850
1775
|
except (FileNotFoundError, ProcessLookupError):
|
1851
1776
|
self._raise_if_zombie()
|
1852
1777
|
# no such file error; might be raised also if the
|
1853
1778
|
# path actually exists for system processes with
|
1854
1779
|
# low pids (about 0-20)
|
1855
|
-
if os.path.lexists("
|
1780
|
+
if os.path.lexists(f"{self._procfs_path}/{self.pid}"):
|
1856
1781
|
return ""
|
1857
1782
|
raise
|
1858
1783
|
|
1859
1784
|
@wrap_exceptions
|
1860
1785
|
def cmdline(self):
|
1861
|
-
with open_text("
|
1786
|
+
with open_text(f"{self._procfs_path}/{self.pid}/cmdline") as f:
|
1862
1787
|
data = f.read()
|
1863
1788
|
if not data:
|
1864
1789
|
# may happen in case of zombie process
|
@@ -1884,7 +1809,7 @@ class Process:
|
|
1884
1809
|
|
1885
1810
|
@wrap_exceptions
|
1886
1811
|
def environ(self):
|
1887
|
-
with open_text("
|
1812
|
+
with open_text(f"{self._procfs_path}/{self.pid}/environ") as f:
|
1888
1813
|
data = f.read()
|
1889
1814
|
return parse_environ_block(data)
|
1890
1815
|
|
@@ -1898,11 +1823,11 @@ class Process:
|
|
1898
1823
|
return None
|
1899
1824
|
|
1900
1825
|
# May not be available on old kernels.
|
1901
|
-
if os.path.exists(
|
1826
|
+
if os.path.exists(f"/proc/{os.getpid()}/io"):
|
1902
1827
|
|
1903
1828
|
@wrap_exceptions
|
1904
1829
|
def io_counters(self):
|
1905
|
-
fname = "
|
1830
|
+
fname = f"{self._procfs_path}/{self.pid}/io"
|
1906
1831
|
fields = {}
|
1907
1832
|
with open_binary(fname) as f:
|
1908
1833
|
for line in f:
|
@@ -1917,7 +1842,8 @@ class Process:
|
|
1917
1842
|
else:
|
1918
1843
|
fields[name] = int(value)
|
1919
1844
|
if not fields:
|
1920
|
-
|
1845
|
+
msg = f"{fname} file was empty"
|
1846
|
+
raise RuntimeError(msg)
|
1921
1847
|
try:
|
1922
1848
|
return pio(
|
1923
1849
|
fields[b'syscr'], # read syscalls
|
@@ -1928,10 +1854,11 @@ class Process:
|
|
1928
1854
|
fields[b'wchar'], # write chars
|
1929
1855
|
)
|
1930
1856
|
except KeyError as err:
|
1931
|
-
|
1932
|
-
"
|
1933
|
-
|
1857
|
+
msg = (
|
1858
|
+
f"{err.args[0]!r} field was not found in {fname}; found"
|
1859
|
+
f" fields are {fields!r}"
|
1934
1860
|
)
|
1861
|
+
raise ValueError(msg) from None
|
1935
1862
|
|
1936
1863
|
@wrap_exceptions
|
1937
1864
|
def cpu_times(self):
|
@@ -1976,7 +1903,7 @@ class Process:
|
|
1976
1903
|
# | data | data + stack | drs | DATA |
|
1977
1904
|
# | dirty | dirty pages (unused in Linux 2.6) | dt | |
|
1978
1905
|
# ============================================================
|
1979
|
-
with open_binary("
|
1906
|
+
with open_binary(f"{self._procfs_path}/{self.pid}/statm") as f:
|
1980
1907
|
vms, rss, shared, text, lib, data, dirty = (
|
1981
1908
|
int(x) * PAGESIZE for x in f.readline().split()[:7]
|
1982
1909
|
)
|
@@ -1995,7 +1922,7 @@ class Process:
|
|
1995
1922
|
# compared to /proc/pid/smaps_rollup.
|
1996
1923
|
uss = pss = swap = 0
|
1997
1924
|
with open_binary(
|
1998
|
-
"{}/{}/smaps_rollup"
|
1925
|
+
f"{self._procfs_path}/{self.pid}/smaps_rollup"
|
1999
1926
|
) as f:
|
2000
1927
|
for line in f:
|
2001
1928
|
if line.startswith(b"Private_"):
|
@@ -2020,8 +1947,6 @@ class Process:
|
|
2020
1947
|
|
2021
1948
|
# Note: using 3 regexes is faster than reading the file
|
2022
1949
|
# line by line.
|
2023
|
-
# XXX: on Python 3 the 2 regexes are 30% slower than on
|
2024
|
-
# Python 2 though. Figure out why.
|
2025
1950
|
#
|
2026
1951
|
# You might be tempted to calculate USS by subtracting
|
2027
1952
|
# the "shared" value from the "resident" value in
|
@@ -2059,7 +1984,7 @@ class Process:
|
|
2059
1984
|
def memory_maps(self):
|
2060
1985
|
"""Return process's mapped memory regions as a list of named
|
2061
1986
|
tuples. Fields are explained in 'man proc'; here is an updated
|
2062
|
-
(Apr 2012) version:
|
1987
|
+
(Apr 2012) version: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/filesystems/proc.txt?id=b76437579d1344b612cf1851ae610c636cec7db0.
|
2063
1988
|
|
2064
1989
|
/proc/{PID}/smaps does not exist on kernels < 2.6.14 or if
|
2065
1990
|
CONFIG_MMU kernel configuration option is not enabled.
|
@@ -2080,11 +2005,8 @@ class Process:
|
|
2080
2005
|
if fields[0].startswith(b'VmFlags:'):
|
2081
2006
|
# see issue #369
|
2082
2007
|
continue
|
2083
|
-
|
2084
|
-
|
2085
|
-
"don't know how to interpret line %r"
|
2086
|
-
% line
|
2087
|
-
)
|
2008
|
+
msg = f"don't know how to interpret line {line!r}"
|
2009
|
+
raise ValueError(msg) from None
|
2088
2010
|
yield (current_block.pop(), data)
|
2089
2011
|
|
2090
2012
|
data = self._read_smaps_file()
|
@@ -2106,8 +2028,7 @@ class Process:
|
|
2106
2028
|
if not path:
|
2107
2029
|
path = '[anon]'
|
2108
2030
|
else:
|
2109
|
-
|
2110
|
-
path = decode(path)
|
2031
|
+
path = decode(path)
|
2111
2032
|
path = path.strip()
|
2112
2033
|
if path.endswith(' (deleted)') and not path_exists_strict(
|
2113
2034
|
path
|
@@ -2133,7 +2054,7 @@ class Process:
|
|
2133
2054
|
|
2134
2055
|
@wrap_exceptions
|
2135
2056
|
def cwd(self):
|
2136
|
-
return readlink("
|
2057
|
+
return readlink(f"{self._procfs_path}/{self.pid}/cwd")
|
2137
2058
|
|
2138
2059
|
@wrap_exceptions
|
2139
2060
|
def num_ctx_switches(
|
@@ -2142,34 +2063,29 @@ class Process:
|
|
2142
2063
|
data = self._read_status_file()
|
2143
2064
|
ctxsw = _ctxsw_re.findall(data)
|
2144
2065
|
if not ctxsw:
|
2145
|
-
|
2146
|
-
"'voluntary_ctxt_switches' and
|
2147
|
-
"lines were not found in
|
2148
|
-
"
|
2066
|
+
msg = (
|
2067
|
+
"'voluntary_ctxt_switches' and"
|
2068
|
+
" 'nonvoluntary_ctxt_switches'lines were not found in"
|
2069
|
+
f" {self._procfs_path}/{self.pid}/status; the kernel is"
|
2070
|
+
" probably older than 2.6.23"
|
2149
2071
|
)
|
2150
|
-
|
2151
|
-
|
2072
|
+
raise NotImplementedError(msg)
|
2073
|
+
return _common.pctxsw(int(ctxsw[0]), int(ctxsw[1]))
|
2152
2074
|
|
2153
2075
|
@wrap_exceptions
|
2154
2076
|
def num_threads(self, _num_threads_re=re.compile(br'Threads:\t(\d+)')):
|
2155
|
-
#
|
2156
|
-
# line by line. On Python 2 is the exact opposite, and iterating
|
2157
|
-
# over a file on Python 3 is slower than on Python 2.
|
2077
|
+
# Using a re is faster than iterating over file line by line.
|
2158
2078
|
data = self._read_status_file()
|
2159
2079
|
return int(_num_threads_re.findall(data)[0])
|
2160
2080
|
|
2161
2081
|
@wrap_exceptions
|
2162
2082
|
def threads(self):
|
2163
|
-
thread_ids = os.listdir("
|
2083
|
+
thread_ids = os.listdir(f"{self._procfs_path}/{self.pid}/task")
|
2164
2084
|
thread_ids.sort()
|
2165
2085
|
retlist = []
|
2166
2086
|
hit_enoent = False
|
2167
2087
|
for thread_id in thread_ids:
|
2168
|
-
fname = "
|
2169
|
-
self._procfs_path,
|
2170
|
-
self.pid,
|
2171
|
-
thread_id,
|
2172
|
-
)
|
2088
|
+
fname = f"{self._procfs_path}/{self.pid}/task/{thread_id}/stat"
|
2173
2089
|
try:
|
2174
2090
|
with open_binary(fname) as f:
|
2175
2091
|
st = f.read().strip()
|
@@ -2191,7 +2107,7 @@ class Process:
|
|
2191
2107
|
|
2192
2108
|
@wrap_exceptions
|
2193
2109
|
def nice_get(self):
|
2194
|
-
# with open_text(
|
2110
|
+
# with open_text(f"{self._procfs_path}/{self.pid}/stat") as f:
|
2195
2111
|
# data = f.read()
|
2196
2112
|
# return int(data.split()[18])
|
2197
2113
|
|
@@ -2230,15 +2146,17 @@ class Process:
|
|
2230
2146
|
all_cpus = tuple(range(len(per_cpu_times())))
|
2231
2147
|
for cpu in cpus:
|
2232
2148
|
if cpu not in all_cpus:
|
2233
|
-
|
2234
|
-
"invalid CPU
|
2235
|
-
|
2149
|
+
msg = (
|
2150
|
+
f"invalid CPU {cpu!r}; choose between"
|
2151
|
+
f" {eligible_cpus!r}"
|
2236
2152
|
)
|
2153
|
+
raise ValueError(msg) from None
|
2237
2154
|
if cpu not in eligible_cpus:
|
2238
|
-
|
2239
|
-
"CPU number
|
2240
|
-
"between
|
2155
|
+
msg = (
|
2156
|
+
f"CPU number {cpu} is not eligible; choose"
|
2157
|
+
f" between {eligible_cpus}"
|
2241
2158
|
)
|
2159
|
+
raise ValueError(msg) from err
|
2242
2160
|
raise
|
2243
2161
|
|
2244
2162
|
# only starting from kernel 2.6.13
|
@@ -2247,22 +2165,25 @@ class Process:
|
|
2247
2165
|
@wrap_exceptions
|
2248
2166
|
def ionice_get(self):
|
2249
2167
|
ioclass, value = cext.proc_ioprio_get(self.pid)
|
2250
|
-
|
2251
|
-
ioclass = IOPriority(ioclass)
|
2168
|
+
ioclass = IOPriority(ioclass)
|
2252
2169
|
return _common.pionice(ioclass, value)
|
2253
2170
|
|
2254
2171
|
@wrap_exceptions
|
2255
2172
|
def ionice_set(self, ioclass, value):
|
2256
2173
|
if value is None:
|
2257
2174
|
value = 0
|
2258
|
-
if value and ioclass in {
|
2259
|
-
|
2175
|
+
if value and ioclass in {
|
2176
|
+
IOPriority.IOPRIO_CLASS_IDLE,
|
2177
|
+
IOPriority.IOPRIO_CLASS_NONE,
|
2178
|
+
}:
|
2179
|
+
msg = f"{ioclass!r} ioclass accepts no value"
|
2180
|
+
raise ValueError(msg)
|
2260
2181
|
if value < 0 or value > 7:
|
2261
2182
|
msg = "value not in 0-7 range"
|
2262
2183
|
raise ValueError(msg)
|
2263
2184
|
return cext.proc_ioprio_set(self.pid, ioclass, value)
|
2264
2185
|
|
2265
|
-
if prlimit
|
2186
|
+
if hasattr(resource, "prlimit"):
|
2266
2187
|
|
2267
2188
|
@wrap_exceptions
|
2268
2189
|
def rlimit(self, resource_, limits=None):
|
@@ -2275,16 +2196,16 @@ class Process:
|
|
2275
2196
|
try:
|
2276
2197
|
if limits is None:
|
2277
2198
|
# get
|
2278
|
-
return prlimit(self.pid, resource_)
|
2199
|
+
return resource.prlimit(self.pid, resource_)
|
2279
2200
|
else:
|
2280
2201
|
# set
|
2281
2202
|
if len(limits) != 2:
|
2282
2203
|
msg = (
|
2283
2204
|
"second argument must be a (soft, hard) "
|
2284
|
-
|
2205
|
+
f"tuple, got {limits!r}"
|
2285
2206
|
)
|
2286
2207
|
raise ValueError(msg)
|
2287
|
-
prlimit(self.pid, resource_, limits)
|
2208
|
+
resource.prlimit(self.pid, resource_, limits)
|
2288
2209
|
except OSError as err:
|
2289
2210
|
if err.errno == errno.ENOSYS:
|
2290
2211
|
# I saw this happening on Travis:
|
@@ -2295,18 +2216,17 @@ class Process:
|
|
2295
2216
|
@wrap_exceptions
|
2296
2217
|
def status(self):
|
2297
2218
|
letter = self._parse_stat_file()['status']
|
2298
|
-
|
2299
|
-
letter = letter.decode()
|
2219
|
+
letter = letter.decode()
|
2300
2220
|
# XXX is '?' legit? (we're not supposed to return it anyway)
|
2301
2221
|
return PROC_STATUSES.get(letter, '?')
|
2302
2222
|
|
2303
2223
|
@wrap_exceptions
|
2304
2224
|
def open_files(self):
|
2305
2225
|
retlist = []
|
2306
|
-
files = os.listdir("
|
2226
|
+
files = os.listdir(f"{self._procfs_path}/{self.pid}/fd")
|
2307
2227
|
hit_enoent = False
|
2308
2228
|
for fd in files:
|
2309
|
-
file = "
|
2229
|
+
file = f"{self._procfs_path}/{self.pid}/fd/{fd}"
|
2310
2230
|
try:
|
2311
2231
|
path = readlink(file)
|
2312
2232
|
except (FileNotFoundError, ProcessLookupError):
|
@@ -2329,11 +2249,7 @@ class Process:
|
|
2329
2249
|
# absolute path though.
|
2330
2250
|
if path.startswith('/') and isfile_strict(path):
|
2331
2251
|
# Get file position and flags.
|
2332
|
-
file = "
|
2333
|
-
self._procfs_path,
|
2334
|
-
self.pid,
|
2335
|
-
fd,
|
2336
|
-
)
|
2252
|
+
file = f"{self._procfs_path}/{self.pid}/fdinfo/{fd}"
|
2337
2253
|
try:
|
2338
2254
|
with open_binary(file) as f:
|
2339
2255
|
pos = int(f.readline().split()[1])
|
@@ -2360,7 +2276,7 @@ class Process:
|
|
2360
2276
|
|
2361
2277
|
@wrap_exceptions
|
2362
2278
|
def num_fds(self):
|
2363
|
-
return len(os.listdir("
|
2279
|
+
return len(os.listdir(f"{self._procfs_path}/{self.pid}/fd"))
|
2364
2280
|
|
2365
2281
|
@wrap_exceptions
|
2366
2282
|
def ppid(self):
|