Malformed .in results in uncaught exception
- Dominant language
- Python
- Stars
- 8k
- Forks
- 678
- Avg merge
- 11h 33m
- Merged PRs (30d)
- 2
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)
Contributor guide
Assessment
This issue has not been assessed yet.