[Zodb-checkins] CVS: ZODB4 - setup.py:1.1 test.py:1.3

Jeremy Hylton jeremy@zope.com
Wed, 4 Dec 2002 19:01:35 -0500


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

Modified Files:
	test.py 
Added Files:
	setup.py 
Log Message:
Add a setup.py for ZODB4 and make test.py run from build directory.






=== Added File ZODB4/setup.py ===
##############################################################################
#
# Copyright (c) 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.
#
##############################################################################
"""Zope Object Database, object database and persistence, version 4

The Zope Object Database provides an object-oriented database for
Python that provides a high-degree of transparency. Applications can
take advantage of object database features with few, if any, changes
to application logic.  ZODB includes features such as a plugable storage
interface, rich transaction support, and undo.

ZODBv4 is compatible with Python 2.2 new-style classes.
"""

from distutils.core import setup
from distutils.extension import Extension
import glob
import os

# A hack to determine if Extension objects support the depends keyword arg.
if not "depends" in Extension.__init__.func_code.co_varnames:
    # If it doesn't, create a local replacement that removes depends
    # from the kwargs before calling the regular constructor.
    _Extension = Extension
    class Extension(_Extension):
        def __init__(self, name, sources, **kwargs):
            if "depends" in kwargs:
                del kwargs["depends"]
            _Extension.__init__(self, name, sources, **kwargs)

def copy_conf_files(cmd, outputbase):
    inputdir = os.path.join("ZConfig", "tests", "input")
    outputdir = os.path.join(outputbase, inputdir)
    if not os.path.exists(outputdir):
        dir_util.mkpath(outputdir)
    for fn in glob.glob(os.path.join(inputdir, "*.conf")):
        cmd.copy_file(fn, os.path.join(outputbase, fn))

# provide a bunch of customer components that make it possible
# to install a non .py file into one of the packages
from distutils import dir_util
from distutils.core import setup
from distutils.dist import Distribution
from distutils.command.install_lib import install_lib
from distutils.command.build_py import build_py

class MyLibInstaller(install_lib):
    """Custom library installer, used to put hosttab in the right place."""
    # We use the install_lib command since we need to put hosttab
    # inside the library directory.  This is where we already have the
    # real information about where to install it after the library
    # location has been set by any relevant distutils command line
    # options.

    def run(self):
        install_lib.run(self)
        copy_conf_files(self, self.install_dir)

class MyPyBuilder(build_py):
    def build_packages(self):
        build_py.build_packages(self)
        copy_conf_files(self, self.build_lib)

class MyDistribution(Distribution):
    # To control the selection of MyLibInstaller and MyPyBuilder, we
    # have to set it into the cmdclass instance variable, set in
    # Distribution.__init__().

    def __init__(self, *attrs):
        Distribution.__init__(self, *attrs)
        self.cmdclass['build_py'] = MyPyBuilder
        self.cmdclass['install_lib'] = MyLibInstaller

base_btrees_depends = [
    "Persistence/cPersistence.h",
    "Persistence/cPersistenceAPI.h",
    "Persistence/BTrees/BTreeItemsTemplate.c",
    "Persistence/BTrees/BTreeModuleTemplate.c",
    "Persistence/BTrees/BTreeTemplate.c",
    "Persistence/BTrees/BucketTemplate.c",
    "Persistence/BTrees/MergeTemplate.c",
    "Persistence/BTrees/SetOpTemplate.c",
    "Persistence/BTrees/SetTemplate.c",
    "Persistence/BTrees/TreeSetTemplate.c",
    "Persistence/BTrees/sorters.c",
    ]

_flavors = {"O": "object", "I": "int"}

def BTreeExtension(flavor):
    key = flavor[0]
    value = flavor[1]
    name = "Persistence.BTrees._%sBTree" % flavor
    sources = ["Persistence/BTrees/_%sBTree.c" % flavor]
    kwargs = {"include_dirs": ["Persistence"]}
    if flavor != "fs":
        kwargs["depends"] = (base_btrees_depends + 
                   ["Persistence/BTrees/%skeymacros.h" % _flavors[key],
                    "Persistence/BTrees/%svaluemacros.h" % _flavors[value]])
    if key != "O":
        kwargs["define_macros"] = [('EXCLUDE_INTSET_SUPPORT', None)]
    return Extension(name, sources, **kwargs)

ext_modules = [
    BTreeExtension("OO"), BTreeExtension("IO"), BTreeExtension("OI"),
    BTreeExtension("II"), BTreeExtension("fs"),
    Extension("Persistence.cPersistence",
              ["Persistence/cPersistence.c"],
              depends = ["Persistence/cPersistence.h",
                         "Persistence/cPersistenceAPI.h",]),
    Extension("ZODB._TimeStamp", ["ZODB/TimeStamp.c"]),
    Extension("ZODB.winlock", ["ZODB/winlock.c"]),
    ]

packages = [
    "Interface", "Interface.Common", "Interface.Registry",
    "Persistence", "Persistence.BTrees",
    "ThreadedAsync",
    "Transaction",
    "ZConfig",
    "ZEO", "ZEO.zrpc",
    "ZODB",
    ]

try:
    import bsddb3
except ImportError:
    pass
else:
    packages += ["BDBStorage"]
    ext_modules += [Extension("BDBStorage._helper",
                              ["BDBStorage/_helper.c"])]

def hastests(p):
    path = "/".join(p.split(".")) + "/tests"
    return os.path.isdir(path)

packages += ["%s.tests" % p for p in packages if hastests(p)]

doclines = __doc__.split("\n")

setup(name="ZODB4",
      version="4.0a1",
      maintainer="Zope Corporation",
      maintainer_email="zodb-dev@zope.org",
      url = "http://www.zope.org/Wikis/ZODB/FrontPage",
      packages = packages,
      ext_modules = ext_modules,
      headers = ['ZODB/cPersistence.h'],
      license = "http://www.zope.org/Resources/ZPL",
      platforms = ["any"],
      description = doclines[0],
      long_description = "\n".join(doclines[2:]),
      distclass = MyDistribution,
      )


=== ZODB4/test.py 1.2 => 1.3 ===
--- ZODB4/test.py:1.2	Fri Nov 22 16:14:53 2002
+++ ZODB4/test.py	Wed Dec  4 19:01:34 2002
@@ -96,14 +96,13 @@
     want to make sure all tests still pass.
 """
 
-import os
+import os.path
 import pdb
 import re
 import sys
 import traceback
 import unittest
 import linecache
-from os.path import join
 
 from distutils.util import get_platform
 
@@ -163,12 +162,28 @@
 
 # setup list of directories to put on the path
 
+PLAT_SPEC = "%s-%s" % (get_platform(), sys.version[0:3])
+
 def setup_path():
-    DIRS = [".",
+    DIRS = ["lib.%s" % PLAT_SPEC,
             ]
-    cwd = os.getcwd()
     for d in DIRS:
-        sys.path.insert(0, join(cwd, d))
+        sys.path.insert(0, 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
+
+# Find test files.
+# They live under either a lib.PLAT_SPEC or plain "lib" directory.
+_sep = re.escape(os.sep)
+_pat = "%s(%s|lib)%s" % (_sep, re.escape("lib." + PLAT_SPEC), _sep)
+hasgooddir = re.compile(_pat).search
+del _sep, _pat
 
 def match(rx, s):
     if not rx:
@@ -185,23 +200,21 @@
     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
-
+        # Since we're running from the build directory, every dir
+        # should be a file.
+        assert "__init__.py" in files
         for file in files:
             if file[:4] == "test" and file[-3:] == ".py":
-                path = join(dir, file)
+                path = os.path.join(dir, file)
+                if not hasgooddir(path):
+                    # built for a different version
+                    continue
                 if match(rx, path):
                     self.files.append(path)
 
 def find_tests(rx):
     finder = TestFileFinder()
-    os.path.walk(".", finder.visit, rx)
+    os.path.walk("build", finder.visit, rx)
     return finder.files
 
 def package_import(modname):
@@ -219,7 +232,7 @@
     while path:
         path, end = os.path.split(path)
         dirs.insert(0, end)
-    return ".".join(dirs[1:])
+    return ".".join(dirs[2:])
 
 def get_suite(file):
     modname = module_from_path(file)
@@ -228,8 +241,6 @@
     except ImportError, err:
         # print traceback
         print "Error importing %s\n%s" % (modname, err)
-        print_tb_last()
-        print
         if debug:
             raise
         return None
@@ -299,6 +310,7 @@
     files = find_tests(module_filter)
     files.sort()
 
+    os.chdir("build")
     if GUI:
         gui_runner(files, test_filter)
     elif LOOP:
@@ -389,7 +401,7 @@
         gc.set_debug(v)
 
     if build:
-        cmd = sys.executable + " build.py"
+        cmd = sys.executable + " setup.py build"
         if VERBOSE:
             print cmd
         sts = os.system(cmd)
@@ -401,41 +413,9 @@
         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
+    bad = main(module_filter, test_filter)
+    if bad:
+        sys.exit(1)
 
 if __name__ == "__main__":
     process_args()