Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

build: validate the source directory passed to ProjectBuilder #260

Merged
merged 7 commits into from
Mar 19, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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)
==================

Expand Down
11 changes: 11 additions & 0 deletions src/build/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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, ...]]
"""
Expand Down Expand Up @@ -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')

Expand Down
5 changes: 5 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -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')
Expand Down
Empty file.
12 changes: 12 additions & 0 deletions tests/test_projectbuilder.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you split each test into its own test please? 👌

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code already went in. This is not a big deal though.

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')

Expand Down