py2docfx 0.1.20rc2245107__py3-none-any.whl → 0.1.21.dev2249770__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/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-0.1.20rc2245107.dist-info → py2docfx-0.1.21.dev2249770.dist-info}/METADATA +1 -1
- {py2docfx-0.1.20rc2245107.dist-info → py2docfx-0.1.21.dev2249770.dist-info}/RECORD +37 -36
- {py2docfx-0.1.20rc2245107.dist-info → py2docfx-0.1.21.dev2249770.dist-info}/WHEEL +0 -0
- {py2docfx-0.1.20rc2245107.dist-info → py2docfx-0.1.21.dev2249770.dist-info}/top_level.txt +0 -0
@@ -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):
|
@@ -30,7 +30,6 @@ from ._common import sockfam_to_enum
|
|
30
30
|
from ._common import socktype_to_enum
|
31
31
|
from ._common import usage_percent
|
32
32
|
|
33
|
-
|
34
33
|
__extra__all__ = ["CONN_IDLE", "CONN_BOUND", "PROCFS_PATH"]
|
35
34
|
|
36
35
|
|
@@ -311,7 +310,7 @@ def boot_time():
|
|
311
310
|
def users():
|
312
311
|
"""Return currently connected users as a list of namedtuples."""
|
313
312
|
retlist = []
|
314
|
-
rawlist =
|
313
|
+
rawlist = cext_posix.users()
|
315
314
|
localhost = (':0.0', ':0')
|
316
315
|
for item in rawlist:
|
317
316
|
user, tty, hostname, tstamp, user_process, pid = item
|
@@ -10,6 +10,7 @@ import functools
|
|
10
10
|
import os
|
11
11
|
import signal
|
12
12
|
import sys
|
13
|
+
import threading
|
13
14
|
import time
|
14
15
|
from collections import namedtuple
|
15
16
|
|
@@ -33,7 +34,6 @@ from ._psutil_windows import IDLE_PRIORITY_CLASS
|
|
33
34
|
from ._psutil_windows import NORMAL_PRIORITY_CLASS
|
34
35
|
from ._psutil_windows import REALTIME_PRIORITY_CLASS
|
35
36
|
|
36
|
-
|
37
37
|
try:
|
38
38
|
from . import _psutil_windows as cext
|
39
39
|
except ImportError as err:
|
@@ -184,12 +184,21 @@ pio = namedtuple('pio', ['read_count', 'write_count',
|
|
184
184
|
@functools.lru_cache(maxsize=512)
|
185
185
|
def convert_dos_path(s):
|
186
186
|
r"""Convert paths using native DOS format like:
|
187
|
-
"\Device\HarddiskVolume1\Windows\systemew\file.txt"
|
187
|
+
"\Device\HarddiskVolume1\Windows\systemew\file.txt" or
|
188
|
+
"\??\C:\Windows\systemew\file.txt"
|
188
189
|
into:
|
189
190
|
"C:\Windows\systemew\file.txt".
|
190
191
|
"""
|
192
|
+
if s.startswith('\\\\'):
|
193
|
+
return s
|
191
194
|
rawdrive = '\\'.join(s.split('\\')[:3])
|
192
|
-
|
195
|
+
if rawdrive in {"\\??\\UNC", "\\Device\\Mup"}:
|
196
|
+
rawdrive = '\\'.join(s.split('\\')[:5])
|
197
|
+
driveletter = '\\\\' + '\\'.join(s.split('\\')[3:5])
|
198
|
+
elif rawdrive.startswith('\\??\\'):
|
199
|
+
driveletter = s.split('\\')[2]
|
200
|
+
else:
|
201
|
+
driveletter = cext.QueryDosDevice(rawdrive)
|
193
202
|
remainder = s[len(rawdrive) :]
|
194
203
|
return os.path.join(driveletter, remainder)
|
195
204
|
|
@@ -322,22 +331,31 @@ def cpu_freq():
|
|
322
331
|
return [_common.scpufreq(float(curr), min_, float(max_))]
|
323
332
|
|
324
333
|
|
325
|
-
|
334
|
+
_loadavg_initialized = False
|
335
|
+
_lock = threading.Lock()
|
336
|
+
|
337
|
+
|
338
|
+
def _getloadavg_impl():
|
339
|
+
# Drop to 2 decimal points which is what Linux does
|
340
|
+
raw_loads = cext.getloadavg()
|
341
|
+
return tuple(round(load, 2) for load in raw_loads)
|
326
342
|
|
327
343
|
|
328
344
|
def getloadavg():
|
329
345
|
"""Return the number of processes in the system run queue averaged
|
330
346
|
over the last 1, 5, and 15 minutes respectively as a tuple.
|
331
347
|
"""
|
332
|
-
global
|
348
|
+
global _loadavg_initialized
|
333
349
|
|
334
|
-
if
|
335
|
-
|
336
|
-
_loadavg_inititialized = True
|
350
|
+
if _loadavg_initialized:
|
351
|
+
return _getloadavg_impl()
|
337
352
|
|
338
|
-
|
339
|
-
|
340
|
-
|
353
|
+
with _lock:
|
354
|
+
if not _loadavg_initialized:
|
355
|
+
cext.init_loadavg_counter()
|
356
|
+
_loadavg_initialized = True
|
357
|
+
|
358
|
+
return _getloadavg_impl()
|
341
359
|
|
342
360
|
|
343
361
|
# =====================================================================
|
@@ -426,12 +444,14 @@ _last_btime = 0
|
|
426
444
|
|
427
445
|
|
428
446
|
def boot_time():
|
429
|
-
"""The system boot time expressed in seconds since the epoch.
|
447
|
+
"""The system boot time expressed in seconds since the epoch. This
|
448
|
+
also includes the time spent during hybernate / suspend.
|
449
|
+
"""
|
430
450
|
# This dirty hack is to adjust the precision of the returned
|
431
451
|
# value which may have a 1 second fluctuation, see:
|
432
452
|
# https://github.com/giampaolo/psutil/issues/1007
|
433
453
|
global _last_btime
|
434
|
-
ret =
|
454
|
+
ret = time.time() - cext.uptime()
|
435
455
|
if abs(ret - _last_btime) <= 1:
|
436
456
|
return _last_btime
|
437
457
|
else:
|