Skip to content

Commit af084d9

Browse files
committed
Issue pypa#2677: Disable wheels for setup.py options.
Using --install-options, --build-options, --global-options changes the way that setup.py behaves, and isn't honoured by the wheel code. The new wheel autobuilding code made this very obvious - disable the use of wheels when these options are supplied.
1 parent ff1206f commit af084d9

File tree

7 files changed

+57
-10
lines changed

7 files changed

+57
-10
lines changed

CHANGES.txt

+4
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@
2828
* Allow fine grained control over the use of wheels and source builds.
2929
(:pull:`2699`)
3030

31+
* The use of ``--install-option``, ``--global-option`` or ``--build-option``
32+
disable the use of wheels, and the autobuilding of wheels. (:pull:`2711`))
33+
Fixes :issue:`2677`
34+
3135
**6.1.1 (2015-04-07)**
3236

3337
* No longer ignore dependencies which have been added to the standard library,

pip/cmdoptions.py

+25-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@
1313
from optparse import OptionGroup, SUPPRESS_HELP, Option
1414

1515
from pip.index import (
16-
PyPI, FormatControl, fmt_ctl_handle_mutual_exclude, fmt_ctl_no_use_wheel)
16+
PyPI, FormatControl, fmt_ctl_handle_mutual_exclude, fmt_ctl_no_binary,
17+
fmt_ctl_no_use_wheel)
1718
from pip.locations import CA_BUNDLE_PATH, USER_CACHE_DIR, src_prefix
1819

1920

@@ -35,6 +36,27 @@ def resolve_wheel_no_use_binary(options):
3536
fmt_ctl_no_use_wheel(control)
3637

3738

39+
def check_install_build_global(options, check_options=None):
40+
"""Disable wheels if per-setup.py call options are set.
41+
42+
:param options: The OptionParser options to update.
43+
:param check_options: The options to check, if not supplied defaults to
44+
options.
45+
"""
46+
if check_options is None:
47+
check_options = options
48+
49+
def getname(n):
50+
return getattr(check_options, n, None)
51+
names = ["build_options", "global_options", "install_options"]
52+
if any(map(getname, names)):
53+
control = options.format_control
54+
fmt_ctl_no_binary(control)
55+
warnings.warn(
56+
'Disabling all use of wheels due to the use of --build-options '
57+
'/ --global-options / --install-options.', stacklevel=2)
58+
59+
3860
###########
3961
# options #
4062
###########
@@ -353,9 +375,11 @@ def editable():
353375
'--use-wheel',
354376
dest='use_wheel',
355377
action='store_true',
378+
default=True,
356379
help=SUPPRESS_HELP,
357380
)
358381

382+
# XXX: deprecated, remove in 9.0
359383
no_use_wheel = partial(
360384
Option,
361385
'--no-use-wheel',

pip/commands/install.py

+1
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,7 @@ def _build_package_finder(self, options, index_urls, session):
194194

195195
def run(self, options, args):
196196
cmdoptions.resolve_wheel_no_use_binary(options)
197+
cmdoptions.check_install_build_global(options)
197198

198199
if options.download_dir:
199200
options.ignore_installed = True

pip/commands/wheel.py

+1
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ def check_required_packages(self):
125125
def run(self, options, args):
126126
self.check_required_packages()
127127
cmdoptions.resolve_wheel_no_use_binary(options)
128+
cmdoptions.check_install_build_global(options)
128129

129130
index_urls = [options.index_url] + options.extra_index_urls
130131
if options.no_index:

pip/index.py

+7-2
Original file line numberDiff line numberDiff line change
@@ -1243,12 +1243,17 @@ def fmt_ctl_formats(fmt_ctl, canonical_name):
12431243
return frozenset(result)
12441244

12451245

1246-
def fmt_ctl_no_use_wheel(fmt_ctl):
1246+
def fmt_ctl_no_binary(fmt_ctl):
12471247
fmt_ctl_handle_mutual_exclude(
12481248
':all:', fmt_ctl.no_binary, fmt_ctl.only_binary)
1249+
1250+
1251+
def fmt_ctl_no_use_wheel(fmt_ctl):
1252+
fmt_ctl_no_binary(fmt_ctl)
12491253
warnings.warn(
12501254
'--no-use-wheel is deprecated and will be removed in the future. '
1251-
' Please use --no-binary :all: instead.')
1255+
' Please use --no-binary :all: instead.', DeprecationWarning,
1256+
stacklevel=2)
12521257

12531258

12541259
Search = namedtuple('Search', 'supplied canonical formats')

pip/req/req_file.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,8 @@ def process_line(line, filename, line_number, finder=None, comes_from=None,
140140
args_line = ' '.join(args)
141141
comes_from = '-r %s (line %s)' % (filename, line_number)
142142
isolated = options.isolated_mode if options else False
143+
if options:
144+
cmdoptions.check_install_build_global(options, opts)
143145
# trim the None items
144146
keys = [opt for opt in opts.__dict__ if getattr(opts, opt) is None]
145147
for key in keys:
@@ -215,8 +217,8 @@ def build_parser():
215217
parser = optparse.OptionParser(add_help_option=False)
216218

217219
options = SUPPORTED_OPTIONS + SUPPORTED_OPTIONS_REQ
218-
for option in options:
219-
option = option()
220+
for option_factory in options:
221+
option = option_factory()
220222
# we want no default values; defaults are handled in `pip install`
221223
# parsing. just concerned with values that are specifically set.
222224
option.default = None

tests/unit/test_req_file.py

+15-5
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
from optparse import Values
12
import os
23
import subprocess
34
from textwrap import dedent
@@ -11,7 +12,7 @@
1112
ReqFileOnleOneOptionPerLineError,
1213
ReqFileOptionNotAllowedWithReqError)
1314
from pip.download import PipSession
14-
from pip.index import PackageFinder
15+
from pip.index import FormatControl, PackageFinder
1516
from pip.req.req_install import InstallRequirement
1617
from pip.req.req_file import (parse_requirements, process_line, join_lines,
1718
ignore_comments)
@@ -68,8 +69,10 @@ class TestProcessLine(object):
6869
"""tests for `process_line`"""
6970

7071
def setup(self):
71-
self.options = stub(isolated_mode=False, default_vcs=None,
72-
skip_requirements_regex=False)
72+
self.options = stub(
73+
isolated_mode=False, default_vcs=None,
74+
skip_requirements_regex=False,
75+
format_control=pip.index.FormatControl(set(), set()))
7376

7477
def test_parser_error(self):
7578
with pytest.raises(RequirementsFileParseError):
@@ -335,6 +338,7 @@ def test_install_requirements_with_options(self, tmpdir, finder, session):
335338
install_option = '--prefix=/opt'
336339

337340
content = '''
341+
--only-binary :all:
338342
INITools==2.0 --global-option="{global_option}" \
339343
--install-option "{install_option}"
340344
'''.format(global_option=global_option, install_option=install_option)
@@ -343,8 +347,12 @@ def test_install_requirements_with_options(self, tmpdir, finder, session):
343347
with open(req_path, 'w') as fh:
344348
fh.write(content)
345349

346-
req = next(parse_requirements(req_path, finder=finder,
347-
session=session))
350+
options = Values()
351+
options.format_control = FormatControl(set(), set())
352+
options.skip_requirements_regex = None
353+
options.isolated_mode = False
354+
req = next(parse_requirements(
355+
req_path, finder=finder, options=options, session=session))
348356

349357
req.source_dir = os.curdir
350358
with patch.object(subprocess, 'Popen') as popen:
@@ -357,3 +365,5 @@ def test_install_requirements_with_options(self, tmpdir, finder, session):
357365
assert call.index(install_option) > \
358366
call.index('install') > \
359367
call.index(global_option) > 0
368+
assert options.format_control.no_binary == set([':all:'])
369+
assert options.format_control.only_binary == set([])

0 commit comments

Comments
 (0)