From 8900f4f947d314c6fdb5fea21a72b0d739811e26 Mon Sep 17 00:00:00 2001 From: derwolfe Date: Tue, 30 Dec 2014 17:44:45 -0600 Subject: [PATCH 01/29] add tests back in --- .../functional/test_install_missing_extras.py | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 tests/functional/test_install_missing_extras.py diff --git a/tests/functional/test_install_missing_extras.py b/tests/functional/test_install_missing_extras.py new file mode 100644 index 00000000000..6474681e0c9 --- /dev/null +++ b/tests/functional/test_install_missing_extras.py @@ -0,0 +1,35 @@ +""" +temporarily locate test here to make it fail faster +""" + +def test_non_existant_extra_warns_user_with_wheel(script, data): + """ + A warning is logged telling the user that the extra option they requested + does not exist in the project they are wishing to install + """ + result = script.pip( + 'install', '--use-wheel', '--no-index', + '--find-links=' + data.find_links, + 'simplewheel[nonexistant]', expect_stderr=True, + ) + assert ( + "simplewheel 2.0 has no such extra feature 'nonexistant'" + in result.stdout + ) + +def test_non_existant_extra_warns_user_no_wheel(script, data): + """ + A warning is logged telling the user that the extra option they requested + does not exist in the project they are wishing to install. + + This is meant to exercise the code that is meant for non-wheel installs. + """ + result = script.pip( + 'install', '--no-use-wheel', + '--no-index', '--find-links=' + data.find_links, + 'simple[nonexistant]', expect_stderr=True, + ) + assert ( + "simple 3.0 has no such extra feature 'nonexistant'" + in result.stdout + ) From deabed5d893eaa182cca42c575d487560bf010af Mon Sep 17 00:00:00 2001 From: derwolfe Date: Tue, 30 Dec 2014 17:48:10 -0600 Subject: [PATCH 02/29] log an error when an extra is requested that doesn't exist --- pip/req/req_set.py | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/pip/req/req_set.py b/pip/req/req_set.py index cf39045f2eb..54b5bc7af20 100644 --- a/pip/req/req_set.py +++ b/pip/req/req_set.py @@ -432,19 +432,22 @@ def prepare_files(self, finder): ) if not self.ignore_dependencies: - for subreq in dist.requires( - req_to_install.extras): - if self.has_requirement( - subreq.project_name): - # FIXME: check for conflict - continue - subreq = InstallRequirement( - str(subreq), - req_to_install, - isolated=self.isolated, - ) - reqs.append(subreq) - self.add_requirement(subreq) + try: + for subreq in dist.requires( + req_to_install.extras): + if self.has_requirement( + subreq.project_name): + # FIXME: check for conflict + continue + subreq = InstallRequirement( + str(subreq), + req_to_install, + isolated=self.isolated, + ) + reqs.append(subreq) + self.add_requirement(subreq) + except pkg_resources.UnknownExtra as ex: + logger.error(ex) if not self.has_requirement(req_to_install.name): # 'unnamed' requirements will get added here From 91f80102dd67f7396855de89a820292c7d2c6006 Mon Sep 17 00:00:00 2001 From: derwolfe Date: Tue, 30 Dec 2014 19:30:40 -0600 Subject: [PATCH 03/29] logging working a bit better Need to access the extras defined on the distribution itself. This way I could just check for membership in the set of extras defined, and throw an error for each, instead of stopping entirely. --- pip/_vendor/pkg_resources.py | 1 + pip/req/req_set.py | 13 +++ .../functional/test_install_missing_extras.py | 80 +++++++++++++------ 3 files changed, 69 insertions(+), 25 deletions(-) diff --git a/pip/_vendor/pkg_resources.py b/pip/_vendor/pkg_resources.py index 370db217adf..04add8afac9 100644 --- a/pip/_vendor/pkg_resources.py +++ b/pip/_vendor/pkg_resources.py @@ -2483,6 +2483,7 @@ def requires(self, extras=()): dm = self._dep_map deps = [] deps.extend(dm.get(None, ())) + for ext in extras: try: deps.extend(dm[safe_extra(ext)]) diff --git a/pip/req/req_set.py b/pip/req/req_set.py index 54b5bc7af20..daef42870ae 100644 --- a/pip/req/req_set.py +++ b/pip/req/req_set.py @@ -432,7 +432,18 @@ def prepare_files(self, finder): ) if not self.ignore_dependencies: + # it seems like this should already know what the + # extra options are, then check for option in the list. + # instead, the current code throws an exception when + # checking for the option. + # further, this will fail on the very first check + # e.g. if a single non-existant one is found, then + # it stops trying to install extras. try: + # req_to_install.extras are the extras + # the user *would like* to install. + # how to get the available options + print req_to_install.extras for subreq in dist.requires( req_to_install.extras): if self.has_requirement( @@ -447,6 +458,8 @@ def prepare_files(self, finder): reqs.append(subreq) self.add_requirement(subreq) except pkg_resources.UnknownExtra as ex: + # looks like the project_name isn't set. + # shouldn't it be? logger.error(ex) if not self.has_requirement(req_to_install.name): diff --git a/tests/functional/test_install_missing_extras.py b/tests/functional/test_install_missing_extras.py index 6474681e0c9..8ad5d633a07 100644 --- a/tests/functional/test_install_missing_extras.py +++ b/tests/functional/test_install_missing_extras.py @@ -2,34 +2,64 @@ temporarily locate test here to make it fail faster """ -def test_non_existant_extra_warns_user_with_wheel(script, data): +# def test_non_existant_extra_warns_user_with_wheel(script, data): +# """ +# A warning is logged telling the user that the extra option they requested +# does not exist in the project they are wishing to install +# """ +# result = script.pip( +# 'install', '--use-wheel', '--no-index', +# '--find-links=' + data.find_links, +# 'simplewheel[nonexistant]', expect_stderr=True, +# ) +# assert ( +# "simplewheel 2.0 has no such extra feature 'nonexistant'" +# in result.stdout +# ) + +# def test_non_existant_extra_warns_user_no_wheel(script, data): +# """ +# A warning is logged telling the user that the extra option they requested +# does not exist in the project they are wishing to install. + +# This is meant to exercise the code that is meant for non-wheel installs. +# """ +# result = script.pip( +# 'install', '--no-use-wheel', '--no-index', +# '--find-links=' + data.find_links, +# 'simple[nonexistant]', expect_stderr=True, +# ) +# assert ( +# "simple 3.0 has no such extra feature 'nonexistant'" +# in result.stdout +# ) + +# def test_non_existant_extras_warn_user_no_wheel(script, data): +# """ +# Warn the user for each extra that doesn't exist. +# """ +# result = script.pip( +# 'install', '--use-wheel', '--no-index', +# '--find-links=' + data.find_links, +# 'simplewheel[nonexistant]', expect_stderr=True, +# ) +# assert ( +# "simple 3.0 has no such extra feature 'nonexistant'" +# in result.stdout +# ) +# assert ( +# "simple 3.0 has no such extra feature 'nope'" +# in result.stdout +# ) + +def test_shows_existing_extrasl(script, data): """ - A warning is logged telling the user that the extra option they requested - does not exist in the project they are wishing to install + Warn the user for each extra that doesn't exist. """ result = script.pip( 'install', '--use-wheel', '--no-index', '--find-links=' + data.find_links, - 'simplewheel[nonexistant]', expect_stderr=True, - ) - assert ( - "simplewheel 2.0 has no such extra feature 'nonexistant'" - in result.stdout - ) - -def test_non_existant_extra_warns_user_no_wheel(script, data): - """ - A warning is logged telling the user that the extra option they requested - does not exist in the project they are wishing to install. - - This is meant to exercise the code that is meant for non-wheel installs. - """ - result = script.pip( - 'install', '--no-use-wheel', - '--no-index', '--find-links=' + data.find_links, - 'simple[nonexistant]', expect_stderr=True, - ) - assert ( - "simple 3.0 has no such extra feature 'nonexistant'" - in result.stdout + 'requires_simple_extra[simple, plop]', expect_stderr=True, ) + print result.stdout + assert 0 From fec9f4fde92adc8b93fe8ef0f144cdc323c4119b Mon Sep 17 00:00:00 2001 From: derwolfe Date: Tue, 30 Dec 2014 19:41:11 -0600 Subject: [PATCH 04/29] working on adding tests. It looks like the case of multiple extras not exisiting isn't handled --- pip/req/req_set.py | 4 +- .../functional/test_install_missing_extras.py | 113 ++++++++++-------- 2 files changed, 69 insertions(+), 48 deletions(-) diff --git a/pip/req/req_set.py b/pip/req/req_set.py index daef42870ae..7e7b2e16684 100644 --- a/pip/req/req_set.py +++ b/pip/req/req_set.py @@ -443,7 +443,9 @@ def prepare_files(self, finder): # req_to_install.extras are the extras # the user *would like* to install. # how to get the available options - print req_to_install.extras + # _dep_map has both extras and something else + # but it is: [Requirement.parse('simple==1.0')] + print dist._dep_map # maybe? for subreq in dist.requires( req_to_install.extras): if self.has_requirement( diff --git a/tests/functional/test_install_missing_extras.py b/tests/functional/test_install_missing_extras.py index 8ad5d633a07..7406abab352 100644 --- a/tests/functional/test_install_missing_extras.py +++ b/tests/functional/test_install_missing_extras.py @@ -2,57 +2,76 @@ temporarily locate test here to make it fail faster """ -# def test_non_existant_extra_warns_user_with_wheel(script, data): -# """ -# A warning is logged telling the user that the extra option they requested -# does not exist in the project they are wishing to install -# """ -# result = script.pip( -# 'install', '--use-wheel', '--no-index', -# '--find-links=' + data.find_links, -# 'simplewheel[nonexistant]', expect_stderr=True, -# ) -# assert ( -# "simplewheel 2.0 has no such extra feature 'nonexistant'" -# in result.stdout -# ) +def test_non_existant_extra_warns_user_with_wheel(script, data): + """ + A warning is logged telling the user that the extra option they requested + does not exist in the project they are wishing to install + """ + result = script.pip( + 'install', '--use-wheel', '--no-index', + '--find-links=' + data.find_links, + 'simplewheel[nonexistant]', expect_stderr=True, + ) + assert ( + "simplewheel 2.0 has no such extra feature 'nonexistant'" + in result.stdout + ) -# def test_non_existant_extra_warns_user_no_wheel(script, data): -# """ -# A warning is logged telling the user that the extra option they requested -# does not exist in the project they are wishing to install. +def test_non_existant_extra_warns_user_no_wheel(script, data): + """ + A warning is logged telling the user that the extra option they requested + does not exist in the project they are wishing to install. -# This is meant to exercise the code that is meant for non-wheel installs. -# """ -# result = script.pip( -# 'install', '--no-use-wheel', '--no-index', -# '--find-links=' + data.find_links, -# 'simple[nonexistant]', expect_stderr=True, -# ) -# assert ( -# "simple 3.0 has no such extra feature 'nonexistant'" -# in result.stdout -# ) + This is meant to exercise the code that is meant for non-wheel installs. + """ + result = script.pip( + 'install', '--no-use-wheel', '--no-index', + '--find-links=' + data.find_links, + 'simple[nonexistant]', expect_stderr=True, + ) + assert ( + "simple 3.0 has no such extra feature 'nonexistant'" + in result.stdout + ) -# def test_non_existant_extras_warn_user_no_wheel(script, data): -# """ -# Warn the user for each extra that doesn't exist. -# """ -# result = script.pip( -# 'install', '--use-wheel', '--no-index', -# '--find-links=' + data.find_links, -# 'simplewheel[nonexistant]', expect_stderr=True, -# ) -# assert ( -# "simple 3.0 has no such extra feature 'nonexistant'" -# in result.stdout -# ) -# assert ( -# "simple 3.0 has no such extra feature 'nope'" -# in result.stdout -# ) +def test_non_existant_extras_warn_user_with_wheel(script, data): + """ + Warn the user for each extra that doesn't exist. + """ + result = script.pip( + 'install', '--use-wheel', '--no-index', + '--find-links=' + data.find_links, + 'simplewheel[nonexistant]', expect_stderr=True, + ) + assert ( + "simplewheel 2.0 has no such extra feature 'nonexistant'" + in result.stdout + ) + assert ( + "simplewheel 2.0 has no such extra feature 'nope'" + in result.stdout + ) + +def test_non_existant_extras_warn_user_with_wheel(script, data): + """ + Warn the user for each extra that doesn't exist. + """ + result = script.pip( + 'install', '--no-use-wheel', '--no-index', + '--find-links=' + data.find_links, + 'simple[nonexistant, nope]', expect_stderr=True, + ) + assert ( + "simple 3.0 has no such extra feature 'nonexistant'" + in result.stdout + ) + assert ( + "simple 3.0 has no such extra feature 'nope'" + in result.stdout + ) -def test_shows_existing_extrasl(script, data): +# this is just meant to be used for development +def test_shows_existing_available_extras(script, data): """ Warn the user for each extra that doesn't exist. """ From 53f3346aac3278ad5b7f8557941b8a8aa90c99a6 Mon Sep 17 00:00:00 2001 From: derwolfe Date: Tue, 30 Dec 2014 19:42:43 -0600 Subject: [PATCH 05/29] phrasing --- pip/req/req_set.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pip/req/req_set.py b/pip/req/req_set.py index 7e7b2e16684..6b0721ba0a9 100644 --- a/pip/req/req_set.py +++ b/pip/req/req_set.py @@ -437,7 +437,7 @@ def prepare_files(self, finder): # instead, the current code throws an exception when # checking for the option. # further, this will fail on the very first check - # e.g. if a single non-existant one is found, then + # i.e. if a single non-existant one is found, then # it stops trying to install extras. try: # req_to_install.extras are the extras From b07918497bdcf40c31a5d70a3846b29cab51dad3 Mon Sep 17 00:00:00 2001 From: derwolfe Date: Mon, 23 Feb 2015 18:25:35 -0600 Subject: [PATCH 06/29] trying to tease out dist and requires information --- pip/req/req_set.py | 11 +- .../functional/test_install_missing_extras.py | 104 +++++++++--------- 2 files changed, 59 insertions(+), 56 deletions(-) diff --git a/pip/req/req_set.py b/pip/req/req_set.py index 3bdb603ae4a..5eecb0f75f3 100644 --- a/pip/req/req_set.py +++ b/pip/req/req_set.py @@ -432,20 +432,19 @@ def prepare_files(self, finder): ) if not self.ignore_dependencies: - # it seems like this should already know what the - # extra options are, then check for option in the list. - # instead, the current code throws an exception when - # checking for the option. - # further, this will fail on the very first check # i.e. if a single non-existant one is found, then # it stops trying to install extras. + # the requires.txt file contains all of the options try: # req_to_install.extras are the extras # the user *would like* to install. # how to get the available options # _dep_map has both extras and something else # but it is: [Requirement.parse('simple==1.0')] - print dist._dep_map # maybe? + extras = dist._dep_map + print("dist - {0}".format(dist)) + print("extr - {0}".format(extras)) + for subreq in dist.requires( req_to_install.extras): if self.has_requirement( diff --git a/tests/functional/test_install_missing_extras.py b/tests/functional/test_install_missing_extras.py index 7406abab352..49c2678ee56 100644 --- a/tests/functional/test_install_missing_extras.py +++ b/tests/functional/test_install_missing_extras.py @@ -2,20 +2,20 @@ temporarily locate test here to make it fail faster """ -def test_non_existant_extra_warns_user_with_wheel(script, data): - """ - A warning is logged telling the user that the extra option they requested - does not exist in the project they are wishing to install - """ - result = script.pip( - 'install', '--use-wheel', '--no-index', - '--find-links=' + data.find_links, - 'simplewheel[nonexistant]', expect_stderr=True, - ) - assert ( - "simplewheel 2.0 has no such extra feature 'nonexistant'" - in result.stdout - ) +# def test_non_existant_extra_warns_user_with_wheel(script, data): +# """ +# A warning is logged telling the user that the extra option they requested +# does not exist in the project they are wishing to install +# """ +# result = script.pip( +# 'install', '--use-wheel', '--no-index', +# '--find-links=' + data.find_links, +# 'simplewheel[nonexistant]', expect_stderr=True, +# ) +# assert ( +# "simplewheel 2.0 has no such extra feature 'nonexistant'" +# in result.stdout +# ) def test_non_existant_extra_warns_user_no_wheel(script, data): """ @@ -29,46 +29,47 @@ def test_non_existant_extra_warns_user_no_wheel(script, data): '--find-links=' + data.find_links, 'simple[nonexistant]', expect_stderr=True, ) + print (result.stdout) assert ( "simple 3.0 has no such extra feature 'nonexistant'" in result.stdout ) -def test_non_existant_extras_warn_user_with_wheel(script, data): - """ - Warn the user for each extra that doesn't exist. - """ - result = script.pip( - 'install', '--use-wheel', '--no-index', - '--find-links=' + data.find_links, - 'simplewheel[nonexistant]', expect_stderr=True, - ) - assert ( - "simplewheel 2.0 has no such extra feature 'nonexistant'" - in result.stdout - ) - assert ( - "simplewheel 2.0 has no such extra feature 'nope'" - in result.stdout - ) +# def test_non_existant_extras_warn_user_with_wheel(script, data): +# """ +# Warn the user for each extra that doesn't exist. +# """ +# result = script.pip( +# 'install', '--use-wheel', '--no-index', +# '--find-links=' + data.find_links, +# 'simplewheel[nonexistant]', expect_stderr=True, +# ) +# assert ( +# "simplewheel 2.0 has no such extra feature 'nonexistant'" +# in result.stdout +# ) +# assert ( +# "simplewheel 2.0 has no such extra feature 'nope'" +# in result.stdout +# ) -def test_non_existant_extras_warn_user_with_wheel(script, data): - """ - Warn the user for each extra that doesn't exist. - """ - result = script.pip( - 'install', '--no-use-wheel', '--no-index', - '--find-links=' + data.find_links, - 'simple[nonexistant, nope]', expect_stderr=True, - ) - assert ( - "simple 3.0 has no such extra feature 'nonexistant'" - in result.stdout - ) - assert ( - "simple 3.0 has no such extra feature 'nope'" - in result.stdout - ) +# def test_non_existant_extras_warn_user_with_wheel(script, data): +# """ +# Warn the user for each extra that doesn't exist. +# """ +# result = script.pip( +# 'install', '--no-use-wheel', '--no-index', +# '--find-links=' + data.find_links, +# 'simple[nonexistant, nope]', expect_stderr=True, +# ) +# assert ( +# "simple 3.0 has no such extra feature 'nonexistant'" +# in result.stdout +# ) +# assert ( +# "simple 3.0 has no such extra feature 'nope'" +# in result.stdout +# ) # this is just meant to be used for development def test_shows_existing_available_extras(script, data): @@ -80,5 +81,8 @@ def test_shows_existing_available_extras(script, data): '--find-links=' + data.find_links, 'requires_simple_extra[simple, plop]', expect_stderr=True, ) - print result.stdout - assert 0 + print (result.stdout) + assert ( + "requires_simple_extra has no such extra feature 'plop'" + in result.stdout + ) From 82668636a296a8b4866c76924f92db3c0ca54b26 Mon Sep 17 00:00:00 2001 From: derwolfe Date: Mon, 23 Feb 2015 22:05:16 -0600 Subject: [PATCH 07/29] find missing packages first --- pip/req/req_set.py | 71 ++++++++++++------- .../functional/test_install_missing_extras.py | 2 +- 2 files changed, 47 insertions(+), 26 deletions(-) diff --git a/pip/req/req_set.py b/pip/req/req_set.py index 5eecb0f75f3..4dfe4dc7109 100644 --- a/pip/req/req_set.py +++ b/pip/req/req_set.py @@ -432,36 +432,27 @@ def prepare_files(self, finder): ) if not self.ignore_dependencies: - # i.e. if a single non-existant one is found, then - # it stops trying to install extras. - # the requires.txt file contains all of the options - try: - # req_to_install.extras are the extras - # the user *would like* to install. - # how to get the available options - # _dep_map has both extras and something else - # but it is: [Requirement.parse('simple==1.0')] - extras = dist._dep_map - print("dist - {0}".format(dist)) - print("extr - {0}".format(extras)) - - for subreq in dist.requires( - req_to_install.extras): - if self.has_requirement( - subreq.project_name): - # FIXME: check for conflict - continue + # XXX EXTRASWORK this is used for debugging only. + print("req - {0}".format(req_to_install.extras)) + logger.error(unavailable) + for missing in missing_extras(dist.extras, + req_to_install.extras): + logger.error("%s does not provide the extra named %s", + dist, missing) + extras_to_install = _available_extras(dist.extras, + req_to_install.extras) + for subreq in dist.requires(extras_to_install): + if self.has_requirement( + subreq.project_name): + # FIXME: check for conflict + continue subreq = InstallRequirement( str(subreq), req_to_install, isolated=self.isolated, ) - reqs.append(subreq) - self.add_requirement(subreq) - except pkg_resources.UnknownExtra as ex: - # looks like the project_name isn't set. - # shouldn't it be? - logger.error(ex) + reqs.append(subreq) + self.add_requirement(subreq) if not self.has_requirement(req_to_install.name): # 'unnamed' requirements will get added here @@ -578,3 +569,33 @@ def install(self, install_options, global_options=(), *args, **kwargs): requirement.remove_temporary_source() self.successfully_installed = to_install + + +def _available_options(provided, requested): + """ + Given a list of installable extras, and a list of extras that the user + has requested to install, return the list of options that the user has + requested that *can* be installed. + + :param provided: a tuple representing the dependencies that are classified + as optional dependencies + :param requested: a list containing the requirments that the user would + like to install. + :returns: a tuple of extras that can be installed + """ + return [r for r in requested if r in provided] + + +def _missing_options(provided, requested): + """ + Given a list of installable extras, and a list of extras that the user + has requested to install, return the list of options that the user has + requested that *cannot* be installed. + + :param provided: a tuple representing the dependencies that are classified + as optional dependencies + :param requested: a list containing the requirments that the user would + like to install. + :returns: a tuple of extras that can be installed + """ + return [r for r in requested if r not in provided] diff --git a/tests/functional/test_install_missing_extras.py b/tests/functional/test_install_missing_extras.py index 49c2678ee56..9ebb82bdf2b 100644 --- a/tests/functional/test_install_missing_extras.py +++ b/tests/functional/test_install_missing_extras.py @@ -79,7 +79,7 @@ def test_shows_existing_available_extras(script, data): result = script.pip( 'install', '--use-wheel', '--no-index', '--find-links=' + data.find_links, - 'requires_simple_extra[simple, plop]', expect_stderr=True, + 'requires_simple_extra[extra,plop]', expect_stderr=True, ) print (result.stdout) assert ( From db50fe6be640d9d3968e87e751d9f279ccf85e06 Mon Sep 17 00:00:00 2001 From: derwolfe Date: Mon, 23 Feb 2015 22:12:10 -0600 Subject: [PATCH 08/29] naming and return type --- pip/req/req_set.py | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/pip/req/req_set.py b/pip/req/req_set.py index 4dfe4dc7109..4220f1f088d 100644 --- a/pip/req/req_set.py +++ b/pip/req/req_set.py @@ -432,13 +432,11 @@ def prepare_files(self, finder): ) if not self.ignore_dependencies: - # XXX EXTRASWORK this is used for debugging only. - print("req - {0}".format(req_to_install.extras)) - logger.error(unavailable) - for missing in missing_extras(dist.extras, + #print("req - {0}".format(req_to_install.extras)) + for missing in _missing_extras(dist.extras, req_to_install.extras): - logger.error("%s does not provide the extra named %s", - dist, missing) + print("{0} does not provide the extra named {1}".format( + dist, missing)) extras_to_install = _available_extras(dist.extras, req_to_install.extras) for subreq in dist.requires(extras_to_install): @@ -571,7 +569,7 @@ def install(self, install_options, global_options=(), *args, **kwargs): self.successfully_installed = to_install -def _available_options(provided, requested): +def _available_extras(provided, requested): """ Given a list of installable extras, and a list of extras that the user has requested to install, return the list of options that the user has @@ -586,7 +584,7 @@ def _available_options(provided, requested): return [r for r in requested if r in provided] -def _missing_options(provided, requested): +def _missing_extras(provided, requested): """ Given a list of installable extras, and a list of extras that the user has requested to install, return the list of options that the user has @@ -598,4 +596,4 @@ def _missing_options(provided, requested): like to install. :returns: a tuple of extras that can be installed """ - return [r for r in requested if r not in provided] + return (r for r in requested if r not in provided) From 6c5edf59a1b634e2cf164699d93875af91ceb093 Mon Sep 17 00:00:00 2001 From: derwolfe Date: Mon, 23 Feb 2015 22:14:33 -0600 Subject: [PATCH 09/29] fix indentation --- pip/req/req_set.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pip/req/req_set.py b/pip/req/req_set.py index 4220f1f088d..6644272a24f 100644 --- a/pip/req/req_set.py +++ b/pip/req/req_set.py @@ -444,11 +444,11 @@ def prepare_files(self, finder): subreq.project_name): # FIXME: check for conflict continue - subreq = InstallRequirement( - str(subreq), - req_to_install, - isolated=self.isolated, - ) + subreq = InstallRequirement( + str(subreq), + req_to_install, + isolated=self.isolated, + ) reqs.append(subreq) self.add_requirement(subreq) From c5d331bba1de575a97a8ea0df1e8a7848809b010 Mon Sep 17 00:00:00 2001 From: derwolfe Date: Tue, 24 Feb 2015 07:14:19 -0600 Subject: [PATCH 10/29] warning showing correctly --- pip/req/req_set.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pip/req/req_set.py b/pip/req/req_set.py index 6644272a24f..2ecb9573fc2 100644 --- a/pip/req/req_set.py +++ b/pip/req/req_set.py @@ -432,11 +432,11 @@ def prepare_files(self, finder): ) if not self.ignore_dependencies: - #print("req - {0}".format(req_to_install.extras)) for missing in _missing_extras(dist.extras, req_to_install.extras): - print("{0} does not provide the extra named {1}".format( - dist, missing)) + logger.warning( + '%s does not provide the extra \'%s\'', + dist, missing) extras_to_install = _available_extras(dist.extras, req_to_install.extras) for subreq in dist.requires(extras_to_install): From 5fcf2d62445a02ffe31da0fbbc370d5000ccf466 Mon Sep 17 00:00:00 2001 From: derwolfe Date: Tue, 24 Feb 2015 07:15:06 -0600 Subject: [PATCH 11/29] fix tests; still need to get the version number --- .../functional/test_install_missing_extras.py | 67 +++++++++---------- 1 file changed, 33 insertions(+), 34 deletions(-) diff --git a/tests/functional/test_install_missing_extras.py b/tests/functional/test_install_missing_extras.py index 9ebb82bdf2b..1e0cca39757 100644 --- a/tests/functional/test_install_missing_extras.py +++ b/tests/functional/test_install_missing_extras.py @@ -13,43 +13,25 @@ # 'simplewheel[nonexistant]', expect_stderr=True, # ) # assert ( -# "simplewheel 2.0 has no such extra feature 'nonexistant'" +# "simplewheel 2.0 does not provide the extra 'nonexistant'" # in result.stdout # ) -def test_non_existant_extra_warns_user_no_wheel(script, data): - """ - A warning is logged telling the user that the extra option they requested - does not exist in the project they are wishing to install. - - This is meant to exercise the code that is meant for non-wheel installs. - """ - result = script.pip( - 'install', '--no-use-wheel', '--no-index', - '--find-links=' + data.find_links, - 'simple[nonexistant]', expect_stderr=True, - ) - print (result.stdout) - assert ( - "simple 3.0 has no such extra feature 'nonexistant'" - in result.stdout - ) - -# def test_non_existant_extras_warn_user_with_wheel(script, data): +# def test_non_existant_extra_warns_user_no_wheel(script, data): # """ -# Warn the user for each extra that doesn't exist. +# A warning is logged telling the user that the extra option they requested +# does not exist in the project they are wishing to install. + +# This is meant to exercise the code that is meant for non-wheel installs. # """ # result = script.pip( -# 'install', '--use-wheel', '--no-index', +# 'install', '--no-use-wheel', '--no-index', # '--find-links=' + data.find_links, -# 'simplewheel[nonexistant]', expect_stderr=True, +# 'simple[nonexistant]', expect_stderr=True, # ) +# print (result.stdout) # assert ( -# "simplewheel 2.0 has no such extra feature 'nonexistant'" -# in result.stdout -# ) -# assert ( -# "simplewheel 2.0 has no such extra feature 'nope'" +# "simple 3.0 does not provide the extra 'nonexistant'" # in result.stdout # ) @@ -58,20 +40,37 @@ def test_non_existant_extra_warns_user_no_wheel(script, data): # Warn the user for each extra that doesn't exist. # """ # result = script.pip( -# 'install', '--no-use-wheel', '--no-index', +# 'install', '--use-wheel', '--no-index', # '--find-links=' + data.find_links, -# 'simple[nonexistant, nope]', expect_stderr=True, +# 'simplewheel[nonexistant]', expect_stderr=True, # ) # assert ( -# "simple 3.0 has no such extra feature 'nonexistant'" +# "simplewheel 2.0 does not provide the extra 'nonexistant'" # in result.stdout # ) # assert ( -# "simple 3.0 has no such extra feature 'nope'" +# "simplewheel 2.0 does not provide the extra 'nope'" # in result.stdout # ) -# this is just meant to be used for development +def test_non_existant_extras_warn_user_with_wheel(script, data): + """ + Warn the user for each extra that doesn't exist. + """ + result = script.pip( + 'install', '--no-use-wheel', '--no-index', + '--find-links=' + data.find_links, + 'simple[nonexistant, nope]', expect_stderr=True, + ) + assert ( + "simple 3.0 does not provide the extra 'nonexistant'" + in result.stdout + ) + assert ( + "simple 3.0 does not provide the extra 'nope'" + in result.stdout + ) + def test_shows_existing_available_extras(script, data): """ Warn the user for each extra that doesn't exist. @@ -83,6 +82,6 @@ def test_shows_existing_available_extras(script, data): ) print (result.stdout) assert ( - "requires_simple_extra has no such extra feature 'plop'" + "requires_simple_extra does not provide the extra 'plop'" in result.stdout ) From 5d3d8ab93344e76310c9241971c67c06973c42a7 Mon Sep 17 00:00:00 2001 From: derwolfe Date: Tue, 24 Feb 2015 07:42:04 -0600 Subject: [PATCH 12/29] tests working, need coverage on two new fucntions --- .../functional/test_install_missing_extras.py | 102 +++++++----------- 1 file changed, 41 insertions(+), 61 deletions(-) diff --git a/tests/functional/test_install_missing_extras.py b/tests/functional/test_install_missing_extras.py index 1e0cca39757..a0929908198 100644 --- a/tests/functional/test_install_missing_extras.py +++ b/tests/functional/test_install_missing_extras.py @@ -2,86 +2,66 @@ temporarily locate test here to make it fail faster """ -# def test_non_existant_extra_warns_user_with_wheel(script, data): -# """ -# A warning is logged telling the user that the extra option they requested -# does not exist in the project they are wishing to install -# """ -# result = script.pip( -# 'install', '--use-wheel', '--no-index', -# '--find-links=' + data.find_links, -# 'simplewheel[nonexistant]', expect_stderr=True, -# ) -# assert ( -# "simplewheel 2.0 does not provide the extra 'nonexistant'" -# in result.stdout -# ) - -# def test_non_existant_extra_warns_user_no_wheel(script, data): -# """ -# A warning is logged telling the user that the extra option they requested -# does not exist in the project they are wishing to install. - -# This is meant to exercise the code that is meant for non-wheel installs. -# """ -# result = script.pip( -# 'install', '--no-use-wheel', '--no-index', -# '--find-links=' + data.find_links, -# 'simple[nonexistant]', expect_stderr=True, -# ) -# print (result.stdout) -# assert ( -# "simple 3.0 does not provide the extra 'nonexistant'" -# in result.stdout -# ) - -# def test_non_existant_extras_warn_user_with_wheel(script, data): -# """ -# Warn the user for each extra that doesn't exist. -# """ -# result = script.pip( -# 'install', '--use-wheel', '--no-index', -# '--find-links=' + data.find_links, -# 'simplewheel[nonexistant]', expect_stderr=True, -# ) -# assert ( -# "simplewheel 2.0 does not provide the extra 'nonexistant'" -# in result.stdout -# ) -# assert ( -# "simplewheel 2.0 does not provide the extra 'nope'" -# in result.stdout -# ) - -def test_non_existant_extras_warn_user_with_wheel(script, data): +def test_non_existant_extra_warns_user_with_wheel(script, data): """ - Warn the user for each extra that doesn't exist. + A warning is logged telling the user that the extra option they requested + does not exist in the project they are wishing to install """ result = script.pip( - 'install', '--no-use-wheel', '--no-index', + 'install', '--use-wheel', '--no-index', '--find-links=' + data.find_links, - 'simple[nonexistant, nope]', expect_stderr=True, + 'simplewheel[nonexistant]', expect_stderr=True, ) assert ( - "simple 3.0 does not provide the extra 'nonexistant'" + "simplewheel 2.0 does not provide the extra 'nonexistant'" in result.stdout ) + +def test_non_existant_extra_warns_user_no_wheel(script, data): + """ + A warning is logged telling the user that the extra option they requested + does not exist in the project they are wishing to install. + + This is meant to exercise the code that is meant for non-wheel installs. + """ + result = script.pip( + 'install', '--no-use-wheel', '--no-index', + '--find-links=' + data.find_links, + 'simple[nonexistant]', expect_stderr=True, + ) assert ( - "simple 3.0 does not provide the extra 'nope'" + "Unknown 3.0 does not provide the extra 'nonexistant'" in result.stdout ) -def test_shows_existing_available_extras(script, data): +def test_non_existant_options_logged_as_single_list_per_dependency(script, data): """ Warn the user for each extra that doesn't exist. """ result = script.pip( 'install', '--use-wheel', '--no-index', '--find-links=' + data.find_links, - 'requires_simple_extra[extra,plop]', expect_stderr=True, + 'simplewheel[nonexistant, nope]', expect_stderr=True, ) - print (result.stdout) assert ( - "requires_simple_extra does not provide the extra 'plop'" + "simplewheel 2.0 does not provide the extra 'nonexistant'" in result.stdout ) + assert ( + "simplewheel 2.0 does not provide the extra 'nope'" + in result.stdout + ) + +# def test_shows_existing_available_extras(script, data): +# """ +# Warn the user for each extra that doesn't exist. +# """ +# result = script.pip( +# 'install', '--no-use-wheel', '--no-index', +# '--find-links=' + data.find_links, +# 'requires_simple_extra[extra,plop]', expect_stderr=True, +# ) +# assert ( +# "requires-simple-extra 0.1 does not provide the extra 'plop'" +# in result.stdout +# ) From 2e30c4732d45e960d05caedaa7063d9387574e9f Mon Sep 17 00:00:00 2001 From: derwolfe Date: Tue, 24 Feb 2015 20:30:11 -0600 Subject: [PATCH 13/29] Cleanup the functional tests, return a tuple instead of list. --- pip/req/req_set.py | 6 +-- .../functional/test_install_missing_extras.py | 38 ++++++------------- 2 files changed, 15 insertions(+), 29 deletions(-) diff --git a/pip/req/req_set.py b/pip/req/req_set.py index 2ecb9573fc2..bbd62b24555 100644 --- a/pip/req/req_set.py +++ b/pip/req/req_set.py @@ -433,7 +433,7 @@ def prepare_files(self, finder): if not self.ignore_dependencies: for missing in _missing_extras(dist.extras, - req_to_install.extras): + req_to_install.extras): logger.warning( '%s does not provide the extra \'%s\'', dist, missing) @@ -581,7 +581,7 @@ def _available_extras(provided, requested): like to install. :returns: a tuple of extras that can be installed """ - return [r for r in requested if r in provided] + return (r for r in requested if r in provided) def _missing_extras(provided, requested): @@ -594,6 +594,6 @@ def _missing_extras(provided, requested): as optional dependencies :param requested: a list containing the requirments that the user would like to install. - :returns: a tuple of extras that can be installed + :returns: a tuple of extras that cannot be installed """ return (r for r in requested if r not in provided) diff --git a/tests/functional/test_install_missing_extras.py b/tests/functional/test_install_missing_extras.py index a0929908198..a28c734f1b9 100644 --- a/tests/functional/test_install_missing_extras.py +++ b/tests/functional/test_install_missing_extras.py @@ -2,35 +2,35 @@ temporarily locate test here to make it fail faster """ -def test_non_existant_extra_warns_user_with_wheel(script, data): +def test_non_existant_extra_warns_user_no_wheel(script, data): """ A warning is logged telling the user that the extra option they requested - does not exist in the project they are wishing to install + does not exist in the project they are wishing to install. + + This is meant to exercise the code that is meant for non-wheel installs. """ result = script.pip( - 'install', '--use-wheel', '--no-index', + 'install', '--no-use-wheel', '--no-index', '--find-links=' + data.find_links, - 'simplewheel[nonexistant]', expect_stderr=True, + 'simple[nonexistant]', expect_stderr=True, ) assert ( - "simplewheel 2.0 does not provide the extra 'nonexistant'" + "Unknown 3.0 does not provide the extra 'nonexistant'" in result.stdout ) -def test_non_existant_extra_warns_user_no_wheel(script, data): +def test_non_existant_extra_warns_user_with_wheel(script, data): """ A warning is logged telling the user that the extra option they requested - does not exist in the project they are wishing to install. - - This is meant to exercise the code that is meant for non-wheel installs. + does not exist in the project they are wishing to install """ result = script.pip( - 'install', '--no-use-wheel', '--no-index', + 'install', '--use-wheel', '--no-index', '--find-links=' + data.find_links, - 'simple[nonexistant]', expect_stderr=True, + 'simplewheel[nonexistant]', expect_stderr=True, ) assert ( - "Unknown 3.0 does not provide the extra 'nonexistant'" + "simplewheel 2.0 does not provide the extra 'nonexistant'" in result.stdout ) @@ -51,17 +51,3 @@ def test_non_existant_options_logged_as_single_list_per_dependency(script, data) "simplewheel 2.0 does not provide the extra 'nope'" in result.stdout ) - -# def test_shows_existing_available_extras(script, data): -# """ -# Warn the user for each extra that doesn't exist. -# """ -# result = script.pip( -# 'install', '--no-use-wheel', '--no-index', -# '--find-links=' + data.find_links, -# 'requires_simple_extra[extra,plop]', expect_stderr=True, -# ) -# assert ( -# "requires-simple-extra 0.1 does not provide the extra 'plop'" -# in result.stdout -# ) From cb1962ef546565703e7c576f63981d65ac8c7dfd Mon Sep 17 00:00:00 2001 From: derwolfe Date: Tue, 24 Feb 2015 20:34:42 -0600 Subject: [PATCH 14/29] shorten line --- pip/req/req_set.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pip/req/req_set.py b/pip/req/req_set.py index bbd62b24555..2afa6d3b141 100644 --- a/pip/req/req_set.py +++ b/pip/req/req_set.py @@ -437,9 +437,9 @@ def prepare_files(self, finder): logger.warning( '%s does not provide the extra \'%s\'', dist, missing) - extras_to_install = _available_extras(dist.extras, - req_to_install.extras) - for subreq in dist.requires(extras_to_install): + extras_install = _available_extras(dist.extras, + req_to_install.extras) + for subreq in dist.requires(extras_install): if self.has_requirement( subreq.project_name): # FIXME: check for conflict From 8a094361e7a1ce80ed13de56ae4f119f1df0e563 Mon Sep 17 00:00:00 2001 From: derwolfe Date: Tue, 24 Feb 2015 22:08:38 -0600 Subject: [PATCH 15/29] fix formatting in tests, comments --- .../functional/test_install_missing_extras.py | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/tests/functional/test_install_missing_extras.py b/tests/functional/test_install_missing_extras.py index a28c734f1b9..1f75f813271 100644 --- a/tests/functional/test_install_missing_extras.py +++ b/tests/functional/test_install_missing_extras.py @@ -2,12 +2,13 @@ temporarily locate test here to make it fail faster """ + def test_non_existant_extra_warns_user_no_wheel(script, data): """ A warning is logged telling the user that the extra option they requested does not exist in the project they are wishing to install. - This is meant to exercise the code that is meant for non-wheel installs. + This exercises source installs. """ result = script.pip( 'install', '--no-use-wheel', '--no-index', @@ -19,10 +20,13 @@ def test_non_existant_extra_warns_user_no_wheel(script, data): in result.stdout ) + def test_non_existant_extra_warns_user_with_wheel(script, data): """ A warning is logged telling the user that the extra option they requested - does not exist in the project they are wishing to install + does not exist in the project they are wishing to install. + + This exercises wheel installs. """ result = script.pip( 'install', '--use-wheel', '--no-index', @@ -34,7 +38,8 @@ def test_non_existant_extra_warns_user_with_wheel(script, data): in result.stdout ) -def test_non_existant_options_logged_as_single_list_per_dependency(script, data): + +def test_non_existant_options_listed_in_order(script, data): """ Warn the user for each extra that doesn't exist. """ @@ -43,11 +48,8 @@ def test_non_existant_options_logged_as_single_list_per_dependency(script, data) '--find-links=' + data.find_links, 'simplewheel[nonexistant, nope]', expect_stderr=True, ) - assert ( - "simplewheel 2.0 does not provide the extra 'nonexistant'" - in result.stdout - ) - assert ( - "simplewheel 2.0 does not provide the extra 'nope'" - in result.stdout + msg = ( + " simplewheel 2.0 does not provide the extra 'nonexistant'\n" + " simplewheel 2.0 does not provide the extra 'nope'" ) + assert msg in result.stdout From d3e207ede485d3991a115626e7ba01e756b9da07 Mon Sep 17 00:00:00 2001 From: derwolfe Date: Wed, 25 Feb 2015 07:48:12 -0600 Subject: [PATCH 16/29] add unit tests for missing and available functions --- pip/req/req_set.py | 16 ++++++---------- tests/unit/test_req.py | 41 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 46 insertions(+), 11 deletions(-) diff --git a/pip/req/req_set.py b/pip/req/req_set.py index 2afa6d3b141..a91021c9bb2 100644 --- a/pip/req/req_set.py +++ b/pip/req/req_set.py @@ -571,14 +571,12 @@ def install(self, install_options, global_options=(), *args, **kwargs): def _available_extras(provided, requested): """ - Given a list of installable extras, and a list of extras that the user + Given a tuple of installable extras, and a list of extras that the user has requested to install, return the list of options that the user has requested that *can* be installed. - :param provided: a tuple representing the dependencies that are classified - as optional dependencies - :param requested: a list containing the requirments that the user would - like to install. + :param provided: a tuple of optional extras provided by a distribution + :param requested: a list of optional extras the user wants to install :returns: a tuple of extras that can be installed """ return (r for r in requested if r in provided) @@ -586,14 +584,12 @@ def _available_extras(provided, requested): def _missing_extras(provided, requested): """ - Given a list of installable extras, and a list of extras that the user + Given a tuple of installable extras, and a list of extras that the user has requested to install, return the list of options that the user has requested that *cannot* be installed. - :param provided: a tuple representing the dependencies that are classified - as optional dependencies - :param requested: a list containing the requirments that the user would - like to install. + :param provided: a tuple of optional extras provided by a distribution + :param requested: a list of optional extras the user wants to install :returns: a tuple of extras that cannot be installed """ return (r for r in requested if r not in provided) diff --git a/tests/unit/test_req.py b/tests/unit/test_req.py index 249eaceff96..f9a9ec3512d 100644 --- a/tests/unit/test_req.py +++ b/tests/unit/test_req.py @@ -12,7 +12,8 @@ from pip.download import PipSession from pip.index import PackageFinder from pip.req import (InstallRequirement, RequirementSet, - Requirements, parse_requirements) + Requirements, parse_requirements, + _missing_extras, _available_extras) from pip.req.req_install import parse_editable from pip.utils import read_text_file from pip._vendor import pkg_resources @@ -357,3 +358,41 @@ def test_req_file_no_finder(tmpdir): """) parse_requirements(tmpdir.join("req.txt"), session=PipSession()) + +def test_req_missing_extras_returns_empty_tuple_when_no_missing(): + """ + When all of the requested extras are available, + `req._missing_extras` returns an empty tuple. + """ + provided = ('tls') + requested = list(provided) + assert _missing_extras(provided, requested) == () + + +def test_req_missing_extras_returns_missing_extras(): + """ + When all of the requested extras are available, + `req._missing_extras` returns a tuple containing each missing extra. + """ + provided = () + missing = ['tls', 'nope', 'nada'] + assert _missing_extras(provided, missing) == missing + + +def test_req_available_extras_returns_empty_tuple_with_no_options(): + """ + When none of the requested options are provided, + `req.available_extras` returns an empty tuple. + """ + provided = () + requested = ['tls', 'nope', 'nada'] + assert _available_extras(provided, requested) == provided + +def test_req_available_extras_returns_available_extras(): + """ + `req.available_extras` returns a tuple containing the intersection + of the extras provided and requested. + """ + provided = ('tls', 'nope') + requested = list(provided) + assert _available_extras(provided, requested) == provided From 19cf33eb67e8520f897f446332439de6b3e17684 Mon Sep 17 00:00:00 2001 From: derwolfe Date: Wed, 25 Feb 2015 07:49:32 -0600 Subject: [PATCH 17/29] spacing --- tests/unit/test_req.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/unit/test_req.py b/tests/unit/test_req.py index f9a9ec3512d..088f9265f08 100644 --- a/tests/unit/test_req.py +++ b/tests/unit/test_req.py @@ -359,6 +359,7 @@ def test_req_file_no_finder(tmpdir): parse_requirements(tmpdir.join("req.txt"), session=PipSession()) + def test_req_missing_extras_returns_empty_tuple_when_no_missing(): """ When all of the requested extras are available, From 8d0cd5663727a32fde22c6dab9989e5eff2ee65a Mon Sep 17 00:00:00 2001 From: Chris Wolfe Date: Wed, 25 Feb 2015 08:49:06 -0600 Subject: [PATCH 18/29] make _missing_extras and _available_extras staticmethods --- pip/req/req_set.py | 65 ++++++++++++++++++++++++---------------------- 1 file changed, 34 insertions(+), 31 deletions(-) diff --git a/pip/req/req_set.py b/pip/req/req_set.py index a91021c9bb2..277a9d4b00b 100644 --- a/pip/req/req_set.py +++ b/pip/req/req_set.py @@ -204,6 +204,32 @@ def locate_files(self): (req_to_install, req_to_install.source_dir) ) + @staticmethod + def _available_extras(provided, requested): + """ + Given a tuple of installable extras, and a list of extras that the user + has requested to install, return the list of options that the user has + requested that *can* be installed. + + :param provided: a tuple of optional extras provided by a distribution + :param requested: a list of optional extras the user wants to install + :returns: a tuple of extras that can be installed + """ + return (r for r in requested if r in provided) + + @staticmethod + def _missing_extras(provided, requested): + """ + Given a tuple of installable extras, and a list of extras that the user + has requested to install, return the list of options that the user has + requested that *cannot* be installed. + + :param provided: a tuple of optional extras provided by a distribution + :param requested: a list of optional extras the user wants to install + :returns: a tuple of extras that cannot be installed + """ + return (r for r in requested if r not in provided) + def prepare_files(self, finder): """ Prepare process. Create temp directories, download and/or unpack files. @@ -432,14 +458,17 @@ def prepare_files(self, finder): ) if not self.ignore_dependencies: - for missing in _missing_extras(dist.extras, - req_to_install.extras): + missing_extras = RequirementSet._missing_extras( + dist.extras, + req_to_install.extras) + requested_and_provided = RequirementSet._available_extras( + dist.extras, + req_to_install.extras) + for missing in missing_extras: logger.warning( '%s does not provide the extra \'%s\'', dist, missing) - extras_install = _available_extras(dist.extras, - req_to_install.extras) - for subreq in dist.requires(extras_install): + for subreq in dist.requires(requested_and_provided): if self.has_requirement( subreq.project_name): # FIXME: check for conflict @@ -567,29 +596,3 @@ def install(self, install_options, global_options=(), *args, **kwargs): requirement.remove_temporary_source() self.successfully_installed = to_install - - -def _available_extras(provided, requested): - """ - Given a tuple of installable extras, and a list of extras that the user - has requested to install, return the list of options that the user has - requested that *can* be installed. - - :param provided: a tuple of optional extras provided by a distribution - :param requested: a list of optional extras the user wants to install - :returns: a tuple of extras that can be installed - """ - return (r for r in requested if r in provided) - - -def _missing_extras(provided, requested): - """ - Given a tuple of installable extras, and a list of extras that the user - has requested to install, return the list of options that the user has - requested that *cannot* be installed. - - :param provided: a tuple of optional extras provided by a distribution - :param requested: a list of optional extras the user wants to install - :returns: a tuple of extras that cannot be installed - """ - return (r for r in requested if r not in provided) From 70351bbe4a0c88965caed0419daea68b1c7d8555 Mon Sep 17 00:00:00 2001 From: Chris Wolfe Date: Wed, 25 Feb 2015 10:00:07 -0600 Subject: [PATCH 19/29] Use the new staticmethods --- tests/unit/test_req.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/tests/unit/test_req.py b/tests/unit/test_req.py index 088f9265f08..35d75d9dc5a 100644 --- a/tests/unit/test_req.py +++ b/tests/unit/test_req.py @@ -12,8 +12,7 @@ from pip.download import PipSession from pip.index import PackageFinder from pip.req import (InstallRequirement, RequirementSet, - Requirements, parse_requirements, - _missing_extras, _available_extras) + Requirements, parse_requirements) from pip.req.req_install import parse_editable from pip.utils import read_text_file from pip._vendor import pkg_resources @@ -367,7 +366,7 @@ def test_req_missing_extras_returns_empty_tuple_when_no_missing(): """ provided = ('tls') requested = list(provided) - assert _missing_extras(provided, requested) == () + assert RequirementSet._missing_extras(provided, requested) == () def test_req_missing_extras_returns_missing_extras(): @@ -377,7 +376,7 @@ def test_req_missing_extras_returns_missing_extras(): """ provided = () missing = ['tls', 'nope', 'nada'] - assert _missing_extras(provided, missing) == missing + assert RequirementSet._missing_extras(provided, missing) == missing def test_req_available_extras_returns_empty_tuple_with_no_options(): @@ -396,4 +395,4 @@ def test_req_available_extras_returns_available_extras(): """ provided = ('tls', 'nope') requested = list(provided) - assert _available_extras(provided, requested) == provided + assert RequirementSet._available_extras(provided, requested) == provided From ee9a7cd05d4c2c3fe419a034738c81a04f3440fb Mon Sep 17 00:00:00 2001 From: Chris Wolfe Date: Wed, 25 Feb 2015 10:13:08 -0600 Subject: [PATCH 20/29] Add missing RequirementSet --- tests/unit/test_req.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/test_req.py b/tests/unit/test_req.py index 35d75d9dc5a..4b64bd96532 100644 --- a/tests/unit/test_req.py +++ b/tests/unit/test_req.py @@ -386,7 +386,7 @@ def test_req_available_extras_returns_empty_tuple_with_no_options(): """ provided = () requested = ['tls', 'nope', 'nada'] - assert _available_extras(provided, requested) == provided + assert RequirementSet._available_extras(provided, requested) == provided def test_req_available_extras_returns_available_extras(): """ From 5e62ad90109c5e66e319ee1551f3827811aece1a Mon Sep 17 00:00:00 2001 From: Chris Wolfe Date: Wed, 25 Feb 2015 12:32:06 -0600 Subject: [PATCH 21/29] Move tests in TestRequirementsSet --- tests/unit/test_req.py | 75 ++++++++++++++++++++---------------------- 1 file changed, 36 insertions(+), 39 deletions(-) diff --git a/tests/unit/test_req.py b/tests/unit/test_req.py index 4b64bd96532..f7c62ecc348 100644 --- a/tests/unit/test_req.py +++ b/tests/unit/test_req.py @@ -71,6 +71,42 @@ def test_environment_marker_extras(self, data): else: assert not reqset.has_requirement('simple') + def test_req_missing_extras_returns_empty_tuple_when_no_missing(): + """ + When all of the requested extras are available, + `req._missing_extras` returns an empty tuple. + """ + provided = ('tls',) + requested = list(provided) + assert not RequirementSet._missing_extras(provided, requested) + + def test_req_missing_extras_returns_missing_extras(): + """ + When all of the requested extras are available, + `req._missing_extras` returns a tuple containing each missing extra. + """ + provided = tuple() + missing = ['tls', 'nope', 'nada'] + assert RequirementSet._missing_extras(provided, missing) == missing + + def test_req_available_extras_returns_empty_tuple_with_no_options(): + """ + When none of the requested options are provided, + `req.available_extras` returns an empty tuple. + """ + provided = tuple() + requested = ['tls', 'nope', 'nada'] + assert not RequirementSet._available_extras(provided, requested) + + def test_req_available_extras_returns_available_extras(): + """ + `req.available_extras` returns a tuple containing the intersection + of the extras provided and requested. + """ + provided = ('tls', 'nope',) + requested = list(provided) + assert RequirementSet._available_extras(provided, requested) == provided + @pytest.mark.parametrize(('file_contents', 'expected'), [ (b'\xf6\x80', b'\xc3\xb6\xe2\x82\xac'), # cp1252 @@ -357,42 +393,3 @@ def test_req_file_no_finder(tmpdir): """) parse_requirements(tmpdir.join("req.txt"), session=PipSession()) - - -def test_req_missing_extras_returns_empty_tuple_when_no_missing(): - """ - When all of the requested extras are available, - `req._missing_extras` returns an empty tuple. - """ - provided = ('tls') - requested = list(provided) - assert RequirementSet._missing_extras(provided, requested) == () - - -def test_req_missing_extras_returns_missing_extras(): - """ - When all of the requested extras are available, - `req._missing_extras` returns a tuple containing each missing extra. - """ - provided = () - missing = ['tls', 'nope', 'nada'] - assert RequirementSet._missing_extras(provided, missing) == missing - - -def test_req_available_extras_returns_empty_tuple_with_no_options(): - """ - When none of the requested options are provided, - `req.available_extras` returns an empty tuple. - """ - provided = () - requested = ['tls', 'nope', 'nada'] - assert RequirementSet._available_extras(provided, requested) == provided - -def test_req_available_extras_returns_available_extras(): - """ - `req.available_extras` returns a tuple containing the intersection - of the extras provided and requested. - """ - provided = ('tls', 'nope') - requested = list(provided) - assert RequirementSet._available_extras(provided, requested) == provided From 86e3300f3b68cb7eabffa397880fbab07073d34b Mon Sep 17 00:00:00 2001 From: derwolfe Date: Wed, 25 Feb 2015 17:27:34 -0600 Subject: [PATCH 22/29] switch to using a tuple wrapping a generator --- pip/req/req_set.py | 14 +++++++------- tests/unit/test_req.py | 18 +++++++++++------- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/pip/req/req_set.py b/pip/req/req_set.py index 277a9d4b00b..c44e884fefc 100644 --- a/pip/req/req_set.py +++ b/pip/req/req_set.py @@ -205,17 +205,17 @@ def locate_files(self): ) @staticmethod - def _available_extras(provided, requested): - """ + def _available_extras(provided, requested): + """ Given a tuple of installable extras, and a list of extras that the user has requested to install, return the list of options that the user has requested that *can* be installed. - + :param provided: a tuple of optional extras provided by a distribution :param requested: a list of optional extras the user wants to install :returns: a tuple of extras that can be installed """ - return (r for r in requested if r in provided) + return tuple((r for r in requested if r in provided)) @staticmethod def _missing_extras(provided, requested): @@ -223,13 +223,13 @@ def _missing_extras(provided, requested): Given a tuple of installable extras, and a list of extras that the user has requested to install, return the list of options that the user has requested that *cannot* be installed. - + :param provided: a tuple of optional extras provided by a distribution :param requested: a list of optional extras the user wants to install :returns: a tuple of extras that cannot be installed """ - return (r for r in requested if r not in provided) - + return tuple((r for r in requested if r not in provided)) + def prepare_files(self, finder): """ Prepare process. Create temp directories, download and/or unpack files. diff --git a/tests/unit/test_req.py b/tests/unit/test_req.py index f7c62ecc348..f6cf534361a 100644 --- a/tests/unit/test_req.py +++ b/tests/unit/test_req.py @@ -71,7 +71,7 @@ def test_environment_marker_extras(self, data): else: assert not reqset.has_requirement('simple') - def test_req_missing_extras_returns_empty_tuple_when_no_missing(): + def test_missing_extras_returns_empty_tuple_when_no_missing(self): """ When all of the requested extras are available, `req._missing_extras` returns an empty tuple. @@ -80,16 +80,18 @@ def test_req_missing_extras_returns_empty_tuple_when_no_missing(): requested = list(provided) assert not RequirementSet._missing_extras(provided, requested) - def test_req_missing_extras_returns_missing_extras(): + def test_missing_extras_returns_missing_extras(self): """ When all of the requested extras are available, `req._missing_extras` returns a tuple containing each missing extra. """ provided = tuple() missing = ['tls', 'nope', 'nada'] - assert RequirementSet._missing_extras(provided, missing) == missing + assert ( + tuple(missing) == RequirementSet._missing_extras(provided, missing) + ) - def test_req_available_extras_returns_empty_tuple_with_no_options(): + def test_available_extras_returns_empty_tuple_with_no_options(self): """ When none of the requested options are provided, `req.available_extras` returns an empty tuple. @@ -98,14 +100,16 @@ def test_req_available_extras_returns_empty_tuple_with_no_options(): requested = ['tls', 'nope', 'nada'] assert not RequirementSet._available_extras(provided, requested) - def test_req_available_extras_returns_available_extras(): + def test_available_extras_returns_available_extras(self): """ `req.available_extras` returns a tuple containing the intersection of the extras provided and requested. """ - provided = ('tls', 'nope',) + provided = ('tls', 'nope') requested = list(provided) - assert RequirementSet._available_extras(provided, requested) == provided + assert ( + provided == RequirementSet._available_extras(provided, requested) + ) @pytest.mark.parametrize(('file_contents', 'expected'), [ From 50237f4fc355c35fc963145f45cf9fa4c00d71ef Mon Sep 17 00:00:00 2001 From: derwolfe Date: Wed, 25 Feb 2015 18:24:04 -0600 Subject: [PATCH 23/29] move missing extras functional tests back into test_install_extras --- tests/functional/test_install_extras.py | 52 ++++++++++++++++++ .../functional/test_install_missing_extras.py | 55 ------------------- 2 files changed, 52 insertions(+), 55 deletions(-) delete mode 100644 tests/functional/test_install_missing_extras.py diff --git a/tests/functional/test_install_extras.py b/tests/functional/test_install_extras.py index 0e27497ef6f..0ebb0c6a6f8 100644 --- a/tests/functional/test_install_extras.py +++ b/tests/functional/test_install_extras.py @@ -51,3 +51,55 @@ def test_no_extras_uninstall(script): # openid should not be uninstalled initools_folder = script.site_packages / 'openid' assert initools_folder not in result2.files_deleted, result.files_deleted + + +def test_non_existant_extra_warns_user_no_wheel(script, data): + """ + A warning is logged telling the user that the extra option they requested + does not exist in the project they are wishing to install. + + This exercises source installs. + """ + result = script.pip( + 'install', '--no-use-wheel', '--no-index', + '--find-links=' + data.find_links, + 'simple[nonexistant]', expect_stderr=True, + ) + assert ( + "Unknown 3.0 does not provide the extra 'nonexistant'" + in result.stdout + ) + + +def test_non_existant_extra_warns_user_with_wheel(script, data): + """ + A warning is logged telling the user that the extra option they requested + does not exist in the project they are wishing to install. + + This exercises wheel installs. + """ + result = script.pip( + 'install', '--use-wheel', '--no-index', + '--find-links=' + data.find_links, + 'simplewheel[nonexistant]', expect_stderr=True, + ) + assert ( + "simplewheel 2.0 does not provide the extra 'nonexistant'" + in result.stdout + ) + + +def test_non_existant_options_listed_in_order(script, data): + """ + Warn the user for each extra that doesn't exist. + """ + result = script.pip( + 'install', '--use-wheel', '--no-index', + '--find-links=' + data.find_links, + 'simplewheel[nonexistant, nope]', expect_stderr=True, + ) + msg = ( + " simplewheel 2.0 does not provide the extra 'nonexistant'\n" + " simplewheel 2.0 does not provide the extra 'nope'" + ) + assert msg in result.stdout diff --git a/tests/functional/test_install_missing_extras.py b/tests/functional/test_install_missing_extras.py deleted file mode 100644 index 1f75f813271..00000000000 --- a/tests/functional/test_install_missing_extras.py +++ /dev/null @@ -1,55 +0,0 @@ -""" -temporarily locate test here to make it fail faster -""" - - -def test_non_existant_extra_warns_user_no_wheel(script, data): - """ - A warning is logged telling the user that the extra option they requested - does not exist in the project they are wishing to install. - - This exercises source installs. - """ - result = script.pip( - 'install', '--no-use-wheel', '--no-index', - '--find-links=' + data.find_links, - 'simple[nonexistant]', expect_stderr=True, - ) - assert ( - "Unknown 3.0 does not provide the extra 'nonexistant'" - in result.stdout - ) - - -def test_non_existant_extra_warns_user_with_wheel(script, data): - """ - A warning is logged telling the user that the extra option they requested - does not exist in the project they are wishing to install. - - This exercises wheel installs. - """ - result = script.pip( - 'install', '--use-wheel', '--no-index', - '--find-links=' + data.find_links, - 'simplewheel[nonexistant]', expect_stderr=True, - ) - assert ( - "simplewheel 2.0 does not provide the extra 'nonexistant'" - in result.stdout - ) - - -def test_non_existant_options_listed_in_order(script, data): - """ - Warn the user for each extra that doesn't exist. - """ - result = script.pip( - 'install', '--use-wheel', '--no-index', - '--find-links=' + data.find_links, - 'simplewheel[nonexistant, nope]', expect_stderr=True, - ) - msg = ( - " simplewheel 2.0 does not provide the extra 'nonexistant'\n" - " simplewheel 2.0 does not provide the extra 'nope'" - ) - assert msg in result.stdout From 704223dff5b093f0a138e2019decb774ee0c4e64 Mon Sep 17 00:00:00 2001 From: derwolfe Date: Thu, 26 Feb 2015 06:50:56 -0600 Subject: [PATCH 24/29] remove assignement iterate directly over the results of the function calls --- pip/req/req_set.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/pip/req/req_set.py b/pip/req/req_set.py index c44e884fefc..6ed0c58cb00 100644 --- a/pip/req/req_set.py +++ b/pip/req/req_set.py @@ -458,17 +458,18 @@ def prepare_files(self, finder): ) if not self.ignore_dependencies: - missing_extras = RequirementSet._missing_extras( - dist.extras, - req_to_install.extras) - requested_and_provided = RequirementSet._available_extras( - dist.extras, - req_to_install.extras) - for missing in missing_extras: + + for missing in RequirementSet._missing_extras( + dist.extras, + req_to_install.extras): logger.warning( '%s does not provide the extra \'%s\'', - dist, missing) - for subreq in dist.requires(requested_and_provided): + str(dist), missing) + + for subreq in dist.requires( + RequirementSet._available_extras( + dist.extras, + req_to_install.extras)): if self.has_requirement( subreq.project_name): # FIXME: check for conflict From f38e10010c6f7e6f5a26fd41518b0e59d2a507b0 Mon Sep 17 00:00:00 2001 From: derwolfe Date: Thu, 26 Feb 2015 07:02:48 -0600 Subject: [PATCH 25/29] revert newline --- pip/_vendor/pkg_resources/__init__.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pip/_vendor/pkg_resources/__init__.py b/pip/_vendor/pkg_resources/__init__.py index b0b092bfebc..617c60a9e47 100644 --- a/pip/_vendor/pkg_resources/__init__.py +++ b/pip/_vendor/pkg_resources/__init__.py @@ -2496,7 +2496,6 @@ def requires(self, extras=()): dm = self._dep_map deps = [] deps.extend(dm.get(None, ())) - for ext in extras: try: deps.extend(dm[safe_extra(ext)]) From 4dfbd2e01c636eb207bfcc7f717947a4854ab920 Mon Sep 17 00:00:00 2001 From: derwolfe Date: Thu, 26 Feb 2015 12:11:04 -0600 Subject: [PATCH 26/29] spacing, sort sets prior to pushing into logger, dist.requires --- pip/req/req_set.py | 44 +++++++++--------------------------------- tests/unit/test_req.py | 40 -------------------------------------- 2 files changed, 9 insertions(+), 75 deletions(-) diff --git a/pip/req/req_set.py b/pip/req/req_set.py index 6ed0c58cb00..999ef59a979 100644 --- a/pip/req/req_set.py +++ b/pip/req/req_set.py @@ -204,32 +204,6 @@ def locate_files(self): (req_to_install, req_to_install.source_dir) ) - @staticmethod - def _available_extras(provided, requested): - """ - Given a tuple of installable extras, and a list of extras that the user - has requested to install, return the list of options that the user has - requested that *can* be installed. - - :param provided: a tuple of optional extras provided by a distribution - :param requested: a list of optional extras the user wants to install - :returns: a tuple of extras that can be installed - """ - return tuple((r for r in requested if r in provided)) - - @staticmethod - def _missing_extras(provided, requested): - """ - Given a tuple of installable extras, and a list of extras that the user - has requested to install, return the list of options that the user has - requested that *cannot* be installed. - - :param provided: a tuple of optional extras provided by a distribution - :param requested: a list of optional extras the user wants to install - :returns: a tuple of extras that cannot be installed - """ - return tuple((r for r in requested if r not in provided)) - def prepare_files(self, finder): """ Prepare process. Create temp directories, download and/or unpack files. @@ -458,18 +432,18 @@ def prepare_files(self, finder): ) if not self.ignore_dependencies: - - for missing in RequirementSet._missing_extras( - dist.extras, - req_to_install.extras): + missing_requested = sorted( + set(req_to_install.extras) - set(dist.extras) + ) + for missing in missing_requested: logger.warning( '%s does not provide the extra \'%s\'', - str(dist), missing) + dist, missing) - for subreq in dist.requires( - RequirementSet._available_extras( - dist.extras, - req_to_install.extras)): + available_requested = sorted( + set(dist.extras) & set(req_to_install.extras) + ) + for subreq in dist.requires(available_requested): if self.has_requirement( subreq.project_name): # FIXME: check for conflict diff --git a/tests/unit/test_req.py b/tests/unit/test_req.py index f6cf534361a..249eaceff96 100644 --- a/tests/unit/test_req.py +++ b/tests/unit/test_req.py @@ -71,46 +71,6 @@ def test_environment_marker_extras(self, data): else: assert not reqset.has_requirement('simple') - def test_missing_extras_returns_empty_tuple_when_no_missing(self): - """ - When all of the requested extras are available, - `req._missing_extras` returns an empty tuple. - """ - provided = ('tls',) - requested = list(provided) - assert not RequirementSet._missing_extras(provided, requested) - - def test_missing_extras_returns_missing_extras(self): - """ - When all of the requested extras are available, - `req._missing_extras` returns a tuple containing each missing extra. - """ - provided = tuple() - missing = ['tls', 'nope', 'nada'] - assert ( - tuple(missing) == RequirementSet._missing_extras(provided, missing) - ) - - def test_available_extras_returns_empty_tuple_with_no_options(self): - """ - When none of the requested options are provided, - `req.available_extras` returns an empty tuple. - """ - provided = tuple() - requested = ['tls', 'nope', 'nada'] - assert not RequirementSet._available_extras(provided, requested) - - def test_available_extras_returns_available_extras(self): - """ - `req.available_extras` returns a tuple containing the intersection - of the extras provided and requested. - """ - provided = ('tls', 'nope') - requested = list(provided) - assert ( - provided == RequirementSet._available_extras(provided, requested) - ) - @pytest.mark.parametrize(('file_contents', 'expected'), [ (b'\xf6\x80', b'\xc3\xb6\xe2\x82\xac'), # cp1252 From 3a1a45af0d7bae119236ac06e75da35b2209c4f5 Mon Sep 17 00:00:00 2001 From: derwolfe Date: Tue, 10 Mar 2015 20:02:09 -0500 Subject: [PATCH 27/29] make splitting of lines/endings consistent /sigmavirus24 --- pip/req/req_set.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pip/req/req_set.py b/pip/req/req_set.py index 999ef59a979..fbd9f1201e8 100644 --- a/pip/req/req_set.py +++ b/pip/req/req_set.py @@ -438,14 +438,14 @@ def prepare_files(self, finder): for missing in missing_requested: logger.warning( '%s does not provide the extra \'%s\'', - dist, missing) + dist, missing + ) available_requested = sorted( set(dist.extras) & set(req_to_install.extras) ) for subreq in dist.requires(available_requested): - if self.has_requirement( - subreq.project_name): + if self.has_requirement(subreq.project_name): # FIXME: check for conflict continue subreq = InstallRequirement( From 55585d0ab8f6a1d51ccd9421250828338fc10942 Mon Sep 17 00:00:00 2001 From: derwolfe Date: Wed, 11 Mar 2015 07:18:22 -0500 Subject: [PATCH 28/29] nonexistant/nonexistent - msabramo comment --- tests/functional/test_install_extras.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/functional/test_install_extras.py b/tests/functional/test_install_extras.py index 0ebb0c6a6f8..5719cd666a1 100644 --- a/tests/functional/test_install_extras.py +++ b/tests/functional/test_install_extras.py @@ -63,10 +63,10 @@ def test_non_existant_extra_warns_user_no_wheel(script, data): result = script.pip( 'install', '--no-use-wheel', '--no-index', '--find-links=' + data.find_links, - 'simple[nonexistant]', expect_stderr=True, + 'simple[nonexistent]', expect_stderr=True, ) assert ( - "Unknown 3.0 does not provide the extra 'nonexistant'" + "Unknown 3.0 does not provide the extra 'nonexistent'" in result.stdout ) @@ -81,10 +81,10 @@ def test_non_existant_extra_warns_user_with_wheel(script, data): result = script.pip( 'install', '--use-wheel', '--no-index', '--find-links=' + data.find_links, - 'simplewheel[nonexistant]', expect_stderr=True, + 'simplewheel[nonexistent]', expect_stderr=True, ) assert ( - "simplewheel 2.0 does not provide the extra 'nonexistant'" + "simplewheel 2.0 does not provide the extra 'nonexistent'" in result.stdout ) @@ -96,10 +96,10 @@ def test_non_existant_options_listed_in_order(script, data): result = script.pip( 'install', '--use-wheel', '--no-index', '--find-links=' + data.find_links, - 'simplewheel[nonexistant, nope]', expect_stderr=True, + 'simplewheel[nonexistent, nope]', expect_stderr=True, ) msg = ( - " simplewheel 2.0 does not provide the extra 'nonexistant'\n" + " simplewheel 2.0 does not provide the extra 'nonexistent'\n" " simplewheel 2.0 does not provide the extra 'nope'" ) assert msg in result.stdout From 97b03f4925d1051d2b195df8959bcab41f1641c5 Mon Sep 17 00:00:00 2001 From: derwolfe Date: Wed, 11 Mar 2015 07:25:09 -0500 Subject: [PATCH 29/29] fix test names, non_existant/nonexistent --- tests/functional/test_install_extras.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/functional/test_install_extras.py b/tests/functional/test_install_extras.py index 5719cd666a1..dcece56a8e6 100644 --- a/tests/functional/test_install_extras.py +++ b/tests/functional/test_install_extras.py @@ -53,7 +53,7 @@ def test_no_extras_uninstall(script): assert initools_folder not in result2.files_deleted, result.files_deleted -def test_non_existant_extra_warns_user_no_wheel(script, data): +def test_nonexistent_extra_warns_user_no_wheel(script, data): """ A warning is logged telling the user that the extra option they requested does not exist in the project they are wishing to install. @@ -71,7 +71,7 @@ def test_non_existant_extra_warns_user_no_wheel(script, data): ) -def test_non_existant_extra_warns_user_with_wheel(script, data): +def test_nonexistent_extra_warns_user_with_wheel(script, data): """ A warning is logged telling the user that the extra option they requested does not exist in the project they are wishing to install. @@ -89,7 +89,7 @@ def test_non_existant_extra_warns_user_with_wheel(script, data): ) -def test_non_existant_options_listed_in_order(script, data): +def test_nonexistent_options_listed_in_order(script, data): """ Warn the user for each extra that doesn't exist. """