diff --git a/news/106.bugfix.md b/news/106.bugfix.md new file mode 100644 index 0000000..f2638ec --- /dev/null +++ b/news/106.bugfix.md @@ -0,0 +1 @@ +Throw a better error message when a malformed requirement is being parsed. diff --git a/pdm/pep517/metadata.py b/pdm/pep517/metadata.py index 5743b2b..8bc205e 100644 --- a/pdm/pep517/metadata.py +++ b/pdm/pep517/metadata.py @@ -241,13 +241,18 @@ def license_files(self) -> Dict[str, List[str]]: raise MetadataError("license-files", "Must specify 'paths' or 'globs'") return rv - def _convert_dependencies(self, deps: List[str]) -> List[str]: - return list(filter(None, map(ensure_pep440_req, deps))) + def _convert_dependencies( + self, deps: List[str], field: str = "dependencies" + ) -> List[str]: + return list(filter(None, (ensure_pep440_req(dep, field) for dep in deps))) def _convert_optional_dependencies( self, deps: Mapping[str, List[str]] ) -> Dict[str, List[str]]: - return {k: self._convert_dependencies(deps[k]) for k in deps} + return { + k: self._convert_dependencies(deps[k], "optional-dependencies") + for k in deps + } dependencies: MetaField[List[str]] = MetaField( "dependencies", _convert_dependencies diff --git a/pdm/pep517/utils.py b/pdm/pep517/utils.py index a197731..dbc8893 100644 --- a/pdm/pep517/utils.py +++ b/pdm/pep517/utils.py @@ -11,8 +11,9 @@ from pdm.pep517._vendor.packaging import tags from pdm.pep517._vendor.packaging.markers import Marker -from pdm.pep517._vendor.packaging.requirements import Requirement +from pdm.pep517._vendor.packaging.requirements import InvalidRequirement, Requirement from pdm.pep517._vendor.packaging.version import InvalidVersion, Version +from pdm.pep517.exceptions import MetadataError from pdm.pep517.macosx_platform import calculate_macosx_platform_tag @@ -184,11 +185,15 @@ def get_abi_tag() -> Optional[str]: return None -def ensure_pep440_req(req: str) -> Optional[str]: +def ensure_pep440_req(req: str, field: str) -> Optional[str]: """Discard all non-PEP 440 requirements, e.g. editable VCS requirements.""" if req.strip().startswith("-e"): return None + try: + Requirement(req) + except InvalidRequirement as e: + raise MetadataError(field, f"Invalid requirement {req!r}\n {e}") from e return req diff --git a/tests/test_metadata.py b/tests/test_metadata.py index 3783570..e3c3222 100644 --- a/tests/test_metadata.py +++ b/tests/test_metadata.py @@ -273,6 +273,22 @@ def test_invalid_license_identifier() -> None: metadata.license_expression +def test_invalid_requirement_strings() -> None: + metadata = make_metadata( + { + "description": "test package", + "name": "demo", + "dependencies": ["+abc"], + "optional-dependencies": {"foo": ["foo&123"]}, + } + ) + with pytest.raises(ValueError): + metadata.dependencies + + with pytest.raises(ValueError): + metadata.optional_dependencies + + @pytest.mark.deprecation @pytest.mark.parametrize( "attr_name, field_name, value",