Skip to content

Commit

Permalink
Closes issue python#17732: ignore install-directory specific options in
Browse files Browse the repository at this point in the history
distutils.cfg when a venv is active.
  • Loading branch information
birkenfeld committed May 12, 2013
1 parent b3bd624 commit 521ed52
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 3 deletions.
5 changes: 5 additions & 0 deletions Doc/install/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -645,6 +645,11 @@ environment variables, such as Mac OS 9, the configuration variables supplied by
the Distutils are the only ones you can use.) See section :ref:`inst-config-files`
for details.

.. note:: When a :ref:`virtual environment <venv-def>` is activated, any options
that change the installation path will be ignored from all distutils configuration
files to prevent inadvertently installing projects outside of the virtual
environment.

.. XXX need some Windows examples---when would custom installation schemes be
needed on those platforms?
Expand Down
4 changes: 4 additions & 0 deletions Doc/library/venv.rst
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ Creating virtual environments
:attr:`sys.exec_prefix` is the same as :attr:`sys.base_exec_prefix` (they
all point to a non-venv Python installation).

When a venv is active, any options that change the installation path will be
ignored from all distutils configuration files to prevent projects being
inadvertently installed outside of the virtual environment.


API
---
Expand Down
14 changes: 13 additions & 1 deletion Lib/distutils/dist.py
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,18 @@ def find_config_files(self):
def parse_config_files(self, filenames=None):
from configparser import ConfigParser

# Ignore install directory options if we have a venv
if sys.prefix != sys.base_prefix:
ignore_options = [
'install-base', 'install-platbase', 'install-lib',
'install-platlib', 'install-purelib', 'install-headers',
'install-scripts', 'install-data', 'prefix', 'exec-prefix',
'home', 'user', 'root']
else:
ignore_options = []

ignore_options = frozenset(ignore_options)

if filenames is None:
filenames = self.find_config_files()

Expand All @@ -359,7 +371,7 @@ def parse_config_files(self, filenames=None):
opt_dict = self.get_option_dict(section)

for opt in options:
if opt != '__name__':
if opt != '__name__' and opt not in ignore_options:
val = parser.get(section,opt)
opt = opt.replace('-', '_')
opt_dict[opt] = (filename, val)
Expand Down
64 changes: 62 additions & 2 deletions Lib/distutils/tests/test_dist.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
import warnings
import textwrap

from unittest import mock

from distutils.dist import Distribution, fix_help_options
from distutils.cmd import Command

Expand All @@ -18,7 +20,7 @@ class test_dist(Command):

user_options = [
("sample-option=", "S", "help text"),
]
]

def initialize_options(self):
self.sample_option = None
Expand Down Expand Up @@ -77,6 +79,64 @@ def test_command_packages_cmdline(self):
self.assertIsInstance(cmd, test_dist)
self.assertEqual(cmd.sample_option, "sometext")

def test_venv_install_options(self):
sys.argv.append("install")
self.addCleanup(os.unlink, TESTFN)

fakepath = '/somedir'

with open(TESTFN, "w") as f:
print(("[install]\n"
"install-base = {0}\n"
"install-platbase = {0}\n"
"install-lib = {0}\n"
"install-platlib = {0}\n"
"install-purelib = {0}\n"
"install-headers = {0}\n"
"install-scripts = {0}\n"
"install-data = {0}\n"
"prefix = {0}\n"
"exec-prefix = {0}\n"
"home = {0}\n"
"user = {0}\n"
"root = {0}").format(fakepath), file=f)

# Base case: Not in a Virtual Environment
with mock.patch.multiple(sys, prefix='/a', base_prefix='/a') as values:
d = self.create_distribution([TESTFN])

option_tuple = (TESTFN, fakepath)

result_dict = {
'install_base': option_tuple,
'install_platbase': option_tuple,
'install_lib': option_tuple,
'install_platlib': option_tuple,
'install_purelib': option_tuple,
'install_headers': option_tuple,
'install_scripts': option_tuple,
'install_data': option_tuple,
'prefix': option_tuple,
'exec_prefix': option_tuple,
'home': option_tuple,
'user': option_tuple,
'root': option_tuple,
}

self.assertEqual(
sorted(d.command_options.get('install').keys()),
sorted(result_dict.keys()))

for (key, value) in d.command_options.get('install').items():
self.assertEqual(value, result_dict[key])

# Test case: In a Virtual Environment
with mock.patch.multiple(sys, prefix='/a', base_prefix='/b') as values:
d = self.create_distribution([TESTFN])

for key in result_dict.keys():
self.assertNotIn(key, d.command_options.get('install', {}))

def test_command_packages_configfile(self):
sys.argv.append("build")
self.addCleanup(os.unlink, TESTFN)
Expand Down Expand Up @@ -304,7 +364,7 @@ def test_custom_pydistutils(self):
os.environ['HOME'] = temp_dir
files = dist.find_config_files()
self.assertIn(user_filename, files,
'%r not found in %r' % (user_filename, files))
'%r not found in %r' % (user_filename, files))
finally:
os.remove(user_filename)

Expand Down
3 changes: 3 additions & 0 deletions Misc/NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ Core and Builtins
Library
-------

- Issue #17732: Ignore distutils.cfg options pertaining to install paths if a
virtual environment is active.

- Issue #1159051: Back out a fix for handling corrupted gzip files that
broke backwards compatibility.

Expand Down

0 comments on commit 521ed52

Please sign in to comment.