diff --git a/.ci/appveyor/install.ps1 b/.ci/appveyor/install.ps1 deleted file mode 100644 index 3f0562825..000000000 --- a/.ci/appveyor/install.ps1 +++ /dev/null @@ -1,85 +0,0 @@ -# Sample script to install Python and pip under Windows -# Authors: Olivier Grisel and Kyle Kastner -# License: CC0 1.0 Universal: http://creativecommons.org/publicdomain/zero/1.0/ - -$BASE_URL = "https://www.python.org/ftp/python/" -$GET_PIP_URL = "https://bootstrap.pypa.io/get-pip.py" -$GET_PIP_PATH = "C:\get-pip.py" - - -function DownloadPython ($python_version, $platform_suffix) { - $webclient = New-Object System.Net.WebClient - $filename = "python-" + $python_version + $platform_suffix + ".msi" - $url = $BASE_URL + $python_version + "/" + $filename - - $basedir = $pwd.Path + "\" - $filepath = $basedir + $filename - if (Test-Path $filename) { - Write-Host "Reusing" $filepath - return $filepath - } - - # Download and retry up to 5 times in case of network transient errors. - Write-Host "Downloading" $filename "from" $url - $retry_attempts = 3 - for($i=0; $i -lt $retry_attempts; $i++){ - try { - $webclient.DownloadFile($url, $filepath) - break - } - Catch [Exception]{ - Start-Sleep 1 - } - } - Write-Host "File saved at" $filepath - return $filepath -} - - -function InstallPython ($python_version, $architecture, $python_home) { - Write-Host "Installing Python" $python_version "for" $architecture "bit architecture to" $python_home - if (Test-Path $python_home) { - Write-Host $python_home "already exists, skipping." - return $false - } - if ($architecture -eq "32") { - $platform_suffix = "" - } else { - $platform_suffix = ".amd64" - } - $filepath = DownloadPython $python_version $platform_suffix - Write-Host "Installing" $filepath "to" $python_home - $args = "/qn /i $filepath TARGETDIR=$python_home" - Write-Host "msiexec.exe" $args - Start-Process -FilePath "msiexec.exe" -ArgumentList $args -Wait -Passthru - Write-Host "Python $python_version ($architecture) installation complete" - return $true -} - - -function InstallPip ($python_home) { - $pip_path = $python_home + "/Scripts/pip.exe" - $python_path = $python_home + "/python.exe" - if (-not(Test-Path $pip_path)) { - Write-Host "Installing pip..." - $webclient = New-Object System.Net.WebClient - $webclient.DownloadFile($GET_PIP_URL, $GET_PIP_PATH) - Write-Host "Executing:" $python_path $GET_PIP_PATH - Start-Process -FilePath "$python_path" -ArgumentList "$GET_PIP_PATH" -Wait -Passthru - } else { - Write-Host "pip already installed." - } -} - -function InstallPackage ($python_home, $pkg) { - $pip_path = $python_home + "/Scripts/pip.exe" - & $pip_path install $pkg -} - -function main () { - InstallPython $env:PYTHON_VERSION $env:PYTHON_ARCH $env:PYTHON - InstallPip $env:PYTHON - InstallPackage $env:PYTHON wheel -} - -main diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 445640be9..d89ced5a6 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -20,15 +20,15 @@ on: [push, pull_request] name: build jobs: - # Linux + macOS + Python 3.6+ - linux-macos-py3: + # Linux + macOS + Windows Python 3.6+ + py3: name: ${{ matrix.os }}-py36-plus runs-on: ${{ matrix.os }} timeout-minutes: 20 strategy: fail-fast: false matrix: - os: [ubuntu-20.04, macos-11] + os: [ubuntu-20.04, macos-11, windows-2019] steps: - name: Cancel previous runs @@ -62,6 +62,49 @@ jobs: mv dist/psutil*.tar.gz wheelhouse/ python scripts/internal/print_hashes.py wheelhouse/ + # Windows cp37+ tests + # psutil tests do not like running from a virtualenv with python>=3.7 so + # not using cibuildwheel for those. run them "manually" with this job. + windows-py3-test: + name: windows-py3-test-${{ matrix.python }}-${{ matrix.architecture }} + needs: py3 + runs-on: windows-2019 + timeout-minutes: 20 + strategy: + fail-fast: false + matrix: + python: ["3.7", "3.8", "3.9", "3.10", "3.11-dev"] + architecture: ["x86", "x64"] + + steps: + - name: Cancel previous runs + uses: styfle/cancel-workflow-action@0.9.1 + with: + access_token: ${{ github.token }} + - uses: actions/checkout@v3 + - uses: actions/setup-python@v3 + with: + python-version: "${{ matrix.python }}" + architecture: "${{ matrix.architecture }}" + cache: pip + cache-dependency-path: .github/workflows/build.yml + - name: Download wheels + uses: actions/download-artifact@v3 + with: + name: wheels + path: wheelhouse + - name: Run tests + run: | + mkdir .tests + cd .tests + pip install $(find ../wheelhouse -name '*-cp36-abi3-${{ matrix.architecture == 'x86' && 'win32' || 'win_amd64'}}.whl')[test] + export PYTHONWARNINGS=always + export PYTHONUNBUFFERED=1 + export PSUTIL_DEBUG=1 + python ../psutil/tests/runner.py + python ../psutil/tests/test_memleaks.py + shell: bash + # Linux + macOS + Python 2.7 & 3.5 linux-macos-py2: name: ${{ matrix.os }}-py27-py35 diff --git a/appveyor.yml b/appveyor.yml index 4bbd51aeb..0752e610c 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -24,62 +24,17 @@ environment: PYTHON_VERSION: "2.7.x" PYTHON_ARCH: "32" - - PYTHON: "C:\\Python36" - PYTHON_VERSION: "3.6.x" - PYTHON_ARCH: "32" - - - PYTHON: "C:\\Python37" - PYTHON_VERSION: "3.7.x" - PYTHON_ARCH: "32" - - - PYTHON: "C:\\Python38" - PYTHON_VERSION: "3.8.x" - PYTHON_ARCH: "32" - - - PYTHON: "C:\\Python39" - PYTHON_VERSION: "3.9.x" - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 - PYTHON_ARCH: "32" - - - PYTHON: "C:\\Python310" - PYTHON_VERSION: "3.10.x" - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 - PYTHON_ARCH: "32" - # 64 bits - PYTHON: "C:\\Python27-x64" PYTHON_VERSION: "2.7.x" PYTHON_ARCH: "64" - - PYTHON: "C:\\Python36-x64" - PYTHON_VERSION: "3.6.x" - PYTHON_ARCH: "64" - - - PYTHON: "C:\\Python37-x64" - PYTHON_VERSION: "3.7.x" - PYTHON_ARCH: "64" - - - PYTHON: "C:\\Python38-x64" - PYTHON_VERSION: "3.8.x" - PYTHON_ARCH: "64" - - - PYTHON: "C:\\Python39-x64" - PYTHON_VERSION: "3.9.x" - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 - PYTHON_ARCH: "64" - - - PYTHON: "C:\\Python310-x64" - PYTHON_VERSION: "3.10.x" - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 - PYTHON_ARCH: "64" init: - "ECHO %PYTHON% %PYTHON_VERSION% %PYTHON_ARCH%" install: - - "powershell .ci\\appveyor\\install.ps1" - # - ps: (new-object net.webclient).DownloadFile('https://raw.github.com/pypa/pip/master/contrib/get-pip.py', 'C:/get-pip.py') - "%WITH_COMPILER% %PYTHON%/python.exe -m pip --version" - "%WITH_COMPILER% %PYTHON%/python.exe -m pip install --upgrade --user setuptools pip" - "%WITH_COMPILER% %PYTHON%/python.exe scripts/internal/winmake.py setup-dev-env" diff --git a/cibuildwheel.toml b/cibuildwheel.toml index 9cf2c4d90..c280fdc18 100644 --- a/cibuildwheel.toml +++ b/cibuildwheel.toml @@ -11,3 +11,18 @@ archs = ["x86_64", "universal2"] [tool.cibuildwheel.macos.environment] MACOSX_DEPLOYMENT_TARGET = "10.9" + +[tool.cibuildwheel.windows] +# psutil tests do not like running from a virtualenv with python>=3.7 +# restrict build & tests to cp36 +# cp36-abi3 wheels will need to be tested outside cibuildwheel for python>=3.7 +build = "cp36-*" +test-command = [ + "python {project}/psutil/tests/runner.py", + "python {project}/psutil/tests/test_memleaks.py" +] + +[tool.cibuildwheel.windows.environment] +PYTHONWARNINGS = "always" +PYTHONUNBUFFERED = "1" +PSUTIL_DEBUG = "1" diff --git a/psutil/_psutil_linux.c b/psutil/_psutil_linux.c index 64cdf0b55..7ef55189c 100644 --- a/psutil/_psutil_linux.c +++ b/psutil/_psutil_linux.c @@ -298,29 +298,25 @@ psutil_proc_cpu_affinity_set(PyObject *self, PyObject *args) { pid_t pid; int i, seq_len; PyObject *py_cpu_set; - PyObject *py_cpu_seq = NULL; if (!PyArg_ParseTuple(args, _Py_PARSE_PID "O", &pid, &py_cpu_set)) return NULL; if (!PySequence_Check(py_cpu_set)) { - PyErr_Format(PyExc_TypeError, "sequence argument expected, got %s", - Py_TYPE(py_cpu_set)->tp_name); + PyErr_Format(PyExc_TypeError, "sequence argument expected, got %R", Py_TYPE(py_cpu_set)); goto error; } - py_cpu_seq = PySequence_Fast(py_cpu_set, "expected a sequence or integer"); - if (!py_cpu_seq) - goto error; - seq_len = PySequence_Fast_GET_SIZE(py_cpu_seq); + seq_len = PySequence_Size(py_cpu_set); CPU_ZERO(&cpu_set); for (i = 0; i < seq_len; i++) { - PyObject *item = PySequence_Fast_GET_ITEM(py_cpu_seq, i); + PyObject *item = PySequence_GetItem(py_cpu_set, i); #if PY_MAJOR_VERSION >= 3 long value = PyLong_AsLong(item); #else long value = PyInt_AsLong(item); #endif + Py_XDECREF(item); if ((value == -1) || PyErr_Occurred()) { if (!PyErr_Occurred()) PyErr_SetString(PyExc_ValueError, "invalid CPU value"); @@ -335,12 +331,9 @@ psutil_proc_cpu_affinity_set(PyObject *self, PyObject *args) { goto error; } - Py_DECREF(py_cpu_seq); Py_RETURN_NONE; error: - if (py_cpu_seq != NULL) - Py_DECREF(py_cpu_seq); return NULL; } #endif /* PSUTIL_HAVE_CPU_AFFINITY */ diff --git a/psutil/arch/windows/process_info.c b/psutil/arch/windows/process_info.c index d44c4eb75..1981d306a 100644 --- a/psutil/arch/windows/process_info.c +++ b/psutil/arch/windows/process_info.c @@ -578,7 +578,7 @@ psutil_get_cmdline(DWORD pid, int use_peb) { wcslen(szArglist[i])); if (py_unicode == NULL) goto out; - PyList_SET_ITEM(py_retlist, i, py_unicode); + PyList_SetItem(py_retlist, i, py_unicode); py_unicode = NULL; } ret = py_retlist; diff --git a/setup.py b/setup.py index 0f6716b3b..b5d4f1291 100755 --- a/setup.py +++ b/setup.py @@ -100,6 +100,14 @@ def get_version(): VERSION = get_version() macros.append(('PSUTIL_VERSION', int(VERSION.replace('.', '')))) +PY36_PLUS = sys.version_info[:2] >= (3, 6) +CP36_PLUS = PY36_PLUS and sys.implementation.name == "cpython" +if CP36_PLUS and (MACOS or LINUX or WINDOWS): + py_limited_api = {"py_limited_api": True} + macros.append(('Py_LIMITED_API', '0x03060000')) +else: + py_limited_api = {} + def get_description(): script = os.path.join(HERE, "scripts", "internal", "convert_readme.py") @@ -182,7 +190,8 @@ def get_winver(): "ws2_32", "PowrProf", "pdh", ], # extra_compile_args=["/W 4"], - # extra_link_args=["/DEBUG"] + # extra_link_args=["/DEBUG"], + **py_limited_api ) elif MACOS: @@ -197,7 +206,8 @@ def get_winver(): define_macros=macros, extra_link_args=[ '-framework', 'CoreFoundation', '-framework', 'IOKit' - ]) + ], + **py_limited_api) elif FREEBSD: macros.append(("PSUTIL_FREEBSD", 1)) @@ -214,7 +224,8 @@ def get_winver(): 'psutil/arch/freebsd/proc_socks.c', ], define_macros=macros, - libraries=["devstat"]) + libraries=["devstat"], + **py_limited_api) elif OPENBSD: macros.append(("PSUTIL_OPENBSD", 1)) @@ -228,7 +239,8 @@ def get_winver(): 'psutil/arch/openbsd/proc.c', ], define_macros=macros, - libraries=["kvm"]) + libraries=["kvm"], + **py_limited_api) elif NETBSD: macros.append(("PSUTIL_NETBSD", 1)) @@ -240,7 +252,8 @@ def get_winver(): 'psutil/arch/netbsd/socks.c', ], define_macros=macros, - libraries=["kvm"]) + libraries=["kvm"], + **py_limited_api) elif LINUX: def get_ethtool_macro(): @@ -276,7 +289,8 @@ def get_ethtool_macro(): ext = Extension( 'psutil._psutil_linux', sources=sources + ['psutil/_psutil_linux.c'], - define_macros=macros) + define_macros=macros, + **py_limited_api) elif SUNOS: macros.append(("PSUTIL_SUNOS", 1)) @@ -288,7 +302,8 @@ def get_ethtool_macro(): 'psutil/arch/solaris/environ.c' ], define_macros=macros, - libraries=['kstat', 'nsl', 'socket']) + libraries=['kstat', 'nsl', 'socket'], + **py_limited_api) elif AIX: macros.append(("PSUTIL_AIX", 1)) @@ -300,7 +315,8 @@ def get_ethtool_macro(): 'psutil/arch/aix/common.c', 'psutil/arch/aix/ifaddrs.c'], libraries=['perfstat'], - define_macros=macros) + define_macros=macros, + **py_limited_api) else: sys.exit('platform %s is not supported' % sys.platform) @@ -310,7 +326,8 @@ def get_ethtool_macro(): posix_extension = Extension( 'psutil._psutil_posix', define_macros=macros, - sources=sources) + sources=sources, + **py_limited_api) if SUNOS: def get_sunos_update(): # See https://serverfault.com/q/524883 @@ -341,11 +358,27 @@ def get_sunos_update(): else: extensions = [ext] +cmdclass = {} +if py_limited_api: + from wheel.bdist_wheel import bdist_wheel as _bdist_wheel + + class bdist_wheel_abi3(_bdist_wheel): + def finalize_options(self): + _bdist_wheel.finalize_options(self) + self.root_is_pure = False + + def get_tag(self): + python, abi, plat = _bdist_wheel.get_tag(self) + return python, "abi3", plat + + cmdclass["bdist_wheel"] = bdist_wheel_abi3 + def main(): kwargs = dict( name='psutil', version=VERSION, + cmdclass=cmdclass, description=__doc__ .replace('\n', ' ').strip() if __doc__ else '', long_description=get_description(), long_description_content_type='text/x-rst',