From 7050a8aeaaf6e7a3b5579fac86a9cfcf93219a38 Mon Sep 17 00:00:00 2001 From: Bernhard Kaindl Date: Fri, 15 Nov 2024 12:00:00 +0100 Subject: [PATCH 01/16] tox.ini: Complete the transition from pyre to pyright Signed-off-by: Bernhard Kaindl --- tox.ini | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/tox.ini b/tox.ini index 5db78e4e..ba49e39b 100644 --- a/tox.ini +++ b/tox.ini @@ -4,8 +4,8 @@ # 1. python 2.7 and 3.10 coverage test for changed, but not covered lines and mypy check # 2. python 3.6 test and pylint warnings from changed lines # 3. pytype (needs Python 3.8 for best results) -# 4. pyre and pyright checks, pytest test report as markdown for GitHub Actions summary -envlist = py38-covcombine-check, py311-lint-test, py310-pytype, py311-pyre-mdreport +# 4. pyright checks, pytest test report as markdown for GitHub Actions summary +envlist = py38-covcombine-check, py311-lint-test, py310-pytype, py311-pyright-mdreport isolated_build = true skip_missing_interpreters = true requires = @@ -42,15 +42,15 @@ description = Run in a {basepython} virtualenv: lint: {[lint]description} mdreport: Make a test report (which is shown in the GitHub Actions Summary Page) test: {[test]description} - # https://pypi.org/project/pyre-check/ pyre intro: https://youtu.be/0FSXS5kw2m4 - pyre: Run pyre for static analyis, only passes using: tox -e py311-pyre + # See https://microsoft.github.io/pyright/#/configuration for more in pyright + pyright: Run pyright for static analyis check: Run mypy for static analyis pytype: Run pytype for static analyis, intro: https://youtu.be/abvW0mOrDiY # checkers(mypy) need the pytest dependices as well: extras = {check,pytype}: {[check]extras} - {cov,covcp,covcombine,fox,check,lint,test,pytype,pyre,mdreport}: {[test]extras} - {cov,covcp,covcombine,fox}: {[cov]extras} + {cov,covcp,covcombine,fox,check,lint,test,pytype,pyright,mdreport}: {[test]extras} + {cov,covcp,covcombine,fox}: {[cov]extras} deps = mdreport: pytest-md-report {py27-test,py27-cov}: pyftpdlib @@ -58,9 +58,7 @@ deps = {cov,covcp,covcombine,fox}: coverage[toml] {cov,covcp,covcombine,fox}: diff-cover {lint,fox}: {[lint]deps} - pyre: pyre-check - pyre: pyre-extensions - pyre: pyright + pyright: pyright pytype: {[pytype]deps} allowlist_externals = {cov,covcp,covcombine,fox,check,lint,test,mdreport}: echo @@ -81,7 +79,6 @@ passenv = covcp: HOME check: MYPY_FORCE_COLOR check: MYPY_FORCE_TERMINAL_WIDTH - pyre: PYRE_TYPESHED {fox,check,pytype}: TERM fox: DISPLAY fox: XAUTHORITY @@ -104,7 +101,7 @@ setenv = {[cov]setenv} commands = lint: {[lint]commands} - pyre: {[pyre]commands} + pyright: {[pyright]commands} check: {[check]commands} pytype: {[pytype]commands} {cov,covcp,covcombine,check,fox,test,mdreport}: {[test]commands} @@ -200,7 +197,7 @@ commands = ignore = W191,W293,W504,E101,E126,E127,E201,E202,E203,E221,E222,E226,E227,E241,E251,E261,E262,E265,E301,E302,E303,E305,E722,W391,E401,E402,E741 max-line-length = 129 -[pyre] +[pyright] commands = -pyright From d335446fab20ff2f166621c1c1dbfe221660a4a2 Mon Sep 17 00:00:00 2001 From: Bernhard Kaindl Date: Fri, 15 Nov 2024 12:00:00 +0100 Subject: [PATCH 02/16] pre-commit: Remove the remaining call to pyre in pre-commit Signed-off-by: Bernhard Kaindl --- .pre-commit-config.yaml | 7 ----- pyproject.toml | 5 ---- pyre_runner.py | 62 ----------------------------------------- 3 files changed, 74 deletions(-) delete mode 100755 pyre_runner.py diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 4dea24a9..36b678db 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -101,13 +101,6 @@ repos: - toml - repo: local hooks: - - id: run-pyre - name: run-pyre (expect this to take 30 seconds) - entry: python pyre_runner.py - types: [python] - language: python - log_file: ".git/pre-commit-pyre.log" - additional_dependencies: [pyre-check,mock] - id: pytype name: pytype (may take up to two minutes) entry: sh -c "pytype >/dev/tty" diff --git a/pyproject.toml b/pyproject.toml index 8edd0ba3..ac1cabf4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -71,11 +71,6 @@ mypy = [ "types-six", "types-toml", ] -# pyre introduced two false-postives recently, pin it to prevent further surprises: -pyre = [ - "pyre-check == 0.9.21", - "pyre-extensions == 0.0.30", -] pytype = [ "pandas", "pytype", diff --git a/pyre_runner.py b/pyre_runner.py deleted file mode 100755 index a67d2427..00000000 --- a/pyre_runner.py +++ /dev/null @@ -1,62 +0,0 @@ -#!/usr/bin/env python -""" -Run a one-time pyre static analysis check without needing a .pyre_configuration -Gets the paths dynamically so it can be used in tox and GitHub CI -""" -import os -import sys -import time - -import mock - -me = os.path.basename(__file__) + ":" - -pyre_typesched = os.environ.get("PYRE_TYPESHED", None) -if pyre_typesched and os.path.exists(pyre_typesched + "/stdlib/os/path.pyi"): - print("Using {env:PYRE_TYPESHED}:", pyre_typesched) -else: - pyre_typesched = sys.path[-1] + "/mypy/typeshed" - if os.path.exists(pyre_typesched + "/stdlib/os/path.pyi"): - print("Using python_lib:", pyre_typesched) - else: - pyre_typesched = "/tmp/typeshed" - if os.path.exists(pyre_typesched + "/stdlib/os/path.pyi"): - print("Using:", pyre_typesched) - else: - clone = "git clone --depth 1 https://github.com/python/typeshed " - print(me, "Falling back to:", clone + pyre_typesched) - ret = os.system(clone + pyre_typesched) - if ret or not os.path.exists(pyre_typesched + "/stdlib/os/path.pyi"): - print(me, "Could not find or clone typeshed, giving up.") - sys.exit(0) - -command = ( - "pyre", - "--source-directory", - "xcp", - "--source-directory", - "tests", - "--search-path", - "stubs", - "--search-path", - ".", - "--search-path", - os.path.dirname(mock.__file__), - "--typeshed", - pyre_typesched, - "check", -) -cmd = " ".join(command) -print(me, "Running:", cmd) -start_time = time.time() -ret = os.system(cmd) -duration = time.time() - start_time -r = os.waitstatus_to_exitcode(ret) # type: ignore[module-addr] # newer versions have it -if r == 0: - print(me, f"OK pyre took: {duration:.1f}s") -else: - print(me, "Ran:", cmd) - print(me, "exit code:", r) - if os.environ.get("ACT", None): - time.sleep(10) -sys.exit(r) From 230782364099c939babacef68e657bd96cbc21b8 Mon Sep 17 00:00:00 2001 From: Bernhard Kaindl Date: Fri, 15 Nov 2024 12:00:00 +0100 Subject: [PATCH 03/16] docs: Complete the transition from pyre to pyright Signed-off-by: Bernhard Kaindl --- CONTRIBUTING.md | 5 ++--- README.md | 7 +++---- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 910602de..8ba18bc9 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -50,13 +50,12 @@ This project uses `tox` to run the tests for different python versions. Intro: > A comprehensive beginner's introduction to `tox`":_ > https://www.seanh.cc/2018/09/01/tox-tutorial/ -`tox` runs `pytest`, `pylint` and static analysis using `mypy`, `pyre`, `pytype`, and `pyright`. +`tox` runs `pytest`, `pylint` and static analysis using `mypy`, `pytype`, and `pyright`. Links: - https://mypy.readthedocs.io/en/stable/ - https://microsoft.github.io/pyright/ - https://google.github.io/pytype/ -- https://pyre-check.org/ With `tox`, developers can run the full test suite for Python 2.7 and 3.x. The same test suite is used in GitHub CI: @@ -78,7 +77,7 @@ Using pip-tools, you can extract the requirements and extras from `pyptoject.tom ```bash PYTHON=python3.10 -EXTRAS=.,test,mypy,pyre,pytype,tox +EXTRAS=.,test,mypy,pytype,tox PFLAGS="--no-warn-conflicts" $PYTHON -m pip install pip-tools==7.3.0 $PYTHON -m piptools compile --extra=$EXTRAS -o - pyproject.toml | diff --git a/README.md b/README.md index 2f24022a..fa00abca 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ The Continuous Integration Tests feature: - Checking of the combined coverage against the diff to master: Fails if changes are not covered! - Pylint report in the GitHub Action Summary page, with Warning and Error annotatios, even in the code review. - Check that changes don't generate pylint warnings (if warning classes which are enabled in .pylintrc) -- Static analysis using `mypy`, `pyre` and `pytype` +- Static analysis using `mypy`, `pylint`, `pyright` and `pytype` This enforces that any change (besides whitespace): @@ -72,7 +72,6 @@ For the installation of the general development dependencies, visit [INSTALL.md] - Test with `python2.7 -m pytest` - Run `mypy` (without any arguments - The configuration is in `pyproject.toml`) - Run `./pytype_runner.py` -- Run `./pyre_runner.py` - Run `tox -e py36-lint` and fix any `Pylint` warnings - Run `tox -e py310-covcombine-check` and fix any missing diff-coverage. - Run `tox` for the full CI test suite @@ -86,7 +85,7 @@ The list of `virtualenvs` configured in tox can be shown using this command: `to $ tox -av default environments: py36-lint -> Run in a py36 virtualenv: Run pylint and fail on warnings remaining on lines in the diff to master -py311-pyre -> Run in a py311 virtualenv: Run pyre for static analyis, only passes using: tox -e py311-pyre +py311-pyright -> Run in a py311 virtualenv: Run pyright for static analyis py38-pytype -> Run in a py38 virtualenv: Run pytype for static analyis, intro: https://youtu.be/abvW0mOrDiY py310-covcombine-check -> Run in a py310 virtualenv: Generate combined coverage reports with py27-test coverage merged Run mypy for static analyis @@ -100,7 +99,7 @@ test -> Run in a python virtualenv: Run pytest in this environ If you have only one version of Python3, that works too. Use: `tox -e py-test` -## Static analysis using mypy, pyre, pyright and pytype +## Static analysis using mypy, pylint, pyright and pytype The preconditions for using static analysis with `mypy` (which passes now but has only a few type comments) and `pyright` are present now and `mypy` is enabled in `tox` From be1336de3ac432b41f38a4e390b636273ef86e86 Mon Sep 17 00:00:00 2001 From: Bernhard Kaindl Date: Fri, 15 Nov 2024 12:00:00 +0100 Subject: [PATCH 04/16] `tox.ini/pyright`: Fail `tox` if `pyright` fails (enforce check) Signed-off-by: Bernhard Kaindl --- tox.ini | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index ba49e39b..0de3fed6 100644 --- a/tox.ini +++ b/tox.ini @@ -199,7 +199,9 @@ max-line-length = 129 [pyright] commands = - -pyright + pyright --version + # To make pyright checks optional, change the next line to '-pyright': + pyright [pytype] deps = pytype From b5752464fb92ed86fcf59441886cec139355cac1 Mon Sep 17 00:00:00 2001 From: Bernhard Kaindl Date: Fri, 15 Nov 2024 12:00:00 +0100 Subject: [PATCH 05/16] pyre: Finally, remove obsolete pyre error suppressions Signed-off-by: Bernhard Kaindl --- tests/conftest.py | 4 ++-- tests/test_cpiofile.py | 1 - tests/test_httpaccessor.py | 1 - xcp/accessor.py | 1 - xcp/bootloader.py | 1 - xcp/cpiofile.py | 2 -- 6 files changed, 2 insertions(+), 8 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 1a2a4974..da395853 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -5,10 +5,10 @@ This module is run automatically by pytest to define and enable fixtures. """ -# pyre-ignore-all-errors[21] import warnings -import pytest # pyre does not find the module when run by tox -e py311-pyre +import pytest + @pytest.fixture(autouse=True) def set_warnings(): diff --git a/tests/test_cpiofile.py b/tests/test_cpiofile.py index cd36a2f2..0371d2df 100644 --- a/tests/test_cpiofile.py +++ b/tests/test_cpiofile.py @@ -1,5 +1,4 @@ # suppress false positive on pytest missing pytest.raises(): -# pyre-ignore-all-errors[16] """ Test various modes of creating and extracting CpioFile using different compression types, opening the archive as stream and as file, using pyfakefs as filesystem without diff --git a/tests/test_httpaccessor.py b/tests/test_httpaccessor.py index d0248f7f..c6bd38fa 100644 --- a/tests/test_httpaccessor.py +++ b/tests/test_httpaccessor.py @@ -43,7 +43,6 @@ def http_get_request_data(self, url, read_file, error_handler): def assert_http_get_request_data(self, url, read_file, error_handler): # type:(str, str, ErrorHandler) -> HTTPAccessor - # pyre-ignore[23]: silence false positive with self.http_get_request_data(url, read_file, error_handler) as (httpaccessor, ref): http_accessor_filehandle = httpaccessor.openAddress(read_file) if sys.version_info >= (3, 0): diff --git a/xcp/accessor.py b/xcp/accessor.py index 0ceec1c1..afdb643d 100644 --- a/xcp/accessor.py +++ b/xcp/accessor.py @@ -24,7 +24,6 @@ """accessor - provide common interface to access methods""" import errno -# pyre-ignore-all-errors[6,16] import ftplib import io import os diff --git a/xcp/bootloader.py b/xcp/bootloader.py index 695c3413..a7fc1fa2 100644 --- a/xcp/bootloader.py +++ b/xcp/bootloader.py @@ -33,7 +33,6 @@ import xcp.cmd -# pyre-ignore-all-errors[21] try: # xenserver-release.rpm puts a branding.py into our xcp installation directory: from xcp import branding # type:ignore[attr-defined] # pytype: disable=import-error except ImportError: # For CI, use stubs/branding.py (./stubs is added to pythonpath) diff --git a/xcp/cpiofile.py b/xcp/cpiofile.py index 995da94c..ff8f5c7c 100644 --- a/xcp/cpiofile.py +++ b/xcp/cpiofile.py @@ -36,8 +36,6 @@ Derived from Lars Gustäbel's tarfile.py """ from __future__ import print_function -# pyre is not as good as other static analysis tools in inferring the correct types: -# pyre-ignore-all-errors[6,16] __version__ = "0.1" __author__ = "Simon Rowe" From 5203159866cbad231739c41108fe68fe3ca41c4c Mon Sep 17 00:00:00 2001 From: Bernhard Kaindl Date: Fri, 15 Aug 2025 12:00:00 +0200 Subject: [PATCH 06/16] Fix remaining pyright warnings found by the unit tests Signed-off-by: Bernhard Kaindl --- pyproject.toml | 4 ++-- tests/test_bootloader.py | 1 + tests/test_xmlunwrap.py | 1 + xcp/bootloader.py | 2 +- 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index ac1cabf4..ae27d940 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -195,8 +195,8 @@ include = ["xcp", "tests"] pythonPlatform = "Linux" pythonVersion = "3.11" reportFunctionMemberAccess = true -reportGeneralTypeIssues = "warning" -reportOptionalMemberAccess = "warning" +reportGeneralTypeIssues = "error" +reportOptionalMemberAccess = "error" reportPrivateUsage = true reportPropertyTypeMismatch = true reportUnnecessaryTypeIgnoreComment = false diff --git a/tests/test_bootloader.py b/tests/test_bootloader.py index 7a0a7a0a..4a34cec6 100644 --- a/tests/test_bootloader.py +++ b/tests/test_bootloader.py @@ -18,6 +18,7 @@ def _test_cfg(self, cfg): stdout = subprocess.PIPE, universal_newlines=True) + assert proc.stdout is not None # for pyright, to ensure it is valid self.assertEqual(proc.stdout.read(), '''5a6,13 > if [ -s $prefix/grubenv ]; then > load_env diff --git a/tests/test_xmlunwrap.py b/tests/test_xmlunwrap.py index 19d9241b..2c47e6af 100644 --- a/tests/test_xmlunwrap.py +++ b/tests/test_xmlunwrap.py @@ -15,6 +15,7 @@ def setUp(self): self.top_el = xmldoc.documentElement def test(self): + assert self.top_el is not None # This test requires that top_el is not None self.assertEqual(self.top_el.tagName, "installation") self.assertEqual([getText(el) diff --git a/xcp/bootloader.py b/xcp/bootloader.py index a7fc1fa2..6bb17459 100644 --- a/xcp/bootloader.py +++ b/xcp/bootloader.py @@ -60,7 +60,7 @@ def __init__(self, hypervisor, hypervisor_args, kernel, kernel_args, self.initrd = initrd self.title = title self.root = root - self.entry_format = None + self.entry_format = None # type: Grub2Format | None def getHypervisorArgs(self): return re.findall(r'\S[^ "]*(?:"[^"]*")?\S*', self.hypervisor_args) From 33e6104db4aca5123b40f273d923ba5e5a8f9664 Mon Sep 17 00:00:00 2001 From: Bernhard Kaindl Date: Fri, 15 Nov 2024 12:00:00 +0100 Subject: [PATCH 07/16] GitHub CI/`tox`: Update CI to use Python `3.11`, `3.12` and `3.13` Signed-off-by: Bernhard Kaindl --- .github/workflows/main.yml | 6 ++++-- pyproject.toml | 5 +++-- tox.ini | 24 ++++++++++++++++-------- 3 files changed, 23 insertions(+), 12 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 07853454..6d54fd87 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -28,10 +28,12 @@ jobs: fail-fast: false matrix: include: - - python-version: '3.10' - os: ubuntu-22.04 - python-version: '3.11' os: ubuntu-22.04 + - python-version: '3.12' + os: ubuntu-22.04 + - python-version: '3.13' + os: ubuntu-22.04 runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 diff --git a/pyproject.toml b/pyproject.toml index ae27d940..df7dc9fc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -111,11 +111,12 @@ show_error_context = true error_summary = true files = ["xcp", "tests/test_*.py"] mypy_path = "stubs" -python_version = "3.10" +python_version = "3.11" warn_redundant_casts = true warn_return_any = true warn_unreachable = true warn_unused_configs = true +explicit_package_bases = true disallow_any_unimported = true disallow_any_explicit = false disallow_any_generics = true @@ -206,7 +207,7 @@ stubPath = "stubs" inputs = ["xcp", "tests", "./*.py"] keepgoing = true platform = "linux" -python_version = "3.10" +python_version = "3.11" pythonpath = ".:stubs" disable = ["ignored-type-comment"] overriding_parameter_count_checks = true diff --git a/tox.ini b/tox.ini index 0de3fed6..0491f56e 100644 --- a/tox.ini +++ b/tox.ini @@ -1,11 +1,17 @@ [tox] -# This is the order how tox runs the tests when used interactively during development. -# Run the tests which uncover issues most often first! For example: -# 1. python 2.7 and 3.10 coverage test for changed, but not covered lines and mypy check -# 2. python 3.6 test and pylint warnings from changed lines -# 3. pytype (needs Python 3.8 for best results) -# 4. pyright checks, pytest test report as markdown for GitHub Actions summary -envlist = py38-covcombine-check, py311-lint-test, py310-pytype, py311-pyright-mdreport +# Set the envlist: +# Defines the environments that tox runs by default (when -e is not used) +# +# Default order of execution when using `tox` without `-e `: +# +# 1. pytest using python 3.11 for code coverage with diff-cover and mypy check +# 2. pytype (needs Python 3.10 or newer) +# 3. pylint and pyright checks (any modern Python version is fine) +# +# .github/workflows/main.yml is set up to test with 3.11, 3.12 and 3.13 in parallel. +# Therefore, use three environments: One with 3.11, one with 3.12 and one with 3.13: +# +envlist = py311-covcp-check-mdreport, py312-cov-pytype, py313-cov-lint-pyright isolated_build = true skip_missing_interpreters = true requires = @@ -186,6 +192,8 @@ python = 3.9: py39 3.10: py310 3.11: py311 + 3.12: py312 + 3.13: py313 [check] extras = mypy @@ -207,7 +215,7 @@ commands = deps = pytype pandas commands = - python3.10 -V # Needs python <= 3.10, and 3.10 is needed to parse new "|" syntax + # Needs python >= 3.10: Needed to parse the newer syntax for "Type2 | Type2" pytype --version # Runs pytype -j auto -k --config .github/workflows/pytype.cfg and parses the output: python3 pytype_runner.py # When switching versions, update .github/workflows/pytype.cfg too! From 409325e18c7543fe8a24d899197fb269412b75b8 Mon Sep 17 00:00:00 2001 From: Bernhard Kaindl Date: Fri, 15 Nov 2024 12:00:00 +0100 Subject: [PATCH 08/16] `CONTRIBUTING.md`: Add `venv` setup and using `pipx` Signed-off-by: Bernhard Kaindl --- CONTRIBUTING.md | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8ba18bc9..5d53d115 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,3 +1,14 @@ +# Development setup + +## Create a virtual environment with the test dependencies + +```bash +python -m venv .venv +. .venv/bin/activate +pip install pip-tools==7.3.0 +pip-compile --extra=test,mypy,pyright,pytype,tox -o - pyproject.toml | pip install -r /dev/stdin +``` + ## Development setup on Fedora 37 On Fedora 37, the `tox` rpm installs all Python versions. @@ -6,9 +17,26 @@ But this `tox` is older, so install `tox==4.5.1` using `pip` (see below) ```bash sudo dnf install tox;sudo rpm -e tox ``` +But preferably use `tox` from the virtual environment instead. + +## Development setup on Ubuntu 24.04 + +Prefer the virtual environment. Alternatively, an option is to use `pipx`: + +```bash +sudo apt install pipx +pipx install tox; pipx install 'pytest<7';pipx install pylint +pipx inject pytest pytest-{forked,localftpserver,pythonpath,subprocess,timeout} pyfakefs pytest_httpserver six mock +pipx inject pylint pyfakefs six mock pytest{,_forked,-localftpserver} +``` + +Use the `deadsnakes` ppa to install Python versions like 3.8 and 3.11 (see below) ## Development setup on Ubuntu 22.04 +Usage of to install +other python versions. + ```bash sudo apt update sudo apt install software-properties-common python{2,3}-dev @@ -77,7 +105,7 @@ Using pip-tools, you can extract the requirements and extras from `pyptoject.tom ```bash PYTHON=python3.10 -EXTRAS=.,test,mypy,pytype,tox +EXTRAS=.,test,mypy,pyright,pytype,tox PFLAGS="--no-warn-conflicts" $PYTHON -m pip install pip-tools==7.3.0 $PYTHON -m piptools compile --extra=$EXTRAS -o - pyproject.toml | From 38baca73e76c7c355f47ceaa02fa4b2158119889 Mon Sep 17 00:00:00 2001 From: Bernhard Kaindl Date: Fri, 15 Nov 2024 12:00:00 +0100 Subject: [PATCH 09/16] `tests/test_logger.py`: Use `pyfakefs`: don't create a file in the host Signed-off-by: Bernhard Kaindl --- tests/test_logger.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/tests/test_logger.py b/tests/test_logger.py index a8bb9bfd..3a14521d 100644 --- a/tests/test_logger.py +++ b/tests/test_logger.py @@ -10,8 +10,16 @@ from xcp.logger import openLog -def test_openLog_mock_open(): - """Cover xcp.logger.openLog.open_with_codec_handling and check the arguments used for open()""" +def test_openLog_mock_open(fs): + # type(FakeFilesystem) -> None + """ + - Covers xcp.logger.openLog.open_with_codec_handling and + - checks the arguments it uses for open() + + Because needs to call openLog() which creates a logfile, this test uses + the pytest pyfakefs fixture 'fs' which wraps creating it in a virtual fs. + With it, this tests does not create a log file on the filesystem of the host. + """ fh = StringIO() with patch("xcp.compat.open", mock_open()) as open_mock: open_mock.return_value = fh From 65bd4a991035a27301d1d3af1b39b1c325efe097 Mon Sep 17 00:00:00 2001 From: Bernhard Kaindl Date: Fri, 15 Nov 2024 12:00:00 +0100 Subject: [PATCH 10/16] `.github/workflows/main.yml`: Cleanup obsolete code for Python 2.7/3.8 Signed-off-by: Bernhard Kaindl --- .github/workflows/main.yml | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 6d54fd87..90403a09 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -58,21 +58,6 @@ jobs: pip install 'virtualenv<20.22' 'tox==4.5.1' tox-gh-actions tox --workdir .github/workflows/.tox --recreate - # tox >= 4.0.0 is needed for using optional-dependencies from pyproject.toml, which is - # is not available for python <= 3.6, so use the python3.8 of Ubuntu-20.04 to install it: - - name: Run tox for 3.6 and 3.8 on ${{ matrix.os }}'s 3.8 to get 'extras' from pyproject.toml) - if: ${{ matrix.python-version == 2.7 || matrix.python-version == 3.6 }} - run: | - set -xv;curl -sSL https://bootstrap.pypa.io/get-pip.py -o get-pip.py - python3.8 get-pip.py - # The alternative is installing python3-pip but we don't need full pip function for now: - # sudo apt-get update && sudo apt-get install -y python3-pip - # Let tox-gh-actions get the environment(s) to run tests with from tox.ini: - # Use tox==4.5.1: tox>=4 is needed for reading the extras from pyproject.toml - # Warning: tox>=4.5.2 depends on virutalenv>=20.23, which breaks Python 2.7: - python3.8 -m pip install 'virtualenv<20.22' 'tox==4.5.1' tox-gh-actions - tox --workdir .github/workflows/.tox --recreate - - name: Select the coverage file for upload if: | ( matrix.python-version == '3.6' || matrix.python-version == '3.11' ) && From da3053d90e811fc5aafa2f88e69bb6570b95992f Mon Sep 17 00:00:00 2001 From: Bernhard Kaindl Date: Fri, 15 Nov 2024 12:00:00 +0100 Subject: [PATCH 11/16] `CONTRIBUTING.md`: Fix Markdown format for linting Signed-off-by: Bernhard Kaindl --- CONTRIBUTING.md | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5d53d115..8177a117 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -47,15 +47,18 @@ sudo apt-get install -y python3.{8,11}{,-distutils} Installation of additional python versions for testing different versions: - If `deadsnakes/ppa` does not work, e.g. for Python 3.6, `conda` or `pyenv` can be used. - For instructions, see https://realpython.com/intro-to-pyenv: - ```yaml + For instructions, see : + + ```bash sudo apt install -y build-essential xz-utils zlib1g-dev \ lib{bz2,ffi,lzma,readline,ssl,sqlite3}-dev curl https://pyenv.run | bash # add displayed commands to .bashrc ~/.pyenv/bin/pyenv install 3.{6,8,11} && ~/.pyenv/bin/pyenv local 3.{6,8,11} # builds them ``` + - For testing on newer Ubuntu which has `python2-dev`, but not `pip2`, install `pip2` this way: - ```yml + + ```bash curl https://bootstrap.pypa.io/pip/2.7/get-pip.py --output get-pip.py;sudo python2 get-pip.py ``` @@ -76,14 +79,14 @@ This project uses `tox` to run the tests for different python versions. Intro: > _"Managing a Project's Virtual environments with `tox` - > A comprehensive beginner's introduction to `tox`":_ -> https://www.seanh.cc/2018/09/01/tox-tutorial/ +> -`tox` runs `pytest`, `pylint` and static analysis using `mypy`, `pytype`, and `pyright`. +`tox` runs `pytest`, `pylint` and static analysis using `mypy`, `pyre`, `pytype`, and `pyright`. Links: -- https://mypy.readthedocs.io/en/stable/ -- https://microsoft.github.io/pyright/ -- https://google.github.io/pytype/ +- +- +- With `tox`, developers can run the full test suite for Python 2.7 and 3.x. The same test suite is used in GitHub CI: @@ -140,13 +143,15 @@ pip install "pytest<7" pytest-picked pytest-sugar pytest-clarity # pytest-icdiff ``` To verify or extract the dependencies and extras configured in `pyproject.toml` and `tox.ini` -for specific `tox` environments, you can use https://pypi.org/project/tox-current-env/: +for specific `tox` environments, you can use +: ```bash tox --print-deps-to=pytype-deps.txt --print-extras-to=pytype-extras.txt -e pytype ``` -For more information to debug `pytest` test suites see: https://stribny.name/blog/pytest/ +For more information to debug `pytest` test suites see +: ## Running GitHub actions locally using `act` @@ -204,7 +209,7 @@ docker run -it --rm alpine:latest grep NAME /etc/os-release Ubuntu 22.04 LTS uses `iptables-nft` by default. Switch to `iptables-legacy` so that Docker will work: -https://crapts.org/2022/05/15/install-docker-in-wsl2-with-ubuntu-22-04-lts/ + ### Copy selection on selecting test (without need for Ctrl-C) @@ -213,11 +218,11 @@ to the X selection/clipboard for pasting it. To use this engrained behavior on Windows as well, it seems the only reliable way to have it for all apps is a `AutoHotKey` script: -- https://www.ilovefreesoftware.com/30/tutorial/auto-copy-selected-text-clipboard-windows-10.html +- While individual extensions for VS Code, Firefox, chrome do work partially, they either don't cover the Firefox URL bar, the VS Code terminal and so on: -- https://addons.mozilla.org/en-GB/firefox/addon/copy-on-select -- https://marketplace.visualstudio.com/items?itemName=dinhani.copy-on-select (VS Code) -- https://www.jackofalladmins.com/knowledge%20bombs/dev%20dungeon/windows-terminal-copy-selection/ +- +- (VS Code) +- From 312691d43e13dce5e77ddf7c2832d256d19c48cf Mon Sep 17 00:00:00 2001 From: Bernhard Kaindl Date: Fri, 15 Nov 2024 12:00:00 +0100 Subject: [PATCH 12/16] `README.md`: Fix Markdown format for linting and update it Signed-off-by: Bernhard Kaindl --- README.md | 48 +++++++++++++++++++++--------------------------- 1 file changed, 21 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index fa00abca..b7e5c133 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ +# Common XenServer/XCP-ng Python classes + [![pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit)](https://github.com/pre-commit/pre-commit) [![](https://img.shields.io/badge/python-2.7_%7C_3.6_%7C_3.7_%7C_3.8_%7C_3.9_%7C_3.10_%7C_3.11+-blue.svg)](https://www.python.org/downloads/) [![codecov](https://codecov.io/gh/xenserver/python-libs/branch/master/graph/badge.svg?token=6WKVLDXJFN)](https://codecov.io/gh/xenserver/python-libs) [![](https://img.shields.io/badge/License-BSD--2--Cause%20%26%20MIT-brightgreen)](https://github.com/xenserver/python-libs/blob/master/LICENSE) -# Common XenServer/XCP-ng Python classes - The `xcp` directory contains the Common XenServer and XCP-ng Python packages. They are intented for use in XenServer and XCP-ng Dom0 only and deal with logging, Hardware/PCI, networking, and other Dom0 tasks. @@ -18,6 +18,8 @@ It depends on `six`, and on Python 2.7, also `configparser` and `pyliblzma`. ## Test-driven Development (TDD) Model +Please see [CONTRIBUTING.md] for installing a local development environment. + This package has CI which can be run locally but is also run in GitHub CI to ensure Test-driven development. @@ -81,7 +83,7 @@ For the installation of the general development dependencies, visit [INSTALL.md] The list of `virtualenvs` configured in tox can be shown using this command: `tox -av` -```yaml +```ml $ tox -av default environments: py36-lint -> Run in a py36 virtualenv: Run pylint and fail on warnings remaining on lines in the diff to master @@ -114,17 +116,20 @@ The goal or final benefit would be to have it to ensure internal type correctnes and code quality but also to use static analysis to check the interoperability with the calling code. -## Type annotations: Use Type comments for now! +## Type annotations: Use Type comments for now Python2.7 can't support the type annotation syntax, but until all users are migrated, annotations in comments (type comments) can be used. They are supported by tools like `mypy` and `pyright` (VS Code): -Quoting from https://stackoverflow.com/questions/53306458/python-3-type-hints-in-python-2: +Quoting from : > Function annotations were introduced in [PEP 3107](https://www.python.org/dev/peps/pep-3107/) for Python 3.0. The usage of annotations as type hints was formalized in in [PEP 484](https://www.python.org/dev/peps/pep-0484/) for Python 3.5+. > -> Any version before 3.0 then will not support the syntax you are using for type hints at all. However, PEP 484 [offers a workaround](https://www.python.org/dev/peps/pep-0484/#suggested-syntax-for-python-2-7-and-straddling-code), which some editors may choose to honor. In your case, the hints would look like this: +> Python < 3.0 does support the type hints syntax, but +> [PEP 484](https://www.python.org/dev/peps/pep-0484/#suggested-syntax-for-python-2-7-and-straddling-code) +> introduces type comments that are equally supported and are otherwise ignored. + These type comments look like this: ```py def get_default_device(use_gpu=True): @@ -170,30 +175,19 @@ xcp/xmlunwrap.py Completed in 0.604sec ``` -See https://github.com/xenserver/python-libs/pull/23 for the context of this example. +See for the context of this example. -## Special open TODOs: +## Guidelines Charset encoding/string handling: -See [README-Unicode.md](README-Unicode.md) for details: - -- What's more: When code is called from a xapi plugin (such as ACK), when such code - attempts to read text files like the `pciids` file, and there is a Unicode char - it int, and the locale is not set up to be UTF-8 (because xapi plugins are started - from xapi), the UTF-8 decoder has to be explicitly enabled for these files, - bese by adding `encoding="utf-8"` to the arguments of these specific `open()` calls, - to have valid Unicode text strings, e.g. `xcp.pci`, for regular text processing. -- TODO: More to be opened for all remaining `open()` and `Popen()` users, - as well as ensuring that users of `urllib` are able to work with they bytes - it returns (there is no option to use text mode, data may be gzip-encoded!) +See [README-Unicode.md](README-Unicode.md) for details on Unicode support. ## Users -- https://github.com/xenserver/host-installer - - /opt/xensource/installer/ (has copies of `cpiofile.py`, `repository.py` (with `accessor.py`) -- https://github.com/xcp-ng-rpms/host-upgrade-plugin ([koji](https://koji.xcp-ng.org/packageinfo?packageID=104)): +- [host-installer](https://github.com/xenserver/host-installer) +- [host-upgrade-plugin](https://github.com/xcp-ng-rpms/host-upgrade-plugin) ([koji](https://koji.xcp-ng.org/packageinfo?packageID=104)): - /etc/xapi.d/plugins/prepare_host_upgrade.py -- https://github.com/xapi-project/xen-api (`xapi-core.rpm` and `xenopsd.rpm`) +- [xapi](https://github.com/xapi-project/xen-api) (`xapi-core.rpm` and `xenopsd.rpm`) - /etc/xapi.d/extensions/pool_update.apply - /etc/xapi.d/extensions/pool_update.precheck - /etc/xapi.d/plugins/disk-space @@ -206,16 +200,16 @@ See [README-Unicode.md](README-Unicode.md) for details: - xenserver-release-config/[xcp-ng-release-config](https://koji.xcp-ng.org/rpminfo?rpmID=10250) - /opt/xensource/libexec/fcoe_driver - /opt/xensource/libexec/xen-cmdline -- https://github.com/xcp-ng-rpms/interface-rename: +- - /etc/sysconfig/network-scripts/interface-rename.py - /opt/xensource/bin/interface-rename - pvsproxy (Proprietary) - /usr/libexec/xapi-storage-script/volume/org.xen.xapi.storage.tmpfs/memoryhelper.py -- https://github.com/xenserver/linux-guest-loader (not installed by default anymore) +- (not installed by default anymore) - /opt/xensource/libexec/eliloader.py -- https://github.com/xcp-ng-rpms/vcputune +- - /opt/xensource/bin/host-cpu-tune -- The ACK xenapi plugin see: https://github.com/xenserver/python-libs/pull/21 +- The ACK xapi plugin. See: Verification: From ed504e3c7a7b11693f22121a254613448dbad0b0 Mon Sep 17 00:00:00 2001 From: Bernhard Kaindl Date: Fri, 15 Nov 2024 12:00:00 +0100 Subject: [PATCH 13/16] `README-Unicode.md`: Fix Markdown format for linting and update it Signed-off-by: Bernhard Kaindl --- README-Unicode.md | 61 +++++++++++++++++++++++++++++++++++------------ 1 file changed, 46 insertions(+), 15 deletions(-) diff --git a/README-Unicode.md b/README-Unicode.md index 82e0999f..f38b93ae 100644 --- a/README-Unicode.md +++ b/README-Unicode.md @@ -1,40 +1,64 @@ -Python3 Unicode migration in the XCP package -============================================ +# Python3 Unicode migration in the XCP package + +## Problem + +Python3.6 on XS8 does not have an all-encompassing default UTF-8 mode for I/O. + +Newer Python versions have an UTF-8 mode that they even enable by default. +Python3.6 only enabled UTF-8 for I/O when an UTF-8 locale is used. +See below for more background info on the UTF-8 mode. + +For situations where UTF-8 enabled, we have to specify UTF-8 explicitly. + +Such sitation happens when LANG or LC_* variables are not set for UTF-8. +XAPI plugins like auto-cert-kit find themself in this situation. + +Example: +For reading UTF-8 files like the `pciids` file, add `encoding="utf-8"`. +This applies especailly to `open()` and `Popen()` when files my contain UTF-8. + +This also applies when en/decoding to/form `urllib` which uses bytes. +`urllib` has to use bytes as HTTP data can of course also be binary, e.g. compressed. + +## Migrating `subprocess.Popen()` -Migrating `subprocess.Popen()` ------------------------------- With Python3, the `stdin`, `stdout` and `stderr` pipes for `Popen()` default to `bytes`(binary mode). Binary mode is much safer because it foregoes the encode/decode. The for working with strings, existing users need to either enable text mode (when safe, it will attempt to decode and encode!) or be able to use bytes instead. For cases where the data is guaranteed to be pure ASCII, such as when resting the `proc.stdout` of `lspci -nm`, it is sufficient to use: + ```py open(["lspci, "-nm"], stdout=subprocess.PIPE, universal_newlines=True) ``` + This is possible because `universal_newlines=True` is accepted by Python2 and Python3. On Python3, it also enables text mode for `subprocess.PIPE` streams (newline conversion not needed, but text mode is needed) -Migrating `builtins.open()` ---------------------------- +## Migrating `builtins.open()` + On Python3, `builtins.open()` can be used in a number of modes: + - Binary mode (when `"b"` is in `mode`): `read()` and `write()` use `bytes`. - Text mode (Python3 default up to Python 3.6), when UTF-8 character encoding is not set by the locale -- UTF-8 mode (default since Python 3.7): https://peps.python.org/pep-0540/ +- UTF-8 mode (default since Python 3.7): When no Unicode locale in force, like in XAPI plugins, Python3 will be in text mode or UTF-8 (since Python 3.7, but existing XS is on 3.6): -* By default, `read()` on files `open()`ed without selecting binary mode attempts +- By default, `read()` on files `open()`ed without selecting binary mode attempts to decode the data into the Python3 Unicode string type. This fails for binary data. Any `ord() >= 128`, when no UTF-8 locale is active With Python 3.6, triggers `UnicodeDecodeError`. -* Thus, all `open()` calls which might open binary files have to be converted to binary +- Thus, all `open()` calls which might open binary files have to be converted to binary or UTF-8 mode unless the caller is sure he is opening an ASCII file. But even then, enabling an error handler to handle decoding errors is recommended: + ```py open(filename, errors="replace") ``` + But neither `errors=` nor `encoding=` is accepted by Python2, so a wrapper is likely best. ### Binary mode @@ -43,10 +67,6 @@ When decoding bytes to strings is not needed, binary mode can be great because i However, when strings need to returned from the library, something like `bytes.decode(errors="ignore")` to get strings is needed. -### Text mode - -Text mode using the `ascii` codec should be only used when it is ensured that the data can only consist of ASCII characters (0-127). Sadly, it is the default in Python 3.6 when the Python interpreter was not started using an UTF-8 locale for the LC_CTYPE locale category (set by LC_ALL, LC_CTYPE, LANG environment variables, overriding each other in that order) - ### UTF-8 mode Most if the time, the `UTF-8` codec should be used since even simple text files which are even documented to contain only ASCII characters like `"/usr/share/hwdata/pci.ids"` in fact __do__ contain UTF-8 characters. @@ -54,10 +74,11 @@ Most if the time, the `UTF-8` codec should be used since even simple text files Some files or some output data from commands even contains legacy `ISO-8859-1` chars, and even the `UTF-8` codec would raise `UnicodeDecodeError` for these. When this is known to be the case, `encoding="iso-8859-1` could be tried (not tested yet). -### Problems +### Problems With the locale set to C (XAPI plugins have that), Python's default mode changes between 3.6 and 3.7: + ```py for i in 3.{6,7,10,11};do echo -n "3.$i: "; LC_ALL=C python3.$i -c 'import locale,sys;print(locale.getpreferredencoding())';done @@ -66,7 +87,9 @@ for i in 3.{6,7,10,11};do echo -n "3.$i: "; 3.10: UTF-8 3.11: utf-8 ``` + This has the effect that in Python 3.6, the default codec for XAPI plugins is `ascii`: + ```py for i in 2.7 3.{6,7};do echo "$i:"; LC_ALL=C python$i -c 'open("/usr/share/hwdata/pci.ids").read()';done @@ -79,6 +102,7 @@ Traceback (most recent call last): UnicodeDecodeError: 'ascii' codec can't decode byte 0xc2 in position 97850: ordinal not in range(128) 3.7: ``` + This error means that the `'ascii' codec` cannot handle input ord() >= 128, and as some Video cards use `²` to reference their power, the `ascii` codec chokes on them. It means `xcp.pci.PCIIds()` cannot use `open("/usr/share/hwdata/pci.ids").read()`. @@ -86,6 +110,7 @@ It means `xcp.pci.PCIIds()` cannot use `open("/usr/share/hwdata/pci.ids").read() While Python 3.7 and newer use UTF-8 mode by default, it does not set up an error handler for `UnicodeDecodeError`. As it happens, some older tools output ISO-8859-1 characters hard-coded and these aren't valid UTF-8 sequences, and even newer Python versions need error handlers to not fail: + ```py echo -e "\0262" # ISO-8859-1 for: "²" python3 -c 'open(".text").read()' @@ -133,6 +158,7 @@ tests/test_bootloader.py line 38 in TestLinuxBootloader.setUp() tests/test_pci.py line 96 in TestPCIIds.test_videoclass_by_mock_calls() tests/test_pci.py line 110 in TestPCIIds.mock_lspci_using_open_testfile() ``` + Of course, `xcp/net/ifrename` won't be affected but it would be good to fix the warning for them as well in an intelligent way. See the proposal for that below. @@ -141,6 +167,7 @@ arguments we need to pass to ensure that all users of open() will work, we need to make passing the arguments conditional on Python >= 3. 1. Overriding `open()`, while technically working would not only affect xcp.python but the entire program: + ```py if sys.version_info >= (3, 0): original_open = __builtins__["open"] @@ -152,7 +179,9 @@ to make passing the arguments conditional on Python >= 3. return original_open(*args, **kwargs) __builtins__["open"] = uopen ``` + 2. This is sufficient but is not very nice: + ```py # xcp/utf8mode.py if sys.version_info >= (3, 0): @@ -165,9 +194,11 @@ to make passing the arguments conditional on Python >= 3. - open(filename) + open(filename, **open_utf8args) ``` + But, `pylint` will still warn about these lines, so I propose: 3. Instead, use a wrapper function, which will also silence the `pylint` warnings at the locations which have been changed to use it: + ```py # xcp/utf8mode.py if sys.version_info >= (3, 0): @@ -189,4 +220,4 @@ Using the 3rd option, the `pylint` warnings for the changed locations explicitly disabling them. PS: Since utf8open() still returns a context-manager, `with open(...) as f:` -would still work. \ No newline at end of file +would still work. From a3a83c2429e43badcddde7a9fcf36e279b069d79 Mon Sep 17 00:00:00 2001 From: Bernhard Kaindl Date: Fri, 15 Nov 2024 12:00:00 +0100 Subject: [PATCH 14/16] `.pre-commit-config.yaml`: Replace mdformat check with markdownlint-cli Signed-off-by: Bernhard Kaindl --- .markdownlint.yaml | 259 ++++++++++++++++++++++++++++++++++++++++ .pre-commit-config.yaml | 11 +- CONTRIBUTING.md | 1 + 3 files changed, 268 insertions(+), 3 deletions(-) create mode 100644 .markdownlint.yaml diff --git a/.markdownlint.yaml b/.markdownlint.yaml new file mode 100644 index 00000000..de8a471d --- /dev/null +++ b/.markdownlint.yaml @@ -0,0 +1,259 @@ +# Example markdownlint configuration with all properties set to their default value + +# Default state for all rules +default: true + +# Path to configuration file to extend +extends: null + +# MD001/heading-increment : Heading levels should only increment by one level at a time : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md001.md +MD001: true + +# MD003/heading-style : Heading style : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md003.md +MD003: + # Heading style + style: "consistent" + +# MD004/ul-style : Unordered list style : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md004.md +MD004: + # List style + style: "consistent" + +# MD005/list-indent : Inconsistent indentation for list items at the same level : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md005.md +MD005: true + +# MD007/ul-indent : Unordered list indentation : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md007.md +MD007: + # Spaces for indent + indent: 2 + # Whether to indent the first level of the list + start_indented: false + # Spaces for first level indent (when start_indented is set) + start_indent: 2 + +# MD009/no-trailing-spaces : Trailing spaces : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md009.md +MD009: + # Spaces for line break + br_spaces: 2 + # Allow spaces for empty lines in list items + list_item_empty_lines: false + # Include unnecessary breaks + strict: false + +# MD010/no-hard-tabs : Hard tabs : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md010.md +MD010: + # Include code blocks + code_blocks: true + # Fenced code languages to ignore + ignore_code_languages: [] + # Number of spaces for each hard tab + spaces_per_tab: 1 + +# MD011/no-reversed-links : Reversed link syntax : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md011.md +MD011: true + +# MD012/no-multiple-blanks : Multiple consecutive blank lines : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md012.md +MD012: + # Consecutive blank lines + maximum: 1 + +# MD013/line-length : Line length : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md013.md +MD013: + # Number of characters + line_length: 362 + # Number of characters for headings + heading_line_length: 210 + # Number of characters for code blocks + code_block_line_length: 278 + # Include code blocks + code_blocks: true + # Include tables + tables: true + # Include headings + headings: true + # Strict length checking + strict: false + # Stern length checking + stern: false + +# MD014/commands-show-output : Dollar signs used before commands without showing output : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md014.md +MD014: true + +# MD018/no-missing-space-atx : No space after hash on atx style heading : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md018.md +MD018: true + +# MD019/no-multiple-space-atx : Multiple spaces after hash on atx style heading : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md019.md +MD019: true + +# MD020/no-missing-space-closed-atx : No space inside hashes on closed atx style heading : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md020.md +MD020: true + +# MD021/no-multiple-space-closed-atx : Multiple spaces inside hashes on closed atx style heading : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md021.md +MD021: true + +# MD022/blanks-around-headings : Headings should be surrounded by blank lines : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md022.md +MD022: + # Blank lines above heading + lines_above: 1 + # Blank lines below heading + lines_below: 1 + +# MD023/heading-start-left : Headings must start at the beginning of the line : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md023.md +MD023: true + +# MD024/no-duplicate-heading : Multiple headings with the same content : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md024.md +MD024: + # Only check sibling headings + allow_different_nesting: false + # Only check sibling headings + siblings_only: false + +# MD025/single-title/single-h1 : Multiple top-level headings in the same document : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md025.md +MD025: + # Heading level + level: 1 + # RegExp for matching title in front matter + front_matter_title: "^\\s*title\\s*[:=]" + +# MD026/no-trailing-punctuation : Trailing punctuation in heading : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md026.md +MD026: + # Punctuation characters + punctuation: ".,;:!。,;:!" + +# MD027/no-multiple-space-blockquote : Multiple spaces after blockquote symbol : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md027.md +MD027: true + +# MD028/no-blanks-blockquote : Blank line inside blockquote : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md028.md +MD028: true + +# MD029/ol-prefix : Ordered list item prefix : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md029.md +MD029: + # List style + style: "one_or_ordered" + +# MD030/list-marker-space : Spaces after list markers : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md030.md +MD030: + # Spaces for single-line unordered list items + ul_single: 1 + # Spaces for single-line ordered list items + ol_single: 1 + # Spaces for multi-line unordered list items + ul_multi: 1 + # Spaces for multi-line ordered list items + ol_multi: 1 + +# MD031/blanks-around-fences : Fenced code blocks should be surrounded by blank lines : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md031.md +MD031: + # Include list items + list_items: true + +# MD032/blanks-around-lists : Lists should be surrounded by blank lines : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md032.md +MD032: true + +# MD033/no-inline-html : Inline HTML : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md033.md +MD033: + # Allowed elements + allowed_elements: [img, kbd] + +# MD034/no-bare-urls : Bare URL used : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md034.md +MD034: true + +# MD035/hr-style : Horizontal rule style : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md035.md +MD035: + # Horizontal rule style + style: "consistent" + +# MD036/no-emphasis-as-heading : Emphasis used instead of a heading : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md036.md +MD036: + # Punctuation characters + punctuation: ".,;:!?。,;:!?" + +# MD037/no-space-in-emphasis : Spaces inside emphasis markers : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md037.md +MD037: true + +# MD038/no-space-in-code : Spaces inside code span elements : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md038.md +MD038: true + +# MD039/no-space-in-links : Spaces inside link text : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md039.md +MD039: true + +# MD040/fenced-code-language : Fenced code blocks should have a language specified : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md040.md +MD040: + # List of languages + allowed_languages: [] + # Require language only + language_only: false + +# MD041/first-line-heading/first-line-h1 : First line in a file should be a top-level heading : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md041.md +MD041: + # Heading level + level: 1 + # RegExp for matching title in front matter + front_matter_title: "^\\s*title\\s*[:=]" + +# MD042/no-empty-links : No empty links : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md042.md +MD042: true + +# MD044/proper-names : Proper names should have the correct capitalization : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md044.md +MD044: + # List of proper names + names: [] + # Include code blocks + code_blocks: true + # Include HTML elements + html_elements: true + +# MD045/no-alt-text : Images should have alternate text (alt text) : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md045.md +MD045: false + +# MD046/code-block-style : Code block style : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md046.md +MD046: + # Block style + style: "consistent" + +# MD047/single-trailing-newline : Files should end with a single newline character : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md047.md +MD047: true + +# MD048/code-fence-style : Code fence style : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md048.md +MD048: + # Code fence style + style: "consistent" + +# MD049/emphasis-style : Emphasis style : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md049.md +MD049: + # Emphasis style + style: "consistent" + +# MD050/strong-style : Strong style : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md050.md +MD050: + # Strong style + style: "consistent" + +# MD051/link-fragments : Link fragments should be valid : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md051.md +MD051: true + +# MD052/reference-links-images : Reference links and images should use a label that is defined : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md052.md +MD052: + # Include shortcut syntax + shortcut_syntax: false + +# MD053/link-image-reference-definitions : Link and image reference definitions should be needed : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md053.md +MD053: + # Ignored definitions + ignored_definitions: + - "//" + +# MD054/link-image-style : Link and image style : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md054.md +MD054: + # Allow autolinks + autolink: true + # Allow inline links and images + inline: true + # Allow full reference links and images + full: true + # Allow collapsed reference links and images + collapsed: true + # Allow shortcut reference links and images + shortcut: true + # Allow URLs as inline links + url_inline: true diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 36b678db..917040ce 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -77,9 +77,14 @@ repos: rev: v0.1.9 hooks: - id: shellcheck - - id: mdformat-check - exclude: README-Unicode.md - language: python + + +- repo: https://github.com/igorshubovych/markdownlint-cli + rev: v0.42.0 + hooks: + - id: markdownlint + + - repo: https://github.com/pycqa/pylint rev: v2.17.4 hooks: diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8177a117..d10150d6 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -17,6 +17,7 @@ But this `tox` is older, so install `tox==4.5.1` using `pip` (see below) ```bash sudo dnf install tox;sudo rpm -e tox ``` + But preferably use `tox` from the virtual environment instead. ## Development setup on Ubuntu 24.04 From 2be5adae62e98b984188468a1d85e90b1d8862cc Mon Sep 17 00:00:00 2001 From: Bernhard Kaindl Date: Fri, 15 Aug 2025 12:00:00 +0200 Subject: [PATCH 15/16] pytest.ini: Support newer pytest versions (>=7) to fix errors devs face Signed-off-by: Bernhard Kaindl --- pyproject.toml | 3 +-- pytest.ini | 26 +++++++------------------- tests/conftest.py | 2 +- tox.ini | 1 + 4 files changed, 10 insertions(+), 22 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index df7dc9fc..9b25f035 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -47,13 +47,12 @@ dependencies = [ test = [ "mock", "pyfakefs", - "pytest<7", + "pytest>=7", "pytest-cov", "pytest-forked", "pytest_httpserver; python_version >= '3.7'", "pytest-localftpserver; python_version >= '3.7'", "pytest-localftpserver==0.5.1; python_version <= '3.6'", - "pytest-pythonpath", "pytest-subprocess; python_version >= '3.6'", "pytest-timeout", "typing_extensions" diff --git a/pytest.ini b/pytest.ini index 0906991a..6c737ec0 100644 --- a/pytest.ini +++ b/pytest.ini @@ -1,19 +1,14 @@ ############################################################################### -# pytest.ini for pytest<=6 to be compatible with Python 2.7. Install command: -# pip install pytest<7 -############################################################################### -# To use pytest>=7, disable "python_paths" below. +# Configuration file for pytest: +# Compatibility with pytest 6.x for Python 2.7 has been dropped, needs pytest>7 +# +# See https://docs.pytest.org for documentation on pytest. ############################################################################### [pytest] -# These are the most of the needed pytest plugins, unfortunately this list does -# not support ;python_version<=3.0 or ;python_version>3.0. Therefore, it can -# only list plugins available for all tested python versions (2.7, 3.6 ... 3.11): -# pytest-localftpserver is also used, but its installation is not checked -# to to its installation not being detected on Ubuntu 24.04: required_plugins = pytest_httpserver + pytest_localftpserver pytest-forked - pytest-pythonpath pytest-subprocess pytest-timeout pyfakefs @@ -30,13 +25,6 @@ timeout=30 log_cli=True log_cli_level=INFO # -# Only effective for pytest<7: Don't warn about new configs for pytest>7: -filterwarnings=ignore:Unknown config option -# # Add directory to find the example branding.py (needed by bootloader.py) in ./stubs: -# -# Used by for pytest >= 7.0.0 (only available for Python >= 3.0): -pythonpath=stubs -# Disable when using pytest >= 7.0.0: -# Used by pytest-pythonpath for Python >=2.7 (https://pypi.org/project/pytest-pythonpath): -python_paths=stubs +# (Requires pytest >= 7.0.0): +pythonpath=stubs \ No newline at end of file diff --git a/tests/conftest.py b/tests/conftest.py index da395853..af45ca25 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -28,7 +28,7 @@ def set_warnings(): run-time checking during tests. By additionally using setenv = PYTHONWARNINGS=ignore in tox.ini, - we can disabling the Deprecation warnings wihch pytest plugins exhibit + we can disable the Deprecation warnings which pytest plugins exhibit (which we are not interested in, those are not our responsiblity). and this fixture will still enable the default warning filter to have e.g. ResourceWarning checks enabled. diff --git a/tox.ini b/tox.ini index 0491f56e..86356801 100644 --- a/tox.ini +++ b/tox.ini @@ -163,6 +163,7 @@ deps = pylint diff-cover pandas tabulate + toml commands = python pylint_runner.py xcp tests diff-quality --compare-branch=origin/master --violations=pylint \ From de4fd89aa760574477e714e301a636a8f6fafc42 Mon Sep 17 00:00:00 2001 From: Bernhard Kaindl Date: Fri, 15 Aug 2025 12:00:00 +0200 Subject: [PATCH 16/16] tox.ini: Fix choking on venvs with symlink to dirs: skip untracked files Signed-off-by: Bernhard Kaindl --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 86356801..535d80ec 100644 --- a/tox.ini +++ b/tox.ini @@ -131,7 +131,7 @@ commands = coverage html -d {envlogdir}/htmlcov coverage html -d {envlogdir}/htmlcov-tests --fail-under {env:TESTS_COV_MIN:96} \ --include="tests/*" - diff-cover --compare-branch=origin/master --include-untracked \ + diff-cover --compare-branch=origin/master \ {env:PY3_DIFFCOVER_OPTIONS} --fail-under {env:DIFF_COV_MIN:92} \ --html-report {envlogdir}/coverage-diff.html \ {envlogdir}/coverage.xml