On 2025-06-23, Michał Górny wrote:
> Introduce a new EPYTEST_PLUGINS variable that can be used to control
> which plugins are used by epytest.  It provides a convenient method
> to disable plugin autoloading, as well as specify which plugins to load.
> It accepts package names, and includes a mapping from package names
> to `-p` argumetns for a number of plugins currently in ::gentoo.

Is hardcoding plugin names the only way to match them with package 
names?  Couldn't it be also done by parsing entry_points.txt?
 
> Signed-off-by: Michał Górny <[email protected]>
> ---
>  eclass/python-utils-r1.eclass | 139 +++++++++++++++++++++++++++++++++-
>  1 file changed, 138 insertions(+), 1 deletion(-)
> 
> diff --git a/eclass/python-utils-r1.eclass b/eclass/python-utils-r1.eclass
> index 83727468b603..44746c4d296d 100644
> --- a/eclass/python-utils-r1.eclass
> +++ b/eclass/python-utils-r1.eclass
> @@ -1273,6 +1273,78 @@ _python_check_occluded_packages() {
>  # parameter, when calling epytest.  The listed files will be entirely
>  # skipped from test collection.
>  
> +# @ECLASS_VARIABLE: EPYTEST_PLUGINS
> +# @DEFAULT_UNSET
> +# @DESCRIPTION:
> +# An array of pytest plugin package names (without categories) to use
> +# for the package.  It has a twofold purpose:
> +#
> +# 1. When set prior to calling distutils_enable_tests, it causes
> +#    dependencies on the specified pytest plugins to be added.
> +#
> +# 2. When plugin autoloading is disabled, it causes "-p" arguments
> +#    loading specified plugins to be added.
> +#
> +# Defaults to an empty list.
> +#
> +# The eclasses explicitly handle a number of pytest plugins, and assume
> +# the default of "dev-python/${package}" and "-p ${package}" for others.
> +# If this is incorrect for some plugin package, please report a bug
> +# to have it added.
> +#
> +# This is not a perfect solution, and may not be sufficient for some
> +# packages.  In these cases, either plugin autoloading should be used
> +# or PYTEST_PLUGINS environment variable may be used directly (see
> +# pytest documentation).
> +#
> +# For pytest-timeout and pytest-xdist plugins, it is generally
> +# preferable to use EPYTEST_TIMEOUT and EPYTEST_XDIST options
> +# that handle passing all needed options.
> +
> +# @ECLASS_VARIABLE: EPYTEST_PLUGIN_AUTOLOAD
> +# @DEFAULT_UNSET
> +# @DESCRIPTION:
> +# If set to a non-empty value, permits pytest plugin autoloading.
> +# Otherwise, PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 is set to disable it.
> +#
> +# If EPYTEST_PLUGINS is set explicitly or EAPI is 9 or later,
> +# defaults to disabled.  Otherwise, defaults to enabled.
> +# The recommended way to disable it in EAPI 8 or earlier is to set
> +# EPYTEST_PLUGINS (possibly to an empty array).
> +
> +# @FUNCTION: _set_epytest_plugins
> +# @INTERNAL
> +# @DESCRIPTION:
> +# Check if EPYTEST_PLUGINS is set correctly, and set the default
> +# if it is not.
> +_set_epytest_plugins() {
> +       debug-print-function ${FUNCNAME} "$@"
> +
> +       # TODO: drop BASH_VERSINFO check when we require EAPI 8
> +       if [[ ${BASH_VERSINFO[0]} -ge 5 ]]; then
> +               [[ ${EPYTEST_PLUGINS@a} == *a* ]]
> +       else
> +               [[ $(declare -p EPYTEST_PLUGINS) == "declare -a"* ]]
> +       fi
> +       if [[ ${?} -eq 0 ]]; then
> +               # EPYTEST_PLUGINS set explicitly -- disable autoloading
> +               : "${EPYTEST_PLUGIN_AUTOLOAD:=}"
> +       else
> +               if ! declare -p EPYTEST_PLUGINS &>/dev/null; then
> +                       # EPYTEST_PLUGINS unset -- default to empty.
> +                       # EPYTEST_PLUGIN_AUTOLOAD default depends on EAPI.
> +                       EPYTEST_PLUGINS=()
> +                       if [[ ${EAPI} != [78] ]]; then
> +                               : "${EPYTEST_PLUGIN_AUTOLOAD:=}"
> +                       else
> +                               : "${EPYTEST_PLUGIN_AUTOLOAD:=1}"
> +                       fi
> +               else
> +                       die 'EPYTEST_PLUGINS must be an array.'
> +               fi
> +       fi
> +}
> +
>  # @ECLASS_VARIABLE: EPYTEST_TIMEOUT
>  # @DEFAULT_UNSET
>  # @DESCRIPTION:
> @@ -1363,7 +1435,72 @@ epytest() {
>                 )
>         fi
>  
> -       if [[ ! ${PYTEST_DISABLE_PLUGIN_AUTOLOAD} ]]; then
> +       _set_epytest_plugins
> +       if [[ ! ${EPYTEST_PLUGIN_AUTOLOAD} ]]; then
> +               local -x PYTEST_DISABLE_PLUGIN_AUTOLOAD=1
> +       fi
> +
> +       if [[ ${PYTEST_DISABLE_PLUGIN_AUTOLOAD} ]]; then
> +               local plugin
> +               for plugin in "${EPYTEST_PLUGINS[@]}"; do
> +                       case ${plugin} in
> +                               # special cases
> +                               hypothesis)
> +                                       plugin=hypothesispytest
> +                                       ;;
> +                               noseofyeti)
> +                                       plugin=nose_of_yeti
> +                                       ;;
> +                               pytest-helpers-namespace)
> +                                       plugin=helpers_namespace
> +                                       ;;
> +                               pytest-lazy-fixtures)
> +                                       plugin=pytest_lazyfixture
> +                                       ;;
> +                               pytest-testinfra)
> +                                       plugin=pytest11.testinfra
> +                                       ;;
> +                               # "generic" cases
> +                               betamax)
> +                                       plugin=pytest-${plugin}
> +                                       ;;
> +                               pyfakefs)
> +                                       plugin=pytest_${plugin}
> +                                       ;;
> +                               # pytest-x-y-z -> x-y-z
> +                               pytest-aiohttp|pytest-asyncio|pytest-check)
> +                                       ;&
> +                               
> pytest-console-scripts|pytest-django|pytest-env)
> +                                       ;&
> +                               pytest-freezer|pytest-home|pytest-httpbin)
> +                                       ;&
> +                               pytest-import-check|pytest-localftpserver)
> +                                       ;&
> +                               
> pytest-localserver|pytest-plus|pytest-recording)
> +                                       ;&
> +                               
> pytest-regressions|pytest-repeat|pytest-reraise)
> +                                       ;&
> +                               
> pytest-rerunfailures|pytest-reserial|pytest-shell-utilities)
> +                                       ;&
> +                               
> pytest-skip-markers|pytest-subtests|pytest-timeout)
> +                                       ;&
> +                               
> pytest-tornasync|pytest-trio|pytext-xdist|pytest-xprocess)
> +                                       ;&
> +                               pytest-xprocess|pytest-xvfb)
> +                                       plugin=${plugin#pytest-}
> +                                       ;;
> +                               # foo-bar-baz unchanged
> +                               pytest-datadir|pytest-qt|pytest-subprocess)
> +                                       ;;
> +                               # foo-bar-baz -> foo_bar_baz
> +                               *)
> +                                       plugin=${plugin//-/_}
> +                                       ;;
> +                       esac
> +
> +                       args+=( -p "${plugin}" )
> +               done
> +       else
>                 args+=(
>                         # disable the undesirable-dependency plugins by 
> default to
>                         # trigger missing argument strips.  strip options 
> that require
> 
> 

Reply via email to