diff --git a/backend/src/hatchling/builders/config.py b/backend/src/hatchling/builders/config.py index 99342b6ba..9b7b33d86 100644 --- a/backend/src/hatchling/builders/config.py +++ b/backend/src/hatchling/builders/config.py @@ -31,16 +31,6 @@ def __init__( self.__build_config = build_config self.__target_config = target_config - # Possible pathspec.GitIgnoreSpec - self.__include_spec: pathspec.GitIgnoreSpec | None = None - self.__exclude_spec: pathspec.GitIgnoreSpec | None = None - self.__artifact_spec: pathspec.GitIgnoreSpec | None = None - - # These are used to create the pathspecs and will never be `None` after the first match attempt - self.__include_patterns: list[str] | None = None - self.__exclude_patterns: list[str] | None = None - self.__artifact_patterns: list[str] | None = None - # This is used when the only file selection is based on forced inclusion or build-time artifacts. This # instructs to `exclude` every encountered path without doing pattern matching that matches everything. self.__exclude_all: bool = False @@ -122,117 +112,108 @@ def directory_is_excluded(self, name: str, relative_path: str) -> bool: or (self.skip_excluded_dirs and self.path_is_excluded(f'{relative_directory}/')) ) - @property + @cached_property def include_spec(self) -> pathspec.GitIgnoreSpec | None: - if self.__include_patterns is None: - if 'include' in self.target_config: - include_config = self.target_config - include_location = f'tool.hatch.build.targets.{self.plugin_name}.include' - else: - include_config = self.build_config - include_location = 'tool.hatch.build.include' - - all_include_patterns = [] - - include_patterns = include_config.get('include', self.default_include()) - if not isinstance(include_patterns, list): - message = f'Field `{include_location}` must be an array of strings' - raise TypeError(message) + if 'include' in self.target_config: + include_config = self.target_config + include_location = f'tool.hatch.build.targets.{self.plugin_name}.include' + else: + include_config = self.build_config + include_location = 'tool.hatch.build.include' - for i, include_pattern in enumerate(include_patterns, 1): - if not isinstance(include_pattern, str): - message = f'Pattern #{i} in field `{include_location}` must be a string' - raise TypeError(message) + all_include_patterns = [] - if not include_pattern: - message = f'Pattern #{i} in field `{include_location}` cannot be an empty string' - raise ValueError(message) + include_patterns = include_config.get('include', self.default_include()) + if not isinstance(include_patterns, list): + message = f'Field `{include_location}` must be an array of strings' + raise TypeError(message) - all_include_patterns.append(include_pattern) + for i, include_pattern in enumerate(include_patterns, 1): + if not isinstance(include_pattern, str): + message = f'Pattern #{i} in field `{include_location}` must be a string' + raise TypeError(message) - # Matching only at the root requires a forward slash, back slashes do not work. As such, - # normalize to forward slashes for consistency. - all_include_patterns.extend(f"/{relative_path.replace(os.sep, '/')}/" for relative_path in self.packages) + if not include_pattern: + message = f'Pattern #{i} in field `{include_location}` cannot be an empty string' + raise ValueError(message) - if all_include_patterns: - self.__include_spec = pathspec.GitIgnoreSpec.from_lines(all_include_patterns) + all_include_patterns.append(include_pattern) - self.__include_patterns = all_include_patterns + # Matching only at the root requires a forward slash, back slashes do not work. As such, + # normalize to forward slashes for consistency. + all_include_patterns.extend(f"/{relative_path.replace(os.sep, '/')}/" for relative_path in self.packages) - return self.__include_spec + if all_include_patterns: + return pathspec.GitIgnoreSpec.from_lines(all_include_patterns) + else: + return None - @property + @cached_property def exclude_spec(self) -> pathspec.GitIgnoreSpec | None: - if self.__exclude_patterns is None: - if 'exclude' in self.target_config: - exclude_config = self.target_config - exclude_location = f'tool.hatch.build.targets.{self.plugin_name}.exclude' - else: - exclude_config = self.build_config - exclude_location = 'tool.hatch.build.exclude' - - all_exclude_patterns = self.default_global_exclude() - - if not self.ignore_vcs: - all_exclude_patterns.extend(self.load_vcs_exclusion_patterns()) - - exclude_patterns = exclude_config.get('exclude', self.default_exclude()) - if not isinstance(exclude_patterns, list): - message = f'Field `{exclude_location}` must be an array of strings' - raise TypeError(message) + if 'exclude' in self.target_config: + exclude_config = self.target_config + exclude_location = f'tool.hatch.build.targets.{self.plugin_name}.exclude' + else: + exclude_config = self.build_config + exclude_location = 'tool.hatch.build.exclude' - for i, exclude_pattern in enumerate(exclude_patterns, 1): - if not isinstance(exclude_pattern, str): - message = f'Pattern #{i} in field `{exclude_location}` must be a string' - raise TypeError(message) + all_exclude_patterns = self.default_global_exclude() - if not exclude_pattern: - message = f'Pattern #{i} in field `{exclude_location}` cannot be an empty string' - raise ValueError(message) + if not self.ignore_vcs: + all_exclude_patterns.extend(self.load_vcs_exclusion_patterns()) + + exclude_patterns = exclude_config.get('exclude', self.default_exclude()) + if not isinstance(exclude_patterns, list): + message = f'Field `{exclude_location}` must be an array of strings' + raise TypeError(message) - all_exclude_patterns.append(exclude_pattern) + for i, exclude_pattern in enumerate(exclude_patterns, 1): + if not isinstance(exclude_pattern, str): + message = f'Pattern #{i} in field `{exclude_location}` must be a string' + raise TypeError(message) - if all_exclude_patterns: - self.__exclude_spec = pathspec.GitIgnoreSpec.from_lines(all_exclude_patterns) + if not exclude_pattern: + message = f'Pattern #{i} in field `{exclude_location}` cannot be an empty string' + raise ValueError(message) - self.__exclude_patterns = all_exclude_patterns + all_exclude_patterns.append(exclude_pattern) - return self.__exclude_spec + if all_exclude_patterns: + return pathspec.GitIgnoreSpec.from_lines(all_exclude_patterns) + else: + return None @property def artifact_spec(self) -> pathspec.GitIgnoreSpec | None: - if self.__artifact_patterns is None: - if 'artifacts' in self.target_config: - artifact_config = self.target_config - artifact_location = f'tool.hatch.build.targets.{self.plugin_name}.artifacts' - else: - artifact_config = self.build_config - artifact_location = 'tool.hatch.build.artifacts' - - all_artifact_patterns = [] - - artifact_patterns = artifact_config.get('artifacts', []) - if not isinstance(artifact_patterns, list): - message = f'Field `{artifact_location}` must be an array of strings' - raise TypeError(message) + if 'artifacts' in self.target_config: + artifact_config = self.target_config + artifact_location = f'tool.hatch.build.targets.{self.plugin_name}.artifacts' + else: + artifact_config = self.build_config + artifact_location = 'tool.hatch.build.artifacts' - for i, artifact_pattern in enumerate(artifact_patterns, 1): - if not isinstance(artifact_pattern, str): - message = f'Pattern #{i} in field `{artifact_location}` must be a string' - raise TypeError(message) + all_artifact_patterns = [] - if not artifact_pattern: - message = f'Pattern #{i} in field `{artifact_location}` cannot be an empty string' - raise ValueError(message) + artifact_patterns = artifact_config.get('artifacts', []) + if not isinstance(artifact_patterns, list): + message = f'Field `{artifact_location}` must be an array of strings' + raise TypeError(message) - all_artifact_patterns.append(artifact_pattern) + for i, artifact_pattern in enumerate(artifact_patterns, 1): + if not isinstance(artifact_pattern, str): + message = f'Pattern #{i} in field `{artifact_location}` must be a string' + raise TypeError(message) - if all_artifact_patterns: - self.__artifact_spec = pathspec.GitIgnoreSpec.from_lines(all_artifact_patterns) + if not artifact_pattern: + message = f'Pattern #{i} in field `{artifact_location}` cannot be an empty string' + raise ValueError(message) - self.__artifact_patterns = all_artifact_patterns + all_artifact_patterns.append(artifact_pattern) - return self.__artifact_spec + if all_artifact_patterns: + return pathspec.GitIgnoreSpec.from_lines(all_artifact_patterns) + else: + return None @cached_property def hook_config(self) -> dict[str, Any]: