'DeprecationWarning: the sets module is deprecated' from foolscap causes failure in test_client_no_noise #1329

Closed
opened 2011-01-16 05:52:24 +00:00 by daira · 8 comments

(http://tahoe-lafs.org/buildbot/builders/Brian%20ubuntu-i386%20linode/builds/133/steps/test/logs/stdio)

[FAIL]: allmydata.test.test_runner.RunNode.test_client_no_noise

Traceback (most recent call last):
  File "/home/buildbot/bb-tahoe/brian-linode/build/src/allmydata/test/test_runner.py", line 442, in _cb2
    and "from pkg_resources import load_entry_point" not in line)], errstr)
twisted.trial.unittest.FailTest: cc=0, OUT: '', ERR: '/home/buildbot/bb-tahoe/brian-linode/build/support/lib/python2.6/site-packages/foolscap-0.6.0-py2.6.egg/foolscap/banana.py:2: DeprecationWarning: the sets module is deprecated
  import struct, sets, time
'
(http://tahoe-lafs.org/buildbot/builders/Brian%20ubuntu-i386%20linode/builds/133/steps/test/logs/stdio) ``` [FAIL]: allmydata.test.test_runner.RunNode.test_client_no_noise Traceback (most recent call last): File "/home/buildbot/bb-tahoe/brian-linode/build/src/allmydata/test/test_runner.py", line 442, in _cb2 and "from pkg_resources import load_entry_point" not in line)], errstr) twisted.trial.unittest.FailTest: cc=0, OUT: '', ERR: '/home/buildbot/bb-tahoe/brian-linode/build/support/lib/python2.6/site-packages/foolscap-0.6.0-py2.6.egg/foolscap/banana.py:2: DeprecationWarning: the sets module is deprecated import struct, sets, time ' ```
daira added the
c/code
p/major
t/defect
v/1.8.1
labels 2011-01-16 05:52:24 +00:00
daira added this to the soon milestone 2011-01-16 05:52:24 +00:00
Author

In [4965/ticket1306]:

src/allmydata/_auto_deps.py: Fix 'DeprecationWarning: the sets module is deprecated'. refs #1329
In [4965/ticket1306]: ``` src/allmydata/_auto_deps.py: Fix 'DeprecationWarning: the sets module is deprecated'. refs #1329 ```
daira modified the milestone from soon to 1.8.2 2011-01-16 21:23:57 +00:00

I just released foolscap-0.6.1, which removes the offending import sets, so this ticket can be resolved by increasing Tahoe's requirement to foolscap-0.6.1 .

I just released foolscap-0.6.1, which removes the offending `import sets`, so this ticket can be resolved by increasing Tahoe's requirement to foolscap-0.6.1 .

-0 from me -- I would rather suppress the warning the way [20110116200112-93fa1-0397f85493a9fd0ae82ce58d7291d598a4f6e2d6]/ticket1306 attempts to do or change the test to tolerate the noise than raise the dependency requirement. But, it is just a -0. If you prefer it, go ahead.

-0 from me -- I would rather suppress the warning the way [20110116200112-93fa1-0397f85493a9fd0ae82ce58d7291d598a4f6e2d6]/ticket1306 attempts to do or change the test to tolerate the noise than raise the dependency requirement. But, it is just a -0. If you prefer it, go ahead.

my main problem with [20110116200112-93fa1-0397f85493a9fd0ae82ce58d7291d598a4f6e2d6]/ticket1306 is that it involved what looked like a signficant refactoring of _auto_deps.py, so I couldn't apply just a single patch (there were more like six). But if there's a clean way to use that approach, I'm happy to go with it.

The clock is ticking, though :)

my main problem with [20110116200112-93fa1-0397f85493a9fd0ae82ce58d7291d598a4f6e2d6]/ticket1306 is that it involved what looked like a signficant refactoring of `_auto_deps.py`, so I couldn't apply just a single patch (there were more like six). But if there's a clean way to use that approach, I'm happy to go with it. The clock is ticking, though :)

Replying to warner:

my main problem with [20110116200112-93fa1-0397f85493a9fd0ae82ce58d7291d598a4f6e2d6]/ticket1306 is that it involved what looked like a signficant refactoring of _auto_deps.py, so I couldn't apply just a single patch (there were more like six). But if there's a clean way to use that approach, I'm happy to go with it.

For the record, here are the patches that (from darcs's perspective) are required for [20110116200112-93fa1-0397f85493a9fd0ae82ce58d7291d598a4f6e2d6]/ticket1306:

HACL Zooko-Ofsimplegeos-MacBook-Pro:~/playground/tahoe-lafs/ticket1329$ time darcs push zooko@dev.allmydata.org:/home/darcs/tahoe-lafs/trunk
Pushing to "zooko@dev.allmydata.org:/home/darcs/tahoe-lafs/trunk"...
The remote repository has 2 patches to pull.
Sat Jan  1 04:01:41 MST 2011  david-sarah@jacaranda.org
  * allmydata/__init__.py: don't use pkg_resources.require to get versions and paths. Also change pyOpenSSL to pyopenssl since that is the package name. fixes #1287
Shall I push this patch? (1/7)  [ynWsfvplxdaqjk], or ? for help: w
Sat Jan  1 13:05:02 MST 2011  david-sarah@jacaranda.org
  * allmydata/_auto_deps.py: add a comment reminding to change __init__.py when dependencies are added or removed. Clarify a comment in __init__.py. refs #1287
Shall I push this patch? (2/7)  [ynWvplxdaqjk], or ? for help: w
Sat Jan  1 12:25:59 MST 2011  david-sarah@jacaranda.org
  * test_runner: add test_import_in_repl, which uses 'bin/tahoe debug repl' to import the allmydata module and checks that it comes from the right path. Also, fix a latent bug that caused test_the_right_code to incorrectly conclude that a path mismatch was due to a Unicode path (causing a skip rather than a failure). This version of the patch avoids a confusing shadowing of 'srcfile'. refs #1258
Shall I push this patch? (3/7)  [ynWsfvplxdaqjk], or ? for help: w
Wed Jan 12 21:24:57 MST 2011  david-sarah@jacaranda.org
  * Make bb-freeze work. This also implements more robust checking of dependency requirements, as discussed in ticket:585#comment:10 . refs #585
Shall I push this patch? (4/7)  [ynWvplxdaqjk], or ? for help: w
Wed Jan 12 21:30:40 MST 2011  david-sarah@jacaranda.org
  * Move get_package_versions_and_locations from __init__.py to _auto_deps.py (because it needs to be updated when dependencies change). refs #585
Shall I push this patch? (5/7)  [ynWvplxdaqjk], or ? for help: w
Fri Jan 14 22:02:45 MST 2011  david-sarah@jacaranda.org
  * Add mock to get_package_versions_and_locations.
Shall I push this patch? (6/7)  [ynWsfvplxdaqjk], or ? for help: w
Sun Jan 16 13:01:12 MST 2011  david-sarah@jacaranda.org
  * src/allmydata/_auto_deps.py: Fix 'DeprecationWarning: the sets module is deprecated'. refs #1329
Shall I push this patch? (7/7)  [ynWsfvplxdaqjk], or ? for help: w

And below and attached is the unified diff of all seven of them coalesced.

I propose that we start by applying the first one -- see #1258.

diff -rN -u old-ticket1329/Makefile new-ticket1329/Makefile
--- old-ticket1329/Makefile	2011-01-17 23:54:16.000000000 -0700
+++ new-ticket1329/Makefile	2011-01-17 23:54:16.000000000 -0700
@@ -179,7 +179,7 @@
 
 
 pyflakes:
-	$(PYTHON) -OOu `which pyflakes` src/allmydata |sort |uniq
+	$(PYTHON) -OOu `which pyflakes` src/allmydata static |sort |uniq
 check-umids:
 	$(PYTHON) misc/coding_tools/check-umids.py `find src/allmydata -name '*.py'`
 
diff -rN -u old-ticket1329/src/allmydata/__init__.py new-ticket1329/src/allmydata/__init__.py
--- old-ticket1329/src/allmydata/__init__.py	2011-01-17 23:54:16.000000000 -0700
+++ new-ticket1329/src/allmydata/__init__.py	2011-01-17 23:54:16.000000000 -0700
@@ -4,57 +4,6 @@
 community web site: U{http://tahoe-lafs.org/}
 """
 
-# We want to call require_auto_deps() before other imports, because the setuptools
-# docs claim that if a distribution is installed with --multi-version, it might not
-# be importable until after pkg_resources.require() has been called for it. We don't
-# have an example of this happening at this time. It is possible that require() isn't
-# actually needed because we set __requires__ in the generated startup script, but
-# that would be an undocumented property of the setuptools implementation.
-
-from allmydata import _auto_deps
-_auto_deps.require_auto_deps()
-
-# This is just to suppress DeprecationWarnings from nevow and twisted.
-# See http://allmydata.org/trac/tahoe/ticket/859 and
-# http://divmod.org/trac/ticket/2994 .
-import warnings
-warnings.filterwarnings("ignore", category=DeprecationWarning,
-    message="the sha module is deprecated; use the hashlib module instead",
-    append=True)
-warnings.filterwarnings("ignore", category=DeprecationWarning,
-    message="object.__new__\(\) takes no parameters",
-    append=True)
-warnings.filterwarnings("ignore", category=DeprecationWarning,
-    message="The popen2 module is deprecated.  Use the subprocess module.",
-    append=True)
-warnings.filterwarnings("ignore", category=DeprecationWarning,
-    message="the md5 module is deprecated; use hashlib instead",
-    append=True)
-warnings.filterwarnings("ignore", category=DeprecationWarning,
-    message="twisted.web.error.NoResource is deprecated since Twisted 9.0.  See twisted.web.resource.NoResource.",
-    append=True)
-try:
-    import nevow
-    from twisted.persisted import sob
-    from twisted.python import filepath
-    hush_pyflakes = (nevow, sob, filepath)
-    del hush_pyflakes
-finally:
-    warnings.filters.pop()
-    warnings.filters.pop()
-    warnings.filters.pop()
-    warnings.filters.pop()
-    # Don't pop the filter for the sha module warning because it is also generated
-    # by pycrypto (which we don't want to import unless needed).
-    # warnings.filters.pop()
-
-# This warning is generated by twisted, PyRex, and possibly other packages,
-# but can happen at any time, not only when they are imported. See
-# http://tahoe-lafs.org/trac/tahoe-lafs/ticket/1129 .
-warnings.filterwarnings("ignore", category=DeprecationWarning,
-    message="BaseException.message has been deprecated as of Python 2.6",
-    append=True)
-
 __version__ = "unknown"
 try:
     from allmydata._version import __version__
@@ -175,88 +124,93 @@
     else:
         return platform.platform()
 
-def get_package_versions_from_setuptools():
-    import pkg_resources
-    return dict([(p.project_name, (p.version, p.location)) for p in pkg_resources.require(__appname__)])
-
-def package_dir(srcfile):
-    return os.path.dirname(os.path.dirname(os.path.normcase(os.path.realpath(srcfile))))
-
-def get_package_versions_and_locations():
-    # because there are a few dependencies that are outside setuptools's ken
-    # (Python and platform, and sqlite3 if you are on Python >= 2.5), and
-    # because setuptools might fail to find something even though import
-    # finds it:
-    import OpenSSL, allmydata, foolscap.api, nevow, platform, pycryptopp, setuptools, simplejson, twisted, zfec, zope.interface
-    pysqlitever = None
-    pysqlitefile = None
-    sqlitever = None
-    try:
-        import sqlite3
-    except ImportError:
-        try:
-            from pysqlite2 import dbapi2
-        except ImportError:
-            pass
-        else:
-            pysqlitever = dbapi2.version
-            pysqlitefile = package_dir(dbapi2.__file__)
-            sqlitever = dbapi2.sqlite_version
-    else:
-        pysqlitever = sqlite3.version
-        pysqlitefile = package_dir(sqlite3.__file__)
-        sqlitever = sqlite3.sqlite_version
-
-    d1 = {
-        'pyOpenSSL': (OpenSSL.__version__, package_dir(OpenSSL.__file__)),
-        __appname__: (allmydata.__version__, package_dir(allmydata.__file__)),
-        'foolscap': (foolscap.api.__version__, package_dir(foolscap.__file__)),
-        'Nevow': (nevow.__version__, package_dir(nevow.__file__)),
-        'pycryptopp': (pycryptopp.__version__, package_dir(pycryptopp.__file__)),
-        'setuptools': (setuptools.__version__, package_dir(setuptools.__file__)),
-        'simplejson': (simplejson.__version__, package_dir(simplejson.__file__)),
-        'pysqlite': (pysqlitever, pysqlitefile),
-        'sqlite': (sqlitever, 'unknown'),
-        'zope.interface': ('unknown', package_dir(zope.interface.__file__)),
-        'Twisted': (twisted.__version__, package_dir(twisted.__file__)),
-        'zfec': (zfec.__version__, package_dir(zfec.__file__)),
-        'python': (platform.python_version(), sys.executable),
-        'platform': (get_platform(), None),
-        }
 
-    # But we prefer to get all the dependencies as known by setuptools:
-    import pkg_resources
-    try:
-        d2 = get_package_versions_from_setuptools()
-    except pkg_resources.DistributionNotFound:
-        # See docstring in _auto_deps.require_auto_deps() to explain why it makes sense to ignore this exception.
-        pass
+from allmydata._auto_deps import get_package_versions_and_locations
+
+_vers_and_locs = get_package_versions_and_locations()
+_vers_and_locs['platform'] = (get_platform(), None)
+
+
+def check_all_requirements():
+    import platform
+    from distutils.version import LooseVersion
+    from allmydata._auto_deps import install_requires
+
+    # we require 2.4.4 on non-UCS-2, non-Redhat builds to avoid <http://www.python.org/news/security/PSF-2006-001/>
+    # we require 2.4.3 on non-UCS-2 Redhat, because 2.4.3 is common on Redhat-based distros and will have patched the above bug
+    # we require at least 2.4.2 in any case to avoid a bug in the base64 module: <http://bugs.python.org/issue1171487>
+    if sys.maxunicode == 65535:
+        if sys.version_info < (2, 4, 2) or sys.version_info[0] > 2:
+            raise NotImplementedError("Tahoe-LAFS current requires Python v2.4.2 or greater "
+                                      "for a UCS-2 build (but less than v3), not %r" %
+                                      (sys.version_info,))
+    elif platform.platform().lower().find('redhat') >= 0:
+        if sys.version_info < (2, 4, 3) or sys.version_info[0] > 2:
+            raise NotImplementedError("Tahoe-LAFS current requires Python v2.4.3 or greater "
+                                      "on Redhat-based distributions (but less than v3), not %r" %
+                                      (sys.version_info,))
     else:
-        d1.update(d2)
+        if sys.version_info < (2, 4, 4) or sys.version_info[0] > 2:
+            raise NotImplementedError("Tahoe-LAFS current requires Python v2.4.4 or greater "
+                                      "for a non-UCS-2 build (but less than v3), not %r" %
+                                      (sys.version_info,))
+
+    def check_requirement(req):
+        # We only support a single >= or ==.
+        def _check(s, ok, relation):
+            name = s[0].strip(' ').partition('[')[0]
+            required = s[1].strip(' ')
+            if name not in _vers_and_locs:
+                raise AssertionError("no version info for %s" % (name,))
+            (actual, location) = _vers_and_locs[name]
+            actual = str(actual)
+            if actual != 'unknown' and not ok(LooseVersion(actual), LooseVersion(required)):
+                msg = ("We require %s version %s of %s, but could only find version %s.\n"
+                      % (relation, required, name, actual))
+                if location and location != 'unknown':
+                    msg += "The version we found is from %r.\n" % (location,)
+                msg += ("To resolve this problem, uninstall that version, either using your\n"
+                        "operating system's package manager or by moving aside the directory.")
+                raise AssertionError(msg)
+
+        s = req.split('>=')
+        if len(s) == 2:
+            _check(s, lambda x, y: x >= y, "at least")
+            return
+        s = req.split('==')
+        if len(s) == 2:
+            _check(s, lambda x, y: x == y, "exactly")
+            return
+        if req not in _vers_and_locs:
+            raise AssertionError("no version info or could not understand requirement for %r" % (req))
+
+    for requirement in install_requires:
+        check_requirement(requirement)
+
+check_all_requirements()
 
-    return d1
 
 def get_package_versions():
-    return dict([(k, v) for k, (v, l) in get_package_versions_and_locations().iteritems()])
+    return dict([(k, v) for k, (v, l) in _vers_and_locs.iteritems()])
 
 def get_package_locations():
-    return dict([(k, l) for k, (v, l) in get_package_versions_and_locations().iteritems()])
+    return dict([(k, l) for k, (v, l) in _vers_and_locs.iteritems()])
 
 def get_package_versions_string(show_paths=False):
-    vers_and_locs = get_package_versions_and_locations()
     res = []
-    for p in [__appname__, "foolscap", "pycryptopp", "zfec", "Twisted", "Nevow", "zope.interface", "python", "platform"]:
-        (ver, loc) = vers_and_locs.get(p, ('UNKNOWN', 'UNKNOWN'))
+    first = [__appname__, "foolscap", "pycryptopp", "zfec", "Twisted", "Nevow", "zope.interface", "python", "platform"]
+    for p in first:
+        (ver, loc) = _vers_and_locs.get(p, ('UNKNOWN', 'UNKNOWN'))
         info = str(p) + ": " + str(ver)
         if show_paths:
             info = info + " (%s)" % str(loc)
         res.append(info)
-        if vers_and_locs.has_key(p):
-            del vers_and_locs[p]
 
-    for p, (v, loc) in vers_and_locs.iteritems():
-        info = str(p) + ": " + str(v)
-        if show_paths:
-            info = info + " (%s)" % str(loc)
-        res.append(info)
+    for p, (v, loc) in _vers_and_locs.iteritems():
+        if p not in first:
+            info = str(p) + ": " + str(v)
+            if show_paths:
+                info = info + " (%s)" % str(loc)
+            res.append(info)
+
     return ', '.join(res)
diff -rN -u old-ticket1329/src/allmydata/_auto_deps.py new-ticket1329/src/allmydata/_auto_deps.py
--- old-ticket1329/src/allmydata/_auto_deps.py	2011-01-17 23:54:16.000000000 -0700
+++ new-ticket1329/src/allmydata/_auto_deps.py	2011-01-17 23:54:16.000000000 -0700
@@ -1,9 +1,10 @@
 # Note: do not import any module from Tahoe-LAFS itself in this
 # file. Also please avoid importing modules from other packages than
-# the Python Standard Library if at all possible (exception: we rely
-# on importing pkg_resources, which is provided by setuptools,
-# zetuptoolz, distribute, and perhaps in the future distutils2, for
-# the require_auto_deps() function.)
+# the Python Standard Library if at all possible. That includes
+# setuptools and pkg_resources.
+
+# If you add or remove dependencies, please remember to update
+# get_package_versions_and_locations() below.
 
 install_requires=[
                   # we require newer versions of setuptools (actually
@@ -27,7 +28,7 @@
 
                   # Needed for SFTP. pyasn1 is needed by twisted.conch in Twisted >= 9.0.
                   # pycrypto 2.2 doesn't work due to https://bugs.launchpad.net/pycrypto/+bug/620253
-                  "pycrypto == 2.0.1, == 2.1, >= 2.3",
+                  "pycrypto >= 2.3",
                   "pyasn1 >= 0.0.8a",
 
                   # Will be needed to test web apps, but not yet. See #1001.
@@ -74,49 +75,105 @@
     install_requires=[]
 del sys # clean up namespace
 
-def require_python_version():
-    import sys, platform
 
-    # we require 2.4.4 on non-UCS-2, non-Redhat builds to avoid <http://www.python.org/news/security/PSF-2006-001/>
-    # we require 2.4.3 on non-UCS-2 Redhat, because 2.4.3 is common on Redhat-based distros and will have patched the above bug
-    # we require at least 2.4.2 in any case to avoid a bug in the base64 module: <http://bugs.python.org/issue1171487>
-    if sys.maxunicode == 65535:
-        if sys.version_info < (2, 4, 2) or sys.version_info[0] > 2:
-            raise NotImplementedError("Tahoe-LAFS current requires Python v2.4.2 or greater "
-                                      "for a UCS-2 build (but less than v3), not %r" %
-                                      (sys.version_info,))
-    elif platform.platform().lower().find('redhat') >= 0:
-        if sys.version_info < (2, 4, 3) or sys.version_info[0] > 2:
-            raise NotImplementedError("Tahoe-LAFS current requires Python v2.4.3 or greater "
-                                      "on Redhat-based distributions (but less than v3), not %r" %
-                                      (sys.version_info,))
+def get_package_versions_and_locations():
+    import warnings, os, sys
+    def package_dir(srcfile):
+        return os.path.dirname(os.path.dirname(os.path.normcase(os.path.realpath(srcfile))))
+
+    # pkg_resources.require returns the distribution that pkg_resources attempted to put
+    # on sys.path, which can differ from the one that we actually import due to #1258,
+    # or any other bug that causes sys.path to be set up incorrectly. Therefore we
+    # must import the packages in order to check their versions and paths. Note that
+    # this needs to be updated if dependencies are added or removed.
+
+    # This warning is generated by twisted, PyRex, and possibly other packages,
+    # but can happen at any time, not only when they are imported. See
+    # http://tahoe-lafs.org/trac/tahoe-lafs/ticket/1129 .
+    warnings.filterwarnings("ignore", category=DeprecationWarning,
+        message="BaseException.message has been deprecated as of Python 2.6",
+        append=True)
+
+    # This is to suppress DeprecationWarnings from nevow, twisted, and pycrypto.
+    # See http://allmydata.org/trac/tahoe/ticket/859 and
+    # http://divmod.org/trac/ticket/2994 .
+    warnings.filterwarnings("ignore", category=DeprecationWarning,
+        message="the sha module is deprecated; use the hashlib module instead",
+        append=True)
+    warnings.filterwarnings("ignore", category=DeprecationWarning,
+        message="object.__new__\(\) takes no parameters",
+        append=True)
+    warnings.filterwarnings("ignore", category=DeprecationWarning,
+        message="The popen2 module is deprecated.  Use the subprocess module.",
+        append=True)
+    warnings.filterwarnings("ignore", category=DeprecationWarning,
+        message="the md5 module is deprecated; use hashlib instead",
+        append=True)
+    warnings.filterwarnings("ignore", category=DeprecationWarning,
+        message="twisted.web.error.NoResource is deprecated since Twisted 9.0.  See twisted.web.resource.NoResource.",
+        append=True)
+    warnings.filterwarnings("ignore", category=DeprecationWarning,
+        message="the sets module is deprecated",
+        append=True)
+    try:
+        import nevow
+        from twisted.persisted import sob
+        from twisted.python import filepath
+        import Crypto
+        import foolscap.api
+        [sob, filepath]  # hush pyflakes
+    finally:
+        for n in range(6):
+            warnings.filters.pop()
+
+    import OpenSSL, allmydata, platform, pycryptopp, simplejson, twisted, zfec, zope.interface, pyasn1, mock
+    pysqlitever = None
+    pysqlitefile = None
+    sqlitever = None
+    try:
+        import sqlite3
+    except ImportError:
+        try:
+            from pysqlite2 import dbapi2
+        except ImportError:
+            pass
+        else:
+            pysqlitever = dbapi2.version
+            pysqlitefile = package_dir(dbapi2.__file__)
+            sqlitever = dbapi2.sqlite_version
     else:
-        if sys.version_info < (2, 4, 4) or sys.version_info[0] > 2:
-            raise NotImplementedError("Tahoe-LAFS current requires Python v2.4.4 or greater "
-                                      "for a non-UCS-2 build (but less than v3), not %r" %
-                                      (sys.version_info,))
-
-def require_auto_deps():
-    """
-    The purpose of this function is to raise a pkg_resources exception if any of the
-    requirements can't be imported.  This is just to give earlier and more explicit error
-    messages, as opposed to waiting until the source code tries to import some module from one
-    of these packages and gets an ImportError.  This function gets called from
-    src/allmydata/__init__.py .
-    """
-    require_python_version()
+        pysqlitever = sqlite3.version
+        pysqlitefile = package_dir(sqlite3.__file__)
+        sqlitever = sqlite3.sqlite_version
+
+    packages = {
+        'pyopenssl': (OpenSSL.__version__, package_dir(OpenSSL.__file__)),
+        allmydata.__appname__: (allmydata.__version__, package_dir(allmydata.__file__)),
+        'foolscap': (foolscap.api.__version__, package_dir(foolscap.__file__)),
+        'Nevow': (nevow.__version__, package_dir(nevow.__file__)),
+        'pycryptopp': (pycryptopp.__version__, package_dir(pycryptopp.__file__)),
+        'simplejson': (simplejson.__version__, package_dir(simplejson.__file__)),
+        'pysqlite': (pysqlitever, pysqlitefile),
+        'sqlite': (sqlitever, 'unknown'),
+        'zope.interface': ('unknown', package_dir(zope.interface.__file__)),
+        'Twisted': (twisted.__version__, package_dir(twisted.__file__)),
+        'zfec': (zfec.__version__, package_dir(zfec.__file__)),
+        'pycrypto': (Crypto.__version__, package_dir(Crypto.__file__)),
+        'pyasn1': ('unknown', package_dir(pyasn1.__file__)),
+        'mock': (mock.__version__, package_dir(mock.__file__)),
+        'python': (platform.python_version(), sys.executable),
+        }
 
-    import pkg_resources
-    for requirement in install_requires:
+    if sys.platform == 'win32':
         try:
-            pkg_resources.require(requirement)
-        except pkg_resources.DistributionNotFound:
-            # there is no .egg-info present for this requirement, which
-            # either means that it isn't installed, or it is installed in a
-            # way that pkg_resources can't find it (but regular python
-            # might).  There are several older Linux distributions which
-            # provide our dependencies just fine, but they don't ship
-            # .egg-info files. Note that if there *is* an .egg-info file,
-            # but it shows a too-old version, then we'll get a
-            # VersionConflict error instead of DistributionNotFound.
+            import win32api
+            packages['pywin32'] = ('unknown', package_dir(win32api.__file__))
+        except ImportError:
             pass
+
+    if not hasattr(sys, 'frozen'):
+        # Don't try to get the setuptools version if using bbfreeze, py2exe etc. See #585.
+        import setuptools
+        packages['setuptools'] = (setuptools.__version__, package_dir(setuptools.__file__))
+
+    return packages
diff -rN -u old-ticket1329/src/allmydata/test/test_runner.py new-ticket1329/src/allmydata/test/test_runner.py
--- old-ticket1329/src/allmydata/test/test_runner.py	2011-01-17 23:54:16.000000000 -0700
+++ new-ticket1329/src/allmydata/test/test_runner.py	2011-01-17 23:54:16.000000000 -0700
@@ -3,7 +3,7 @@
 
 from twisted.python import usage, runtime
 from twisted.internet import utils
-import os.path, re, sys
+import os.path, re, sys, subprocess
 from cStringIO import StringIO
 from allmydata.util import fileutil, pollmixin
 from allmydata.util.encodingutil import unicode_to_argv, unicode_to_output, get_filesystem_encoding
@@ -14,24 +14,36 @@
 
 timeout = 240
 
+def get_root_from_file(src):
+    srcdir = os.path.dirname(os.path.dirname(os.path.normcase(os.path.realpath(src))))
+
+    root = os.path.dirname(srcdir)
+    if os.path.basename(srcdir) == 'site-packages':
+        if re.search(r'python.+\..+', os.path.basename(root)):
+            root = os.path.dirname(root)
+        root = os.path.dirname(root)
+    elif os.path.basename(root) == 'src':
+        root = os.path.dirname(root)
+
+    return root
+
 srcfile = allmydata.__file__
-srcdir = os.path.dirname(os.path.dirname(os.path.normcase(os.path.realpath(srcfile))))
+rootdir = get_root_from_file(srcfile)
 
-rootdir = os.path.dirname(srcdir)
-if os.path.basename(srcdir) == 'site-packages':
-    if re.search(r'python.+\..+', os.path.basename(rootdir)):
-        rootdir = os.path.dirname(rootdir)
-    rootdir = os.path.dirname(rootdir)
-elif os.path.basename(rootdir) == 'src':
-    rootdir = os.path.dirname(rootdir)
-
-bintahoe = os.path.join(rootdir, 'bin', 'tahoe')
-if sys.platform == "win32":
-    bintahoe += ".pyscript"
-    if not os.path.exists(bintahoe):
-       alt_bintahoe = os.path.join(rootdir, 'Scripts', 'tahoe.pyscript')
-       if os.path.exists(alt_bintahoe):
-           bintahoe = alt_bintahoe
+
+if hasattr(sys, 'frozen'):
+    bintahoe = os.path.join(rootdir, 'tahoe')
+
+    if sys.platform == "win32" and os.path.exists(bintahoe + '.exe'):
+        bintahoe += '.exe'
+else:
+    bintahoe = os.path.join(rootdir, 'bin', 'tahoe')
+    if sys.platform == "win32":
+        bintahoe += '.pyscript'
+        if not os.path.exists(bintahoe):
+            alt_bintahoe = os.path.join(rootdir, 'Scripts', 'tahoe.pyscript')
+            if os.path.exists(alt_bintahoe):
+                bintahoe = alt_bintahoe
 
 
 class SkipMixin:
@@ -49,16 +61,20 @@
 
 
 class BinTahoe(common_util.SignalMixin, unittest.TestCase, SkipMixin):
-    def test_the_right_code(self):
+    def _check_right_code(self, file_to_check):
+        root_to_check = get_root_from_file(file_to_check)
+        if os.path.basename(root_to_check) == 'dist':
+            root_to_check = os.path.dirname(root_to_check)
+
         cwd = os.path.normcase(os.path.realpath("."))
         root_from_cwd = os.path.dirname(cwd)
         if os.path.basename(root_from_cwd) == 'src':
             root_from_cwd = os.path.dirname(root_from_cwd)
 
-        same = (root_from_cwd == rootdir)
+        same = (root_from_cwd == root_to_check)
         if not same:
             try:
-                same = os.path.samefile(root_from_cwd, rootdir)
+                same = os.path.samefile(root_from_cwd, root_to_check)
             except AttributeError, e:
                 e  # hush pyflakes
 
@@ -66,9 +82,9 @@
             msg = ("We seem to be testing the code at %r,\n"
                    "(according to the source filename %r),\n"
                    "but expected to be testing the code at %r.\n"
-                   % (rootdir, srcfile, root_from_cwd))
+                   % (root_to_check, file_to_check, root_from_cwd))
 
-            root_from_cwdu = os.path.normcase(os.path.normpath(os.getcwdu()))
+            root_from_cwdu = os.path.dirname(os.path.normcase(os.path.normpath(os.getcwdu())))
             if os.path.basename(root_from_cwdu) == u'src':
                 root_from_cwdu = os.path.dirname(root_from_cwdu)
 
@@ -81,6 +97,24 @@
                 msg += "Please run the tests from the root of the Tahoe-LAFS distribution."
                 self.fail(msg)
 
+    def test_the_right_code(self):
+        self._check_right_code(srcfile)
+
+    def test_import_in_repl(self):
+        self.skip_if_cannot_run_bintahoe()
+
+        args = [bintahoe, "debug", "repl"]
+        if not hasattr(sys, 'frozen'):
+            args = [sys.executable] + args
+
+        p = subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+        (out, err) = p.communicate("import allmydata; print allmydata.__file__")
+
+        self.failUnlessEqual(p.returncode, 0)
+        first = out.splitlines()[0]
+        self.failUnless(first.startswith('>>> '))
+        self._check_right_code(first[4:])
+
     def test_path(self):
         self.skip_if_cannot_run_bintahoe()
         d = utils.getProcessOutputAndValue(bintahoe, args=["--version-and-path"], env=os.environ)
@@ -112,6 +146,7 @@
                 else:
                     altverstr = verstr
 
+            srcdir = os.path.dirname(os.path.dirname(os.path.normcase(os.path.realpath(srcfile))))
             required_ver_and_path = "%s: %s (%s)" % (allmydata.__appname__, verstr, srcdir)
             alt_required_ver_and_path = "%s: %s (%s)" % (allmydata.__appname__, altverstr, srcdir)
 
@@ -121,6 +156,8 @@
 
     def test_unicode_arguments_and_output(self):
         self.skip_if_cannot_run_bintahoe()
+        if hasattr(sys, 'frozen') and sys.platform == "win32":
+            raise unittest.SkipTest("This test can't currently be made to work for frozen executables on Windows,\ndue to lack of support for Unicode in twisted.internet.utils.getProcessOutputAndValue.")
 
         tricky = u"\u2621"
         try:
@@ -139,6 +176,8 @@
 
     def test_run_with_python_options(self):
         self.skip_if_cannot_run_bintahoe()
+        if hasattr(sys, 'frozen'):
+            raise unittest.SkipTest("This test doesn't apply to frozen executables.")
 
         # -t is a harmless option that warns about tabs.
         d = utils.getProcessOutputAndValue(sys.executable, args=['-t', bintahoe, '--version'],
diff -rN -u old-ticket1329/src/allmydata/test/test_system.py new-ticket1329/src/allmydata/test/test_system.py
--- old-ticket1329/src/allmydata/test/test_system.py	2011-01-17 23:54:16.000000000 -0700
+++ new-ticket1329/src/allmydata/test/test_system.py	2011-01-17 23:54:16.000000000 -0700
@@ -1769,8 +1769,7 @@
 
         if env is None:
             env = os.environ
-        d = utils.getProcessOutputAndValue(sys.executable, args=[bintahoe] + argv,
-                                           env=env)
+        d = utils.getProcessOutputAndValue(bintahoe, argv, env=env)
         return d
 
     def _test_checker(self, res):
Replying to [warner](/tahoe-lafs/trac/issues/1329#issuecomment-383286): > my main problem with [20110116200112-93fa1-0397f85493a9fd0ae82ce58d7291d598a4f6e2d6]/ticket1306 is that it involved what looked like a signficant refactoring of `_auto_deps.py`, so I couldn't apply just a single patch (there were more like six). But if there's a clean way to use that approach, I'm happy to go with it. For the record, here are the patches that (from darcs's perspective) are required for [20110116200112-93fa1-0397f85493a9fd0ae82ce58d7291d598a4f6e2d6]/ticket1306: ``` HACL Zooko-Ofsimplegeos-MacBook-Pro:~/playground/tahoe-lafs/ticket1329$ time darcs push zooko@dev.allmydata.org:/home/darcs/tahoe-lafs/trunk Pushing to "zooko@dev.allmydata.org:/home/darcs/tahoe-lafs/trunk"... The remote repository has 2 patches to pull. Sat Jan 1 04:01:41 MST 2011 david-sarah@jacaranda.org * allmydata/__init__.py: don't use pkg_resources.require to get versions and paths. Also change pyOpenSSL to pyopenssl since that is the package name. fixes #1287 Shall I push this patch? (1/7) [ynWsfvplxdaqjk], or ? for help: w Sat Jan 1 13:05:02 MST 2011 david-sarah@jacaranda.org * allmydata/_auto_deps.py: add a comment reminding to change __init__.py when dependencies are added or removed. Clarify a comment in __init__.py. refs #1287 Shall I push this patch? (2/7) [ynWvplxdaqjk], or ? for help: w Sat Jan 1 12:25:59 MST 2011 david-sarah@jacaranda.org * test_runner: add test_import_in_repl, which uses 'bin/tahoe debug repl' to import the allmydata module and checks that it comes from the right path. Also, fix a latent bug that caused test_the_right_code to incorrectly conclude that a path mismatch was due to a Unicode path (causing a skip rather than a failure). This version of the patch avoids a confusing shadowing of 'srcfile'. refs #1258 Shall I push this patch? (3/7) [ynWsfvplxdaqjk], or ? for help: w Wed Jan 12 21:24:57 MST 2011 david-sarah@jacaranda.org * Make bb-freeze work. This also implements more robust checking of dependency requirements, as discussed in ticket:585#comment:10 . refs #585 Shall I push this patch? (4/7) [ynWvplxdaqjk], or ? for help: w Wed Jan 12 21:30:40 MST 2011 david-sarah@jacaranda.org * Move get_package_versions_and_locations from __init__.py to _auto_deps.py (because it needs to be updated when dependencies change). refs #585 Shall I push this patch? (5/7) [ynWvplxdaqjk], or ? for help: w Fri Jan 14 22:02:45 MST 2011 david-sarah@jacaranda.org * Add mock to get_package_versions_and_locations. Shall I push this patch? (6/7) [ynWsfvplxdaqjk], or ? for help: w Sun Jan 16 13:01:12 MST 2011 david-sarah@jacaranda.org * src/allmydata/_auto_deps.py: Fix 'DeprecationWarning: the sets module is deprecated'. refs #1329 Shall I push this patch? (7/7) [ynWsfvplxdaqjk], or ? for help: w ``` And below and attached is the unified diff of all seven of them coalesced. I propose that we start by applying the first one -- see #1258. ``` diff -rN -u old-ticket1329/Makefile new-ticket1329/Makefile --- old-ticket1329/Makefile 2011-01-17 23:54:16.000000000 -0700 +++ new-ticket1329/Makefile 2011-01-17 23:54:16.000000000 -0700 @@ -179,7 +179,7 @@ pyflakes: - $(PYTHON) -OOu `which pyflakes` src/allmydata |sort |uniq + $(PYTHON) -OOu `which pyflakes` src/allmydata static |sort |uniq check-umids: $(PYTHON) misc/coding_tools/check-umids.py `find src/allmydata -name '*.py'` diff -rN -u old-ticket1329/src/allmydata/__init__.py new-ticket1329/src/allmydata/__init__.py --- old-ticket1329/src/allmydata/__init__.py 2011-01-17 23:54:16.000000000 -0700 +++ new-ticket1329/src/allmydata/__init__.py 2011-01-17 23:54:16.000000000 -0700 @@ -4,57 +4,6 @@ community web site: U{http://tahoe-lafs.org/} """ -# We want to call require_auto_deps() before other imports, because the setuptools -# docs claim that if a distribution is installed with --multi-version, it might not -# be importable until after pkg_resources.require() has been called for it. We don't -# have an example of this happening at this time. It is possible that require() isn't -# actually needed because we set __requires__ in the generated startup script, but -# that would be an undocumented property of the setuptools implementation. - -from allmydata import _auto_deps -_auto_deps.require_auto_deps() - -# This is just to suppress DeprecationWarnings from nevow and twisted. -# See http://allmydata.org/trac/tahoe/ticket/859 and -# http://divmod.org/trac/ticket/2994 . -import warnings -warnings.filterwarnings("ignore", category=DeprecationWarning, - message="the sha module is deprecated; use the hashlib module instead", - append=True) -warnings.filterwarnings("ignore", category=DeprecationWarning, - message="object.__new__\(\) takes no parameters", - append=True) -warnings.filterwarnings("ignore", category=DeprecationWarning, - message="The popen2 module is deprecated. Use the subprocess module.", - append=True) -warnings.filterwarnings("ignore", category=DeprecationWarning, - message="the md5 module is deprecated; use hashlib instead", - append=True) -warnings.filterwarnings("ignore", category=DeprecationWarning, - message="twisted.web.error.NoResource is deprecated since Twisted 9.0. See twisted.web.resource.NoResource.", - append=True) -try: - import nevow - from twisted.persisted import sob - from twisted.python import filepath - hush_pyflakes = (nevow, sob, filepath) - del hush_pyflakes -finally: - warnings.filters.pop() - warnings.filters.pop() - warnings.filters.pop() - warnings.filters.pop() - # Don't pop the filter for the sha module warning because it is also generated - # by pycrypto (which we don't want to import unless needed). - # warnings.filters.pop() - -# This warning is generated by twisted, PyRex, and possibly other packages, -# but can happen at any time, not only when they are imported. See -# http://tahoe-lafs.org/trac/tahoe-lafs/ticket/1129 . -warnings.filterwarnings("ignore", category=DeprecationWarning, - message="BaseException.message has been deprecated as of Python 2.6", - append=True) - __version__ = "unknown" try: from allmydata._version import __version__ @@ -175,88 +124,93 @@ else: return platform.platform() -def get_package_versions_from_setuptools(): - import pkg_resources - return dict([(p.project_name, (p.version, p.location)) for p in pkg_resources.require(__appname__)]) - -def package_dir(srcfile): - return os.path.dirname(os.path.dirname(os.path.normcase(os.path.realpath(srcfile)))) - -def get_package_versions_and_locations(): - # because there are a few dependencies that are outside setuptools's ken - # (Python and platform, and sqlite3 if you are on Python >= 2.5), and - # because setuptools might fail to find something even though import - # finds it: - import OpenSSL, allmydata, foolscap.api, nevow, platform, pycryptopp, setuptools, simplejson, twisted, zfec, zope.interface - pysqlitever = None - pysqlitefile = None - sqlitever = None - try: - import sqlite3 - except ImportError: - try: - from pysqlite2 import dbapi2 - except ImportError: - pass - else: - pysqlitever = dbapi2.version - pysqlitefile = package_dir(dbapi2.__file__) - sqlitever = dbapi2.sqlite_version - else: - pysqlitever = sqlite3.version - pysqlitefile = package_dir(sqlite3.__file__) - sqlitever = sqlite3.sqlite_version - - d1 = { - 'pyOpenSSL': (OpenSSL.__version__, package_dir(OpenSSL.__file__)), - __appname__: (allmydata.__version__, package_dir(allmydata.__file__)), - 'foolscap': (foolscap.api.__version__, package_dir(foolscap.__file__)), - 'Nevow': (nevow.__version__, package_dir(nevow.__file__)), - 'pycryptopp': (pycryptopp.__version__, package_dir(pycryptopp.__file__)), - 'setuptools': (setuptools.__version__, package_dir(setuptools.__file__)), - 'simplejson': (simplejson.__version__, package_dir(simplejson.__file__)), - 'pysqlite': (pysqlitever, pysqlitefile), - 'sqlite': (sqlitever, 'unknown'), - 'zope.interface': ('unknown', package_dir(zope.interface.__file__)), - 'Twisted': (twisted.__version__, package_dir(twisted.__file__)), - 'zfec': (zfec.__version__, package_dir(zfec.__file__)), - 'python': (platform.python_version(), sys.executable), - 'platform': (get_platform(), None), - } - # But we prefer to get all the dependencies as known by setuptools: - import pkg_resources - try: - d2 = get_package_versions_from_setuptools() - except pkg_resources.DistributionNotFound: - # See docstring in _auto_deps.require_auto_deps() to explain why it makes sense to ignore this exception. - pass +from allmydata._auto_deps import get_package_versions_and_locations + +_vers_and_locs = get_package_versions_and_locations() +_vers_and_locs['platform'] = (get_platform(), None) + + +def check_all_requirements(): + import platform + from distutils.version import LooseVersion + from allmydata._auto_deps import install_requires + + # we require 2.4.4 on non-UCS-2, non-Redhat builds to avoid <http://www.python.org/news/security/PSF-2006-001/> + # we require 2.4.3 on non-UCS-2 Redhat, because 2.4.3 is common on Redhat-based distros and will have patched the above bug + # we require at least 2.4.2 in any case to avoid a bug in the base64 module: <http://bugs.python.org/issue1171487> + if sys.maxunicode == 65535: + if sys.version_info < (2, 4, 2) or sys.version_info[0] > 2: + raise NotImplementedError("Tahoe-LAFS current requires Python v2.4.2 or greater " + "for a UCS-2 build (but less than v3), not %r" % + (sys.version_info,)) + elif platform.platform().lower().find('redhat') >= 0: + if sys.version_info < (2, 4, 3) or sys.version_info[0] > 2: + raise NotImplementedError("Tahoe-LAFS current requires Python v2.4.3 or greater " + "on Redhat-based distributions (but less than v3), not %r" % + (sys.version_info,)) else: - d1.update(d2) + if sys.version_info < (2, 4, 4) or sys.version_info[0] > 2: + raise NotImplementedError("Tahoe-LAFS current requires Python v2.4.4 or greater " + "for a non-UCS-2 build (but less than v3), not %r" % + (sys.version_info,)) + + def check_requirement(req): + # We only support a single >= or ==. + def _check(s, ok, relation): + name = s[0].strip(' ').partition('[')[0] + required = s[1].strip(' ') + if name not in _vers_and_locs: + raise AssertionError("no version info for %s" % (name,)) + (actual, location) = _vers_and_locs[name] + actual = str(actual) + if actual != 'unknown' and not ok(LooseVersion(actual), LooseVersion(required)): + msg = ("We require %s version %s of %s, but could only find version %s.\n" + % (relation, required, name, actual)) + if location and location != 'unknown': + msg += "The version we found is from %r.\n" % (location,) + msg += ("To resolve this problem, uninstall that version, either using your\n" + "operating system's package manager or by moving aside the directory.") + raise AssertionError(msg) + + s = req.split('>=') + if len(s) == 2: + _check(s, lambda x, y: x >= y, "at least") + return + s = req.split('==') + if len(s) == 2: + _check(s, lambda x, y: x == y, "exactly") + return + if req not in _vers_and_locs: + raise AssertionError("no version info or could not understand requirement for %r" % (req)) + + for requirement in install_requires: + check_requirement(requirement) + +check_all_requirements() - return d1 def get_package_versions(): - return dict([(k, v) for k, (v, l) in get_package_versions_and_locations().iteritems()]) + return dict([(k, v) for k, (v, l) in _vers_and_locs.iteritems()]) def get_package_locations(): - return dict([(k, l) for k, (v, l) in get_package_versions_and_locations().iteritems()]) + return dict([(k, l) for k, (v, l) in _vers_and_locs.iteritems()]) def get_package_versions_string(show_paths=False): - vers_and_locs = get_package_versions_and_locations() res = [] - for p in [__appname__, "foolscap", "pycryptopp", "zfec", "Twisted", "Nevow", "zope.interface", "python", "platform"]: - (ver, loc) = vers_and_locs.get(p, ('UNKNOWN', 'UNKNOWN')) + first = [__appname__, "foolscap", "pycryptopp", "zfec", "Twisted", "Nevow", "zope.interface", "python", "platform"] + for p in first: + (ver, loc) = _vers_and_locs.get(p, ('UNKNOWN', 'UNKNOWN')) info = str(p) + ": " + str(ver) if show_paths: info = info + " (%s)" % str(loc) res.append(info) - if vers_and_locs.has_key(p): - del vers_and_locs[p] - for p, (v, loc) in vers_and_locs.iteritems(): - info = str(p) + ": " + str(v) - if show_paths: - info = info + " (%s)" % str(loc) - res.append(info) + for p, (v, loc) in _vers_and_locs.iteritems(): + if p not in first: + info = str(p) + ": " + str(v) + if show_paths: + info = info + " (%s)" % str(loc) + res.append(info) + return ', '.join(res) diff -rN -u old-ticket1329/src/allmydata/_auto_deps.py new-ticket1329/src/allmydata/_auto_deps.py --- old-ticket1329/src/allmydata/_auto_deps.py 2011-01-17 23:54:16.000000000 -0700 +++ new-ticket1329/src/allmydata/_auto_deps.py 2011-01-17 23:54:16.000000000 -0700 @@ -1,9 +1,10 @@ # Note: do not import any module from Tahoe-LAFS itself in this # file. Also please avoid importing modules from other packages than -# the Python Standard Library if at all possible (exception: we rely -# on importing pkg_resources, which is provided by setuptools, -# zetuptoolz, distribute, and perhaps in the future distutils2, for -# the require_auto_deps() function.) +# the Python Standard Library if at all possible. That includes +# setuptools and pkg_resources. + +# If you add or remove dependencies, please remember to update +# get_package_versions_and_locations() below. install_requires=[ # we require newer versions of setuptools (actually @@ -27,7 +28,7 @@ # Needed for SFTP. pyasn1 is needed by twisted.conch in Twisted >= 9.0. # pycrypto 2.2 doesn't work due to https://bugs.launchpad.net/pycrypto/+bug/620253 - "pycrypto == 2.0.1, == 2.1, >= 2.3", + "pycrypto >= 2.3", "pyasn1 >= 0.0.8a", # Will be needed to test web apps, but not yet. See #1001. @@ -74,49 +75,105 @@ install_requires=[] del sys # clean up namespace -def require_python_version(): - import sys, platform - # we require 2.4.4 on non-UCS-2, non-Redhat builds to avoid <http://www.python.org/news/security/PSF-2006-001/> - # we require 2.4.3 on non-UCS-2 Redhat, because 2.4.3 is common on Redhat-based distros and will have patched the above bug - # we require at least 2.4.2 in any case to avoid a bug in the base64 module: <http://bugs.python.org/issue1171487> - if sys.maxunicode == 65535: - if sys.version_info < (2, 4, 2) or sys.version_info[0] > 2: - raise NotImplementedError("Tahoe-LAFS current requires Python v2.4.2 or greater " - "for a UCS-2 build (but less than v3), not %r" % - (sys.version_info,)) - elif platform.platform().lower().find('redhat') >= 0: - if sys.version_info < (2, 4, 3) or sys.version_info[0] > 2: - raise NotImplementedError("Tahoe-LAFS current requires Python v2.4.3 or greater " - "on Redhat-based distributions (but less than v3), not %r" % - (sys.version_info,)) +def get_package_versions_and_locations(): + import warnings, os, sys + def package_dir(srcfile): + return os.path.dirname(os.path.dirname(os.path.normcase(os.path.realpath(srcfile)))) + + # pkg_resources.require returns the distribution that pkg_resources attempted to put + # on sys.path, which can differ from the one that we actually import due to #1258, + # or any other bug that causes sys.path to be set up incorrectly. Therefore we + # must import the packages in order to check their versions and paths. Note that + # this needs to be updated if dependencies are added or removed. + + # This warning is generated by twisted, PyRex, and possibly other packages, + # but can happen at any time, not only when they are imported. See + # http://tahoe-lafs.org/trac/tahoe-lafs/ticket/1129 . + warnings.filterwarnings("ignore", category=DeprecationWarning, + message="BaseException.message has been deprecated as of Python 2.6", + append=True) + + # This is to suppress DeprecationWarnings from nevow, twisted, and pycrypto. + # See http://allmydata.org/trac/tahoe/ticket/859 and + # http://divmod.org/trac/ticket/2994 . + warnings.filterwarnings("ignore", category=DeprecationWarning, + message="the sha module is deprecated; use the hashlib module instead", + append=True) + warnings.filterwarnings("ignore", category=DeprecationWarning, + message="object.__new__\(\) takes no parameters", + append=True) + warnings.filterwarnings("ignore", category=DeprecationWarning, + message="The popen2 module is deprecated. Use the subprocess module.", + append=True) + warnings.filterwarnings("ignore", category=DeprecationWarning, + message="the md5 module is deprecated; use hashlib instead", + append=True) + warnings.filterwarnings("ignore", category=DeprecationWarning, + message="twisted.web.error.NoResource is deprecated since Twisted 9.0. See twisted.web.resource.NoResource.", + append=True) + warnings.filterwarnings("ignore", category=DeprecationWarning, + message="the sets module is deprecated", + append=True) + try: + import nevow + from twisted.persisted import sob + from twisted.python import filepath + import Crypto + import foolscap.api + [sob, filepath] # hush pyflakes + finally: + for n in range(6): + warnings.filters.pop() + + import OpenSSL, allmydata, platform, pycryptopp, simplejson, twisted, zfec, zope.interface, pyasn1, mock + pysqlitever = None + pysqlitefile = None + sqlitever = None + try: + import sqlite3 + except ImportError: + try: + from pysqlite2 import dbapi2 + except ImportError: + pass + else: + pysqlitever = dbapi2.version + pysqlitefile = package_dir(dbapi2.__file__) + sqlitever = dbapi2.sqlite_version else: - if sys.version_info < (2, 4, 4) or sys.version_info[0] > 2: - raise NotImplementedError("Tahoe-LAFS current requires Python v2.4.4 or greater " - "for a non-UCS-2 build (but less than v3), not %r" % - (sys.version_info,)) - -def require_auto_deps(): - """ - The purpose of this function is to raise a pkg_resources exception if any of the - requirements can't be imported. This is just to give earlier and more explicit error - messages, as opposed to waiting until the source code tries to import some module from one - of these packages and gets an ImportError. This function gets called from - src/allmydata/__init__.py . - """ - require_python_version() + pysqlitever = sqlite3.version + pysqlitefile = package_dir(sqlite3.__file__) + sqlitever = sqlite3.sqlite_version + + packages = { + 'pyopenssl': (OpenSSL.__version__, package_dir(OpenSSL.__file__)), + allmydata.__appname__: (allmydata.__version__, package_dir(allmydata.__file__)), + 'foolscap': (foolscap.api.__version__, package_dir(foolscap.__file__)), + 'Nevow': (nevow.__version__, package_dir(nevow.__file__)), + 'pycryptopp': (pycryptopp.__version__, package_dir(pycryptopp.__file__)), + 'simplejson': (simplejson.__version__, package_dir(simplejson.__file__)), + 'pysqlite': (pysqlitever, pysqlitefile), + 'sqlite': (sqlitever, 'unknown'), + 'zope.interface': ('unknown', package_dir(zope.interface.__file__)), + 'Twisted': (twisted.__version__, package_dir(twisted.__file__)), + 'zfec': (zfec.__version__, package_dir(zfec.__file__)), + 'pycrypto': (Crypto.__version__, package_dir(Crypto.__file__)), + 'pyasn1': ('unknown', package_dir(pyasn1.__file__)), + 'mock': (mock.__version__, package_dir(mock.__file__)), + 'python': (platform.python_version(), sys.executable), + } - import pkg_resources - for requirement in install_requires: + if sys.platform == 'win32': try: - pkg_resources.require(requirement) - except pkg_resources.DistributionNotFound: - # there is no .egg-info present for this requirement, which - # either means that it isn't installed, or it is installed in a - # way that pkg_resources can't find it (but regular python - # might). There are several older Linux distributions which - # provide our dependencies just fine, but they don't ship - # .egg-info files. Note that if there *is* an .egg-info file, - # but it shows a too-old version, then we'll get a - # VersionConflict error instead of DistributionNotFound. + import win32api + packages['pywin32'] = ('unknown', package_dir(win32api.__file__)) + except ImportError: pass + + if not hasattr(sys, 'frozen'): + # Don't try to get the setuptools version if using bbfreeze, py2exe etc. See #585. + import setuptools + packages['setuptools'] = (setuptools.__version__, package_dir(setuptools.__file__)) + + return packages diff -rN -u old-ticket1329/src/allmydata/test/test_runner.py new-ticket1329/src/allmydata/test/test_runner.py --- old-ticket1329/src/allmydata/test/test_runner.py 2011-01-17 23:54:16.000000000 -0700 +++ new-ticket1329/src/allmydata/test/test_runner.py 2011-01-17 23:54:16.000000000 -0700 @@ -3,7 +3,7 @@ from twisted.python import usage, runtime from twisted.internet import utils -import os.path, re, sys +import os.path, re, sys, subprocess from cStringIO import StringIO from allmydata.util import fileutil, pollmixin from allmydata.util.encodingutil import unicode_to_argv, unicode_to_output, get_filesystem_encoding @@ -14,24 +14,36 @@ timeout = 240 +def get_root_from_file(src): + srcdir = os.path.dirname(os.path.dirname(os.path.normcase(os.path.realpath(src)))) + + root = os.path.dirname(srcdir) + if os.path.basename(srcdir) == 'site-packages': + if re.search(r'python.+\..+', os.path.basename(root)): + root = os.path.dirname(root) + root = os.path.dirname(root) + elif os.path.basename(root) == 'src': + root = os.path.dirname(root) + + return root + srcfile = allmydata.__file__ -srcdir = os.path.dirname(os.path.dirname(os.path.normcase(os.path.realpath(srcfile)))) +rootdir = get_root_from_file(srcfile) -rootdir = os.path.dirname(srcdir) -if os.path.basename(srcdir) == 'site-packages': - if re.search(r'python.+\..+', os.path.basename(rootdir)): - rootdir = os.path.dirname(rootdir) - rootdir = os.path.dirname(rootdir) -elif os.path.basename(rootdir) == 'src': - rootdir = os.path.dirname(rootdir) - -bintahoe = os.path.join(rootdir, 'bin', 'tahoe') -if sys.platform == "win32": - bintahoe += ".pyscript" - if not os.path.exists(bintahoe): - alt_bintahoe = os.path.join(rootdir, 'Scripts', 'tahoe.pyscript') - if os.path.exists(alt_bintahoe): - bintahoe = alt_bintahoe + +if hasattr(sys, 'frozen'): + bintahoe = os.path.join(rootdir, 'tahoe') + + if sys.platform == "win32" and os.path.exists(bintahoe + '.exe'): + bintahoe += '.exe' +else: + bintahoe = os.path.join(rootdir, 'bin', 'tahoe') + if sys.platform == "win32": + bintahoe += '.pyscript' + if not os.path.exists(bintahoe): + alt_bintahoe = os.path.join(rootdir, 'Scripts', 'tahoe.pyscript') + if os.path.exists(alt_bintahoe): + bintahoe = alt_bintahoe class SkipMixin: @@ -49,16 +61,20 @@ class BinTahoe(common_util.SignalMixin, unittest.TestCase, SkipMixin): - def test_the_right_code(self): + def _check_right_code(self, file_to_check): + root_to_check = get_root_from_file(file_to_check) + if os.path.basename(root_to_check) == 'dist': + root_to_check = os.path.dirname(root_to_check) + cwd = os.path.normcase(os.path.realpath(".")) root_from_cwd = os.path.dirname(cwd) if os.path.basename(root_from_cwd) == 'src': root_from_cwd = os.path.dirname(root_from_cwd) - same = (root_from_cwd == rootdir) + same = (root_from_cwd == root_to_check) if not same: try: - same = os.path.samefile(root_from_cwd, rootdir) + same = os.path.samefile(root_from_cwd, root_to_check) except AttributeError, e: e # hush pyflakes @@ -66,9 +82,9 @@ msg = ("We seem to be testing the code at %r,\n" "(according to the source filename %r),\n" "but expected to be testing the code at %r.\n" - % (rootdir, srcfile, root_from_cwd)) + % (root_to_check, file_to_check, root_from_cwd)) - root_from_cwdu = os.path.normcase(os.path.normpath(os.getcwdu())) + root_from_cwdu = os.path.dirname(os.path.normcase(os.path.normpath(os.getcwdu()))) if os.path.basename(root_from_cwdu) == u'src': root_from_cwdu = os.path.dirname(root_from_cwdu) @@ -81,6 +97,24 @@ msg += "Please run the tests from the root of the Tahoe-LAFS distribution." self.fail(msg) + def test_the_right_code(self): + self._check_right_code(srcfile) + + def test_import_in_repl(self): + self.skip_if_cannot_run_bintahoe() + + args = [bintahoe, "debug", "repl"] + if not hasattr(sys, 'frozen'): + args = [sys.executable] + args + + p = subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + (out, err) = p.communicate("import allmydata; print allmydata.__file__") + + self.failUnlessEqual(p.returncode, 0) + first = out.splitlines()[0] + self.failUnless(first.startswith('>>> ')) + self._check_right_code(first[4:]) + def test_path(self): self.skip_if_cannot_run_bintahoe() d = utils.getProcessOutputAndValue(bintahoe, args=["--version-and-path"], env=os.environ) @@ -112,6 +146,7 @@ else: altverstr = verstr + srcdir = os.path.dirname(os.path.dirname(os.path.normcase(os.path.realpath(srcfile)))) required_ver_and_path = "%s: %s (%s)" % (allmydata.__appname__, verstr, srcdir) alt_required_ver_and_path = "%s: %s (%s)" % (allmydata.__appname__, altverstr, srcdir) @@ -121,6 +156,8 @@ def test_unicode_arguments_and_output(self): self.skip_if_cannot_run_bintahoe() + if hasattr(sys, 'frozen') and sys.platform == "win32": + raise unittest.SkipTest("This test can't currently be made to work for frozen executables on Windows,\ndue to lack of support for Unicode in twisted.internet.utils.getProcessOutputAndValue.") tricky = u"\u2621" try: @@ -139,6 +176,8 @@ def test_run_with_python_options(self): self.skip_if_cannot_run_bintahoe() + if hasattr(sys, 'frozen'): + raise unittest.SkipTest("This test doesn't apply to frozen executables.") # -t is a harmless option that warns about tabs. d = utils.getProcessOutputAndValue(sys.executable, args=['-t', bintahoe, '--version'], diff -rN -u old-ticket1329/src/allmydata/test/test_system.py new-ticket1329/src/allmydata/test/test_system.py --- old-ticket1329/src/allmydata/test/test_system.py 2011-01-17 23:54:16.000000000 -0700 +++ new-ticket1329/src/allmydata/test/test_system.py 2011-01-17 23:54:16.000000000 -0700 @@ -1769,8 +1769,7 @@ if env is None: env = os.environ - d = utils.getProcessOutputAndValue(sys.executable, args=[bintahoe] + argv, - env=env) + d = utils.getProcessOutputAndValue(bintahoe, argv, env=env) return d def _test_checker(self, res): ```

Attachment 1329.diff (26465 bytes) added

**Attachment** 1329.diff (26465 bytes) added
Author

Yes, yes, I know these patches need refactoring! It will be easy to apply the #1329 fix after I've done that; it makes no sense to apply it first (because the relevant code has been moved to a different file).

Yes, yes, I know these patches need refactoring! It will be easy to apply the #1329 fix after I've done that; it makes no sense to apply it first (because the relevant code has been moved to a different file).
Author

In changeset:8d2983c49348e4e7:

Update foolscap requirement to >= 0.6.1. fixes #1329
In changeset:8d2983c49348e4e7: ``` Update foolscap requirement to >= 0.6.1. fixes #1329 ```
daira added the
r/fixed
label 2011-01-19 07:04:37 +00:00
daira closed this issue 2011-01-19 07:04:37 +00:00
Sign in to join this conversation.
No labels
c/code
c/code-dirnodes
c/code-encoding
c/code-frontend
c/code-frontend-cli
c/code-frontend-ftp-sftp
c/code-frontend-magic-folder
c/code-frontend-web
c/code-mutable
c/code-network
c/code-nodeadmin
c/code-peerselection
c/code-storage
c/contrib
c/dev-infrastructure
c/docs
c/operational
c/packaging
c/unknown
c/website
kw:2pc
kw:410
kw:9p
kw:ActivePerl
kw:AttributeError
kw:DataUnavailable
kw:DeadReferenceError
kw:DoS
kw:FileZilla
kw:GetLastError
kw:IFinishableConsumer
kw:K
kw:LeastAuthority
kw:Makefile
kw:RIStorageServer
kw:StringIO
kw:UncoordinatedWriteError
kw:about
kw:access
kw:access-control
kw:accessibility
kw:accounting
kw:accounting-crawler
kw:add-only
kw:aes
kw:aesthetics
kw:alias
kw:aliases
kw:aliens
kw:allmydata
kw:amazon
kw:ambient
kw:annotations
kw:anonymity
kw:anonymous
kw:anti-censorship
kw:api_auth_token
kw:appearance
kw:appname
kw:apport
kw:archive
kw:archlinux
kw:argparse
kw:arm
kw:assertion
kw:attachment
kw:auth
kw:authentication
kw:automation
kw:avahi
kw:availability
kw:aws
kw:azure
kw:backend
kw:backoff
kw:backup
kw:backupdb
kw:backward-compatibility
kw:bandwidth
kw:basedir
kw:bayes
kw:bbfreeze
kw:beta
kw:binaries
kw:binutils
kw:bitcoin
kw:bitrot
kw:blacklist
kw:blocker
kw:blocks-cloud-deployment
kw:blocks-cloud-merge
kw:blocks-magic-folder-merge
kw:blocks-merge
kw:blocks-raic
kw:blocks-release
kw:blog
kw:bom
kw:bonjour
kw:branch
kw:branding
kw:breadcrumbs
kw:brians-opinion-needed
kw:browser
kw:bsd
kw:build
kw:build-helpers
kw:buildbot
kw:builders
kw:buildslave
kw:buildslaves
kw:cache
kw:cap
kw:capleak
kw:captcha
kw:cast
kw:centos
kw:cffi
kw:chacha
kw:charset
kw:check
kw:checker
kw:chroot
kw:ci
kw:clean
kw:cleanup
kw:cli
kw:cloud
kw:cloud-backend
kw:cmdline
kw:code
kw:code-checks
kw:coding-standards
kw:coding-tools
kw:coding_tools
kw:collection
kw:compatibility
kw:completion
kw:compression
kw:confidentiality
kw:config
kw:configuration
kw:configuration.txt
kw:conflict
kw:connection
kw:connectivity
kw:consistency
kw:content
kw:control
kw:control.furl
kw:convergence
kw:coordination
kw:copyright
kw:corruption
kw:cors
kw:cost
kw:coverage
kw:coveralls
kw:coveralls.io
kw:cpu-watcher
kw:cpyext
kw:crash
kw:crawler
kw:crawlers
kw:create-container
kw:cruft
kw:crypto
kw:cryptography
kw:cryptography-lib
kw:cryptopp
kw:csp
kw:curl
kw:cutoff-date
kw:cycle
kw:cygwin
kw:d3
kw:daemon
kw:darcs
kw:darcsver
kw:database
kw:dataloss
kw:db
kw:dead-code
kw:deb
kw:debian
kw:debug
kw:deep-check
kw:defaults
kw:deferred
kw:delete
kw:deletion
kw:denial-of-service
kw:dependency
kw:deployment
kw:deprecation
kw:desert-island
kw:desert-island-build
kw:design
kw:design-review-needed
kw:detection
kw:dev-infrastructure
kw:devpay
kw:directory
kw:directory-page
kw:dirnode
kw:dirnodes
kw:disconnect
kw:discovery
kw:disk
kw:disk-backend
kw:distribute
kw:distutils
kw:dns
kw:do_http
kw:doc-needed
kw:docker
kw:docs
kw:docs-needed
kw:dokan
kw:dos
kw:download
kw:downloader
kw:dragonfly
kw:drop-upload
kw:duplicity
kw:dusty
kw:earth-dragon
kw:easy
kw:ec2
kw:ecdsa
kw:ed25519
kw:egg-needed
kw:eggs
kw:eliot
kw:email
kw:empty
kw:encoding
kw:endpoint
kw:enterprise
kw:enum34
kw:environment
kw:erasure
kw:erasure-coding
kw:error
kw:escaping
kw:etag
kw:etch
kw:evangelism
kw:eventual
kw:example
kw:excess-authority
kw:exec
kw:exocet
kw:expiration
kw:extensibility
kw:extension
kw:failure
kw:fedora
kw:ffp
kw:fhs
kw:figleaf
kw:file
kw:file-descriptor
kw:filename
kw:filesystem
kw:fileutil
kw:fips
kw:firewall
kw:first
kw:floatingpoint
kw:flog
kw:foolscap
kw:forward-compatibility
kw:forward-secrecy
kw:forwarding
kw:free
kw:freebsd
kw:frontend
kw:fsevents
kw:ftp
kw:ftpd
kw:full
kw:furl
kw:fuse
kw:garbage
kw:garbage-collection
kw:gateway
kw:gatherer
kw:gc
kw:gcc
kw:gentoo
kw:get
kw:git
kw:git-annex
kw:github
kw:glacier
kw:globalcaps
kw:glossary
kw:google-cloud-storage
kw:google-drive-backend
kw:gossip
kw:governance
kw:grid
kw:grid-manager
kw:gridid
kw:gridsync
kw:grsec
kw:gsoc
kw:gvfs
kw:hackfest
kw:hacktahoe
kw:hang
kw:hardlink
kw:heartbleed
kw:heisenbug
kw:help
kw:helper
kw:hint
kw:hooks
kw:how
kw:how-to
kw:howto
kw:hp
kw:hp-cloud
kw:html
kw:http
kw:https
kw:i18n
kw:i2p
kw:i2p-collab
kw:illustration
kw:image
kw:immutable
kw:impressions
kw:incentives
kw:incident
kw:init
kw:inlineCallbacks
kw:inotify
kw:install
kw:installer
kw:integration
kw:integration-test
kw:integrity
kw:interactive
kw:interface
kw:interfaces
kw:interoperability
kw:interstellar-exploration
kw:introducer
kw:introduction
kw:iphone
kw:ipkg
kw:iputil
kw:ipv6
kw:irc
kw:jail
kw:javascript
kw:joke
kw:jquery
kw:json
kw:jsui
kw:junk
kw:key-value-store
kw:kfreebsd
kw:known-issue
kw:konqueror
kw:kpreid
kw:kvm
kw:l10n
kw:lae
kw:large
kw:latency
kw:leak
kw:leasedb
kw:leases
kw:libgmp
kw:license
kw:licenss
kw:linecount
kw:link
kw:linux
kw:lit
kw:localhost
kw:location
kw:locking
kw:logging
kw:logo
kw:loopback
kw:lucid
kw:mac
kw:macintosh
kw:magic-folder
kw:manhole
kw:manifest
kw:manual-test-needed
kw:map
kw:mapupdate
kw:max_space
kw:mdmf
kw:memcheck
kw:memory
kw:memory-leak
kw:mesh
kw:metadata
kw:meter
kw:migration
kw:mime
kw:mingw
kw:minimal
kw:misc
kw:miscapture
kw:mlp
kw:mock
kw:more-info-needed
kw:mountain-lion
kw:move
kw:multi-users
kw:multiple
kw:multiuser-gateway
kw:munin
kw:music
kw:mutability
kw:mutable
kw:mystery
kw:names
kw:naming
kw:nas
kw:navigation
kw:needs-review
kw:needs-spawn
kw:netbsd
kw:network
kw:nevow
kw:new-user
kw:newcaps
kw:news
kw:news-done
kw:news-needed
kw:newsletter
kw:newurls
kw:nfc
kw:nginx
kw:nixos
kw:no-clobber
kw:node
kw:node-url
kw:notification
kw:notifyOnDisconnect
kw:nsa310
kw:nsa320
kw:nsa325
kw:numpy
kw:objects
kw:old
kw:openbsd
kw:openitp-packaging
kw:openssl
kw:openstack
kw:opensuse
kw:operation-helpers
kw:operational
kw:operations
kw:ophandle
kw:ophandles
kw:ops
kw:optimization
kw:optional
kw:options
kw:organization
kw:os
kw:os.abort
kw:ostrom
kw:osx
kw:osxfuse
kw:otf-magic-folder-objective1
kw:otf-magic-folder-objective2
kw:otf-magic-folder-objective3
kw:otf-magic-folder-objective4
kw:otf-magic-folder-objective5
kw:otf-magic-folder-objective6
kw:p2p
kw:packaging
kw:partial
kw:password
kw:path
kw:paths
kw:pause
kw:peer-selection
kw:performance
kw:permalink
kw:permissions
kw:persistence
kw:phone
kw:pickle
kw:pip
kw:pipermail
kw:pkg_resources
kw:placement
kw:planning
kw:policy
kw:port
kw:portability
kw:portal
kw:posthook
kw:pratchett
kw:preformance
kw:preservation
kw:privacy
kw:process
kw:profile
kw:profiling
kw:progress
kw:proxy
kw:publish
kw:pyOpenSSL
kw:pyasn1
kw:pycparser
kw:pycrypto
kw:pycrypto-lib
kw:pycryptopp
kw:pyfilesystem
kw:pyflakes
kw:pylint
kw:pypi
kw:pypy
kw:pysqlite
kw:python
kw:python3
kw:pythonpath
kw:pyutil
kw:pywin32
kw:quickstart
kw:quiet
kw:quotas
kw:quoting
kw:raic
kw:rainhill
kw:random
kw:random-access
kw:range
kw:raspberry-pi
kw:reactor
kw:readonly
kw:rebalancing
kw:recovery
kw:recursive
kw:redhat
kw:redirect
kw:redressing
kw:refactor
kw:referer
kw:referrer
kw:regression
kw:rekey
kw:relay
kw:release
kw:release-blocker
kw:reliability
kw:relnotes
kw:remote
kw:removable
kw:removable-disk
kw:rename
kw:renew
kw:repair
kw:replace
kw:report
kw:repository
kw:research
kw:reserved_space
kw:response-needed
kw:response-time
kw:restore
kw:retrieve
kw:retry
kw:review
kw:review-needed
kw:reviewed
kw:revocation
kw:roadmap
kw:rollback
kw:rpm
kw:rsa
kw:rss
kw:rst
kw:rsync
kw:rusty
kw:s3
kw:s3-backend
kw:s3-frontend
kw:s4
kw:same-origin
kw:sandbox
kw:scalability
kw:scaling
kw:scheduling
kw:schema
kw:scheme
kw:scp
kw:scripts
kw:sdist
kw:sdmf
kw:security
kw:self-contained
kw:server
kw:servermap
kw:servers-of-happiness
kw:service
kw:setup
kw:setup.py
kw:setup_requires
kw:setuptools
kw:setuptools_darcs
kw:sftp
kw:shared
kw:shareset
kw:shell
kw:signals
kw:simultaneous
kw:six
kw:size
kw:slackware
kw:slashes
kw:smb
kw:sneakernet
kw:snowleopard
kw:socket
kw:solaris
kw:space
kw:space-efficiency
kw:spam
kw:spec
kw:speed
kw:sqlite
kw:ssh
kw:ssh-keygen
kw:sshfs
kw:ssl
kw:stability
kw:standards
kw:start
kw:startup
kw:static
kw:static-analysis
kw:statistics
kw:stats
kw:stats_gatherer
kw:status
kw:stdeb
kw:storage
kw:streaming
kw:strports
kw:style
kw:stylesheet
kw:subprocess
kw:sumo
kw:survey
kw:svg
kw:symlink
kw:synchronous
kw:tac
kw:tahoe-*
kw:tahoe-add-alias
kw:tahoe-admin
kw:tahoe-archive
kw:tahoe-backup
kw:tahoe-check
kw:tahoe-cp
kw:tahoe-create-alias
kw:tahoe-create-introducer
kw:tahoe-debug
kw:tahoe-deep-check
kw:tahoe-deepcheck
kw:tahoe-lafs-trac-stream
kw:tahoe-list-aliases
kw:tahoe-ls
kw:tahoe-magic-folder
kw:tahoe-manifest
kw:tahoe-mkdir
kw:tahoe-mount
kw:tahoe-mv
kw:tahoe-put
kw:tahoe-restart
kw:tahoe-rm
kw:tahoe-run
kw:tahoe-start
kw:tahoe-stats
kw:tahoe-unlink
kw:tahoe-webopen
kw:tahoe.css
kw:tahoe_files
kw:tahoewapi
kw:tarball
kw:tarballs
kw:tempfile
kw:templates
kw:terminology
kw:test
kw:test-and-set
kw:test-from-egg
kw:test-needed
kw:testgrid
kw:testing
kw:tests
kw:throttling
kw:ticket999-s3-backend
kw:tiddly
kw:time
kw:timeout
kw:timing
kw:to
kw:to-be-closed-on-2011-08-01
kw:tor
kw:tor-protocol
kw:torsocks
kw:tox
kw:trac
kw:transparency
kw:travis
kw:travis-ci
kw:trial
kw:trickle
kw:trivial
kw:truckee
kw:tub
kw:tub.location
kw:twine
kw:twistd
kw:twistd.log
kw:twisted
kw:twisted-14
kw:twisted-trial
kw:twitter
kw:twn
kw:txaws
kw:type
kw:typeerror
kw:ubuntu
kw:ucwe
kw:ueb
kw:ui
kw:unclean
kw:uncoordinated-writes
kw:undeletable
kw:unfinished-business
kw:unhandled-error
kw:unhappy
kw:unicode
kw:unit
kw:unix
kw:unlink
kw:update
kw:upgrade
kw:upload
kw:upload-helper
kw:uri
kw:url
kw:usability
kw:use-case
kw:utf-8
kw:util
kw:uwsgi
kw:ux
kw:validation
kw:variables
kw:vdrive
kw:verify
kw:verlib
kw:version
kw:versioning
kw:versions
kw:video
kw:virtualbox
kw:virtualenv
kw:vista
kw:visualization
kw:visualizer
kw:vm
kw:volunteergrid2
kw:volunteers
kw:vpn
kw:wapi
kw:warners-opinion-needed
kw:warning
kw:weapi
kw:web
kw:web.port
kw:webapi
kw:webdav
kw:webdrive
kw:webport
kw:websec
kw:website
kw:websocket
kw:welcome
kw:welcome-page
kw:welcomepage
kw:wiki
kw:win32
kw:win64
kw:windows
kw:windows-related
kw:winscp
kw:workaround
kw:world-domination
kw:wrapper
kw:write-enabler
kw:wui
kw:x86
kw:x86-64
kw:xhtml
kw:xml
kw:xss
kw:zbase32
kw:zetuptoolz
kw:zfec
kw:zookos-opinion-needed
kw:zope
kw:zope.interface
p/blocker
p/critical
p/major
p/minor
p/normal
p/supercritical
p/trivial
r/cannot reproduce
r/duplicate
r/fixed
r/invalid
r/somebody else's problem
r/was already fixed
r/wontfix
r/worksforme
t/defect
t/enhancement
t/task
v/0.2.0
v/0.3.0
v/0.4.0
v/0.5.0
v/0.5.1
v/0.6.0
v/0.6.1
v/0.7.0
v/0.8.0
v/0.9.0
v/1.0.0
v/1.1.0
v/1.10.0
v/1.10.1
v/1.10.2
v/1.10a2
v/1.11.0
v/1.12.0
v/1.12.1
v/1.13.0
v/1.14.0
v/1.15.0
v/1.15.1
v/1.2.0
v/1.3.0
v/1.4.1
v/1.5.0
v/1.6.0
v/1.6.1
v/1.7.0
v/1.7.1
v/1.7β
v/1.8.0
v/1.8.1
v/1.8.2
v/1.8.3
v/1.8β
v/1.9.0
v/1.9.0-s3branch
v/1.9.0a1
v/1.9.0a2
v/1.9.0b1
v/1.9.1
v/1.9.2
v/1.9.2a1
v/cloud-branch
v/unknown
No milestone
No project
No assignees
3 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: tahoe-lafs/trac#1329
No description provided.