From 884861f390bb7faf37794e3970671707851d9bb6 Mon Sep 17 00:00:00 2001
From: Paul Moore
Date: Wed, 4 Dec 2013 13:04:54 +0000
Subject: [PATCH 1/2] Added a virtualenv-specific configuration file
---
docs/configuration.rst | 6 ++++++
pip/baseparser.py | 12 +++++++++---
pip/locations.py | 6 ++++--
tests/functional/test_install_config.py | 17 +++++++++++++++++
tests/unit/test_options.py | 14 ++++++++++++++
5 files changed, 50 insertions(+), 5 deletions(-)
diff --git a/docs/configuration.rst b/docs/configuration.rst
index 74e9362bcf6..6e76027244d 100644
--- a/docs/configuration.rst
+++ b/docs/configuration.rst
@@ -19,6 +19,12 @@ platforms.
You can set a custom path location for the config file using the environment variable ``PIP_CONFIG_FILE``.
+In a virtual environment, an additional config file will be read from the base
+directory of the virtualenv (``sys.prefix`` as reported by Python). The base
+name of the file is the same as the user configuration file (:file:`pip.conf`
+on Unix and OSX, :file:`pip.ini` on Windows). Values in the virtualenv-specific
+configuration file take precedence over those in the user configuration file.
+
The names of the settings are derived from the long command line option, e.g.
if you want to use a different package index (``--index-url``) and set the
HTTP timeout (``--default-timeout``) to 60 seconds your config file would
diff --git a/pip/baseparser.py b/pip/baseparser.py
index ce4016033fc..42aca8f5fd7 100644
--- a/pip/baseparser.py
+++ b/pip/baseparser.py
@@ -7,7 +7,7 @@
import textwrap
from distutils.util import strtobool
from pip.backwardcompat import ConfigParser, string_types
-from pip.locations import default_config_file
+from pip.locations import default_config_file, default_config_basename, running_under_virtualenv
from pip.util import get_terminal_size, get_prog
@@ -136,8 +136,14 @@ def __init__(self, *args, **kwargs):
def get_config_files(self):
config_file = os.environ.get('PIP_CONFIG_FILE', False)
if config_file and os.path.exists(config_file):
- return [config_file]
- return [default_config_file]
+ files = [config_file]
+ else:
+ files = [default_config_file]
+ if running_under_virtualenv():
+ venv_config_file = os.path.join(sys.prefix, default_config_basename)
+ if os.path.exists(venv_config_file):
+ files.append(venv_config_file)
+ return files
def check_default(self, option, key, val):
try:
diff --git a/pip/locations.py b/pip/locations.py
index 00cf27cb73a..85e250eb342 100644
--- a/pip/locations.py
+++ b/pip/locations.py
@@ -112,12 +112,14 @@ def _get_build_prefix():
if not os.path.exists(bin_py):
bin_py = os.path.join(sys.prefix, 'bin')
default_storage_dir = os.path.join(user_dir, 'pip')
- default_config_file = os.path.join(default_storage_dir, 'pip.ini')
+ default_config_basename = 'pip.ini'
+ default_config_file = os.path.join(default_storage_dir, default_config_basename)
default_log_file = os.path.join(default_storage_dir, 'pip.log')
else:
bin_py = os.path.join(sys.prefix, 'bin')
default_storage_dir = os.path.join(user_dir, '.pip')
- default_config_file = os.path.join(default_storage_dir, 'pip.conf')
+ default_config_basename = 'pip.conf'
+ default_config_file = os.path.join(default_storage_dir, default_config_basename)
default_log_file = os.path.join(default_storage_dir, 'pip.log')
# Forcing to use /usr/local/bin for standard Mac OS X framework installs
diff --git a/tests/functional/test_install_config.py b/tests/functional/test_install_config.py
index 7a896d35ce4..ca6c360cb4e 100644
--- a/tests/functional/test_install_config.py
+++ b/tests/functional/test_install_config.py
@@ -138,3 +138,20 @@ def test_log_file_no_directory():
fp.close()
assert os.path.exists(fp.name)
os.remove(fp.name)
+
+
+def test_options_from_venv_config(script, virtualenv):
+ """
+ Test if ConfigOptionParser reads a virtualenv-local config file
+
+ """
+ from pip.locations import default_config_basename
+ conf = "[global]\nno-index = true"
+ ini = virtualenv.location / default_config_basename
+ with open(ini, 'w') as f:
+ f.write(conf)
+ result = script.pip('install', '-vvv', 'INITools', expect_error=True)
+ assert "Ignoring indexes:" in result.stdout, str(result)
+ assert "DistributionNotFound: No distributions at all found for INITools" in result.stdout
+
+
diff --git a/tests/unit/test_options.py b/tests/unit/test_options.py
index 56be3ae771a..a50282ee2e7 100644
--- a/tests/unit/test_options.py
+++ b/tests/unit/test_options.py
@@ -226,3 +226,17 @@ def test_cert(self):
options1, args1 = main(['--cert', 'path', 'fake'])
options2, args2 = main(['fake', '--cert', 'path'])
assert options1.cert == options2.cert == 'path'
+
+
+class TestOptionsConfigFiles(object):
+
+ def test_general_option_after_subcommand(self, monkeypatch):
+ # We only want a dummy object to call the get_config_files method
+ monkeypatch.setattr(pip.baseparser.ConfigOptionParser, '__init__', lambda self: None)
+
+ # If we are running in a virtualenv and all files appear to exist,
+ # we should see two config files.
+ monkeypatch.setattr(pip.baseparser, 'running_under_virtualenv', lambda: True)
+ monkeypatch.setattr(os.path, 'exists', lambda filename: True)
+ cp = pip.baseparser.ConfigOptionParser()
+ assert len(cp.get_config_files()) == 2
From 1e7ae116f5bb8c3fc1a34a56a8b6cdee97217d73 Mon Sep 17 00:00:00 2001
From: Paul Moore
Date: Sun, 8 Dec 2013 12:08:22 +0000
Subject: [PATCH 2/2] Typo fixes and clarifications
---
docs/configuration.rst | 3 ++-
tests/unit/test_options.py | 2 +-
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/docs/configuration.rst b/docs/configuration.rst
index 6e76027244d..b1d9faf09ff 100644
--- a/docs/configuration.rst
+++ b/docs/configuration.rst
@@ -23,7 +23,8 @@ In a virtual environment, an additional config file will be read from the base
directory of the virtualenv (``sys.prefix`` as reported by Python). The base
name of the file is the same as the user configuration file (:file:`pip.conf`
on Unix and OSX, :file:`pip.ini` on Windows). Values in the virtualenv-specific
-configuration file take precedence over those in the user configuration file.
+configuration file take precedence over those in the user's configuration file
+(whether from the user home or specified via ``PIP_CONFIG_FILE``).
The names of the settings are derived from the long command line option, e.g.
if you want to use a different package index (``--index-url``) and set the
diff --git a/tests/unit/test_options.py b/tests/unit/test_options.py
index a50282ee2e7..d6f864fb52d 100644
--- a/tests/unit/test_options.py
+++ b/tests/unit/test_options.py
@@ -230,7 +230,7 @@ def test_cert(self):
class TestOptionsConfigFiles(object):
- def test_general_option_after_subcommand(self, monkeypatch):
+ def test_venv_config_file_found(self, monkeypatch):
# We only want a dummy object to call the get_config_files method
monkeypatch.setattr(pip.baseparser.ConfigOptionParser, '__init__', lambda self: None)