diff --git a/misc/python3/ratchet-passing b/misc/python3/ratchet-passing index 293733b2b..522a9fc6d 100644 --- a/misc/python3/ratchet-passing +++ b/misc/python3/ratchet-passing @@ -45,3 +45,13 @@ allmydata.test.test_observer.Observer.test_oneshot_fireagain allmydata.test.test_python3.Python3PortingEffortTests.test_finished_porting allmydata.test.test_python3.Python3PortingEffortTests.test_ported_modules_distinct allmydata.test.test_python3.Python3PortingEffortTests.test_ported_modules_exist +allmydata.test.test_version.CheckRequirement.test_cross_check +allmydata.test.test_version.CheckRequirement.test_cross_check_unparseable_versions +allmydata.test.test_version.CheckRequirement.test_extract_openssl_version +allmydata.test.test_version.CheckRequirement.test_packages_from_pkg_resources +allmydata.test.test_version.T.test_report_import_error +allmydata.test.test_version.VersionTestCase.test_basic_versions +allmydata.test.test_version.VersionTestCase.test_comparison +allmydata.test.test_version.VersionTestCase.test_from_parts +allmydata.test.test_version.VersionTestCase.test_irrational_versions +allmydata.test.test_version.VersionTestCase.test_suggest_normalized_version diff --git a/newsfragments/3357.minor b/newsfragments/3357.minor new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/newsfragments/3357.minor @@ -0,0 +1 @@ + diff --git a/nix/tahoe-lafs.nix b/nix/tahoe-lafs.nix index 097a463d1..0e941bce1 100644 --- a/nix/tahoe-lafs.nix +++ b/nix/tahoe-lafs.nix @@ -4,7 +4,7 @@ , setuptools, setuptoolsTrial, pyasn1, zope_interface , service-identity, pyyaml, magic-wormhole, treq, appdirs , beautifulsoup4, eliot, autobahn, cryptography -, html5lib, pyutil +, html5lib, pyutil, distro }: python.pkgs.buildPythonPackage rec { version = "1.14.0.dev"; @@ -50,7 +50,7 @@ python.pkgs.buildPythonPackage rec { setuptoolsTrial pyasn1 zope_interface service-identity pyyaml magic-wormhole treq eliot autobahn cryptography setuptools - future pyutil + future pyutil distro ]; checkInputs = with python.pkgs; [ diff --git a/setup.py b/setup.py index f22ca0f4c..9bb385cb4 100644 --- a/setup.py +++ b/setup.py @@ -127,6 +127,9 @@ install_requires = [ # Utility code: "pyutil >= 3.3.0", + + # Linux distribution detection: + "distro >= 1.4.0", ] setup_requires = [ diff --git a/src/allmydata/test/test_version.py b/src/allmydata/test/test_version.py index fd0cb0e20..1b447e346 100644 --- a/src/allmydata/test/test_version.py +++ b/src/allmydata/test/test_version.py @@ -1,3 +1,16 @@ +""" +Tests for allmydata.util.verlib and allmydata.version_checks. + +Ported to Python 3. +""" +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function +from __future__ import unicode_literals + +from future.utils import PY2 +if PY2: + from builtins import filter, map, zip, ascii, chr, hex, input, next, oct, open, pow, round, super, bytes, dict, int, list, object, range, str, max, min # noqa: F401 import sys import pkg_resources @@ -79,7 +92,7 @@ class CheckRequirement(unittest.TestCase): res = cross_check({}, [("foo", ("unparseable", "", None))]) self.failUnlessEqual(len(res), 1) - self.failUnlessIn("version 'unparseable'", res[0]) + self.assertTrue(("version 'unparseable'" in res[0]) or ("version u'unparseable'" in res[0])) self.failUnlessIn("was not found by pkg_resources", res[0]) res = cross_check({"distribute": ("1.0", "/somewhere")}, [("setuptools", ("2.0", "/somewhere", "distribute"))]) @@ -120,7 +133,7 @@ class CheckRequirement(unittest.TestCase): res = cross_check({"foo": ("1.0", "/somewhere")}, [("foo", ("2.0", "/somewhere_different", None))]) self.failUnlessEqual(len(res), 1) - self.failUnlessIn("but version '2.0'", res[0]) + self.assertTrue(("but version '2.0'" in res[0]) or ("but version u'2.0'" in res[0])) def test_extract_openssl_version(self): self.failUnlessEqual(extract_openssl_version(MockSSL("")), diff --git a/src/allmydata/util/_python3.py b/src/allmydata/util/_python3.py index a79f20cd0..4bb639996 100644 --- a/src/allmydata/util/_python3.py +++ b/src/allmydata/util/_python3.py @@ -38,6 +38,7 @@ PORTED_TEST_MODULES = [ "allmydata.test.test_humanreadable", "allmydata.test.test_netstring", "allmydata.test.test_python3", + "allmydata.test.test_version", ] diff --git a/src/allmydata/util/verlib.py b/src/allmydata/util/verlib.py index 619f1a845..f69e34e3d 100644 --- a/src/allmydata/util/verlib.py +++ b/src/allmydata/util/verlib.py @@ -1,11 +1,21 @@ """ "Rational" version definition and parsing for DistutilsVersionFight discussion at PyCon 2009. -""" +Ported to Python 3. +""" +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function +from __future__ import unicode_literals + +from future.utils import PY2 +if PY2: + from builtins import filter, map, zip, ascii, chr, hex, input, next, oct, open, pow, round, super, bytes, dict, int, list, object, range, str, max, min # noqa: F401 import re + class IrrationalVersionError(Exception): """This is an irrational version.""" pass diff --git a/src/allmydata/version_checks.py b/src/allmydata/version_checks.py index 7092a422b..51a49d78a 100644 --- a/src/allmydata/version_checks.py +++ b/src/allmydata/version_checks.py @@ -1,7 +1,17 @@ """ Produce reports about the versions of Python software in use by Tahoe-LAFS for debugging and auditing purposes. + +Ported to Python 3. """ +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function +from __future__ import unicode_literals + +from future.utils import PY2 +if PY2: + from builtins import filter, map, zip, ascii, chr, hex, input, next, oct, open, pow, round, super, bytes, dict, int, list, object, range, str, max, min # noqa: F401 __all__ = [ "PackagingError", @@ -10,10 +20,12 @@ __all__ = [ "normalized_version", ] -import os, platform, re, subprocess, sys, traceback, pkg_resources +import os, platform, re, sys, traceback, pkg_resources import six +import distro + from . import ( __appname__, full_version, @@ -80,7 +92,7 @@ def normalized_version(verstr, what=None): return verlib.NormalizedVersion(suggested) except verlib.IrrationalVersionError: raise - except StandardError: + except Exception: cls, value, trace = sys.exc_info() new_exc = PackagingError("could not parse %s due to %s: %s" % (what or repr(verstr), cls.__name__, value)) @@ -109,7 +121,7 @@ def _get_error_string(errors, debug=False): 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.""" - from _auto_deps import not_import_versionable + from ._auto_deps import not_import_versionable errors = [] not_pkg_resourceable = ['python', 'platform', __appname__.lower(), 'openssl'] @@ -201,83 +213,6 @@ def _extract_openssl_version(ssl_module): return (version, None, comment if comment else None) -def _get_linux_distro(): - """ Tries to determine the name of the Linux OS distribution name. - - First, try to parse a file named "/etc/lsb-release". If it exists, and - contains the "DISTRIB_ID=" line and the "DISTRIB_RELEASE=" line, then return - the strings parsed from that file. - - If that doesn't work, then invoke platform.dist(). - - If that doesn't work, then try to execute "lsb_release", as standardized in - 2001: - - http://refspecs.freestandards.org/LSB_1.0.0/gLSB/lsbrelease.html - - The current version of the standard is here: - - http://refspecs.freestandards.org/LSB_3.2.0/LSB-Core-generic/LSB-Core-generic/lsbrelease.html - - that lsb_release emitted, as strings. - - Returns a tuple (distname,version). Distname is what LSB calls a - "distributor id", e.g. "Ubuntu". Version is what LSB calls a "release", - e.g. "8.04". - - A version of this has been submitted to python as a patch for the standard - library module "platform": - - http://bugs.python.org/issue3937 - """ - global _distname,_version - if _distname and _version: - return (_distname, _version) - - try: - with open("/etc/lsb-release", "rU") as etclsbrel: - for line in etclsbrel: - m = _distributor_id_file_re.search(line) - if m: - _distname = m.group(1).strip() - if _distname and _version: - return (_distname, _version) - m = _release_file_re.search(line) - if m: - _version = m.group(1).strip() - if _distname and _version: - return (_distname, _version) - except EnvironmentError: - pass - - (_distname, _version) = platform.dist()[:2] - if _distname and _version: - return (_distname, _version) - - if os.path.isfile("/usr/bin/lsb_release") or os.path.isfile("/bin/lsb_release"): - try: - p = subprocess.Popen(["lsb_release", "--all"], stdout=subprocess.PIPE, stderr=subprocess.PIPE) - rc = p.wait() - if rc == 0: - for line in p.stdout.readlines(): - m = _distributor_id_cmdline_re.search(line) - if m: - _distname = m.group(1).strip() - if _distname and _version: - return (_distname, _version) - - m = _release_cmdline_re.search(p.stdout.read()) - if m: - _version = m.group(1).strip() - if _distname and _version: - return (_distname, _version) - except EnvironmentError: - pass - - if os.path.exists("/etc/arch-release"): - return ("Arch_Linux", "") - - return (_distname,_version) def _get_platform(): # Our version of platform.platform(), telling us both less and more than the @@ -288,7 +223,7 @@ def _get_platform(): if "linux" in platform.system().lower(): return ( platform.system() + "-" + - "_".join(_get_linux_distro()) + "-" + + "_".join(distro.linux_distribution()[:2]) + "-" + platform.machine() + "-" + "_".join([x for x in platform.architecture() if x]) ) @@ -321,7 +256,7 @@ def _get_package_versions_and_locations(): for modulename in warning_imports: try: __import__(modulename) - except ImportError: + except (ImportError, SyntaxError): pass finally: # Leave suppressions for UserWarnings and global_deprecation_messages active. @@ -355,7 +290,7 @@ def _get_package_versions_and_locations(): try: __import__(modulename) module = sys.modules[modulename] - except ImportError: + except (ImportError, SyntaxError): etype, emsg, etrace = sys.exc_info() trace_info = (etype, str(emsg), ([None] + traceback.extract_tb(etrace))[-1]) packages.append( (pkgname, (None, None, trace_info)) ) @@ -386,7 +321,7 @@ def _get_package_versions_and_locations(): 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(): + for pr_name, (pr_ver, pr_loc) in pkg_resources_vers_and_locs.items(): 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")) )