diff --git a/news/5716.bugfix b/news/5716.bugfix new file mode 100644 index 00000000000..1b705df6f92 --- /dev/null +++ b/news/5716.bugfix @@ -0,0 +1 @@ +Fix case sensitive comparison of pip freeze when used with -r option. \ No newline at end of file diff --git a/src/pip/_internal/operations/freeze.py b/src/pip/_internal/operations/freeze.py index 6eaa85b19ec..441c66b8a72 100644 --- a/src/pip/_internal/operations/freeze.py +++ b/src/pip/_internal/operations/freeze.py @@ -79,7 +79,7 @@ def freeze( continue if exclude_editable and req.editable: continue - installations[req.name] = req + installations[req.canonical_name] = req if requirement: # the options that don't get turned into an InstallRequirement @@ -138,22 +138,24 @@ def freeze( " (add #egg=PackageName to the URL to avoid" " this warning)" ) - elif line_req.name not in installations: - # either it's not installed, or it is installed - # but has been processed already - if not req_files[line_req.name]: - logger.warning( - "Requirement file [%s] contains %s, but " - "package %r is not installed", - req_file_path, - COMMENT_RE.sub('', line).strip(), line_req.name - ) + else: + line_req_canonical_name = canonicalize_name(line_req.name) + if line_req_canonical_name not in installations: + # either it's not installed, or it is installed + # but has been processed already + if not req_files[line_req.name]: + logger.warning( + "Requirement file [%s] contains %s, but " + "package %r is not installed", + req_file_path, + COMMENT_RE.sub('', line).strip(), line_req.name + ) + else: + req_files[line_req.name].append(req_file_path) else: + yield str(installations[line_req_canonical_name]).rstrip() + del installations[line_req_canonical_name] req_files[line_req.name].append(req_file_path) - else: - yield str(installations[line_req.name]).rstrip() - del installations[line_req.name] - req_files[line_req.name].append(req_file_path) # Warn about requirements that were included multiple times (in a # single requirements file or in different requirements files). @@ -168,7 +170,7 @@ def freeze( ) for installation in sorted( installations.values(), key=lambda x: x.name.lower()): - if canonicalize_name(installation.name) not in skip: + if installation.canonical_name not in skip: yield str(installation).rstrip() @@ -238,6 +240,7 @@ class FrozenRequirement(object): def __init__(self, name, req, editable, comments=()): # type: (str, Union[str, Requirement], bool, Iterable[str]) -> None self.name = name + self.canonical_name = canonicalize_name(name) self.req = req self.editable = editable self.comments = comments diff --git a/tests/functional/test_freeze.py b/tests/functional/test_freeze.py index 77f83796abc..98d04f2802b 100644 --- a/tests/functional/test_freeze.py +++ b/tests/functional/test_freeze.py @@ -502,15 +502,20 @@ def test_freeze_with_requirement_option(script): """ - script.scratch_path.joinpath("hint.txt").write_text(textwrap.dedent("""\ + script.scratch_path.joinpath("hint1.txt").write_text(textwrap.dedent("""\ INITools==0.1 NoExist==4.2 # A comment that ensures end of line comments work. simple==3.0; python_version > '1.0' """) + _freeze_req_opts) + script.scratch_path.joinpath("hint2.txt").write_text(textwrap.dedent("""\ + iniTools==0.1 + Noexist==4.2 # A comment that ensures end of line comments work. + Simple==3.0; python_version > '1.0' + """) + _freeze_req_opts) result = script.pip_install_local('initools==0.2') result = script.pip_install_local('simple') result = script.pip( - 'freeze', '--requirement', 'hint.txt', + 'freeze', '--requirement', 'hint1.txt', expect_stderr=True, ) expected = textwrap.dedent("""\ @@ -524,6 +529,15 @@ def test_freeze_with_requirement_option(script): "Requirement file [hint.txt] contains NoExist==4.2, but package " "'NoExist' is not installed" ) in result.stderr + result = script.pip( + 'freeze', '--requirement', 'hint2.txt', + expect_stderr=True, + ) + _check_output(result.stdout, expected) + assert ( + "Requirement file [hint.txt] contains NoExist==4.2, but package " + "'NoExist' is not installed" + ) in result.stderr def test_freeze_with_requirement_option_multiple(script):