Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 521ed52

Browse files
committed
Closes issue #17732: ignore install-directory specific options in
distutils.cfg when a venv is active.
1 parent b3bd624 commit 521ed52

5 files changed

Lines changed: 87 additions & 3 deletions

File tree

Doc/install/index.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -645,6 +645,11 @@ environment variables, such as Mac OS 9, the configuration variables supplied by
645645
the Distutils are the only ones you can use.) See section :ref:`inst-config-files`
646646
for details.
647647

648+
.. note:: When a :ref:`virtual environment <venv-def>` is activated, any options
649+
that change the installation path will be ignored from all distutils configuration
650+
files to prevent inadvertently installing projects outside of the virtual
651+
environment.
652+
648653
.. XXX need some Windows examples---when would custom installation schemes be
649654
needed on those platforms?
650655

Doc/library/venv.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,10 @@ Creating virtual environments
5757
:attr:`sys.exec_prefix` is the same as :attr:`sys.base_exec_prefix` (they
5858
all point to a non-venv Python installation).
5959

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

6165
API
6266
---

Lib/distutils/dist.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,18 @@ def find_config_files(self):
343343
def parse_config_files(self, filenames=None):
344344
from configparser import ConfigParser
345345

346+
# Ignore install directory options if we have a venv
347+
if sys.prefix != sys.base_prefix:
348+
ignore_options = [
349+
'install-base', 'install-platbase', 'install-lib',
350+
'install-platlib', 'install-purelib', 'install-headers',
351+
'install-scripts', 'install-data', 'prefix', 'exec-prefix',
352+
'home', 'user', 'root']
353+
else:
354+
ignore_options = []
355+
356+
ignore_options = frozenset(ignore_options)
357+
346358
if filenames is None:
347359
filenames = self.find_config_files()
348360

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

361373
for opt in options:
362-
if opt != '__name__':
374+
if opt != '__name__' and opt not in ignore_options:
363375
val = parser.get(section,opt)
364376
opt = opt.replace('-', '_')
365377
opt_dict[opt] = (filename, val)

Lib/distutils/tests/test_dist.py

Lines changed: 62 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
import warnings
77
import textwrap
88

9+
from unittest import mock
10+
911
from distutils.dist import Distribution, fix_help_options
1012
from distutils.cmd import Command
1113

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

1921
user_options = [
2022
("sample-option=", "S", "help text"),
21-
]
23+
]
2224

2325
def initialize_options(self):
2426
self.sample_option = None
@@ -77,6 +79,64 @@ def test_command_packages_cmdline(self):
7779
self.assertIsInstance(cmd, test_dist)
7880
self.assertEqual(cmd.sample_option, "sometext")
7981

82+
def test_venv_install_options(self):
83+
sys.argv.append("install")
84+
self.addCleanup(os.unlink, TESTFN)
85+
86+
fakepath = '/somedir'
87+
88+
with open(TESTFN, "w") as f:
89+
print(("[install]\n"
90+
"install-base = {0}\n"
91+
"install-platbase = {0}\n"
92+
"install-lib = {0}\n"
93+
"install-platlib = {0}\n"
94+
"install-purelib = {0}\n"
95+
"install-headers = {0}\n"
96+
"install-scripts = {0}\n"
97+
"install-data = {0}\n"
98+
"prefix = {0}\n"
99+
"exec-prefix = {0}\n"
100+
"home = {0}\n"
101+
"user = {0}\n"
102+
"root = {0}").format(fakepath), file=f)
103+
104+
# Base case: Not in a Virtual Environment
105+
with mock.patch.multiple(sys, prefix='/a', base_prefix='/a') as values:
106+
d = self.create_distribution([TESTFN])
107+
108+
option_tuple = (TESTFN, fakepath)
109+
110+
result_dict = {
111+
'install_base': option_tuple,
112+
'install_platbase': option_tuple,
113+
'install_lib': option_tuple,
114+
'install_platlib': option_tuple,
115+
'install_purelib': option_tuple,
116+
'install_headers': option_tuple,
117+
'install_scripts': option_tuple,
118+
'install_data': option_tuple,
119+
'prefix': option_tuple,
120+
'exec_prefix': option_tuple,
121+
'home': option_tuple,
122+
'user': option_tuple,
123+
'root': option_tuple,
124+
}
125+
126+
self.assertEqual(
127+
sorted(d.command_options.get('install').keys()),
128+
sorted(result_dict.keys()))
129+
130+
for (key, value) in d.command_options.get('install').items():
131+
self.assertEqual(value, result_dict[key])
132+
133+
# Test case: In a Virtual Environment
134+
with mock.patch.multiple(sys, prefix='/a', base_prefix='/b') as values:
135+
d = self.create_distribution([TESTFN])
136+
137+
for key in result_dict.keys():
138+
self.assertNotIn(key, d.command_options.get('install', {}))
139+
80140
def test_command_packages_configfile(self):
81141
sys.argv.append("build")
82142
self.addCleanup(os.unlink, TESTFN)
@@ -304,7 +364,7 @@ def test_custom_pydistutils(self):
304364
os.environ['HOME'] = temp_dir
305365
files = dist.find_config_files()
306366
self.assertIn(user_filename, files,
307-
'%r not found in %r' % (user_filename, files))
367+
'%r not found in %r' % (user_filename, files))
308368
finally:
309369
os.remove(user_filename)
310370

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@ Core and Builtins
4949
Library
5050
-------
5151

52+
- Issue #17732: Ignore distutils.cfg options pertaining to install paths if a
53+
virtual environment is active.
54+
5255
- Issue #1159051: Back out a fix for handling corrupted gzip files that
5356
broke backwards compatibility.
5457

0 commit comments

Comments
 (0)