Source code for extra_platforms.pytest
# Copyright Kevin Deldycke <kevin@deldycke.com> and contributors.
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
"""Pytest decorators to skip tests depending on the platform they're run on.
Generates a pair of ready-to-use ``@skip_<id>`` and ``@unless_<id>`` decorators for
each platform and group.
"""
from __future__ import annotations
try:
import pytest # noqa: F401
except ImportError:
raise ImportError(
"You need to install extra_platforms[pytest] extra dependencies to use this "
"module."
)
from itertools import chain
import extra_platforms
from .group import Group
from .group_data import ALL_GROUPS, ALL_PLATFORMS
from .platform import Platform
TYPE_CHECKING = False
if TYPE_CHECKING:
from collections.abc import Callable
from _pytest.mark.structures import MarkDecorator
[docs]
class DeferredCondition:
"""Defer the evaluation of a condition.
This allow a callable returning a boolean to be evaluated only when the boolean
value is requested.
Pytest's marks can have a condition attached to them. Which is practical for
implementing our own ready-to-use ``@skip`` and ``@unless`` decorators.
The problem is: this condition is evaluated at import time. Which leads to all our
platform detection heuristics to be called when we generates our custom decorators
below.
This issue is being discussed upstream at:
- https://github.com/pytest-dev/pytest/issues/7395
- https://github.com/pytest-dev/pytest/issues/9650
"""
def __init__(self, condition: Callable[[], bool], invert: bool = False) -> None:
self.condition = condition
self.invert = invert
def __bool__(self) -> bool:
"""Call the deferred condition and return its result."""
result = self.condition()
return not result if self.invert else result
# Generate a pair of skip/unless decorators for each platform and group.
for _obj in chain(ALL_PLATFORMS, ALL_GROUPS):
# Sanity check to please the type checker.
assert isinstance(_obj, (Platform, Group))
# Get the detection function for the current object.
_func = getattr(extra_platforms, f"is_{_obj.id}")
# Generate @skip decorator.
globals()[f"skip_{_obj.id}"] = pytest.mark.skipif(
DeferredCondition(_func), # type: ignore[arg-type]
reason=f"Skip {_obj.short_desc}",
)
# Generate @unless decorator.
globals()[f"unless_{_obj.id}"] = pytest.mark.skipif(
DeferredCondition(_func, invert=True), # type: ignore[arg-type]
reason=f"Requires {_obj.short_desc}",
)
# XXX Mypy doesn't understand dynamic type annotation, so we need to explicitly declare
# all generated decorators after their generation.
# These annotations are checked and enforced in unittests.
if TYPE_CHECKING:
skip_aix: MarkDecorator
skip_all_platforms: MarkDecorator
skip_all_platforms_without_ci: MarkDecorator
skip_altlinux: MarkDecorator
skip_amzn: MarkDecorator
skip_android: MarkDecorator
skip_any_windows: MarkDecorator
skip_arch: MarkDecorator
skip_azure_pipelines: MarkDecorator
skip_bamboo: MarkDecorator
skip_bsd: MarkDecorator
skip_bsd_without_macos: MarkDecorator
skip_buildkite: MarkDecorator
skip_buildroot: MarkDecorator
skip_cachyos: MarkDecorator
skip_centos: MarkDecorator
skip_ci: MarkDecorator
skip_circle_ci: MarkDecorator
skip_cirrus_ci: MarkDecorator
skip_cloudlinux: MarkDecorator
skip_codebuild: MarkDecorator
skip_cygwin: MarkDecorator
skip_debian: MarkDecorator
skip_exherbo: MarkDecorator
skip_fedora: MarkDecorator
skip_freebsd: MarkDecorator
skip_gentoo: MarkDecorator
skip_github_ci: MarkDecorator
skip_gitlab_ci: MarkDecorator
skip_guix: MarkDecorator
skip_heroku_ci: MarkDecorator
skip_hurd: MarkDecorator
skip_ibm_powerkvm: MarkDecorator
skip_kvmibm: MarkDecorator
skip_linux: MarkDecorator
skip_linux_layers: MarkDecorator
skip_linux_like: MarkDecorator
skip_linuxmint: MarkDecorator
skip_macos: MarkDecorator
skip_mageia: MarkDecorator
skip_mandriva: MarkDecorator
skip_midnightbsd: MarkDecorator
skip_netbsd: MarkDecorator
skip_nobara: MarkDecorator
skip_openbsd: MarkDecorator
skip_opensuse: MarkDecorator
skip_oracle: MarkDecorator
skip_other_unix: MarkDecorator
skip_parallels: MarkDecorator
skip_pidora: MarkDecorator
skip_raspbian: MarkDecorator
skip_rhel: MarkDecorator
skip_rocky: MarkDecorator
skip_scientific: MarkDecorator
skip_slackware: MarkDecorator
skip_sles: MarkDecorator
skip_solaris: MarkDecorator
skip_sunos: MarkDecorator
skip_system_v: MarkDecorator
skip_teamcity: MarkDecorator
skip_travis_ci: MarkDecorator
skip_tumbleweed: MarkDecorator
skip_tuxedo: MarkDecorator
skip_ubuntu: MarkDecorator
skip_ultramarine: MarkDecorator
skip_unix: MarkDecorator
skip_unix_layers: MarkDecorator
skip_unix_without_macos: MarkDecorator
skip_unknown_ci: MarkDecorator
skip_unknown_linux: MarkDecorator
skip_windows: MarkDecorator
skip_wsl1: MarkDecorator
skip_wsl2: MarkDecorator
skip_xenserver: MarkDecorator
unless_aix: MarkDecorator
unless_all_platforms: MarkDecorator
unless_all_platforms_without_ci: MarkDecorator
unless_altlinux: MarkDecorator
unless_amzn: MarkDecorator
unless_android: MarkDecorator
unless_any_windows: MarkDecorator
unless_arch: MarkDecorator
unless_azure_pipelines: MarkDecorator
unless_bamboo: MarkDecorator
unless_bsd: MarkDecorator
unless_bsd_without_macos: MarkDecorator
unless_buildkite: MarkDecorator
unless_buildroot: MarkDecorator
unless_cachyos: MarkDecorator
unless_centos: MarkDecorator
unless_ci: MarkDecorator
unless_circle_ci: MarkDecorator
unless_cirrus_ci: MarkDecorator
unless_cloudlinux: MarkDecorator
unless_codebuild: MarkDecorator
unless_cygwin: MarkDecorator
unless_debian: MarkDecorator
unless_exherbo: MarkDecorator
unless_fedora: MarkDecorator
unless_freebsd: MarkDecorator
unless_gentoo: MarkDecorator
unless_github_ci: MarkDecorator
unless_gitlab_ci: MarkDecorator
unless_guix: MarkDecorator
unless_heroku_ci: MarkDecorator
unless_hurd: MarkDecorator
unless_ibm_powerkvm: MarkDecorator
unless_kvmibm: MarkDecorator
unless_linux: MarkDecorator
unless_linux_layers: MarkDecorator
unless_linux_like: MarkDecorator
unless_linuxmint: MarkDecorator
unless_macos: MarkDecorator
unless_mageia: MarkDecorator
unless_mandriva: MarkDecorator
unless_midnightbsd: MarkDecorator
unless_netbsd: MarkDecorator
unless_nobara: MarkDecorator
unless_openbsd: MarkDecorator
unless_opensuse: MarkDecorator
unless_oracle: MarkDecorator
unless_other_unix: MarkDecorator
unless_parallels: MarkDecorator
unless_pidora: MarkDecorator
unless_raspbian: MarkDecorator
unless_rhel: MarkDecorator
unless_rocky: MarkDecorator
unless_scientific: MarkDecorator
unless_slackware: MarkDecorator
unless_sles: MarkDecorator
unless_solaris: MarkDecorator
unless_sunos: MarkDecorator
unless_system_v: MarkDecorator
unless_teamcity: MarkDecorator
unless_travis_ci: MarkDecorator
unless_tumbleweed: MarkDecorator
unless_tuxedo: MarkDecorator
unless_ubuntu: MarkDecorator
unless_ultramarine: MarkDecorator
unless_unix: MarkDecorator
unless_unix_layers: MarkDecorator
unless_unix_without_macos: MarkDecorator
unless_unknown_ci: MarkDecorator
unless_unknown_linux: MarkDecorator
unless_windows: MarkDecorator
unless_wsl1: MarkDecorator
unless_wsl2: MarkDecorator
unless_xenserver: MarkDecorator