Don't show scary diagnostic warnings from --version[-and-path] (corrected). refs ticket:2436

The previous version would incorrectly add to the output of
get_package_versions_string each time it was called.

Signed-off-by: Daira Hopwood <daira@jacaranda.org>
This commit is contained in:
Daira Hopwood 2015-07-28 23:41:13 +01:00
parent 3239527929
commit 2c99294a4f
3 changed files with 66 additions and 44 deletions

View File

@ -178,7 +178,7 @@ def extract_openssl_version(ssl_module):
def get_package_versions_and_locations(): def get_package_versions_and_locations():
import warnings import warnings
from _auto_deps import package_imports, global_deprecation_messages, deprecation_messages, \ from _auto_deps import package_imports, global_deprecation_messages, deprecation_messages, \
runtime_warning_messages, warning_imports runtime_warning_messages, warning_imports, ignorable
def package_dir(srcfile): def package_dir(srcfile):
return os.path.dirname(os.path.dirname(os.path.normcase(os.path.realpath(srcfile)))) return os.path.dirname(os.path.dirname(os.path.normcase(os.path.realpath(srcfile))))
@ -246,7 +246,26 @@ def get_package_versions_and_locations():
elif pkgname == 'OpenSSL': elif pkgname == 'OpenSSL':
packages.append( (pkgname, get_openssl_version()) ) packages.append( (pkgname, get_openssl_version()) )
return packages cross_check_errors = []
if not hasattr(sys, 'frozen'):
import pkg_resources
from _auto_deps import install_requires
pkg_resources_vers_and_locs = dict([(p.project_name.lower(), (str(p.version), p.location))
for p in pkg_resources.require(install_requires)])
imported_packages = set([p.lower() for (p, _) in packages])
extra_packages = []
for pr_name, (pr_ver, pr_loc) in pkg_resources_vers_and_locs.iteritems():
if pr_name not in imported_packages and pr_name not in ignorable:
extra_packages.append( (pr_name, (pr_ver, pr_loc, "according to pkg_resources")) )
cross_check_errors = cross_check(pkg_resources_vers_and_locs, packages)
packages += extra_packages
return packages, cross_check_errors
def check_requirement(req, vers_and_locs): def check_requirement(req, vers_and_locs):
@ -300,25 +319,10 @@ def match_requirement(req, reqlist, actualver):
return True return True
_vers_and_locs_list = get_package_versions_and_locations()
def cross_check_pkg_resources_versus_import():
"""This function returns a list of errors due to any failed cross-checks."""
import pkg_resources
from _auto_deps import install_requires
pkg_resources_vers_and_locs = dict([(p.project_name.lower(), (str(p.version), p.location))
for p in pkg_resources.require(install_requires)])
return cross_check(pkg_resources_vers_and_locs, _vers_and_locs_list)
def cross_check(pkg_resources_vers_and_locs, imported_vers_and_locs_list): def cross_check(pkg_resources_vers_and_locs, imported_vers_and_locs_list):
"""This function returns a list of errors due to any failed cross-checks.""" """This function returns a list of errors due to any failed cross-checks."""
from _auto_deps import not_import_versionable, ignorable from _auto_deps import not_import_versionable
errors = [] errors = []
not_pkg_resourceable = ['python', 'platform', __appname__.lower(), 'openssl'] not_pkg_resourceable = ['python', 'platform', __appname__.lower(), 'openssl']
@ -376,16 +380,12 @@ def cross_check(pkg_resources_vers_and_locs, imported_vers_and_locs_list):
"by pkg_resources, but version %r (normalized to %r, from %r) by import." "by pkg_resources, but version %r (normalized to %r, from %r) by import."
% (name, pr_ver, str(pr_normver), pr_loc, imp_ver, str(imp_normver), imp_loc)) % (name, pr_ver, str(pr_normver), pr_loc, imp_ver, str(imp_normver), imp_loc))
imported_packages = set([p.lower() for (p, _) in imported_vers_and_locs_list])
extra_vers_and_locs_list = []
for pr_name, (pr_ver, pr_loc) in pkg_resources_vers_and_locs.iteritems():
if pr_name not in imported_packages and pr_name not in ignorable:
errors.append("Warning: dependency %r (version %r) found by pkg_resources not found by import."
% (pr_name, pr_ver))
return errors return errors
_vers_and_locs_list, _cross_check_errors = get_package_versions_and_locations()
def get_error_string(errors, debug=False): def get_error_string(errors, debug=False):
from allmydata._auto_deps import install_requires from allmydata._auto_deps import install_requires
@ -406,7 +406,7 @@ def check_all_requirements():
from allmydata._auto_deps import install_requires from allmydata._auto_deps import install_requires
errors = [] fatal_errors = []
# We require at least 2.6 on all platforms. # We require at least 2.6 on all platforms.
# (On Python 3, we'll have failed long before this point.) # (On Python 3, we'll have failed long before this point.)
@ -415,7 +415,7 @@ def check_all_requirements():
version_string = ".".join(map(str, sys.version_info)) version_string = ".".join(map(str, sys.version_info))
except Exception: except Exception:
version_string = repr(sys.version_info) version_string = repr(sys.version_info)
errors.append("Tahoe-LAFS currently requires Python v2.6 or greater (but less than v3), not %s" fatal_errors.append("Tahoe-LAFS currently requires Python v2.6 or greater (but less than v3), not %s"
% (version_string,)) % (version_string,))
vers_and_locs = dict(_vers_and_locs_list) vers_and_locs = dict(_vers_and_locs_list)
@ -423,10 +423,10 @@ def check_all_requirements():
try: try:
check_requirement(requirement, vers_and_locs) check_requirement(requirement, vers_and_locs)
except (ImportError, PackagingError), e: except (ImportError, PackagingError), e:
errors.append("%s: %s" % (e.__class__.__name__, e)) fatal_errors.append("%s: %s" % (e.__class__.__name__, e))
if errors: if fatal_errors:
raise PackagingError(get_error_string(errors, debug=True)) raise PackagingError(get_error_string(fatal_errors + _cross_check_errors, debug=True))
check_all_requirements() check_all_requirements()
@ -449,9 +449,7 @@ def get_package_versions_string(show_paths=False, debug=False):
output = "\n".join(res) + "\n" output = "\n".join(res) + "\n"
if not hasattr(sys, 'frozen'): if _cross_check_errors:
errors = cross_check_pkg_resources_versus_import() output += get_error_string(_cross_check_errors, debug=debug)
if errors:
output += get_error_string(errors, debug=debug)
return output return output

View File

@ -8,19 +8,22 @@ import __builtin__
class T(unittest.TestCase): class T(unittest.TestCase):
def test_report_import_error(self): def test_report_import_error(self):
marker = "wheeeyo"
real_import_func = __import__ real_import_func = __import__
def raiseIE_from_this_particular_func(name, *args): def raiseIE_from_this_particular_func(name, *args):
if name == "foolscap": if name == "foolscap":
marker = "wheeeyo"
raise ImportError(marker + " foolscap cant be imported") raise ImportError(marker + " foolscap cant be imported")
else: else:
return real_import_func(name, *args) return real_import_func(name, *args)
# Let's run as little code as possible with __import__ patched. # Let's run as little code as possible with __import__ patched.
patcher = MonkeyPatcher((__builtin__, '__import__', raiseIE_from_this_particular_func)) patcher = MonkeyPatcher((__builtin__, '__import__', raiseIE_from_this_particular_func))
vers_and_locs = patcher.runWithPatches(allmydata.get_package_versions_and_locations) vers_and_locs, errors = patcher.runWithPatches(allmydata.get_package_versions_and_locations)
for (pkgname, stuff) in vers_and_locs: foolscap_stuffs = [stuff for (pkg, stuff) in vers_and_locs if pkg == 'foolscap']
if pkgname == 'foolscap': self.failUnlessEqual(len(foolscap_stuffs), 1)
self.failUnless('wheeeyo' in str(stuff[2]), stuff) comment = str(foolscap_stuffs[0][2])
self.failUnless('raiseIE_from_this_particular_func' in str(stuff[2]), stuff) self.failUnlessIn(marker, comment)
self.failUnlessIn('raiseIE_from_this_particular_func', comment)
self.failUnless([e for e in errors if "dependency \'foolscap\' could not be imported" in e])

View File

@ -1,9 +1,12 @@
import sys
import pkg_resources
from pkg_resources import Requirement from pkg_resources import Requirement
from twisted.trial import unittest from twisted.trial import unittest
from allmydata import check_requirement, cross_check, extract_openssl_version, PackagingError from allmydata import check_requirement, cross_check, get_package_versions_and_locations, \
extract_openssl_version, PackagingError
from allmydata.util.verlib import NormalizedVersion as V, \ from allmydata.util.verlib import NormalizedVersion as V, \
IrrationalVersionError, \ IrrationalVersionError, \
suggest_normalized_version as suggest suggest_normalized_version as suggest
@ -69,6 +72,25 @@ class CheckRequirement(unittest.TestCase):
for pkg, ver in vers_and_locs.items(): for pkg, ver in vers_and_locs.items():
self.failIf(ver[0] in Requirement.parse(req), str((ver, req))) self.failIf(ver[0] in Requirement.parse(req), str((ver, req)))
def test_packages_from_pkg_resources(self):
if hasattr(sys, 'frozen'):
raise unittest.SkipTest("This test doesn't apply to frozen builds.")
class MockPackage(object):
def __init__(self, project_name, version, location):
self.project_name = project_name
self.version = version
self.location = location
def call_pkg_resources_require(*args):
return [MockPackage("Foo", "1.0", "/path")]
self.patch(pkg_resources, 'require', call_pkg_resources_require)
(packages, errors) = get_package_versions_and_locations()
self.failUnlessIn(("foo", ("1.0", "/path", "according to pkg_resources")), packages)
self.failIfEqual(errors, [])
self.failUnlessEqual([e for e in errors if "was not found by pkg_resources" not in e], [])
def test_cross_check_ticket_1355(self): def test_cross_check_ticket_1355(self):
# The bug in #1355 is triggered when a version string from either pkg_resources or import # The bug in #1355 is triggered when a version string from either pkg_resources or import
# is not parseable at all by normalized_version. # is not parseable at all by normalized_version.
@ -89,8 +111,7 @@ class CheckRequirement(unittest.TestCase):
self.failUnlessEqual(res, []) self.failUnlessEqual(res, [])
res = cross_check({"foo": ("unparseable", "")}, []) res = cross_check({"foo": ("unparseable", "")}, [])
self.failUnlessEqual(len(res), 1) self.failUnlessEqual(res, [])
self.failUnlessIn("not found by import", res[0])
res = cross_check({"argparse": ("unparseable", "")}, []) res = cross_check({"argparse": ("unparseable", "")}, [])
self.failUnlessEqual(len(res), 0) self.failUnlessEqual(len(res), 0)