|
31 | 31 | # stdlib
|
32 | 32 | import itertools
|
33 | 33 | import random
|
| 34 | +import sys |
34 | 35 | from functools import lru_cache
|
35 |
| -from typing import Any, Iterator, List, Sequence |
| 36 | +from typing import Any, Iterator, List, Optional, Sequence, Tuple, Union |
36 | 37 |
|
37 | 38 | # 3rd party
|
| 39 | +import _pytest |
38 | 40 | import pytest
|
39 | 41 | from _pytest.mark import MarkDecorator
|
40 | 42 |
|
41 | 43 | # this package
|
| 44 | +from domdf_python_tools.doctools import PYPY |
42 | 45 | from domdf_python_tools.utils import Len
|
| 46 | +from domdf_python_tools.versions import Version |
43 | 47 |
|
44 | 48 | __all__ = [
|
45 | 49 | "generate_truthy_values",
|
|
49 | 53 | "whitespace_perms_list",
|
50 | 54 | "whitespace_perms",
|
51 | 55 | "count",
|
| 56 | + "min_version", |
| 57 | + "max_version", |
| 58 | + "not_windows", |
| 59 | + "only_windows", |
| 60 | + "not_pypy", |
| 61 | + "only_pypy", |
52 | 62 | ]
|
53 | 63 |
|
54 | 64 |
|
@@ -199,3 +209,110 @@ def count(stop: int, start: int = 0, step: int = 1) -> MarkDecorator:
|
199 | 209 | """
|
200 | 210 |
|
201 | 211 | return pytest.mark.parametrize("count", range(start, stop, step))
|
| 212 | + |
| 213 | + |
| 214 | +def _make_version(version: Union[str, float, Tuple[int, ...]]) -> Version: |
| 215 | + if isinstance(version, float): |
| 216 | + return Version.from_float(version) |
| 217 | + elif isinstance(version, str): |
| 218 | + return Version.from_str(version) |
| 219 | + else: |
| 220 | + return Version.from_tuple(version) |
| 221 | + |
| 222 | + |
| 223 | +def min_version( |
| 224 | + version: Union[str, float, Tuple[int]], |
| 225 | + reason: Optional[str] = None, |
| 226 | + ) -> _pytest.mark.structures.MarkDecorator: |
| 227 | + """ |
| 228 | + Factory function to return a ``@pytest.mark.skipif`` decorator that will |
| 229 | + skip a test if the current Python version is less than the required one. |
| 230 | +
|
| 231 | + :param version: The version number to compare to :py:data:`sys.version_info`. |
| 232 | + :param reason: The reason to display when skipping. |
| 233 | + :default reason: ``'Requires Python <version> or greater.'`` |
| 234 | +
|
| 235 | + .. versionadded:: 0.9.0 |
| 236 | + """ |
| 237 | + |
| 238 | + version_ = _make_version(version) |
| 239 | + |
| 240 | + if reason is None: |
| 241 | + reason = f"Requires Python {version_} or greater." |
| 242 | + |
| 243 | + return pytest.mark.skipif(condition=sys.version_info[:3] < version_, reason=reason) |
| 244 | + |
| 245 | + |
| 246 | +def max_version( |
| 247 | + version: Union[str, float, Tuple[int]], |
| 248 | + reason: Optional[str] = None, |
| 249 | + ) -> _pytest.mark.structures.MarkDecorator: |
| 250 | + """ |
| 251 | + Factory function to return a ``@pytest.mark.skipif`` decorator that will |
| 252 | + skip a test if the current Python version is greater than the required one. |
| 253 | +
|
| 254 | + :param version: The version number to compare to :py:data:`sys.version_info`. |
| 255 | + :param reason: The reason to display when skipping. |
| 256 | + :default reason: ``'Not needed after Python <version>.'`` |
| 257 | +
|
| 258 | + .. versionadded:: 0.9.0 |
| 259 | + """ |
| 260 | + |
| 261 | + version_ = _make_version(version) |
| 262 | + |
| 263 | + if reason is None: |
| 264 | + reason = f"Not needed after Python {version_}." |
| 265 | + |
| 266 | + return pytest.mark.skipif(condition=sys.version_info[:3] > version_, reason=reason) |
| 267 | + |
| 268 | + |
| 269 | +def not_windows(reason: str = "Not required on Windows.", ) -> _pytest.mark.structures.MarkDecorator: |
| 270 | + """ |
| 271 | + Factory function to return a ``@pytest.mark.skipif`` decorator that will |
| 272 | + skip a test if the current platform is Windows. |
| 273 | +
|
| 274 | + :param reason: The reason to display when skipping. |
| 275 | +
|
| 276 | + .. versionadded:: 0.9.0 |
| 277 | + """ |
| 278 | + |
| 279 | + return pytest.mark.skipif(condition=sys.platform == "win32", reason=reason) |
| 280 | + |
| 281 | + |
| 282 | +def only_windows(reason: str = "Only required on Windows.", ) -> _pytest.mark.structures.MarkDecorator: |
| 283 | + """ |
| 284 | + Factory function to return a ``@pytest.mark.skipif`` decorator that will |
| 285 | + skip a test if the current platform is **not** Windows. |
| 286 | +
|
| 287 | + :param reason: The reason to display when skipping. |
| 288 | +
|
| 289 | + .. versionadded:: 0.9.0 |
| 290 | + """ |
| 291 | + |
| 292 | + return pytest.mark.skipif(condition=sys.platform != "win32", reason=reason) |
| 293 | + |
| 294 | + |
| 295 | +def not_pypy(reason: str = "Not required on PyPy.", ) -> _pytest.mark.structures.MarkDecorator: |
| 296 | + """ |
| 297 | + Factory function to return a ``@pytest.mark.skipif`` decorator that will |
| 298 | + skip a test if the current Python implementation is PyPy. |
| 299 | +
|
| 300 | + :param reason: The reason to display when skipping. |
| 301 | +
|
| 302 | + .. versionadded:: 0.9.0 |
| 303 | + """ |
| 304 | + |
| 305 | + return pytest.mark.skipif(condition=PYPY, reason=reason) |
| 306 | + |
| 307 | + |
| 308 | +def only_pypy(reason: str = "Only required on PyPy.", ) -> _pytest.mark.structures.MarkDecorator: |
| 309 | + """ |
| 310 | + Factory function to return a ``@pytest.mark.skipif`` decorator that will |
| 311 | + skip a test if the current Python implementation is not PyPy. |
| 312 | +
|
| 313 | + :param reason: The reason to display when skipping. |
| 314 | +
|
| 315 | + .. versionadded:: 0.9.0 |
| 316 | + """ |
| 317 | + |
| 318 | + return pytest.mark.skipif(condition=PYPY, reason=reason) |
0 commit comments