xref: /petsc/src/binding/petsc4py/test/runtests.py (revision db9fc945a3c8a0a4b4e9c7cf33c611e450ed8efd)
1# Author:  Lisandro Dalcin
2# Contact: dalcinl@gmail.com
3import os
4import sys
5import optparse
6import unittest
7
8__unittest = True
9
10components = [
11    'PETSc',
12]
13
14
15def getoptionparser():
16    parser = optparse.OptionParser()
17
18    parser.add_option("-q", "--quiet",
19                      action="store_const", const=0, dest="verbose", default=1,
20                      help="do not print status messages to stdout")
21    parser.add_option("-v", "--verbose",
22                      action="store_const", const=2, dest="verbose", default=1,
23                      help="print status messages to stdout")
24    parser.add_option("-i", "--include", type="string",
25                      action="append",  dest="include", default=[],
26                      help="include tests matching PATTERN", metavar="PATTERN")
27    parser.add_option("-e", "--exclude", type="string",
28                      action="append", dest="exclude", default=[],
29                      help="exclude tests matching PATTERN", metavar="PATTERN")
30    parser.add_option("-k", "--pattern", type="string",
31                      action="append", dest="patterns", default=[],
32                      help="only run tests which match the given substring")
33    parser.add_option("-f", "--failfast",
34                      action="store_true", dest="failfast", default=False,
35                      help="Stop on first failure")
36    parser.add_option("--no-builddir",
37                      action="store_false", dest="builddir", default=True,
38                      help="disable testing from build directory")
39    parser.add_option("--path", type="string",
40                      action="append", dest="path", default=[],
41                      help="prepend PATH to sys.path", metavar="PATH")
42    parser.add_option("--arch", type="string",
43                      action="store", dest="arch", default=None,
44                      help="use PETSC_ARCH",
45                      metavar="PETSC_ARCH")
46    parser.add_option("-s","--summary",
47                      action="store_true", dest="summary", default=0,
48                      help="print PETSc log summary")
49    parser.add_option("--no-memdebug",
50                      action="store_false", dest="memdebug", default=True,
51                      help="Do not use PETSc memory debugging")
52    return parser
53
54
55def getbuilddir():
56    try:
57        try:
58            from setuptools.dist import Distribution
59        except ImportError:
60            from distutils.dist import Distribution
61        try:
62            from setuptools.command.build import build
63        except ImportError:
64            from distutils.command.build import build
65        cmd_obj = build(Distribution())
66        cmd_obj.finalize_options()
67        return cmd_obj.build_platlib
68    except Exception:
69        return None
70
71
72def getprocessorinfo():
73    try:
74        name = os.uname()[1]
75    except:
76        import platform
77        name = platform.uname()[1]
78    from petsc4py.PETSc import COMM_WORLD
79    rank = COMM_WORLD.getRank()
80    return (rank, name)
81
82
83def getlibraryinfo(name):
84    modname = "%s4py.%s" % (name.lower(), name)
85    module = __import__(modname, fromlist=[name])
86    (major, minor, micro), devel = module.Sys.getVersion(devel=True)
87    r = not devel
88    if r: release = 'release'
89    else: release = 'development'
90    arch = module.__arch__
91    return (
92        "%s %d.%d.%d %s (conf: '%s')" %
93        (name, major, minor, micro, release, arch)
94    )
95
96
97def getpythoninfo():
98    x, y, z = sys.version_info[:3]
99    return ("Python %d.%d.%d (%s)" % (x, y, z, sys.executable))
100
101
102def getpackageinfo(pkg):
103    try:
104        pkg = __import__(pkg)
105    except ImportError:
106        return None
107    name = pkg.__name__
108    version = pkg.__version__
109    path = pkg.__path__[0]
110    return ("%s %s (%s)" % (name, version, path))
111
112
113def setup_python(options):
114    rootdir = os.path.dirname(os.path.dirname(__file__))
115    builddir = os.path.join(rootdir, getbuilddir())
116    if options.builddir and os.path.exists(builddir):
117        sys.path.insert(0, builddir)
118    if options.path:
119        path = options.path[:]
120        path.reverse()
121        for p in path:
122            sys.path.insert(0, p)
123
124
125def setup_unittest(options):
126    from unittest import TestSuite
127    try:
128        from unittest.runner import _WritelnDecorator
129    except ImportError:
130        from unittest import _WritelnDecorator
131    #
132    writeln_orig = _WritelnDecorator.writeln
133    def writeln(self, message=''):
134        try: self.stream.flush()
135        except: pass
136        writeln_orig(self, message)
137        try: self.stream.flush()
138        except: pass
139    _WritelnDecorator.writeln = writeln
140
141
142def import_package(options, pkgname):
143    args = [sys.argv[0]]
144    if options.memdebug:
145        args.append('-malloc_debug')
146        args.append('-malloc_dump')
147    if options.summary:
148        args.append('-log_view')
149    package = __import__(pkgname)
150    package.init(args, arch=options.arch)
151
152
153def print_banner(options):
154    r, n = getprocessorinfo()
155    prefix = "[%d@%s]" % (r, n)
156
157    def writeln(message='', endl='\n'):
158        if message is None:
159            return
160        from petsc4py.PETSc import Sys
161        message = "%s %s" % (prefix, message)
162        Sys.syncPrint(message, endl=endl, flush=True)
163
164    if options.verbose:
165        writeln(getpythoninfo())
166        writeln(getpackageinfo('numpy'))
167        for entry in components:
168            writeln(getlibraryinfo(entry))
169            writeln(getpackageinfo('%s4py' % entry.lower()))
170
171
172def load_tests(options, args):
173    from glob import glob
174    import re
175    testsuitedir = os.path.dirname(__file__)
176    sys.path.insert(0, testsuitedir)
177    pattern = 'test_*.py'
178    wildcard = os.path.join(testsuitedir, pattern)
179    testfiles = glob(wildcard)
180    testfiles.sort()
181    testsuite = unittest.TestSuite()
182    testloader = unittest.TestLoader()
183    if options.patterns:
184        testloader.testNamePatterns = [
185            ('*%s*' % p) if ('*' not in p) else p
186            for p in options.patterns
187        ]
188    include = exclude = None
189    if options.include:
190        include = re.compile('|'.join(options.include)).search
191    if options.exclude:
192        exclude = re.compile('|'.join(options.exclude)).search
193    for testfile in testfiles:
194        filename = os.path.basename(testfile)
195        testname = os.path.splitext(filename)[0]
196        if ((exclude and exclude(testname)) or
197            (include and not include(testname))):
198            continue
199        module = __import__(testname)
200        for arg in args:
201            try:
202                cases = testloader.loadTestsFromNames((arg,), module)
203                testsuite.addTests(cases)
204            except AttributeError:
205                pass
206        if not args:
207            cases = testloader.loadTestsFromModule(module)
208            testsuite.addTests(cases)
209    return testsuite
210
211
212def run_tests(options, testsuite, runner=None):
213    if runner is None:
214        runner = unittest.TextTestRunner(verbosity=options.verbose)
215        runner.failfast = options.failfast
216    result = runner.run(testsuite)
217    return result.wasSuccessful()
218
219
220
221def abort(code=1):
222    os.abort()
223
224
225def shutdown(success):
226    pass
227
228
229def main(args=None):
230    pkgname = '%s4py' % components[-1].lower()
231    parser = getoptionparser()
232    (options, args) = parser.parse_args(args)
233    setup_python(options)
234    setup_unittest(options)
235    import_package(options, pkgname)
236    print_banner(options)
237    testsuite = load_tests(options, args)
238    success = run_tests(options, testsuite)
239    if not success and options.failfast: abort()
240    shutdown(success)
241    return not success
242
243
244if __name__ == '__main__':
245    import sys
246    sys.dont_write_bytecode = True
247    sys.exit(main())
248