Source code for repo_helper.testing

#!/usr/bin/env python
Helpers for running tests with pytest.

.. extras-require:: testing

.. versionadded:: 2020.11.17
#  Copyright © 2020 Dominic Davis-Foster <>
#  This program is free software; you can redistribute it and/or modify
#  it under the terms of the GNU Lesser General Public License as published by
#  the Free Software Foundation; either version 3 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
#  GNU Lesser General Public License for more details.
#  You should have received a copy of the GNU Lesser General Public License
#  along with this program; if not, write to the Free Software
#  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
#  MA 02110-1301, USA.

# stdlib
import datetime
import os
import pathlib
import secrets
import sys
from pathlib import Path

# 3rd party
import check_wheel_contents.__main__  # type: ignore  # nodep
import jinja2
import pytest  # nodep
from apeye.url import URL
from domdf_python_tools.paths import PathPlus
from dulwich.config import StackedConfig
from southwark.repo import Repo

# this package
import repo_helper.utils
from repo_helper.configuration import get_tox_python_versions
from repo_helper.files.linting import lint_warn_list
from repo_helper.templates import Environment, template_dir
from repo_helper.utils import brace

__all__ = [

[docs]@pytest.fixture() def demo_environment() -> Environment: """ Pytest fixture to create a jinja2 environment for use in tests. The environment has the following variables available by default: .. code-block:: json { "username": "octocat", "assignee": "octocat", "imgbot_ignore": [], "travis_ubuntu_version": "xenial", "github_ci_requirements": {"Linux": {"pre": [], "post": []}}, "travis_additional_requirements": [], "conda_channels": ["conda-forge"], "python_versions": ["3.6", "3.7"], "enable_tests": true, "enable_conda": true, "enable_docs": true, "enable_releases": true, "python_deploy_version": "3.6", "min_py_version": "3.6", "modname": "hello-world", "repo_name": "hello-world", "import_name": "hello_world", "platforms": ["Windows"], "pypi_name": "hello-world", "py_modules": [], "manifest_additional": [], "additional_requirements_files": [], "source_dir": "", "tests_dir": "tests", "additional_setup_args": {}, "setup_pre": [], "docs_dir": "doc-source", "sphinx_html_theme": "alabaster", "additional_ignore": ["foo", "bar", "fuzz"], "join_path": "os.path.join", "pure_python": true, "stubs_package": false, "managed_message": "This file is managed by 'repo_helper'. Don't edit it directly.", "short_desc": "a short description", "on_pypi": true, "docs_fail_on_warning": false, "requires_python": "3.6.1", "third_party_version_matrix": {} } plus ``lint_warn_list`` = :py:data:`repo_helper.files.linting.lint_warn_list`. Additional options can be set and values changed at the start of with: .. code-block:: python def test(demo_environment): demo_environment.templates.globals["source_dir"] = "src" """ templates = Environment( # nosec: B701 loader=jinja2.FileSystemLoader(str(template_dir)), undefined=jinja2.StrictUndefined, ) templates.globals.update( dict( username="octocat", assignee="octocat", imgbot_ignore=[], travis_ubuntu_version="xenial", github_ci_requirements={"Linux": {"pre": [], "post": []}}, travis_additional_requirements=[], conda_channels=["conda-forge"], python_versions={"3.6": {"experimental": False}, "3.7": {"experimental": False}}, enable_tests=True, enable_conda=True, enable_docs=True, enable_releases=True, python_deploy_version="3.6", requires_python="3.6.1", min_py_version="3.6", modname="hello-world", repo_name="hello-world", docs_url="", import_name="hello_world", platforms=["Windows"], pypi_name="hello-world", lint_warn_list=lint_warn_list, py_modules=[], manifest_additional=[], additional_requirements_files=[], source_dir='', tests_dir="tests", additional_setup_args={}, setup_pre=[], docs_dir="doc-source", sphinx_html_theme="alabaster", additional_ignore=["foo", "bar", "fuzz"], join_path=os.path.join, pure_python=True, stubs_package=False, managed_message="This file is managed by 'repo_helper'. Don't edit it directly.", short_desc="a short description", on_pypi=True, docs_fail_on_warning=False, brace=brace, third_party_version_matrix={}, gh_actions_versions={ "3.6": "py36, mypy", "3.7": "py37, build", }, ) ) templates.globals["tox_py_versions"] = get_tox_python_versions(templates.globals["python_versions"]) return templates
@pytest.fixture() def original_datadir(request) -> Path: # noqa: D103 # Work around pycharm confusing datadir with test file. return PathPlus(os.path.splitext(request.module.__file__)[0] + '_') FAKE_DATE =, 7, 25)
[docs]@pytest.fixture() def temp_empty_repo(tmp_pathplus, monkeypatch) -> Repo: """ Pytest fixture to return an empty git repository in a temporary location. :data:`` is monkeypatched to return 25th July 2020. """ # Monkeypatch dulwich so it doesn't try to use the global config. monkeypatch.setattr(StackedConfig, "default_backends", lambda *args: [], raising=True) monkeypatch.setenv("GIT_COMMITTER_NAME", "Guido") monkeypatch.setenv("GIT_COMMITTER_EMAIL", "") monkeypatch.setenv("GIT_AUTHOR_NAME", "Guido") monkeypatch.setenv("GIT_AUTHOR_EMAIL", "") monkeypatch.setattr(repo_helper.utils, "today", FAKE_DATE) repo_dir = tmp_pathplus / secrets.token_hex(8) if sys.platform == "linux": repo_dir /= "%%tmp" repo_dir.maybe_make(parents=True) repo: Repo = Repo.init(repo_dir) return repo
[docs]@pytest.fixture() def temp_repo(temp_empty_repo, example_config) -> Repo: """ Pytest fixture to return a git repository in a temporary location. The repository will contain a ``repo_helper.yml`` yaml file, the contents of which can be seen at :data:`` is monkeypatched to return 25th July 2020. """ (temp_empty_repo.path / "repo_helper.yml").write_text(example_config) return temp_empty_repo
[docs]@pytest.fixture(scope="session") def example_config() -> str: """ Returns the contents of the example ``repo_helper.yml`` file. """ return (pathlib.Path(__file__).parent / "repo_helper_example.yml").read_text()
[docs]def is_running_on_actions() -> bool: """ Returns :py:obj:`True` if running on GitHub Actions. """ # From # Copyright (c) 2019 Yusuke Miyazaki # MIT Licensed # See the following document on which environ to use for this purpose. # return "GITHUB_ACTIONS" in os.environ