diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 4f298480..f025405e 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -3,6 +3,16 @@ Changelog +++++++++ +0.3.2 (XX-XX-2021) +================== + +- Validate that the supplied source directory is valid (`PR #260`_, Fixes `#259`_) + +.. _PR #260: https://github.com/pypa/build/pull/260 +.. _#259: https://github.com/pypa/build/issues/259 + + + 0.3.1 (09-03-2021) ================== diff --git a/src/build/__init__.py b/src/build/__init__.py index 1c4eb716..10e5c9df 100644 --- a/src/build/__init__.py +++ b/src/build/__init__.py @@ -59,6 +59,16 @@ class TypoWarning(Warning): """ +def _validate_source_directory(srcdir): + # type: (str) -> None + if not os.path.isdir(srcdir): + raise BuildException('Source {} is not a directory'.format(srcdir)) + pyproject_toml = os.path.join(srcdir, 'pyproject.toml') + setup_py = os.path.join(srcdir, 'setup.py') + if not os.path.exists(pyproject_toml) and not os.path.exists(setup_py): + raise BuildException('Source {} does not appear to be a Python project: no pyproject.toml or setup.py'.format(srcdir)) + + def check_dependency(req_string, ancestral_req_strings=(), parent_extras=frozenset()): # type: (str, Tuple[str, ...], AbstractSet[str]) -> Iterator[Tuple[str, ...]] """ @@ -137,6 +147,7 @@ def __init__(self, srcdir, python_executable=sys.executable, scripts_dir=None): :param python_executable: The python executable where the backend lives """ self.srcdir = os.path.abspath(srcdir) # type: str + _validate_source_directory(srcdir) spec_file = os.path.join(srcdir, 'pyproject.toml') diff --git a/tests/conftest.py b/tests/conftest.py index ee7a4962..e04914c1 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -135,6 +135,11 @@ def test_no_backend_path(packages_path): return os.path.join(packages_path, 'test-no-backend') +@pytest.fixture +def test_no_project_path(packages_path): + return os.path.join(packages_path, 'test-no-project') + + @pytest.fixture def test_no_requires_path(packages_path): return os.path.join(packages_path, 'test-no-requires') diff --git a/tests/packages/test-no-project/empty.txt b/tests/packages/test-no-project/empty.txt new file mode 100644 index 00000000..e69de29b diff --git a/tests/test_projectbuilder.py b/tests/test_projectbuilder.py index c83895ce..1485b740 100644 --- a/tests/test_projectbuilder.py +++ b/tests/test_projectbuilder.py @@ -136,6 +136,18 @@ def test_check_dependency(monkeypatch, requirement_string, expected): assert next(build.check_dependency(requirement_string), None) == expected +def test_bad_project(test_no_project_path): + # Passing a nonexistent project directory + with pytest.raises(build.BuildException): + build.ProjectBuilder(os.path.join(test_no_project_path, 'does-not-exist')) + # Passing a file as a project directory + with pytest.raises(build.BuildException): + build.ProjectBuilder(os.path.join(test_no_project_path, 'empty.txt')) + # Passing a project directory with no pyproject.toml or setup.py + with pytest.raises(build.BuildException): + build.ProjectBuilder(test_no_project_path) + + def test_init(mocker, test_flit_path, legacy_path, test_no_permission, test_bad_syntax_path): mocker.patch('pep517.wrappers.Pep517HookCaller')