Skip to content

Commit

Permalink
Use pytest, get rid of test/runner.py (#2447)
Browse files Browse the repository at this point in the history
See #2446.

This PR:

* gets rid of [psutil/tests/runner.py](https://github.com/giampaolo/psutil/blob/622bd442eef704627202282d5805e4b39358b897/psutil/tests/runner.py#L1) (less code to maintain)
* use `pytest-xdist` to allow for parallel test execution
* get rid of [concurrencytest](https://pypi.org/project/concurrencytest/) dep
* update Github and Appveyor CI config
* removes 400 lines of code

Replacing `self.assert*` APIs will  be done in a separate PR.
  • Loading branch information
giampaolo authored Oct 1, 2024
1 parent 622bd44 commit 42c7a24
Show file tree
Hide file tree
Showing 33 changed files with 205 additions and 639 deletions.
29 changes: 18 additions & 11 deletions .github/workflows/bsd.yml
Original file line number Diff line number Diff line change
@@ -1,15 +1,22 @@
# # Execute tests on *BSD platforms. Does not produce wheels.
# # Useful URLs:
# # https://github.com/vmactions/freebsd-vm
# # https://github.com/vmactions/openbsd-vm
# # https://github.com/vmactions/netbsd-vm
# Execute tests on *BSD platforms. Does not produce wheels.
# Useful URLs:
# https://github.com/vmactions/freebsd-vm
# https://github.com/vmactions/openbsd-vm
# https://github.com/vmactions/netbsd-vm

on: [push, pull_request]
name: bsd-tests
concurrency:
group: ${{ github.ref }}-${{ github.workflow }}-${{ github.event_name }}-${{ github.ref == format('refs/heads/{0}', github.event.repository.default_branch) && github.sha || '' }}
cancel-in-progress: true
jobs:
# here just so that I can comment the next jobs to temporarily disable them
empty-job:
if: false
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4

# on: [push, pull_request]
# name: bsd-tests
# concurrency:
# group: ${{ github.ref }}-${{ github.workflow }}-${{ github.event_name }}-${{ github.ref == format('refs/heads/{0}', github.event.repository.default_branch) && github.sha || '' }}
# cancel-in-progress: true
# jobs:
# freebsd:
# runs-on: ubuntu-22.04
# steps:
Expand Down
14 changes: 8 additions & 6 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ concurrency:
jobs:
# Linux + macOS + Windows Python 3
py3:
name: "py3-${{ matrix.os }}-${{ matrix.arch }}"
name: "py3, ${{ matrix.os }}, ${{ matrix.arch }}"
runs-on: ${{ matrix.os }}
timeout-minutes: 30
strategy:
Expand Down Expand Up @@ -57,6 +57,9 @@ jobs:
env:
CIBW_ARCHS: "${{ matrix.arch }}"
CIBW_PRERELEASE_PYTHONS: True
CIBW_TEST_EXTRAS: test
CIBW_TEST_COMMAND:
make -C {project} PYTHON="env python" PSUTIL_SCRIPTS_DIR="{project}/scripts" setup-dev-env install print-sysinfo test test-memleaks

- name: Upload wheels
uses: actions/upload-artifact@v4
Expand All @@ -73,19 +76,18 @@ jobs:
# Linux + macOS + Python 2
py2:
name: py2-${{ matrix.os }}
name: py2, ${{ matrix.os }}
runs-on: ${{ matrix.os }}
timeout-minutes: 20
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-12]
env:
CIBW_TEST_COMMAND:
PYTHONWARNINGS=always PYTHONUNBUFFERED=1 PSUTIL_DEBUG=1 python {project}/psutil/tests/runner.py &&
PYTHONWARNINGS=always PYTHONUNBUFFERED=1 PSUTIL_DEBUG=1 python {project}/psutil/tests/test_memleaks.py
CIBW_TEST_EXTRAS: test
CIBW_BUILD: 'cp27-*'
CIBW_TEST_EXTRAS: test
CIBW_TEST_COMMAND:
make -C {project} PYTHON="env python" PSUTIL_SCRIPTS_DIR="{project}/scripts" setup-dev-env install print-sysinfo test test-memleaks

steps:
- uses: actions/checkout@v4
Expand Down
1 change: 0 additions & 1 deletion MANIFEST.in
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,6 @@ include psutil/arch/windows/wmi.h
include psutil/tests/README.rst
include psutil/tests/__init__.py
include psutil/tests/__main__.py
include psutil/tests/runner.py
include psutil/tests/test_aix.py
include psutil/tests/test_bsd.py
include psutil/tests/test_connections.py
Expand Down
98 changes: 56 additions & 42 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,49 +2,64 @@
# To use a specific Python version run: "make install PYTHON=python3.3"
# You can set the variables below from the command line.

# Configurable.
PYTHON = python3
PYTHON_ENV_VARS = PYTHONWARNINGS=always PYTHONUNBUFFERED=1 PSUTIL_DEBUG=1
PYTEST_ARGS = -v -s --tb=short
ARGS =
TSCRIPT = psutil/tests/runner.py

# Internal.
# mandatory deps for running tests
PY3_DEPS = \
black \
check-manifest \
concurrencytest \
coverage \
packaging \
pylint \
pyperf \
pypinfo \
requests \
rstcheck \
ruff \
setuptools \
sphinx_rtd_theme \
teyit \
toml-sort \
twine \
virtualenv \
wheel
pytest \
pytest-xdist

# deps for local development
ifndef CIBUILDWHEEL
PY3_DEPS += \
black \
check-manifest \
coverage \
packaging \
pylint \
pyperf \
pypinfo \
pytest-cov \
requests \
rstcheck \
ruff \
setuptools \
sphinx_rtd_theme \
toml-sort \
twine \
virtualenv \
wheel
endif

# python 2 deps
PY2_DEPS = \
futures \
ipaddress \
mock
mock==1.0.1 \
pytest==4.6.11 \
pytest-xdist \
setuptools

PY_DEPS = `$(PYTHON) -c \
"import sys; \
py3 = sys.version_info[0] == 3; \
py38 = sys.version_info[:2] >= (3, 8); \
py3_extra = ' abi3audit' if py38 else ''; \
print('$(PY3_DEPS)' + py3_extra if py3 else '$(PY2_DEPS)')"`

NUM_WORKERS = `$(PYTHON) -c "import os; print(os.cpu_count() or 1)"`

# "python3 setup.py build" can be parallelized on Python >= 3.6.
BUILD_OPTS = `$(PYTHON) -c \
"import sys, os; \
py36 = sys.version_info[:2] >= (3, 6); \
cpus = os.cpu_count() or 1 if py36 else 1; \
print('--parallel %s' % cpus if cpus > 1 else '')"`

# In not in a virtualenv, add --user options for install commands.
INSTALL_OPTS = `$(PYTHON) -c \
"import sys; print('' if hasattr(sys, 'real_prefix') or hasattr(sys, 'base_prefix') and sys.base_prefix != sys.prefix else '--user')"`
Expand Down Expand Up @@ -123,74 +138,74 @@ install-pip: ## Install pip (no-op if already installed).
setup-dev-env: ## Install GIT hooks, pip, test deps (also upgrades them).
${MAKE} install-git-hooks
${MAKE} install-pip
$(PYTHON_ENV_VARS) $(PYTHON) -m pip install $(INSTALL_OPTS) --trusted-host files.pythonhosted.org --trusted-host pypi.org --upgrade pip
$(PYTHON_ENV_VARS) $(PYTHON) -m pip install $(INSTALL_OPTS) --trusted-host files.pythonhosted.org --trusted-host pypi.org --upgrade $(PY_DEPS)
$(PYTHON) -m pip install $(INSTALL_OPTS) --trusted-host files.pythonhosted.org --trusted-host pypi.org --upgrade pip
$(PYTHON) -m pip install $(INSTALL_OPTS) --trusted-host files.pythonhosted.org --trusted-host pypi.org --upgrade $(PY_DEPS)

# ===================================================================
# Tests
# ===================================================================

test: ## Run all tests. To run a specific test do "make test ARGS=psutil.tests.test_system.TestDiskAPIs"
${MAKE} build
$(PYTHON_ENV_VARS) $(PYTHON) $(TSCRIPT) $(ARGS)
$(PYTHON_ENV_VARS) $(PYTHON) -m pytest $(PYTEST_ARGS) --ignore=psutil/tests/test_memleaks.py $(ARGS)

test-parallel: ## Run all tests in parallel.
${MAKE} build
$(PYTHON_ENV_VARS) $(PYTHON) $(TSCRIPT) $(ARGS) --parallel
$(PYTHON_ENV_VARS) $(PYTHON) -m pytest $(PYTEST_ARGS) --ignore=psutil/tests/test_memleaks.py -n auto --dist loadgroup $(ARGS)

test-process: ## Run process-related API tests.
${MAKE} build
$(PYTHON_ENV_VARS) $(PYTHON) $(TSCRIPT) $(ARGS) psutil/tests/test_process.py
$(PYTHON_ENV_VARS) $(PYTHON) -m pytest $(PYTEST_ARGS) $(ARGS) psutil/tests/test_process.py

test-process-all: ## Run tests which iterate over all process PIDs.
${MAKE} build
$(PYTHON_ENV_VARS) $(PYTHON) $(TSCRIPT) $(ARGS) psutil/tests/test_process_all.py
$(PYTHON_ENV_VARS) $(PYTHON) -m pytest $(PYTEST_ARGS) $(ARGS) psutil/tests/test_process_all.py

test-system: ## Run system-related API tests.
${MAKE} build
$(PYTHON_ENV_VARS) $(PYTHON) $(TSCRIPT) $(ARGS) psutil/tests/test_system.py
$(PYTHON_ENV_VARS) $(PYTHON) -m pytest $(PYTEST_ARGS) $(ARGS) psutil/tests/test_system.py

test-misc: ## Run miscellaneous tests.
${MAKE} build
$(PYTHON_ENV_VARS) $(PYTHON) $(TSCRIPT) $(ARGS) psutil/tests/test_misc.py
$(PYTHON_ENV_VARS) $(PYTHON) -m pytest $(PYTEST_ARGS) $(ARGS) psutil/tests/test_misc.py

test-testutils: ## Run test utils tests.
${MAKE} build
$(PYTHON_ENV_VARS) $(PYTHON) $(TSCRIPT) $(ARGS) psutil/tests/test_testutils.py
$(PYTHON_ENV_VARS) $(PYTHON) -m pytest $(PYTEST_ARGS) $(ARGS) psutil/tests/test_testutils.py

test-unicode: ## Test APIs dealing with strings.
${MAKE} build
$(PYTHON_ENV_VARS) $(PYTHON) $(TSCRIPT) $(ARGS) psutil/tests/test_unicode.py
$(PYTHON_ENV_VARS) $(PYTHON) -m pytest $(PYTEST_ARGS) $(ARGS) psutil/tests/test_unicode.py

test-contracts: ## APIs sanity tests.
${MAKE} build
$(PYTHON_ENV_VARS) $(PYTHON) $(TSCRIPT) $(ARGS) psutil/tests/test_contracts.py
$(PYTHON_ENV_VARS) $(PYTHON) -m pytest $(PYTEST_ARGS) $(ARGS) psutil/tests/test_contracts.py

test-connections: ## Test psutil.net_connections() and Process.net_connections().
${MAKE} build
$(PYTHON_ENV_VARS) $(PYTHON) $(TSCRIPT) $(ARGS) psutil/tests/test_connections.py
$(PYTHON_ENV_VARS) $(PYTHON) -m pytest $(PYTEST_ARGS) $(ARGS) psutil/tests/test_connections.py

test-posix: ## POSIX specific tests.
${MAKE} build
$(PYTHON_ENV_VARS) $(PYTHON) $(TSCRIPT) $(ARGS) psutil/tests/test_posix.py
$(PYTHON_ENV_VARS) $(PYTHON) -m pytest $(PYTEST_ARGS) $(ARGS) psutil/tests/test_posix.py

test-platform: ## Run specific platform tests only.
${MAKE} build
$(PYTHON_ENV_VARS) $(PYTHON) $(TSCRIPT) $(ARGS) psutil/tests/test_`$(PYTHON) -c 'import psutil; print([x.lower() for x in ("LINUX", "BSD", "OSX", "SUNOS", "WINDOWS", "AIX") if getattr(psutil, x)][0])'`.py
$(PYTHON_ENV_VARS) $(PYTHON) -m pytest $(PYTEST_ARGS) $(ARGS) psutil/tests/test_`$(PYTHON) -c 'import psutil; print([x.lower() for x in ("LINUX", "BSD", "OSX", "SUNOS", "WINDOWS", "AIX") if getattr(psutil, x)][0])'`.py

test-memleaks: ## Memory leak tests.
${MAKE} build
$(PYTHON_ENV_VARS) $(PYTHON) $(TSCRIPT) $(ARGS) psutil/tests/test_memleaks.py
$(PYTHON_ENV_VARS) $(PYTHON) -m pytest $(PYTEST_ARGS) $(ARGS) psutil/tests/test_memleaks.py

test-last-failed: ## Re-run tests which failed on last run
${MAKE} build
$(PYTHON_ENV_VARS) $(PYTHON) $(TSCRIPT) $(ARGS) --last-failed
$(PYTHON_ENV_VARS) $(PYTHON) -m pytest $(PYTEST_ARGS) --last-failed $(ARGS)

test-coverage: ## Run test coverage.
${MAKE} build
# Note: coverage options are controlled by .coveragerc file
rm -rf .coverage htmlcov
$(PYTHON_ENV_VARS) $(PYTHON) -m coverage run -m unittest -v
$(PYTHON_ENV_VARS) $(PYTHON) -m coverage run -m pytest $(PYTEST_ARGS) --ignore=psutil/tests/test_memleaks.py $(ARGS)
$(PYTHON) -m coverage report
@echo "writing results to htmlcov/index.html"
$(PYTHON) -m coverage html
Expand Down Expand Up @@ -235,16 +250,12 @@ fix-black:
fix-ruff:
@git ls-files '*.py' | xargs $(PYTHON) -m ruff check --no-cache --fix $(ARGS)

fix-unittests: ## Fix unittest idioms.
@git ls-files '*test_*.py' | xargs $(PYTHON) -m teyit --show-stats

fix-toml: ## Fix pyproject.toml
@git ls-files '*.toml' | xargs toml-sort

fix-all: ## Run all code fixers.
${MAKE} fix-ruff
${MAKE} fix-black
${MAKE} fix-unittests
${MAKE} fix-toml

# ===================================================================
Expand Down Expand Up @@ -351,6 +362,9 @@ print-downloads: ## Print PYPI download statistics
print-hashes: ## Prints hashes of files in dist/ directory
$(PYTHON) scripts/internal/print_hashes.py dist/

print-sysinfo: ## Prints system info
$(PYTHON) -c "from psutil.tests import print_sysinfo; print_sysinfo()"

# ===================================================================
# Misc
# ===================================================================
Expand Down
2 changes: 1 addition & 1 deletion appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,14 @@ init:

install:
- "%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"
- "%WITH_COMPILER% %PYTHON%/python.exe -m pip freeze"
- "%WITH_COMPILER% %PYTHON%/python.exe scripts/internal/winmake.py install"

build: off

test_script:
- "%WITH_COMPILER% %PYTHON%/python.exe scripts/internal/winmake.py print-sysinfo"
- "%WITH_COMPILER% %PYTHON%/python.exe scripts/internal/winmake.py test"
- "%WITH_COMPILER% %PYTHON%/python.exe scripts/internal/winmake.py test-memleaks"

Expand Down
2 changes: 1 addition & 1 deletion docs/DEVGUIDE.rst
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ Once you have a compiler installed run:

.. code-block:: bash
make test TSCRIPT=test_script.py # on UNIX
make test ARGS=test_script.py # on UNIX
make test test_script.py # on Windows
- Do not use ``sudo``. ``make install`` installs psutil as a limited user in
Expand Down
7 changes: 0 additions & 7 deletions make.bat
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,12 @@ rem ...therefore it might not work on your Windows installation.
rem
rem To compile for a specific Python version run:
rem set PYTHON=C:\Python34\python.exe & make.bat build
rem
rem To use a different test script:
rem set TSCRIPT=foo.py & make.bat test
rem ==========================================================================

if "%PYTHON%" == "" (
set PYTHON=python
)

if "%TSCRIPT%" == "" (
set TSCRIPT=psutil\tests\runner.py
)

rem Needed to locate the .pypirc file and upload exes on PyPI.
set HOME=%USERPROFILE%
set PSUTIL_DEBUG=1
Expand Down
2 changes: 1 addition & 1 deletion psutil/_psaix.py
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,7 @@ def wrapper(self, *args, **kwargs):
class Process:
"""Wrapper class around underlying C implementation."""

__slots__ = ["pid", "_name", "_ppid", "_procfs_path", "_cache"]
__slots__ = ["_cache", "_name", "_ppid", "_procfs_path", "pid"]

def __init__(self, pid):
self.pid = pid
Expand Down
2 changes: 1 addition & 1 deletion psutil/_psbsd.py
Original file line number Diff line number Diff line change
Expand Up @@ -640,7 +640,7 @@ def wrap_exceptions_procfs(inst):
class Process:
"""Wrapper class around underlying C implementation."""

__slots__ = ["pid", "_name", "_ppid", "_cache"]
__slots__ = ["_cache", "_name", "_ppid", "pid"]

def __init__(self, pid):
self.pid = pid
Expand Down
2 changes: 1 addition & 1 deletion psutil/_pslinux.py
Original file line number Diff line number Diff line change
Expand Up @@ -1732,7 +1732,7 @@ def wrapper(self, *args, **kwargs):
class Process:
"""Linux process implementation."""

__slots__ = ["pid", "_name", "_ppid", "_procfs_path", "_cache"]
__slots__ = ["_cache", "_name", "_ppid", "_procfs_path", "pid"]

def __init__(self, pid):
self.pid = pid
Expand Down
2 changes: 1 addition & 1 deletion psutil/_psosx.py
Original file line number Diff line number Diff line change
Expand Up @@ -361,7 +361,7 @@ def wrapper(self, *args, **kwargs):
class Process:
"""Wrapper class around underlying C implementation."""

__slots__ = ["pid", "_name", "_ppid", "_cache"]
__slots__ = ["_cache", "_name", "_ppid", "pid"]

def __init__(self, pid):
self.pid = pid
Expand Down
2 changes: 1 addition & 1 deletion psutil/_pssunos.py
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,7 @@ def wrapper(self, *args, **kwargs):
class Process:
"""Wrapper class around underlying C implementation."""

__slots__ = ["pid", "_name", "_ppid", "_procfs_path", "_cache"]
__slots__ = ["_cache", "_name", "_ppid", "_procfs_path", "pid"]

def __init__(self, pid):
self.pid = pid
Expand Down
2 changes: 1 addition & 1 deletion psutil/_pswindows.py
Original file line number Diff line number Diff line change
Expand Up @@ -762,7 +762,7 @@ def wrapper(self, *args, **kwargs):
class Process:
"""Wrapper class around underlying C implementation."""

__slots__ = ["pid", "_name", "_ppid", "_cache"]
__slots__ = ["_cache", "_name", "_ppid", "pid"]

def __init__(self, pid):
self.pid = pid
Expand Down
Loading

0 comments on commit 42c7a24

Please sign in to comment.