[Zope-CVS] CVS: ZODB4 - LICENSE.txt:1.1 README.txt:1.1 build.py:1.1 test.py:1.1

Jeremy Hylton jeremy@zope.com
Tue, 25 Jun 2002 13:29:23 -0400


Update of /cvs-repository/ZODB4
In directory cvs.zope.org:/tmp/cvs-serv1645

Added Files:
	LICENSE.txt README.txt build.py test.py 
Log Message:
Add reademe, license, build, & test scripts


=== Added File ZODB4/LICENSE.txt ===
Zope Public License (ZPL) Version 2.0
-----------------------------------------------

This software is Copyright (c) Zope Corporation (tm) and
Contributors. All rights reserved.

This license has been certified as open source. It has also
been designated as GPL compatible by the Free Software
Foundation (FSF).

Redistribution and use in source and binary forms, with or
without modification, are permitted provided that the
following conditions are met:

1. Redistributions in source code must retain the above
   copyright notice, this list of conditions, and the following
   disclaimer.

2. Redistributions in binary form must reproduce the above
   copyright notice, this list of conditions, and the following
   disclaimer in the documentation and/or other materials
   provided with the distribution.

3. The name Zope Corporation (tm) must not be used to
   endorse or promote products derived from this software
   without prior written permission from Zope Corporation.

4. The right to distribute this software or to use it for
   any purpose does not give you the right to use Servicemarks
   (sm) or Trademarks (tm) of Zope Corporation. Use of them is
   covered in a separate agreement (see
   http://www.zope.com/Marks).

5. If any files are modified, you must cause the modified
   files to carry prominent notices stating that you changed
   the files and the date of any change.

Disclaimer

  THIS SOFTWARE IS PROVIDED BY ZOPE CORPORATION ``AS IS''
  AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
  NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
  AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
  NO EVENT SHALL ZOPE CORPORATION OR ITS CONTRIBUTORS BE
  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
  OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
  DAMAGE.


This software consists of contributions made by Zope
Corporation and many individuals on behalf of Zope
Corporation.  Specific attributions are listed in the
accompanying credits file.


=== Added File ZODB4/README.txt ===
Welcome to the ZODB4 source

  ZODB4 is being developed as part of the Zope3 project.  There is
  more developer info in the Zope3 Wiki:
  http://dev.zope.org/Wikis/DevSite/Projects/ComponentArchitecture/
  Zope3DeveloperInfo

  That's one URL split over two lines.

Building and running tests

  ZODB4 requires Python 2.2 or higher

  In the top-level ZODB4 directory, you should find a script called
  build.py.  Run it to build the extension modules needed by
  ZODB.  Example:

  # cd src/ZODB4
  # python2.2 build.py

  ZODB3 includes unit tests based on the Python unittest module.  If
  you checkin changes, you should verify that all the tests succeed
  before you checkin.

  To run all the tests, use the script test.py.
  # python test.py -v

  Use test.py -h for usage.  The test script can run selected tests,
  stop after the first error, run the tests in a loop, etc.


=== Added File ZODB4/build.py ===
##############################################################################
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# All Rights Reserved.
# 
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
# 
##############################################################################
"""
Really stupid in-place builder for C extensions that are linked in to ZODB4.

usage:

$ cd /path/to/ZODB4
$ python2.2 build.py

Usage with a specific compiler such as mingw32:

$ python2.2 build.py -c mingw32
"""

import sys, os

def remove_stale_bytecode(arg, dirname, names):
    names = [os.path.normcase(n) for n in names]
    for name in names:
        if name.endswith(".pyc") or name.endswith(".pyo"):
            srcname = name[:-1]
            if srcname not in names:
                fullname = os.path.join(dirname, name)
                print "Removing stale bytecode file", fullname
                os.unlink(fullname)

def visit(setup_dirs, dirname, names):
    remove_stale_bytecode(None, dirname, names)
    if 'setup.py' in names:
        setup_dirs.append(dirname)

def main():
    setup_dirs = []
    os.path.walk(os.getcwd(), visit, setup_dirs)
    args = tuple(sys.argv[1:])
##    if not args:
##        args = ('clean',)
    for dir in setup_dirs:
        print "Building extensions in %s" % dir
        os.chdir(dir)
        os.spawnl(os.P_WAIT, sys.executable,
                  sys.executable, "setup.py", 'build_ext', '-i', *args)
        print

if __name__ == "__main__":
    main()


=== Added File ZODB4/test.py ===
##############################################################################
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# All Rights Reserved.
# 
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
# 
##############################################################################
"""
test.py [-bdvvL] [modfilter [testfilter]]

Test harness.

-b  build
    Run "python setup.py -q build" before running tests, where "python"
    is the version of python used to run test.py.  Highly recommended.

-d  debug
    Instead of the normal test harness, run a debug version which
    doesn't catch any exceptions.  This is occasionally handy when the
    unittest code catching the exception doesn't work right.
    Unfortunately, the debug harness doesn't print the name of the
    test, so Use With Care.

-v  verbose
    With one -v, unittest prints a dot (".") for each test run.  With
    -vv, unittest prints the name of each test (for some definition of
    "name" ...).  Witn no -v, unittest is silent until the end of the
    run, except when errors occur.

-L  Loop
    Keep running the selected tests in a loop.  You may experience
    memory leakage.

-g  threshold
    Set the garbage collector generation0 threshold.  This can be used to
    stress memory and gc correctness.  Some crashes are only reproducible when
    the threshold is set to 1 (agressive garbage collection).  Do "-g 0" to
    disable garbage collection altogether.

modfilter
testfilter
    Case-sensitive regexps to limit which tests are run, used in search
    (not match) mode.
    In an extension of Python regexp notation, a leading "!" is stripped
    and causes the sense of the remaining regexp to be negated (so "!bc"
    matches any string that does not match "bc", and vice versa).
    By default these act like ".", i.e. nothing is excluded.

    modfilter is applied to a test file's path, starting at "build" and
    including (OS-dependent) path separators.

    testfilter is applied to the (method) name of the unittest methods
    contained in the test files whose paths modfilter matched.

Extreme (yet useful) examples:

    test.py -vvb . "^checkWriteClient$"

    Builds the project silently, then runs unittest in verbose mode on all
    tests whose names are precisely "checkWriteClient".  Useful when
    debugging a specific test.

    test.py -vvb . "!^checkWriteClient$"

    As before, but runs all tests whose names aren't precisely
    "checkWriteClient".  Useful to avoid a specific failing test you don't
    want to deal with just yet.
"""

import os
import re
import sys
import traceback
import unittest
import linecache
from os.path import join

from distutils.util import get_platform

class ImmediateTestResult(unittest._TextTestResult):

    __super_init = unittest._TextTestResult.__init__

    def __init__(self, *args, **kwarg):
        debug = kwarg.get('debug')
        if debug is not None:
            del kwarg['debug']
        self.__super_init(*args, **kwarg)
        self._debug = debug
        
    def _print_traceback(self, msg, err, test, errlist):
        if self.showAll or self.dots:
            self.stream.writeln("\n")

        tb = ''.join(traceback.format_exception(*err))
        self.stream.writeln(msg)
        self.stream.writeln(tb)
        errlist.append((test, tb))

    def addError(self, test, err):
        if self._debug:
            raise err[0], err[1], err[2]
        self._print_traceback("Error in test %s" % test, err,
                              test, self.errors)

    def addFailure(self, test, err):
        if self._debug:
            raise err[0], err[1], err[2]
        self._print_traceback("Failure in test %s" % test, err,
                              test, self.failures)

    def printErrorList(self, flavor, errors):
        for test, err in errors:
            self.stream.writeln(self.separator1)
            self.stream.writeln("%s: %s" % (flavor, self.getDescription(test)))
            self.stream.writeln(self.separator2)
            self.stream.writeln(err)

class ImmediateTestRunner(unittest.TextTestRunner):

    __super_init = unittest.TextTestRunner.__init__

    def __init__(self, **kwarg):
        debug = kwarg.get('debug')
        if debug is not None:
            del kwarg['debug']
        self.__super_init(**kwarg)
        self._debug = debug

    def _makeResult(self):
        return ImmediateTestResult(self.stream, self.descriptions,
                                   self.verbosity, debug=self._debug)

# setup list of directories to put on the path

def setup_path():
    DIRS = [".",
            ]
    cwd = os.getcwd()
    for d in DIRS:
        sys.path.insert(0, join(cwd, d))

def match(rx, s):
    if not rx:
        return 1
    if rx[0] == '!':
        return re.search(rx[1:], s) is None
    else:
        return re.search(rx, s) is not None

class TestFileFinder:
    def __init__(self):
        self.files = []

    def visit(self, rx, dir, files):
        if dir[-5:] != "tests":
            return
        # ignore tests that aren't in packages
        if not "__init__.py" in files:
            if not files or files == ['CVS']:
                return

            print "not a package", dir
            return

        for file in files:
            if file[:4] == "test" and file[-3:] == ".py":
                path = join(dir, file)
                if match(rx, path):
                    self.files.append(path)

def find_tests(rx):
    finder = TestFileFinder()
    os.path.walk(".", finder.visit, rx)
    return finder.files

def package_import(modname):
    mod = __import__(modname)
    for part in modname.split(".")[1:]:
        mod = getattr(mod, part)
    return mod

def module_from_path(path):
    """Return the Python package name indiciated by the filesystem path."""

    assert path.endswith('.py')
    path = path[:-3]
    dirs = []
    while path:
        path, end = os.path.split(path)
        dirs.insert(0, end)
    return ".".join(dirs[1:])

def get_suite(file):
    modname = module_from_path(file)
    try:
        mod = package_import(modname)
    except ImportError, err:
        # print traceback
        print "Error importing %s\n%s" % (modname, err)
        print_tb_last()
        print
        if debug:
            raise
        return None
    try:
        suite_func = mod.test_suite
    except AttributeError:
        print "No test_suite() in %s" % file
        return None
    return suite_func()

def filter_testcases(s, rx):
    new = unittest.TestSuite()
    for test in s._tests:
        if isinstance(test, unittest.TestCase):
            name = test.id() # Full test name: package.module.class.method
            name = name[1 + name.rfind('.'):] # extract method name
            if match(rx, name):
                new.addTest(test)
        else:
            filtered = filter_testcases(test, rx)
            if filtered:
                new.addTest(filtered)
    return new

def runner(files, test_filter, debug):
    runner = ImmediateTestRunner(verbosity=VERBOSE, debug=debug)
    suite = unittest.TestSuite()
    for file in files:
        s = get_suite(file)
        if s is not None:
            if test_filter is not None:
                s = filter_testcases(s, test_filter)
            suite.addTest(s)
    r = runner.run(suite)

def remove_stale_bytecode(arg, dirname, names):
    names = map(os.path.normcase, names)
    for name in names:
        if name.endswith(".pyc") or name.endswith(".pyo"):
            srcname = name[:-1]
            if srcname not in names:
                fullname = os.path.join(dirname, name)
                print "Removing stale bytecode file", fullname
                os.unlink(fullname)

def main(module_filter, test_filter):
    os.path.walk(os.curdir, remove_stale_bytecode, None)
    setup_path()
    files = find_tests(module_filter)
    files.sort()

    if LOOP:
        while 1:
            runner(files, test_filter, debug)
    else:
        runner(files, test_filter, debug)


def process_args():
    import getopt
    global module_filter
    global test_filter
    global VERBOSE
    global LOOP
    global debug
    global build
    global gcthresh

    module_filter = None
    test_filter = None
    VERBOSE = 0
    LOOP = 0
    debug = 0 # Don't collect test results; simply let tests crash
    build = 0
    gcthresh = None

    try:
        opts, args = getopt.getopt(sys.argv[1:], 'vdLbhCg:',
                                   ['help'])
    except getopt.error, msg:
        print msg
        print "Try `python %s -h' for more information." % sys.argv[0]
        sys.exit(2)

    for k, v in opts:
        if k == '-v':
            VERBOSE += 1
        elif k == '-d':
            debug = 1
        elif k == '-L':
            LOOP = 1
        elif k == '-b':
            build = 1
        elif k in ('-h', '--help'):
            print __doc__
            sys.exit(0)
        elif k == '-C':
            import pychecker.checker
        elif k == '-g':
            gcthresh = int(v)

    if gcthresh is not None:
        import gc
        gc.set_threshold(gcthresh)
        print 'gc threshold:', gc.get_threshold()

    if build:
        cmd = sys.executable + " build.py"
        if VERBOSE:
            print cmd
        sts = os.system(cmd)
        if sts:
            print "Build failed", hex(sts)
            sys.exit(1)

    if args:
        if len(args) > 1:
            test_filter = args[1]
        module_filter = args[0]
    try:
        bad = main(module_filter, test_filter)
        if bad:
            sys.exit(1)
    except ImportError, err:
        print err
        print sys.path
        raise



def print_tb_last():
    """Print up to 'limit' stack trace entries from the traceback 'tb'.

    If 'limit' is omitted or None, all entries are printed.  If 'file'
    is omitted or None, the output goes to sys.stderr; otherwise
    'file' should be an open file or file-like object with a write()
    method.
    """
    tb = sys.exc_info()[2]
    file = sys.stderr
    while 1:
        f = tb.tb_frame
        lineno = traceback.tb_lineno(tb)
        tb = tb.tb_next
        if tb is not None:
            continue

        co = f.f_code
        filename = co.co_filename
        name = co.co_name
        file.write('  File "%s", line %d, in %s\n' % (filename,lineno,name))
        line = linecache.getline(filename, lineno)
        if line: file.write('    %s\n' % line.strip())
        break

if __name__ == "__main__":
    process_args()