pytestCheckHook: support __structuredAttrs

Add flag pytestFlags as the new, conforming interface
replacing pytestFlagsArray.

Stop Bash-expanding disabledTests and disabledTestPaths.

Handle disabledTestPaths with `pytest --ignore-glob <path>`
to keep globbing support.
Check if each path glob matches at least one path
using the `glob` module from the Python standard library.

Also make buildPythonPackage and buildPythonApplication
stop escaping the elements of disabledTests and disabledTestPaths.
This commit is contained in:
Yueh-Shun Li 2024-10-09 18:14:29 +08:00
parent e8f3fe8c6e
commit 26f09762a8
3 changed files with 40 additions and 24 deletions

View file

@ -1273,7 +1273,7 @@ Using the example above, the analogous `pytestCheckHook` usage would be:
];
# requires additional data
pytestFlagsArray = [
pytestFlags = [
"tests/"
"--ignore=tests/integration"
];
@ -2002,7 +2002,7 @@ Occasionally packages don't make use of a common test framework, which may then
* Non-working tests can often be deselected. Most Python modules
do follow the standard test protocol where the pytest runner can be used.
`pytest` supports the `-k` and `--ignore` parameters to ignore test
`pytest` supports the `-k` and `--ignore-glob` parameters to ignore test
methods or classes as well as whole files. For `pytestCheckHook` these are
conveniently exposed as `disabledTests` and `disabledTestPaths` respectively.
@ -2019,11 +2019,17 @@ Occasionally packages don't make use of a common test framework, which may then
];
disabledTestPaths = [
"this/file.py"
"path/to/performance.py"
"path/to/connect-*.py"
];
}
```
::: {.note}
If the test path to disable contains characters like `*`, `?`, `[`, and `]`,
quote them with square brackets (`[*]`, `[?]`, `[[]`, and `[]]`) to match literally.
:::
* Tests that attempt to access `$HOME` can be fixed by using the following
work-around before running tests (e.g. `preCheck`): `export HOME=$(mktemp -d)`
* Compiling with Cython causes tests to fail with a `ModuleNotLoadedError`.

View file

@ -1,33 +1,41 @@
# Setup hook for pytest
echo "Sourcing pytest-check-hook"
declare -ar disabledTests
declare -a disabledTestPaths
echo "Sourcing pytest-check-hook"
function pytestCheckPhase() {
echo "Executing pytestCheckPhase"
runHook preCheck
# Compose arguments
args=" -m pytest"
if [ -n "$disabledTests" ]; then
local -a flagsArray=(-m pytest)
if [ -n "${disabledTests[*]-}" ]; then
disabledTestsString="not $(concatStringsSep " and not " disabledTests)"
args+=" -k \""$disabledTestsString"\""
flagsArray+=(-k "$disabledTestsString")
fi
if [ -n "${disabledTestPaths-}" ]; then
eval "disabledTestPaths=($disabledTestPaths)"
fi
for path in ${disabledTestPaths[@]}; do
if [ ! -e "$path" ]; then
echo "Disabled tests path \"$path\" does not exist. Aborting"
exit 1
fi
args+=" --ignore=\"$path\""
local -a _pathsArray=()
concatTo _pathsArray disabledTestPaths
for path in "${_pathsArray[@]}"; do
# Check if every path glob matches at least one path
@pythonCheckInterpreter@ <(cat <<EOF
import glob
import sys
path_glob=sys.argv[1]
if not len(path_glob):
sys.exit('Got an empty disabled tests path glob. Aborting')
if next(glob.iglob(path_glob), None) is None:
sys.exit('Disabled tests path glob "{}" does not match any paths. Aborting'.format(path_glob))
EOF
) "$path"
flagsArray+=("--ignore-glob=$path")
done
args+=" ${pytestFlagsArray[@]}"
eval "@pythonCheckInterpreter@ $args"
# Compatibility layer to the obsolete pytestFlagsArray
eval "flagsArray+=(${pytestFlagsArray[*]-})"
concatTo flagsArray pytestFlags
echoCmd 'pytest flags' "${flagsArray[@]}"
@pythonCheckInterpreter@ "${flagsArray[@]}"
runHook postCheck
echo "Finished executing pytestCheckPhase"

View file

@ -106,6 +106,7 @@ let
"format"
"disabledTestPaths"
"disabledTests"
"pytestFlags"
"pytestFlagsArray"
"unittestFlagsArray"
"outputs"
@ -434,13 +435,14 @@ let
}
// optionalAttrs (attrs.doCheck or true) (
optionalAttrs (disabledTestPaths != [ ]) {
disabledTestPaths = escapeShellArgs disabledTestPaths;
disabledTestPaths = disabledTestPaths;
}
// optionalAttrs (attrs ? disabledTests) {
# `escapeShellArgs` should be used as well as `disabledTestPaths`,
# but some packages rely on existing raw strings.
disabledTests = attrs.disabledTests;
}
// optionalAttrs (attrs ? pytestFlags) {
pytestFlags = attrs.pytestFlags;
}
// optionalAttrs (attrs ? pytestFlagsArray) {
pytestFlagsArray = attrs.pytestFlagsArray;
}