diff --git a/src/pip/_internal/commands/configuration.py b/src/pip/_internal/commands/configuration.py index 8d4c95928..1ec77d2a6 100644 --- a/src/pip/_internal/commands/configuration.py +++ b/src/pip/_internal/commands/configuration.py @@ -4,9 +4,10 @@ import subprocess from pip._internal.cli.base_command import Command from pip._internal.cli.status_codes import ERROR, SUCCESS -from pip._internal.configuration import Configuration, kinds +from pip._internal.configuration import ( + Configuration, get_configuration_files, kinds, +) from pip._internal.exceptions import PipError -from pip._internal.locations import site_config_file from pip._internal.utils.deprecation import deprecated from pip._internal.utils.misc import get_prog from pip._internal.utils.virtualenv import running_under_virtualenv @@ -165,7 +166,10 @@ class ConfigurationCommand(Command): if not need_value: return None # Default to user, unless there's a site file. - elif os.path.exists(site_config_file): + elif any( + os.path.exists(site_config_file) + for site_config_file in get_configuration_files()[kinds.SITE] + ): return kinds.SITE else: return kinds.USER diff --git a/src/pip/_internal/configuration.py b/src/pip/_internal/configuration.py index 783fa93f0..437e92eeb 100644 --- a/src/pip/_internal/configuration.py +++ b/src/pip/_internal/configuration.py @@ -14,15 +14,15 @@ Some terminology: import locale import logging import os +import sys from pip._vendor.six.moves import configparser from pip._internal.exceptions import ( ConfigurationError, ConfigurationFileCouldNotBeLoaded, ) -from pip._internal.locations import ( - global_config_files, legacy_config_file, new_config_file, site_config_file, -) +from pip._internal.utils import appdirs +from pip._internal.utils.compat import WINDOWS, expanduser from pip._internal.utils.misc import ensure_dir, enum from pip._internal.utils.typing import MYPY_CHECK_RUNNING @@ -69,6 +69,31 @@ kinds = enum( ) +CONFIG_BASENAME = 'pip.ini' if WINDOWS else 'pip.conf' + + +def get_configuration_files(): + global_config_files = [ + os.path.join(path, CONFIG_BASENAME) + for path in appdirs.site_config_dirs('pip') + ] + + site_config_file = os.path.join(sys.prefix, CONFIG_BASENAME) + legacy_config_file = os.path.join( + expanduser('~'), + 'pip' if WINDOWS else '.pip', + CONFIG_BASENAME, + ) + new_config_file = os.path.join( + appdirs.user_config_dir("pip"), CONFIG_BASENAME + ) + return { + kinds.GLOBAL: global_config_files, + kinds.SITE: [site_config_file], + kinds.USER: [legacy_config_file, new_config_file], + } + + class Configuration(object): """Handles management of configuration. @@ -355,8 +380,10 @@ class Configuration(object): else: yield kinds.ENV, [] + config_files = get_configuration_files() + # at the base we have any global configuration - yield kinds.GLOBAL, list(global_config_files) + yield kinds.GLOBAL, config_files[kinds.GLOBAL] # per-user configuration next should_load_user_config = not self.isolated and not ( @@ -364,10 +391,10 @@ class Configuration(object): ) if should_load_user_config: # The legacy config file is overridden by the new config file - yield kinds.USER, [legacy_config_file, new_config_file] + yield kinds.USER, config_files[kinds.USER] # finally virtualenv configuration first trumping others - yield kinds.SITE, [site_config_file] + yield kinds.SITE, config_files[kinds.SITE] def _get_parser_to_modify(self): # type: () -> Tuple[str, RawConfigParser] diff --git a/src/pip/_internal/locations.py b/src/pip/_internal/locations.py index 94996c8a6..5f843d797 100644 --- a/src/pip/_internal/locations.py +++ b/src/pip/_internal/locations.py @@ -11,7 +11,7 @@ from distutils import sysconfig as distutils_sysconfig from distutils.command.install import SCHEME_KEYS # type: ignore from pip._internal.utils import appdirs -from pip._internal.utils.compat import WINDOWS, expanduser +from pip._internal.utils.compat import WINDOWS from pip._internal.utils.typing import MYPY_CHECK_RUNNING from pip._internal.utils.virtualenv import running_under_virtualenv @@ -56,7 +56,7 @@ try: user_site = site.getusersitepackages() except AttributeError: user_site = site.USER_SITE -user_dir = expanduser('~') + if WINDOWS: bin_py = os.path.join(sys.prefix, 'Scripts') bin_user = os.path.join(user_site, 'Scripts') @@ -64,38 +64,15 @@ if WINDOWS: if not os.path.exists(bin_py): bin_py = os.path.join(sys.prefix, 'bin') bin_user = os.path.join(user_site, 'bin') - - config_basename = 'pip.ini' - - legacy_storage_dir = os.path.join(user_dir, 'pip') - legacy_config_file = os.path.join( - legacy_storage_dir, - config_basename, - ) else: bin_py = os.path.join(sys.prefix, 'bin') bin_user = os.path.join(user_site, 'bin') - config_basename = 'pip.conf' - - legacy_storage_dir = os.path.join(user_dir, '.pip') - legacy_config_file = os.path.join( - legacy_storage_dir, - config_basename, - ) # Forcing to use /usr/local/bin for standard macOS framework installs # Also log to ~/Library/Logs/ for use with the Console.app log viewer if sys.platform[:6] == 'darwin' and sys.prefix[:16] == '/System/Library/': bin_py = '/usr/local/bin' -global_config_files = [ - os.path.join(path, config_basename) - for path in appdirs.site_config_dirs('pip') -] - -site_config_file = os.path.join(sys.prefix, config_basename) -new_config_file = os.path.join(appdirs.user_config_dir("pip"), config_basename) - def distutils_scheme(dist_name, user=False, home=None, root=None, isolated=False, prefix=None): diff --git a/tests/functional/test_install_config.py b/tests/functional/test_install_config.py index e6625c8cc..4cb2e3e7c 100644 --- a/tests/functional/test_install_config.py +++ b/tests/functional/test_install_config.py @@ -192,9 +192,9 @@ def test_options_from_venv_config(script, virtualenv): Test if ConfigOptionParser reads a virtualenv-local config file """ - from pip._internal.locations import config_basename + from pip._internal.configuration import CONFIG_BASENAME conf = "[global]\nno-index = true" - ini = virtualenv.location / config_basename + ini = virtualenv.location / CONFIG_BASENAME with open(ini, 'w') as f: f.write(conf) result = script.pip('install', '-vvv', 'INITools', expect_error=True) diff --git a/tests/unit/test_configuration.py b/tests/unit/test_configuration.py index 01a9a7779..f16252f44 100644 --- a/tests/unit/test_configuration.py +++ b/tests/unit/test_configuration.py @@ -6,11 +6,9 @@ import os import pytest from mock import MagicMock +from pip._internal.configuration import get_configuration_files, kinds from pip._internal.exceptions import ConfigurationError -from pip._internal.locations import ( - global_config_files, new_config_file, site_config_file, -) -from tests.lib.configuration_helpers import ConfigurationMixin, kinds +from tests.lib.configuration_helpers import ConfigurationMixin class TestConfigurationLoading(ConfigurationMixin): @@ -194,7 +192,9 @@ class TestConfigurationModification(ConfigurationMixin): # get the path to site config file assert mymock.call_count == 1 - assert mymock.call_args[0][0] == site_config_file + assert mymock.call_args[0][0] == ( + get_configuration_files()[kinds.SITE][0] + ) def test_user_modification(self): # get the path to local config file @@ -209,7 +209,10 @@ class TestConfigurationModification(ConfigurationMixin): # get the path to user config file assert mymock.call_count == 1 - assert mymock.call_args[0][0] == new_config_file + assert mymock.call_args[0][0] == ( + # Use new config file + get_configuration_files()[kinds.USER][1] + ) def test_global_modification(self): # get the path to local config file @@ -224,4 +227,6 @@ class TestConfigurationModification(ConfigurationMixin): # get the path to user config file assert mymock.call_count == 1 - assert mymock.call_args[0][0] == global_config_files[-1] + assert mymock.call_args[0][0] == ( + get_configuration_files()[kinds.GLOBAL][-1] + ) diff --git a/tests/unit/test_options.py b/tests/unit/test_options.py index 1bcee00bf..0eb452ef4 100644 --- a/tests/unit/test_options.py +++ b/tests/unit/test_options.py @@ -384,9 +384,10 @@ class TestGeneralOptions(AddFakeCommandMixin): class TestOptionsConfigFiles(object): def test_venv_config_file_found(self, monkeypatch): - # strict limit on the global_config_files list + # strict limit on the global config files list monkeypatch.setattr( - pip._internal.configuration, 'global_config_files', ['/a/place'] + pip._internal.utils.appdirs, 'site_config_dirs', + lambda _: ['/a/place'] ) cp = pip._internal.configuration.Configuration(isolated=False)