psutil
/
Makefile
372 строки · 12.9 Кб
1# Shortcuts for various tasks (UNIX only).
2# To use a specific Python version run: "make install PYTHON=python3.3"
3# You can set the variables below from the command line.
4
5# Configurable.
6PYTHON = python3
7PYTHON_ENV_VARS = PYTHONWARNINGS=always PYTHONUNBUFFERED=1 PSUTIL_DEBUG=1
8ARGS =
9TSCRIPT = psutil/tests/runner.py
10
11# Internal.
12PY3_DEPS = \
13black \
14check-manifest \
15concurrencytest \
16coverage \
17packaging \
18pylint \
19pyperf \
20pypinfo \
21requests \
22rstcheck \
23ruff \
24setuptools \
25sphinx_rtd_theme \
26teyit \
27toml-sort \
28twine \
29virtualenv \
30wheel
31PY2_DEPS = \
32futures \
33ipaddress \
34mock
35PY_DEPS = `$(PYTHON) -c \
36"import sys; \
37py3 = sys.version_info[0] == 3; \
38py38 = sys.version_info[:2] >= (3, 8); \
39py3_extra = ' abi3audit' if py38 else ''; \
40print('$(PY3_DEPS)' + py3_extra if py3 else '$(PY2_DEPS)')"`
41NUM_WORKERS = `$(PYTHON) -c "import os; print(os.cpu_count() or 1)"`
42# "python3 setup.py build" can be parallelized on Python >= 3.6.
43BUILD_OPTS = `$(PYTHON) -c \
44"import sys, os; \
45py36 = sys.version_info[:2] >= (3, 6); \
46cpus = os.cpu_count() or 1 if py36 else 1; \
47print('--parallel %s' % cpus if cpus > 1 else '')"`
48# In not in a virtualenv, add --user options for install commands.
49INSTALL_OPTS = `$(PYTHON) -c \
50"import sys; print('' if hasattr(sys, 'real_prefix') or hasattr(sys, 'base_prefix') and sys.base_prefix != sys.prefix else '--user')"`
51
52# if make is invoked with no arg, default to `make help`
53.DEFAULT_GOAL := help
54
55# ===================================================================
56# Install
57# ===================================================================
58
59clean: ## Remove all build files.
60@rm -rfv `find . \
61-type d -name __pycache__ \
62-o -type f -name \*.bak \
63-o -type f -name \*.orig \
64-o -type f -name \*.pyc \
65-o -type f -name \*.pyd \
66-o -type f -name \*.pyo \
67-o -type f -name \*.rej \
68-o -type f -name \*.so \
69-o -type f -name \*.~ \
70-o -type f -name \*\$testfn`
71@rm -rfv \
72*.core \
73*.egg-info \
74*\@psutil-* \
75.coverage \
76.failed-tests.txt \
77.pytest_cache \
78.ruff_cache/ \
79build/ \
80dist/ \
81docs/_build/ \
82htmlcov/ \
83wheelhouse
84
85.PHONY: build
86build: ## Compile (in parallel) without installing.
87@# "build_ext -i" copies compiled *.so files in ./psutil directory in order
88@# to allow "import psutil" when using the interactive interpreter from
89@# within this directory.
90$(PYTHON_ENV_VARS) $(PYTHON) setup.py build_ext -i $(BUILD_OPTS)
91$(PYTHON_ENV_VARS) $(PYTHON) -c "import psutil" # make sure it actually worked
92
93install: ## Install this package as current user in "edit" mode.
94${MAKE} build
95$(PYTHON_ENV_VARS) $(PYTHON) setup.py develop $(INSTALL_OPTS)
96$(PYTHON_ENV_VARS) $(PYTHON) -c "import psutil" # make sure it actually worked
97
98uninstall: ## Uninstall this package via pip.
99cd ..; $(PYTHON_ENV_VARS) $(PYTHON) -m pip uninstall -y -v psutil || true
100$(PYTHON_ENV_VARS) $(PYTHON) scripts/internal/purge_installation.py
101
102install-pip: ## Install pip (no-op if already installed).
103@$(PYTHON) -c \
104"import sys, ssl, os, pkgutil, tempfile, atexit; \
105sys.exit(0) if pkgutil.find_loader('pip') else None; \
106PY3 = sys.version_info[0] == 3; \
107pyexc = 'from urllib.request import urlopen' if PY3 else 'from urllib2 import urlopen'; \
108exec(pyexc); \
109ctx = ssl._create_unverified_context() if hasattr(ssl, '_create_unverified_context') else None; \
110url = 'https://bootstrap.pypa.io/pip/2.7/get-pip.py' if not PY3 else 'https://bootstrap.pypa.io/get-pip.py'; \
111kw = dict(context=ctx) if ctx else {}; \
112req = urlopen(url, **kw); \
113data = req.read(); \
114f = tempfile.NamedTemporaryFile(suffix='.py'); \
115atexit.register(f.close); \
116f.write(data); \
117f.flush(); \
118print('downloaded %s' % f.name); \
119code = os.system('%s %s --user --upgrade' % (sys.executable, f.name)); \
120f.close(); \
121sys.exit(code);"
122
123setup-dev-env: ## Install GIT hooks, pip, test deps (also upgrades them).
124${MAKE} install-git-hooks
125${MAKE} install-pip
126$(PYTHON_ENV_VARS) $(PYTHON) -m pip install $(INSTALL_OPTS) --trusted-host files.pythonhosted.org --trusted-host pypi.org --upgrade pip
127$(PYTHON_ENV_VARS) $(PYTHON) -m pip install $(INSTALL_OPTS) --trusted-host files.pythonhosted.org --trusted-host pypi.org --upgrade $(PY_DEPS)
128
129# ===================================================================
130# Tests
131# ===================================================================
132
133test: ## Run all tests. To run a specific test do "make test ARGS=psutil.tests.test_system.TestDiskAPIs"
134${MAKE} build
135$(PYTHON_ENV_VARS) $(PYTHON) $(TSCRIPT) $(ARGS)
136
137test-parallel: ## Run all tests in parallel.
138${MAKE} build
139$(PYTHON_ENV_VARS) $(PYTHON) $(TSCRIPT) $(ARGS) --parallel
140
141test-process: ## Run process-related API tests.
142${MAKE} build
143$(PYTHON_ENV_VARS) $(PYTHON) $(TSCRIPT) $(ARGS) psutil/tests/test_process.py
144
145test-process-all: ## Run tests which iterate over all process PIDs.
146${MAKE} build
147$(PYTHON_ENV_VARS) $(PYTHON) $(TSCRIPT) $(ARGS) psutil/tests/test_process_all.py
148
149test-system: ## Run system-related API tests.
150${MAKE} build
151$(PYTHON_ENV_VARS) $(PYTHON) $(TSCRIPT) $(ARGS) psutil/tests/test_system.py
152
153test-misc: ## Run miscellaneous tests.
154${MAKE} build
155$(PYTHON_ENV_VARS) $(PYTHON) $(TSCRIPT) $(ARGS) psutil/tests/test_misc.py
156
157test-testutils: ## Run test utils tests.
158${MAKE} build
159$(PYTHON_ENV_VARS) $(PYTHON) $(TSCRIPT) $(ARGS) psutil/tests/test_testutils.py
160
161test-unicode: ## Test APIs dealing with strings.
162${MAKE} build
163$(PYTHON_ENV_VARS) $(PYTHON) $(TSCRIPT) $(ARGS) psutil/tests/test_unicode.py
164
165test-contracts: ## APIs sanity tests.
166${MAKE} build
167$(PYTHON_ENV_VARS) $(PYTHON) $(TSCRIPT) $(ARGS) psutil/tests/test_contracts.py
168
169test-connections: ## Test psutil.net_connections() and Process.net_connections().
170${MAKE} build
171$(PYTHON_ENV_VARS) $(PYTHON) $(TSCRIPT) $(ARGS) psutil/tests/test_connections.py
172
173test-posix: ## POSIX specific tests.
174${MAKE} build
175$(PYTHON_ENV_VARS) $(PYTHON) $(TSCRIPT) $(ARGS) psutil/tests/test_posix.py
176
177test-platform: ## Run specific platform tests only.
178${MAKE} build
179$(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
180
181test-memleaks: ## Memory leak tests.
182${MAKE} build
183$(PYTHON_ENV_VARS) $(PYTHON) $(TSCRIPT) $(ARGS) psutil/tests/test_memleaks.py
184
185test-last-failed: ## Re-run tests which failed on last run
186${MAKE} build
187$(PYTHON_ENV_VARS) $(PYTHON) $(TSCRIPT) $(ARGS) --last-failed
188
189test-coverage: ## Run test coverage.
190${MAKE} build
191# Note: coverage options are controlled by .coveragerc file
192rm -rf .coverage htmlcov
193$(PYTHON_ENV_VARS) $(PYTHON) -m coverage run -m unittest -v
194$(PYTHON) -m coverage report
195@echo "writing results to htmlcov/index.html"
196$(PYTHON) -m coverage html
197$(PYTHON) -m webbrowser -t htmlcov/index.html
198
199# ===================================================================
200# Linters
201# ===================================================================
202
203ruff: ## Run ruff linter.
204@git ls-files '*.py' | xargs $(PYTHON) -m ruff check --no-cache
205
206black: ## Python files linting (via black)
207@git ls-files '*.py' | xargs $(PYTHON) -m black --check --safe
208
209_pylint: ## Python pylint (not mandatory, just run it from time to time)
210@git ls-files '*.py' | xargs $(PYTHON) -m pylint --rcfile=pyproject.toml --jobs=${NUM_WORKERS}
211
212lint-c: ## Run C linter.
213@git ls-files '*.c' '*.h' | xargs $(PYTHON) scripts/internal/clinter.py
214
215lint-rst: ## Run C linter.
216@git ls-files '*.rst' | xargs rstcheck --config=pyproject.toml
217
218lint-toml: ## Linter for pyproject.toml
219@git ls-files '*.toml' | xargs toml-sort --check
220
221lint-all: ## Run all linters
222${MAKE} black
223${MAKE} ruff
224${MAKE} lint-c
225${MAKE} lint-rst
226${MAKE} lint-toml
227
228# ===================================================================
229# Fixers
230# ===================================================================
231
232fix-black:
233@git ls-files '*.py' | xargs $(PYTHON) -m black
234
235fix-ruff:
236@git ls-files '*.py' | xargs $(PYTHON) -m ruff check --no-cache --fix $(ARGS)
237
238fix-unittests: ## Fix unittest idioms.
239@git ls-files '*test_*.py' | xargs $(PYTHON) -m teyit --show-stats
240
241fix-toml: ## Fix pyproject.toml
242@git ls-files '*.toml' | xargs toml-sort
243
244fix-all: ## Run all code fixers.
245${MAKE} fix-ruff
246${MAKE} fix-black
247${MAKE} fix-unittests
248${MAKE} fix-toml
249
250# ===================================================================
251# GIT
252# ===================================================================
253
254install-git-hooks: ## Install GIT pre-commit hook.
255ln -sf ../../scripts/internal/git_pre_commit.py .git/hooks/pre-commit
256chmod +x .git/hooks/pre-commit
257
258# ===================================================================
259# Distribution
260# ===================================================================
261
262sdist: ## Create tar.gz source distribution.
263${MAKE} generate-manifest
264$(PYTHON_ENV_VARS) $(PYTHON) setup.py sdist
265
266download-wheels-github: ## Download latest wheels hosted on github.
267$(PYTHON_ENV_VARS) $(PYTHON) scripts/internal/download_wheels_github.py --tokenfile=~/.github.token
268${MAKE} print-dist
269
270download-wheels-appveyor: ## Download latest wheels hosted on appveyor.
271$(PYTHON_ENV_VARS) $(PYTHON) scripts/internal/download_wheels_appveyor.py
272${MAKE} print-dist
273
274check-sdist: ## Check sanity of source distribution.
275$(PYTHON_ENV_VARS) $(PYTHON) -m virtualenv --clear --no-wheel --quiet build/venv
276$(PYTHON_ENV_VARS) build/venv/bin/python -m pip install -v --isolated --quiet dist/*.tar.gz
277$(PYTHON_ENV_VARS) build/venv/bin/python -c "import os; os.chdir('build/venv'); import psutil"
278$(PYTHON) -m twine check --strict dist/*.tar.gz
279
280check-wheels: ## Check sanity of wheels.
281$(PYTHON) -m abi3audit --verbose --strict dist/*-abi3-*.whl
282$(PYTHON) -m twine check --strict dist/*.whl
283
284pre-release: ## Check if we're ready to produce a new release.
285${MAKE} clean
286${MAKE} sdist
287${MAKE} check-sdist
288${MAKE} install
289$(PYTHON) -c \
290"import requests, sys; \
291from packaging.version import parse; \
292from psutil import __version__; \
293res = requests.get('https://pypi.org/pypi/psutil/json', timeout=5); \
294versions = sorted(res.json()['releases'], key=parse, reverse=True); \
295sys.exit('version %r already exists on PYPI' % __version__) if __version__ in versions else 0"
296$(PYTHON) -c \
297"from psutil import __version__ as ver; \
298doc = open('docs/index.rst').read(); \
299history = open('HISTORY.rst').read(); \
300assert ver in doc, '%r not in docs/index.rst' % ver; \
301assert ver in history, '%r not in HISTORY.rst' % ver; \
302assert 'XXXX' not in history, 'XXXX in HISTORY.rst';"
303${MAKE} download-wheels-github
304${MAKE} download-wheels-appveyor
305${MAKE} check-wheels
306${MAKE} print-hashes
307${MAKE} print-dist
308
309release: ## Upload a new release.
310${MAKE} check-sdist
311${MAKE} check-wheels
312$(PYTHON) -m twine upload dist/*.tar.gz
313$(PYTHON) -m twine upload dist/*.whl
314${MAKE} git-tag-release
315
316generate-manifest: ## Generates MANIFEST.in file.
317$(PYTHON) scripts/internal/generate_manifest.py > MANIFEST.in
318
319print-dist: ## Print downloaded wheels / tar.gs
320$(PYTHON) scripts/internal/print_dist.py
321
322git-tag-release: ## Git-tag a new release.
323git tag -a release-`python3 -c "import setup; print(setup.get_version())"` -m `git rev-list HEAD --count`:`git rev-parse --short HEAD`
324git push --follow-tags
325
326# ===================================================================
327# Printers
328# ===================================================================
329
330print-announce: ## Print announce of new release.
331@$(PYTHON) scripts/internal/print_announce.py
332
333print-timeline: ## Print releases' timeline.
334@$(PYTHON) scripts/internal/print_timeline.py
335
336print-access-denied: ## Print AD exceptions
337${MAKE} build
338@$(PYTHON_ENV_VARS) $(PYTHON) scripts/internal/print_access_denied.py
339
340print-api-speed: ## Benchmark all API calls
341${MAKE} build
342@$(PYTHON_ENV_VARS) $(PYTHON) scripts/internal/print_api_speed.py $(ARGS)
343
344print-downloads: ## Print PYPI download statistics
345$(PYTHON) scripts/internal/print_downloads.py
346
347print-hashes: ## Prints hashes of files in dist/ directory
348$(PYTHON) scripts/internal/print_hashes.py dist/
349
350# ===================================================================
351# Misc
352# ===================================================================
353
354grep-todos: ## Look for TODOs in the source files.
355git grep -EIn "TODO|FIXME|XXX"
356
357bench-oneshot: ## Benchmarks for oneshot() ctx manager (see #799).
358${MAKE} build
359$(PYTHON_ENV_VARS) $(PYTHON) scripts/internal/bench_oneshot.py
360
361bench-oneshot-2: ## Same as above but using perf module (supposed to be more precise)
362${MAKE} build
363$(PYTHON_ENV_VARS) $(PYTHON) scripts/internal/bench_oneshot_2.py
364
365check-broken-links: ## Look for broken links in source files.
366git ls-files | xargs $(PYTHON) -Wa scripts/internal/check_broken_links.py
367
368check-manifest: ## Inspect MANIFEST.in file.
369$(PYTHON) -m check_manifest -v $(ARGS)
370
371help: ## Display callable targets.
372@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}'
373