1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
|
import contextlib
import errno
import functools
import os
import shutil
import stat
import sys
import tempfile
from pathlib import Path
from types import TracebackType
from typing import Any, Callable, Generator, Tuple, Type
import click
import pytest
from click.testing import CliRunner
if sys.version_info >= (3, 8):
from importlib import metadata as imp_metadata
_HAVE_IMPORTLIB_METADATA = True
else:
_HAVE_IMPORTLIB_METADATA = False
@functools.lru_cache
def _click_version() -> Tuple[int, int]:
"""Try to figure out the version of the `click` library."""
if _HAVE_IMPORTLIB_METADATA:
# If this fails, we have bigger problems...
version_str = imp_metadata.version("click")
else:
version_str = getattr(click, "__version__", "0.0")
try:
parts_int = [int(part) for part in version_str.split(".")[:2]]
except ValueError:
parts_int = [0, 0]
try:
return parts_int[0], parts_int[1]
except IndexError:
return 0, 0
# --------------------------------------------------------------------------------------
# Fixtures
@pytest.fixture
def runner() -> CliRunner:
return CliRunner() if _click_version() >= (8, 2) else CliRunner(mix_stderr=False)
@pytest.fixture
def cli() -> click.Group:
from sphinx_theme_builder._internal.cli import compose_command_line
return compose_command_line()
@pytest.fixture
def click_version() -> Tuple[int, int]:
return _click_version()
# --------------------------------------------------------------------------------------
# Work around https://github.com/pytest-dev/pytest/issues/7821
@contextlib.contextmanager
def tmpdir() -> Generator[Path, None, None]:
"""Contextmanager to create a temporary directory. It will be cleaned up
afterwards.
"""
tempdir = tempfile.mkdtemp()
try:
yield Path(tempdir)
finally:
rmtree(tempdir)
def rmtree(path: str) -> None:
"""On windows, rmtree fails for readonly dirs."""
def handle_remove_readonly(
func: Callable[..., Any],
path: str,
exc: Tuple[Type[OSError], OSError, TracebackType],
) -> None:
excvalue = exc[1]
if func in (os.rmdir, os.remove, os.unlink) and excvalue.errno == errno.EACCES:
for p in (path, os.path.dirname(path)):
os.chmod(p, os.stat(p).st_mode | stat.S_IWUSR)
func(path)
else:
raise # noqa
shutil.rmtree(path, ignore_errors=False, onerror=handle_remove_readonly)
# --------------------------------------------------------------------------------------
|