增加JAVA环境配置
增加VC运行库安装
增加检测升级功能
更新PY模块
This commit is contained in:
shileiye 2022-01-05 03:12:34 +08:00
parent f3ce17779b
commit 3ece9fa803
55 changed files with 827 additions and 1776 deletions

2
.idea/misc.xml generated
View File

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.9 (onekey)" project-jdk-type="Python SDK" /> <component name="ProjectRootManager" version="2" project-jdk-name="Python 3.9" project-jdk-type="Python SDK" />
</project> </project>

2
.idea/onekey.iml generated
View File

@ -4,7 +4,7 @@
<content url="file://$MODULE_DIR$"> <content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/venv" /> <excludeFolder url="file://$MODULE_DIR$/venv" />
</content> </content>
<orderEntry type="inheritedJdk" /> <orderEntry type="jdk" jdkName="Python 3.9" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" /> <orderEntry type="sourceFolder" forTests="false" />
</component> </component>
</module> </module>

8
dist/config.ini vendored
View File

@ -52,7 +52,7 @@ gm_url = http://${domain_name}:${web_port}/gm
gm_code = 123456 gm_code = 123456
gm_user = test gm_user = test
gm_pass = test gm_pass = test
game_back = http://${domain_name}:${web_port}/gameback game_url = http://${domain_name}:${web_port}/gameback
game_code = 123456 game_code = 123456
game_user = test game_user = test
game_pass = test game_pass = test
@ -79,11 +79,11 @@ android_name_file = ${android_path}game\
tmp_android_name = ${android_path}game_tmp.apk tmp_android_name = ${android_path}game_tmp.apk
new_android_name = ${android_path}game_signed.apk new_android_name = ${android_path}game_signed.apk
[pc] [PC]
pc_path = ${GAME:client_path}pc\ pc_path = ${GAME:client_path}pc\
pc_name = ${pc_path}pc\bin.exe pc_name = ${pc_path}pc\bin.exe
[ios] [IOS]
ios_path = ${GAME:client_path}ios\ ios_path = ${GAME:client_path}ios\
ios_name = ${android_path}game.ipa ios_name = ${android_path}game.ipa
@ -92,6 +92,8 @@ apktool_path = ${GAME:tool_path}apktool\
heidisql_path = ${GAME:tool_path}HeidiSQL\heidisql.exe heidisql_path = ${GAME:tool_path}HeidiSQL\heidisql.exe
notepad3_path = ${GAME:tool_path}Notepad3\Notepad3.exe notepad3_path = ${GAME:tool_path}Notepad3\Notepad3.exe
composer_path = ${GAME:tool_path}Composer\ composer_path = ${GAME:tool_path}Composer\
java_path = ${GAME:tool_path}jdk-8\
msvbcrt_path = ${GAME:tool_path}Other\MSVBCRT.exe
[OTHER] [OTHER]
about = shileiye about = shileiye

BIN
dist/main.exe vendored

Binary file not shown.

View File

@ -5,7 +5,7 @@ block_cipher = None
a = Analysis(['main.py'], a = Analysis(['main.py'],
pathex=['D:\\soft\\Python\\Python39\\Lib\\site-packages', 'D:\\soft\\Python\\Python39\\Lib', 'D:\\soft\\Python\\Python39\\Lib\\site-packages\\PyQt5\\Qt\\bin', 'D:\\Code\\python\\onekey\\venv\\Lib\\site-packages', ''], pathex=[],
binaries=[], binaries=[],
datas=[], datas=[],
hiddenimports=[], hiddenimports=[],

View File

@ -2,5 +2,5 @@
### 打包命令 ### 打包命令
```python ```python
pyinstaller -F -w -p D:\soft\Python\Python39\Lib\site-packages;D:\soft\Python\Python39\Lib;D:\soft\Python\Python39\Lib\site-packages\PyQt5\Qt\bin;D:\Code\python\onekey\venv\Lib\site-packages; main.py pyinstaller -F -w -p D:\soft\Python\Python39\Lib\site-packages;D:\soft\Python\Python39\Lib;D:\soft\Python\Python39\Lib\site-packages\PyQt5\Qt\bin;D:\Code\python\onekey\venv\Lib\site-packages; .\main.py
``` ```

View File

@ -3,6 +3,7 @@ import os
import re import re
import importlib import importlib
import warnings import warnings
import contextlib
is_pypy = '__pypy__' in sys.builtin_module_names is_pypy = '__pypy__' in sys.builtin_module_names
@ -52,9 +53,8 @@ def ensure_local_distutils():
# With the DistutilsMetaFinder in place, # With the DistutilsMetaFinder in place,
# perform an import to cause distutils to be # perform an import to cause distutils to be
# loaded from setuptools._distutils. Ref #2906. # loaded from setuptools._distutils. Ref #2906.
add_shim() with shim():
importlib.import_module('distutils') importlib.import_module('distutils')
remove_shim()
# check that submodules load as expected # check that submodules load as expected
core = importlib.import_module('distutils.core') core = importlib.import_module('distutils.core')
@ -86,10 +86,23 @@ class DistutilsMetaFinder:
import importlib.abc import importlib.abc
import importlib.util import importlib.util
try:
mod = importlib.import_module('setuptools._distutils')
except Exception:
# There are a couple of cases where setuptools._distutils
# may not be present:
# - An older Setuptools without a local distutils is
# taking precedence. Ref #2957.
# - Path manipulation during sitecustomize removes
# setuptools from the path but only after the hook
# has been loaded. Ref #2980.
# In either case, fall back to stdlib behavior.
return
class DistutilsLoader(importlib.abc.Loader): class DistutilsLoader(importlib.abc.Loader):
def create_module(self, spec): def create_module(self, spec):
return importlib.import_module('setuptools._distutils') return mod
def exec_module(self, module): def exec_module(self, module):
pass pass
@ -130,6 +143,19 @@ DISTUTILS_FINDER = DistutilsMetaFinder()
def add_shim(): def add_shim():
DISTUTILS_FINDER in sys.meta_path or insert_shim()
@contextlib.contextmanager
def shim():
insert_shim()
try:
yield
finally:
remove_shim()
def insert_shim():
sys.meta_path.insert(0, DISTUTILS_FINDER) sys.meta_path.insert(0, DISTUTILS_FINDER)

View File

@ -1,29 +0,0 @@
BSD 3-Clause License
Copyright (c) 2009, Jay Loden, Dave Daeschler, Giampaolo Rodola'
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of the psutil authors nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -1,560 +0,0 @@
Metadata-Version: 2.1
Name: psutil
Version: 5.8.0
Summary: Cross-platform lib for process and system monitoring in Python.
Home-page: https://github.com/giampaolo/psutil
Author: Giampaolo Rodola
Author-email: g.rodola@gmail.com
License: BSD
Keywords: ps,top,kill,free,lsof,netstat,nice,tty,ionice,uptime,taskmgr,process,df,iotop,iostat,ifconfig,taskset,who,pidof,pmap,smem,pstree,monitoring,ulimit,prlimit,smem,performance,metrics,agent,observability
Platform: Platform Independent
Classifier: Development Status :: 5 - Production/Stable
Classifier: Environment :: Console
Classifier: Environment :: Win32 (MS Windows)
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Information Technology
Classifier: Intended Audience :: System Administrators
Classifier: License :: OSI Approved :: BSD License
Classifier: Operating System :: MacOS :: MacOS X
Classifier: Operating System :: Microsoft :: Windows :: Windows 10
Classifier: Operating System :: Microsoft :: Windows :: Windows 7
Classifier: Operating System :: Microsoft :: Windows :: Windows 8
Classifier: Operating System :: Microsoft :: Windows :: Windows 8.1
Classifier: Operating System :: Microsoft :: Windows :: Windows Server 2003
Classifier: Operating System :: Microsoft :: Windows :: Windows Server 2008
Classifier: Operating System :: Microsoft :: Windows :: Windows Vista
Classifier: Operating System :: Microsoft
Classifier: Operating System :: OS Independent
Classifier: Operating System :: POSIX :: AIX
Classifier: Operating System :: POSIX :: BSD :: FreeBSD
Classifier: Operating System :: POSIX :: BSD :: NetBSD
Classifier: Operating System :: POSIX :: BSD :: OpenBSD
Classifier: Operating System :: POSIX :: BSD
Classifier: Operating System :: POSIX :: Linux
Classifier: Operating System :: POSIX :: SunOS/Solaris
Classifier: Operating System :: POSIX
Classifier: Programming Language :: C
Classifier: Programming Language :: Python :: 2
Classifier: Programming Language :: Python :: 2.6
Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Programming Language :: Python :: Implementation :: PyPy
Classifier: Programming Language :: Python
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Software Development :: Libraries
Classifier: Topic :: System :: Benchmark
Classifier: Topic :: System :: Hardware :: Hardware Drivers
Classifier: Topic :: System :: Hardware
Classifier: Topic :: System :: Monitoring
Classifier: Topic :: System :: Networking :: Monitoring :: Hardware Watchdog
Classifier: Topic :: System :: Networking :: Monitoring
Classifier: Topic :: System :: Networking
Classifier: Topic :: System :: Operating System
Classifier: Topic :: System :: Systems Administration
Classifier: Topic :: Utilities
Requires-Python: >=2.6, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*
Description-Content-Type: text/x-rst
Provides-Extra: test
Requires-Dist: ipaddress ; (python_version < "3.0") and extra == 'test'
Requires-Dist: mock ; (python_version < "3.0") and extra == 'test'
Requires-Dist: unittest2 ; (python_version < "3.0") and extra == 'test'
Requires-Dist: enum34 ; (python_version <= "3.4") and extra == 'test'
Requires-Dist: pywin32 ; (sys_platform == "win32") and extra == 'test'
Requires-Dist: wmi ; (sys_platform == "win32") and extra == 'test'
| |downloads| |stars| |forks| |contributors| |coverage| |quality|
| |version| |py-versions| |packages| |license|
| |github-actions| |appveyor| |doc| |twitter| |tidelift|
.. |downloads| image:: https://img.shields.io/pypi/dm/psutil.svg
:target: https://pepy.tech/project/psutil
:alt: Downloads
.. |stars| image:: https://img.shields.io/github/stars/giampaolo/psutil.svg
:target: https://github.com/giampaolo/psutil/stargazers
:alt: Github stars
.. |forks| image:: https://img.shields.io/github/forks/giampaolo/psutil.svg
:target: https://github.com/giampaolo/psutil/network/members
:alt: Github forks
.. |contributors| image:: https://img.shields.io/github/contributors/giampaolo/psutil.svg
:target: https://github.com/giampaolo/psutil/graphs/contributors
:alt: Contributors
.. |quality| image:: https://img.shields.io/codacy/grade/ce63e7f7f69d44b5b59682196e6fbfca.svg
:target: https://www.codacy.com/app/g-rodola/psutil?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=giampaolo/psutil&amp;utm_campaign=Badge_Grade
:alt: Code quality
.. |github-actions| image:: https://img.shields.io/github/workflow/status/giampaolo/psutil/CI?label=Linux%2C%20macOS%2C%20FreeBSD
:target: https://github.com/giampaolo/psutil/actions?query=workflow%3ACI
:alt: Linux, macOS, Windows tests
.. |appveyor| image:: https://img.shields.io/appveyor/ci/giampaolo/psutil/master.svg?maxAge=3600&label=Windows
:target: https://ci.appveyor.com/project/giampaolo/psutil
:alt: Windows tests (Appveyor)
.. |coverage| image:: https://coveralls.io/repos/github/giampaolo/psutil/badge.svg?branch=master
:target: https://coveralls.io/github/giampaolo/psutil?branch=master
:alt: Test coverage (coverall.io)
.. |doc| image:: https://readthedocs.org/projects/psutil/badge/?version=latest
:target: http://psutil.readthedocs.io/en/latest/?badge=latest
:alt: Documentation Status
.. |version| image:: https://img.shields.io/pypi/v/psutil.svg?label=pypi
:target: https://pypi.org/project/psutil
:alt: Latest version
.. |py-versions| image:: https://img.shields.io/pypi/pyversions/psutil.svg
:target: https://pypi.org/project/psutil
:alt: Supported Python versions
.. |packages| image:: https://repology.org/badge/tiny-repos/python:psutil.svg
:target: https://repology.org/metapackage/python:psutil/versions
:alt: Binary packages
.. |license| image:: https://img.shields.io/pypi/l/psutil.svg
:target: https://github.com/giampaolo/psutil/blob/master/LICENSE
:alt: License
.. |twitter| image:: https://img.shields.io/twitter/follow/grodola.svg?label=follow&style=flat&logo=twitter&logoColor=4FADFF
:target: https://twitter.com/grodola
:alt: Twitter Follow
.. |tidelift| image:: https://tidelift.com/badges/github/giampaolo/psutil?style=flat
:target: https://tidelift.com/subscription/pkg/pypi-psutil?utm_source=pypi-psutil&utm_medium=referral&utm_campaign=readme
:alt: Tidelift
-----
Quick links
===========
- `Home page <https://github.com/giampaolo/psutil>`_
- `Install <https://github.com/giampaolo/psutil/blob/master/INSTALL.rst>`_
- `Documentation <http://psutil.readthedocs.io>`_
- `Download <https://pypi.org/project/psutil/#files>`_
- `Forum <http://groups.google.com/group/psutil/topics>`_
- `StackOverflow <https://stackoverflow.com/questions/tagged/psutil>`_
- `Blog <https://gmpy.dev/tags/psutil>`_
- `What's new <https://github.com/giampaolo/psutil/blob/master/HISTORY.rst>`_
Summary
=======
psutil (process and system utilities) is a cross-platform library for
retrieving information on **running processes** and **system utilization**
(CPU, memory, disks, network, sensors) in Python.
It is useful mainly for **system monitoring**, **profiling and limiting process
resources** and **management of running processes**.
It implements many functionalities offered by classic UNIX command line tools
such as *ps, top, iotop, lsof, netstat, ifconfig, free* and others.
psutil currently supports the following platforms:
- **Linux**
- **Windows**
- **macOS**
- **FreeBSD, OpenBSD**, **NetBSD**
- **Sun Solaris**
- **AIX**
Supported Python versions are **2.6**, **2.7**, **3.4+** and
`PyPy <http://pypy.org/>`__.
Funding
=======
While psutil is free software and will always be, the project would benefit
immensely from some funding.
Keeping up with bug reports and maintenance has become hardly sustainable for
me alone in terms of time.
If you're a company that's making significant use of psutil you can consider
becoming a sponsor via `GitHub <https://github.com/sponsors/giampaolo>`__,
`Open Collective <https://opencollective.com/psutil>`__ or
`PayPal <https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A9ZS7PKKRM3S8>`__
and have your logo displayed in here and psutil `doc <https://psutil.readthedocs.io>`__.
Sponsors
========
.. image:: https://github.com/giampaolo/psutil/raw/master/docs/_static/tidelift-logo.png
:width: 200
:alt: Alternative text
`Add your logo <https://github.com/sponsors/giampaolo>`__.
Example usages
==============
This represents pretty much the whole psutil API.
CPU
---
.. code-block:: python
>>> import psutil
>>>
>>> psutil.cpu_times()
scputimes(user=3961.46, nice=169.729, system=2150.659, idle=16900.540, iowait=629.59, irq=0.0, softirq=19.42, steal=0.0, guest=0, nice=0.0)
>>>
>>> for x in range(3):
... psutil.cpu_percent(interval=1)
...
4.0
5.9
3.8
>>>
>>> for x in range(3):
... psutil.cpu_percent(interval=1, percpu=True)
...
[4.0, 6.9, 3.7, 9.2]
[7.0, 8.5, 2.4, 2.1]
[1.2, 9.0, 9.9, 7.2]
>>>
>>> for x in range(3):
... psutil.cpu_times_percent(interval=1, percpu=False)
...
scputimes(user=1.5, nice=0.0, system=0.5, idle=96.5, iowait=1.5, irq=0.0, softirq=0.0, steal=0.0, guest=0.0, guest_nice=0.0)
scputimes(user=1.0, nice=0.0, system=0.0, idle=99.0, iowait=0.0, irq=0.0, softirq=0.0, steal=0.0, guest=0.0, guest_nice=0.0)
scputimes(user=2.0, nice=0.0, system=0.0, idle=98.0, iowait=0.0, irq=0.0, softirq=0.0, steal=0.0, guest=0.0, guest_nice=0.0)
>>>
>>> psutil.cpu_count()
4
>>> psutil.cpu_count(logical=False)
2
>>>
>>> psutil.cpu_stats()
scpustats(ctx_switches=20455687, interrupts=6598984, soft_interrupts=2134212, syscalls=0)
>>>
>>> psutil.cpu_freq()
scpufreq(current=931.42925, min=800.0, max=3500.0)
>>>
>>> psutil.getloadavg() # also on Windows (emulated)
(3.14, 3.89, 4.67)
Memory
------
.. code-block:: python
>>> psutil.virtual_memory()
svmem(total=10367352832, available=6472179712, percent=37.6, used=8186245120, free=2181107712, active=4748992512, inactive=2758115328, buffers=790724608, cached=3500347392, shared=787554304)
>>> psutil.swap_memory()
sswap(total=2097147904, used=296128512, free=1801019392, percent=14.1, sin=304193536, sout=677842944)
>>>
Disks
-----
.. code-block:: python
>>> psutil.disk_partitions()
[sdiskpart(device='/dev/sda1', mountpoint='/', fstype='ext4', opts='rw,nosuid', maxfile=255, maxpath=4096),
sdiskpart(device='/dev/sda2', mountpoint='/home', fstype='ext, opts='rw', maxfile=255, maxpath=4096)]
>>>
>>> psutil.disk_usage('/')
sdiskusage(total=21378641920, used=4809781248, free=15482871808, percent=22.5)
>>>
>>> psutil.disk_io_counters(perdisk=False)
sdiskio(read_count=719566, write_count=1082197, read_bytes=18626220032, write_bytes=24081764352, read_time=5023392, write_time=63199568, read_merged_count=619166, write_merged_count=812396, busy_time=4523412)
>>>
Network
-------
.. code-block:: python
>>> psutil.net_io_counters(pernic=True)
{'eth0': netio(bytes_sent=485291293, bytes_recv=6004858642, packets_sent=3251564, packets_recv=4787798, errin=0, errout=0, dropin=0, dropout=0),
'lo': netio(bytes_sent=2838627, bytes_recv=2838627, packets_sent=30567, packets_recv=30567, errin=0, errout=0, dropin=0, dropout=0)}
>>>
>>> psutil.net_connections(kind='tcp')
[sconn(fd=115, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=addr(ip='10.0.0.1', port=48776), raddr=addr(ip='93.186.135.91', port=80), status='ESTABLISHED', pid=1254),
sconn(fd=117, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=addr(ip='10.0.0.1', port=43761), raddr=addr(ip='72.14.234.100', port=80), status='CLOSING', pid=2987),
...]
>>>
>>> psutil.net_if_addrs()
{'lo': [snicaddr(family=<AddressFamily.AF_INET: 2>, address='127.0.0.1', netmask='255.0.0.0', broadcast='127.0.0.1', ptp=None),
snicaddr(family=<AddressFamily.AF_INET6: 10>, address='::1', netmask='ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff', broadcast=None, ptp=None),
snicaddr(family=<AddressFamily.AF_LINK: 17>, address='00:00:00:00:00:00', netmask=None, broadcast='00:00:00:00:00:00', ptp=None)],
'wlan0': [snicaddr(family=<AddressFamily.AF_INET: 2>, address='192.168.1.3', netmask='255.255.255.0', broadcast='192.168.1.255', ptp=None),
snicaddr(family=<AddressFamily.AF_INET6: 10>, address='fe80::c685:8ff:fe45:641%wlan0', netmask='ffff:ffff:ffff:ffff::', broadcast=None, ptp=None),
snicaddr(family=<AddressFamily.AF_LINK: 17>, address='c4:85:08:45:06:41', netmask=None, broadcast='ff:ff:ff:ff:ff:ff', ptp=None)]}
>>>
>>> psutil.net_if_stats()
{'lo': snicstats(isup=True, duplex=<NicDuplex.NIC_DUPLEX_UNKNOWN: 0>, speed=0, mtu=65536),
'wlan0': snicstats(isup=True, duplex=<NicDuplex.NIC_DUPLEX_FULL: 2>, speed=100, mtu=1500)}
>>>
Sensors
-------
.. code-block:: python
>>> import psutil
>>> psutil.sensors_temperatures()
{'acpitz': [shwtemp(label='', current=47.0, high=103.0, critical=103.0)],
'asus': [shwtemp(label='', current=47.0, high=None, critical=None)],
'coretemp': [shwtemp(label='Physical id 0', current=52.0, high=100.0, critical=100.0),
shwtemp(label='Core 0', current=45.0, high=100.0, critical=100.0)]}
>>>
>>> psutil.sensors_fans()
{'asus': [sfan(label='cpu_fan', current=3200)]}
>>>
>>> psutil.sensors_battery()
sbattery(percent=93, secsleft=16628, power_plugged=False)
>>>
Other system info
-----------------
.. code-block:: python
>>> import psutil
>>> psutil.users()
[suser(name='giampaolo', terminal='pts/2', host='localhost', started=1340737536.0, pid=1352),
suser(name='giampaolo', terminal='pts/3', host='localhost', started=1340737792.0, pid=1788)]
>>>
>>> psutil.boot_time()
1365519115.0
>>>
Process management
------------------
.. code-block:: python
>>> import psutil
>>> psutil.pids()
[1, 2, 3, 4, 5, 6, 7, 46, 48, 50, 51, 178, 182, 222, 223, 224, 268, 1215,
1216, 1220, 1221, 1243, 1244, 1301, 1601, 2237, 2355, 2637, 2774, 3932,
4176, 4177, 4185, 4187, 4189, 4225, 4243, 4245, 4263, 4282, 4306, 4311,
4312, 4313, 4314, 4337, 4339, 4357, 4358, 4363, 4383, 4395, 4408, 4433,
4443, 4445, 4446, 5167, 5234, 5235, 5252, 5318, 5424, 5644, 6987, 7054,
7055, 7071]
>>>
>>> p = psutil.Process(7055)
>>> p
psutil.Process(pid=7055, name='python3', status='running', started='09:04:44')
>>> p.name()
'python'
>>> p.exe()
'/usr/bin/python'
>>> p.cwd()
'/home/giampaolo'
>>> p.cmdline()
['/usr/bin/python', 'main.py']
>>>
>>> p.pid
7055
>>> p.ppid()
7054
>>> p.children(recursive=True)
[psutil.Process(pid=29835, name='python3', status='sleeping', started='11:45:38'),
psutil.Process(pid=29836, name='python3', status='waking', started='11:43:39')]
>>>
>>> p.parent()
psutil.Process(pid=4699, name='bash', status='sleeping', started='09:06:44')
>>> p.parents()
[psutil.Process(pid=4699, name='bash', started='09:06:44'),
psutil.Process(pid=4689, name='gnome-terminal-server', status='sleeping', started='0:06:44'),
psutil.Process(pid=1, name='systemd', status='sleeping', started='05:56:55')]
>>>
>>> p.status()
'running'
>>> p.username()
'giampaolo'
>>> p.create_time()
1267551141.5019531
>>> p.terminal()
'/dev/pts/0'
>>>
>>> p.uids()
puids(real=1000, effective=1000, saved=1000)
>>> p.gids()
pgids(real=1000, effective=1000, saved=1000)
>>>
>>> p.cpu_times()
pcputimes(user=1.02, system=0.31, children_user=0.32, children_system=0.1, iowait=0.0)
>>> p.cpu_percent(interval=1.0)
12.1
>>> p.cpu_affinity()
[0, 1, 2, 3]
>>> p.cpu_affinity([0, 1]) # set
>>> p.cpu_num()
1
>>>
>>> p.memory_info()
pmem(rss=10915840, vms=67608576, shared=3313664, text=2310144, lib=0, data=7262208, dirty=0)
>>> p.memory_full_info() # "real" USS memory usage (Linux, macOS, Win only)
pfullmem(rss=10199040, vms=52133888, shared=3887104, text=2867200, lib=0, data=5967872, dirty=0, uss=6545408, pss=6872064, swap=0)
>>> p.memory_percent()
0.7823
>>> p.memory_maps()
[pmmap_grouped(path='/lib/x8664-linux-gnu/libutil-2.15.so', rss=32768, size=2125824, pss=32768, shared_clean=0, shared_dirty=0, private_clean=20480, private_dirty=12288, referenced=32768, anonymous=12288, swap=0),
pmmap_grouped(path='/lib/x8664-linux-gnu/libc-2.15.so', rss=3821568, size=3842048, pss=3821568, shared_clean=0, shared_dirty=0, private_clean=0, private_dirty=3821568, referenced=3575808, anonymous=3821568, swap=0),
pmmap_grouped(path='[heap]', rss=32768, size=139264, pss=32768, shared_clean=0, shared_dirty=0, private_clean=0, private_dirty=32768, referenced=32768, anonymous=32768, swap=0),
pmmap_grouped(path='[stack]', rss=2465792, size=2494464, pss=2465792, shared_clean=0, shared_dirty=0, private_clean=0, private_dirty=2465792, referenced=2277376, anonymous=2465792, swap=0),
...]
>>>
>>> p.io_counters()
pio(read_count=478001, write_count=59371, read_bytes=700416, write_bytes=69632, read_chars=456232, write_chars=517543)
>>>
>>> p.open_files()
[popenfile(path='/home/giampaolo/monit.py', fd=3, position=0, mode='r', flags=32768),
popenfile(path='/var/log/monit.log', fd=4, position=235542, mode='a', flags=33793)]
>>>
>>> p.connections(kind='tcp')
[pconn(fd=115, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=addr(ip='10.0.0.1', port=48776), raddr=addr(ip='93.186.135.91', port=80), status='ESTABLISHED'),
pconn(fd=117, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=addr(ip='10.0.0.1', port=43761), raddr=addr(ip='72.14.234.100', port=80), status='CLOSING')]
>>>
>>> p.num_threads()
4
>>> p.num_fds()
8
>>> p.threads()
[pthread(id=5234, user_time=22.5, system_time=9.2891),
pthread(id=5237, user_time=0.0707, system_time=1.1)]
>>>
>>> p.num_ctx_switches()
pctxsw(voluntary=78, involuntary=19)
>>>
>>> p.nice()
0
>>> p.nice(10) # set
>>>
>>> p.ionice(psutil.IOPRIO_CLASS_IDLE) # IO priority (Win and Linux only)
>>> p.ionice()
pionice(ioclass=<IOPriority.IOPRIO_CLASS_IDLE: 3>, value=0)
>>>
>>> p.rlimit(psutil.RLIMIT_NOFILE, (5, 5)) # set resource limits (Linux only)
>>> p.rlimit(psutil.RLIMIT_NOFILE)
(5, 5)
>>>
>>> p.environ()
{'LC_PAPER': 'it_IT.UTF-8', 'SHELL': '/bin/bash', 'GREP_OPTIONS': '--color=auto',
'XDG_CONFIG_DIRS': '/etc/xdg/xdg-ubuntu:/usr/share/upstart/xdg:/etc/xdg',
...}
>>>
>>> p.as_dict()
{'status': 'running', 'num_ctx_switches': pctxsw(voluntary=63, involuntary=1), 'pid': 5457, ...}
>>> p.is_running()
True
>>> p.suspend()
>>> p.resume()
>>>
>>> p.terminate()
>>> p.kill()
>>> p.wait(timeout=3)
<Exitcode.EX_OK: 0>
>>>
>>> psutil.test()
USER PID %CPU %MEM VSZ RSS TTY START TIME COMMAND
root 1 0.0 0.0 24584 2240 Jun17 00:00 init
root 2 0.0 0.0 0 0 Jun17 00:00 kthreadd
...
giampaolo 31475 0.0 0.0 20760 3024 /dev/pts/0 Jun19 00:00 python2.4
giampaolo 31721 0.0 2.2 773060 181896 00:04 10:30 chrome
root 31763 0.0 0.0 0 0 00:05 00:00 kworker/0:1
>>>
Further process APIs
--------------------
.. code-block:: python
>>> import psutil
>>> for proc in psutil.process_iter(['pid', 'name']):
... print(proc.info)
...
{'pid': 1, 'name': 'systemd'}
{'pid': 2, 'name': 'kthreadd'}
{'pid': 3, 'name': 'ksoftirqd/0'}
...
>>>
>>> psutil.pid_exists(3)
True
>>>
>>> def on_terminate(proc):
... print("process {} terminated".format(proc))
...
>>> # waits for multiple processes to terminate
>>> gone, alive = psutil.wait_procs(procs_list, timeout=3, callback=on_terminate)
>>>
Popen wrapper:
.. code-block:: python
>>> import psutil
>>> from subprocess import PIPE
>>> p = psutil.Popen(["/usr/bin/python", "-c", "print('hello')"], stdout=PIPE)
>>> p.name()
'python'
>>> p.username()
'giampaolo'
>>> p.communicate()
('hello\n', None)
>>> p.wait(timeout=2)
0
>>>
Windows services
----------------
.. code-block:: python
>>> list(psutil.win_service_iter())
[<WindowsService(name='AeLookupSvc', display_name='Application Experience') at 38850096>,
<WindowsService(name='ALG', display_name='Application Layer Gateway Service') at 38850128>,
<WindowsService(name='APNMCP', display_name='Ask Update Service') at 38850160>,
<WindowsService(name='AppIDSvc', display_name='Application Identity') at 38850192>,
...]
>>> s = psutil.win_service_get('alg')
>>> s.as_dict()
{'binpath': 'C:\\Windows\\System32\\alg.exe',
'description': 'Provides support for 3rd party protocol plug-ins for Internet Connection Sharing',
'display_name': 'Application Layer Gateway Service',
'name': 'alg',
'pid': None,
'start_type': 'manual',
'status': 'stopped',
'username': 'NT AUTHORITY\\LocalService'}
Projects using psutil
=====================
Here's some I find particularly interesting:
- https://github.com/google/grr
- https://github.com/facebook/osquery/
- https://github.com/nicolargo/glances
- https://github.com/Jahaja/psdash
- https://github.com/ajenti/ajenti
- https://github.com/home-assistant/home-assistant/
Portings
========
- Go: https://github.com/shirou/gopsutil
- C: https://github.com/hamon-in/cpslib
- Rust: https://github.com/rust-psutil/rust-psutil
- Nim: https://github.com/johnscillieri/psutil-nim
Security
========
To report a security vulnerability, please use the `Tidelift security
contact`_. Tidelift will coordinate the fix and disclosure.
.. _`Giampaolo Rodola`: https://gmpy.dev/about
.. _`donation`: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A9ZS7PKKRM3S8
.. _Tidelift security contact: https://tidelift.com/security
.. _Tidelift Subscription: https://tidelift.com/subscription/pkg/pypi-psutil?utm_source=pypi-psutil&utm_medium=referral&utm_campaign=readme

View File

@ -1,64 +0,0 @@
psutil-5.8.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
psutil-5.8.0.dist-info/LICENSE,sha256=JMEphFAMqgf_3OGe68BjlsXm0kS1c7xsQ49KbvjlbBs,1549
psutil-5.8.0.dist-info/METADATA,sha256=Bphj_aWaN0I3HJ9grSaLCwTHYKWVx9Gh3lV9WQvyBeY,22626
psutil-5.8.0.dist-info/RECORD,,
psutil-5.8.0.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
psutil-5.8.0.dist-info/WHEEL,sha256=jr7ubY0Lkz_yXH9FfFe9PTtLhGOsf62dZkNvTYrJINE,100
psutil-5.8.0.dist-info/top_level.txt,sha256=gCNhn57wzksDjSAISmgMJ0aiXzQulk0GJhb2-BAyYgw,7
psutil/__init__.py,sha256=kBgynYzuxNXqFVpCNdTr0RqSmR-TqcHraDedB2ycPak,86749
psutil/__pycache__/__init__.cpython-39.pyc,,
psutil/__pycache__/_common.cpython-39.pyc,,
psutil/__pycache__/_compat.cpython-39.pyc,,
psutil/__pycache__/_psaix.cpython-39.pyc,,
psutil/__pycache__/_psbsd.cpython-39.pyc,,
psutil/__pycache__/_pslinux.cpython-39.pyc,,
psutil/__pycache__/_psosx.cpython-39.pyc,,
psutil/__pycache__/_psposix.cpython-39.pyc,,
psutil/__pycache__/_pssunos.cpython-39.pyc,,
psutil/__pycache__/_pswindows.cpython-39.pyc,,
psutil/_common.py,sha256=Iej9ua0_H4c-lgmKx3xBWDHRP-Pb4szU-QNb8cN6d8M,26218
psutil/_compat.py,sha256=wiGTaLFqCNUrCFvFfRXp4Y3gn5FiqzLUFVTCp6GA3tY,14474
psutil/_psaix.py,sha256=0tYwysbZZOZshzh5Jlrmgh7yZBj9mARdKpfIEtSB2CM,18555
psutil/_psbsd.py,sha256=wciWlLRNUfukUjld8xO-6MpO5D0q-3WxFQbeC9OKmlw,31069
psutil/_pslinux.py,sha256=5YfU-zmscLdqxrm481q3_PFyrY8z0iQnRHjbLmY0nJ0,82101
psutil/_psosx.py,sha256=SLUzYazQXOdIJ0yZjm-UqlDF-hJHy8yaDR4sljDeMCc,17494
psutil/_psposix.py,sha256=IcXJTdU6osTJwjB2uDohCLnuGPl5BGQYD6vDg0sOJ8c,8045
psutil/_pssunos.py,sha256=u3wVhSnBLtQFtCfhND1rxD2KHWB4zKaNIpmeCG5z5Mc,25495
psutil/_psutil_windows.cp39-win_amd64.pyd,sha256=959nMupaNnUxLvS5UGvtjhWqLZxyLTDQyWJ0Z1qp3Gg,76288
psutil/_pswindows.py,sha256=JyffHx0PmRJY-4FnL0eevPdmrnB7d96AuV6mTvUavPc,36841
psutil/tests/__init__.py,sha256=6SFK_zga_qUnJOnKF6AIWasKGIYwd6XXqXg3KxJiX1Y,57568
psutil/tests/__main__.py,sha256=bBfMPu_gPzyiA4gfAFSZLk7LyLSPTUIHQFU1kFcj_Ok,291
psutil/tests/__pycache__/__init__.cpython-39.pyc,,
psutil/tests/__pycache__/__main__.cpython-39.pyc,,
psutil/tests/__pycache__/runner.cpython-39.pyc,,
psutil/tests/__pycache__/test_aix.cpython-39.pyc,,
psutil/tests/__pycache__/test_bsd.cpython-39.pyc,,
psutil/tests/__pycache__/test_connections.cpython-39.pyc,,
psutil/tests/__pycache__/test_contracts.cpython-39.pyc,,
psutil/tests/__pycache__/test_linux.cpython-39.pyc,,
psutil/tests/__pycache__/test_memleaks.cpython-39.pyc,,
psutil/tests/__pycache__/test_misc.cpython-39.pyc,,
psutil/tests/__pycache__/test_osx.cpython-39.pyc,,
psutil/tests/__pycache__/test_posix.cpython-39.pyc,,
psutil/tests/__pycache__/test_process.cpython-39.pyc,,
psutil/tests/__pycache__/test_sunos.cpython-39.pyc,,
psutil/tests/__pycache__/test_system.cpython-39.pyc,,
psutil/tests/__pycache__/test_testutils.cpython-39.pyc,,
psutil/tests/__pycache__/test_unicode.cpython-39.pyc,,
psutil/tests/__pycache__/test_windows.cpython-39.pyc,,
psutil/tests/runner.py,sha256=aWiBnzMuH42dGAeofRuOgmDPcyKI9Yr0u1PI4HLDPOE,11332
psutil/tests/test_aix.py,sha256=r78PBazMdlagip3tnWdZIS6HxQNTirE9c8GWqPkcKTw,4526
psutil/tests/test_bsd.py,sha256=3tTFVIkmXZFkHyaFydsmJH_-lsAEk1HuAAi3-LgBGJM,20695
psutil/tests/test_connections.py,sha256=-4pjxtJGWobjidWEkuEFIS7SHA5eXvEcrj2MG51Fqb8,21434
psutil/tests/test_contracts.py,sha256=ID5_K_GwlQLYJZdl3BbZcV-ZcnptwlfNx42mM7a58Kk,27097
psutil/tests/test_linux.py,sha256=jEiPD5gSCrUiFOvau-sRncPO3StetoIlxPJcYzarTas,89802
psutil/tests/test_memleaks.py,sha256=tDP4poPQeCdXcD5DayQ0uLb71Yy_bk0QlIYNdBl-ems,14796
psutil/tests/test_misc.py,sha256=KyB__5fP8Lwt57ZirpFkWtPa3psX9S5D9zJQIR2dFl8,28584
psutil/tests/test_osx.py,sha256=PAQf49HUiN8n0DKmUWCXCaEV-2h20m1jeuLX85pxsg8,7550
psutil/tests/test_posix.py,sha256=qN0W3r760F5c6dGFTYKVsyNjG16wX_fpVs2k1K8CqSE,15143
psutil/tests/test_process.py,sha256=bCcCqfc2JxKI9PvuW7mpFY599rxoMZKzkxDRT-Oms0k,59703
psutil/tests/test_sunos.py,sha256=tosB6-4boM6ZlIVaeJZh6YbBY8gVGRm0YIXgb_Z69GU,1351
psutil/tests/test_system.py,sha256=dT0v3X4ZZl1RO0ARYU_AkvNAzsGt21CIIQ9-_VvbQa4,35596
psutil/tests/test_testutils.py,sha256=A9nneh29Z9rN7wM4ekBg4QdXL5diD4mCUI1Uw6B5jec,14420
psutil/tests/test_unicode.py,sha256=cPwy2YUW8XV0U9oIsMCBFhS2SMu5htdFD3DTimmRtic,12459
psutil/tests/test_windows.py,sha256=dkEkbFEUaI2L5syFte9vok42n_r_DsTjbFu6IZ6SzvQ,32589

View File

@ -1,5 +0,0 @@
Wheel-Version: 1.0
Generator: bdist_wheel (0.36.2)
Root-Is-Purelib: false
Tag: cp39-cp39-win_amd64

View File

@ -21,6 +21,7 @@ Works with Python versions from 2.6 to 3.4+.
""" """
from __future__ import division from __future__ import division
import collections import collections
import contextlib import contextlib
import datetime import datetime
@ -31,24 +32,16 @@ import subprocess
import sys import sys
import threading import threading
import time import time
try: try:
import pwd import pwd
except ImportError: except ImportError:
pwd = None pwd = None
from . import _common from . import _common
from ._common import AccessDenied from ._common import AIX
from ._common import Error from ._common import BSD
from ._common import memoize_when_activated
from ._common import NoSuchProcess
from ._common import TimeoutExpired
from ._common import wrap_numbers as _wrap_numbers
from ._common import ZombieProcess
from ._compat import long
from ._compat import PermissionError
from ._compat import ProcessLookupError
from ._compat import PY3 as _PY3
from ._common import CONN_CLOSE from ._common import CONN_CLOSE
from ._common import CONN_CLOSE_WAIT from ._common import CONN_CLOSE_WAIT
from ._common import CONN_CLOSING from ._common import CONN_CLOSING
@ -61,9 +54,16 @@ from ._common import CONN_NONE
from ._common import CONN_SYN_RECV from ._common import CONN_SYN_RECV
from ._common import CONN_SYN_SENT from ._common import CONN_SYN_SENT
from ._common import CONN_TIME_WAIT from ._common import CONN_TIME_WAIT
from ._common import FREEBSD # NOQA
from ._common import LINUX
from ._common import MACOS
from ._common import NETBSD # NOQA
from ._common import NIC_DUPLEX_FULL from ._common import NIC_DUPLEX_FULL
from ._common import NIC_DUPLEX_HALF from ._common import NIC_DUPLEX_HALF
from ._common import NIC_DUPLEX_UNKNOWN from ._common import NIC_DUPLEX_UNKNOWN
from ._common import OPENBSD # NOQA
from ._common import OSX # deprecated alias
from ._common import POSIX # NOQA
from ._common import POWER_TIME_UNKNOWN from ._common import POWER_TIME_UNKNOWN
from ._common import POWER_TIME_UNLIMITED from ._common import POWER_TIME_UNLIMITED
from ._common import STATUS_DEAD from ._common import STATUS_DEAD
@ -78,18 +78,21 @@ from ._common import STATUS_TRACING_STOP
from ._common import STATUS_WAITING from ._common import STATUS_WAITING
from ._common import STATUS_WAKING from ._common import STATUS_WAKING
from ._common import STATUS_ZOMBIE from ._common import STATUS_ZOMBIE
from ._common import AIX
from ._common import BSD
from ._common import FREEBSD # NOQA
from ._common import LINUX
from ._common import MACOS
from ._common import NETBSD # NOQA
from ._common import OPENBSD # NOQA
from ._common import OSX # deprecated alias
from ._common import POSIX # NOQA
from ._common import SUNOS from ._common import SUNOS
from ._common import WINDOWS from ._common import WINDOWS
from ._common import AccessDenied
from ._common import Error
from ._common import NoSuchProcess
from ._common import TimeoutExpired
from ._common import ZombieProcess
from ._common import memoize_when_activated
from ._common import wrap_numbers as _wrap_numbers
from ._compat import PY3 as _PY3
from ._compat import PermissionError
from ._compat import ProcessLookupError
from ._compat import SubprocessTimeoutExpired as _SubprocessTimeoutExpired
from ._compat import long
if LINUX: if LINUX:
# This is public API and it will be retrieved from _pslinux.py # This is public API and it will be retrieved from _pslinux.py
@ -97,7 +100,6 @@ if LINUX:
PROCFS_PATH = "/proc" PROCFS_PATH = "/proc"
from . import _pslinux as _psplatform from . import _pslinux as _psplatform
from ._pslinux import IOPRIO_CLASS_BE # NOQA from ._pslinux import IOPRIO_CLASS_BE # NOQA
from ._pslinux import IOPRIO_CLASS_IDLE # NOQA from ._pslinux import IOPRIO_CLASS_IDLE # NOQA
from ._pslinux import IOPRIO_CLASS_NONE # NOQA from ._pslinux import IOPRIO_CLASS_NONE # NOQA
@ -112,10 +114,10 @@ elif WINDOWS:
from ._psutil_windows import NORMAL_PRIORITY_CLASS # NOQA from ._psutil_windows import NORMAL_PRIORITY_CLASS # NOQA
from ._psutil_windows import REALTIME_PRIORITY_CLASS # NOQA from ._psutil_windows import REALTIME_PRIORITY_CLASS # NOQA
from ._pswindows import CONN_DELETE_TCB # NOQA from ._pswindows import CONN_DELETE_TCB # NOQA
from ._pswindows import IOPRIO_VERYLOW # NOQA from ._pswindows import IOPRIO_HIGH # NOQA
from ._pswindows import IOPRIO_LOW # NOQA from ._pswindows import IOPRIO_LOW # NOQA
from ._pswindows import IOPRIO_NORMAL # NOQA from ._pswindows import IOPRIO_NORMAL # NOQA
from ._pswindows import IOPRIO_HIGH # NOQA from ._pswindows import IOPRIO_VERYLOW # NOQA
elif MACOS: elif MACOS:
from . import _psosx as _psplatform from . import _psosx as _psplatform
@ -209,7 +211,7 @@ if hasattr(_psplatform.Process, "rlimit"):
AF_LINK = _psplatform.AF_LINK AF_LINK = _psplatform.AF_LINK
__author__ = "Giampaolo Rodola'" __author__ = "Giampaolo Rodola'"
__version__ = "5.8.0" __version__ = "5.9.0"
version_info = tuple([int(num) for num in __version__.split('.')]) version_info = tuple([int(num) for num in __version__.split('.')])
_timer = getattr(time, 'monotonic', time.time) _timer = getattr(time, 'monotonic', time.time)
@ -268,7 +270,11 @@ def _assert_pid_not_reused(fun):
@functools.wraps(fun) @functools.wraps(fun)
def wrapper(self, *args, **kwargs): def wrapper(self, *args, **kwargs):
if not self.is_running(): if not self.is_running():
raise NoSuchProcess(self.pid, self._name) if self._pid_reused:
msg = "process no longer exists and its PID has been reused"
else:
msg = None
raise NoSuchProcess(self.pid, self._name, msg=msg)
return fun(self, *args, **kwargs) return fun(self, *args, **kwargs)
return wrapper return wrapper
@ -339,6 +345,7 @@ class Process(object):
self._exe = None self._exe = None
self._create_time = None self._create_time = None
self._gone = False self._gone = False
self._pid_reused = False
self._hash = None self._hash = None
self._lock = threading.RLock() self._lock = threading.RLock()
# used for caching on Windows only (on POSIX ppid may change) # used for caching on Windows only (on POSIX ppid may change)
@ -363,8 +370,7 @@ class Process(object):
pass pass
except NoSuchProcess: except NoSuchProcess:
if not _ignore_nsp: if not _ignore_nsp:
msg = 'no process found with pid %s' % pid raise NoSuchProcess(pid, msg='process PID not found')
raise NoSuchProcess(pid, None, msg)
else: else:
self._gone = True self._gone = True
# This pair is supposed to indentify a Process instance # This pair is supposed to indentify a Process instance
@ -570,7 +576,7 @@ class Process(object):
It also checks if PID has been reused by another process in It also checks if PID has been reused by another process in
which case return False. which case return False.
""" """
if self._gone: if self._gone or self._pid_reused:
return False return False
try: try:
# Checking if PID is alive is not enough as the PID might # Checking if PID is alive is not enough as the PID might
@ -578,7 +584,8 @@ class Process(object):
# verify process identity. # verify process identity.
# Process identity / uniqueness over time is guaranteed by # Process identity / uniqueness over time is guaranteed by
# (PID + creation time) and that is verified in __eq__. # (PID + creation time) and that is verified in __eq__.
return self == Process(self.pid) self._pid_reused = self != Process(self.pid)
return not self._pid_reused
except ZombieProcess: except ZombieProcess:
# We should never get here as it's already handled in # We should never get here as it's already handled in
# Process.__init__; here just for extra safety. # Process.__init__; here just for extra safety.
@ -1386,7 +1393,6 @@ def pid_exists(pid):
_pmap = {} _pmap = {}
_lock = threading.Lock()
def process_iter(attrs=None, ad_value=None): def process_iter(attrs=None, ad_value=None):
@ -1410,36 +1416,35 @@ def process_iter(attrs=None, ad_value=None):
If *attrs* is an empty list it will retrieve all process info If *attrs* is an empty list it will retrieve all process info
(slow). (slow).
""" """
global _pmap
def add(pid): def add(pid):
proc = Process(pid) proc = Process(pid)
if attrs is not None: if attrs is not None:
proc.info = proc.as_dict(attrs=attrs, ad_value=ad_value) proc.info = proc.as_dict(attrs=attrs, ad_value=ad_value)
with _lock: pmap[proc.pid] = proc
_pmap[proc.pid] = proc
return proc return proc
def remove(pid): def remove(pid):
with _lock: pmap.pop(pid, None)
_pmap.pop(pid, None)
pmap = _pmap.copy()
a = set(pids()) a = set(pids())
b = set(_pmap.keys()) b = set(pmap.keys())
new_pids = a - b new_pids = a - b
gone_pids = b - a gone_pids = b - a
for pid in gone_pids: for pid in gone_pids:
remove(pid) remove(pid)
try:
with _lock: ls = sorted(list(pmap.items()) + list(dict.fromkeys(new_pids).items()))
ls = sorted(list(_pmap.items()) +
list(dict.fromkeys(new_pids).items()))
for pid, proc in ls: for pid, proc in ls:
try: try:
if proc is None: # new process if proc is None: # new process
yield add(pid) yield add(pid)
else: else:
# use is_running() to check whether PID has been reused by # use is_running() to check whether PID has been
# another process in which case yield a new Process instance # reused by another process in which case yield a
# new Process instance
if proc.is_running(): if proc.is_running():
if attrs is not None: if attrs is not None:
proc.info = proc.as_dict( proc.info = proc.as_dict(
@ -1453,15 +1458,17 @@ def process_iter(attrs=None, ad_value=None):
# Process creation time can't be determined hence there's # Process creation time can't be determined hence there's
# no way to tell whether the pid of the cached process # no way to tell whether the pid of the cached process
# has been reused. Just return the cached version. # has been reused. Just return the cached version.
if proc is None and pid in _pmap: if proc is None and pid in pmap:
try: try:
yield _pmap[pid] yield pmap[pid]
except KeyError: except KeyError:
# If we get here it is likely that 2 threads were # If we get here it is likely that 2 threads were
# using process_iter(). # using process_iter().
pass pass
else: else:
raise raise
finally:
_pmap = pmap
def wait_procs(procs, timeout=None, callback=None): def wait_procs(procs, timeout=None, callback=None):
@ -1505,6 +1512,8 @@ def wait_procs(procs, timeout=None, callback=None):
returncode = proc.wait(timeout=timeout) returncode = proc.wait(timeout=timeout)
except TimeoutExpired: except TimeoutExpired:
pass pass
except _SubprocessTimeoutExpired:
pass
else: else:
if returncode is not None or not proc.is_running(): if returncode is not None or not proc.is_running():
# Set new Process instance attribute. # Set new Process instance attribute.
@ -1575,7 +1584,7 @@ def cpu_count(logical=True):
if logical: if logical:
ret = _psplatform.cpu_count_logical() ret = _psplatform.cpu_count_logical()
else: else:
ret = _psplatform.cpu_count_physical() ret = _psplatform.cpu_count_cores()
if ret is not None and ret < 1: if ret is not None and ret < 1:
ret = None ret = None
return ret return ret
@ -1721,7 +1730,6 @@ def cpu_percent(interval=None, percpu=False):
def calculate(t1, t2): def calculate(t1, t2):
times_delta = _cpu_times_deltas(t1, t2) times_delta = _cpu_times_deltas(t1, t2)
all_delta = _cpu_tot_time(times_delta) all_delta = _cpu_tot_time(times_delta)
busy_delta = _cpu_busy_time(times_delta) busy_delta = _cpu_busy_time(times_delta)
@ -1849,7 +1857,7 @@ def cpu_stats():
if hasattr(_psplatform, "cpu_freq"): if hasattr(_psplatform, "cpu_freq"):
def cpu_freq(percpu=False): def cpu_freq(percpu=False):
"""Return CPU frequency as a nameduple including current, """Return CPU frequency as a namedtuple including current,
min and max frequency expressed in Mhz. min and max frequency expressed in Mhz.
If *percpu* is True and the system supports per-cpu frequency If *percpu* is True and the system supports per-cpu frequency
@ -2338,6 +2346,15 @@ if WINDOWS:
# ===================================================================== # =====================================================================
def _set_debug(value):
"""Enable or disable PSUTIL_DEBUG option, which prints debugging
messages to stderr.
"""
import psutil._common
psutil._common.PSUTIL_DEBUG = bool(value)
_psplatform.cext.set_debug(bool(value))
def test(): # pragma: no cover def test(): # pragma: no cover
from ._common import bytes2human from ._common import bytes2human
from ._compat import get_terminal_size from ._compat import get_terminal_size

View File

@ -7,8 +7,10 @@
# Note: this module is imported by setup.py so it should not import # Note: this module is imported by setup.py so it should not import
# psutil or third-party modules. # psutil or third-party modules.
from __future__ import division, print_function from __future__ import division
from __future__ import print_function
import collections
import contextlib import contextlib
import errno import errno
import functools import functools
@ -18,12 +20,12 @@ import stat
import sys import sys
import threading import threading
import warnings import warnings
from collections import defaultdict
from collections import namedtuple from collections import namedtuple
from socket import AF_INET from socket import AF_INET
from socket import SOCK_DGRAM from socket import SOCK_DGRAM
from socket import SOCK_STREAM from socket import SOCK_STREAM
try: try:
from socket import AF_INET6 from socket import AF_INET6
except ImportError: except ImportError:
@ -41,6 +43,7 @@ else:
# can't take it from _common.py as this script is imported by setup.py # can't take it from _common.py as this script is imported by setup.py
PY3 = sys.version_info[0] == 3 PY3 = sys.version_info[0] == 3
PSUTIL_DEBUG = bool(os.getenv('PSUTIL_DEBUG', 0))
__all__ = [ __all__ = [
# OS constants # OS constants
@ -83,7 +86,7 @@ WINDOWS = os.name == "nt"
LINUX = sys.platform.startswith("linux") LINUX = sys.platform.startswith("linux")
MACOS = sys.platform.startswith("darwin") MACOS = sys.platform.startswith("darwin")
OSX = MACOS # deprecated alias OSX = MACOS # deprecated alias
FREEBSD = sys.platform.startswith("freebsd") FREEBSD = sys.platform.startswith(("freebsd", "midnightbsd"))
OPENBSD = sys.platform.startswith("openbsd") OPENBSD = sys.platform.startswith("openbsd")
NETBSD = sys.platform.startswith("netbsd") NETBSD = sys.platform.startswith("netbsd")
BSD = FREEBSD or OPENBSD or NETBSD BSD = FREEBSD or OPENBSD or NETBSD
@ -275,15 +278,32 @@ class Error(Exception):
""" """
__module__ = 'psutil' __module__ = 'psutil'
def __init__(self, msg=""): def _infodict(self, attrs):
Exception.__init__(self, msg) try:
self.msg = msg info = collections.OrderedDict()
except AttributeError: # pragma: no cover
info = {} # Python 2.6
for name in attrs:
value = getattr(self, name, None)
if value:
info[name] = value
return info
def __str__(self):
# invoked on `raise Error`
info = self._infodict(("pid", "ppid", "name"))
if info:
details = "(%s)" % ", ".join(
["%s=%r" % (k, v) for k, v in info.items()])
else:
details = None
return " ".join([x for x in (self.msg, details) if x])
def __repr__(self): def __repr__(self):
ret = "psutil.%s %s" % (self.__class__.__name__, self.msg) # invoked on `repr(Error)`
return ret.strip() info = self._infodict(("pid", "ppid", "name", "seconds", "msg"))
details = ", ".join(["%s=%r" % (k, v) for k, v in info.items()])
__str__ = __repr__ return "psutil.%s(%s)" % (self.__class__.__name__, details)
class NoSuchProcess(Error): class NoSuchProcess(Error):
@ -293,16 +313,10 @@ class NoSuchProcess(Error):
__module__ = 'psutil' __module__ = 'psutil'
def __init__(self, pid, name=None, msg=None): def __init__(self, pid, name=None, msg=None):
Error.__init__(self, msg) Error.__init__(self)
self.pid = pid self.pid = pid
self.name = name self.name = name
self.msg = msg self.msg = msg or "process no longer exists"
if msg is None:
if name:
details = "(pid=%s, name=%s)" % (self.pid, repr(self.name))
else:
details = "(pid=%s)" % self.pid
self.msg = "process no longer exists " + details
class ZombieProcess(NoSuchProcess): class ZombieProcess(NoSuchProcess):
@ -315,19 +329,9 @@ class ZombieProcess(NoSuchProcess):
__module__ = 'psutil' __module__ = 'psutil'
def __init__(self, pid, name=None, ppid=None, msg=None): def __init__(self, pid, name=None, ppid=None, msg=None):
NoSuchProcess.__init__(self, msg) NoSuchProcess.__init__(self, pid, name, msg)
self.pid = pid
self.ppid = ppid self.ppid = ppid
self.name = name self.msg = msg or "PID still exists but it's a zombie"
self.msg = msg
if msg is None:
args = ["pid=%s" % pid]
if name:
args.append("name=%s" % repr(self.name))
if ppid:
args.append("ppid=%s" % self.ppid)
details = "(%s)" % ", ".join(args)
self.msg = "process still exists but it's a zombie " + details
class AccessDenied(Error): class AccessDenied(Error):
@ -335,17 +339,10 @@ class AccessDenied(Error):
__module__ = 'psutil' __module__ = 'psutil'
def __init__(self, pid=None, name=None, msg=None): def __init__(self, pid=None, name=None, msg=None):
Error.__init__(self, msg) Error.__init__(self)
self.pid = pid self.pid = pid
self.name = name self.name = name
self.msg = msg self.msg = msg or ""
if msg is None:
if (pid is not None) and (name is not None):
self.msg = "(pid=%s, name=%s)" % (pid, repr(name))
elif (pid is not None):
self.msg = "(pid=%s)" % self.pid
else:
self.msg = ""
class TimeoutExpired(Error): class TimeoutExpired(Error):
@ -355,14 +352,11 @@ class TimeoutExpired(Error):
__module__ = 'psutil' __module__ = 'psutil'
def __init__(self, seconds, pid=None, name=None): def __init__(self, seconds, pid=None, name=None):
Error.__init__(self, "timeout after %s seconds" % seconds) Error.__init__(self)
self.seconds = seconds self.seconds = seconds
self.pid = pid self.pid = pid
self.name = name self.name = name
if (pid is not None) and (name is not None): self.msg = "timeout after %s seconds" % seconds
self.msg += " (pid=%s, name=%s)" % (pid, repr(name))
elif (pid is not None):
self.msg += " (pid=%s)" % self.pid
# =================================================================== # ===================================================================
@ -451,7 +445,13 @@ def memoize_when_activated(fun):
except KeyError: except KeyError:
# case 3: we entered oneshot() ctx but there's no cache # case 3: we entered oneshot() ctx but there's no cache
# for this entry yet # for this entry yet
ret = self._cache[fun] = fun(self) ret = fun(self)
try:
self._cache[fun] = ret
except AttributeError:
# multi-threading race condition, see:
# https://github.com/giampaolo/psutil/issues/1948
pass
return ret return ret
def cache_activate(proc): def cache_activate(proc):
@ -622,8 +622,8 @@ class _WrapNumbers:
assert name not in self.reminders assert name not in self.reminders
assert name not in self.reminder_keys assert name not in self.reminder_keys
self.cache[name] = input_dict self.cache[name] = input_dict
self.reminders[name] = defaultdict(int) self.reminders[name] = collections.defaultdict(int)
self.reminder_keys[name] = defaultdict(set) self.reminder_keys[name] = collections.defaultdict(set)
def _remove_dead_reminders(self, input_dict, name): def _remove_dead_reminders(self, input_dict, name):
"""In case the number of keys changed between calls (e.g. a """In case the number of keys changed between calls (e.g. a
@ -832,15 +832,17 @@ def print_color(
SetConsoleTextAttribute(handle, DEFAULT_COLOR) SetConsoleTextAttribute(handle, DEFAULT_COLOR)
if bool(os.getenv('PSUTIL_DEBUG', 0)): def debug(msg):
import inspect
def debug(msg):
"""If PSUTIL_DEBUG env var is set, print a debug message to stderr.""" """If PSUTIL_DEBUG env var is set, print a debug message to stderr."""
if PSUTIL_DEBUG:
import inspect
fname, lineno, func_name, lines, index = inspect.getframeinfo( fname, lineno, func_name, lines, index = inspect.getframeinfo(
inspect.currentframe().f_back) inspect.currentframe().f_back)
if isinstance(msg, Exception):
if isinstance(msg, (OSError, IOError, EnvironmentError)):
# ...because str(exc) may contain info about the file name
msg = "ignoring %s" % msg
else:
msg = "ignoring %r" % msg
print("psutil-debug [%s:%s]> %s" % (fname, lineno, msg), # NOQA print("psutil-debug [%s:%s]> %s" % (fname, lineno, msg), # NOQA
file=sys.stderr) file=sys.stderr)
else:
def debug(msg):
pass

View File

@ -8,12 +8,14 @@ Python 3 way of doing things).
""" """
import collections import collections
import contextlib
import errno import errno
import functools import functools
import os import os
import sys import sys
import types import types
__all__ = [ __all__ = [
# constants # constants
"PY3", "PY3",
@ -25,6 +27,8 @@ __all__ = [
"lru_cache", "lru_cache",
# shutil module # shutil module
"which", "get_terminal_size", "which", "get_terminal_size",
# contextlib module
"redirect_stderr",
# python 3 exceptions # python 3 exceptions
"FileNotFoundError", "PermissionError", "ProcessLookupError", "FileNotFoundError", "PermissionError", "ProcessLookupError",
"InterruptedError", "ChildProcessError", "FileExistsError"] "InterruptedError", "ChildProcessError", "FileExistsError"]
@ -410,8 +414,8 @@ except ImportError:
def get_terminal_size(fallback=(80, 24)): def get_terminal_size(fallback=(80, 24)):
try: try:
import fcntl import fcntl
import termios
import struct import struct
import termios
except ImportError: except ImportError:
return fallback return fallback
else: else:
@ -422,3 +426,25 @@ except ImportError:
return (res[1], res[0]) return (res[1], res[0])
except Exception: except Exception:
return fallback return fallback
# python 3.3
try:
from subprocess import TimeoutExpired as SubprocessTimeoutExpired
except ImportError:
class SubprocessTimeoutExpired:
pass
# python 3.5
try:
from contextlib import redirect_stderr
except ImportError:
@contextlib.contextmanager
def redirect_stderr(new_target):
original = getattr(sys, "stderr")
try:
setattr(sys, "stderr", new_target)
yield new_target
finally:
setattr(sys, "stderr", original)

View File

@ -18,20 +18,20 @@ from . import _common
from . import _psposix from . import _psposix
from . import _psutil_aix as cext from . import _psutil_aix as cext
from . import _psutil_posix as cext_posix from . import _psutil_posix as cext_posix
from ._common import AccessDenied
from ._common import conn_to_ntuple
from ._common import get_procfs_path
from ._common import memoize_when_activated
from ._common import NIC_DUPLEX_FULL from ._common import NIC_DUPLEX_FULL
from ._common import NIC_DUPLEX_HALF from ._common import NIC_DUPLEX_HALF
from ._common import NIC_DUPLEX_UNKNOWN from ._common import NIC_DUPLEX_UNKNOWN
from ._common import AccessDenied
from ._common import NoSuchProcess from ._common import NoSuchProcess
from ._common import usage_percent
from ._common import ZombieProcess from ._common import ZombieProcess
from ._common import conn_to_ntuple
from ._common import get_procfs_path
from ._common import memoize_when_activated
from ._common import usage_percent
from ._compat import PY3
from ._compat import FileNotFoundError from ._compat import FileNotFoundError
from ._compat import PermissionError from ._compat import PermissionError
from ._compat import ProcessLookupError from ._compat import ProcessLookupError
from ._compat import PY3
__extra__all__ = ["PROCFS_PATH"] __extra__all__ = ["PROCFS_PATH"]
@ -143,7 +143,7 @@ def cpu_count_logical():
return None return None
def cpu_count_physical(): def cpu_count_cores():
cmd = "lsdev -Cc processor" cmd = "lsdev -Cc processor"
p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE,
stderr=subprocess.PIPE) stderr=subprocess.PIPE)

View File

@ -9,24 +9,24 @@ import errno
import functools import functools
import os import os
import xml.etree.ElementTree as ET import xml.etree.ElementTree as ET
from collections import namedtuple
from collections import defaultdict from collections import defaultdict
from collections import namedtuple
from . import _common from . import _common
from . import _psposix from . import _psposix
from . import _psutil_bsd as cext from . import _psutil_bsd as cext
from . import _psutil_posix as cext_posix from . import _psutil_posix as cext_posix
from ._common import FREEBSD
from ._common import NETBSD
from ._common import OPENBSD
from ._common import AccessDenied from ._common import AccessDenied
from ._common import NoSuchProcess
from ._common import ZombieProcess
from ._common import conn_tmap from ._common import conn_tmap
from ._common import conn_to_ntuple from ._common import conn_to_ntuple
from ._common import FREEBSD
from ._common import memoize from ._common import memoize
from ._common import memoize_when_activated from ._common import memoize_when_activated
from ._common import NETBSD
from ._common import NoSuchProcess
from ._common import OPENBSD
from ._common import usage_percent from ._common import usage_percent
from ._common import ZombieProcess
from ._compat import FileNotFoundError from ._compat import FileNotFoundError
from ._compat import PermissionError from ._compat import PermissionError
from ._compat import ProcessLookupError from ._compat import ProcessLookupError
@ -249,19 +249,19 @@ def cpu_count_logical():
if OPENBSD or NETBSD: if OPENBSD or NETBSD:
def cpu_count_physical(): def cpu_count_cores():
# OpenBSD and NetBSD do not implement this. # OpenBSD and NetBSD do not implement this.
return 1 if cpu_count_logical() == 1 else None return 1 if cpu_count_logical() == 1 else None
else: else:
def cpu_count_physical(): def cpu_count_cores():
"""Return the number of physical CPUs in the system.""" """Return the number of CPU cores in the system."""
# From the C module we'll get an XML string similar to this: # From the C module we'll get an XML string similar to this:
# http://manpages.ubuntu.com/manpages/precise/man4/smp.4freebsd.html # http://manpages.ubuntu.com/manpages/precise/man4/smp.4freebsd.html
# We may get None in case "sysctl kern.sched.topology_spec" # We may get None in case "sysctl kern.sched.topology_spec"
# is not supported on this BSD version, in which case we'll mimic # is not supported on this BSD version, in which case we'll mimic
# os.cpu_count() and return None. # os.cpu_count() and return None.
ret = None ret = None
s = cext.cpu_count_phys() s = cext.cpu_topology()
if s is not None: if s is not None:
# get rid of padding chars appended at the end of the string # get rid of padding chars appended at the end of the string
index = s.rfind("</groups>") index = s.rfind("</groups>")
@ -274,8 +274,7 @@ else:
# needed otherwise it will memleak # needed otherwise it will memleak
root.clear() root.clear()
if not ret: if not ret:
# If logical CPUs are 1 it's obvious we'll have only 1 # If logical CPUs == 1 it's obvious we' have only 1 core.
# physical CPU.
if cpu_count_logical() == 1: if cpu_count_logical() == 1:
return 1 return 1
return ret return ret

View File

@ -25,30 +25,31 @@ from . import _common
from . import _psposix from . import _psposix
from . import _psutil_linux as cext from . import _psutil_linux as cext
from . import _psutil_posix as cext_posix from . import _psutil_posix as cext_posix
from ._common import NIC_DUPLEX_FULL
from ._common import NIC_DUPLEX_HALF
from ._common import NIC_DUPLEX_UNKNOWN
from ._common import AccessDenied from ._common import AccessDenied
from ._common import NoSuchProcess
from ._common import ZombieProcess
from ._common import debug from ._common import debug
from ._common import decode from ._common import decode
from ._common import get_procfs_path from ._common import get_procfs_path
from ._common import isfile_strict from ._common import isfile_strict
from ._common import memoize from ._common import memoize
from ._common import memoize_when_activated from ._common import memoize_when_activated
from ._common import NIC_DUPLEX_FULL
from ._common import NIC_DUPLEX_HALF
from ._common import NIC_DUPLEX_UNKNOWN
from ._common import NoSuchProcess
from ._common import open_binary from ._common import open_binary
from ._common import open_text from ._common import open_text
from ._common import parse_environ_block from ._common import parse_environ_block
from ._common import path_exists_strict from ._common import path_exists_strict
from ._common import supports_ipv6 from ._common import supports_ipv6
from ._common import usage_percent from ._common import usage_percent
from ._common import ZombieProcess from ._compat import PY3
from ._compat import b
from ._compat import basestring
from ._compat import FileNotFoundError from ._compat import FileNotFoundError
from ._compat import PermissionError from ._compat import PermissionError
from ._compat import ProcessLookupError from ._compat import ProcessLookupError
from ._compat import PY3 from ._compat import b
from ._compat import basestring
if sys.version_info >= (3, 4): if sys.version_info >= (3, 4):
import enum import enum
@ -656,8 +657,8 @@ def cpu_count_logical():
return num return num
def cpu_count_physical(): def cpu_count_cores():
"""Return the number of physical cores in the system.""" """Return the number of CPU cores in the system."""
# Method #1 # Method #1
ls = set() ls = set()
# These 2 files are the same but */core_cpus_list is newer while # These 2 files are the same but */core_cpus_list is newer while
@ -719,6 +720,17 @@ def cpu_stats():
ctx_switches, interrupts, soft_interrupts, syscalls) ctx_switches, interrupts, soft_interrupts, syscalls)
def _cpu_get_cpuinfo_freq():
"""Return current CPU frequency from cpuinfo if available.
"""
ret = []
with open_binary('%s/cpuinfo' % get_procfs_path()) as f:
for line in f:
if line.lower().startswith(b'cpu mhz'):
ret.append(float(line.split(b':', 1)[1]))
return ret
if os.path.exists("/sys/devices/system/cpu/cpufreq/policy0") or \ if os.path.exists("/sys/devices/system/cpu/cpufreq/policy0") or \
os.path.exists("/sys/devices/system/cpu/cpu0/cpufreq"): os.path.exists("/sys/devices/system/cpu/cpu0/cpufreq"):
def cpu_freq(): def cpu_freq():
@ -726,19 +738,19 @@ if os.path.exists("/sys/devices/system/cpu/cpufreq/policy0") or \
Contrarily to other OSes, Linux updates these values in Contrarily to other OSes, Linux updates these values in
real-time. real-time.
""" """
def get_path(num): cpuinfo_freqs = _cpu_get_cpuinfo_freq()
for p in ("/sys/devices/system/cpu/cpufreq/policy%s" % num, paths = \
"/sys/devices/system/cpu/cpu%s/cpufreq" % num): glob.glob("/sys/devices/system/cpu/cpufreq/policy[0-9]*") or \
if os.path.exists(p): glob.glob("/sys/devices/system/cpu/cpu[0-9]*/cpufreq")
return p paths.sort(key=lambda x: int(re.search(r"[0-9]+", x).group()))
ret = [] ret = []
for n in range(cpu_count_logical()):
path = get_path(n)
if not path:
continue
pjoin = os.path.join pjoin = os.path.join
for i, path in enumerate(paths):
if len(paths) == len(cpuinfo_freqs):
# take cached value from cpuinfo if available, see:
# https://github.com/giampaolo/psutil/issues/1851
curr = cpuinfo_freqs[i]
else:
curr = cat(pjoin(path, "scaling_cur_freq"), fallback=None) curr = cat(pjoin(path, "scaling_cur_freq"), fallback=None)
if curr is None: if curr is None:
# Likely an old RedHat, see: # Likely an old RedHat, see:
@ -753,24 +765,12 @@ if os.path.exists("/sys/devices/system/cpu/cpufreq/policy0") or \
ret.append(_common.scpufreq(curr, min_, max_)) ret.append(_common.scpufreq(curr, min_, max_))
return ret return ret
elif os.path.exists("/proc/cpuinfo"): else:
def cpu_freq(): def cpu_freq():
"""Alternate implementation using /proc/cpuinfo. """Alternate implementation using /proc/cpuinfo.
min and max frequencies are not available and are set to None. min and max frequencies are not available and are set to None.
""" """
ret = [] return [_common.scpufreq(x, 0., 0.) for x in _cpu_get_cpuinfo_freq()]
with open_binary('%s/cpuinfo' % get_procfs_path()) as f:
for line in f:
if line.lower().startswith(b'cpu mhz'):
key, value = line.split(b':', 1)
ret.append(_common.scpufreq(float(value), 0., 0.))
return ret
else:
def cpu_freq():
"""Dummy implementation when none of the above files are present.
"""
return []
# ===================================================================== # =====================================================================
@ -834,6 +834,10 @@ class Connections:
if err.errno == errno.EINVAL: if err.errno == errno.EINVAL:
# not a link # not a link
continue continue
if err.errno == errno.ENAMETOOLONG:
# file name too long
debug(err)
continue
raise raise
else: else:
if inode.startswith('socket:['): if inode.startswith('socket:['):
@ -1080,6 +1084,8 @@ def net_if_stats():
# https://github.com/giampaolo/psutil/issues/1279 # https://github.com/giampaolo/psutil/issues/1279
if err.errno != errno.ENODEV: if err.errno != errno.ENODEV:
raise raise
else:
debug(err)
else: else:
ret[name] = _common.snicstats(isup, duplex_map[duplex], speed, mtu) ret[name] = _common.snicstats(isup, duplex_map[duplex], speed, mtu)
return ret return ret
@ -1188,6 +1194,80 @@ def disk_io_counters(perdisk=False):
return retdict return retdict
class RootFsDeviceFinder:
"""disk_partitions() may return partitions with device == "/dev/root"
or "rootfs". This container class uses different strategies to try to
obtain the real device path. Resources:
https://bootlin.com/blog/find-root-device/
https://www.systutorials.com/how-to-find-the-disk-where-root-is-on-in-bash-on-linux/
"""
__slots__ = ['major', 'minor']
def __init__(self):
dev = os.stat("/").st_dev
self.major = os.major(dev)
self.minor = os.minor(dev)
def ask_proc_partitions(self):
with open_text("%s/partitions" % get_procfs_path()) as f:
for line in f.readlines()[2:]:
fields = line.split()
if len(fields) < 4: # just for extra safety
continue
major = int(fields[0]) if fields[0].isdigit() else None
minor = int(fields[1]) if fields[1].isdigit() else None
name = fields[3]
if major == self.major and minor == self.minor:
if name: # just for extra safety
return "/dev/%s" % name
def ask_sys_dev_block(self):
path = "/sys/dev/block/%s:%s/uevent" % (self.major, self.minor)
with open_text(path) as f:
for line in f:
if line.startswith("DEVNAME="):
name = line.strip().rpartition("DEVNAME=")[2]
if name: # just for extra safety
return "/dev/%s" % name
def ask_sys_class_block(self):
needle = "%s:%s" % (self.major, self.minor)
files = glob.iglob("/sys/class/block/*/dev")
for file in files:
try:
f = open_text(file)
except FileNotFoundError: # race condition
continue
else:
with f:
data = f.read().strip()
if data == needle:
name = os.path.basename(os.path.dirname(file))
return "/dev/%s" % name
def find(self):
path = None
if path is None:
try:
path = self.ask_proc_partitions()
except (IOError, OSError) as err:
debug(err)
if path is None:
try:
path = self.ask_sys_dev_block()
except (IOError, OSError) as err:
debug(err)
if path is None:
try:
path = self.ask_sys_class_block()
except (IOError, OSError) as err:
debug(err)
# We use exists() because the "/dev/*" part of the path is hard
# coded, so we want to be sure.
if path is not None and os.path.exists(path):
return path
def disk_partitions(all=False): def disk_partitions(all=False):
"""Return mounted disk partitions as a list of namedtuples.""" """Return mounted disk partitions as a list of namedtuples."""
fstypes = set() fstypes = set()
@ -1215,6 +1295,8 @@ def disk_partitions(all=False):
device, mountpoint, fstype, opts = partition device, mountpoint, fstype, opts = partition
if device == 'none': if device == 'none':
device = '' device = ''
if device in ("/dev/root", "rootfs"):
device = RootFsDeviceFinder().find() or device
if not all: if not all:
if device == '' or fstype not in fstypes: if device == '' or fstype not in fstypes:
continue continue
@ -1310,7 +1392,7 @@ def sensors_temperatures():
path = os.path.join(base, 'type') path = os.path.join(base, 'type')
unit_name = cat(path, binary=False) unit_name = cat(path, binary=False)
except (IOError, OSError, ValueError) as err: except (IOError, OSError, ValueError) as err:
debug("ignoring %r for file %r" % (err, path)) debug(err)
continue continue
trip_paths = glob.glob(base + '/trip_point*') trip_paths = glob.glob(base + '/trip_point*')
@ -1366,7 +1448,7 @@ def sensors_fans():
try: try:
current = int(cat(base + '_input')) current = int(cat(base + '_input'))
except (IOError, OSError) as err: except (IOError, OSError) as err:
warnings.warn("ignoring %r" % err, RuntimeWarning) debug(err)
continue continue
unit_name = cat(os.path.join(os.path.dirname(base), 'name'), unit_name = cat(os.path.join(os.path.dirname(base), 'name'),
binary=False) binary=False)
@ -1392,7 +1474,10 @@ def sensors_battery():
for path in paths: for path in paths:
ret = cat(path, fallback=null) ret = cat(path, fallback=null)
if ret != null: if ret != null:
return int(ret) if ret.isdigit() else ret try:
return int(ret)
except ValueError:
return ret
return None return None
bats = [x for x in os.listdir(POWER_SUPPLY_PATH) if x.startswith('BAT') or bats = [x for x in os.listdir(POWER_SUPPLY_PATH) if x.startswith('BAT') or
@ -2100,6 +2185,10 @@ class Process(object):
if err.errno == errno.EINVAL: if err.errno == errno.EINVAL:
# not a link # not a link
continue continue
if err.errno == errno.ENAMETOOLONG:
# file name too long
debug(err)
continue
raise raise
else: else:
# If path is not an absolute there's no way to tell # If path is not an absolute there's no way to tell

View File

@ -4,7 +4,6 @@
"""macOS platform implementation.""" """macOS platform implementation."""
import contextlib
import errno import errno
import functools import functools
import os import os
@ -15,14 +14,14 @@ from . import _psposix
from . import _psutil_osx as cext from . import _psutil_osx as cext
from . import _psutil_posix as cext_posix from . import _psutil_posix as cext_posix
from ._common import AccessDenied from ._common import AccessDenied
from ._common import NoSuchProcess
from ._common import ZombieProcess
from ._common import conn_tmap from ._common import conn_tmap
from ._common import conn_to_ntuple from ._common import conn_to_ntuple
from ._common import isfile_strict from ._common import isfile_strict
from ._common import memoize_when_activated from ._common import memoize_when_activated
from ._common import NoSuchProcess
from ._common import parse_environ_block from ._common import parse_environ_block
from ._common import usage_percent from ._common import usage_percent
from ._common import ZombieProcess
from ._compat import PermissionError from ._compat import PermissionError
from ._compat import ProcessLookupError from ._compat import ProcessLookupError
@ -159,9 +158,9 @@ def cpu_count_logical():
return cext.cpu_count_logical() return cext.cpu_count_logical()
def cpu_count_physical(): def cpu_count_cores():
"""Return the number of physical CPUs in the system.""" """Return the number of CPU cores in the system."""
return cext.cpu_count_phys() return cext.cpu_count_cores()
def cpu_stats(): def cpu_stats():
@ -354,32 +353,6 @@ def wrap_exceptions(fun):
return wrapper return wrapper
@contextlib.contextmanager
def catch_zombie(proc):
"""There are some poor C APIs which incorrectly raise ESRCH when
the process is still alive or it's a zombie, or even RuntimeError
(those who don't set errno). This is here in order to solve:
https://github.com/giampaolo/psutil/issues/1044
"""
try:
yield
except (OSError, RuntimeError) as err:
if isinstance(err, RuntimeError) or err.errno == errno.ESRCH:
try:
# status() is not supposed to lie and correctly detect
# zombies so if it raises ESRCH it's true.
status = proc.status()
except NoSuchProcess:
raise err
else:
if status == _common.STATUS_ZOMBIE:
raise ZombieProcess(proc.pid, proc._name, proc._ppid)
else:
raise AccessDenied(proc.pid, proc._name)
else:
raise
class Process(object): class Process(object):
"""Wrapper class around underlying C implementation.""" """Wrapper class around underlying C implementation."""
@ -402,7 +375,6 @@ class Process(object):
@memoize_when_activated @memoize_when_activated
def _get_pidtaskinfo(self): def _get_pidtaskinfo(self):
# Note: should work for PIDs owned by user only. # Note: should work for PIDs owned by user only.
with catch_zombie(self):
ret = cext.proc_pidtaskinfo_oneshot(self.pid) ret = cext.proc_pidtaskinfo_oneshot(self.pid)
assert len(ret) == len(pidtaskinfo_map) assert len(ret) == len(pidtaskinfo_map)
return ret return ret
@ -422,17 +394,14 @@ class Process(object):
@wrap_exceptions @wrap_exceptions
def exe(self): def exe(self):
with catch_zombie(self):
return cext.proc_exe(self.pid) return cext.proc_exe(self.pid)
@wrap_exceptions @wrap_exceptions
def cmdline(self): def cmdline(self):
with catch_zombie(self):
return cext.proc_cmdline(self.pid) return cext.proc_cmdline(self.pid)
@wrap_exceptions @wrap_exceptions
def environ(self): def environ(self):
with catch_zombie(self):
return parse_environ_block(cext.proc_environ(self.pid)) return parse_environ_block(cext.proc_environ(self.pid))
@wrap_exceptions @wrap_exceptions
@ -442,7 +411,6 @@ class Process(object):
@wrap_exceptions @wrap_exceptions
def cwd(self): def cwd(self):
with catch_zombie(self):
return cext.proc_cwd(self.pid) return cext.proc_cwd(self.pid)
@wrap_exceptions @wrap_exceptions
@ -516,7 +484,6 @@ class Process(object):
if self.pid == 0: if self.pid == 0:
return [] return []
files = [] files = []
with catch_zombie(self):
rawlist = cext.proc_open_files(self.pid) rawlist = cext.proc_open_files(self.pid)
for path, fd in rawlist: for path, fd in rawlist:
if isfile_strict(path): if isfile_strict(path):
@ -530,7 +497,6 @@ class Process(object):
raise ValueError("invalid %r kind argument; choose between %s" raise ValueError("invalid %r kind argument; choose between %s"
% (kind, ', '.join([repr(x) for x in conn_tmap]))) % (kind, ', '.join([repr(x) for x in conn_tmap])))
families, types = conn_tmap[kind] families, types = conn_tmap[kind]
with catch_zombie(self):
rawlist = cext.proc_connections(self.pid, families, types) rawlist = cext.proc_connections(self.pid, families, types)
ret = [] ret = []
for item in rawlist: for item in rawlist:
@ -544,7 +510,6 @@ class Process(object):
def num_fds(self): def num_fds(self):
if self.pid == 0: if self.pid == 0:
return 0 return 0
with catch_zombie(self):
return cext.proc_num_fds(self.pid) return cext.proc_num_fds(self.pid)
@wrap_exceptions @wrap_exceptions
@ -553,12 +518,10 @@ class Process(object):
@wrap_exceptions @wrap_exceptions
def nice_get(self): def nice_get(self):
with catch_zombie(self):
return cext_posix.getpriority(self.pid) return cext_posix.getpriority(self.pid)
@wrap_exceptions @wrap_exceptions
def nice_set(self, value): def nice_set(self, value):
with catch_zombie(self):
return cext_posix.setpriority(self.pid, value) return cext_posix.setpriority(self.pid, value)
@wrap_exceptions @wrap_exceptions

View File

@ -10,18 +10,19 @@ import signal
import sys import sys
import time import time
from ._common import TimeoutExpired
from ._common import memoize from ._common import memoize
from ._common import sdiskusage from ._common import sdiskusage
from ._common import TimeoutExpired
from ._common import usage_percent from ._common import usage_percent
from ._compat import PY3
from ._compat import ChildProcessError from ._compat import ChildProcessError
from ._compat import FileNotFoundError from ._compat import FileNotFoundError
from ._compat import InterruptedError from ._compat import InterruptedError
from ._compat import PermissionError from ._compat import PermissionError
from ._compat import ProcessLookupError from ._compat import ProcessLookupError
from ._compat import PY3
from ._compat import unicode from ._compat import unicode
if sys.version_info >= (3, 4): if sys.version_info >= (3, 4):
import enum import enum
else: else:

View File

@ -17,22 +17,22 @@ from . import _common
from . import _psposix from . import _psposix
from . import _psutil_posix as cext_posix from . import _psutil_posix as cext_posix
from . import _psutil_sunos as cext from . import _psutil_sunos as cext
from ._common import AccessDenied
from ._common import AF_INET6 from ._common import AF_INET6
from ._common import AccessDenied
from ._common import NoSuchProcess
from ._common import ZombieProcess
from ._common import debug from ._common import debug
from ._common import get_procfs_path from ._common import get_procfs_path
from ._common import isfile_strict from ._common import isfile_strict
from ._common import memoize_when_activated from ._common import memoize_when_activated
from ._common import NoSuchProcess
from ._common import sockfam_to_enum from ._common import sockfam_to_enum
from ._common import socktype_to_enum from ._common import socktype_to_enum
from ._common import usage_percent from ._common import usage_percent
from ._common import ZombieProcess from ._compat import PY3
from ._compat import b
from ._compat import FileNotFoundError from ._compat import FileNotFoundError
from ._compat import PermissionError from ._compat import PermissionError
from ._compat import ProcessLookupError from ._compat import ProcessLookupError
from ._compat import PY3 from ._compat import b
__extra__all__ = ["CONN_IDLE", "CONN_BOUND", "PROCFS_PATH"] __extra__all__ = ["CONN_IDLE", "CONN_BOUND", "PROCFS_PATH"]
@ -155,7 +155,7 @@ def swap_memory():
total = free = 0 total = free = 0
for line in lines: for line in lines:
line = line.split() line = line.split()
t, f = line[3:4] t, f = line[3:5]
total += int(int(t) * 512) total += int(int(t) * 512)
free += int(int(f) * 512) free += int(int(f) * 512)
used = total - free used = total - free
@ -190,9 +190,9 @@ def cpu_count_logical():
return None return None
def cpu_count_physical(): def cpu_count_cores():
"""Return the number of physical CPUs in the system.""" """Return the number of CPU cores in the system."""
return cext.cpu_count_phys() return cext.cpu_count_cores()
def cpu_stats(): def cpu_stats():
@ -231,7 +231,7 @@ def disk_partitions(all=False):
continue continue
except OSError as err: except OSError as err:
# https://github.com/giampaolo/psutil/issues/1674 # https://github.com/giampaolo/psutil/issues/1674
debug("skipping %r: %r" % (mountpoint, err)) debug("skipping %r: %s" % (mountpoint, err))
continue continue
maxfile = maxpath = None # set later maxfile = maxpath = None # set later
ntuple = _common.sdiskpart(device, mountpoint, fstype, opts, ntuple = _common.sdiskpart(device, mountpoint, fstype, opts,

View File

@ -14,22 +14,22 @@ import time
from collections import namedtuple from collections import namedtuple
from . import _common from . import _common
from ._common import ENCODING
from ._common import ENCODING_ERRS
from ._common import AccessDenied from ._common import AccessDenied
from ._common import NoSuchProcess
from ._common import TimeoutExpired
from ._common import conn_tmap from ._common import conn_tmap
from ._common import conn_to_ntuple from ._common import conn_to_ntuple
from ._common import debug from ._common import debug
from ._common import ENCODING
from ._common import ENCODING_ERRS
from ._common import isfile_strict from ._common import isfile_strict
from ._common import memoize from ._common import memoize
from ._common import memoize_when_activated from ._common import memoize_when_activated
from ._common import NoSuchProcess
from ._common import parse_environ_block from ._common import parse_environ_block
from ._common import TimeoutExpired
from ._common import usage_percent from ._common import usage_percent
from ._compat import PY3
from ._compat import long from ._compat import long
from ._compat import lru_cache from ._compat import lru_cache
from ._compat import PY3
from ._compat import range from ._compat import range
from ._compat import unicode from ._compat import unicode
from ._psutil_windows import ABOVE_NORMAL_PRIORITY_CLASS from ._psutil_windows import ABOVE_NORMAL_PRIORITY_CLASS
@ -39,6 +39,7 @@ from ._psutil_windows import IDLE_PRIORITY_CLASS
from ._psutil_windows import NORMAL_PRIORITY_CLASS from ._psutil_windows import NORMAL_PRIORITY_CLASS
from ._psutil_windows import REALTIME_PRIORITY_CLASS from ._psutil_windows import REALTIME_PRIORITY_CLASS
try: try:
from . import _psutil_windows as cext from . import _psutil_windows as cext
except ImportError as err: except ImportError as err:
@ -197,7 +198,7 @@ def convert_dos_path(s):
"C:\Windows\systemew\file.txt" "C:\Windows\systemew\file.txt"
""" """
rawdrive = '\\'.join(s.split('\\')[:3]) rawdrive = '\\'.join(s.split('\\')[:3])
driveletter = cext.win32_QueryDosDevice(rawdrive) driveletter = cext.QueryDosDevice(rawdrive)
remainder = s[len(rawdrive):] remainder = s[len(rawdrive):]
return os.path.join(driveletter, remainder) return os.path.join(driveletter, remainder)
@ -241,8 +242,16 @@ def virtual_memory():
def swap_memory(): def swap_memory():
"""Swap system memory as a (total, used, free, sin, sout) tuple.""" """Swap system memory as a (total, used, free, sin, sout) tuple."""
mem = cext.virtual_mem() mem = cext.virtual_mem()
total = mem[2]
free = mem[3] total_phys = mem[0]
free_phys = mem[1]
total_system = mem[2]
free_system = mem[3]
# Despite the name PageFile refers to total system memory here
# thus physical memory values need to be substracted to get swap values
total = total_system - total_phys
free = min(total, free_system - free_phys)
used = total - free used = total - free
percent = usage_percent(used, total, round_=1) percent = usage_percent(used, total, round_=1)
return _common.sswap(total, used, free, percent, 0, 0) return _common.sswap(total, used, free, percent, 0, 0)
@ -304,9 +313,9 @@ def cpu_count_logical():
return cext.cpu_count_logical() return cext.cpu_count_logical()
def cpu_count_physical(): def cpu_count_cores():
"""Return the number of physical CPU cores in the system.""" """Return the number of CPU cores in the system."""
return cext.cpu_count_phys() return cext.cpu_count_cores()
def cpu_stats(): def cpu_stats():
@ -759,7 +768,7 @@ class Process(object):
# 24 = ERROR_TOO_MANY_OPEN_FILES. Not sure why this happens # 24 = ERROR_TOO_MANY_OPEN_FILES. Not sure why this happens
# (perhaps PyPy's JIT delaying garbage collection of files?). # (perhaps PyPy's JIT delaying garbage collection of files?).
if err.errno == 24: if err.errno == 24:
debug("%r forced into AccessDenied" % err) debug("%r translated into AccessDenied" % err)
raise AccessDenied(self.pid, self._name) raise AccessDenied(self.pid, self._name)
raise raise
else: else:

View File

@ -9,6 +9,7 @@ Test utilities.
""" """
from __future__ import print_function from __future__ import print_function
import atexit import atexit
import contextlib import contextlib
import ctypes import ctypes
@ -46,15 +47,16 @@ from psutil import WINDOWS
from psutil._common import bytes2human from psutil._common import bytes2human
from psutil._common import print_color from psutil._common import print_color
from psutil._common import supports_ipv6 from psutil._common import supports_ipv6
from psutil._compat import PY3
from psutil._compat import FileExistsError from psutil._compat import FileExistsError
from psutil._compat import FileNotFoundError from psutil._compat import FileNotFoundError
from psutil._compat import PY3
from psutil._compat import range from psutil._compat import range
from psutil._compat import super from psutil._compat import super
from psutil._compat import u from psutil._compat import u
from psutil._compat import unicode from psutil._compat import unicode
from psutil._compat import which from psutil._compat import which
if PY3: if PY3:
import unittest import unittest
else: else:
@ -72,6 +74,9 @@ if sys.version_info >= (3, 4):
else: else:
enum = None enum = None
if POSIX:
from psutil._psposix import wait_pid
__all__ = [ __all__ = [
# constants # constants
@ -482,9 +487,6 @@ def terminate(proc_or_pid, sig=signal.SIGTERM, wait_timeout=GLOBAL_TIMEOUT):
Does nothing if the process does not exist. Does nothing if the process does not exist.
Return process exit status. Return process exit status.
""" """
if POSIX:
from psutil._psposix import wait_pid
def wait(proc, timeout): def wait(proc, timeout):
if isinstance(proc, subprocess.Popen) and not PY3: if isinstance(proc, subprocess.Popen) and not PY3:
proc.wait() proc.wait()
@ -952,6 +954,15 @@ class TestMemoryLeak(PsutilTestCase):
retries = 10 if CI_TESTING else 5 retries = 10 if CI_TESTING else 5
verbose = True verbose = True
_thisproc = psutil.Process() _thisproc = psutil.Process()
_psutil_debug_orig = bool(os.getenv('PSUTIL_DEBUG', 0))
@classmethod
def setUpClass(cls):
psutil._set_debug(False) # avoid spamming to stderr
@classmethod
def tearDownClass(cls):
psutil._set_debug(cls._psutil_debug_orig)
def _get_mem(self): def _get_mem(self):
# USS is the closest thing we have to "real" memory usage and it # USS is the closest thing we have to "real" memory usage and it
@ -1724,8 +1735,8 @@ else:
in memory via ctypes. in memory via ctypes.
Return the new absolutized, normcased path. Return the new absolutized, normcased path.
""" """
from ctypes import wintypes
from ctypes import WinError from ctypes import WinError
from ctypes import wintypes
ext = ".dll" ext = ".dll"
dst = get_testfn(suffix=suffix + ext) dst = get_testfn(suffix=suffix + ext)
libs = [x.path for x in psutil.Process().memory_maps() if libs = [x.path for x in psutil.Process().memory_maps() if

View File

@ -10,4 +10,6 @@ $ python -m psutil.tests
""" """
from .runner import main from .runner import main
main() main()

View File

@ -21,6 +21,7 @@ Parallel:
""" """
from __future__ import print_function from __future__ import print_function
import atexit import atexit
import optparse import optparse
import os import os
@ -28,6 +29,8 @@ import sys
import textwrap import textwrap
import time import time
import unittest import unittest
try: try:
import ctypes import ctypes
except ImportError: except ImportError:
@ -298,16 +301,15 @@ def get_runner(parallel=False):
# Used by test_*,py modules. # Used by test_*,py modules.
def run_from_name(name): def run_from_name(name):
if CI_TESTING:
print_sysinfo()
suite = TestLoader().from_name(name) suite = TestLoader().from_name(name)
runner = get_runner() runner = get_runner()
runner.run(suite) runner.run(suite)
def setup(): def setup():
# Note: doc states that altering os.environment may cause memory psutil._set_debug(True)
# leaks on some platforms.
# Sets PSUTIL_TESTING and PSUTIL_DEBUG in the C module.
psutil._psplatform.cext.set_testing()
def main(): def main():

View File

@ -10,11 +10,11 @@
import re import re
import psutil
from psutil import AIX from psutil import AIX
from psutil.tests import PsutilTestCase from psutil.tests import PsutilTestCase
from psutil.tests import sh from psutil.tests import sh
from psutil.tests import unittest from psutil.tests import unittest
import psutil
@unittest.skipIf(not AIX, "AIX only") @unittest.skipIf(not AIX, "AIX only")

View File

@ -20,12 +20,12 @@ from psutil import BSD
from psutil import FREEBSD from psutil import FREEBSD
from psutil import NETBSD from psutil import NETBSD
from psutil import OPENBSD from psutil import OPENBSD
from psutil.tests import spawn_testproc
from psutil.tests import HAS_BATTERY from psutil.tests import HAS_BATTERY
from psutil.tests import TOLERANCE_SYS_MEM
from psutil.tests import PsutilTestCase from psutil.tests import PsutilTestCase
from psutil.tests import retry_on_failure from psutil.tests import retry_on_failure
from psutil.tests import sh from psutil.tests import sh
from psutil.tests import TOLERANCE_SYS_MEM from psutil.tests import spawn_testproc
from psutil.tests import terminate from psutil.tests import terminate
from psutil.tests import unittest from psutil.tests import unittest
from psutil.tests import which from psutil.tests import which

View File

@ -8,7 +8,6 @@
import os import os
import socket import socket
import sys
import textwrap import textwrap
from contextlib import closing from contextlib import closing
from socket import AF_INET from socket import AF_INET
@ -28,17 +27,17 @@ from psutil import WINDOWS
from psutil._common import supports_ipv6 from psutil._common import supports_ipv6
from psutil._compat import PY3 from psutil._compat import PY3
from psutil.tests import AF_UNIX from psutil.tests import AF_UNIX
from psutil.tests import HAS_CONNECTIONS_UNIX
from psutil.tests import SKIP_SYSCONS
from psutil.tests import PsutilTestCase
from psutil.tests import bind_socket from psutil.tests import bind_socket
from psutil.tests import bind_unix_socket from psutil.tests import bind_unix_socket
from psutil.tests import check_connection_ntuple from psutil.tests import check_connection_ntuple
from psutil.tests import create_sockets from psutil.tests import create_sockets
from psutil.tests import HAS_CONNECTIONS_UNIX
from psutil.tests import PsutilTestCase
from psutil.tests import reap_children from psutil.tests import reap_children
from psutil.tests import retry_on_failure from psutil.tests import retry_on_failure
from psutil.tests import serialrun from psutil.tests import serialrun
from psutil.tests import skip_on_access_denied from psutil.tests import skip_on_access_denied
from psutil.tests import SKIP_SYSCONS
from psutil.tests import tcp_socketpair from psutil.tests import tcp_socketpair
from psutil.tests import unittest from psutil.tests import unittest
from psutil.tests import unix_socketpair from psutil.tests import unix_socketpair
@ -47,7 +46,6 @@ from psutil.tests import wait_for_file
thisproc = psutil.Process() thisproc = psutil.Process()
SOCK_SEQPACKET = getattr(socket, "SOCK_SEQPACKET", object()) SOCK_SEQPACKET = getattr(socket, "SOCK_SEQPACKET", object())
PYTHON_39 = sys.version_info[:2] == (3, 9)
@serialrun @serialrun

View File

@ -18,6 +18,7 @@ import sys
import time import time
import traceback import traceback
import psutil
from psutil import AIX from psutil import AIX
from psutil import BSD from psutil import BSD
from psutil import FREEBSD from psutil import FREEBSD
@ -33,25 +34,24 @@ from psutil._compat import FileNotFoundError
from psutil._compat import long from psutil._compat import long
from psutil._compat import range from psutil._compat import range
from psutil.tests import APPVEYOR from psutil.tests import APPVEYOR
from psutil.tests import check_connection_ntuple
from psutil.tests import CI_TESTING from psutil.tests import CI_TESTING
from psutil.tests import create_sockets
from psutil.tests import enum
from psutil.tests import GITHUB_ACTIONS from psutil.tests import GITHUB_ACTIONS
from psutil.tests import HAS_CPU_FREQ from psutil.tests import HAS_CPU_FREQ
from psutil.tests import HAS_NET_IO_COUNTERS from psutil.tests import HAS_NET_IO_COUNTERS
from psutil.tests import HAS_SENSORS_FANS from psutil.tests import HAS_SENSORS_FANS
from psutil.tests import HAS_SENSORS_TEMPERATURES from psutil.tests import HAS_SENSORS_TEMPERATURES
from psutil.tests import PYPY
from psutil.tests import SKIP_SYSCONS
from psutil.tests import VALID_PROC_STATUSES
from psutil.tests import PsutilTestCase
from psutil.tests import check_connection_ntuple
from psutil.tests import create_sockets
from psutil.tests import enum
from psutil.tests import is_namedtuple from psutil.tests import is_namedtuple
from psutil.tests import kernel_version from psutil.tests import kernel_version
from psutil.tests import process_namespace from psutil.tests import process_namespace
from psutil.tests import PsutilTestCase
from psutil.tests import PYPY
from psutil.tests import serialrun from psutil.tests import serialrun
from psutil.tests import SKIP_SYSCONS
from psutil.tests import unittest from psutil.tests import unittest
from psutil.tests import VALID_PROC_STATUSES
import psutil
# =================================================================== # ===================================================================
@ -360,7 +360,6 @@ def proc_info(pid):
elif isinstance(exc, psutil.NoSuchProcess): elif isinstance(exc, psutil.NoSuchProcess):
tcase.assertProcessGone(proc) tcase.assertProcessGone(proc)
str(exc) str(exc)
assert exc.msg
def do_wait(): def do_wait():
if pid != 0: if pid != 0:

View File

@ -7,6 +7,7 @@
"""Linux specific tests.""" """Linux specific tests."""
from __future__ import division from __future__ import division
import collections import collections
import contextlib import contextlib
import errno import errno
@ -23,31 +24,39 @@ import warnings
import psutil import psutil
from psutil import LINUX from psutil import LINUX
from psutil._compat import basestring
from psutil._compat import FileNotFoundError
from psutil._compat import PY3 from psutil._compat import PY3
from psutil._compat import FileNotFoundError
from psutil._compat import basestring
from psutil._compat import u from psutil._compat import u
from psutil.tests import call_until from psutil.tests import GITHUB_ACTIONS
from psutil.tests import GLOBAL_TIMEOUT from psutil.tests import GLOBAL_TIMEOUT
from psutil.tests import HAS_BATTERY from psutil.tests import HAS_BATTERY
from psutil.tests import HAS_CPU_FREQ from psutil.tests import HAS_CPU_FREQ
from psutil.tests import HAS_GETLOADAVG from psutil.tests import HAS_GETLOADAVG
from psutil.tests import HAS_RLIMIT from psutil.tests import HAS_RLIMIT
from psutil.tests import mock
from psutil.tests import PsutilTestCase
from psutil.tests import PYPY from psutil.tests import PYPY
from psutil.tests import TOLERANCE_DISK_USAGE
from psutil.tests import TOLERANCE_SYS_MEM
from psutil.tests import PsutilTestCase
from psutil.tests import ThreadTask
from psutil.tests import call_until
from psutil.tests import mock
from psutil.tests import reload_module from psutil.tests import reload_module
from psutil.tests import retry_on_failure from psutil.tests import retry_on_failure
from psutil.tests import safe_rmpath from psutil.tests import safe_rmpath
from psutil.tests import sh from psutil.tests import sh
from psutil.tests import skip_on_not_implemented from psutil.tests import skip_on_not_implemented
from psutil.tests import ThreadTask
from psutil.tests import TOLERANCE_DISK_USAGE
from psutil.tests import TOLERANCE_SYS_MEM
from psutil.tests import unittest from psutil.tests import unittest
from psutil.tests import which from psutil.tests import which
if LINUX:
from psutil._pslinux import CLOCK_TICKS
from psutil._pslinux import RootFsDeviceFinder
from psutil._pslinux import calculate_avail_vmem
from psutil._pslinux import open_binary
HERE = os.path.abspath(os.path.dirname(__file__)) HERE = os.path.abspath(os.path.dirname(__file__))
SIOCGIFADDR = 0x8915 SIOCGIFADDR = 0x8915
SIOCGIFCONF = 0x8912 SIOCGIFCONF = 0x8912
@ -58,6 +67,7 @@ if LINUX:
SECTOR_SIZE = 512 SECTOR_SIZE = 512
EMPTY_TEMPERATURES = not glob.glob('/sys/class/hwmon/hwmon*') EMPTY_TEMPERATURES = not glob.glob('/sys/class/hwmon/hwmon*')
# ===================================================================== # =====================================================================
# --- utils # --- utils
# ===================================================================== # =====================================================================
@ -141,7 +151,7 @@ def free_swap():
"""Parse 'free' cmd and return swap memory's s total, used and free """Parse 'free' cmd and return swap memory's s total, used and free
values. values.
""" """
out = sh('free -b', env={"LANG": "C.UTF-8"}) out = sh(["free", "-b"], env={"LANG": "C.UTF-8"})
lines = out.split('\n') lines = out.split('\n')
for line in lines: for line in lines:
if line.startswith('Swap'): if line.startswith('Swap'):
@ -160,7 +170,7 @@ def free_physmem():
# and 'cached' memory which may have different positions so we # and 'cached' memory which may have different positions so we
# do not return them. # do not return them.
# https://github.com/giampaolo/psutil/issues/538#issuecomment-57059946 # https://github.com/giampaolo/psutil/issues/538#issuecomment-57059946
out = sh('free -b', env={"LANG": "C.UTF-8"}) out = sh(["free", "-b"], env={"LANG": "C.UTF-8"})
lines = out.split('\n') lines = out.split('\n')
for line in lines: for line in lines:
if line.startswith('Mem'): if line.startswith('Mem'):
@ -174,7 +184,7 @@ def free_physmem():
def vmstat(stat): def vmstat(stat):
out = sh("vmstat -s", env={"LANG": "C.UTF-8"}) out = sh(["vmstat", "-s"], env={"LANG": "C.UTF-8"})
for line in out.split("\n"): for line in out.split("\n"):
line = line.strip() line = line.strip()
if stat in line: if stat in line:
@ -183,7 +193,7 @@ def vmstat(stat):
def get_free_version_info(): def get_free_version_info():
out = sh("free -V").strip() out = sh(["free", "-V"]).strip()
if 'UNKNOWN' in out: if 'UNKNOWN' in out:
raise unittest.SkipTest("can't determine free version") raise unittest.SkipTest("can't determine free version")
return tuple(map(int, out.split()[-1].split('.'))) return tuple(map(int, out.split()[-1].split('.')))
@ -243,7 +253,8 @@ class TestSystemVirtualMemory(PsutilTestCase):
# self.assertEqual(free_value, psutil_value) # self.assertEqual(free_value, psutil_value)
vmstat_value = vmstat('total memory') * 1024 vmstat_value = vmstat('total memory') * 1024
psutil_value = psutil.virtual_memory().total psutil_value = psutil.virtual_memory().total
self.assertAlmostEqual(vmstat_value, psutil_value) self.assertAlmostEqual(
vmstat_value, psutil_value, delta=TOLERANCE_SYS_MEM)
@retry_on_failure() @retry_on_failure()
def test_used(self): def test_used(self):
@ -303,7 +314,7 @@ class TestSystemVirtualMemory(PsutilTestCase):
def test_available(self): def test_available(self):
# "free" output format has changed at some point: # "free" output format has changed at some point:
# https://github.com/giampaolo/psutil/issues/538#issuecomment-147192098 # https://github.com/giampaolo/psutil/issues/538#issuecomment-147192098
out = sh("free -b") out = sh(["free", "-b"])
lines = out.split('\n') lines = out.split('\n')
if 'available' not in lines[0]: if 'available' not in lines[0]:
raise unittest.SkipTest("free does not support 'available' column") raise unittest.SkipTest("free does not support 'available' column")
@ -357,9 +368,6 @@ class TestSystemVirtualMemory(PsutilTestCase):
def test_avail_old_percent(self): def test_avail_old_percent(self):
# Make sure that our calculation of avail mem for old kernels # Make sure that our calculation of avail mem for old kernels
# is off by max 15%. # is off by max 15%.
from psutil._pslinux import calculate_avail_vmem
from psutil._pslinux import open_binary
mems = {} mems = {}
with open_binary('/proc/meminfo') as f: with open_binary('/proc/meminfo') as f:
for line in f: for line in f:
@ -715,7 +723,7 @@ class TestSystemCPUCountLogical(PsutilTestCase):
@unittest.skipIf(not LINUX, "LINUX only") @unittest.skipIf(not LINUX, "LINUX only")
class TestSystemCPUCountPhysical(PsutilTestCase): class TestSystemCPUCountCores(PsutilTestCase):
@unittest.skipIf(not which("lscpu"), "lscpu utility not available") @unittest.skipIf(not which("lscpu"), "lscpu utility not available")
def test_against_lscpu(self): def test_against_lscpu(self):
@ -728,9 +736,9 @@ class TestSystemCPUCountPhysical(PsutilTestCase):
self.assertEqual(psutil.cpu_count(logical=False), len(core_ids)) self.assertEqual(psutil.cpu_count(logical=False), len(core_ids))
def test_method_2(self): def test_method_2(self):
meth_1 = psutil._pslinux.cpu_count_physical() meth_1 = psutil._pslinux.cpu_count_cores()
with mock.patch('glob.glob', return_value=[]) as m: with mock.patch('glob.glob', return_value=[]) as m:
meth_2 = psutil._pslinux.cpu_count_physical() meth_2 = psutil._pslinux.cpu_count_cores()
assert m.called assert m.called
if meth_1 is not None: if meth_1 is not None:
self.assertEqual(meth_1, meth_2) self.assertEqual(meth_1, meth_2)
@ -738,7 +746,7 @@ class TestSystemCPUCountPhysical(PsutilTestCase):
def test_emulate_none(self): def test_emulate_none(self):
with mock.patch('glob.glob', return_value=[]) as m1: with mock.patch('glob.glob', return_value=[]) as m1:
with mock.patch('psutil._common.open', create=True) as m2: with mock.patch('psutil._common.open', create=True) as m2:
self.assertIsNone(psutil._pslinux.cpu_count_physical()) self.assertIsNone(psutil._pslinux.cpu_count_cores())
assert m1.called assert m1.called
assert m2.called assert m2.called
@ -768,18 +776,14 @@ class TestSystemCPUFrequency(PsutilTestCase):
if path.startswith('/sys/devices/system/cpu/'): if path.startswith('/sys/devices/system/cpu/'):
return False return False
else: else:
if path == "/proc/cpuinfo":
flags.append(None)
return os_path_exists(path) return os_path_exists(path)
flags = []
os_path_exists = os.path.exists os_path_exists = os.path.exists
try: try:
with mock.patch("os.path.exists", side_effect=path_exists_mock): with mock.patch("os.path.exists", side_effect=path_exists_mock):
reload_module(psutil._pslinux) reload_module(psutil._pslinux)
ret = psutil.cpu_freq() ret = psutil.cpu_freq()
assert ret assert ret
assert flags
self.assertEqual(ret.max, 0.0) self.assertEqual(ret.max, 0.0)
self.assertEqual(ret.min, 0.0) self.assertEqual(ret.min, 0.0)
for freq in psutil.cpu_freq(percpu=True): for freq in psutil.cpu_freq(percpu=True):
@ -1263,6 +1267,68 @@ class TestSystemDiskIoCounters(PsutilTestCase):
self.assertRaises(NotImplementedError, psutil.disk_io_counters) self.assertRaises(NotImplementedError, psutil.disk_io_counters)
@unittest.skipIf(not LINUX, "LINUX only")
class TestRootFsDeviceFinder(PsutilTestCase):
def setUp(self):
dev = os.stat("/").st_dev
self.major = os.major(dev)
self.minor = os.minor(dev)
def test_call_methods(self):
finder = RootFsDeviceFinder()
if os.path.exists("/proc/partitions"):
finder.ask_proc_partitions()
else:
self.assertRaises(FileNotFoundError, finder.ask_proc_partitions)
if os.path.exists("/sys/dev/block/%s:%s/uevent" % (
self.major, self.minor)):
finder.ask_sys_dev_block()
else:
self.assertRaises(FileNotFoundError, finder.ask_sys_dev_block)
finder.ask_sys_class_block()
@unittest.skipIf(GITHUB_ACTIONS, "unsupported on GITHUB_ACTIONS")
def test_comparisons(self):
finder = RootFsDeviceFinder()
self.assertIsNotNone(finder.find())
a = b = c = None
if os.path.exists("/proc/partitions"):
a = finder.ask_proc_partitions()
if os.path.exists("/sys/dev/block/%s:%s/uevent" % (
self.major, self.minor)):
b = finder.ask_sys_class_block()
c = finder.ask_sys_dev_block()
base = a or b or c
if base and a:
self.assertEqual(base, a)
if base and b:
self.assertEqual(base, b)
if base and c:
self.assertEqual(base, c)
@unittest.skipIf(not which("findmnt"), "findmnt utility not available")
@unittest.skipIf(GITHUB_ACTIONS, "unsupported on GITHUB_ACTIONS")
def test_against_findmnt(self):
psutil_value = RootFsDeviceFinder().find()
findmnt_value = sh("findmnt -o SOURCE -rn /")
self.assertEqual(psutil_value, findmnt_value)
def test_disk_partitions_mocked(self):
with mock.patch(
'psutil._pslinux.cext.disk_partitions',
return_value=[('/dev/root', '/', 'ext4', 'rw')]) as m:
part = psutil.disk_partitions()[0]
assert m.called
if not GITHUB_ACTIONS:
self.assertNotEqual(part.device, "/dev/root")
self.assertEqual(part.device, RootFsDeviceFinder().find())
else:
self.assertEqual(part.device, "/dev/root")
# ===================================================================== # =====================================================================
# --- misc # --- misc
# ===================================================================== # =====================================================================
@ -1431,9 +1497,7 @@ class TestMisc(PsutilTestCase):
# - Process(tid) is supposed to work # - Process(tid) is supposed to work
# - pids() should not return the TID # - pids() should not return the TID
# See: https://github.com/giampaolo/psutil/issues/687 # See: https://github.com/giampaolo/psutil/issues/687
t = ThreadTask() with ThreadTask():
t.start()
try:
p = psutil.Process() p = psutil.Process()
threads = p.threads() threads = p.threads()
self.assertEqual(len(threads), 2) self.assertEqual(len(threads), 2)
@ -1442,8 +1506,6 @@ class TestMisc(PsutilTestCase):
pt = psutil.Process(tid) pt = psutil.Process(tid)
pt.as_dict() pt.as_dict()
self.assertNotIn(tid, psutil.pids()) self.assertNotIn(tid, psutil.pids())
finally:
t.stop()
def test_pid_exists_no_proc_status(self): def test_pid_exists_no_proc_status(self):
# Internally pid_exists relies on /proc/{pid}/status. # Internally pid_exists relies on /proc/{pid}/status.
@ -1837,6 +1899,22 @@ class TestProcess(PsutilTestCase):
assert not files assert not files
assert m.called assert m.called
def test_open_files_enametoolong(self):
# Simulate a case where /proc/{pid}/fd/{fd} symlink
# points to a file with full path longer than PATH_MAX, see:
# https://github.com/giampaolo/psutil/issues/1940
p = psutil.Process()
files = p.open_files()
with open(self.get_testfn(), 'w'):
# give the kernel some time to see the new file
call_until(p.open_files, "len(ret) != %i" % len(files))
patch_point = 'psutil._pslinux.os.readlink'
with mock.patch(patch_point,
side_effect=OSError(errno.ENAMETOOLONG, "")) as m:
files = p.open_files()
assert not files
assert m.called
# --- mocked tests # --- mocked tests
def test_terminal_mocked(self): def test_terminal_mocked(self):
@ -1985,8 +2063,6 @@ class TestProcess(PsutilTestCase):
self.assertEqual(exc.exception.name, p.name()) self.assertEqual(exc.exception.name, p.name())
def test_stat_file_parsing(self): def test_stat_file_parsing(self):
from psutil._pslinux import CLOCK_TICKS
args = [ args = [
"0", # pid "0", # pid
"(cat)", # name "(cat)", # name
@ -2072,6 +2148,16 @@ class TestProcess(PsutilTestCase):
self.assertEqual(gids.saved, 1006) self.assertEqual(gids.saved, 1006)
self.assertEqual(p._proc._get_eligible_cpus(), list(range(0, 8))) self.assertEqual(p._proc._get_eligible_cpus(), list(range(0, 8)))
def test_connections_enametoolong(self):
# Simulate a case where /proc/{pid}/fd/{fd} symlink points to
# a file with full path longer than PATH_MAX, see:
# https://github.com/giampaolo/psutil/issues/1940
with mock.patch('psutil._pslinux.os.readlink',
side_effect=OSError(errno.ENAMETOOLONG, "")) as m:
p = psutil.Process()
assert not p.connections()
assert m.called
@unittest.skipIf(not LINUX, "LINUX only") @unittest.skipIf(not LINUX, "LINUX only")
class TestProcessAgainstStatus(PsutilTestCase): class TestProcessAgainstStatus(PsutilTestCase):

View File

@ -16,6 +16,7 @@ because of how its JIT handles memory, so tests are skipped.
""" """
from __future__ import print_function from __future__ import print_function
import functools import functools
import os import os
@ -29,8 +30,6 @@ from psutil import SUNOS
from psutil import WINDOWS from psutil import WINDOWS
from psutil._compat import ProcessLookupError from psutil._compat import ProcessLookupError
from psutil._compat import super from psutil._compat import super
from psutil.tests import create_sockets
from psutil.tests import get_testfn
from psutil.tests import HAS_CPU_AFFINITY from psutil.tests import HAS_CPU_AFFINITY
from psutil.tests import HAS_CPU_FREQ from psutil.tests import HAS_CPU_FREQ
from psutil.tests import HAS_ENVIRON from psutil.tests import HAS_ENVIRON
@ -43,12 +42,14 @@ from psutil.tests import HAS_RLIMIT
from psutil.tests import HAS_SENSORS_BATTERY from psutil.tests import HAS_SENSORS_BATTERY
from psutil.tests import HAS_SENSORS_FANS from psutil.tests import HAS_SENSORS_FANS
from psutil.tests import HAS_SENSORS_TEMPERATURES from psutil.tests import HAS_SENSORS_TEMPERATURES
from psutil.tests import TestMemoryLeak
from psutil.tests import create_sockets
from psutil.tests import get_testfn
from psutil.tests import process_namespace from psutil.tests import process_namespace
from psutil.tests import skip_on_access_denied from psutil.tests import skip_on_access_denied
from psutil.tests import spawn_testproc from psutil.tests import spawn_testproc
from psutil.tests import system_namespace from psutil.tests import system_namespace
from psutil.tests import terminate from psutil.tests import terminate
from psutil.tests import TestMemoryLeak
from psutil.tests import unittest from psutil.tests import unittest
@ -347,7 +348,7 @@ class TestModuleFunctionsLeaks(TestMemoryLeak):
self.execute(lambda: psutil.cpu_count(logical=True)) self.execute(lambda: psutil.cpu_count(logical=True))
@fewtimes_if_linux() @fewtimes_if_linux()
def test_cpu_count_physical(self): def test_cpu_count_cores(self):
self.execute(lambda: psutil.cpu_count(logical=False)) self.execute(lambda: psutil.cpu_count(logical=False))
@fewtimes_if_linux() @fewtimes_if_linux()
@ -456,6 +457,9 @@ class TestModuleFunctionsLeaks(TestMemoryLeak):
def test_users(self): def test_users(self):
self.execute(psutil.users) self.execute(psutil.users)
def test_set_debug(self):
self.execute(lambda: psutil._set_debug(False))
if WINDOWS: if WINDOWS:
# --- win services # --- win services

View File

@ -17,16 +17,19 @@ import os
import pickle import pickle
import socket import socket
import stat import stat
import sys
import psutil
import psutil.tests
from psutil import LINUX from psutil import LINUX
from psutil import POSIX from psutil import POSIX
from psutil import WINDOWS from psutil import WINDOWS
from psutil._common import debug
from psutil._common import memoize from psutil._common import memoize
from psutil._common import memoize_when_activated from psutil._common import memoize_when_activated
from psutil._common import supports_ipv6 from psutil._common import supports_ipv6
from psutil._common import wrap_numbers from psutil._common import wrap_numbers
from psutil._compat import PY3 from psutil._compat import PY3
from psutil._compat import redirect_stderr
from psutil.tests import APPVEYOR from psutil.tests import APPVEYOR
from psutil.tests import CI_TESTING from psutil.tests import CI_TESTING
from psutil.tests import HAS_BATTERY from psutil.tests import HAS_BATTERY
@ -35,20 +38,15 @@ from psutil.tests import HAS_NET_IO_COUNTERS
from psutil.tests import HAS_SENSORS_BATTERY from psutil.tests import HAS_SENSORS_BATTERY
from psutil.tests import HAS_SENSORS_FANS from psutil.tests import HAS_SENSORS_FANS
from psutil.tests import HAS_SENSORS_TEMPERATURES from psutil.tests import HAS_SENSORS_TEMPERATURES
from psutil.tests import import_module_by_path
from psutil.tests import mock
from psutil.tests import PsutilTestCase
from psutil.tests import PYTHON_EXE from psutil.tests import PYTHON_EXE
from psutil.tests import reload_module
from psutil.tests import ROOT_DIR from psutil.tests import ROOT_DIR
from psutil.tests import SCRIPTS_DIR from psutil.tests import SCRIPTS_DIR
from psutil.tests import PsutilTestCase
from psutil.tests import import_module_by_path
from psutil.tests import mock
from psutil.tests import reload_module
from psutil.tests import sh from psutil.tests import sh
from psutil.tests import unittest from psutil.tests import unittest
import psutil
import psutil.tests
PYTHON_39 = sys.version_info[:2] == (3, 9)
# =================================================================== # ===================================================================
@ -97,57 +95,71 @@ class TestMisc(PsutilTestCase):
def test_process__str__(self): def test_process__str__(self):
self.test_process__repr__(func=str) self.test_process__repr__(func=str)
def test_no_such_process__repr__(self, func=repr): def test_no_such_process__repr__(self):
self.assertEqual( self.assertEqual(
repr(psutil.NoSuchProcess(321)), repr(psutil.NoSuchProcess(321)),
"psutil.NoSuchProcess process no longer exists (pid=321)") "psutil.NoSuchProcess(pid=321, msg='process no longer exists')")
self.assertEqual( self.assertEqual(
repr(psutil.NoSuchProcess(321, name='foo')), repr(psutil.NoSuchProcess(321, name="name", msg="msg")),
"psutil.NoSuchProcess process no longer exists (pid=321, " "psutil.NoSuchProcess(pid=321, name='name', msg='msg')")
"name='foo')")
self.assertEqual(
repr(psutil.NoSuchProcess(321, msg='foo')),
"psutil.NoSuchProcess foo")
def test_zombie_process__repr__(self, func=repr): def test_no_such_process__str__(self):
self.assertEqual(
str(psutil.NoSuchProcess(321)),
"process no longer exists (pid=321)")
self.assertEqual(
str(psutil.NoSuchProcess(321, name="name", msg="msg")),
"msg (pid=321, name='name')")
def test_zombie_process__repr__(self):
self.assertEqual( self.assertEqual(
repr(psutil.ZombieProcess(321)), repr(psutil.ZombieProcess(321)),
"psutil.ZombieProcess process still exists but it's a zombie " 'psutil.ZombieProcess(pid=321, msg="PID still '
"(pid=321)") 'exists but it\'s a zombie")')
self.assertEqual( self.assertEqual(
repr(psutil.ZombieProcess(321, name='foo')), repr(psutil.ZombieProcess(321, name="name", ppid=320, msg="foo")),
"psutil.ZombieProcess process still exists but it's a zombie " "psutil.ZombieProcess(pid=321, ppid=320, name='name', msg='foo')")
"(pid=321, name='foo')")
self.assertEqual(
repr(psutil.ZombieProcess(321, name='foo', ppid=1)),
"psutil.ZombieProcess process still exists but it's a zombie "
"(pid=321, name='foo', ppid=1)")
self.assertEqual(
repr(psutil.ZombieProcess(321, msg='foo')),
"psutil.ZombieProcess foo")
def test_access_denied__repr__(self, func=repr): def test_zombie_process__str__(self):
self.assertEqual(
str(psutil.ZombieProcess(321)),
"PID still exists but it's a zombie (pid=321)")
self.assertEqual(
str(psutil.ZombieProcess(321, name="name", ppid=320, msg="foo")),
"foo (pid=321, ppid=320, name='name')")
def test_access_denied__repr__(self):
self.assertEqual( self.assertEqual(
repr(psutil.AccessDenied(321)), repr(psutil.AccessDenied(321)),
"psutil.AccessDenied (pid=321)") "psutil.AccessDenied(pid=321)")
self.assertEqual( self.assertEqual(
repr(psutil.AccessDenied(321, name='foo')), repr(psutil.AccessDenied(321, name="name", msg="msg")),
"psutil.AccessDenied (pid=321, name='foo')") "psutil.AccessDenied(pid=321, name='name', msg='msg')")
self.assertEqual(
repr(psutil.AccessDenied(321, msg='foo')),
"psutil.AccessDenied foo")
def test_timeout_expired__repr__(self, func=repr): def test_access_denied__str__(self):
self.assertEqual( self.assertEqual(
repr(psutil.TimeoutExpired(321)), str(psutil.AccessDenied(321)),
"psutil.TimeoutExpired timeout after 321 seconds") "(pid=321)")
self.assertEqual( self.assertEqual(
repr(psutil.TimeoutExpired(321, pid=111)), str(psutil.AccessDenied(321, name="name", msg="msg")),
"psutil.TimeoutExpired timeout after 321 seconds (pid=111)") "msg (pid=321, name='name')")
def test_timeout_expired__repr__(self):
self.assertEqual( self.assertEqual(
repr(psutil.TimeoutExpired(321, pid=111, name='foo')), repr(psutil.TimeoutExpired(5)),
"psutil.TimeoutExpired timeout after 321 seconds " "psutil.TimeoutExpired(seconds=5, msg='timeout after 5 seconds')")
"(pid=111, name='foo')") self.assertEqual(
repr(psutil.TimeoutExpired(5, pid=321, name="name")),
"psutil.TimeoutExpired(pid=321, name='name', seconds=5, "
"msg='timeout after 5 seconds')")
def test_timeout_expired__str__(self):
self.assertEqual(
str(psutil.TimeoutExpired(5)),
"timeout after 5 seconds")
self.assertEqual(
str(psutil.TimeoutExpired(5, pid=321, name="name")),
"timeout after 5 seconds (pid=321, name='name')")
def test_process__eq__(self): def test_process__eq__(self):
p1 = psutil.Process() p1 = psutil.Process()
@ -354,6 +366,8 @@ class TestMisc(PsutilTestCase):
check(psutil.disk_usage(os.getcwd())) check(psutil.disk_usage(os.getcwd()))
check(psutil.users()) check(psutil.users())
# XXX: https://github.com/pypa/setuptools/pull/2896
@unittest.skipIf(APPVEYOR, "temporarily disabled due to setuptools bug")
def test_setup_script(self): def test_setup_script(self):
setup_py = os.path.join(ROOT_DIR, 'setup.py') setup_py = os.path.join(ROOT_DIR, 'setup.py')
if CI_TESTING and not os.path.exists(setup_py): if CI_TESTING and not os.path.exists(setup_py):
@ -387,6 +401,35 @@ class TestMisc(PsutilTestCase):
reload_module(psutil) reload_module(psutil)
self.assertIn("version conflict", str(cm.exception).lower()) self.assertIn("version conflict", str(cm.exception).lower())
def test_debug(self):
if PY3:
from io import StringIO
else:
from StringIO import StringIO
with redirect_stderr(StringIO()) as f:
debug("hello")
msg = f.getvalue()
assert msg.startswith("psutil-debug"), msg
self.assertIn("hello", msg)
self.assertIn(__file__.replace('.pyc', '.py'), msg)
# supposed to use repr(exc)
with redirect_stderr(StringIO()) as f:
debug(ValueError("this is an error"))
msg = f.getvalue()
self.assertIn("ignoring ValueError", msg)
self.assertIn("'this is an error'", msg)
# supposed to use str(exc), because of extra info about file name
with redirect_stderr(StringIO()) as f:
exc = OSError(2, "no such file")
exc.filename = "/foo"
debug(exc)
msg = f.getvalue()
self.assertIn("no such file", msg)
self.assertIn("/foo", msg)
# =================================================================== # ===================================================================
# --- Tests for wrap_numbers() function. # --- Tests for wrap_numbers() function.
@ -679,11 +722,12 @@ class TestScripts(PsutilTestCase):
@unittest.skipIf(not POSIX, "POSIX only") @unittest.skipIf(not POSIX, "POSIX only")
def test_executable(self): def test_executable(self):
for name in os.listdir(SCRIPTS_DIR): for root, dirs, files in os.walk(SCRIPTS_DIR):
if name.endswith('.py'): for file in files:
path = os.path.join(SCRIPTS_DIR, name) if file.endswith('.py'):
path = os.path.join(root, file)
if not stat.S_IXUSR & os.stat(path)[stat.ST_MODE]: if not stat.S_IXUSR & os.stat(path)[stat.ST_MODE]:
self.fail('%r is not executable' % path) raise self.fail('%r is not executable' % path)
def test_disk_usage(self): def test_disk_usage(self):
self.assert_stdout('disk_usage.py') self.assert_stdout('disk_usage.py')

View File

@ -11,17 +11,22 @@ import time
import psutil import psutil
from psutil import MACOS from psutil import MACOS
from psutil import POSIX
from psutil.tests import HAS_BATTERY from psutil.tests import HAS_BATTERY
from psutil.tests import TOLERANCE_DISK_USAGE
from psutil.tests import TOLERANCE_SYS_MEM
from psutil.tests import PsutilTestCase from psutil.tests import PsutilTestCase
from psutil.tests import retry_on_failure from psutil.tests import retry_on_failure
from psutil.tests import sh from psutil.tests import sh
from psutil.tests import spawn_testproc from psutil.tests import spawn_testproc
from psutil.tests import terminate from psutil.tests import terminate
from psutil.tests import TOLERANCE_DISK_USAGE
from psutil.tests import TOLERANCE_SYS_MEM
from psutil.tests import unittest from psutil.tests import unittest
if POSIX:
from psutil._psutil_posix import getpagesize
def sysctl(cmdline): def sysctl(cmdline):
"""Expects a sysctl command with an argument and parse the result """Expects a sysctl command with an argument and parse the result
returning only the value of interest. returning only the value of interest.
@ -36,8 +41,6 @@ def sysctl(cmdline):
def vm_stat(field): def vm_stat(field):
"""Wrapper around 'vm_stat' cmdline utility.""" """Wrapper around 'vm_stat' cmdline utility."""
from psutil._psutil_posix import getpagesize
out = sh('vm_stat') out = sh('vm_stat')
for line in out.split('\n'): for line in out.split('\n'):
if field in line: if field in line:
@ -137,7 +140,7 @@ class TestSystemAPIs(PsutilTestCase):
num = sysctl("sysctl hw.logicalcpu") num = sysctl("sysctl hw.logicalcpu")
self.assertEqual(num, psutil.cpu_count(logical=True)) self.assertEqual(num, psutil.cpu_count(logical=True))
def test_cpu_count_physical(self): def test_cpu_count_cores(self):
num = sysctl("sysctl hw.physicalcpu") num = sysctl("sysctl hw.physicalcpu")
self.assertEqual(num, psutil.cpu_count(logical=False)) self.assertEqual(num, psutil.cpu_count(logical=False))

View File

@ -23,18 +23,19 @@ from psutil import OPENBSD
from psutil import POSIX from psutil import POSIX
from psutil import SUNOS from psutil import SUNOS
from psutil.tests import CI_TESTING from psutil.tests import CI_TESTING
from psutil.tests import spawn_testproc
from psutil.tests import HAS_NET_IO_COUNTERS from psutil.tests import HAS_NET_IO_COUNTERS
from psutil.tests import mock
from psutil.tests import PsutilTestCase
from psutil.tests import PYTHON_EXE from psutil.tests import PYTHON_EXE
from psutil.tests import PsutilTestCase
from psutil.tests import mock
from psutil.tests import retry_on_failure from psutil.tests import retry_on_failure
from psutil.tests import sh from psutil.tests import sh
from psutil.tests import skip_on_access_denied from psutil.tests import skip_on_access_denied
from psutil.tests import spawn_testproc
from psutil.tests import terminate from psutil.tests import terminate
from psutil.tests import unittest from psutil.tests import unittest
from psutil.tests import which from psutil.tests import which
if POSIX: if POSIX:
import mmap import mmap
import resource import resource

View File

@ -21,7 +21,6 @@ import time
import types import types
import psutil import psutil
from psutil import AIX from psutil import AIX
from psutil import BSD from psutil import BSD
from psutil import LINUX from psutil import LINUX
@ -33,15 +32,12 @@ from psutil import POSIX
from psutil import SUNOS from psutil import SUNOS
from psutil import WINDOWS from psutil import WINDOWS
from psutil._common import open_text from psutil._common import open_text
from psutil._compat import PY3
from psutil._compat import FileNotFoundError from psutil._compat import FileNotFoundError
from psutil._compat import long from psutil._compat import long
from psutil._compat import PY3
from psutil._compat import super from psutil._compat import super
from psutil.tests import APPVEYOR from psutil.tests import APPVEYOR
from psutil.tests import call_until
from psutil.tests import CI_TESTING from psutil.tests import CI_TESTING
from psutil.tests import copyload_shared_lib
from psutil.tests import create_exe
from psutil.tests import GITHUB_ACTIONS from psutil.tests import GITHUB_ACTIONS
from psutil.tests import GLOBAL_TIMEOUT from psutil.tests import GLOBAL_TIMEOUT
from psutil.tests import HAS_CPU_AFFINITY from psutil.tests import HAS_CPU_AFFINITY
@ -52,17 +48,20 @@ from psutil.tests import HAS_PROC_CPU_NUM
from psutil.tests import HAS_PROC_IO_COUNTERS from psutil.tests import HAS_PROC_IO_COUNTERS
from psutil.tests import HAS_RLIMIT from psutil.tests import HAS_RLIMIT
from psutil.tests import HAS_THREADS from psutil.tests import HAS_THREADS
from psutil.tests import mock
from psutil.tests import process_namespace
from psutil.tests import PsutilTestCase
from psutil.tests import PYPY from psutil.tests import PYPY
from psutil.tests import PYTHON_EXE from psutil.tests import PYTHON_EXE
from psutil.tests import PsutilTestCase
from psutil.tests import ThreadTask
from psutil.tests import call_until
from psutil.tests import copyload_shared_lib
from psutil.tests import create_exe
from psutil.tests import mock
from psutil.tests import process_namespace
from psutil.tests import reap_children from psutil.tests import reap_children
from psutil.tests import retry_on_failure from psutil.tests import retry_on_failure
from psutil.tests import sh from psutil.tests import sh
from psutil.tests import skip_on_access_denied from psutil.tests import skip_on_access_denied
from psutil.tests import skip_on_not_implemented from psutil.tests import skip_on_not_implemented
from psutil.tests import ThreadTask
from psutil.tests import unittest from psutil.tests import unittest
from psutil.tests import wait_for_pid from psutil.tests import wait_for_pid
@ -718,6 +717,12 @@ class TestProcess(PsutilTestCase):
if NETBSD or OPENBSD or AIX: if NETBSD or OPENBSD or AIX:
self.assertEqual(p.cmdline()[0], PYTHON_EXE) self.assertEqual(p.cmdline()[0], PYTHON_EXE)
else: else:
if MACOS and CI_TESTING:
pyexe = p.cmdline()[0]
if pyexe != PYTHON_EXE:
self.assertEqual(' '.join(p.cmdline()[1:]),
' '.join(cmdline[1:]))
return
self.assertEqual(' '.join(p.cmdline()), ' '.join(cmdline)) self.assertEqual(' '.join(p.cmdline()), ' '.join(cmdline))
@unittest.skipIf(PYPY, "broken on PYPY") @unittest.skipIf(PYPY, "broken on PYPY")
@ -1326,6 +1331,20 @@ class TestProcess(PsutilTestCase):
self.assertEqual(p.status(), psutil.STATUS_ZOMBIE) self.assertEqual(p.status(), psutil.STATUS_ZOMBIE)
assert m.called assert m.called
def test_reused_pid(self):
# Emulate a case where PID has been reused by another process.
subp = self.spawn_testproc()
p = psutil.Process(subp.pid)
p._ident = (p.pid, p.create_time() + 100)
assert not p.is_running()
assert p != psutil.Process(subp.pid)
msg = "process no longer exists and its PID has been reused"
self.assertRaisesRegex(psutil.NoSuchProcess, msg, p.suspend)
self.assertRaisesRegex(psutil.NoSuchProcess, msg, p.resume)
self.assertRaisesRegex(psutil.NoSuchProcess, msg, p.terminate)
self.assertRaisesRegex(psutil.NoSuchProcess, msg, p.kill)
self.assertRaisesRegex(psutil.NoSuchProcess, msg, p.children)
def test_pid_0(self): def test_pid_0(self):
# Process(0) is supposed to work on all platforms except Linux # Process(0) is supposed to work on all platforms except Linux
if 0 not in psutil.pids(): if 0 not in psutil.pids():
@ -1369,7 +1388,6 @@ class TestProcess(PsutilTestCase):
def test_environ(self): def test_environ(self):
def clean_dict(d): def clean_dict(d):
# Most of these are problematic on Travis. # Most of these are problematic on Travis.
d.pop("PSUTIL_TESTING", None)
d.pop("PLAT", None) d.pop("PLAT", None)
d.pop("HOME", None) d.pop("HOME", None)
if MACOS: if MACOS:
@ -1395,11 +1413,13 @@ class TestProcess(PsutilTestCase):
code = textwrap.dedent(""" code = textwrap.dedent("""
#include <unistd.h> #include <unistd.h>
#include <fcntl.h> #include <fcntl.h>
char * const argv[] = {"cat", 0}; char * const argv[] = {"cat", 0};
char * const envp[] = {"A=1", "X", "C=3", 0}; char * const envp[] = {"A=1", "X", "C=3", 0};
int main(void) { int main(void) {
/* Close stderr on exec so parent can wait for the execve to // Close stderr on exec so parent can wait for the
* finish. */ // execve to finish.
if (fcntl(2, F_SETFD, FD_CLOEXEC) != 0) if (fcntl(2, F_SETFD, FD_CLOEXEC) != 0)
return 0; return 0;
return execve("/bin/cat", argv, envp); return execve("/bin/cat", argv, envp);

View File

@ -31,10 +31,9 @@ from psutil import WINDOWS
from psutil._compat import FileNotFoundError from psutil._compat import FileNotFoundError
from psutil._compat import long from psutil._compat import long
from psutil.tests import ASCII_FS from psutil.tests import ASCII_FS
from psutil.tests import check_net_address
from psutil.tests import CI_TESTING from psutil.tests import CI_TESTING
from psutil.tests import DEVNULL from psutil.tests import DEVNULL
from psutil.tests import enum from psutil.tests import GITHUB_ACTIONS
from psutil.tests import GLOBAL_TIMEOUT from psutil.tests import GLOBAL_TIMEOUT
from psutil.tests import HAS_BATTERY from psutil.tests import HAS_BATTERY
from psutil.tests import HAS_CPU_FREQ from psutil.tests import HAS_CPU_FREQ
@ -44,12 +43,13 @@ from psutil.tests import HAS_SENSORS_BATTERY
from psutil.tests import HAS_SENSORS_FANS from psutil.tests import HAS_SENSORS_FANS
from psutil.tests import HAS_SENSORS_TEMPERATURES from psutil.tests import HAS_SENSORS_TEMPERATURES
from psutil.tests import IS_64BIT from psutil.tests import IS_64BIT
from psutil.tests import mock
from psutil.tests import PsutilTestCase
from psutil.tests import PYPY from psutil.tests import PYPY
from psutil.tests import retry_on_failure
from psutil.tests import GITHUB_ACTIONS
from psutil.tests import UNICODE_SUFFIX from psutil.tests import UNICODE_SUFFIX
from psutil.tests import PsutilTestCase
from psutil.tests import check_net_address
from psutil.tests import enum
from psutil.tests import mock
from psutil.tests import retry_on_failure
from psutil.tests import unittest from psutil.tests import unittest
@ -316,16 +316,16 @@ class TestCpuAPIs(PsutilTestCase):
if "physical id" not in cpuinfo_data: if "physical id" not in cpuinfo_data:
raise unittest.SkipTest("cpuinfo doesn't include physical id") raise unittest.SkipTest("cpuinfo doesn't include physical id")
def test_cpu_count_physical(self): def test_cpu_count_cores(self):
logical = psutil.cpu_count() logical = psutil.cpu_count()
physical = psutil.cpu_count(logical=False) cores = psutil.cpu_count(logical=False)
if physical is None: if cores is None:
raise self.skipTest("physical cpu_count() is None") raise self.skipTest("cpu_count_cores() is None")
if WINDOWS and sys.getwindowsversion()[:2] <= (6, 1): # <= Vista if WINDOWS and sys.getwindowsversion()[:2] <= (6, 1): # <= Vista
self.assertIsNone(physical) self.assertIsNone(cores)
else: else:
self.assertGreaterEqual(physical, 1) self.assertGreaterEqual(cores, 1)
self.assertGreaterEqual(logical, physical) self.assertGreaterEqual(logical, cores)
def test_cpu_count_none(self): def test_cpu_count_none(self):
# https://github.com/giampaolo/psutil/issues/1085 # https://github.com/giampaolo/psutil/issues/1085
@ -334,7 +334,7 @@ class TestCpuAPIs(PsutilTestCase):
return_value=val) as m: return_value=val) as m:
self.assertIsNone(psutil.cpu_count()) self.assertIsNone(psutil.cpu_count())
assert m.called assert m.called
with mock.patch('psutil._psplatform.cpu_count_physical', with mock.patch('psutil._psplatform.cpu_count_cores',
return_value=val) as m: return_value=val) as m:
self.assertIsNone(psutil.cpu_count(logical=False)) self.assertIsNone(psutil.cpu_count(logical=False))
assert m.called assert m.called

View File

@ -17,25 +17,28 @@ import socket
import stat import stat
import subprocess import subprocess
import psutil
import psutil.tests
from psutil import FREEBSD from psutil import FREEBSD
from psutil import NETBSD from psutil import NETBSD
from psutil import POSIX from psutil import POSIX
from psutil._common import open_binary from psutil._common import open_binary
from psutil._common import open_text from psutil._common import open_text
from psutil._common import supports_ipv6 from psutil._common import supports_ipv6
from psutil.tests import CI_TESTING
from psutil.tests import HAS_CONNECTIONS_UNIX
from psutil.tests import PYTHON_EXE
from psutil.tests import PsutilTestCase
from psutil.tests import TestMemoryLeak
from psutil.tests import bind_socket from psutil.tests import bind_socket
from psutil.tests import bind_unix_socket from psutil.tests import bind_unix_socket
from psutil.tests import call_until from psutil.tests import call_until
from psutil.tests import chdir from psutil.tests import chdir
from psutil.tests import CI_TESTING
from psutil.tests import create_sockets from psutil.tests import create_sockets
from psutil.tests import get_free_port from psutil.tests import get_free_port
from psutil.tests import HAS_CONNECTIONS_UNIX
from psutil.tests import is_namedtuple from psutil.tests import is_namedtuple
from psutil.tests import mock from psutil.tests import mock
from psutil.tests import process_namespace from psutil.tests import process_namespace
from psutil.tests import PsutilTestCase
from psutil.tests import PYTHON_EXE
from psutil.tests import reap_children from psutil.tests import reap_children
from psutil.tests import retry from psutil.tests import retry
from psutil.tests import retry_on_failure from psutil.tests import retry_on_failure
@ -45,13 +48,11 @@ from psutil.tests import serialrun
from psutil.tests import system_namespace from psutil.tests import system_namespace
from psutil.tests import tcp_socketpair from psutil.tests import tcp_socketpair
from psutil.tests import terminate from psutil.tests import terminate
from psutil.tests import TestMemoryLeak
from psutil.tests import unittest from psutil.tests import unittest
from psutil.tests import unix_socketpair from psutil.tests import unix_socketpair
from psutil.tests import wait_for_file from psutil.tests import wait_for_file
from psutil.tests import wait_for_pid from psutil.tests import wait_for_pid
import psutil
import psutil.tests
# =================================================================== # ===================================================================
# --- Unit tests for test utilities. # --- Unit tests for test utilities.
@ -350,6 +351,7 @@ class TestNetUtils(PsutilTestCase):
@serialrun @serialrun
class TestMemLeakClass(TestMemoryLeak): class TestMemLeakClass(TestMemoryLeak):
@retry_on_failure()
def test_times(self): def test_times(self):
def fun(): def fun():
cnt['cnt'] += 1 cnt['cnt'] += 1

View File

@ -79,6 +79,7 @@ import traceback
import warnings import warnings
from contextlib import closing from contextlib import closing
import psutil
from psutil import BSD from psutil import BSD
from psutil import OPENBSD from psutil import OPENBSD
from psutil import POSIX from psutil import POSIX
@ -87,28 +88,27 @@ from psutil._compat import PY3
from psutil._compat import u from psutil._compat import u
from psutil.tests import APPVEYOR from psutil.tests import APPVEYOR
from psutil.tests import ASCII_FS from psutil.tests import ASCII_FS
from psutil.tests import bind_unix_socket
from psutil.tests import chdir
from psutil.tests import CI_TESTING from psutil.tests import CI_TESTING
from psutil.tests import copyload_shared_lib
from psutil.tests import create_exe
from psutil.tests import get_testfn
from psutil.tests import HAS_CONNECTIONS_UNIX from psutil.tests import HAS_CONNECTIONS_UNIX
from psutil.tests import HAS_ENVIRON from psutil.tests import HAS_ENVIRON
from psutil.tests import HAS_MEMORY_MAPS from psutil.tests import HAS_MEMORY_MAPS
from psutil.tests import INVALID_UNICODE_SUFFIX from psutil.tests import INVALID_UNICODE_SUFFIX
from psutil.tests import PsutilTestCase
from psutil.tests import PYPY from psutil.tests import PYPY
from psutil.tests import TESTFN_PREFIX
from psutil.tests import UNICODE_SUFFIX
from psutil.tests import PsutilTestCase
from psutil.tests import bind_unix_socket
from psutil.tests import chdir
from psutil.tests import copyload_shared_lib
from psutil.tests import create_exe
from psutil.tests import get_testfn
from psutil.tests import safe_mkdir from psutil.tests import safe_mkdir
from psutil.tests import safe_rmpath from psutil.tests import safe_rmpath
from psutil.tests import serialrun from psutil.tests import serialrun
from psutil.tests import skip_on_access_denied from psutil.tests import skip_on_access_denied
from psutil.tests import spawn_testproc from psutil.tests import spawn_testproc
from psutil.tests import terminate from psutil.tests import terminate
from psutil.tests import TESTFN_PREFIX
from psutil.tests import UNICODE_SUFFIX
from psutil.tests import unittest from psutil.tests import unittest
import psutil
if APPVEYOR: if APPVEYOR:

View File

@ -27,15 +27,15 @@ from psutil.tests import APPVEYOR
from psutil.tests import GITHUB_ACTIONS from psutil.tests import GITHUB_ACTIONS
from psutil.tests import HAS_BATTERY from psutil.tests import HAS_BATTERY
from psutil.tests import IS_64BIT from psutil.tests import IS_64BIT
from psutil.tests import mock
from psutil.tests import PsutilTestCase
from psutil.tests import PY3 from psutil.tests import PY3
from psutil.tests import PYPY from psutil.tests import PYPY
from psutil.tests import TOLERANCE_DISK_USAGE
from psutil.tests import PsutilTestCase
from psutil.tests import mock
from psutil.tests import retry_on_failure from psutil.tests import retry_on_failure
from psutil.tests import sh from psutil.tests import sh
from psutil.tests import spawn_testproc from psutil.tests import spawn_testproc
from psutil.tests import terminate from psutil.tests import terminate
from psutil.tests import TOLERANCE_DISK_USAGE
from psutil.tests import unittest from psutil.tests import unittest
@ -47,24 +47,13 @@ if WINDOWS and not PYPY:
import win32process import win32process
import wmi # requires "pip install wmi" / "make setup-dev-env" import wmi # requires "pip install wmi" / "make setup-dev-env"
if WINDOWS:
from psutil._pswindows import convert_oserror
cext = psutil._psplatform.cext cext = psutil._psplatform.cext
def wrap_exceptions(fun):
def wrapper(self, *args, **kwargs):
try:
return fun(self, *args, **kwargs)
except OSError as err:
from psutil._pswindows import ACCESS_DENIED_SET
if err.errno in ACCESS_DENIED_SET:
raise psutil.AccessDenied(None, None)
if err.errno == errno.ESRCH:
raise psutil.NoSuchProcess(None, None)
raise
return wrapper
@unittest.skipIf(not WINDOWS, "WINDOWS only") @unittest.skipIf(not WINDOWS, "WINDOWS only")
@unittest.skipIf(PYPY, "pywin32 not available on PYPY") @unittest.skipIf(PYPY, "pywin32 not available on PYPY")
# https://github.com/giampaolo/psutil/pull/1762#issuecomment-632892692 # https://github.com/giampaolo/psutil/pull/1762#issuecomment-632892692
@ -100,7 +89,7 @@ class TestCpuAPIs(WindowsTestCase):
proc = w.Win32_Processor()[0] proc = w.Win32_Processor()[0]
self.assertEqual(psutil.cpu_count(), proc.NumberOfLogicalProcessors) self.assertEqual(psutil.cpu_count(), proc.NumberOfLogicalProcessors)
def test_cpu_count_phys_vs_wmi(self): def test_cpu_count_cores_vs_wmi(self):
w = wmi.WMI() w = wmi.WMI()
proc = w.Win32_Processor()[0] proc = w.Win32_Processor()[0]
self.assertEqual(psutil.cpu_count(logical=False), proc.NumberOfCores) self.assertEqual(psutil.cpu_count(logical=False), proc.NumberOfCores)
@ -633,7 +622,6 @@ class TestDualProcessImplementation(PsutilTestCase):
assert fun.called assert fun.called
def test_cmdline(self): def test_cmdline(self):
from psutil._pswindows import convert_oserror
for pid in psutil.pids(): for pid in psutil.pids():
try: try:
a = cext.proc_cmdline(pid, use_peb=True) a = cext.proc_cmdline(pid, use_peb=True)
@ -725,7 +713,7 @@ class RemoteProcessTestCase(PsutilTestCase):
p = psutil.Process(self.proc32.pid) p = psutil.Process(self.proc32.pid)
e = p.environ() e = p.environ()
self.assertIn("THINK_OF_A_NUMBER", e) self.assertIn("THINK_OF_A_NUMBER", e)
self.assertEquals(e["THINK_OF_A_NUMBER"], str(os.getpid())) self.assertEqual(e["THINK_OF_A_NUMBER"], str(os.getpid()))
def test_environ_64(self): def test_environ_64(self):
p = psutil.Process(self.proc64.pid) p = psutil.Process(self.proc64.pid)

View File

@ -1,19 +0,0 @@
Copyright Jason R. Coombs
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to
deal in the Software without restriction, including without limitation the
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.

View File

@ -1,124 +0,0 @@
Metadata-Version: 2.1
Name: setuptools
Version: 60.0.3
Summary: Easily download, build, install, upgrade, and uninstall Python packages
Home-page: https://github.com/pypa/setuptools
Author: Python Packaging Authority
Author-email: distutils-sig@python.org
License: UNKNOWN
Project-URL: Documentation, https://setuptools.pypa.io/
Keywords: CPAN PyPI distutils eggs package management
Platform: UNKNOWN
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: System :: Archiving :: Packaging
Classifier: Topic :: System :: Systems Administration
Classifier: Topic :: Utilities
Requires-Python: >=3.7
License-File: LICENSE
Provides-Extra: certs
Provides-Extra: docs
Requires-Dist: sphinx ; extra == 'docs'
Requires-Dist: jaraco.packaging (>=8.2) ; extra == 'docs'
Requires-Dist: rst.linker (>=1.9) ; extra == 'docs'
Requires-Dist: jaraco.tidelift (>=1.4) ; extra == 'docs'
Requires-Dist: pygments-github-lexers (==0.0.5) ; extra == 'docs'
Requires-Dist: sphinx-inline-tabs ; extra == 'docs'
Requires-Dist: sphinxcontrib-towncrier ; extra == 'docs'
Requires-Dist: furo ; extra == 'docs'
Provides-Extra: ssl
Provides-Extra: testing
Requires-Dist: pytest (>=6) ; extra == 'testing'
Requires-Dist: pytest-checkdocs (>=2.4) ; extra == 'testing'
Requires-Dist: pytest-flake8 ; extra == 'testing'
Requires-Dist: pytest-cov ; extra == 'testing'
Requires-Dist: pytest-enabler (>=1.0.1) ; extra == 'testing'
Requires-Dist: mock ; extra == 'testing'
Requires-Dist: flake8-2020 ; extra == 'testing'
Requires-Dist: virtualenv (>=13.0.0) ; extra == 'testing'
Requires-Dist: pytest-virtualenv (>=1.2.7) ; extra == 'testing'
Requires-Dist: wheel ; extra == 'testing'
Requires-Dist: paver ; extra == 'testing'
Requires-Dist: pip (>=19.1) ; extra == 'testing'
Requires-Dist: jaraco.envs (>=2.2) ; extra == 'testing'
Requires-Dist: pytest-xdist ; extra == 'testing'
Requires-Dist: sphinx ; extra == 'testing'
Requires-Dist: jaraco.path (>=3.2.0) ; extra == 'testing'
Requires-Dist: pytest-black (>=0.3.7) ; (platform_python_implementation != "PyPy") and extra == 'testing'
Requires-Dist: pytest-mypy ; (platform_python_implementation != "PyPy") and extra == 'testing'
.. image:: https://raw.githubusercontent.com/pypa/setuptools/main/docs/images/banner-640x320.svg
:align: center
|
.. image:: https://img.shields.io/pypi/v/setuptools.svg
:target: `PyPI link`_
.. image:: https://img.shields.io/pypi/pyversions/setuptools.svg
:target: `PyPI link`_
.. _PyPI link: https://pypi.org/project/setuptools
.. image:: https://github.com/pypa/setuptools/workflows/tests/badge.svg
:target: https://github.com/pypa/setuptools/actions?query=workflow%3A%22tests%22
:alt: tests
.. image:: https://img.shields.io/badge/code%20style-black-000000.svg
:target: https://github.com/psf/black
:alt: Code style: Black
.. image:: https://img.shields.io/readthedocs/setuptools/latest.svg
:target: https://setuptools.pypa.io
.. image:: https://img.shields.io/badge/skeleton-2021-informational
:target: https://blog.jaraco.com/skeleton
.. image:: https://img.shields.io/codecov/c/github/pypa/setuptools/master.svg?logo=codecov&logoColor=white
:target: https://codecov.io/gh/pypa/setuptools
.. image:: https://tidelift.com/badges/github/pypa/setuptools?style=flat
:target: https://tidelift.com/subscription/pkg/pypi-setuptools?utm_source=pypi-setuptools&utm_medium=readme
See the `Installation Instructions
<https://packaging.python.org/installing/>`_ in the Python Packaging
User's Guide for instructions on installing, upgrading, and uninstalling
Setuptools.
Questions and comments should be directed to the `distutils-sig
mailing list <http://mail.python.org/pipermail/distutils-sig/>`_.
Bug reports and especially tested patches may be
submitted directly to the `bug tracker
<https://github.com/pypa/setuptools/issues>`_.
Code of Conduct
===============
Everyone interacting in the setuptools project's codebases, issue trackers,
chat rooms, and mailing lists is expected to follow the
`PSF Code of Conduct <https://github.com/pypa/.github/blob/main/CODE_OF_CONDUCT.md>`_.
For Enterprise
==============
Available as part of the Tidelift Subscription.
Setuptools and the maintainers of thousands of other packages are working with Tidelift to deliver one enterprise subscription that covers all of the open source you use.
`Learn more <https://tidelift.com/subscription/pkg/pypi-setuptools?utm_source=pypi-setuptools&utm_medium=referral&utm_campaign=github>`_.
Security Contact
================
To report a security vulnerability, please use the
`Tidelift security contact <https://tidelift.com/security>`_.
Tidelift will coordinate the fix and disclosure.

View File

@ -1,297 +0,0 @@
_distutils_hack/__init__.py,sha256=8AFtsXYDw0MMp6RE4osVd0Rdnaf38y90btaCDDRCoH0,4014
_distutils_hack/__pycache__/__init__.cpython-39.pyc,,
_distutils_hack/__pycache__/override.cpython-39.pyc,,
_distutils_hack/override.py,sha256=Eu_s-NF6VIZ4Cqd0tbbA5wtWky2IZPNd8et6GLt1mzo,44
distutils-precedence.pth,sha256=JjjOniUA5XKl4N5_rtZmHrVp0baW_LoHsN0iPaX10iQ,151
pkg_resources/__init__.py,sha256=uAnPq8FsTXHAEHFWK7UU9AhdNjE4o5Skfk8CyfbztO8,108573
pkg_resources/__pycache__/__init__.cpython-39.pyc,,
pkg_resources/_vendor/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
pkg_resources/_vendor/__pycache__/__init__.cpython-39.pyc,,
pkg_resources/_vendor/__pycache__/appdirs.cpython-39.pyc,,
pkg_resources/_vendor/__pycache__/pyparsing.cpython-39.pyc,,
pkg_resources/_vendor/appdirs.py,sha256=MievUEuv3l_mQISH5SF0shDk_BNhHHzYiAPrT3ITN4I,24701
pkg_resources/_vendor/packaging/__about__.py,sha256=IIRHpOsJlJSgkjq1UoeBoMTqhvNp3gN9FyMb5Kf8El4,661
pkg_resources/_vendor/packaging/__init__.py,sha256=b9Kk5MF7KxhhLgcDmiUWukN-LatWFxPdNug0joPhHSk,497
pkg_resources/_vendor/packaging/__pycache__/__about__.cpython-39.pyc,,
pkg_resources/_vendor/packaging/__pycache__/__init__.cpython-39.pyc,,
pkg_resources/_vendor/packaging/__pycache__/_manylinux.cpython-39.pyc,,
pkg_resources/_vendor/packaging/__pycache__/_musllinux.cpython-39.pyc,,
pkg_resources/_vendor/packaging/__pycache__/_structures.cpython-39.pyc,,
pkg_resources/_vendor/packaging/__pycache__/markers.cpython-39.pyc,,
pkg_resources/_vendor/packaging/__pycache__/requirements.cpython-39.pyc,,
pkg_resources/_vendor/packaging/__pycache__/specifiers.cpython-39.pyc,,
pkg_resources/_vendor/packaging/__pycache__/tags.cpython-39.pyc,,
pkg_resources/_vendor/packaging/__pycache__/utils.cpython-39.pyc,,
pkg_resources/_vendor/packaging/__pycache__/version.cpython-39.pyc,,
pkg_resources/_vendor/packaging/_manylinux.py,sha256=XcbiXB-qcjv3bcohp6N98TMpOP4_j3m-iOA8ptK2GWY,11488
pkg_resources/_vendor/packaging/_musllinux.py,sha256=z5yeG1ygOPx4uUyLdqj-p8Dk5UBb5H_b0NIjW9yo8oA,4378
pkg_resources/_vendor/packaging/_structures.py,sha256=TMiAgFbdUOPmIfDIfiHc3KFhSJ8kMjof2QS5I-2NyQ8,1629
pkg_resources/_vendor/packaging/markers.py,sha256=gFSKoBTb0sKDw1v_apJy15lPr0v2mEvuEkfooTtcWx4,8496
pkg_resources/_vendor/packaging/requirements.py,sha256=uJ4cjwm3_nrfHJLCcGU9mT5aw8SXfw8v1aBUD7OFuVs,4706
pkg_resources/_vendor/packaging/specifiers.py,sha256=MZ-fYcNL3u7pNrt-6g2EQO7AbRXkjc-SPEYwXMQbLmc,30964
pkg_resources/_vendor/packaging/tags.py,sha256=vGybAUQYlPKMcukzX_2e65fmafnFFuMbD25naYTEwtc,15710
pkg_resources/_vendor/packaging/utils.py,sha256=dJjeat3BS-TYn1RrUFVwufUMasbtzLfYRoy_HXENeFQ,4200
pkg_resources/_vendor/packaging/version.py,sha256=_fLRNrFrxYcHVfyo8vk9j8s6JM8N_xsSxVFr6RJyco8,14665
pkg_resources/_vendor/pyparsing.py,sha256=tmrp-lu-qO1i75ZzIN5A12nKRRD1Cm4Vpk-5LR9rims,232055
pkg_resources/extern/__init__.py,sha256=3PixaT9Tzzd4NoyV6CVhGd7S_9Z-U5yvMWAftZKvC6k,2362
pkg_resources/extern/__pycache__/__init__.cpython-39.pyc,,
pkg_resources/tests/data/my-test-package-source/__pycache__/setup.cpython-39.pyc,,
pkg_resources/tests/data/my-test-package-source/setup.py,sha256=Mrezl3nqxkYkjCYpIxmjhhg4AR8hgi4QZdEYmk-I7R8,104
setuptools-60.0.3.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
setuptools-60.0.3.dist-info/LICENSE,sha256=2z8CRrH5J48VhFuZ_sR4uLUG63ZIeZNyL4xuJUKF-vg,1050
setuptools-60.0.3.dist-info/METADATA,sha256=mGuu7DhncmGsqzGoOzN0s1FZ7ydotAT7_hVg2x2veRQ,4963
setuptools-60.0.3.dist-info/RECORD,,
setuptools-60.0.3.dist-info/WHEEL,sha256=ewwEueio1C2XeHTvT17n8dZUJgOvyCWCt0WVNLClP9o,92
setuptools-60.0.3.dist-info/entry_points.txt,sha256=wpnhLrbtyk4hZ1qCCw48cCSxoQPzULMhIuaFqsB7GxQ,2636
setuptools-60.0.3.dist-info/top_level.txt,sha256=d9yL39v_W7qmKDDSH6sT4bE0j_Ls1M3P161OGgdsm4g,41
setuptools/__init__.py,sha256=l7ULo8jGk-4-8jbacmJ58cYpSRX4swS1ccbJaJVAGdM,7448
setuptools/__pycache__/__init__.cpython-39.pyc,,
setuptools/__pycache__/_deprecation_warning.cpython-39.pyc,,
setuptools/__pycache__/_imp.cpython-39.pyc,,
setuptools/__pycache__/archive_util.cpython-39.pyc,,
setuptools/__pycache__/build_meta.cpython-39.pyc,,
setuptools/__pycache__/config.cpython-39.pyc,,
setuptools/__pycache__/dep_util.cpython-39.pyc,,
setuptools/__pycache__/depends.cpython-39.pyc,,
setuptools/__pycache__/dist.cpython-39.pyc,,
setuptools/__pycache__/errors.cpython-39.pyc,,
setuptools/__pycache__/extension.cpython-39.pyc,,
setuptools/__pycache__/glob.cpython-39.pyc,,
setuptools/__pycache__/installer.cpython-39.pyc,,
setuptools/__pycache__/launch.cpython-39.pyc,,
setuptools/__pycache__/monkey.cpython-39.pyc,,
setuptools/__pycache__/msvc.cpython-39.pyc,,
setuptools/__pycache__/namespaces.cpython-39.pyc,,
setuptools/__pycache__/package_index.cpython-39.pyc,,
setuptools/__pycache__/py34compat.cpython-39.pyc,,
setuptools/__pycache__/sandbox.cpython-39.pyc,,
setuptools/__pycache__/unicode_utils.cpython-39.pyc,,
setuptools/__pycache__/version.cpython-39.pyc,,
setuptools/__pycache__/wheel.cpython-39.pyc,,
setuptools/__pycache__/windows_support.cpython-39.pyc,,
setuptools/_deprecation_warning.py,sha256=jU9-dtfv6cKmtQJOXN8nP1mm7gONw5kKEtiPtbwnZyI,218
setuptools/_distutils/__init__.py,sha256=3YtkfadGoU57VMEQFk2TNyMZVud1kDkakWQLhWg2Fm8,536
setuptools/_distutils/__pycache__/__init__.cpython-39.pyc,,
setuptools/_distutils/__pycache__/_msvccompiler.cpython-39.pyc,,
setuptools/_distutils/__pycache__/archive_util.cpython-39.pyc,,
setuptools/_distutils/__pycache__/bcppcompiler.cpython-39.pyc,,
setuptools/_distutils/__pycache__/ccompiler.cpython-39.pyc,,
setuptools/_distutils/__pycache__/cmd.cpython-39.pyc,,
setuptools/_distutils/__pycache__/config.cpython-39.pyc,,
setuptools/_distutils/__pycache__/core.cpython-39.pyc,,
setuptools/_distutils/__pycache__/cygwinccompiler.cpython-39.pyc,,
setuptools/_distutils/__pycache__/debug.cpython-39.pyc,,
setuptools/_distutils/__pycache__/dep_util.cpython-39.pyc,,
setuptools/_distutils/__pycache__/dir_util.cpython-39.pyc,,
setuptools/_distutils/__pycache__/dist.cpython-39.pyc,,
setuptools/_distutils/__pycache__/errors.cpython-39.pyc,,
setuptools/_distutils/__pycache__/extension.cpython-39.pyc,,
setuptools/_distutils/__pycache__/fancy_getopt.cpython-39.pyc,,
setuptools/_distutils/__pycache__/file_util.cpython-39.pyc,,
setuptools/_distutils/__pycache__/filelist.cpython-39.pyc,,
setuptools/_distutils/__pycache__/log.cpython-39.pyc,,
setuptools/_distutils/__pycache__/msvc9compiler.cpython-39.pyc,,
setuptools/_distutils/__pycache__/msvccompiler.cpython-39.pyc,,
setuptools/_distutils/__pycache__/py35compat.cpython-39.pyc,,
setuptools/_distutils/__pycache__/py38compat.cpython-39.pyc,,
setuptools/_distutils/__pycache__/spawn.cpython-39.pyc,,
setuptools/_distutils/__pycache__/sysconfig.cpython-39.pyc,,
setuptools/_distutils/__pycache__/text_file.cpython-39.pyc,,
setuptools/_distutils/__pycache__/unixccompiler.cpython-39.pyc,,
setuptools/_distutils/__pycache__/util.cpython-39.pyc,,
setuptools/_distutils/__pycache__/version.cpython-39.pyc,,
setuptools/_distutils/__pycache__/versionpredicate.cpython-39.pyc,,
setuptools/_distutils/_msvccompiler.py,sha256=jR0JM5A1JMnZ6xMDicQzhXWgXTVXs1lWAeUexC1z198,20813
setuptools/_distutils/archive_util.py,sha256=qW-uiGwYexTvK5e-iSel_31Dshx-CqTanNPK6snwf98,8572
setuptools/_distutils/bcppcompiler.py,sha256=OJDVpCUmX6H8v_7lV1zifV1fcx92Cr2dhiUh6989UJI,14894
setuptools/_distutils/ccompiler.py,sha256=YbernlpGZZqKnfzZSfJ814fINca8cicZiUlBjyUPyaM,47644
setuptools/_distutils/cmd.py,sha256=eco6LAGUtobLuPafuhmgKgkwRRL_WY8KJ4YeDCHpcls,18079
setuptools/_distutils/command/__init__.py,sha256=2TA-rlNDlzeI-csbWHXFjGD8uOYqALMfyWOhT49nC6g,799
setuptools/_distutils/command/__pycache__/__init__.cpython-39.pyc,,
setuptools/_distutils/command/__pycache__/bdist.cpython-39.pyc,,
setuptools/_distutils/command/__pycache__/bdist_dumb.cpython-39.pyc,,
setuptools/_distutils/command/__pycache__/bdist_msi.cpython-39.pyc,,
setuptools/_distutils/command/__pycache__/bdist_rpm.cpython-39.pyc,,
setuptools/_distutils/command/__pycache__/bdist_wininst.cpython-39.pyc,,
setuptools/_distutils/command/__pycache__/build.cpython-39.pyc,,
setuptools/_distutils/command/__pycache__/build_clib.cpython-39.pyc,,
setuptools/_distutils/command/__pycache__/build_ext.cpython-39.pyc,,
setuptools/_distutils/command/__pycache__/build_py.cpython-39.pyc,,
setuptools/_distutils/command/__pycache__/build_scripts.cpython-39.pyc,,
setuptools/_distutils/command/__pycache__/check.cpython-39.pyc,,
setuptools/_distutils/command/__pycache__/clean.cpython-39.pyc,,
setuptools/_distutils/command/__pycache__/config.cpython-39.pyc,,
setuptools/_distutils/command/__pycache__/install.cpython-39.pyc,,
setuptools/_distutils/command/__pycache__/install_data.cpython-39.pyc,,
setuptools/_distutils/command/__pycache__/install_egg_info.cpython-39.pyc,,
setuptools/_distutils/command/__pycache__/install_headers.cpython-39.pyc,,
setuptools/_distutils/command/__pycache__/install_lib.cpython-39.pyc,,
setuptools/_distutils/command/__pycache__/install_scripts.cpython-39.pyc,,
setuptools/_distutils/command/__pycache__/py37compat.cpython-39.pyc,,
setuptools/_distutils/command/__pycache__/register.cpython-39.pyc,,
setuptools/_distutils/command/__pycache__/sdist.cpython-39.pyc,,
setuptools/_distutils/command/__pycache__/upload.cpython-39.pyc,,
setuptools/_distutils/command/bdist.py,sha256=2z4eudRl_n7m3lG9leL0IYqes4bsm8c0fxfZuiafjMg,5562
setuptools/_distutils/command/bdist_dumb.py,sha256=BTur9jcIppyP7Piavjfsk7YjElqvxeYO2npUyPPOekc,4913
setuptools/_distutils/command/bdist_msi.py,sha256=EVFQYN_X-ExeeP8gmdV9JcINsuUGsLJUz9afMU0Rt8c,35579
setuptools/_distutils/command/bdist_rpm.py,sha256=gjOw22GhDSbcq0bdq25cTb-n6HWWm0bShLQad_mkJ4k,21537
setuptools/_distutils/command/bdist_wininst.py,sha256=iGlaI-VfElHOneeczKHWnSN5a10-7IMcJaXuR1mdS3c,16030
setuptools/_distutils/command/build.py,sha256=1AF-dxN_NlOEyoydBz19AwpeWYPSYCZvOLJSN_PdatY,5773
setuptools/_distutils/command/build_clib.py,sha256=bgVTHh28eLQA2Gkw68amApd_j7qQBX4MTI-zTvAK_J4,8022
setuptools/_distutils/command/build_ext.py,sha256=KgxpopuD6sqep0LsumMH15joWih0VdbnXpYm-ETNjoE,31612
setuptools/_distutils/command/build_py.py,sha256=hXesMrH_epNj6K8SUtJdipgEis3EdICKeZ8VWe_ndck,16495
setuptools/_distutils/command/build_scripts.py,sha256=urdn6wPxPMW5dLqpqFkZ8dqaFG1tf9TiAao6U9LCoEI,5963
setuptools/_distutils/command/check.py,sha256=5qDtI75ccZg3sAItQWeaIu8y3FR314O4rr9Smz4HsEo,5637
setuptools/_distutils/command/clean.py,sha256=2TCt47ru4hZZM0RfVfUYj5bbpicpGLP4Qhw5jBtvp9k,2776
setuptools/_distutils/command/config.py,sha256=2aTjww3PwjMB8-ZibCe4P7B-qG1hM1gn_rJXYyxRz6c,13117
setuptools/_distutils/command/install.py,sha256=wpaYPr38D55ZL9JCLqHKuTIUdhwX9K3LyQ_4T2E2n8w,29704
setuptools/_distutils/command/install_data.py,sha256=YhGOAwh3gJPqF7em5XA0rmpR42z1bLh80ooElzDyUvk,2822
setuptools/_distutils/command/install_egg_info.py,sha256=WijZ7cHMAkNMMCwrZ--KoqV9M2RtLouU4-qSbiCwv70,2753
setuptools/_distutils/command/install_headers.py,sha256=XQ6idkbIDfr1ljXCOznuVUMvOFpHBn6cK0Wz9gIM2b4,1298
setuptools/_distutils/command/install_lib.py,sha256=9AofR-MO9lAtjwwuukCptepOaJEKMZW2VHiyR5hU7HA,8397
setuptools/_distutils/command/install_scripts.py,sha256=_CLUeQwGJRcY2kik7azPMn5IdtDCrjWdUvZ1khlG6ck,2017
setuptools/_distutils/command/py37compat.py,sha256=qzRhhvTihqx_PZZt2ZYECxh1X3Oj255VqatzelYFAKw,671
setuptools/_distutils/command/register.py,sha256=2jaq9968rt2puRVDBx1HbNiXv27uOk8idE_4lPf_3VM,11712
setuptools/_distutils/command/sdist.py,sha256=qotJjAOzyhJjq2-oDImjNFrOtaSneEFDJTB-sEk1wnU,19005
setuptools/_distutils/command/upload.py,sha256=BLO1w7eSAqsCjCLXtf_CRVSjwF1WmyOByGVGNdcQ8oY,7597
setuptools/_distutils/config.py,sha256=dtHgblx9JhfyrKx1-J7Jlxw_f7s8ZbPFQii2UWMTZpY,4827
setuptools/_distutils/core.py,sha256=0v7Emh9y0AW9o4AEjfVMhDxKzTFWFxUQn46spFSL56g,9282
setuptools/_distutils/cygwinccompiler.py,sha256=oZh-mbF-3ClAsZBplFrxt4ck9iXXNIK3ipFNNfdnGIk,17357
setuptools/_distutils/debug.py,sha256=N6MrTAqK6l9SVk6tWweR108PM8Ol7qNlfyV-nHcLhsY,139
setuptools/_distutils/dep_util.py,sha256=GuR9Iw_jzZRkyemJ5HX8rB_wRGxkIBcBm1qh54r7zhk,3491
setuptools/_distutils/dir_util.py,sha256=UwhBOUTcV65GTwce4SPuTXR8Z8q3LYEcmttqcGb0bYo,7778
setuptools/_distutils/dist.py,sha256=Biuf6ca8uiFfMScRFsYUKtb5neMPtxKxRtXn50_1f3U,50421
setuptools/_distutils/errors.py,sha256=Yr6tKZGdzBoNi53vBtiq0UJ__X05CmxSdQJqOWaw6SY,3577
setuptools/_distutils/extension.py,sha256=bTb3Q0CoevGKYv5dX1ls--Ln8tlB0-UEOsi9BwzlZ-s,10515
setuptools/_distutils/fancy_getopt.py,sha256=OPxp2CxHi1Yp_d1D8JxW4Ueq9fC71tegQFaafh58GGU,17784
setuptools/_distutils/file_util.py,sha256=0hUqfItN_x2DVihR0MHdA4KCMVCOO8VoByaFp_a6MDg,8148
setuptools/_distutils/filelist.py,sha256=Z9f5hvepZnpniZ2IFmCnWIjdviWozs8sbARBhWajwoM,13407
setuptools/_distutils/log.py,sha256=hWBmdUC2K927QcVv3REMW3HMPclxccPQngxLSuUXQl0,1969
setuptools/_distutils/msvc9compiler.py,sha256=23cxMWGk2i8iFEvr5xdAXThlGM4LDuhQcM0175psc7A,30483
setuptools/_distutils/msvccompiler.py,sha256=qruALeGRq8-CjtjE2tLQ8W26QnchcYedWzFme8AxZ4Q,23540
setuptools/_distutils/py35compat.py,sha256=-sk1vBIsOgH-AobjIYbK_OEjdJF_54Ul_D1EiE9XM_c,455
setuptools/_distutils/py38compat.py,sha256=II7ddBxOijC7uNN4z_46HYUjwYTJYMNiLJoGTormZm0,212
setuptools/_distutils/spawn.py,sha256=4uE9k3VZWijxy7E_Rlcmh1MoamaPJ8rajdNBagKxjgU,3498
setuptools/_distutils/sysconfig.py,sha256=k3fzINx3-qjge0udI6fC1UQSDPYpMGrxeSuV9cY4rmU,22151
setuptools/_distutils/text_file.py,sha256=PsuAJeWdKJoLSV_6N6IpB5-0Pa84KzLUucJMFRazw3I,12483
setuptools/_distutils/unixccompiler.py,sha256=u2Sfs6LRmqQux4nZW08GwDtoFMded6wYnkiaO2TvKC4,14538
setuptools/_distutils/util.py,sha256=0v7B6nIsAXP11A7xqS6FC6lFAdaIqzxz_C-at4aMcgs,20655
setuptools/_distutils/version.py,sha256=syRvPxuMQxnftpuIKeRE-2ELQ_ZMCwMJ-o8ie-lxdZo,13015
setuptools/_distutils/versionpredicate.py,sha256=vx4ND3BtMgxFR9iZ4_t3WFa-NdIKxO8vtOd0twBppxc,5277
setuptools/_imp.py,sha256=HmF91IbitRfsD5z-g4_wmcuH-RahyIONbPgiCOFgtzA,2392
setuptools/_vendor/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
setuptools/_vendor/__pycache__/__init__.cpython-39.pyc,,
setuptools/_vendor/__pycache__/ordered_set.cpython-39.pyc,,
setuptools/_vendor/__pycache__/pyparsing.cpython-39.pyc,,
setuptools/_vendor/more_itertools/__init__.py,sha256=C7sXffHTXM3P-iaLPPfqfmDoxOflQMJLcM7ed9p3jak,82
setuptools/_vendor/more_itertools/__pycache__/__init__.cpython-39.pyc,,
setuptools/_vendor/more_itertools/__pycache__/more.cpython-39.pyc,,
setuptools/_vendor/more_itertools/__pycache__/recipes.cpython-39.pyc,,
setuptools/_vendor/more_itertools/more.py,sha256=DlZa8v6JihVwfQ5zHidOA-xDE0orcQIUyxVnCaUoDKE,117968
setuptools/_vendor/more_itertools/recipes.py,sha256=UkNkrsZyqiwgLHANBTmvMhCvaNSvSNYhyOpz_Jc55DY,16256
setuptools/_vendor/ordered_set.py,sha256=dbaCcs27dyN9gnMWGF5nA_BrVn6Q-NrjKYJpV9_fgBs,15130
setuptools/_vendor/packaging/__about__.py,sha256=IIRHpOsJlJSgkjq1UoeBoMTqhvNp3gN9FyMb5Kf8El4,661
setuptools/_vendor/packaging/__init__.py,sha256=b9Kk5MF7KxhhLgcDmiUWukN-LatWFxPdNug0joPhHSk,497
setuptools/_vendor/packaging/__pycache__/__about__.cpython-39.pyc,,
setuptools/_vendor/packaging/__pycache__/__init__.cpython-39.pyc,,
setuptools/_vendor/packaging/__pycache__/_manylinux.cpython-39.pyc,,
setuptools/_vendor/packaging/__pycache__/_musllinux.cpython-39.pyc,,
setuptools/_vendor/packaging/__pycache__/_structures.cpython-39.pyc,,
setuptools/_vendor/packaging/__pycache__/markers.cpython-39.pyc,,
setuptools/_vendor/packaging/__pycache__/requirements.cpython-39.pyc,,
setuptools/_vendor/packaging/__pycache__/specifiers.cpython-39.pyc,,
setuptools/_vendor/packaging/__pycache__/tags.cpython-39.pyc,,
setuptools/_vendor/packaging/__pycache__/utils.cpython-39.pyc,,
setuptools/_vendor/packaging/__pycache__/version.cpython-39.pyc,,
setuptools/_vendor/packaging/_manylinux.py,sha256=XcbiXB-qcjv3bcohp6N98TMpOP4_j3m-iOA8ptK2GWY,11488
setuptools/_vendor/packaging/_musllinux.py,sha256=z5yeG1ygOPx4uUyLdqj-p8Dk5UBb5H_b0NIjW9yo8oA,4378
setuptools/_vendor/packaging/_structures.py,sha256=TMiAgFbdUOPmIfDIfiHc3KFhSJ8kMjof2QS5I-2NyQ8,1629
setuptools/_vendor/packaging/markers.py,sha256=lihRgqpZjLM-JW-vxlLPqU3kmVe79g9vypy1kxmTRuQ,8493
setuptools/_vendor/packaging/requirements.py,sha256=Opd0FjqgdEiWkzBLyo1oLU0Dj01uIFwTAnAJQrr6j2A,4700
setuptools/_vendor/packaging/specifiers.py,sha256=MZ-fYcNL3u7pNrt-6g2EQO7AbRXkjc-SPEYwXMQbLmc,30964
setuptools/_vendor/packaging/tags.py,sha256=vGybAUQYlPKMcukzX_2e65fmafnFFuMbD25naYTEwtc,15710
setuptools/_vendor/packaging/utils.py,sha256=dJjeat3BS-TYn1RrUFVwufUMasbtzLfYRoy_HXENeFQ,4200
setuptools/_vendor/packaging/version.py,sha256=_fLRNrFrxYcHVfyo8vk9j8s6JM8N_xsSxVFr6RJyco8,14665
setuptools/_vendor/pyparsing.py,sha256=tmrp-lu-qO1i75ZzIN5A12nKRRD1Cm4Vpk-5LR9rims,232055
setuptools/archive_util.py,sha256=maJDbozRbDeSPw53VT0cb_IS3W0Ap73lJR8tX8RZDx0,7077
setuptools/build_meta.py,sha256=hCU742vjgXHY6oKPYttBkie-n4DVNAJrUOgn0O_V3nc,10536
setuptools/cli-32.exe,sha256=dfEuovMNnA2HLa3jRfMPVi5tk4R7alCbpTvuxtCyw0Y,65536
setuptools/cli-64.exe,sha256=KLABu5pyrnokJCv6skjXZ6GsXeyYHGcqOUT3oHI3Xpo,74752
setuptools/cli-arm64.exe,sha256=o9amxowudZ98NvNWh_a2DRY8LhoIRqTAekxABqltiMc,137216
setuptools/cli.exe,sha256=dfEuovMNnA2HLa3jRfMPVi5tk4R7alCbpTvuxtCyw0Y,65536
setuptools/command/__init__.py,sha256=e-8TJOikUe3St0fw2b2p9u5EDdSxl5zHUBJJKifbcQ8,217
setuptools/command/__pycache__/__init__.cpython-39.pyc,,
setuptools/command/__pycache__/alias.cpython-39.pyc,,
setuptools/command/__pycache__/bdist_egg.cpython-39.pyc,,
setuptools/command/__pycache__/bdist_rpm.cpython-39.pyc,,
setuptools/command/__pycache__/build_clib.cpython-39.pyc,,
setuptools/command/__pycache__/build_ext.cpython-39.pyc,,
setuptools/command/__pycache__/build_py.cpython-39.pyc,,
setuptools/command/__pycache__/develop.cpython-39.pyc,,
setuptools/command/__pycache__/dist_info.cpython-39.pyc,,
setuptools/command/__pycache__/easy_install.cpython-39.pyc,,
setuptools/command/__pycache__/egg_info.cpython-39.pyc,,
setuptools/command/__pycache__/install.cpython-39.pyc,,
setuptools/command/__pycache__/install_egg_info.cpython-39.pyc,,
setuptools/command/__pycache__/install_lib.cpython-39.pyc,,
setuptools/command/__pycache__/install_scripts.cpython-39.pyc,,
setuptools/command/__pycache__/py36compat.cpython-39.pyc,,
setuptools/command/__pycache__/register.cpython-39.pyc,,
setuptools/command/__pycache__/rotate.cpython-39.pyc,,
setuptools/command/__pycache__/saveopts.cpython-39.pyc,,
setuptools/command/__pycache__/sdist.cpython-39.pyc,,
setuptools/command/__pycache__/setopt.cpython-39.pyc,,
setuptools/command/__pycache__/test.cpython-39.pyc,,
setuptools/command/__pycache__/upload.cpython-39.pyc,,
setuptools/command/__pycache__/upload_docs.cpython-39.pyc,,
setuptools/command/alias.py,sha256=1sLQxZcNh6dDQpDmm4G7UGGTol83nY1NTPmNBbm2siI,2381
setuptools/command/bdist_egg.py,sha256=-upiB6fFtm8cQSQj1LRDVpG1-T143DsXCvV0fh03u7U,16604
setuptools/command/bdist_rpm.py,sha256=PxrgoHPNaw2Pw2qNjjHDPC-Ay_IaDbCqP3d_5N-cj2A,1182
setuptools/command/build_clib.py,sha256=fWHSFGkk10VCddBWCszvNhowbG9Z9CZXVjQ2uSInoOs,4415
setuptools/command/build_ext.py,sha256=SNK042HfB2ezlDQbSVRGFqI1IM5A4AsjU1wpV3fgskE,13212
setuptools/command/build_py.py,sha256=c90V1nVPEtYkdye-xvo-B48V5RLvSgD8JBMfPtUbtYw,8751
setuptools/command/develop.py,sha256=5_Ss7ENd1_B_jVMY1tF5UV_y1Xu6jbVzAPG8oKeluGA,7012
setuptools/command/dist_info.py,sha256=5t6kOfrdgALT-P3ogss6PF9k-Leyesueycuk3dUyZnI,960
setuptools/command/easy_install.py,sha256=gapK3GqeIhiT1DEXX46orMxWC6bJRa8lxp9usbBD1Ts,85791
setuptools/command/egg_info.py,sha256=0Y3BXOaQ5tftvCet6LA4lD4A_K9igTKfl-wUJmvs84A,26126
setuptools/command/install.py,sha256=UynjFBgRyyHrDZRVAmXrXG0vChJAMx-sxnOO3JoAzVo,4906
setuptools/command/install_egg_info.py,sha256=bMgeIeRiXzQ4DAGPV1328kcjwQjHjOWU4FngAWLV78Q,2203
setuptools/command/install_lib.py,sha256=Uz42McsyHZAjrB6cw9E7Bz0xsaTbzxnM1PI9CBhiPtE,3875
setuptools/command/install_scripts.py,sha256=o0jN_ex7yYYk8W5clymTFOXwkFMKzW9q_zd9Npcex7M,2593
setuptools/command/launcher manifest.xml,sha256=xlLbjWrB01tKC0-hlVkOKkiSPbzMml2eOPtJ_ucCnbE,628
setuptools/command/py36compat.py,sha256=7yLWzQj179Enx3pJ8V1cDDCzeLMFMd9XJXlK-iZTq5Y,4946
setuptools/command/register.py,sha256=kk3DxXCb5lXTvqnhfwx2g6q7iwbUmgTyXUCaBooBOUk,468
setuptools/command/rotate.py,sha256=SvsQPasezIojPjvMnfkqzh8P0U0tCj0daczF8uc3NQM,2128
setuptools/command/saveopts.py,sha256=za7QCBcQimKKriWcoCcbhxPjUz30gSB74zuTL47xpP4,658
setuptools/command/sdist.py,sha256=2onJidYBPFpUgcX6J4KjZX5ilwciHPRB8VkID5YVaL0,6413
setuptools/command/setopt.py,sha256=okxhqD1NM1nQlbSVDCNv6P7Y7g680sc2r-tUW7wPH1Y,5086
setuptools/command/test.py,sha256=qGY-Hx1RPCndlVh2rsrEs5479CgmxRsrEflVLr98jVA,8088
setuptools/command/upload.py,sha256=XT3YFVfYPAmA5qhGg0euluU98ftxRUW-PzKcODMLxUs,462
setuptools/command/upload_docs.py,sha256=ba5kOyedD_u62weinrxqqnvpuQvBIuamXehJG6tAvO0,7218
setuptools/config.py,sha256=O-T_28163qkEeaX8bLgqJLuOLYur15cC2_xpA0RENfM,23153
setuptools/dep_util.py,sha256=BDx1BkzNQntvAB4alypHbW5UVBzjqths000PrUL4Zqc,949
setuptools/depends.py,sha256=QYQIadr5DwLxPzkErhNt5hmRhvGhWxoXZMRXCm_jcQ0,5499
setuptools/dist.py,sha256=y3gQZbodbqOTG_cXFXuQ2OnTwciIlpZpIciapxOIfBc,43154
setuptools/errors.py,sha256=t4Rm85eXm71Ti0-PO1gAQMRK3V7NN3x1tcbcw0-xGSI,1555
setuptools/extension.py,sha256=NMM46XjNdVelWemc0x8CyVKA5Ks6Zm3xTWSA2SS6xZM,1684
setuptools/extern/__init__.py,sha256=Hhf9W73WAitw9TdRJfDIb6YFjmK56CF61afds1Mg0HY,2407
setuptools/extern/__pycache__/__init__.cpython-39.pyc,,
setuptools/glob.py,sha256=1oZjbfjAHSXbgdhSuR6YGU8jKob9L8NtEmBYqcPTLYk,4873
setuptools/gui-32.exe,sha256=XBr0bHMA6Hpz2s9s9Bzjl-PwXfa9nH4ie0rFn4V2kWA,65536
setuptools/gui-64.exe,sha256=aYKMhX1IJLn4ULHgWX0sE0yREUt6B3TEHf_jOw6yNyE,75264
setuptools/gui-arm64.exe,sha256=TEFnOKDi-mq3ZszxqbCoCXTnM_lhUWjdIqBpr6fVs40,137728
setuptools/gui.exe,sha256=XBr0bHMA6Hpz2s9s9Bzjl-PwXfa9nH4ie0rFn4V2kWA,65536
setuptools/installer.py,sha256=s6DQfsoICBJxbUqbduhOJtl1oG0S4yegRCg3EAs0i3M,3824
setuptools/launch.py,sha256=TyPT-Ic1T2EnYvGO26gfNRP4ysBlrhpbRjQxWsiO414,812
setuptools/monkey.py,sha256=0e3HdVKXHL415O7np-AUqhEFXPPuDdJKbI47chQ_DE4,5217
setuptools/msvc.py,sha256=3LLt938e6OR7wWPzIvCQu7LCWZSIKqoKV6w3r8jV3kY,50561
setuptools/namespaces.py,sha256=PMqGVPXPYQgjUTvEg9bGccRAkIODrQ6NmsDg_fwErwI,3093
setuptools/package_index.py,sha256=SV0gUvX5-uEsnjDJYCS5IRiWs-zEqN5H_vYJcuaq7-A,40092
setuptools/py34compat.py,sha256=KYOd6ybRxjBW8NJmYD8t_UyyVmysppFXqHpFLdslGXU,245
setuptools/sandbox.py,sha256=mR83i-mu-ZUU_7TaMgYCeRSyzkqv8loJ_GR9xhS2DDw,14348
setuptools/script (dev).tmpl,sha256=RUzQzCQUaXtwdLtYHWYbIQmOaES5Brqq1FvUA_tu-5I,218
setuptools/script.tmpl,sha256=WGTt5piezO27c-Dbx6l5Q4T3Ff20A5z7872hv3aAhYY,138
setuptools/unicode_utils.py,sha256=aOOFo4JGwAsiBttGYDsqFS7YqWQeZ2j6DWiCuctR_00,941
setuptools/version.py,sha256=og_cuZQb0QI6ukKZFfZWPlr1HgJBPPn2vO2m_bI9ZTE,144
setuptools/wheel.py,sha256=0P8tSk105uF_Ub-30N2HU2X2v7MKDSdjpeQlRRW3SkI,8288
setuptools/windows_support.py,sha256=5GrfqSP2-dLGJoZTq2g6dCKkyQxxa2n5IQiXlJCoYEE,714

View File

@ -1,5 +0,0 @@
Wheel-Version: 1.0
Generator: bdist_wheel (0.37.0)
Root-Is-Purelib: true
Tag: py3-none-any

View File

@ -1,56 +0,0 @@
[distutils.commands]
alias = setuptools.command.alias:alias
bdist_egg = setuptools.command.bdist_egg:bdist_egg
bdist_rpm = setuptools.command.bdist_rpm:bdist_rpm
build_clib = setuptools.command.build_clib:build_clib
build_ext = setuptools.command.build_ext:build_ext
build_py = setuptools.command.build_py:build_py
develop = setuptools.command.develop:develop
dist_info = setuptools.command.dist_info:dist_info
easy_install = setuptools.command.easy_install:easy_install
egg_info = setuptools.command.egg_info:egg_info
install = setuptools.command.install:install
install_egg_info = setuptools.command.install_egg_info:install_egg_info
install_lib = setuptools.command.install_lib:install_lib
install_scripts = setuptools.command.install_scripts:install_scripts
rotate = setuptools.command.rotate:rotate
saveopts = setuptools.command.saveopts:saveopts
sdist = setuptools.command.sdist:sdist
setopt = setuptools.command.setopt:setopt
test = setuptools.command.test:test
upload_docs = setuptools.command.upload_docs:upload_docs
[distutils.setup_keywords]
dependency_links = setuptools.dist:assert_string_list
eager_resources = setuptools.dist:assert_string_list
entry_points = setuptools.dist:check_entry_points
exclude_package_data = setuptools.dist:check_package_data
extras_require = setuptools.dist:check_extras
include_package_data = setuptools.dist:assert_bool
install_requires = setuptools.dist:check_requirements
namespace_packages = setuptools.dist:check_nsp
package_data = setuptools.dist:check_package_data
packages = setuptools.dist:check_packages
python_requires = setuptools.dist:check_specifier
setup_requires = setuptools.dist:check_requirements
test_loader = setuptools.dist:check_importable
test_runner = setuptools.dist:check_importable
test_suite = setuptools.dist:check_test_suite
tests_require = setuptools.dist:check_requirements
use_2to3 = setuptools.dist:invalid_unless_false
zip_safe = setuptools.dist:assert_bool
[egg_info.writers]
PKG-INFO = setuptools.command.egg_info:write_pkg_info
dependency_links.txt = setuptools.command.egg_info:overwrite_arg
depends.txt = setuptools.command.egg_info:warn_depends_obsolete
eager_resources.txt = setuptools.command.egg_info:overwrite_arg
entry_points.txt = setuptools.command.egg_info:write_entries
namespace_packages.txt = setuptools.command.egg_info:overwrite_arg
requires.txt = setuptools.command.egg_info:write_requirements
top_level.txt = setuptools.command.egg_info:write_toplevel_names
[setuptools.finalize_distribution_options]
keywords = setuptools.dist:Distribution._finalize_setup_keywords
parent_finalize = setuptools.dist:_Distribution.finalize_options

View File

@ -1,3 +0,0 @@
_distutils_hack
pkg_resources
setuptools

View File

@ -18,6 +18,7 @@ from setuptools.extension import Extension
from setuptools.dist import Distribution from setuptools.dist import Distribution
from setuptools.depends import Require from setuptools.depends import Require
from . import monkey from . import monkey
from . import logging
__all__ = [ __all__ = [
@ -149,6 +150,7 @@ def _install_setup_requires(attrs):
def setup(**attrs): def setup(**attrs):
# Make sure we have any requirements needed to interpret 'attrs'. # Make sure we have any requirements needed to interpret 'attrs'.
logging.configure()
_install_setup_requires(attrs) _install_setup_requires(attrs)
return distutils.core.setup(**attrs) return distutils.core.setup(**attrs)

View File

@ -527,7 +527,7 @@ class MSVCCompiler(CCompiler) :
return return
warnings.warn( warnings.warn(
"Fallback spawn triggered. Please update distutils monkeypatch.") "Fallback spawn triggered. Please update distutils monkeypatch.")
with unittest.mock.patch('os.environ', env): with unittest.mock.patch.dict('os.environ', env):
bag.value = super().spawn(cmd) bag.value = super().spawn(cmd)
# -- Miscellaneous methods ----------------------------------------- # -- Miscellaneous methods -----------------------------------------

View File

@ -81,11 +81,6 @@ if HAS_USER_SITE:
'data' : '{userbase}', 'data' : '{userbase}',
} }
INSTALL_SCHEMES['osx_framework_user'] = {
'headers':
'{userbase}/include/{implementation_lower}{py_version_short}{abiflags}/{dist_name}',
}
# The keys to an installation scheme; if any new types of files are to be # The keys to an installation scheme; if any new types of files are to be
# installed, be sure to add an entry to every installation scheme above, # installed, be sure to add an entry to every installation scheme above,
# and to SCHEME_KEYS here. # and to SCHEME_KEYS here.
@ -124,7 +119,8 @@ def _get_implementation():
def _select_scheme(ob, name): def _select_scheme(ob, name):
vars(ob).update(_remove_set(ob, _scheme_attrs(_resolve_scheme(name)))) scheme = _inject_headers(name, _load_scheme(_resolve_scheme(name)))
vars(ob).update(_remove_set(ob, _scheme_attrs(scheme)))
def _remove_set(ob, attrs): def _remove_set(ob, attrs):
@ -147,9 +143,26 @@ def _resolve_scheme(name):
return resolved return resolved
def _scheme_attrs(name): def _load_scheme(name):
return _load_schemes()[name]
def _inject_headers(name, scheme):
"""
Given a scheme name and the resolved scheme,
if the scheme does not include headers, resolve
the fallback scheme for the name and use headers
from it. pypa/distutils#88
"""
# Bypass the preferred scheme, which may not
# have defined headers.
fallback = _load_scheme(_pypy_hack(name))
scheme.setdefault('headers', fallback['headers'])
return scheme
def _scheme_attrs(scheme):
"""Resolve install directories by applying the install schemes.""" """Resolve install directories by applying the install schemes."""
scheme = _load_schemes()[name]
return { return {
f'install_{key}': scheme[key] f'install_{key}': scheme[key]
for key in SCHEME_KEYS for key in SCHEME_KEYS
@ -395,6 +408,7 @@ class install(Command):
'platlibdir': getattr(sys, 'platlibdir', 'lib'), 'platlibdir': getattr(sys, 'platlibdir', 'lib'),
'implementation_lower': _get_implementation().lower(), 'implementation_lower': _get_implementation().lower(),
'implementation': _get_implementation(), 'implementation': _get_implementation(),
'platsubdir': sysconfig.get_config_var('platsubdir'),
} }
if HAS_USER_SITE: if HAS_USER_SITE:
@ -635,7 +649,7 @@ class install(Command):
return return
home = convert_path(os.path.expanduser("~")) home = convert_path(os.path.expanduser("~"))
for name, path in self.config_vars.items(): for name, path in self.config_vars.items():
if path.startswith(home) and not os.path.isdir(path): if str(path).startswith(home) and not os.path.isdir(path):
self.debug_print("os.makedirs('%s', 0o700)" % path) self.debug_print("os.makedirs('%s', 0o700)" % path)
os.makedirs(path, 0o700) os.makedirs(path, 0o700)

View File

@ -51,16 +51,14 @@ import os
import sys import sys
import copy import copy
import shlex import shlex
from subprocess import Popen, PIPE, check_output import warnings
import re from subprocess import check_output
import distutils.version
from distutils.unixccompiler import UnixCCompiler from distutils.unixccompiler import UnixCCompiler
from distutils.file_util import write_file from distutils.file_util import write_file
from distutils.errors import (DistutilsExecError, CCompilerError, from distutils.errors import (DistutilsExecError, CCompilerError,
CompileError, UnknownFileError) CompileError, UnknownFileError)
from distutils.version import LooseVersion from distutils.version import LooseVersion, suppress_known_deprecation
from distutils.spawn import find_executable
def get_msvcr(): def get_msvcr():
"""Include the appropriate MSVC runtime library if Python was built """Include the appropriate MSVC runtime library if Python was built
@ -125,31 +123,6 @@ class CygwinCCompiler(UnixCCompiler):
self.cc = os.environ.get('CC', 'gcc') self.cc = os.environ.get('CC', 'gcc')
self.cxx = os.environ.get('CXX', 'g++') self.cxx = os.environ.get('CXX', 'g++')
if ('gcc' in self.cc): # Start gcc workaround
self.gcc_version, self.ld_version, self.dllwrap_version = \
get_versions()
self.debug_print(self.compiler_type + ": gcc %s, ld %s, dllwrap %s\n" %
(self.gcc_version,
self.ld_version,
self.dllwrap_version) )
# ld_version >= "2.10.90" and < "2.13" should also be able to use
# gcc -mdll instead of dllwrap
# Older dllwraps had own version numbers, newer ones use the
# same as the rest of binutils ( also ld )
# dllwrap 2.10.90 is buggy
if self.ld_version >= "2.10.90":
self.linker_dll = self.cc
else:
self.linker_dll = "dllwrap"
# ld_version >= "2.13" support -shared so use it instead of
# -mdll -static
if self.ld_version >= "2.13":
shared_option = "-shared"
else:
shared_option = "-mdll -static"
else: # Assume linker is up to date
self.linker_dll = self.cc self.linker_dll = self.cc
shared_option = "-shared" shared_option = "-shared"
@ -160,18 +133,25 @@ class CygwinCCompiler(UnixCCompiler):
linker_so=('%s -mcygwin %s' % linker_so=('%s -mcygwin %s' %
(self.linker_dll, shared_option))) (self.linker_dll, shared_option)))
# cygwin and mingw32 need different sets of libraries
if ('gcc' in self.cc and self.gcc_version == "2.91.57"):
# cygwin shouldn't need msvcrt, but without the dlls will crash
# (gcc version 2.91.57) -- perhaps something about initialization
self.dll_libraries=["msvcrt"]
self.warn(
"Consider upgrading to a newer version of gcc")
else:
# Include the appropriate MSVC runtime library if Python was built # Include the appropriate MSVC runtime library if Python was built
# with MSVC 7.0 or later. # with MSVC 7.0 or later.
self.dll_libraries = get_msvcr() self.dll_libraries = get_msvcr()
@property
def gcc_version(self):
# Older numpy dependend on this existing to check for ancient
# gcc versions. This doesn't make much sense with clang etc so
# just hardcode to something recent.
# https://github.com/numpy/numpy/pull/20333
warnings.warn(
"gcc_version attribute of CygwinCCompiler is deprecated. "
"Instead of returning actual gcc version a fixed value 11.2.0 is returned.",
DeprecationWarning,
stacklevel=2,
)
with suppress_known_deprecation():
return LooseVersion("11.2.0")
def _compile(self, obj, src, ext, cc_args, extra_postargs, pp_opts): def _compile(self, obj, src, ext, cc_args, extra_postargs, pp_opts):
"""Compiles the source by spawning GCC and windres if needed.""" """Compiles the source by spawning GCC and windres if needed."""
if ext == '.rc' or ext == '.res': if ext == '.rc' or ext == '.res':
@ -232,13 +212,6 @@ class CygwinCCompiler(UnixCCompiler):
# next add options for def-file and to creating import libraries # next add options for def-file and to creating import libraries
# dllwrap uses different options than gcc/ld
if self.linker_dll == "dllwrap":
extra_preargs.extend(["--output-lib", lib_file])
# for dllwrap we have to use a special option
extra_preargs.extend(["--def", def_file])
# we use gcc/ld here and can be sure ld is >= 2.9.10
else:
# doesn't work: bfd_close build\...\libfoo.a: Invalid operation # doesn't work: bfd_close build\...\libfoo.a: Invalid operation
#extra_preargs.extend(["-Wl,--out-implib,%s" % lib_file]) #extra_preargs.extend(["-Wl,--out-implib,%s" % lib_file])
# for gcc/ld the def-file is specified as any object files # for gcc/ld the def-file is specified as any object files
@ -249,7 +222,7 @@ class CygwinCCompiler(UnixCCompiler):
# who wants symbols and a many times larger output file # who wants symbols and a many times larger output file
# should explicitly switch the debug mode on # should explicitly switch the debug mode on
# otherwise we let dllwrap/ld strip the output file # otherwise we let ld strip the output file
# (On my machine: 10KiB < stripped_file < ??100KiB # (On my machine: 10KiB < stripped_file < ??100KiB
# unstripped_file = stripped_file + XXX KiB # unstripped_file = stripped_file + XXX KiB
# ( XXX=254 for a typical python extension)) # ( XXX=254 for a typical python extension))
@ -297,20 +270,8 @@ class Mingw32CCompiler(CygwinCCompiler):
CygwinCCompiler.__init__ (self, verbose, dry_run, force) CygwinCCompiler.__init__ (self, verbose, dry_run, force)
# ld_version >= "2.13" support -shared so use it instead of
# -mdll -static
if ('gcc' in self.cc and self.ld_version < "2.13"):
shared_option = "-mdll -static"
else:
shared_option = "-shared" shared_option = "-shared"
# A real mingw32 doesn't need to specify a different entry point,
# but cygwin 2.91.57 in no-cygwin-mode needs it.
if ('gcc' in self.cc and self.gcc_version <= "2.91.57"):
entry_point = '--entry _DllMain@12'
else:
entry_point = ''
if is_cygwincc(self.cc): if is_cygwincc(self.cc):
raise CCompilerError( raise CCompilerError(
'Cygwin gcc cannot be used with --compiler=mingw32') 'Cygwin gcc cannot be used with --compiler=mingw32')
@ -319,9 +280,9 @@ class Mingw32CCompiler(CygwinCCompiler):
compiler_so='%s -mdll -O -Wall' % self.cc, compiler_so='%s -mdll -O -Wall' % self.cc,
compiler_cxx='%s -O -Wall' % self.cxx, compiler_cxx='%s -O -Wall' % self.cxx,
linker_exe='%s' % self.cc, linker_exe='%s' % self.cc,
linker_so='%s %s %s' linker_so='%s %s'
% (self.linker_dll, shared_option, % (self.linker_dll, shared_option))
entry_point))
# Maybe we should also append -mthreads, but then the finished # Maybe we should also append -mthreads, but then the finished
# dlls need another dll (mingwm10.dll see Mingw32 docs) # dlls need another dll (mingwm10.dll see Mingw32 docs)
# (-mthreads: Support thread-safe exception handling on `Mingw32') # (-mthreads: Support thread-safe exception handling on `Mingw32')
@ -388,39 +349,14 @@ def check_config_h():
return (CONFIG_H_UNCERTAIN, return (CONFIG_H_UNCERTAIN,
"couldn't read '%s': %s" % (fn, exc.strerror)) "couldn't read '%s': %s" % (fn, exc.strerror))
RE_VERSION = re.compile(br'(\d+\.\d+(\.\d+)*)')
def _find_exe_version(cmd):
"""Find the version of an executable by running `cmd` in the shell.
If the command is not found, or the output does not match
`RE_VERSION`, returns None.
"""
executable = cmd.split()[0]
if find_executable(executable) is None:
return None
out = Popen(cmd, shell=True, stdout=PIPE).stdout
try:
out_string = out.read()
finally:
out.close()
result = RE_VERSION.search(out_string)
if result is None:
return None
# LooseVersion works with strings; decode
ver_str = result.group(1).decode()
with distutils.version.suppress_known_deprecation():
return LooseVersion(ver_str)
def get_versions():
""" Try to find out the versions of gcc, ld and dllwrap.
If not possible it returns None for it.
"""
commands = ['gcc -dumpversion', 'ld -v', 'dllwrap --version']
return tuple([_find_exe_version(cmd) for cmd in commands])
def is_cygwincc(cc): def is_cygwincc(cc):
'''Try to determine if the compiler that would be used is from cygwin.''' '''Try to determine if the compiler that would be used is from cygwin.'''
out_string = check_output(shlex.split(cc) + ['-dumpmachine']) out_string = check_output(shlex.split(cc) + ['-dumpmachine'])
return out_string.strip().endswith(b'cygwin') return out_string.strip().endswith(b'cygwin')
get_versions = None
"""
A stand-in for the previous get_versions() function to prevent failures
when monkeypatched. See pypa/setuptools#2969.
"""

View File

@ -3,13 +3,14 @@
# The class here is styled after PEP 282 so that it could later be # The class here is styled after PEP 282 so that it could later be
# replaced with a standard Python logging implementation. # replaced with a standard Python logging implementation.
import sys
DEBUG = 1 DEBUG = 1
INFO = 2 INFO = 2
WARN = 3 WARN = 3
ERROR = 4 ERROR = 4
FATAL = 5 FATAL = 5
import sys
class Log: class Log:
@ -54,6 +55,7 @@ class Log:
def fatal(self, msg, *args): def fatal(self, msg, *args):
self._log(FATAL, msg, args) self._log(FATAL, msg, args)
_global_log = Log() _global_log = Log()
log = _global_log.log log = _global_log.log
debug = _global_log.debug debug = _global_log.debug
@ -62,12 +64,14 @@ warn = _global_log.warn
error = _global_log.error error = _global_log.error
fatal = _global_log.fatal fatal = _global_log.fatal
def set_threshold(level): def set_threshold(level):
# return the old threshold for use from tests # return the old threshold for use from tests
old = _global_log.threshold old = _global_log.threshold
_global_log.threshold = level _global_log.threshold = level
return old return old
def set_verbosity(v): def set_verbosity(v):
if v <= 0: if v <= 0:
set_threshold(WARN) set_threshold(WARN)

View File

@ -13,6 +13,7 @@ import _imp
import os import os
import re import re
import sys import sys
import sysconfig
from .errors import DistutilsPlatformError from .errors import DistutilsPlatformError
@ -274,31 +275,15 @@ def get_config_h_filename():
inc_dir = os.path.join(_sys_home or project_base, "PC") inc_dir = os.path.join(_sys_home or project_base, "PC")
else: else:
inc_dir = _sys_home or project_base inc_dir = _sys_home or project_base
else:
inc_dir = get_python_inc(plat_specific=1)
return os.path.join(inc_dir, 'pyconfig.h') return os.path.join(inc_dir, 'pyconfig.h')
else:
return sysconfig.get_config_h_filename()
# Allow this value to be patched by pkgsrc. Ref pypa/distutils#16.
_makefile_tmpl = 'config-{python_ver}{build_flags}{multiarch}'
def get_makefile_filename(): def get_makefile_filename():
"""Return full pathname of installed Makefile from the Python build.""" """Return full pathname of installed Makefile from the Python build."""
if python_build: return sysconfig.get_makefile_filename()
return os.path.join(_sys_home or project_base, "Makefile")
lib_dir = get_python_lib(plat_specific=0, standard_lib=1)
multiarch = (
'-%s' % sys.implementation._multiarch
if hasattr(sys.implementation, '_multiarch') else ''
)
config_file = _makefile_tmpl.format(
python_ver=get_python_version(),
build_flags=build_flags,
multiarch=multiarch,
)
return os.path.join(lib_dir, config_file, 'Makefile')
def parse_config_h(fp, g=None): def parse_config_h(fp, g=None):
@ -308,26 +293,7 @@ def parse_config_h(fp, g=None):
optional dictionary is passed in as the second argument, it is optional dictionary is passed in as the second argument, it is
used instead of a new dictionary. used instead of a new dictionary.
""" """
if g is None: return sysconfig.parse_config_h(fp, vars=g)
g = {}
define_rx = re.compile("#define ([A-Z][A-Za-z0-9_]+) (.*)\n")
undef_rx = re.compile("/[*] #undef ([A-Z][A-Za-z0-9_]+) [*]/\n")
#
while True:
line = fp.readline()
if not line:
break
m = define_rx.match(line)
if m:
n, v = m.group(1, 2)
try: v = int(v)
except ValueError: pass
g[n] = v
else:
m = undef_rx.match(line)
if m:
g[m.group(1)] = 0
return g
# Regexes needed for parsing Makefile (and similar syntaxes, # Regexes needed for parsing Makefile (and similar syntaxes,