From afc23a2a281779a07488828bb228ce468bee87ca Mon Sep 17 00:00:00 2001 From: Maximilian Hils Date: Wed, 23 Aug 2023 16:01:12 +0200 Subject: [PATCH] error if force-include source is not found --- .../hatchling/builders/plugin/interface.py | 3 +++ backend/src/hatchling/builders/sdist.py | 10 +++---- docs/config/build.md | 2 +- docs/history/hatchling.md | 5 ++++ .../backend/builders/plugin/test_interface.py | 26 +++++++++++++++++-- 5 files changed, 38 insertions(+), 8 deletions(-) diff --git a/backend/src/hatchling/builders/plugin/interface.py b/backend/src/hatchling/builders/plugin/interface.py index dd7587722..6ae0884b5 100644 --- a/backend/src/hatchling/builders/plugin/interface.py +++ b/backend/src/hatchling/builders/plugin/interface.py @@ -224,6 +224,9 @@ def recurse_forced_files(self, inclusion_map: dict[str, str]) -> Iterable[Includ '' if external else relative_file_path, self.config.get_distribution_path(relative_file_path), ) + else: + msg = f'Forced include not found: {source}' + raise FileNotFoundError(msg) def recurse_explicit_files(self, inclusion_map: dict[str, str]) -> Iterable[IncludedFile]: for source, target_path in inclusion_map.items(): diff --git a/backend/src/hatchling/builders/sdist.py b/backend/src/hatchling/builders/sdist.py index 7aa23fcad..9a7e31544 100644 --- a/backend/src/hatchling/builders/sdist.py +++ b/backend/src/hatchling/builders/sdist.py @@ -319,11 +319,11 @@ def construct_setup_py_file(self, packages: list[str], extra_dependencies: tuple return contents def get_default_build_data(self) -> dict[str, Any]: - force_include = { - os.path.join(self.root, 'pyproject.toml'): 'pyproject.toml', - os.path.join(self.root, DEFAULT_CONFIG_FILE): DEFAULT_CONFIG_FILE, - os.path.join(self.root, DEFAULT_BUILD_SCRIPT): DEFAULT_BUILD_SCRIPT, - } + force_include = {} + for filename in ['pyproject.toml', DEFAULT_CONFIG_FILE, DEFAULT_BUILD_SCRIPT]: + path = os.path.join(self.root, filename) + if os.path.exists(path): + force_include[path] = filename build_data = {'force_include': force_include, 'dependencies': []} for exclusion_files in self.config.vcs_exclusion_files.values(): diff --git a/docs/config/build.md b/docs/config/build.md index ac7d5bfa4..e86637049 100644 --- a/docs/config/build.md +++ b/docs/config/build.md @@ -192,7 +192,7 @@ For example, if there was a directory alongside the project root named `artifact - Files must be mapped exactly to their desired paths, not to directories. - The contents of directory sources are recursively included. - To map directory contents directly to the root use `/` (a forward slash). - - Sources that do not exist are silently ignored. + - Sources that do not exist will raise an error. !!! warning Files included using this option will overwrite any file path that was already included by other file selection options. diff --git a/docs/history/hatchling.md b/docs/history/hatchling.md index df6653a95..412434c21 100644 --- a/docs/history/hatchling.md +++ b/docs/history/hatchling.md @@ -12,6 +12,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), - Fix parsing dependencies for environments when warnings are emitted +***Changed:*** + +- If a force-included file or directory does not exist, an error will now be raised + instead of silently ignoring it. + ## [1.18.0](https://github.com/pypa/hatch/releases/tag/hatchling-v1.18.0) - 2023-06-12 ## {: #hatchling-v1.18.0 } ***Changed:*** diff --git a/tests/backend/builders/plugin/test_interface.py b/tests/backend/builders/plugin/test_interface.py index 0f5144bb9..64939563b 100644 --- a/tests/backend/builders/plugin/test_interface.py +++ b/tests/backend/builders/plugin/test_interface.py @@ -218,6 +218,30 @@ def test_no_duplication(self, temp_dir): (str(temp_dir / 'external.txt'), f'new{path_sep}target2.txt'), ] + def test_exists(self, temp_dir): + project_dir = temp_dir / 'project' + project_dir.ensure_dir_exists() + + with project_dir.as_cwd(): + config = { + 'tool': { + 'hatch': { + 'build': { + 'force-include': { + '../notfound': 'target.txt', + }, + } + } + } + } + builder = MockBuilder(str(project_dir), config=config) + build_data = builder.get_default_build_data() + builder.set_build_data_defaults(build_data) + with builder.config.set_build_data(build_data), pytest.raises( + FileNotFoundError, match='Forced include not found' + ): + list(builder.recurse_included_files()) + def test_order(self, temp_dir): project_dir = temp_dir / 'project' project_dir.ensure_dir_exists() @@ -234,8 +258,6 @@ def test_order(self, temp_dir): '../external1.txt': 'nested/target2.txt', '../external2.txt': 'nested/target1.txt', '../external': 'nested', - # Should be silently ignored - '../missing': 'missing', }, } }