Skip to content

Commit

Permalink
test: add tests using git (pypa#347)
Browse files Browse the repository at this point in the history
git is isolated using the following environment, which are set globally
for the duration of that the new pytest fixture "tmp_git" is used:

GIT_CONFIG_GLOBAL
GIT_CONFIG_NOSYSTEM
HOME
GIT_AUTHOR_EMAIL
GIT_AUTHOR_NAME
GIT_AUTHOR_DATE
GIT_COMMITTER_EMAIL
GIT_COMMITTER_NAME
GIT_COMMITTER_DATE

GIT_DIR and GIT_WORK_TREE could be set so that git can be called using
any method, but instead a git() function is added that uses git's -C
command-line option.

These were taken from one of git's test scripts:
https://github.com/git/git/blob/cefe983a320c03d7843ac78e73bd513a27806845/t/test-lib.sh#L454-L461

There are probably other ways git can be isolated.

The repository is initialized with an empty commit, but this isn't
strictly necessary, it just makes some of the possible tests require
less setup.

The new tmp_project fixture copies the sample module from
./test/samples/module1_toml to the project and commits the files.

A test is added for pypa#345 as an example of how this can be used.

A pytest marker is added so that tests with either "needgit" or
"needsgit" in the name are skipped if python can't find an executable
named "git".

The tox configuration is changed and another pytest marker is added so
that those tests can be run by themselves:

tox -- -m needgit

or skipped:

tox -- -m "not needgit"

Type hints were added to help with development, but aren't necessary to
keep.
  • Loading branch information
mawillcockson committed Sep 29, 2021
1 parent 734ab12 commit a1b1b4d
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 3 deletions.
6 changes: 6 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,9 @@ Source = "https://github.com/takluyver/flit"

[project.scripts]
flit = "flit:main"

[tool.pytest.ini_options]
markers = [
"needgit: needs git to be installed in order to run",
"needsgit: needs git to be installed in order to run",
]
86 changes: 84 additions & 2 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,97 @@
from pathlib import Path
from shutil import copy, copytree, which
from subprocess import check_output
from typing import TYPE_CHECKING
from unittest.mock import patch

import pytest
from shutil import copytree

samples_dir = Path(__file__).parent / 'samples'
if TYPE_CHECKING:
from typing import Iterator, List, Union

samples_dir = Path(__file__).parent / "samples"

skip_if_no_git = pytest.mark.skipif(
(not which("git")),
reason="needs git to be installed and findable through the PATH environment variable",
)


def pytest_collection_modifyitems(items):
for item in items:
if "needgit" in item.nodeid or "needsgit" in item.nodeid:
item.add_marker(skip_if_no_git)
item.add_marker(pytest.mark.needgit)
item.add_marker(pytest.mark.needsgit)


@pytest.fixture
def copy_sample(tmp_path):
"""Copy a subdirectory from the samples dir to a temp dir"""

def copy(dirname):
dst = tmp_path / dirname
copytree(str(samples_dir / dirname), str(dst))
return dst

return copy


def git(repo: Path, command: "Union[List[str], str]") -> bytes:
if isinstance(command, str):
args = command.split()
else:
args = command

return check_output(
["git", "-C", str(repo), *args],
)


@pytest.fixture
def tmp_git(tmp_path: Path) -> "Iterator[Path]":
"""
Make a git repository in a temporary folder
The path returned is what should be passed to git's -C command, or what cwd
should be set to in subprocess calls
"""
git_global_config = tmp_path / "git_global_config"
git_global_config.touch(exist_ok=False)
repository = tmp_path / "repository"
repository.mkdir(exist_ok=False)
with patch.dict(
"os.environ",
{
# https://git-scm.com/docs/git#Documentation/git.txt-codeGITCONFIGGLOBALcode
"GIT_CONFIG_GLOBAL": str(git_global_config),
# https://git-scm.com/docs/git#Documentation/git.txt-codeGITCONFIGNOSYSTEMcode
"GIT_CONFIG_NOSYSTEM": "true",
"HOME": str(tmp_path),
# tox by default only passes the PATH environment variable, so
# XDG_CONFIG_HOME is already unset
# https://github.com/git/git/blob/cefe983a320c03d7843ac78e73bd513a27806845/t/test-lib.sh#L454-L461
"GIT_AUTHOR_EMAIL": "author@example.com",
"GIT_AUTHOR_NAME": "A U Thor",
"GIT_AUTHOR_DATE": "1112354055 +0200",
"GIT_COMMITTER_EMAIL": "committer@example.com",
"GIT_COMMITTER_NAME": "committer",
"GIT_COMMITTER_DATE": "1112354055 +0200",
},
):
git(repository, "config --global init.defaultBranch main")
git(repository, ["init"])
git(repository, "commit --allow-empty --allow-empty-message --no-edit")

yield repository


@pytest.fixture
def tmp_project(tmp_git: Path) -> "Iterator[Path]":
"return a path to the root of a git repository containing a sample package"
for file in (samples_dir / "module1_toml").glob("*"):
copy(str(file), str(tmp_git / file.name))
git(tmp_git, "add -A :/")
git(tmp_git, "commit --allow-empty --allow-empty-message --no-edit")

yield tmp_git
9 changes: 9 additions & 0 deletions tests/test_build.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from tempfile import TemporaryDirectory
from testpath import assert_isdir, MockCommand

from .conftest import git
from flit_core import common
from flit import build

Expand Down Expand Up @@ -69,3 +70,11 @@ def test_build_module_no_docstring():
with pytest.raises(common.NoDocstringError) as exc_info:
build.main(pyproject)
assert 'no_docstring.py' in str(exc_info.value)

def test_build_needgit_unicode_filenames(tmp_project: Path) -> None:
"does a package build if it includes a unicode filename?"
noel_file = tmp_project / "No\N{LATIN SMALL LETTER E WITH DIAERESIS}l"
noel_file.touch()
git(tmp_project, "add -A :/")
git(tmp_project, "commit --allow-empty --allow-empty-message --no-edit")
build.main(tmp_project / "pyproject.toml")
2 changes: 1 addition & 1 deletion tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ setenv =
PYTHONPATH = flit_core

commands =
python -m pytest --cov=flit --cov=flit_core/flit_core
python -m pytest --cov=flit --cov=flit_core/flit_core {posargs}

[testenv:bootstrap]
skip_install = true
Expand Down

0 comments on commit a1b1b4d

Please sign in to comment.