py2docfx 0.1.20rc2196756__py3-none-any.whl → 0.1.21.dev2246704__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/convert_prepare/get_source.py +1 -1
- py2docfx/convert_prepare/package_info.py +37 -27
- py2docfx/convert_prepare/tests/test_get_source.py +3 -1
- py2docfx/convert_prepare/tests/test_package_info.py +159 -1
- py2docfx/docfx_yaml/build_finished.py +1 -1
- py2docfx/docfx_yaml/logger.py +42 -28
- py2docfx/venv/basevenv/Lib/site-packages/charset_normalizer/api.py +3 -2
- py2docfx/venv/basevenv/Lib/site-packages/charset_normalizer/legacy.py +17 -1
- py2docfx/venv/basevenv/Lib/site-packages/charset_normalizer/version.py +1 -1
- py2docfx/venv/basevenv/Lib/site-packages/requests/__version__.py +2 -2
- py2docfx/venv/basevenv/Lib/site-packages/requests/adapters.py +17 -40
- py2docfx/venv/basevenv/Lib/site-packages/requests/sessions.py +1 -1
- py2docfx/venv/venv1/Lib/site-packages/azure/core/_version.py +1 -1
- py2docfx/venv/venv1/Lib/site-packages/azure/core/pipeline/policies/_authentication.py +21 -9
- py2docfx/venv/venv1/Lib/site-packages/azure/core/pipeline/policies/_authentication_async.py +21 -9
- py2docfx/venv/venv1/Lib/site-packages/azure/core/pipeline/policies/_retry.py +1 -1
- py2docfx/venv/venv1/Lib/site-packages/azure/identity/_bearer_token_provider.py +1 -1
- 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 +82 -17
- py2docfx/venv/venv1/Lib/site-packages/azure/identity/_credentials/azure_cli.py +28 -5
- py2docfx/venv/venv1/Lib/site-packages/azure/identity/_credentials/azure_powershell.py +28 -4
- py2docfx/venv/venv1/Lib/site-packages/azure/identity/_credentials/broker.py +79 -0
- py2docfx/venv/venv1/Lib/site-packages/azure/identity/_credentials/chained.py +9 -3
- py2docfx/venv/venv1/Lib/site-packages/azure/identity/_credentials/default.py +153 -53
- py2docfx/venv/venv1/Lib/site-packages/azure/identity/_credentials/imds.py +25 -1
- py2docfx/venv/venv1/Lib/site-packages/azure/identity/_credentials/shared_cache.py +12 -5
- py2docfx/venv/venv1/Lib/site-packages/azure/identity/_credentials/vscode.py +163 -144
- py2docfx/venv/venv1/Lib/site-packages/azure/identity/_credentials/workload_identity.py +23 -12
- py2docfx/venv/venv1/Lib/site-packages/azure/identity/_internal/__init__.py +4 -0
- py2docfx/venv/venv1/Lib/site-packages/azure/identity/_internal/interactive.py +14 -2
- py2docfx/venv/venv1/Lib/site-packages/azure/identity/_internal/pipeline.py +4 -2
- py2docfx/venv/venv1/Lib/site-packages/azure/identity/_internal/utils.py +96 -0
- py2docfx/venv/venv1/Lib/site-packages/azure/identity/_version.py +1 -1
- py2docfx/venv/venv1/Lib/site-packages/azure/identity/aio/_bearer_token_provider.py +3 -3
- py2docfx/venv/venv1/Lib/site-packages/azure/identity/aio/_credentials/authorization_code.py +1 -1
- py2docfx/venv/venv1/Lib/site-packages/azure/identity/aio/_credentials/azd_cli.py +32 -13
- py2docfx/venv/venv1/Lib/site-packages/azure/identity/aio/_credentials/azure_cli.py +26 -5
- py2docfx/venv/venv1/Lib/site-packages/azure/identity/aio/_credentials/azure_powershell.py +13 -2
- py2docfx/venv/venv1/Lib/site-packages/azure/identity/aio/_credentials/chained.py +1 -1
- py2docfx/venv/venv1/Lib/site-packages/azure/identity/aio/_credentials/default.py +120 -55
- py2docfx/venv/venv1/Lib/site-packages/azure/identity/aio/_credentials/imds.py +27 -1
- py2docfx/venv/venv1/Lib/site-packages/azure/identity/aio/_credentials/on_behalf_of.py +1 -1
- py2docfx/venv/venv1/Lib/site-packages/azure/identity/aio/_credentials/shared_cache.py +12 -5
- py2docfx/venv/venv1/Lib/site-packages/azure/identity/aio/_credentials/vscode.py +15 -67
- py2docfx/venv/venv1/Lib/site-packages/azure/identity/aio/_credentials/workload_identity.py +17 -13
- py2docfx/venv/venv1/Lib/site-packages/cffi/__init__.py +2 -2
- py2docfx/venv/venv1/Lib/site-packages/cffi/cparser.py +1 -1
- py2docfx/venv/venv1/Lib/site-packages/cffi/recompiler.py +5 -5
- py2docfx/venv/venv1/Lib/site-packages/cffi/setuptools_ext.py +13 -0
- py2docfx/venv/venv1/Lib/site-packages/cffi/vengine_cpy.py +3 -0
- py2docfx/venv/venv1/Lib/site-packages/charset_normalizer/api.py +3 -2
- py2docfx/venv/venv1/Lib/site-packages/charset_normalizer/legacy.py +17 -1
- py2docfx/venv/venv1/Lib/site-packages/charset_normalizer/version.py +1 -1
- py2docfx/venv/venv1/Lib/site-packages/cryptography/__about__.py +1 -1
- py2docfx/venv/venv1/Lib/site-packages/cryptography/__init__.py +0 -13
- py2docfx/venv/venv1/Lib/site-packages/cryptography/hazmat/_oid.py +8 -0
- py2docfx/venv/venv1/Lib/site-packages/cryptography/hazmat/asn1/__init__.py +10 -0
- py2docfx/venv/venv1/Lib/site-packages/cryptography/hazmat/asn1/asn1.py +116 -0
- py2docfx/venv/venv1/Lib/site-packages/cryptography/hazmat/backends/openssl/backend.py +3 -9
- py2docfx/venv/venv1/Lib/site-packages/cryptography/hazmat/bindings/_rust/declarative_asn1.pyi +32 -0
- py2docfx/venv/venv1/Lib/site-packages/cryptography/hazmat/bindings/_rust/openssl/kdf.pyi +23 -0
- py2docfx/venv/venv1/Lib/site-packages/cryptography/hazmat/bindings/_rust/x509.pyi +1 -13
- py2docfx/venv/venv1/Lib/site-packages/cryptography/hazmat/bindings/openssl/_conditional.py +16 -0
- py2docfx/venv/venv1/Lib/site-packages/cryptography/hazmat/bindings/openssl/binding.py +16 -1
- py2docfx/venv/venv1/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/padding.py +0 -2
- py2docfx/venv/venv1/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/rsa.py +8 -0
- py2docfx/venv/venv1/Lib/site-packages/cryptography/hazmat/primitives/ciphers/algorithms.py +0 -47
- py2docfx/venv/venv1/Lib/site-packages/cryptography/hazmat/primitives/kdf/hkdf.py +6 -91
- py2docfx/venv/venv1/Lib/site-packages/cryptography/hazmat/primitives/kdf/kbkdf.py +1 -3
- py2docfx/venv/venv1/Lib/site-packages/cryptography/hazmat/primitives/serialization/ssh.py +1 -1
- py2docfx/venv/venv1/Lib/site-packages/cryptography/utils.py +0 -2
- py2docfx/venv/venv1/Lib/site-packages/cryptography/x509/name.py +2 -3
- py2docfx/venv/venv1/Lib/site-packages/google/protobuf/__init__.py +1 -1
- py2docfx/venv/venv1/Lib/site-packages/google/protobuf/any_pb2.py +2 -2
- py2docfx/venv/venv1/Lib/site-packages/google/protobuf/api_pb2.py +12 -8
- py2docfx/venv/venv1/Lib/site-packages/google/protobuf/compiler/plugin_pb2.py +2 -2
- py2docfx/venv/venv1/Lib/site-packages/google/protobuf/descriptor.py +398 -246
- py2docfx/venv/venv1/Lib/site-packages/google/protobuf/descriptor_pb2.py +74 -72
- py2docfx/venv/venv1/Lib/site-packages/google/protobuf/descriptor_pool.py +5 -4
- py2docfx/venv/venv1/Lib/site-packages/google/protobuf/duration_pb2.py +2 -2
- py2docfx/venv/venv1/Lib/site-packages/google/protobuf/empty_pb2.py +2 -2
- py2docfx/venv/venv1/Lib/site-packages/google/protobuf/field_mask_pb2.py +2 -2
- py2docfx/venv/venv1/Lib/site-packages/google/protobuf/internal/api_implementation.py +0 -6
- py2docfx/venv/venv1/Lib/site-packages/google/protobuf/internal/extension_dict.py +3 -3
- py2docfx/venv/venv1/Lib/site-packages/google/protobuf/internal/field_mask.py +3 -3
- py2docfx/venv/venv1/Lib/site-packages/google/protobuf/internal/python_edition_defaults.py +1 -1
- py2docfx/venv/venv1/Lib/site-packages/google/protobuf/internal/python_message.py +10 -2
- py2docfx/venv/venv1/Lib/site-packages/google/protobuf/internal/type_checkers.py +47 -5
- py2docfx/venv/venv1/Lib/site-packages/google/protobuf/json_format.py +55 -32
- py2docfx/venv/venv1/Lib/site-packages/google/protobuf/runtime_version.py +6 -26
- py2docfx/venv/venv1/Lib/site-packages/google/protobuf/source_context_pb2.py +2 -2
- py2docfx/venv/venv1/Lib/site-packages/google/protobuf/struct_pb2.py +2 -2
- py2docfx/venv/venv1/Lib/site-packages/google/protobuf/text_format.py +30 -19
- py2docfx/venv/venv1/Lib/site-packages/google/protobuf/timestamp_pb2.py +2 -2
- py2docfx/venv/venv1/Lib/site-packages/google/protobuf/type_pb2.py +2 -2
- py2docfx/venv/venv1/Lib/site-packages/google/protobuf/wrappers_pb2.py +2 -2
- py2docfx/venv/venv1/Lib/site-packages/psutil/__init__.py +39 -19
- py2docfx/venv/venv1/Lib/site-packages/psutil/_common.py +3 -5
- py2docfx/venv/venv1/Lib/site-packages/psutil/_psaix.py +1 -2
- py2docfx/venv/venv1/Lib/site-packages/psutil/_psbsd.py +53 -78
- py2docfx/venv/venv1/Lib/site-packages/psutil/_pslinux.py +55 -38
- py2docfx/venv/venv1/Lib/site-packages/psutil/_psosx.py +40 -12
- py2docfx/venv/venv1/Lib/site-packages/psutil/_psposix.py +0 -1
- py2docfx/venv/venv1/Lib/site-packages/psutil/_pssunos.py +1 -2
- py2docfx/venv/venv1/Lib/site-packages/psutil/_pswindows.py +33 -13
- py2docfx/venv/venv1/Lib/site-packages/psutil/tests/__init__.py +185 -122
- py2docfx/venv/venv1/Lib/site-packages/psutil/tests/__main__.py +2 -3
- py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_bsd.py +5 -10
- py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_connections.py +3 -4
- py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_contracts.py +41 -45
- py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_linux.py +35 -38
- py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_memleaks.py +4 -8
- py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_misc.py +6 -12
- py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_osx.py +17 -8
- py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_posix.py +29 -17
- py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_process.py +74 -75
- py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_process_all.py +11 -13
- py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_scripts.py +2 -3
- py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_sudo.py +117 -0
- py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_system.py +21 -31
- py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_testutils.py +23 -23
- py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_unicode.py +15 -8
- py2docfx/venv/venv1/Lib/site-packages/psutil/tests/test_windows.py +65 -33
- py2docfx/venv/venv1/Lib/site-packages/pycparser/__init__.py +1 -1
- py2docfx/venv/venv1/Lib/site-packages/pycparser/c_generator.py +1 -1
- py2docfx/venv/venv1/Lib/site-packages/pycparser/c_lexer.py +14 -0
- py2docfx/venv/venv1/Lib/site-packages/pycparser/c_parser.py +30 -7
- py2docfx/venv/venv1/Lib/site-packages/pycparser/lextab.py +1 -1
- py2docfx/venv/venv1/Lib/site-packages/pycparser/yacctab.py +132 -127
- py2docfx/venv/venv1/Lib/site-packages/requests/__version__.py +2 -2
- py2docfx/venv/venv1/Lib/site-packages/requests/adapters.py +17 -40
- py2docfx/venv/venv1/Lib/site-packages/requests/sessions.py +1 -1
- py2docfx/venv/venv1/Lib/site-packages/typing_extensions.py +91 -18
- {py2docfx-0.1.20rc2196756.dist-info → py2docfx-0.1.21.dev2246704.dist-info}/METADATA +1 -1
- {py2docfx-0.1.20rc2196756.dist-info → py2docfx-0.1.21.dev2246704.dist-info}/RECORD +137 -135
- py2docfx/venv/venv1/Lib/site-packages/azure/identity/_internal/linux_vscode_adapter.py +0 -100
- py2docfx/venv/venv1/Lib/site-packages/azure/identity/_internal/macos_vscode_adapter.py +0 -34
- py2docfx/venv/venv1/Lib/site-packages/azure/identity/_internal/win_vscode_adapter.py +0 -77
- {py2docfx-0.1.20rc2196756.dist-info → py2docfx-0.1.21.dev2246704.dist-info}/WHEEL +0 -0
- {py2docfx-0.1.20rc2196756.dist-info → py2docfx-0.1.21.dev2246704.dist-info}/top_level.txt +0 -0
@@ -30,7 +30,6 @@ import sys
|
|
30
30
|
import threading
|
31
31
|
import time
|
32
32
|
|
33
|
-
|
34
33
|
try:
|
35
34
|
import pwd
|
36
35
|
except ImportError:
|
@@ -86,7 +85,6 @@ from ._common import debug
|
|
86
85
|
from ._common import memoize_when_activated
|
87
86
|
from ._common import wrap_numbers as _wrap_numbers
|
88
87
|
|
89
|
-
|
90
88
|
if LINUX:
|
91
89
|
# This is public API and it will be retrieved from _pslinux.py
|
92
90
|
# via sys.modules.
|
@@ -207,7 +205,7 @@ if hasattr(_psplatform.Process, "rlimit"):
|
|
207
205
|
AF_LINK = _psplatform.AF_LINK
|
208
206
|
|
209
207
|
__author__ = "Giampaolo Rodola'"
|
210
|
-
__version__ = "7.
|
208
|
+
__version__ = "7.1.0"
|
211
209
|
version_info = tuple(int(num) for num in __version__.split('.'))
|
212
210
|
|
213
211
|
_timer = getattr(time, 'monotonic', time.time)
|
@@ -377,7 +375,11 @@ class Process:
|
|
377
375
|
won't reuse the same PID after such a short period of time
|
378
376
|
(0.01 secs). Technically this is inherently racy, but
|
379
377
|
practically it should be good enough.
|
378
|
+
|
379
|
+
NOTE: unreliable on FreeBSD and OpenBSD as ctime is subject to
|
380
|
+
system clock updates.
|
380
381
|
"""
|
382
|
+
|
381
383
|
if WINDOWS:
|
382
384
|
# Use create_time() fast method in order to speedup
|
383
385
|
# `process_iter()`. This means we'll get AccessDenied for
|
@@ -386,6 +388,11 @@ class Process:
|
|
386
388
|
# https://github.com/giampaolo/psutil/issues/2366#issuecomment-2381646555
|
387
389
|
self._create_time = self._proc.create_time(fast_only=True)
|
388
390
|
return (self.pid, self._create_time)
|
391
|
+
elif LINUX or NETBSD or OSX:
|
392
|
+
# Use 'monotonic' process starttime since boot to form unique
|
393
|
+
# process identity, since it is stable over changes to system
|
394
|
+
# time.
|
395
|
+
return (self.pid, self._proc.create_time(monotonic=True))
|
389
396
|
else:
|
390
397
|
return (self.pid, self.create_time())
|
391
398
|
|
@@ -426,12 +433,12 @@ class Process:
|
|
426
433
|
# on PID and creation time.
|
427
434
|
if not isinstance(other, Process):
|
428
435
|
return NotImplemented
|
429
|
-
if OPENBSD or NETBSD: # pragma: no cover
|
430
|
-
# Zombie processes on Open/NetBSD have a
|
431
|
-
# 0.0.
|
432
|
-
# (so it has a ctime), then it turned into a
|
433
|
-
# important to do this because is_running()
|
434
|
-
# __eq__.
|
436
|
+
if OPENBSD or NETBSD or SUNOS: # pragma: no cover
|
437
|
+
# Zombie processes on Open/NetBSD/illumos/Solaris have a
|
438
|
+
# creation time of 0.0. This covers the case when a process
|
439
|
+
# started normally (so it has a ctime), then it turned into a
|
440
|
+
# zombie. It's important to do this because is_running()
|
441
|
+
# depends on __eq__.
|
435
442
|
pid1, ident1 = self._ident
|
436
443
|
pid2, ident2 = other._ident
|
437
444
|
if pid1 == pid2:
|
@@ -593,10 +600,13 @@ class Process:
|
|
593
600
|
return None
|
594
601
|
ppid = self.ppid()
|
595
602
|
if ppid is not None:
|
596
|
-
|
603
|
+
# Get a fresh (non-cached) ctime in case the system clock
|
604
|
+
# was updated. TODO: use a monotonic ctime on platforms
|
605
|
+
# where it's supported.
|
606
|
+
proc_ctime = Process(self.pid).create_time()
|
597
607
|
try:
|
598
608
|
parent = Process(ppid)
|
599
|
-
if parent.create_time() <=
|
609
|
+
if parent.create_time() <= proc_ctime:
|
600
610
|
return parent
|
601
611
|
# ...else ppid has been reused by another process
|
602
612
|
except NoSuchProcess:
|
@@ -765,8 +775,11 @@ class Process:
|
|
765
775
|
|
766
776
|
def create_time(self):
|
767
777
|
"""The process creation time as a floating point number
|
768
|
-
expressed in seconds since the epoch
|
769
|
-
The return value is cached after
|
778
|
+
expressed in seconds since the epoch (seconds since January 1,
|
779
|
+
1970, at midnight UTC). The return value, which is cached after
|
780
|
+
first call, is based on the system clock, which means it may be
|
781
|
+
affected by changes such as manual adjustments or time
|
782
|
+
synchronization (e.g. NTP).
|
770
783
|
"""
|
771
784
|
if self._create_time is None:
|
772
785
|
self._create_time = self._proc.create_time()
|
@@ -964,6 +977,10 @@ class Process:
|
|
964
977
|
"""
|
965
978
|
self._raise_if_pid_reused()
|
966
979
|
ppid_map = _ppid_map()
|
980
|
+
# Get a fresh (non-cached) ctime in case the system clock was
|
981
|
+
# updated. TODO: use a monotonic ctime on platforms where it's
|
982
|
+
# supported.
|
983
|
+
proc_ctime = Process(self.pid).create_time()
|
967
984
|
ret = []
|
968
985
|
if not recursive:
|
969
986
|
for pid, ppid in ppid_map.items():
|
@@ -972,7 +989,7 @@ class Process:
|
|
972
989
|
child = Process(pid)
|
973
990
|
# if child happens to be older than its parent
|
974
991
|
# (self) it means child's PID has been reused
|
975
|
-
if
|
992
|
+
if proc_ctime <= child.create_time():
|
976
993
|
ret.append(child)
|
977
994
|
except (NoSuchProcess, ZombieProcess):
|
978
995
|
pass
|
@@ -998,7 +1015,7 @@ class Process:
|
|
998
1015
|
child = Process(child_pid)
|
999
1016
|
# if child happens to be older than its parent
|
1000
1017
|
# (self) it means child's PID has been reused
|
1001
|
-
intime =
|
1018
|
+
intime = proc_ctime <= child.create_time()
|
1002
1019
|
if intime:
|
1003
1020
|
ret.append(child)
|
1004
1021
|
stack.append(child_pid)
|
@@ -1484,7 +1501,7 @@ def process_iter(attrs=None, ad_value=None):
|
|
1484
1501
|
|
1485
1502
|
Every new Process instance is only created once and then cached
|
1486
1503
|
into an internal table which is updated every time this is used.
|
1487
|
-
Cache can optionally be cleared via `process_iter.
|
1504
|
+
Cache can optionally be cleared via `process_iter.cache_clear()`.
|
1488
1505
|
|
1489
1506
|
The sorting order in which processes are yielded is based on
|
1490
1507
|
their PIDs.
|
@@ -2352,9 +2369,12 @@ if hasattr(_psplatform, "sensors_battery"):
|
|
2352
2369
|
|
2353
2370
|
|
2354
2371
|
def boot_time():
|
2355
|
-
"""Return the system boot time expressed in seconds since the epoch
|
2356
|
-
|
2357
|
-
|
2372
|
+
"""Return the system boot time expressed in seconds since the epoch
|
2373
|
+
(seconds since January 1, 1970, at midnight UTC). The returned
|
2374
|
+
value is based on the system clock, which means it may be affected
|
2375
|
+
by changes such as manual adjustments or time synchronization (e.g.
|
2376
|
+
NTP).
|
2377
|
+
"""
|
2358
2378
|
return _psplatform.boot_time()
|
2359
2379
|
|
2360
2380
|
|
@@ -22,7 +22,6 @@ from socket import AF_INET
|
|
22
22
|
from socket import SOCK_DGRAM
|
23
23
|
from socket import SOCK_STREAM
|
24
24
|
|
25
|
-
|
26
25
|
try:
|
27
26
|
from socket import AF_INET6
|
28
27
|
except ImportError:
|
@@ -409,7 +408,7 @@ def memoize(fun):
|
|
409
408
|
except KeyError:
|
410
409
|
try:
|
411
410
|
ret = cache[key] = fun(*args, **kwargs)
|
412
|
-
except Exception as err:
|
411
|
+
except Exception as err:
|
413
412
|
raise err from None
|
414
413
|
return ret
|
415
414
|
|
@@ -458,14 +457,14 @@ def memoize_when_activated(fun):
|
|
458
457
|
# case 2: we never entered oneshot() ctx
|
459
458
|
try:
|
460
459
|
return fun(self)
|
461
|
-
except Exception as err:
|
460
|
+
except Exception as err:
|
462
461
|
raise err from None
|
463
462
|
except KeyError:
|
464
463
|
# case 3: we entered oneshot() ctx but there's no cache
|
465
464
|
# for this entry yet
|
466
465
|
try:
|
467
466
|
ret = fun(self)
|
468
|
-
except Exception as err:
|
467
|
+
except Exception as err:
|
469
468
|
raise err from None
|
470
469
|
try:
|
471
470
|
self._cache[fun] = ret
|
@@ -523,7 +522,6 @@ def path_exists_strict(path):
|
|
523
522
|
return True
|
524
523
|
|
525
524
|
|
526
|
-
@memoize
|
527
525
|
def supports_ipv6():
|
528
526
|
"""Return True if IPv6 is supported on this platform."""
|
529
527
|
if not socket.has_ipv6 or AF_INET6 is None:
|
@@ -29,7 +29,6 @@ from ._common import get_procfs_path
|
|
29
29
|
from ._common import memoize_when_activated
|
30
30
|
from ._common import usage_percent
|
31
31
|
|
32
|
-
|
33
32
|
__extra__all__ = ["PROCFS_PATH"]
|
34
33
|
|
35
34
|
|
@@ -279,7 +278,7 @@ def boot_time():
|
|
279
278
|
def users():
|
280
279
|
"""Return currently connected users as a list of namedtuples."""
|
281
280
|
retlist = []
|
282
|
-
rawlist =
|
281
|
+
rawlist = cext_posix.users()
|
283
282
|
localhost = (':0.0', ':0')
|
284
283
|
for item in rawlist:
|
285
284
|
user, tty, hostname, tstamp, user_process, pid = item
|
@@ -29,7 +29,6 @@ from ._common import memoize
|
|
29
29
|
from ._common import memoize_when_activated
|
30
30
|
from ._common import usage_percent
|
31
31
|
|
32
|
-
|
33
32
|
__extra__all__ = []
|
34
33
|
|
35
34
|
|
@@ -98,10 +97,7 @@ TCP_STATUSES = {
|
|
98
97
|
PAGESIZE = cext_posix.getpagesize()
|
99
98
|
AF_LINK = cext_posix.AF_LINK
|
100
99
|
|
101
|
-
HAS_PER_CPU_TIMES = hasattr(cext, "per_cpu_times")
|
102
100
|
HAS_PROC_NUM_THREADS = hasattr(cext, "proc_num_threads")
|
103
|
-
HAS_PROC_OPEN_FILES = hasattr(cext, 'proc_open_files')
|
104
|
-
HAS_PROC_NUM_FDS = hasattr(cext, 'proc_num_fds')
|
105
101
|
|
106
102
|
kinfo_proc_map = dict(
|
107
103
|
ppid=0,
|
@@ -240,36 +236,14 @@ def cpu_times():
|
|
240
236
|
return scputimes(user, nice, system, idle, irq)
|
241
237
|
|
242
238
|
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
ret.append(item)
|
252
|
-
return ret
|
253
|
-
|
254
|
-
else:
|
255
|
-
# XXX
|
256
|
-
# Ok, this is very dirty.
|
257
|
-
# On FreeBSD < 8 we cannot gather per-cpu information, see:
|
258
|
-
# https://github.com/giampaolo/psutil/issues/226
|
259
|
-
# If num cpus > 1, on first call we return single cpu times to avoid a
|
260
|
-
# crash at psutil import time.
|
261
|
-
# Next calls will fail with NotImplementedError
|
262
|
-
def per_cpu_times():
|
263
|
-
"""Return system CPU times as a namedtuple."""
|
264
|
-
if cpu_count_logical() == 1:
|
265
|
-
return [cpu_times()]
|
266
|
-
if per_cpu_times.__called__:
|
267
|
-
msg = "supported only starting from FreeBSD 8"
|
268
|
-
raise NotImplementedError(msg)
|
269
|
-
per_cpu_times.__called__ = True
|
270
|
-
return [cpu_times()]
|
271
|
-
|
272
|
-
per_cpu_times.__called__ = False
|
239
|
+
def per_cpu_times():
|
240
|
+
"""Return system CPU times as a namedtuple."""
|
241
|
+
ret = []
|
242
|
+
for cpu_t in cext.per_cpu_times():
|
243
|
+
user, nice, system, idle, irq = cpu_t
|
244
|
+
item = scputimes(user, nice, system, idle, irq)
|
245
|
+
ret.append(item)
|
246
|
+
return ret
|
273
247
|
|
274
248
|
|
275
249
|
def cpu_count_logical():
|
@@ -505,15 +479,36 @@ def boot_time():
|
|
505
479
|
return cext.boot_time()
|
506
480
|
|
507
481
|
|
482
|
+
if NETBSD:
|
483
|
+
|
484
|
+
try:
|
485
|
+
INIT_BOOT_TIME = boot_time()
|
486
|
+
except Exception as err: # noqa: BLE001
|
487
|
+
# Don't want to crash at import time.
|
488
|
+
debug(f"ignoring exception on import: {err!r}")
|
489
|
+
INIT_BOOT_TIME = 0
|
490
|
+
|
491
|
+
def adjust_proc_create_time(ctime):
|
492
|
+
"""Account for system clock updates."""
|
493
|
+
if INIT_BOOT_TIME == 0:
|
494
|
+
return ctime
|
495
|
+
|
496
|
+
diff = INIT_BOOT_TIME - boot_time()
|
497
|
+
if diff == 0 or abs(diff) < 1:
|
498
|
+
return ctime
|
499
|
+
|
500
|
+
debug("system clock was updated; adjusting process create_time()")
|
501
|
+
if diff < 0:
|
502
|
+
return ctime - diff
|
503
|
+
return ctime + diff
|
504
|
+
|
505
|
+
|
508
506
|
def users():
|
509
507
|
"""Return currently connected users as a list of namedtuples."""
|
510
508
|
retlist = []
|
511
|
-
rawlist = cext.users()
|
509
|
+
rawlist = cext.users() if OPENBSD else cext_posix.users()
|
512
510
|
for item in rawlist:
|
513
511
|
user, tty, hostname, tstamp, pid = item
|
514
|
-
if pid == -1:
|
515
|
-
assert OPENBSD
|
516
|
-
pid = None
|
517
512
|
if tty == '~':
|
518
513
|
continue # reboot or shutdown
|
519
514
|
nt = _common.suser(user, tty or None, hostname, tstamp, pid)
|
@@ -779,13 +774,17 @@ class Process:
|
|
779
774
|
memory_full_info = memory_info
|
780
775
|
|
781
776
|
@wrap_exceptions
|
782
|
-
def create_time(self):
|
783
|
-
|
777
|
+
def create_time(self, monotonic=False):
|
778
|
+
ctime = self.oneshot()[kinfo_proc_map['create_time']]
|
779
|
+
if NETBSD and not monotonic:
|
780
|
+
# NetBSD: ctime subject to system clock updates.
|
781
|
+
ctime = adjust_proc_create_time(ctime)
|
782
|
+
return ctime
|
784
783
|
|
785
784
|
@wrap_exceptions
|
786
785
|
def num_threads(self):
|
787
786
|
if HAS_PROC_NUM_THREADS:
|
788
|
-
# FreeBSD
|
787
|
+
# FreeBSD / NetBSD
|
789
788
|
return cext.proc_num_threads(self.pid)
|
790
789
|
else:
|
791
790
|
return len(self.threads())
|
@@ -870,14 +869,7 @@ class Process:
|
|
870
869
|
# it into None
|
871
870
|
if OPENBSD and self.pid == 0:
|
872
871
|
return "" # ...else it would raise EINVAL
|
873
|
-
|
874
|
-
# FreeBSD < 8 does not support functions based on
|
875
|
-
# kinfo_getfile() and kinfo_getvmmap()
|
876
|
-
return cext.proc_cwd(self.pid)
|
877
|
-
else:
|
878
|
-
raise NotImplementedError(
|
879
|
-
"supported only starting from FreeBSD 8" if FREEBSD else ""
|
880
|
-
)
|
872
|
+
return cext.proc_cwd(self.pid)
|
881
873
|
|
882
874
|
nt_mmap_grouped = namedtuple(
|
883
875
|
'mmap', 'path rss, private, ref_count, shadow_count'
|
@@ -886,36 +878,19 @@ class Process:
|
|
886
878
|
'mmap', 'addr, perms path rss, private, ref_count, shadow_count'
|
887
879
|
)
|
888
880
|
|
889
|
-
|
890
|
-
|
891
|
-
|
892
|
-
|
893
|
-
|
894
|
-
if HAS_PROC_OPEN_FILES:
|
895
|
-
|
896
|
-
@wrap_exceptions
|
897
|
-
def open_files(self):
|
898
|
-
"""Return files opened by process as a list of namedtuples."""
|
899
|
-
rawlist = cext.proc_open_files(self.pid)
|
900
|
-
return [_common.popenfile(path, fd) for path, fd in rawlist]
|
901
|
-
|
902
|
-
else:
|
903
|
-
open_files = _not_implemented
|
904
|
-
|
905
|
-
# FreeBSD < 8 does not support functions based on kinfo_getfile()
|
906
|
-
# and kinfo_getvmmap()
|
907
|
-
if HAS_PROC_NUM_FDS:
|
908
|
-
|
909
|
-
@wrap_exceptions
|
910
|
-
def num_fds(self):
|
911
|
-
"""Return the number of file descriptors opened by this process."""
|
912
|
-
ret = cext.proc_num_fds(self.pid)
|
913
|
-
if NETBSD:
|
914
|
-
self._assert_alive()
|
915
|
-
return ret
|
881
|
+
@wrap_exceptions
|
882
|
+
def open_files(self):
|
883
|
+
"""Return files opened by process as a list of namedtuples."""
|
884
|
+
rawlist = cext.proc_open_files(self.pid)
|
885
|
+
return [_common.popenfile(path, fd) for path, fd in rawlist]
|
916
886
|
|
917
|
-
|
918
|
-
|
887
|
+
@wrap_exceptions
|
888
|
+
def num_fds(self):
|
889
|
+
"""Return the number of file descriptors opened by this process."""
|
890
|
+
ret = cext.proc_num_fds(self.pid)
|
891
|
+
if NETBSD:
|
892
|
+
self._assert_alive()
|
893
|
+
return ret
|
919
894
|
|
920
895
|
# --- FreeBSD only APIs
|
921
896
|
|
@@ -47,7 +47,6 @@ from ._common import path_exists_strict
|
|
47
47
|
from ._common import supports_ipv6
|
48
48
|
from ._common import usage_percent
|
49
49
|
|
50
|
-
|
51
50
|
# fmt: off
|
52
51
|
__extra__all__ = [
|
53
52
|
'PROCFS_PATH',
|
@@ -81,8 +80,8 @@ HAS_CPU_AFFINITY = hasattr(cext, "proc_cpu_affinity_get")
|
|
81
80
|
# Number of clock ticks per second
|
82
81
|
CLOCK_TICKS = os.sysconf("SC_CLK_TCK")
|
83
82
|
PAGESIZE = cext_posix.getpagesize()
|
84
|
-
BOOT_TIME = None # set later
|
85
83
|
LITTLE_ENDIAN = sys.byteorder == 'little'
|
84
|
+
UNSET = object()
|
86
85
|
|
87
86
|
# "man iostat" states that sectors are equivalent with blocks and have
|
88
87
|
# a size of 512 bytes. Despite this value can be queried at runtime
|
@@ -421,12 +420,6 @@ def virtual_memory():
|
|
421
420
|
except KeyError:
|
422
421
|
slab = 0
|
423
422
|
|
424
|
-
used = total - free - cached - buffers
|
425
|
-
if used < 0:
|
426
|
-
# May be symptomatic of running within a LCX container where such
|
427
|
-
# values will be dramatically distorted over those of the host.
|
428
|
-
used = total - free
|
429
|
-
|
430
423
|
# - starting from 4.4.0 we match free's "available" column.
|
431
424
|
# Before 4.4.0 we calculated it as (free + buffers + cached)
|
432
425
|
# which matched htop.
|
@@ -457,6 +450,8 @@ def virtual_memory():
|
|
457
450
|
# 24fd2605c51fccc375ab0287cec33aa767f06718/proc/sysinfo.c#L764
|
458
451
|
avail = free
|
459
452
|
|
453
|
+
used = total - avail
|
454
|
+
|
460
455
|
percent = usage_percent((total - avail), total, round_=1)
|
461
456
|
|
462
457
|
# Warn about missing metrics which are set to 0.
|
@@ -1525,7 +1520,7 @@ def sensors_battery():
|
|
1525
1520
|
secsleft = _common.POWER_TIME_UNLIMITED
|
1526
1521
|
elif energy_now is not None and power_now is not None:
|
1527
1522
|
try:
|
1528
|
-
secsleft = int(energy_now / power_now * 3600)
|
1523
|
+
secsleft = int(energy_now / abs(power_now) * 3600)
|
1529
1524
|
except ZeroDivisionError:
|
1530
1525
|
secsleft = _common.POWER_TIME_UNKNOWN
|
1531
1526
|
elif time_to_empty is not None:
|
@@ -1546,7 +1541,7 @@ def sensors_battery():
|
|
1546
1541
|
def users():
|
1547
1542
|
"""Return currently connected users as a list of namedtuples."""
|
1548
1543
|
retlist = []
|
1549
|
-
rawlist =
|
1544
|
+
rawlist = cext_posix.users()
|
1550
1545
|
for item in rawlist:
|
1551
1546
|
user, tty, hostname, tstamp, pid = item
|
1552
1547
|
nt = _common.suser(user, tty or None, hostname, tstamp, pid)
|
@@ -1556,14 +1551,11 @@ def users():
|
|
1556
1551
|
|
1557
1552
|
def boot_time():
|
1558
1553
|
"""Return the system boot time expressed in seconds since the epoch."""
|
1559
|
-
global BOOT_TIME
|
1560
1554
|
path = f"{get_procfs_path()}/stat"
|
1561
1555
|
with open_binary(path) as f:
|
1562
1556
|
for line in f:
|
1563
1557
|
if line.startswith(b'btime'):
|
1564
|
-
|
1565
|
-
BOOT_TIME = ret
|
1566
|
-
return ret
|
1558
|
+
return float(line.strip().split()[1])
|
1567
1559
|
msg = f"line 'btime' not found in {path}"
|
1568
1560
|
raise RuntimeError(msg)
|
1569
1561
|
|
@@ -1623,9 +1615,9 @@ def ppid_map():
|
|
1623
1615
|
with open_binary(f"{procfs_path}/{pid}/stat") as f:
|
1624
1616
|
data = f.read()
|
1625
1617
|
except (FileNotFoundError, ProcessLookupError):
|
1626
|
-
# Note: we should be able to access /stat for all processes
|
1627
|
-
# aka it's unlikely we'll bump into EPERM, which is good.
|
1628
1618
|
pass
|
1619
|
+
except PermissionError as err:
|
1620
|
+
raise AccessDenied(pid) from err
|
1629
1621
|
else:
|
1630
1622
|
rpar = data.rfind(b')')
|
1631
1623
|
dset = data[rpar + 2 :].split()
|
@@ -1664,12 +1656,20 @@ def wrap_exceptions(fun):
|
|
1664
1656
|
class Process:
|
1665
1657
|
"""Linux process implementation."""
|
1666
1658
|
|
1667
|
-
__slots__ = [
|
1659
|
+
__slots__ = [
|
1660
|
+
"_cache",
|
1661
|
+
"_ctime",
|
1662
|
+
"_name",
|
1663
|
+
"_ppid",
|
1664
|
+
"_procfs_path",
|
1665
|
+
"pid",
|
1666
|
+
]
|
1668
1667
|
|
1669
1668
|
def __init__(self, pid):
|
1670
1669
|
self.pid = pid
|
1671
1670
|
self._name = None
|
1672
1671
|
self._ppid = None
|
1672
|
+
self._ctime = None
|
1673
1673
|
self._procfs_path = get_procfs_path()
|
1674
1674
|
|
1675
1675
|
def _is_zombie(self):
|
@@ -1698,6 +1698,22 @@ class Process:
|
|
1698
1698
|
# incorrect or incomplete result.
|
1699
1699
|
os.stat(f"{self._procfs_path}/{self.pid}")
|
1700
1700
|
|
1701
|
+
def _readlink(self, path, fallback=UNSET):
|
1702
|
+
# * https://github.com/giampaolo/psutil/issues/503
|
1703
|
+
# os.readlink('/proc/pid/exe') may raise ESRCH (ProcessLookupError)
|
1704
|
+
# instead of ENOENT (FileNotFoundError) when it races.
|
1705
|
+
# * ENOENT may occur also if the path actually exists if PID is
|
1706
|
+
# a low PID (~0-20 range).
|
1707
|
+
# * https://github.com/giampaolo/psutil/issues/2514
|
1708
|
+
try:
|
1709
|
+
return readlink(path)
|
1710
|
+
except (FileNotFoundError, ProcessLookupError):
|
1711
|
+
if os.path.lexists(f"{self._procfs_path}/{self.pid}"):
|
1712
|
+
self._raise_if_zombie()
|
1713
|
+
if fallback is not UNSET:
|
1714
|
+
return fallback
|
1715
|
+
raise
|
1716
|
+
|
1701
1717
|
@wrap_exceptions
|
1702
1718
|
@memoize_when_activated
|
1703
1719
|
def _parse_stat_file(self):
|
@@ -1770,16 +1786,9 @@ class Process:
|
|
1770
1786
|
|
1771
1787
|
@wrap_exceptions
|
1772
1788
|
def exe(self):
|
1773
|
-
|
1774
|
-
|
1775
|
-
|
1776
|
-
self._raise_if_zombie()
|
1777
|
-
# no such file error; might be raised also if the
|
1778
|
-
# path actually exists for system processes with
|
1779
|
-
# low pids (about 0-20)
|
1780
|
-
if os.path.lexists(f"{self._procfs_path}/{self.pid}"):
|
1781
|
-
return ""
|
1782
|
-
raise
|
1789
|
+
return self._readlink(
|
1790
|
+
f"{self._procfs_path}/{self.pid}/exe", fallback=""
|
1791
|
+
)
|
1783
1792
|
|
1784
1793
|
@wrap_exceptions
|
1785
1794
|
def cmdline(self):
|
@@ -1880,15 +1889,21 @@ class Process:
|
|
1880
1889
|
return _psposix.wait_pid(self.pid, timeout, self._name)
|
1881
1890
|
|
1882
1891
|
@wrap_exceptions
|
1883
|
-
def create_time(self):
|
1884
|
-
|
1885
|
-
#
|
1886
|
-
#
|
1887
|
-
#
|
1888
|
-
#
|
1889
|
-
|
1890
|
-
|
1891
|
-
|
1892
|
+
def create_time(self, monotonic=False):
|
1893
|
+
# The 'starttime' field in /proc/[pid]/stat is expressed in
|
1894
|
+
# jiffies (clock ticks per second), a relative value which
|
1895
|
+
# represents the number of clock ticks that have passed since
|
1896
|
+
# the system booted until the process was created. It never
|
1897
|
+
# changes and is unaffected by system clock updates.
|
1898
|
+
if self._ctime is None:
|
1899
|
+
self._ctime = (
|
1900
|
+
float(self._parse_stat_file()['create_time']) / CLOCK_TICKS
|
1901
|
+
)
|
1902
|
+
if monotonic:
|
1903
|
+
return self._ctime
|
1904
|
+
# Add the boot time, returning time expressed in seconds since
|
1905
|
+
# the epoch. This is subject to system clock updates.
|
1906
|
+
return self._ctime + boot_time()
|
1892
1907
|
|
1893
1908
|
@wrap_exceptions
|
1894
1909
|
def memory_info(self):
|
@@ -2001,7 +2016,7 @@ class Process:
|
|
2001
2016
|
else:
|
2002
2017
|
try:
|
2003
2018
|
data[fields[0]] = int(fields[1]) * 1024
|
2004
|
-
except ValueError:
|
2019
|
+
except (ValueError, IndexError):
|
2005
2020
|
if fields[0].startswith(b'VmFlags:'):
|
2006
2021
|
# see issue #369
|
2007
2022
|
continue
|
@@ -2054,7 +2069,9 @@ class Process:
|
|
2054
2069
|
|
2055
2070
|
@wrap_exceptions
|
2056
2071
|
def cwd(self):
|
2057
|
-
return
|
2072
|
+
return self._readlink(
|
2073
|
+
f"{self._procfs_path}/{self.pid}/cwd", fallback=""
|
2074
|
+
)
|
2058
2075
|
|
2059
2076
|
@wrap_exceptions
|
2060
2077
|
def num_ctx_switches(
|
@@ -18,12 +18,12 @@ from ._common import NoSuchProcess
|
|
18
18
|
from ._common import ZombieProcess
|
19
19
|
from ._common import conn_tmap
|
20
20
|
from ._common import conn_to_ntuple
|
21
|
+
from ._common import debug
|
21
22
|
from ._common import isfile_strict
|
22
23
|
from ._common import memoize_when_activated
|
23
24
|
from ._common import parse_environ_block
|
24
25
|
from ._common import usage_percent
|
25
26
|
|
26
|
-
|
27
27
|
__extra__all__ = []
|
28
28
|
|
29
29
|
|
@@ -170,14 +170,16 @@ def cpu_stats():
|
|
170
170
|
)
|
171
171
|
|
172
172
|
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
173
|
+
if cext.has_cpu_freq(): # not always available on ARM64
|
174
|
+
|
175
|
+
def cpu_freq():
|
176
|
+
"""Return CPU frequency.
|
177
|
+
On macOS per-cpu frequency is not supported.
|
178
|
+
Also, the returned frequency never changes, see:
|
179
|
+
https://arstechnica.com/civis/viewtopic.php?f=19&t=465002.
|
180
|
+
"""
|
181
|
+
curr, min_, max_ = cext.cpu_freq()
|
182
|
+
return [_common.scpufreq(curr, min_, max_)]
|
181
183
|
|
182
184
|
|
183
185
|
# =====================================================================
|
@@ -288,10 +290,33 @@ def boot_time():
|
|
288
290
|
return cext.boot_time()
|
289
291
|
|
290
292
|
|
293
|
+
try:
|
294
|
+
INIT_BOOT_TIME = boot_time()
|
295
|
+
except Exception as err: # noqa: BLE001
|
296
|
+
# Don't want to crash at import time.
|
297
|
+
debug(f"ignoring exception on import: {err!r}")
|
298
|
+
INIT_BOOT_TIME = 0
|
299
|
+
|
300
|
+
|
301
|
+
def adjust_proc_create_time(ctime):
|
302
|
+
"""Account for system clock updates."""
|
303
|
+
if INIT_BOOT_TIME == 0:
|
304
|
+
return ctime
|
305
|
+
|
306
|
+
diff = INIT_BOOT_TIME - boot_time()
|
307
|
+
if diff == 0 or abs(diff) < 1:
|
308
|
+
return ctime
|
309
|
+
|
310
|
+
debug("system clock was updated; adjusting process create_time()")
|
311
|
+
if diff < 0:
|
312
|
+
return ctime - diff
|
313
|
+
return ctime + diff
|
314
|
+
|
315
|
+
|
291
316
|
def users():
|
292
317
|
"""Return currently connected users as a list of namedtuples."""
|
293
318
|
retlist = []
|
294
|
-
rawlist =
|
319
|
+
rawlist = cext_posix.users()
|
295
320
|
for item in rawlist:
|
296
321
|
user, tty, hostname, tstamp, pid = item
|
297
322
|
if tty == '~':
|
@@ -470,8 +495,11 @@ class Process:
|
|
470
495
|
)
|
471
496
|
|
472
497
|
@wrap_exceptions
|
473
|
-
def create_time(self):
|
474
|
-
|
498
|
+
def create_time(self, monotonic=False):
|
499
|
+
ctime = self._get_kinfo_proc()[kinfo_proc_map['ctime']]
|
500
|
+
if not monotonic:
|
501
|
+
ctime = adjust_proc_create_time(ctime)
|
502
|
+
return ctime
|
475
503
|
|
476
504
|
@wrap_exceptions
|
477
505
|
def num_ctx_switches(self):
|