Skip to content
Draft
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
21 changes: 21 additions & 0 deletions pipenv/utils/dependencies.py
Original file line number Diff line number Diff line change
Expand Up @@ -1283,6 +1283,25 @@ def process_vcs_url(cls, url: str) -> str:
return urlunparse(tuple(processed_parts))


def _validate_pipfile_entry(name: str, pipfile_dict: Dict[str, Any]) -> None:
"""Warn or raise when a Pipfile entry contains unrecognised keys.

This catches common mistakes such as writing ``commit = "hash"`` instead
of ``ref = "hash"`` for VCS dependencies.
"""
from pipenv.vendor.plette.models.packages import KNOWN_PACKAGE_KEYS

unknown = set(pipfile_dict.keys()) - KNOWN_PACKAGE_KEYS
if unknown:
raise PipenvUsageError(
f"Unrecognized option(s) in Pipfile for package '{name}': "
f"{', '.join(sorted(unknown))}. "
"Valid options include: version, extras, editable, markers, "
"ref, git, svn, hg, bzr, path, file, index, subdirectory, "
"hashes, no_binary, and PEP 508 marker keys."
)


def install_req_from_pipfile(name: str, pipfile: Dict[str, Any]) -> Tuple[Any, Any, str]:
"""
Creates an InstallRequirement from a name and a pipfile entry.
Expand All @@ -1293,6 +1312,8 @@ def install_req_from_pipfile(name: str, pipfile: Dict[str, Any]) -> Tuple[Any, A

if hasattr(pipfile, "keys"):
_pipfile = dict(pipfile).copy()
# Validate that all keys are recognised before processing.
_validate_pipfile_entry(name, _pipfile)
else:
vcs = next(iter([vcs for vcs in VCS_LIST if pipfile.startswith(f"{vcs}+")]), None)
if vcs is not None:
Expand Down
57 changes: 57 additions & 0 deletions pipenv/vendor/plette/models/packages.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,48 @@

from .base import DataModel, DataValidationError

# All recognized keys for a Pipfile package entry (dict form).
# Any key not in this set will trigger a validation error so that typos
# like ``commit = "…"`` (should be ``ref``) are caught early.
KNOWN_PACKAGE_KEYS = frozenset(
{
# VCS back-ends
"git",
"svn",
"hg",
"bzr",
# VCS ref / sub-directory
"ref",
"subdirectory",
# Package metadata
"name",
"version",
"extras",
"editable",
"markers",
"os_markers",
"hashes",
"index",
"no_binary",
# Path / file source
"path",
"file",
# PEP 508 environment-marker short-hands (also accepted as top-level keys)
"os_name",
"sys_platform",
"platform_machine",
"platform_python_implementation",
"platform_release",
"platform_system",
"platform_version",
"python_version",
"python_full_version",
"implementation_name",
"implementation_version",
}
)


class PackageSpecfiers(DataModel):
# TODO: one could add here more validation for path editable
# and more stuff which is currently allowed and undocumented
Expand All @@ -12,6 +54,21 @@ class PackageSpecfiers(DataModel):
"extras": list
}

@classmethod
def validate(cls, data):
super().validate(data)
# Reject unrecognised keys so that typos are caught early
# (e.g. ``commit`` instead of ``ref``).
if isinstance(data, dict):
unknown = set(data.keys()) - KNOWN_PACKAGE_KEYS
if unknown:
raise DataValidationError(
f"Unrecognized Pipfile option(s): {', '.join(sorted(unknown))}. "
"Valid options include: version, extras, editable, markers, "
"ref, git, svn, hg, bzr, path, file, index, subdirectory, "
"hashes, no_binary, and PEP 508 marker keys."
)


class Package(DataModel):
"""A package requirement specified in a Pipfile.
Expand Down
Loading