Skip to content

Commit 91f7267

Browse files
committed
Remove pkg_resources from requirement parser
1 parent e6b9ddc commit 91f7267

File tree

1 file changed

+43
-19
lines changed

1 file changed

+43
-19
lines changed

src/pip/_internal/req/constructors.py

Lines changed: 43 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
from pip._vendor.packaging.markers import Marker
1717
from pip._vendor.packaging.requirements import InvalidRequirement, Requirement
1818
from pip._vendor.packaging.specifiers import Specifier
19-
from pip._vendor.pkg_resources import RequirementParseError, parse_requirements
2019

2120
from pip._internal.exceptions import InstallationError
2221
from pip._internal.models.index import PyPI, TestPyPI
@@ -113,31 +112,56 @@ def parse_editable(editable_req: str) -> Tuple[Optional[str], str, Set[str]]:
113112
return package_name, url, set()
114113

115114

115+
def check_first_requirement_in_file(filename: str) -> None:
116+
"""Check if file is parsable as a requirements file.
117+
118+
This is heavily based on ``pkg_resources.parse_requirements``, but
119+
simplified to just check the first meaningful line.
120+
121+
:raises InvalidRequirement: If the first meaningful line cannot be parsed
122+
as an requirement.
123+
"""
124+
with open(filename, encoding="utf-8", errors="ignore") as f:
125+
# Create a steppable iterator, so we can handle \-continuations.
126+
lines = (
127+
line
128+
for line in (line.strip() for line in f)
129+
if line and not line.startswith("#") # Skip blank lines/comments.
130+
)
131+
132+
for line in lines:
133+
# Drop comments -- a hash without a space may be in a URL.
134+
if " #" in line:
135+
line = line[: line.find(" #")]
136+
# If there is a line continuation, drop it, and append the next line.
137+
if line.endswith("\\"):
138+
line = line[:-2].strip() + next(lines, "")
139+
Requirement(line)
140+
return
141+
142+
116143
def deduce_helpful_msg(req: str) -> str:
117144
"""Returns helpful msg in case requirements file does not exist,
118145
or cannot be parsed.
119146
120147
:params req: Requirements file path
121148
"""
122-
msg = ""
123-
if os.path.exists(req):
124-
msg = " The path does exist. "
125-
# Try to parse and check if it is a requirements file.
126-
try:
127-
with open(req) as fp:
128-
# parse first line only
129-
next(parse_requirements(fp.read()))
130-
msg += (
131-
"The argument you provided "
132-
"({}) appears to be a"
133-
" requirements file. If that is the"
134-
" case, use the '-r' flag to install"
135-
" the packages specified within it."
136-
).format(req)
137-
except RequirementParseError:
138-
logger.debug("Cannot parse '%s' as requirements file", req, exc_info=True)
149+
if not os.path.exists(req):
150+
return f" File '{req}' does not exist."
151+
msg = " The path does exist. "
152+
# Try to parse and check if it is a requirements file.
153+
try:
154+
check_first_requirement_in_file(req)
155+
except InvalidRequirement:
156+
logger.debug("Cannot parse '%s' as requirements file", req)
139157
else:
140-
msg += f" File '{req}' does not exist."
158+
msg += (
159+
f"The argument you provided "
160+
f"({req}) appears to be a"
161+
f" requirements file. If that is the"
162+
f" case, use the '-r' flag to install"
163+
f" the packages specified within it."
164+
)
141165
return msg
142166

143167

0 commit comments

Comments
 (0)