From fc456dfd0caacacacd71128c18cd44994573a0e2 Mon Sep 17 00:00:00 2001 From: Yuan Jing Vincent Yan Date: Sat, 27 Oct 2018 14:45:07 -0400 Subject: [PATCH] pip freeze: skip local directory by default --- news/2926.bugfix | 1 + src/pip/_internal/operations/freeze.py | 3 +- src/pip/_internal/utils/misc.py | 24 +++++++++++-- tests/functional/test_freeze.py | 49 +++++++++++++++++--------- tests/unit/test_utils.py | 34 +++++++++++++----- 5 files changed, 83 insertions(+), 28 deletions(-) create mode 100644 news/2926.bugfix diff --git a/news/2926.bugfix b/news/2926.bugfix new file mode 100644 index 00000000000..ab9b646f273 --- /dev/null +++ b/news/2926.bugfix @@ -0,0 +1 @@ +Skip local directory by default for 'pip freeze'. diff --git a/src/pip/_internal/operations/freeze.py b/src/pip/_internal/operations/freeze.py index db3bcd4f815..231f3983950 100644 --- a/src/pip/_internal/operations/freeze.py +++ b/src/pip/_internal/operations/freeze.py @@ -39,7 +39,8 @@ def freeze( installations = {} for dist in get_installed_distributions(local_only=local_only, skip=(), - user_only=user_only): + user_only=user_only, + include_curr_dir=False): try: req = FrozenRequirement.from_dist(dist) except RequirementParseError: diff --git a/src/pip/_internal/utils/misc.py b/src/pip/_internal/utils/misc.py index c5a46a25565..8990fb7d9d8 100644 --- a/src/pip/_internal/utils/misc.py +++ b/src/pip/_internal/utils/misc.py @@ -330,11 +330,20 @@ def dist_is_editable(dist): return False +def dist_in_curr_dir(dist): + ''' + Return True if given Distribution is installed in the current directory. + ''' + norm_path = normalize_path(dist_location(dist)) + return norm_path.startswith(normalize_path(os.getcwd())) + + def get_installed_distributions(local_only=True, skip=stdlib_pkgs, include_editables=True, editables_only=False, - user_only=False): + user_only=False, + include_curr_dir=True): """ Return a list of installed Distribution objects. @@ -351,6 +360,9 @@ def get_installed_distributions(local_only=True, If ``user_only`` is True , only report installations in the user site directory. + If ``include_curr_dir`` is False, ignore the current directory when + looking for installations. + """ if local_only: local_test = dist_is_local @@ -378,12 +390,20 @@ def editables_only_test(d): def user_test(d): return True + if include_curr_dir: + def curr_dir_test(d): + return True + else: + def curr_dir_test(d): + return not dist_in_curr_dir(d) + return [d for d in pkg_resources.working_set if local_test(d) and d.key not in skip and editable_test(d) and editables_only_test(d) and - user_test(d) + user_test(d) and + curr_dir_test(d) ] diff --git a/tests/functional/test_freeze.py b/tests/functional/test_freeze.py index 53f49858154..05e1344a8a0 100644 --- a/tests/functional/test_freeze.py +++ b/tests/functional/test_freeze.py @@ -42,6 +42,25 @@ def banner(msg): ) +def _fake_install(pkgname, dest): + egg_info_path = os.path.join( + dest, '{}-1.0-py{}.{}.egg-info'.format( + pkgname.replace('-', '_'), + sys.version_info[0], + sys.version_info[1] + ) + ) + with open(egg_info_path, 'w') as egg_info_file: + egg_info_file.write(textwrap.dedent("""\ + Metadata-Version: 1.0 + Name: {} + Version: 1.0 + """.format(pkgname) + )) + + return egg_info_path + + def test_basic_freeze(script): """ Some tests of freeze, first we have to install some stuff. Note that @@ -73,34 +92,30 @@ def test_freeze_with_pip(script): assert 'pip==' in result.stdout +def test_freeze_skip_curr_dir(script): + ''' + Test that 'pip freeze' skips current directory by default. + ''' + + curr_dir = os.getcwd() + egg_info_path = _fake_install("local-package", curr_dir) + result = script.pip('freeze') + os.remove(egg_info_path) + assert 'local-package==' not in result.stdout + + def test_freeze_with_invalid_names(script): """ Test that invalid names produce warnings and are passed over gracefully. """ - def fake_install(pkgname, dest): - egg_info_path = os.path.join( - dest, '{}-1.0-py{}.{}.egg-info'.format( - pkgname.replace('-', '_'), - sys.version_info[0], - sys.version_info[1] - ) - ) - with open(egg_info_path, 'w') as egg_info_file: - egg_info_file.write(textwrap.dedent("""\ - Metadata-Version: 1.0 - Name: {} - Version: 1.0 - """.format(pkgname) - )) - valid_pkgnames = ('middle-dash', 'middle_underscore', 'middle.dot') invalid_pkgnames = ( '-leadingdash', '_leadingunderscore', '.leadingdot', 'trailingdash-', 'trailingunderscore_', 'trailingdot.' ) for pkgname in valid_pkgnames + invalid_pkgnames: - fake_install(pkgname, script.site_packages_path) + _fake_install(pkgname, script.site_packages_path) result = script.pip('freeze', expect_stderr=True) for pkgname in valid_pkgnames: _check_output( diff --git a/tests/unit/test_utils.py b/tests/unit/test_utils.py index 6aab631c2b2..540b54cef4f 100644 --- a/tests/unit/test_utils.py +++ b/tests/unit/test_utils.py @@ -166,6 +166,7 @@ def test_noegglink_in_sitepkgs_venv_global(self): assert egg_link_path(self.mock_dist) is None +@patch('pip._internal.utils.misc.dist_in_curr_dir') @patch('pip._internal.utils.misc.dist_in_usersite') @patch('pip._internal.utils.misc.dist_is_local') @patch('pip._internal.utils.misc.dist_is_editable') @@ -177,6 +178,7 @@ class Tests_get_installed_distributions: Mock(test_name="editable"), Mock(test_name="normal"), Mock(test_name="user"), + Mock(test_name="curr_dir") ] workingset_stdlib = [ @@ -199,13 +201,18 @@ def dist_is_local(self, dist): def dist_in_usersite(self, dist): return dist.test_name == "user" + def dist_in_curr_dir(self, dist): + return dist.test_name == "curr_dir" + @patch('pip._vendor.pkg_resources.working_set', workingset) def test_editables_only(self, mock_dist_is_editable, mock_dist_is_local, - mock_dist_in_usersite): + mock_dist_in_usersite, + mock_dist_in_curr_dir): mock_dist_is_editable.side_effect = self.dist_is_editable mock_dist_is_local.side_effect = self.dist_is_local mock_dist_in_usersite.side_effect = self.dist_in_usersite + mock_dist_in_curr_dir.side_effect = self.dist_in_curr_dir dists = get_installed_distributions(editables_only=True) assert len(dists) == 1, dists assert dists[0].test_name == "editable" @@ -213,31 +220,38 @@ def test_editables_only(self, mock_dist_is_editable, @patch('pip._vendor.pkg_resources.working_set', workingset) def test_exclude_editables(self, mock_dist_is_editable, mock_dist_is_local, - mock_dist_in_usersite): + mock_dist_in_usersite, + mock_dist_in_curr_dir): mock_dist_is_editable.side_effect = self.dist_is_editable mock_dist_is_local.side_effect = self.dist_is_local mock_dist_in_usersite.side_effect = self.dist_in_usersite + mock_dist_in_curr_dir.side_effect = self.dist_in_curr_dir dists = get_installed_distributions(include_editables=False) - assert len(dists) == 1 + assert len(dists) == 2 assert dists[0].test_name == "normal" + assert dists[1].test_name == "curr_dir" @patch('pip._vendor.pkg_resources.working_set', workingset) def test_include_globals(self, mock_dist_is_editable, mock_dist_is_local, - mock_dist_in_usersite): + mock_dist_in_usersite, + mock_dist_in_curr_dir): mock_dist_is_editable.side_effect = self.dist_is_editable mock_dist_is_local.side_effect = self.dist_is_local mock_dist_in_usersite.side_effect = self.dist_in_usersite + mock_dist_in_curr_dir.side_effect = self.dist_in_curr_dir dists = get_installed_distributions(local_only=False) - assert len(dists) == 4 + assert len(dists) == 5 @patch('pip._vendor.pkg_resources.working_set', workingset) def test_user_only(self, mock_dist_is_editable, mock_dist_is_local, - mock_dist_in_usersite): + mock_dist_in_usersite, + mock_dist_in_curr_dir): mock_dist_is_editable.side_effect = self.dist_is_editable mock_dist_is_local.side_effect = self.dist_is_local mock_dist_in_usersite.side_effect = self.dist_in_usersite + mock_dist_in_curr_dir.side_effect = self.dist_in_curr_dir dists = get_installed_distributions(local_only=False, user_only=True) assert len(dists) == 1 @@ -246,20 +260,24 @@ def test_user_only(self, mock_dist_is_editable, @patch('pip._vendor.pkg_resources.working_set', workingset_stdlib) def test_gte_py27_excludes(self, mock_dist_is_editable, mock_dist_is_local, - mock_dist_in_usersite): + mock_dist_in_usersite, + mock_dist_in_curr_dir): mock_dist_is_editable.side_effect = self.dist_is_editable mock_dist_is_local.side_effect = self.dist_is_local mock_dist_in_usersite.side_effect = self.dist_in_usersite + mock_dist_in_curr_dir.side_effect = self.dist_in_curr_dir dists = get_installed_distributions() assert len(dists) == 0 @patch('pip._vendor.pkg_resources.working_set', workingset_freeze) def test_freeze_excludes(self, mock_dist_is_editable, mock_dist_is_local, - mock_dist_in_usersite): + mock_dist_in_usersite, + mock_dist_in_curr_dir): mock_dist_is_editable.side_effect = self.dist_is_editable mock_dist_is_local.side_effect = self.dist_is_local mock_dist_in_usersite.side_effect = self.dist_in_usersite + mock_dist_in_curr_dir.side_effect = self.dist_in_curr_dir dists = get_installed_distributions( skip=('setuptools', 'pip', 'distribute')) assert len(dists) == 0