Description
Lets see how pip-compile performs given a purposefully malformed .in file. Normally would expect a pip-compile specific Exception and a non-zero exit code.
malformed-pip.in
>=24pip\n
Which is obviously malformed. Since a .in is user input, it can contain errors.
pip has vendored package, packaging. When packaging fails to parse a requirement, it produces this Exception chain
pip._vendor.packaging._tokenizer.ParserSyntaxError
pip._vendor.packaging.requirements.InvalidRequirement
pip._internal.exceptions.InstallationError
pip-compile does not gracefully catch the InstallationError. Instead just bombs with exit code 1 and the below traceback.
Environment Versions
OS: Linux distro Void Linux LXDE
Python version: Python 3.9.16
pip version: pip 24.3.1
pip-tools version: pip-compile, version 7.4.1
Steps to replicate
echo ">=24pip\n" > malformed-pip.in
pip-compile --allow-unsafe --no-header -o malformed-pip.txt malformed-pip.in
Expected result
pip-compile should catch the Exception in a try-except block. Exception is reraised with a pip-compile specific Exception. The entire traceback does not get shown.
Taken from the traceback, handling of the Exception doesn't happen here.
piptools/scripts/compile.py", line 383, in cli
constraints.extend(
Actual result
Traceback (most recent call last):
File "[venv base path]/lib/python3.9/site-packages/pip/_vendor/packaging/requirements.py", line 36, in init
parsed = _parse_requirement(requirement_string)
File "[venv base path]/lib/python3.9/site-packages/pip/_vendor/packaging/_parser.py", line 62, in parse_requirement
return _parse_requirement(Tokenizer(source, rules=DEFAULT_RULES))
File "[venv base path]/lib/python3.9/site-packages/pip/_vendor/packaging/_parser.py", line 71, in _parse_requirement
name_token = tokenizer.expect(
File "[venv base path]/lib/python3.9/site-packages/pip/_vendor/packaging/_tokenizer.py", line 142, in expect
raise self.raise_syntax_error(f"Expected {expected}")
File "[venv base path]/lib/python3.9/site-packages/pip/_vendor/packaging/_tokenizer.py", line 167, in raise_syntax_error
raise ParserSyntaxError(
pip._vendor.packaging._tokenizer.ParserSyntaxError: Expected package name at the start of dependency specifier
>=24pip
^
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "[venv base path]/lib/python3.9/site-packages/pip/_internal/req/constructors.py", line 362, in _parse_req_string
return get_requirement(req_as_string)
File "[venv base path]/lib/python3.9/site-packages/pip/_internal/utils/packaging.py", line 45, in get_requirement
return Requirement(req_string)
File "[venv base path]/lib/python3.9/site-packages/pip/_vendor/packaging/requirements.py", line 38, in init
raise InvalidRequirement(str(e)) from e
pip._vendor.packaging.requirements.InvalidRequirement: Expected package name at the start of dependency specifier
>=24pip
^
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "[venv base path]/bin/pip-compile", line 8, in
sys.exit(cli())
File "[venv base path]/lib/python3.9/site-packages/click/core.py", line 1157, in call
return self.main(*args, **kwargs)
File "[venv base path]/lib/python3.9/site-packages/click/core.py", line 1078, in main
rv = self.invoke(ctx)
File "[venv base path]/lib/python3.9/site-packages/click/core.py", line 1434, in invoke
return ctx.invoke(self.callback, **ctx.params)
File "[venv base path]/lib/python3.9/site-packages/click/core.py", line 783, in invoke
return __callback(*args, **kwargs)
File "[venv base path]/lib/python3.9/site-packages/click/decorators.py", line 33, in new_func
return f(get_current_context(), *args, **kwargs)
File "[venv base path]/lib/python3.9/site-packages/piptools/scripts/compile.py", line 383, in cli
constraints.extend(
File "[venv base path]/lib/python3.9/site-packages/piptools/_compat/pip_compat.py", line 77, in parse_requirements
yield install_req_from_parsed_requirement(parsed_req, isolated=isolated)
File "[venv base path]/lib/python3.9/site-packages/pip/_internal/req/constructors.py", line 480, in install_req_from_parsed_requirement
req = install_req_from_line(
File "[venv base path]/lib/python3.9/site-packages/pip/_internal/req/constructors.py", line 405, in install_req_from_line
parts = parse_req_from_line(name, line_source)
File "[venv base path]/lib/python3.9/site-packages/pip/_internal/req/constructors.py", line 379, in parse_req_from_line
req: Optional[Requirement] = _parse_req_string(req_as_string)
File "[venv base path]/lib/python3.9/site-packages/pip/_internal/req/constructors.py", line 376, in _parse_req_string
raise InstallationError(msg)
pip._internal.exceptions.InstallationError: Invalid requirement: '>=24pip': Expected package name at the start of dependency specifier
>=24pip
^ (from line 1 of /tmp/pytest-of-chaosmonkey/pytest-24/test_compile_malformed_in_mix_0/requirements/malformed-pip.in)