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