[Zodb-checkins] SVN: zdaemon/trunk/ Merge the py3 branch.

Marius Gedminas cvs-admin at zope.org
Fri Feb 15 13:24:53 UTC 2013


Log message for revision 129432:
  Merge the py3 branch.
  
    svn merge -r 129325:129415 svn+ssh://svn.zope.org/repos/main/zdaemon/branches/py3 .
  
  

Changed:
  _U  zdaemon/trunk/
  U   zdaemon/trunk/CHANGES.txt
  A   zdaemon/trunk/MANIFEST.in
  U   zdaemon/trunk/bootstrap.py
  U   zdaemon/trunk/buildout.cfg
  U   zdaemon/trunk/setup.py
  U   zdaemon/trunk/src/zdaemon/README.txt
  U   zdaemon/trunk/src/zdaemon/tests/parent.py
  U   zdaemon/trunk/src/zdaemon/tests/tests.py
  U   zdaemon/trunk/src/zdaemon/tests/testuser.py
  U   zdaemon/trunk/src/zdaemon/tests/testzdoptions.py
  U   zdaemon/trunk/src/zdaemon/tests/testzdrun.py
  U   zdaemon/trunk/src/zdaemon/zdctl.py
  U   zdaemon/trunk/src/zdaemon/zdoptions.py
  U   zdaemon/trunk/src/zdaemon/zdrun.py
  A   zdaemon/trunk/tox.ini

-=-

Property changes on: zdaemon/trunk
___________________________________________________________________
Modified: svn:ignore
   - .installed.cfg
build
develop-eggs
dist
eggs
bin
parts

   + .coverage
.installed.cfg
.tox
build
coverage
develop-eggs
dist
eggs
bin
parts
*.xml


Modified: zdaemon/trunk/CHANGES.txt
===================================================================
--- zdaemon/trunk/CHANGES.txt	2013-02-15 12:53:25 UTC (rev 129431)
+++ zdaemon/trunk/CHANGES.txt	2013-02-15 13:24:52 UTC (rev 129432)
@@ -2,6 +2,13 @@
 Change log
 ==========
 
+4.0.0 (unreleased)
+==================
+
+- Added tox support and MANIFEST.in for proper releasing.
+
+- Drop Python 2.4 and 2.5 support.
+
 3.0.5 (2012-11-27)
 ==================
 

Copied: zdaemon/trunk/MANIFEST.in (from rev 129415, zdaemon/branches/py3/MANIFEST.in)
===================================================================
--- zdaemon/trunk/MANIFEST.in	                        (rev 0)
+++ zdaemon/trunk/MANIFEST.in	2013-02-15 13:24:52 UTC (rev 129432)
@@ -0,0 +1,9 @@
+include *.rst
+include *.txt
+include tox.ini
+include bootstrap.py
+include buildout.cfg
+
+recursive-include src *
+
+global-exclude *.pyc

Modified: zdaemon/trunk/bootstrap.py
===================================================================
--- zdaemon/trunk/bootstrap.py	2013-02-15 12:53:25 UTC (rev 129431)
+++ zdaemon/trunk/bootstrap.py	2013-02-15 13:24:52 UTC (rev 129432)
@@ -16,51 +16,150 @@
 Simply run this script in a directory containing a buildout.cfg.
 The script accepts buildout command-line options, so you can
 use the -c option to specify an alternate configuration file.
-
-$Id: bootstrap.py 68905 2006-06-29 10:46:56Z jim $
 """
 
-import os, shutil, sys, tempfile, urllib2
+import os, shutil, sys, tempfile
+from optparse import OptionParser
 
 tmpeggs = tempfile.mkdtemp()
 
-ez = {}
-exec urllib2.urlopen('http://peak.telecommunity.com/dist/ez_setup.py'
-                     ).read() in ez
-ez['use_setuptools'](to_dir=tmpeggs, download_delay=0)
+usage = '''\
+[DESIRED PYTHON FOR BUILDOUT] bootstrap.py [options]
 
-import pkg_resources
+Bootstraps a buildout-based project.
 
-is_jython = sys.platform.startswith('java')
+Simply run this script in a directory containing a buildout.cfg, using the
+Python that you want bin/buildout to use.
 
-if is_jython:
-    import subprocess
+Note that by using --setup-source and --download-base to point to
+local resources, you can keep this script from going over the network.
+'''
 
-ws = pkg_resources.working_set
+parser = OptionParser(usage=usage)
+parser.add_option("-v", "--version", help="use a specific zc.buildout version")
 
-if is_jython:
-    assert subprocess.Popen(
-           [sys.executable] + ['-c', 
-           'from setuptools.command.easy_install import main; main()',
-           '-mqNxd', tmpeggs, 'zc.buildout'],
-           env = dict(
-                PYTHONPATH = 
-                ws.find(pkg_resources.Requirement.parse('setuptools')).location
-           ),
-    ).wait() == 0
+parser.add_option("-t", "--accept-buildout-test-releases",
+                  dest='accept_buildout_test_releases',
+                  action="store_true", default=False,
+                  help=("Normally, if you do not specify a --version, the "
+                        "bootstrap script and buildout gets the newest "
+                        "*final* versions of zc.buildout and its recipes and "
+                        "extensions for you.  If you use this flag, "
+                        "bootstrap and buildout will get the newest releases "
+                        "even if they are alphas or betas."))
+parser.add_option("-c", "--config-file",
+                   help=("Specify the path to the buildout configuration "
+                         "file to be used."))
+parser.add_option("-f", "--find-links",
+                   help=("Specify a URL to search for buildout releases"))
 
-else:
-    assert os.spawnle(
-        os.P_WAIT, sys.executable, sys.executable,
-        '-c', 'from setuptools.command.easy_install import main; main()',
-        '-mqNxd', tmpeggs, 'zc.buildout',
-        {'PYTHONPATH':
-        ws.find(pkg_resources.Requirement.parse('setuptools')).location
-        },
-        ) == 0
 
+options, args = parser.parse_args()
+
+######################################################################
+# load/install distribute
+
+to_reload = False
+try:
+    import pkg_resources, setuptools
+    if not hasattr(pkg_resources, '_distribute'):
+        to_reload = True
+        raise ImportError
+except ImportError:
+    ez = {}
+
+    try:
+        from urllib.request import urlopen
+    except ImportError:
+        from urllib2 import urlopen
+
+    exec(urlopen('http://python-distribute.org/distribute_setup.py').read(), ez)
+    setup_args = dict(to_dir=tmpeggs, download_delay=0, no_fake=True)
+    ez['use_setuptools'](**setup_args)
+
+    if to_reload:
+        reload(pkg_resources)
+    import pkg_resources
+    # This does not (always?) update the default working set.  We will
+    # do it.
+    for path in sys.path:
+        if path not in pkg_resources.working_set.entries:
+            pkg_resources.working_set.add_entry(path)
+
+######################################################################
+# Install buildout
+
+ws  = pkg_resources.working_set
+
+cmd = [sys.executable, '-c',
+       'from setuptools.command.easy_install import main; main()',
+       '-mZqNxd', tmpeggs]
+
+find_links = os.environ.get(
+    'bootstrap-testing-find-links',
+    options.find_links or
+    ('http://downloads.buildout.org/'
+     if options.accept_buildout_test_releases else None)
+    )
+if find_links:
+    cmd.extend(['-f', find_links])
+
+distribute_path = ws.find(
+    pkg_resources.Requirement.parse('distribute')).location
+
+requirement = 'zc.buildout'
+version = options.version
+if version is None and not options.accept_buildout_test_releases:
+    # Figure out the most recent final version of zc.buildout.
+    import setuptools.package_index
+    _final_parts = '*final-', '*final'
+    def _final_version(parsed_version):
+        for part in parsed_version:
+            if (part[:1] == '*') and (part not in _final_parts):
+                return False
+        return True
+    index = setuptools.package_index.PackageIndex(
+        search_path=[distribute_path])
+    if find_links:
+        index.add_find_links((find_links,))
+    req = pkg_resources.Requirement.parse(requirement)
+    if index.obtain(req) is not None:
+        best = []
+        bestv = None
+        for dist in index[req.project_name]:
+            distv = dist.parsed_version
+            if _final_version(distv):
+                if bestv is None or distv > bestv:
+                    best = [dist]
+                    bestv = distv
+                elif distv == bestv:
+                    best.append(dist)
+        if best:
+            best.sort()
+            version = best[-1].version
+if version:
+    requirement = '=='.join((requirement, version))
+cmd.append(requirement)
+
+import subprocess
+if subprocess.call(cmd, env=dict(os.environ, PYTHONPATH=distribute_path)) != 0:
+    raise Exception(
+        "Failed to execute command:\n%s",
+        repr(cmd)[1:-1])
+
+######################################################################
+# Import and run buildout
+
 ws.add_entry(tmpeggs)
-ws.require('zc.buildout')
+ws.require(requirement)
 import zc.buildout.buildout
-zc.buildout.buildout.main(sys.argv[1:] + ['bootstrap'])
+
+if not [a for a in args if '=' not in a]:
+    args.append('bootstrap')
+
+# if -c was provided, we push it back into args for buildout' main function
+if options.config_file is not None:
+    args[0:0] = ['-c', options.config_file]
+
+zc.buildout.buildout.main(args)
 shutil.rmtree(tmpeggs)

Modified: zdaemon/trunk/buildout.cfg
===================================================================
--- zdaemon/trunk/buildout.cfg	2013-02-15 12:53:25 UTC (rev 129431)
+++ zdaemon/trunk/buildout.cfg	2013-02-15 13:24:52 UTC (rev 129432)
@@ -1,7 +1,8 @@
 [buildout]
 develop = .
-parts = test scripts coverage-test coverage-report
-find-links = http://download.zope.org/distribution/
+          ../ZConfig
+parts = test scripts coverage-test
+        coverage-report
 
 [test]
 recipe = zc.recipe.testrunner
@@ -10,13 +11,14 @@
 [coverage-test]
 recipe = zc.recipe.testrunner
 eggs = ${test:eggs}
-defaults = ['--coverage', '../../coverage']
+defaults = ['--coverage', '${buildout:directory}/coverage']
 
 [coverage-report]
 recipe = zc.recipe.egg
 eggs = z3c.coverage
-scripts = coverage=coverage-report
-arguments = ('coverage', 'coverage/report')
+scripts = coveragereport=coverage-report
+arguments = ('${buildout:directory}/coverage',
+             '${buildout:directory}/coverage/report')
 
 [scripts]
 recipe = zc.recipe.egg

Modified: zdaemon/trunk/setup.py
===================================================================
--- zdaemon/trunk/setup.py	2013-02-15 12:53:25 UTC (rev 129431)
+++ zdaemon/trunk/setup.py	2013-02-15 13:24:52 UTC (rev 129432)
@@ -11,10 +11,11 @@
 # FOR A PARTICULAR PURPOSE.
 #
 ##############################################################################
+import os
 
-version = '0.0.0'
+tests_require = ['zope.testing', 'zope.testrunner', 'manuel', 'mock',
+                 'zc.customdoctests']
 
-import os
 
 entry_points = """
 [console_scripts]
@@ -24,6 +25,21 @@
 def read(*rnames):
     return open(os.path.join(os.path.dirname(__file__), *rnames)).read()
 
+def alltests():
+    import os
+    import sys
+    import unittest
+    # use the zope.testrunner machinery to find all the
+    # test suites we've put under ourselves
+    import zope.testrunner.find
+    import zope.testrunner.options
+    here = os.path.abspath(os.path.join(os.path.dirname(__file__), 'src'))
+    args = sys.argv[:]
+    defaults = ["--test-path", here]
+    options = zope.testrunner.options.get_options(args, defaults)
+    suites = list(zope.testrunner.find.find_suites(options))
+    return unittest.TestSuite(suites)
+
 try:
     from setuptools import setup
     setuptools_options = dict(
@@ -31,17 +47,17 @@
         entry_points=entry_points,
         include_package_data = True,
         install_requires=["ZConfig"],
-        extras_require=dict(
-            test=['zope.testing', 'manuel', 'zc.customdoctests', 'mock']),
+        extras_require=dict(test=tests_require),
+        test_suite='__main__.alltests',
+        tests_require=tests_require
         )
 except ImportError:
     from distutils.core import setup
     setuptools_options = {}
 
-name = "zdaemon"
 setup(
-    name=name,
-    version = version,
+    name="zdaemon",
+    version = "4.0.0dev",
     url="http://www.python.org/pypi/zdaemon",
     license="ZPL 2.1",
     description=
@@ -65,8 +81,15 @@
        'Intended Audience :: Developers',
        'Intended Audience :: System Administrators',
        'License :: OSI Approved :: Zope Public License',
+       'Programming Language :: Python',
+       'Programming Language :: Python :: 2',
+       'Programming Language :: Python :: 2.6',
+       'Programming Language :: Python :: 2.7',
+       'Programming Language :: Python :: 3',
+       'Programming Language :: Python :: 3.3',
+       'Programming Language :: Python :: Implementation :: CPython',
+       'Operating System :: POSIX',
        'Topic :: Utilities',
-       'Operating System :: POSIX',
        ],
 
     **setuptools_options)

Modified: zdaemon/trunk/src/zdaemon/README.txt
===================================================================
--- zdaemon/trunk/src/zdaemon/README.txt	2013-02-15 12:53:25 UTC (rev 129431)
+++ zdaemon/trunk/src/zdaemon/README.txt	2013-02-15 13:24:52 UTC (rev 129432)
@@ -83,7 +83,8 @@
 
 .. -> text
 
-    >>> open('conf', 'w').write(text)
+    >>> with open('conf', 'w') as file:
+    ...     _ = file.write(text)
 
 Now, we can run with the -C option to read the configuration file:
 
@@ -115,7 +116,8 @@
 
 .. -> text
 
-    >>> open('conf', 'w').write(text.replace('/tmp', tmpdir))
+    >>> with open('conf', 'w') as file:
+    ...     _ = file.write(text.replace('/tmp', tmpdir))
 
 Now, when we run zdaemon:
 
@@ -149,7 +151,8 @@
 
 .. -> text
 
-    >>> open('conf', 'w').write(text.replace('/tmp', tmpdir))
+    >>> with open('conf', 'w') as file:
+    ...     _ = file.write(text.replace('/tmp', tmpdir))
 
 Then we can pass the program argument on the command line:
 
@@ -184,7 +187,8 @@
 
 .. -> text
 
-    >>> open('conf', 'w').write(text.replace('/tmp', tmpdir))
+    >>> with open('conf', 'w') as file:
+    ...     _ = file.write(text.replace('/tmp', tmpdir))
 
 Now, when we run the command, we'll see out environment settings reflected:
 
@@ -215,9 +219,9 @@
 Let's look at an example. We'll have a long-running process that
 simple tails a data file:
 
-    >>> f = open('data', 'w', 0)
+    >>> f = open('data', 'w', 1)
     >>> import os
-    >>> f.write('rec 1\n'); os.fsync(f.fileno())
+    >>> _ = f.write('rec 1\n'); f.flush(); os.fsync(f.fileno())
 
 Now, here's out zdaemon configuration::
 
@@ -228,7 +232,8 @@
 
 .. -> text
 
-    >>> open('conf', 'w').write(text)
+    >>> with open('conf', 'w') as file:
+    ...     _ = file.write(text)
 
 Now we'll start:
 
@@ -243,7 +248,8 @@
 
 After waiting a bit, if we look at the log file, it contains the tail output:
 
-    >>> open('log').read()
+    >>> with open('log') as file:
+    ...     file.read()
     'rec 1\n'
 
 We can rotate the transcript log by renaming it and telling zdaemon to
@@ -254,7 +260,7 @@
 
 If we generate more output:
 
-    >>> f.write('rec 2\n'); os.fsync(f.fileno())
+    >>> _ = f.write('rec 2\n'); f.flush(); os.fsync(f.fileno())
 
 .. Wait a little bit to make sure tail has a chance to work
 
@@ -263,7 +269,8 @@
 The output will appear in the old file, because zdaemon still has it
 open:
 
-    >>> open('log.1').read()
+    >>> with open('log.1') as file:
+    ...     file.read()
     'rec 1\nrec 2\n'
 
 Now, if we tell zdaemon to reopen the file:
@@ -272,7 +279,7 @@
 
 and generate some output:
 
-    >>> f.write('rec 3\n'); os.fsync(f.fileno())
+    >>> _ = f.write('rec 3\n'); f.flush(); os.fsync(f.fileno())
 
 .. Wait a little bit to make sure tail has a chance to work
 
@@ -280,12 +287,18 @@
 
 the output will show up in the new file, not the old:
 
-    >>> open('log').read()
+    >>> with open('log') as file:
+    ...     file.read()
     'rec 3\n'
 
-    >>> open('log.1').read()
+    >>> with open('log.1') as file:
+    ...     file.read()
     'rec 1\nrec 2\n'
 
+Close files:
+
+    >>> f.close()
+
 Start test program and timeout
 ==============================
 

Modified: zdaemon/trunk/src/zdaemon/tests/parent.py
===================================================================
--- zdaemon/trunk/src/zdaemon/tests/parent.py	2013-02-15 12:53:25 UTC (rev 129431)
+++ zdaemon/trunk/src/zdaemon/tests/parent.py	2013-02-15 13:24:52 UTC (rev 129432)
@@ -18,15 +18,13 @@
     zctldir = os.path.dirname(dir)
     zdrun = os.path.join(zctldir, 'zdrun.py')
     donothing = os.path.join(tmp, 'donothing.sh')
-    fd = os.open(donothing, os.O_WRONLY|os.O_CREAT, 0700)
-    os.write(fd, donothing_contents)
+    fd = os.open(donothing, os.O_WRONLY|os.O_CREAT, 0o700)
+    os.write(fd, donothing_contents.encode())
     os.close(fd)
     args = [sys.executable, zdrun]
     args += ['-d', '-b', '10', '-s', os.path.join(tmp, 'testsock'),
              '-x', '0,2', '-z', dir, donothing]
     flag = os.P_NOWAIT
-    #cmd = ' '.join([sys.executable] + args)
-    #print cmd
     os.spawnvpe(flag, args[0], args,
                 dict(os.environ, PYTHONPATH=':'.join(sys.path)),
                 )

Modified: zdaemon/trunk/src/zdaemon/tests/tests.py
===================================================================
--- zdaemon/trunk/src/zdaemon/tests/tests.py	2013-02-15 12:53:25 UTC (rev 129431)
+++ zdaemon/trunk/src/zdaemon/tests/tests.py	2013-02-15 13:24:52 UTC (rev 129432)
@@ -11,19 +11,23 @@
 # FOR A PARTICULAR PURPOSE.
 #
 ##############################################################################
+from __future__ import print_function
 
 import doctest
-import manuel.capture
-import manuel.doctest
-import manuel.testing
 import os
 import re
+import signal
 import shutil
 import subprocess
 import sys
 import tempfile
 import unittest
+from contextlib import contextmanager
+
 import ZConfig
+import manuel.capture
+import manuel.doctest
+import manuel.testing
 import zc.customdoctests
 import zdaemon
 from zope.testing import renormalizing
@@ -38,6 +42,7 @@
     zdaemon_loc = os.path.dirname(os.path.dirname(zdaemon.__file__))
     zconfig_loc = os.path.dirname(os.path.dirname(ZConfig.__file__))
 
+
 def write(name, text):
     with open(name, 'w') as f:
         f.write(text)
@@ -46,6 +51,7 @@
     with open(name) as f:
         return f.read()
 
+
 def make_sure_non_daemon_mode_doesnt_hang_when_program_exits():
     """
     The whole awhile bit that waits for a program to start
@@ -84,12 +90,11 @@
 
 def allow_duplicate_arguments():
     """
+    Wrapper scripts will often embed configuration arguments. This could
+    cause a problem when zdaemon reinvokes itself, passing it's own set of
+    configuration arguments.  To deal with this, we'll allow duplicate
+    arguments that have the same values.
 
-Wrapper scripts will often embed configuration arguments. This could
-cause a problem when zdaemon reinvokes itself, passing it's own set of
-configuration arguments.  To deal with this, we'll allow duplicate
-arguments that have the same values.
-
     >>> write('conf',
     ... '''
     ... <runner>
@@ -105,7 +110,7 @@
     . .
     daemon process stopped
 
-"""
+    """
 
 def test_stop_timeout():
     r"""
@@ -153,7 +158,7 @@
     ... '''
     ... import time
     ... time.sleep(1)
-    ... open('x', 'w')
+    ... open('x', 'w').close()
     ... time.sleep(99)
     ... ''')
 
@@ -186,7 +191,7 @@
     ... '''
     ... import time
     ... time.sleep(1)
-    ... open('x', 'w')
+    ... open('x', 'w').close()
     ... time.sleep(99)
     ... ''')
 
@@ -269,7 +274,7 @@
     True
     """
 
-def nonzeo_exit_on_program_failure():
+def nonzero_exit_on_program_failure():
     """
     >>> write('conf',
     ... '''
@@ -322,44 +327,70 @@
     workspace = tempfile.mkdtemp()
     td.append(lambda : shutil.rmtree(workspace))
     os.chdir(workspace)
-    open('zdaemon', 'w').write(zdaemon_template % dict(
-        python = sys.executable,
-        zdaemon = zdaemon_loc,
-        ZConfig = zconfig_loc,
-        ))
-    os.chmod('zdaemon', 0755)
-    test.globs.update(dict(
-        system = system
-        ))
+    write('zdaemon', zdaemon_template % dict(
+        python=sys.executable,
+        zdaemon=zdaemon_loc,
+        ZConfig=zconfig_loc,
+    ))
+    os.chmod('zdaemon', 0o755)
+    test.globs['system'] = system
 
 def tearDown(test):
     for f in test.globs['_td']:
         f()
 
+
+class Timeout(BaseException):
+    pass
+
+
+ at contextmanager
+def timeout(seconds):
+    this_frame = sys._getframe()
+    def raiseTimeout(signal, frame):
+        # the if statement here is meant to prevent an exception in the
+        # finally: clause before clean up can take place
+        if frame is not this_frame:
+            raise Timeout('timed out after %s seconds' % seconds)
+    try:
+        prev_handler = signal.signal(signal.SIGALRM, raiseTimeout)
+    except ValueError:
+        # signal only works in main thread
+        # let's ignore the request for a timeout and hope the test doesn't hang
+        yield
+    else:
+        try:
+            signal.alarm(seconds)
+            yield
+        finally:
+            signal.alarm(0)
+            signal.signal(signal.SIGALRM, prev_handler)
+
+
 def system(command, input='', quiet=False, echo=False):
     if echo:
-        print command
+        print(command)
     p = subprocess.Popen(
         command, shell=True,
         stdin=subprocess.PIPE,
         stdout=subprocess.PIPE,
         stderr=subprocess.STDOUT)
-    if input:
-        p.stdin.write(input)
-    p.stdin.close()
-    data = p.stdout.read()
+    with timeout(60):
+        data = p.communicate(input)[0]
     if not quiet:
-        print data,
+        print(data.decode(), end='')
     r = p.wait()
     if r:
-        print 'Failed:', r
+        print('Failed:', r)
 
+
 def checkenv(match):
     match = [a for a in match.group(1).split('\n')[:-1]
              if a.split('=')[0] in ('HOME', 'LD_LIBRARY_PATH')]
     match.sort()
     return '\n'.join(match) + '\n'
 
+
 zdaemon_template = """#!%(python)s
 
 import sys
@@ -387,20 +418,18 @@
             checker=renormalizing.RENormalizing([
                 (re.compile('pid=\d+'), 'pid=NNN'),
                 (re.compile('(\. )+\.?'), '<BLANKLINE>'),
-                ])
-        ),
+                ])),
         manuel.testing.TestSuite(
-            manuel.doctest.Manuel(
-                parser=zc.customdoctests.DocTestParser(
-                    ps1='sh>',
-                    transform=lambda s: 'system("%s")\n' % s.rstrip()
-                    ),
-                checker=README_checker,
-                ) +
-            manuel.doctest.Manuel(checker=README_checker) +
-            manuel.capture.Manuel(),
-            '../README.txt',
-            setUp=setUp, tearDown=tearDown,
-            ),
+                manuel.doctest.Manuel(
+                    parser=zc.customdoctests.DocTestParser(
+                        ps1='sh>',
+                        transform=lambda s: 'system("%s")\n' % s.rstrip()
+                        ),
+                    checker=README_checker,
+                    ) +
+                manuel.doctest.Manuel(checker=README_checker) +
+                manuel.capture.Manuel(),
+                '../README.txt',
+                setUp=setUp, tearDown=tearDown),
         ))
 

Modified: zdaemon/trunk/src/zdaemon/tests/testuser.py
===================================================================
--- zdaemon/trunk/src/zdaemon/tests/testuser.py	2013-02-15 12:53:25 UTC (rev 129431)
+++ zdaemon/trunk/src/zdaemon/tests/testuser.py	2013-02-15 13:24:52 UTC (rev 129432)
@@ -50,7 +50,7 @@
     ...     except SystemExit:
     ...         pass
     ...     else:
-    ...         print 'oops'
+    ...         print('oops')
     ... # doctest: +ELLIPSIS
     Error: only root can use -u USER to change users
     For help, use ... -h

Modified: zdaemon/trunk/src/zdaemon/tests/testzdoptions.py
===================================================================
--- zdaemon/trunk/src/zdaemon/tests/testzdoptions.py	2013-02-15 12:53:25 UTC (rev 129431)
+++ zdaemon/trunk/src/zdaemon/tests/testzdoptions.py	2013-02-15 13:24:52 UTC (rev 129432)
@@ -19,7 +19,6 @@
 import tempfile
 import shutil
 import unittest
-from StringIO import StringIO
 
 import ZConfig
 import zdaemon
@@ -27,6 +26,12 @@
     ZDOptions, RunnerOptions,
     existing_parent_directory, existing_parent_dirpath)
 
+try:
+    from StringIO import StringIO
+except:
+    # Python 3 support.
+    from io import StringIO
+
 class ZDOptionsTestBase(unittest.TestCase):
 
     OptionsClass = ZDOptions
@@ -47,7 +52,7 @@
             sys.stderr = StringIO()
             try:
                 options.realize(args)
-            except SystemExit, err:
+            except SystemExit as err:
                 self.assertEqual(err.code, 2)
             else:
                 self.fail("SystemExit expected")
@@ -96,7 +101,7 @@
                     options.realize([arg],**kw)
                 finally:
                     self.restore_streams()
-            except SystemExit, err:
+            except SystemExit as err:
                 self.assertEqual(err.code, 0)
             else:
                 self.fail("%s didn't call sys.exit()" % repr(arg))
@@ -199,7 +204,7 @@
         L = []
         options.add("setting", None, "a:", "append=", handler=L.append)
         options.realize(["-a2", "--append", "3"])
-        self.assert_(options.setting is None)
+        self.assertTrue(options.setting is None)
         self.assertEqual(L, ["2", "3"])
 
     def test_handler_with_bad_value(self):
@@ -307,7 +312,7 @@
                 options.realize([])
             finally:
                 self.restore_streams()
-        except SystemExit, e:
+        except SystemExit as e:
             self.assertEqual(e.code, 2)
         else:
             self.fail("expected SystemExit")
@@ -368,7 +373,7 @@
         options = self.OptionsClass()
         path = os.path.join(self.root, 'will-be-created')
         options.realize(["-z", path])
-        self.assertEquals(path, options.directory)
+        self.assertEqual(path, options.directory)
         socket = os.path.join(path, 'socket')
         options = self.OptionsClass()
         options.realize(["-s", socket])

Modified: zdaemon/trunk/src/zdaemon/tests/testzdrun.py
===================================================================
--- zdaemon/trunk/src/zdaemon/tests/testzdrun.py	2013-02-15 12:53:25 UTC (rev 129431)
+++ zdaemon/trunk/src/zdaemon/tests/testzdrun.py	2013-02-15 13:24:52 UTC (rev 129432)
@@ -1,4 +1,5 @@
 """Test suite for zdrun.py."""
+from __future__ import print_function
 
 import os
 import sys
@@ -9,7 +10,11 @@
 import unittest
 import socket
 
-from StringIO import StringIO
+try:
+    from StringIO import StringIO
+except:
+    # Python 3 support.
+    from io import StringIO
 
 import ZConfig
 
@@ -105,7 +110,7 @@
     def testCmdclassOverride(self):
         class MyCmd(zdctl.ZDCmd):
             def do_sproing(self, rest):
-                print rest
+                print(rest)
         self._run("-p echo sproing expected", cmdclass=MyCmd)
         self.expect = "expected\n"
 
@@ -146,8 +151,8 @@
         options = zdrun.ZDRunOptions()
         try:
             options.realize(["-h"], doc=zdrun.__doc__)
-        except SystemExit, err:
-            self.failIf(err.code)
+        except SystemExit as err:
+            self.assertEqual(err.code, 0)
         else:
             self.fail("SystemExit expected")
         self.expect = zdrun.__doc__
@@ -217,7 +222,7 @@
                      )
                 )
             # Wait for it to start, but no longer than a minute.
-            deadline = time.time() + 6000
+            deadline = time.time() + 60
             is_started = False
             while time.time() < deadline:
                  response = send_action('status\n', zdrun_socket)
@@ -226,14 +231,16 @@
                  else:
                      is_started = True
                      break
-            self.assert_(is_started,
-                         "spawned process failed to start in a minute")
+            self.assertTrue(is_started,
+                            "spawned process failed to start in a minute")
             # Kill it, and wait a little to ensure it's dead.
             os.kill(zdctlpid, signal.SIGINT)
             time.sleep(0.25)
             # Make sure the child is still responsive.
-            response = send_action('status\n', zdrun_socket)
-            self.assert_(response is not None and '\n' in response)
+            response = send_action('status\n', zdrun_socket,
+                                   raise_on_error=True)
+            self.assertTrue(b'\n' in response,
+                            'no newline in response: ' + repr(response))
             # Kill the process.
             send_action('exit\n', zdrun_socket)
         finally:
@@ -277,8 +284,8 @@
             for i in range(5):
                 if not os.path.exists(path):
                     time.sleep(0.1)
-            self.assert_(os.path.exists(path))
-            self.assert_(not os.access(path, os.W_OK))
+            self.assertTrue(os.path.exists(path))
+            self.assertTrue(not os.access(path, os.W_OK))
         finally:
             if os.path.exists(path):
                 os.remove(path)
@@ -305,7 +312,7 @@
         sys.stdout = self.save_stdout
         sys.stderr = self.save_stderr
         if err:
-            print >>sys.stderr, err,
+            print(err, end='', file=sys.stderr)
         self.assertEqual(self.expect, got)
         super(TestRunnerDirectory, self).tearDown()
 
@@ -319,7 +326,7 @@
     def testCtlRunDirectoryCreation(self):
         path = os.path.join(self.root, 'rundir')
         self.run_ctl(['-z', path, '-p', self.cmd])
-        self.assert_(os.path.exists(path))
+        self.assertTrue(os.path.exists(path))
 
     def testCtlRunDirectoryCreationFromConfigFile(self):
         path = os.path.join(self.root, 'rundir')
@@ -328,7 +335,7 @@
         config = self.writeConfig(
             '<runner>\n%s\n</runner>' % '\n'.join(options))
         self.run_ctl(['-C', config])
-        self.assert_(os.path.exists(path))
+        self.assertTrue(os.path.exists(path))
 
     def testCtlRunDirectoryCreationOnlyOne(self):
         path = os.path.join(self.root, 'rundir', 'not-created')
@@ -342,13 +349,13 @@
     def testCtlSocketDirectoryCreation(self):
         path = os.path.join(self.root, 'rundir', 'sock')
         self.run_ctl(['-s', path, '-p', self.cmd])
-        self.assert_(os.path.exists(os.path.dirname(path)))
+        self.assertTrue(os.path.exists(os.path.dirname(path)))
 
     def testCtlSocketDirectoryCreationRelativePath(self):
         path = os.path.join('rundir', 'sock')
         self.run_ctl(['-s', path, '-p', self.cmd])
-        self.assert_(os.path.exists(os.path.dirname(os.path.join(os.getcwd(),
-                                                                 path))))
+        self.assertTrue(os.path.exists(os.path.dirname(os.path.join(os.getcwd(),
+                                                                    path))))
 
     def testCtlSocketDirectoryCreationOnlyOne(self):
         path = os.path.join(self.root, 'rundir', 'not-created', 'sock')
@@ -366,7 +373,7 @@
         config = self.writeConfig(
             '<runner>\n%s\n</runner>' % '\n'.join(options))
         self.run_ctl(['-C', config])
-        self.assert_(os.path.exists(path))
+        self.assertTrue(os.path.exists(path))
 
     def testCtlSocketDirectoryCreationFromConfigFileRelativePath(self):
         path = 'rel-rundir'
@@ -375,11 +382,12 @@
         config = self.writeConfig(
             '<runner>\n%s\n</runner>' % '\n'.join(options))
         self.run_ctl(['-C', config])
-        self.assert_(os.path.exists(os.path.join(os.getcwd(), path)))
+        self.assertTrue(os.path.exists(os.path.join(os.getcwd(), path)))
 
     def writeConfig(self, config):
         config_file = os.path.join(self.root, 'config')
-        open(config_file, 'w').write(config)
+        with open(config_file, 'w') as f:
+            f.write(config)
         return config_file
 
     def testDirectoryChown(self):
@@ -407,7 +415,7 @@
         self.assertEqual([('chown', path, 27, 28)], calls)
 
 
-def send_action(action, sockname):
+def send_action(action, sockname, raise_on_error=False):
     """Send an action to the zdrun server and return the response.
 
     Return None if the server is not up or any other error happened.
@@ -415,9 +423,9 @@
     sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
     try:
         sock.connect(sockname)
-        sock.send(action + "\n")
+        sock.send(action.encode() + b"\n")
         sock.shutdown(1) # We're not writing any more
-        response = ""
+        response = b""
         while 1:
             data = sock.recv(1000)
             if not data:
@@ -425,13 +433,17 @@
             response += data
         sock.close()
         return response
-    except socket.error, msg:
+    except socket.error as msg:
         if str(msg) == 'AF_UNIX path too long':
             # MacOS has apparent small limits on the length of a UNIX
             # domain socket filename, we want to make MacOS users aware
             # of the actual problem
             raise
+        if raise_on_error:
+            raise
         return None
+    finally:
+        sock.close()
 
 def test_suite():
     suite = unittest.TestSuite()

Modified: zdaemon/trunk/src/zdaemon/zdctl.py
===================================================================
--- zdaemon/trunk/src/zdaemon/zdctl.py	2013-02-15 12:53:25 UTC (rev 129431)
+++ zdaemon/trunk/src/zdaemon/zdctl.py	2013-02-15 13:24:52 UTC (rev 129432)
@@ -37,6 +37,7 @@
 Actions are commands like "start", "stop" and "status".  Use the
 action "help" to find out about available actions.
 """
+from __future__ import print_function
 
 import os
 import os.path
@@ -127,9 +128,9 @@
                 args = eval(s, {"__builtins__": {}})
                 program = self.options.program
                 if args[:len(program)] != program:
-                    print "WARNING! zdrun is managing a different program!"
-                    print "our program   =", program
-                    print "daemon's args =", args
+                    print("WARNING! zdrun is managing a different program!")
+                    print("our program   =", program)
+                    print("daemon's args =", args)
 
         if options.configroot is not None:
             env = getattr(options.configroot, 'environment', None)
@@ -216,18 +217,19 @@
         sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
         try:
             sock.connect(self.options.sockname)
-            sock.send(action + "\n")
+            sock.send(action.encode() + b"\n")
             sock.shutdown(1) # We're not writing any more
-            response = ""
+            response = b""
             while 1:
                 data = sock.recv(1000)
                 if not data:
                     break
                 response += data
+            return response.decode()
+        except socket.error as msg:
+            return None
+        finally:
             sock.close()
-            return response
-        except socket.error, msg:
-            return None
 
     zd_testing = 0
     def get_status(self):
@@ -266,21 +268,21 @@
                 if self.get_status():
                     was_running = True
                 elif (was_running or n > 10) and not cond(n):
-                    print "\ndaemon manager not running"
+                    print("\ndaemon manager not running")
                     return 1
 
         except KeyboardInterrupt:
-            print "^C"
-        print "\n" + msg % self.__dict__
+            print("^C")
+        print("\n" + msg % self.__dict__)
 
 
     def help_help(self):
-        print "help          -- Print a list of available actions."
-        print "help <action> -- Print help for <action>."
+        print("help          -- Print a list of available actions.")
+        print("help <action> -- Print help for <action>.")
 
     def _start_cond(self, n):
         if (n > self.options.start_timeout):
-            print '\nProgram took too long to start'
+            print('\nProgram took too long to start')
             sys.exit(1)
         return self.zd_pid and not self.zd_testing
 
@@ -315,7 +317,7 @@
         elif not self.zd_pid:
             self.send_action("start")
         else:
-            print "daemon process already running; pid=%d" % self.zd_pid
+            print("daemon process already running; pid=%d" % self.zd_pid)
             return
         if self.options.daemon:
             return self.awhile(
@@ -349,30 +351,30 @@
         return args
 
     def help_start(self):
-        print "start -- Start the daemon process."
-        print "         If it is already running, do nothing."
+        print("start -- Start the daemon process.")
+        print("         If it is already running, do nothing.")
 
     def do_stop(self, arg):
         self.get_status()
         if not self.zd_up:
-            print "daemon manager not running"
+            print("daemon manager not running")
         elif not self.zd_pid:
-            print "daemon process not running"
+            print("daemon process not running")
         else:
             self.send_action("stop")
             self.awhile(lambda n: not self.zd_pid, "daemon process stopped")
 
     def do_reopen_transcript(self, arg):
         if not self.zd_up:
-            print "daemon manager not running"
+            print("daemon manager not running")
         elif not self.zd_pid:
-            print "daemon process not running"
+            print("daemon process not running")
         else:
             self.send_action("reopen_transcript")
 
     def help_stop(self):
-        print "stop -- Stop the daemon process."
-        print "        If it is not running, do nothing."
+        print("stop -- Stop the daemon process.")
+        print("        If it is not running, do nothing.")
 
     def do_restart(self, arg):
         self.get_status()
@@ -385,7 +387,7 @@
                         "daemon process restarted, pid=%(zd_pid)d")
 
     def help_restart(self):
-        print "restart -- Stop and then start the daemon process."
+        print("restart -- Stop and then start the daemon process.")
 
     def do_kill(self, arg):
         if not arg:
@@ -394,149 +396,149 @@
             try:
                 sig = int(arg)
             except: # int() can raise any number of exceptions
-                print "invalid signal number", `arg`
+                print("invalid signal number", repr(arg))
                 return
         self.get_status()
         if not self.zd_pid:
-            print "daemon process not running"
+            print("daemon process not running")
             return
-        print "kill(%d, %d)" % (self.zd_pid, sig)
+        print("kill(%d, %d)" % (self.zd_pid, sig))
         try:
             os.kill(self.zd_pid, sig)
-        except os.error, msg:
-            print "Error:", msg
+        except os.error as msg:
+            print("Error:", msg)
         else:
-            print "signal %d sent to process %d" % (sig, self.zd_pid)
+            print("signal %d sent to process %d" % (sig, self.zd_pid))
 
     def help_kill(self):
-        print "kill [sig] -- Send signal sig to the daemon process."
-        print "              The default signal is SIGTERM."
+        print("kill [sig] -- Send signal sig to the daemon process.")
+        print("              The default signal is SIGTERM.")
 
     def do_wait(self, arg):
         self.awhile(lambda n: not self.zd_pid, "daemon process stopped")
         self.do_status()
 
     def help_wait(self):
-        print "wait -- Wait for the daemon process to exit."
+        print("wait -- Wait for the daemon process to exit.")
 
     def do_status(self, arg=""):
         status = 0
         if arg not in ["", "-l"]:
-            print "status argument must be absent or -l"
+            print("status argument must be absent or -l")
             return 1
         self.get_status()
         if not self.zd_up:
-            print "daemon manager not running"
+            print("daemon manager not running")
             status = 3
         elif not self.zd_pid:
-            print "daemon manager running; daemon process not running"
+            print("daemon manager running; daemon process not running")
         else:
-            print "program running; pid=%d" % self.zd_pid
+            print("program running; pid=%d" % self.zd_pid)
         if arg == "-l" and self.zd_status:
-            print self.zd_status
+            print(self.zd_status)
         return status
 
     def help_status(self):
-        print "status [-l] -- Print status for the daemon process."
-        print "               With -l, show raw status output as well."
+        print("status [-l] -- Print status for the daemon process.")
+        print("               With -l, show raw status output as well.")
 
     def do_show(self, arg):
         if not arg:
             arg = "options"
         try:
             method = getattr(self, "show_" + arg)
-        except AttributeError, err:
-            print err
+        except AttributeError as err:
+            print(err)
             self.help_show()
             return
         method()
 
     def show_options(self):
-        print "zdctl/zdrun options:"
-        print "schemafile:  ", repr(self.options.schemafile)
-        print "configfile:  ", repr(self.options.configfile)
-        print "zdrun:       ", repr(self.options.zdrun)
-        print "python:      ", repr(self.options.python)
-        print "program:     ", repr(self.options.program)
-        print "backofflimit:", repr(self.options.backofflimit)
-        print "daemon:      ", repr(self.options.daemon)
-        print "forever:     ", repr(self.options.forever)
-        print "sockname:    ", repr(self.options.sockname)
-        print "exitcodes:   ", repr(self.options.exitcodes)
-        print "user:        ", repr(self.options.user)
+        print("zdctl/zdrun options:")
+        print("schemafile:  ", repr(self.options.schemafile))
+        print("configfile:  ", repr(self.options.configfile))
+        print("zdrun:       ", repr(self.options.zdrun))
+        print("python:      ", repr(self.options.python))
+        print("program:     ", repr(self.options.program))
+        print("backofflimit:", repr(self.options.backofflimit))
+        print("daemon:      ", repr(self.options.daemon))
+        print("forever:     ", repr(self.options.forever))
+        print("sockname:    ", repr(self.options.sockname))
+        print("exitcodes:   ", repr(self.options.exitcodes))
+        print("user:        ", repr(self.options.user))
         umask = self.options.umask
         if not umask:
             # Here we're just getting the current umask so we can report it:
-            umask = os.umask(0777)
+            umask = os.umask(0o777)
             os.umask(umask)
-        print "umask:       ", oct(umask)
-        print "directory:   ", repr(self.options.directory)
-        print "logfile:     ", repr(self.options.logfile)
+        print("umask:       ", oct(umask))
+        print("directory:   ", repr(self.options.directory))
+        print("logfile:     ", repr(self.options.logfile))
 
     def show_python(self):
-        print "Python info:"
+        print("Python info:")
         version = sys.version.replace("\n", "\n              ")
-        print "Version:     ", version
-        print "Platform:    ", sys.platform
-        print "Executable:  ", repr(sys.executable)
-        print "Arguments:   ", repr(sys.argv)
-        print "Directory:   ", repr(os.getcwd())
-        print "Path:"
+        print("Version:     ", version)
+        print("Platform:    ", sys.platform)
+        print("Executable:  ", repr(sys.executable))
+        print("Arguments:   ", repr(sys.argv))
+        print("Directory:   ", repr(os.getcwd()))
+        print("Path:")
         for dir in sys.path:
-            print "    " + repr(dir)
+            print("    " + repr(dir))
 
     def show_all(self):
         self.show_options()
-        print
+        print()
         self.show_python()
 
     def help_show(self):
-        print "show options -- show zdctl options"
-        print "show python -- show Python version and details"
-        print "show all -- show all of the above"
+        print("show options -- show zdctl options")
+        print("show python -- show Python version and details")
+        print("show all -- show all of the above")
 
     def do_logtail(self, arg):
         if not arg:
             arg = self.options.logfile
             if not arg:
-                print "No default log file specified; use logtail <logfile>"
+                print("No default log file specified; use logtail <logfile>")
                 return
         try:
             helper = TailHelper(arg)
             helper.tailf()
         except KeyboardInterrupt:
-            print
-        except IOError, msg:
-            print msg
-        except OSError, msg:
-            print msg
+            print()
+        except IOError as msg:
+            print(msg)
+        except OSError as msg:
+            print(msg)
 
     def help_logtail(self):
-        print "logtail [logfile] -- Run tail -f on the given logfile."
-        print "                     A default file may exist."
-        print "                     Hit ^C to exit this mode."
+        print("logtail [logfile] -- Run tail -f on the given logfile.")
+        print("                     A default file may exist.")
+        print("                     Hit ^C to exit this mode.")
 
     def do_foreground(self, arg):
         self.get_status()
         pid = self.zd_pid
         if pid:
-            print "To run the program in the foreground, please stop it first."
+            print("To run the program in the foreground, please stop it first.")
             return
 
         program = self.options.program + self.options.args[1:]
-        print " ".join(program)
+        print(" ".join(program))
         sys.stdout.flush()
         try:
             os.spawnlp(os.P_WAIT, program[0], *program)
         except KeyboardInterrupt:
-            print
+            print()
 
     def do_fg(self, arg):
         self.do_foreground(arg)
 
     def help_foreground(self):
-        print "foreground -- Run the program in the forground."
-        print "fg -- an alias for foreground."
+        print("foreground -- Run the program in the forground.")
+        print("fg -- an alias for foreground.")
 
     def help_fg(self):
         self.help_foreground()
@@ -559,7 +561,7 @@
             bytes_added = newsz - sz
             if bytes_added < 0:
                 sz = 0
-                print "==> File truncated <=="
+                print("==> File truncated <==")
                 bytes_added = newsz
             if bytes_added > 0:
                 self.f.seek(-bytes_added, 2)

Modified: zdaemon/trunk/src/zdaemon/zdoptions.py
===================================================================
--- zdaemon/trunk/src/zdaemon/zdoptions.py	2013-02-15 12:53:25 UTC (rev 129431)
+++ zdaemon/trunk/src/zdaemon/zdoptions.py	2013-02-15 13:24:52 UTC (rev 129432)
@@ -11,9 +11,8 @@
 # FOR A PARTICULAR PURPOSE.
 #
 ##############################################################################
-
 """Option processing for zdaemon and related code."""
-
+from __future__ import print_function
 import os
 import sys
 import getopt
@@ -78,7 +77,7 @@
             doc = "No help available."
         elif doc.find("%s") > 0:
             doc = doc.replace("%s", self.progname)
-        print doc,
+        print(doc, end='')
         sys.exit(0)
 
     def usage(self, msg):
@@ -98,9 +97,9 @@
             for n, cn in self.names_list[:]:
                 if n == name:
                     self.names_list.remove((n, cn))
-            if self.default_map.has_key(name):
+            if name in self.default_map:
                 del self.default_map[name]
-            if self.required_map.has_key(name):
+            if name in self.required_map:
                 del self.required_map[name]
         if confname:
             for n, cn in self.names_list[:]:
@@ -108,13 +107,13 @@
                     self.names_list.remove((n, cn))
         if short:
             key = "-" + short[0]
-            if self.options_map.has_key(key):
+            if key in self.options_map:
                 del self.options_map[key]
         if long:
             key = "--" + long
             if key[-1] == "=":
                 key = key[:-1]
-            if self.options_map.has_key(key):
+            if key in self.options_map:
                 del self.options_map[key]
 
     def add(self,
@@ -173,7 +172,7 @@
             if rest not in ("", ":"):
                 raise ValueError("short option should be 'x' or 'x:'")
             key = "-" + key
-            if self.options_map.has_key(key):
+            if key in self.options_map:
                 raise ValueError("duplicate short option key '%s'" % key)
             self.options_map[key] = (name, handler)
             self.short_options.append(short)
@@ -185,7 +184,7 @@
             if key[-1] == "=":
                 key = key[:-1]
             key = "--" + key
-            if self.options_map.has_key(key):
+            if key in self.options_map:
                 raise ValueError("duplicate long option key '%s'" % key)
             self.options_map[key] = (name, handler)
             self.long_options.append(long)
@@ -239,7 +238,7 @@
         try:
             self.options, self.args = getopt.getopt(
                 args, "".join(self.short_options), self.long_options)
-        except getopt.error, msg:
+        except getopt.error as msg:
             if raise_getopt_errs:
                 self.usage(msg)
 
@@ -253,7 +252,7 @@
             if handler is not None:
                 try:
                     arg = handler(arg)
-                except ValueError, msg:
+                except ValueError as msg:
                     self.usage("invalid value for %s %r: %s" % (opt, arg, msg))
             if name and arg is not None:
                 if getattr(self, name) is not None:
@@ -269,12 +268,12 @@
             name, handler = self.environ_map[envvar]
             if name and getattr(self, name, None) is not None:
                 continue
-            if os.environ.has_key(envvar):
+            if envvar in os.environ:
                 value = os.environ[envvar]
                 if handler is not None:
                     try:
                         value = handler(value)
-                    except ValueError, msg:
+                    except ValueError as msg:
                         self.usage("invalid environment value for %s %r: %s"
                                    % (envvar, value, msg))
                 if name and value is not None:
@@ -290,7 +289,7 @@
             self.load_schema()
             try:
                 self.load_configfile()
-            except ZConfig.ConfigurationError, msg:
+            except ZConfig.ConfigurationError as msg:
                 self.usage(str(msg))
 
         # Copy config options to attributes of self.  This only fills
@@ -371,7 +370,7 @@
                  list_of_ints, default=[0, 2])
         self.add("user", "runner.user", "u:", "user=")
         self.add("umask", "runner.umask", "m:", "umask=", octal_type,
-                 default=022)
+                 default=0o22)
         self.add("directory", "runner.directory", "z:", "directory=",
                  existing_parent_directory)
 
@@ -382,7 +381,7 @@
     if not arg:
         return []
     else:
-        return map(int, arg.split(","))
+        return list(map(int, arg.split(",")))
 
 def octal_type(arg):
     return int(arg, 8)
@@ -416,12 +415,12 @@
     # Stupid test program
     z = ZDOptions()
     z.add("program", "zdctl.program", "p:", "program=")
-    print z.names_list
+    print(z.names_list)
     z.realize()
     names = z.names_list[:]
     names.sort()
     for name, confname in names:
-        print "%-20s = %.56r" % (name, getattr(z, name))
+        print("%-20s = %.56r" % (name, getattr(z, name)))
 
 if __name__ == "__main__":
     __file__ = sys.argv[0]

Modified: zdaemon/trunk/src/zdaemon/zdrun.py
===================================================================
--- zdaemon/trunk/src/zdaemon/zdrun.py	2013-02-15 12:53:25 UTC (rev 129431)
+++ zdaemon/trunk/src/zdaemon/zdrun.py	2013-02-15 13:24:52 UTC (rev 129432)
@@ -135,7 +135,7 @@
                 except os.error:
                     continue
                 mode = st[ST_MODE]
-                if mode & 0111:
+                if mode & 0o111:
                     break
             else:
                 self.options.usage("can't find program %r on PATH %s" %
@@ -188,9 +188,10 @@
                         pass
                 try:
                     os.execv(self.filename, self.args)
-                except os.error, err:
+                except os.error as err:
                     sys.stderr.write("can't exec %r: %s\n" %
                                      (self.filename, err))
+                    sys.stderr.flush() # just in case
             finally:
                 os._exit(127)
             # Does not return
@@ -205,7 +206,7 @@
             return "no subprocess running"
         try:
             os.kill(self.pid, sig)
-        except os.error, msg:
+        except os.error as msg:
             return str(msg)
         return None
 
@@ -251,7 +252,7 @@
             sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
             try:
                 sock.bind(tempname)
-                os.chmod(tempname, 0700)
+                os.chmod(tempname, 0o700)
                 try:
                     os.link(tempname, sockname)
                     break
@@ -261,6 +262,7 @@
                     # Stale socket -- delete, sleep, and try again.
                     msg = "Unlinking stale socket %s; sleep 1" % sockname
                     sys.stderr.write(msg + "\n")
+                    sys.stderr.flush() # just in case
                     self.logger.warn(msg)
                     self.unlink_quietly(sockname)
                     sock.close()
@@ -282,17 +284,17 @@
         s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
         try:
             s.connect(self.options.sockname)
-            s.send("status\n")
-            data = s.recv(1000)
+            s.send(b"status\n")
+            data = s.recv(1000).decode()
             s.close()
         except socket.error:
             pass
         else:
-            while data.endswith("\n"):
-                data = data[:-1]
+            data = data.rstrip("\n")
             msg = ("Another zrdun is already up using socket %r:\n%s" %
                    (self.options.sockname, data))
             sys.stderr.write(msg + "\n")
+            sys.stderr.flush() # just in case
             self.logger.critical(msg)
             sys.exit(1)
 
@@ -351,7 +353,7 @@
         if self.options.directory:
             try:
                 os.chdir(self.options.directory)
-            except os.error, err:
+            except os.error as err:
                 self.logger.warn("can't chdir into %r: %s"
                                  % (self.options.directory, err))
             else:
@@ -396,8 +398,8 @@
                         self.delay = time.time() + self.options.backofflimit
             try:
                 r, w, x = select.select(r, w, x, timeout)
-            except select.error, err:
-                if err[0] != errno.EINTR:
+            except select.error as err:
+                if err.args[0] != errno.EINTR:
                     raise
                 r = w = x = []
             if self.waitstatus:
@@ -405,14 +407,14 @@
             if self.commandsocket and self.commandsocket in r:
                 try:
                     self.dorecv()
-                except socket.error, msg:
+                except socket.error as msg:
                     self.logger.exception("socket.error in dorecv(): %s"
                                           % str(msg))
                     self.commandsocket = None
             if self.mastersocket in r:
                 try:
                     self.doaccept()
-                except socket.error, msg:
+                except socket.error as msg:
                     self.logger.exception("socket.error in doaccept(): %s"
                                           % str(msg))
                     self.commandsocket = None
@@ -471,7 +473,7 @@
             self.commandsocket.close()
             self.commandsocket = None
         self.commandsocket, addr = self.mastersocket.accept()
-        self.commandbuffer = ""
+        self.commandbuffer = b""
 
     def dorecv(self):
         data = self.commandsocket.recv(1000)
@@ -480,7 +482,7 @@
             self.commandsocket.close()
             self.commandsocket = None
         self.commandbuffer += data
-        if "\n" in self.commandbuffer:
+        if b"\n" in self.commandbuffer:
             self.docommand()
             self.commandsocket.close()
             self.commandsocket = None
@@ -490,18 +492,18 @@
             self.commandsocket = None
 
     def docommand(self):
-        lines = self.commandbuffer.split("\n")
+        lines = self.commandbuffer.split(b"\n")
         args = lines[0].split()
         if not args:
             self.sendreply("Empty command")
             return
-        command = args[0]
+        command = args[0].decode()
         methodname = "cmd_" + command
         method = getattr(self, methodname, None)
         if method:
-            method(args)
+            method([a.decode() for a in args])
         else:
-            self.sendreply("Unknown command %r; 'help' for a list" % args[0])
+            self.sendreply("Unknown command %r; 'help' for a list" % command)
 
     def cmd_start(self, args):
         self.should_be_up = True
@@ -585,6 +587,7 @@
         try:
             if not msg.endswith("\n"):
                 msg = msg + "\n"
+            msg = msg.encode()
             if hasattr(self.commandsocket, "sendall"):
                 self.commandsocket.sendall(msg)
             else:
@@ -592,7 +595,7 @@
                 while msg:
                     sent = self.commandsocket.send(msg)
                     msg = msg[sent:]
-        except socket.error, msg:
+        except socket.error as msg:
             self.logger.warn("Error sending reply: %s" % str(msg))
 
 
@@ -601,11 +604,11 @@
     def __init__(self, filename):
         self.read_from, w = os.pipe()
         os.dup2(w, 1)
-        sys.stdout = sys.__stdout__ = os.fdopen(1, "a", 0)
+        sys.stdout = sys.__stdout__ = os.fdopen(1, "w", 1)
         os.dup2(w, 2)
-        sys.stderr = sys.__stderr__ = os.fdopen(2, "a", 0)
+        sys.stderr = sys.__stderr__ = os.fdopen(2, "w", 1)
         self.filename = filename
-        self.file = open(filename, 'a', 0)
+        self.file = open(filename, 'ab', 0)
         self.write = self.file.write
         self.lock = threading.Lock()
         thread = threading.Thread(target=self.copy)
@@ -626,7 +629,7 @@
     def reopen(self):
         self.lock.acquire()
         self.file.close()
-        self.file = open(self.filename, 'a', 0)
+        self.file = open(self.filename, 'ab', 0)
         self.write = self.file.write
         self.lock.release()
 
@@ -685,7 +688,7 @@
 def get_path():
     """Return a list corresponding to $PATH, or a default."""
     path = ["/bin", "/usr/bin", "/usr/local/bin"]
-    if os.environ.has_key("PATH"):
+    if "PATH" in os.environ:
         p = os.environ["PATH"]
         if p:
             path = p.split(os.pathsep)

Copied: zdaemon/trunk/tox.ini (from rev 129415, zdaemon/branches/py3/tox.ini)
===================================================================
--- zdaemon/trunk/tox.ini	                        (rev 0)
+++ zdaemon/trunk/tox.ini	2013-02-15 13:24:52 UTC (rev 129432)
@@ -0,0 +1,30 @@
+[tox]
+envlist = py26,py27,py33
+
+[testenv]
+commands =
+    python setup.py test -q
+# without explicit deps, setup.py test will download a bunch of eggs into $PWD
+deps =
+    zc.customdoctests
+    zope.testing
+    zope.testrunner
+    manuel
+    mock
+
+
+[testenv:coverage]
+basepython =
+    python2.7
+commands =
+#   The installed version messes up nose's test discovery / coverage reporting
+#   So, we uninstall that from the environment, and then install the editable
+#   version, before running nosetests.
+    pip uninstall -y zdaemon
+    pip install -e .
+    nosetests --with-xunit --with-xcoverage
+deps =
+    {[testenv]deps}
+    nose
+    coverage
+    nosexcover



More information about the Zodb-checkins mailing list