~launchpad/zope.testing/3.9.4-p4

« back to all changes in this revision

Viewing changes to src/zope/testing/testrunner/options.py

  • Committer: Maris Fogels
  • Date: 2010-06-04 14:58:44 UTC
  • Revision ID: maris.fogels@canonical.com-20100604145844-mb48c1ig9gty2kao
Initial import of zope.testing's 3.9.4 SVN tag

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
##############################################################################
 
2
#
 
3
# Copyright (c) 2004-2008 Zope Foundation and Contributors.
 
4
# All Rights Reserved.
 
5
#
 
6
# This software is subject to the provisions of the Zope Public License,
 
7
# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
 
8
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
 
9
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 
10
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
 
11
# FOR A PARTICULAR PURPOSE.
 
12
#
 
13
##############################################################################
 
14
"""Command-line option parsing
 
15
 
 
16
$Id: __init__.py 86231 2008-05-03 15:03:27Z ctheune $
 
17
"""
 
18
 
 
19
import optparse
 
20
import re
 
21
import os
 
22
import sys
 
23
 
 
24
import pkg_resources
 
25
 
 
26
from zope.testing.testrunner.profiling import available_profilers
 
27
from zope.testing.testrunner.formatter import (
 
28
    OutputFormatter,
 
29
    ColorfulOutputFormatter,
 
30
    SubunitOutputFormatter,
 
31
    )
 
32
from zope.testing.testrunner.formatter import terminal_has_colors
 
33
 
 
34
 
 
35
parser = optparse.OptionParser("Usage: %prog [options] [MODULE] [TEST]")
 
36
 
 
37
######################################################################
 
38
# Searching and filtering
 
39
 
 
40
searching = optparse.OptionGroup(parser, "Searching and filtering", """\
 
41
Options in this group are used to define which tests to run.
 
42
""")
 
43
 
 
44
searching.add_option(
 
45
    '--package', '--dir', '-s', action="append", dest='package',
 
46
    help="""\
 
47
Search the given package's directories for tests.  This can be
 
48
specified more than once to run tests in multiple parts of the source
 
49
tree.  For example, if refactoring interfaces, you don't want to see
 
50
the way you have broken setups for tests in other packages. You *just*
 
51
want to run the interface tests.
 
52
 
 
53
Packages are supplied as dotted names.  For compatibility with the old
 
54
test runner, forward and backward slashed in package names are
 
55
converted to dots.
 
56
 
 
57
(In the special case of packages spread over multiple directories,
 
58
only directories within the test search path are searched. See the
 
59
--path option.)
 
60
 
 
61
""")
 
62
 
 
63
searching.add_option(
 
64
    '--module', '-m', action="append", dest='module',
 
65
    help="""\
 
66
Specify a test-module filter as a regular expression.  This is a
 
67
case-sensitive regular expression, used in search (not match) mode, to
 
68
limit which test modules are searched for tests.  The regular
 
69
expressions are checked against dotted module names.  In an extension
 
70
of Python regexp notation, a leading "!" is stripped and causes the
 
71
sense of the remaining regexp to be negated (so "!bc" matches any
 
72
string that does not match "bc", and vice versa).  The option can be
 
73
specified multiple test-module filters.  Test modules matching any of
 
74
the test filters are searched.  If no test-module filter is specified,
 
75
then all test modules are used.
 
76
""")
 
77
 
 
78
searching.add_option(
 
79
    '--test', '-t', action="append", dest='test',
 
80
    help="""\
 
81
Specify a test filter as a regular expression.  This is a
 
82
case-sensitive regular expression, used in search (not match) mode, to
 
83
limit which tests are run.  In an extension of Python regexp notation,
 
84
a leading "!" is stripped and causes the sense of the remaining regexp
 
85
to be negated (so "!bc" matches any string that does not match "bc",
 
86
and vice versa).  The option can be specified multiple test filters.
 
87
Tests matching any of the test filters are included.  If no test
 
88
filter is specified, then all tests are run.
 
89
""")
 
90
 
 
91
searching.add_option(
 
92
    '--unit', '-u', action="store_true", dest='unit',
 
93
    help="""\
 
94
Run only unit tests, ignoring any layer options.
 
95
""")
 
96
 
 
97
searching.add_option(
 
98
    '--non-unit', '-f', action="store_true", dest='non_unit',
 
99
    help="""\
 
100
Run tests other than unit tests.
 
101
""")
 
102
 
 
103
searching.add_option(
 
104
    '--layer', action="append", dest='layer',
 
105
    help="""\
 
106
Specify a test layer to run.  The option can be given multiple times
 
107
to specify more than one layer.  If not specified, all layers are run.
 
108
It is common for the running script to provide default values for this
 
109
option.  Layers are specified regular expressions, used in search
 
110
mode, for dotted names of objects that define a layer.  In an
 
111
extension of Python regexp notation, a leading "!" is stripped and
 
112
causes the sense of the remaining regexp to be negated (so "!bc"
 
113
matches any string that does not match "bc", and vice versa).  The
 
114
layer named 'zope.testing.testrunner.layer.UnitTests' is reserved for
 
115
unit tests, however, take note of the --unit and non-unit options.
 
116
""")
 
117
 
 
118
searching.add_option(
 
119
    '-a', '--at-level', type='int', dest='at_level',
 
120
    help="""\
 
121
Run the tests at the given level.  Any test at a level at or below
 
122
this is run, any test at a level above this is not run.  Level 0
 
123
runs all tests.
 
124
""")
 
125
 
 
126
searching.add_option(
 
127
    '--all', action="store_true", dest='all',
 
128
    help="Run tests at all levels.")
 
129
 
 
130
searching.add_option(
 
131
    '--list-tests', action="store_true", dest='list_tests',
 
132
    help="List all tests that matched your filters.  Do not run any tests.")
 
133
 
 
134
parser.add_option_group(searching)
 
135
 
 
136
######################################################################
 
137
# Reporting
 
138
 
 
139
reporting = optparse.OptionGroup(parser, "Reporting", """\
 
140
Reporting options control basic aspects of test-runner output
 
141
""")
 
142
 
 
143
reporting.add_option(
 
144
    '--verbose', '-v', action="count", dest='verbose',
 
145
    help="""\
 
146
Make output more verbose.
 
147
Increment the verbosity level.
 
148
""")
 
149
 
 
150
reporting.add_option(
 
151
    '--quiet', '-q', action="store_true", dest='quiet',
 
152
    help="""\
 
153
Make the output minimal, overriding any verbosity options.
 
154
""")
 
155
 
 
156
reporting.add_option(
 
157
    '--progress', '-p', action="store_true", dest='progress',
 
158
    help="""\
 
159
Output progress status
 
160
""")
 
161
 
 
162
reporting.add_option(
 
163
    '--no-progress',action="store_false", dest='progress',
 
164
    help="""\
 
165
Do not output progress status.  This is the default, but can be used to
 
166
counter a previous use of --progress or -p.
 
167
""")
 
168
 
 
169
# We use a noop callback because the actual processing will be done in the
 
170
# get_options function, but we want optparse to generate appropriate help info
 
171
# for us, so we add an option anyway.
 
172
reporting.add_option(
 
173
    '--auto-progress', action="callback", callback=lambda *args: None,
 
174
    help="""\
 
175
Output progress status, but only when stdout is a terminal.
 
176
""")
 
177
 
 
178
reporting.add_option(
 
179
    '--color', '-c', action="store_true", dest='color',
 
180
    help="""\
 
181
Colorize the output.
 
182
""")
 
183
 
 
184
reporting.add_option(
 
185
    '--no-color', '-C', action="store_false", dest='color',
 
186
    help="""\
 
187
Do not colorize the output.  This is the default, but can be used to
 
188
counter a previous use of --color or -c.
 
189
""")
 
190
 
 
191
# We use a noop callback because the actual processing will be done in the
 
192
# get_options function, but we want optparse to generate appropriate help info
 
193
# for us, so we add an option anyway.
 
194
reporting.add_option(
 
195
    '--auto-color', action="callback", callback=lambda *args: None,
 
196
    help="""\
 
197
Colorize the output, but only when stdout is a terminal.
 
198
""")
 
199
 
 
200
reporting.add_option(
 
201
    '--subunit', action="store_true", dest='subunit',
 
202
    help="""\
 
203
Use subunit output. Will not be colorized.
 
204
""")
 
205
 
 
206
reporting.add_option(
 
207
    '--slow-test', type='float', dest='slow_test_threshold', metavar='N',
 
208
    help="""\
 
209
With -c and -vvv, highlight tests that take longer than N seconds (default:
 
210
%default).
 
211
""")
 
212
 
 
213
reporting.add_option(
 
214
    '-1', '--hide-secondary-failures',
 
215
    action="store_true", dest='report_only_first_failure',
 
216
    help="""\
 
217
Report only the first failure in a doctest. (Examples after the
 
218
failure are still executed, in case they do any cleanup.)
 
219
""")
 
220
 
 
221
reporting.add_option(
 
222
    '--show-secondary-failures',
 
223
    action="store_false", dest='report_only_first_failure',
 
224
    help="""\
 
225
Report all failures in a doctest.  This is the default, but can
 
226
be used to counter a default use of -1 or --hide-secondary-failures.
 
227
""")
 
228
 
 
229
reporting.add_option(
 
230
    '--ndiff', action="store_true", dest="ndiff",
 
231
    help="""\
 
232
When there is a doctest failure, show it as a diff using the ndiff.py utility.
 
233
""")
 
234
 
 
235
reporting.add_option(
 
236
    '--udiff', action="store_true", dest="udiff",
 
237
    help="""\
 
238
When there is a doctest failure, show it as a unified diff.
 
239
""")
 
240
 
 
241
reporting.add_option(
 
242
    '--cdiff', action="store_true", dest="cdiff",
 
243
    help="""\
 
244
When there is a doctest failure, show it as a context diff.
 
245
""")
 
246
 
 
247
parser.add_option_group(reporting)
 
248
 
 
249
######################################################################
 
250
# Analysis
 
251
 
 
252
analysis = optparse.OptionGroup(parser, "Analysis", """\
 
253
Analysis options provide tools for analysing test output.
 
254
""")
 
255
 
 
256
 
 
257
analysis.add_option(
 
258
    '--stop-on-error', '--stop', '-x', action="store_true",
 
259
    dest='stop_on_error',
 
260
    help="Stop running tests after first test failure or error."
 
261
    )
 
262
 
 
263
analysis.add_option(
 
264
    '--post-mortem', '--pdb', '-D', action="store_true", dest='post_mortem',
 
265
    help="Enable post-mortem debugging of test failures"
 
266
    )
 
267
 
 
268
 
 
269
analysis.add_option(
 
270
    '--gc', '-g', action="append", dest='gc', type="int",
 
271
    help="""\
 
272
Set the garbage collector generation threshold.  This can be used
 
273
to stress memory and gc correctness.  Some crashes are only
 
274
reproducible when the threshold is set to 1 (aggressive garbage
 
275
collection).  Do "--gc 0" to disable garbage collection altogether.
 
276
 
 
277
The --gc option can be used up to 3 times to specify up to 3 of the 3
 
278
Python gc_threshold settings.
 
279
 
 
280
""")
 
281
 
 
282
analysis.add_option(
 
283
    '--gc-option', '-G', action="append", dest='gc_option', type="choice",
 
284
    choices=['DEBUG_STATS', 'DEBUG_COLLECTABLE', 'DEBUG_UNCOLLECTABLE',
 
285
             'DEBUG_INSTANCES', 'DEBUG_OBJECTS', 'DEBUG_SAVEALL',
 
286
             'DEBUG_LEAK'],
 
287
    help="""\
 
288
Set a Python gc-module debug flag.  This option can be used more than
 
289
once to set multiple flags.
 
290
""")
 
291
 
 
292
analysis.add_option(
 
293
    '--repeat', '-N', action="store", type="int", dest='repeat',
 
294
    help="""\
 
295
Repeat the tests the given number of times.  This option is used to
 
296
make sure that tests leave their environment in the state they found
 
297
it and, with the --report-refcounts option to look for memory leaks.
 
298
""")
 
299
 
 
300
analysis.add_option(
 
301
    '--report-refcounts', '-r', action="store_true", dest='report_refcounts',
 
302
    help="""\
 
303
After each run of the tests, output a report summarizing changes in
 
304
refcounts by object type.  This option that requires that Python was
 
305
built with the --with-pydebug option to configure.
 
306
""")
 
307
 
 
308
analysis.add_option(
 
309
    '--coverage', action="store", type='string', dest='coverage',
 
310
    help="""\
 
311
Perform code-coverage analysis, saving trace data to the directory
 
312
with the given name.  A code coverage summary is printed to standard
 
313
out.
 
314
""")
 
315
 
 
316
analysis.add_option(
 
317
    '--profile', action="store", dest='profile', type="choice",
 
318
    choices=available_profilers.keys(),
 
319
    help="""\
 
320
Run the tests under cProfiler or hotshot and display the top 50 stats, sorted
 
321
by cumulative time and number of calls.
 
322
""")
 
323
 
 
324
def do_pychecker(*args):
 
325
    if not os.environ.get("PYCHECKER"):
 
326
        os.environ["PYCHECKER"] = "-q"
 
327
    import pychecker.checker
 
328
 
 
329
analysis.add_option(
 
330
    '--pychecker', action="callback", callback=do_pychecker,
 
331
    help="""\
 
332
Run the tests under pychecker
 
333
""")
 
334
 
 
335
parser.add_option_group(analysis)
 
336
 
 
337
######################################################################
 
338
# Setup
 
339
 
 
340
setup = optparse.OptionGroup(parser, "Setup", """\
 
341
Setup options are normally supplied by the testrunner script, although
 
342
they can be overridden by users.
 
343
""")
 
344
 
 
345
setup.add_option(
 
346
    '--path', action="append", dest='path',
 
347
    help="""\
 
348
Specify a path to be added to Python's search path.  This option can
 
349
be used multiple times to specify multiple search paths.  The path is
 
350
usually specified by the test-runner script itself, rather than by
 
351
users of the script, although it can be overridden by users.  Only
 
352
tests found in the path will be run.
 
353
 
 
354
This option also specifies directories to be searched for tests.
 
355
See the search_directory.
 
356
""")
 
357
 
 
358
setup.add_option(
 
359
    '--test-path', action="append", dest='test_path',
 
360
    help="""\
 
361
Specify a path to be searched for tests, but not added to the Python
 
362
search path.  This option can be used multiple times to specify
 
363
multiple search paths.  The path is usually specified by the
 
364
test-runner script itself, rather than by users of the script,
 
365
although it can be overridden by users.  Only tests found in the path
 
366
will be run.
 
367
""")
 
368
 
 
369
setup.add_option(
 
370
    '--package-path', action="append", dest='package_path', nargs=2,
 
371
    help="""\
 
372
Specify a path to be searched for tests, but not added to the Python
 
373
search path.  Also specify a package for files found in this path.
 
374
This is used to deal with directories that are stitched into packages
 
375
that are not otherwise searched for tests.
 
376
 
 
377
This option takes 2 arguments.  The first is a path name. The second is
 
378
the package name.
 
379
 
 
380
This option can be used multiple times to specify
 
381
multiple search paths.  The path is usually specified by the
 
382
test-runner script itself, rather than by users of the script,
 
383
although it can be overridden by users.  Only tests found in the path
 
384
will be run.
 
385
""")
 
386
 
 
387
setup.add_option(
 
388
    '--tests-pattern', action="store", dest='tests_pattern',
 
389
    help="""\
 
390
The test runner looks for modules containing tests.  It uses this
 
391
pattern to identify these modules.  The modules may be either packages
 
392
or python files.
 
393
 
 
394
If a test module is a package, it uses the value given by the
 
395
test-file-pattern to identify python files within the package
 
396
containing tests.
 
397
""")
 
398
 
 
399
setup.add_option(
 
400
    '--suite-name', action="store", dest='suite_name',
 
401
    help="""\
 
402
Specify the name of the object in each test_module that contains the
 
403
module's test suite.
 
404
""")
 
405
 
 
406
setup.add_option(
 
407
    '--test-file-pattern', action="store", dest='test_file_pattern',
 
408
    help="""\
 
409
Specify a pattern for identifying python files within a tests package.
 
410
See the documentation for the --tests-pattern option.
 
411
""")
 
412
 
 
413
setup.add_option(
 
414
    '--ignore_dir', action="append", dest='ignore_dir',
 
415
    help="""\
 
416
Specifies the name of a directory to ignore when looking for tests.
 
417
""")
 
418
 
 
419
setup.add_option(
 
420
    '--shuffle', action="store_true", dest='shuffle',
 
421
    help="""\
 
422
Shuffles the order in which tests are ran.
 
423
""")
 
424
 
 
425
setup.add_option(
 
426
    '--shuffle-seed', action="store", dest='shuffle_seed', type="int",
 
427
    help="""\
 
428
Value used to initialize the tests shuffler. Specify a value to create
 
429
repeatable random ordered tests.
 
430
""")
 
431
 
 
432
parser.add_option_group(setup)
 
433
 
 
434
######################################################################
 
435
# Other
 
436
 
 
437
other = optparse.OptionGroup(parser, "Other", "Other options")
 
438
 
 
439
other.add_option(
 
440
    '--version', action="store_true", dest='showversion',
 
441
    help="Print the version of the testrunner, and exit.")
 
442
 
 
443
other.add_option(
 
444
    '-j', action="store", type="int", dest='processes',
 
445
    help="""\
 
446
Use up to given number of parallel processes to execute tests.  May decrease
 
447
test run time substantially.  Defaults to %default.
 
448
""")
 
449
 
 
450
other.add_option(
 
451
    '--keepbytecode', '-k', action="store_true", dest='keepbytecode',
 
452
    help="""\
 
453
Normally, the test runner scans the test paths and the test
 
454
directories looking for and deleting pyc or pyo files without
 
455
corresponding py files.  This is to prevent spurious test failures due
 
456
to finding compiled modules where source modules have been deleted.
 
457
This scan can be time consuming.  Using this option disables this
 
458
scan.  If you know you haven't removed any modules since last running
 
459
the tests, can make the test run go much faster.
 
460
""")
 
461
 
 
462
other.add_option(
 
463
    '--usecompiled', action="store_true", dest='usecompiled',
 
464
    help="""\
 
465
Normally, a package must contain an __init__.py file, and only .py files
 
466
can contain test code.  When this option is specified, compiled Python
 
467
files (.pyc and .pyo) can be used instead:  a directory containing
 
468
__init__.pyc or __init__.pyo is also considered to be a package, and if
 
469
file XYZ.py contains tests but is absent while XYZ.pyc or XYZ.pyo exists
 
470
then the compiled files will be used.  This is necessary when running
 
471
tests against a tree where the .py files have been removed after
 
472
compilation to .pyc/.pyo.  Use of this option implies --keepbytecode.
 
473
""")
 
474
 
 
475
other.add_option(
 
476
    '--exit-with-status', action="store_true", dest='exitwithstatus',
 
477
    help="""DEPRECATED: The test runner will always exit with a status.\
 
478
""")
 
479
 
 
480
 
 
481
parser.add_option_group(other)
 
482
 
 
483
######################################################################
 
484
# Default values
 
485
 
 
486
parser.set_defaults(
 
487
    ignore_dir=['.svn', 'CVS', '{arch}', '.arch-ids', '_darcs'],
 
488
    tests_pattern='^tests$',
 
489
    at_level=1,
 
490
    test_file_pattern='^test',
 
491
    suite_name='test_suite',
 
492
    list_tests=False,
 
493
    slow_test_threshold=10,
 
494
    processes=1,
 
495
    )
 
496
 
 
497
 
 
498
######################################################################
 
499
# Command-line processing
 
500
 
 
501
def compile_filter(pattern):
 
502
    if pattern.startswith('!'):
 
503
        pattern = re.compile(pattern[1:]).search
 
504
        return (lambda s: not pattern(s))
 
505
    return re.compile(pattern).search
 
506
 
 
507
def merge_options(options, defaults):
 
508
    odict = options.__dict__
 
509
    for name, value in defaults.__dict__.items():
 
510
        if (value is not None) and (odict[name] is None):
 
511
            odict[name] = value
 
512
 
 
513
def get_options(args=None, defaults=None):
 
514
    # Because we want to inspect stdout and decide to colorize or not, we
 
515
    # replace the --auto-color option with the appropriate --color or
 
516
    # --no-color option.  That way the subprocess doesn't have to decide (which
 
517
    # it would do incorrectly anyway because stdout would be a pipe).
 
518
    def apply_auto_color(args):
 
519
        if args and '--auto-color' in args:
 
520
            if sys.stdout.isatty() and terminal_has_colors():
 
521
                colorization = '--color'
 
522
            else:
 
523
                colorization = '--no-color'
 
524
 
 
525
            args[:] = [arg.replace('--auto-color', colorization)
 
526
                       for arg in args]
 
527
 
 
528
    # The comment of apply_auto_color applies here as well
 
529
    def apply_auto_progress(args):
 
530
        if args and '--auto-progress' in args:
 
531
            if sys.stdout.isatty():
 
532
                progress = '--progress'
 
533
            else:
 
534
                progress = '--no-progress'
 
535
 
 
536
            args[:] = [arg.replace('--auto-progress', progress)
 
537
                       for arg in args]
 
538
 
 
539
    apply_auto_color(args)
 
540
    apply_auto_color(defaults)
 
541
    apply_auto_progress(args)
 
542
    apply_auto_progress(defaults)
 
543
 
 
544
    if defaults:
 
545
        defaults, _ = parser.parse_args(defaults)
 
546
        assert not _
 
547
    else:
 
548
        defaults = None
 
549
 
 
550
    if args is None:
 
551
        args = sys.argv
 
552
 
 
553
    options, positional = parser.parse_args(args[1:], defaults)
 
554
    options.original_testrunner_args = args
 
555
 
 
556
    if options.showversion:
 
557
        dist = pkg_resources.require('zope.testing')[0]
 
558
        print 'zope.app.testrunner version %s' % dist.version
 
559
        options.fail = True
 
560
        return options
 
561
 
 
562
    if options.subunit:
 
563
        try:
 
564
            import subunit
 
565
        except ImportError:
 
566
            print """\
 
567
        Subunit is not installed. Please install Subunit
 
568
        to generate subunit output.
 
569
        """
 
570
            options.fail = True
 
571
            return options
 
572
        else:
 
573
            options.output = SubunitOutputFormatter(options)
 
574
    elif options.color:
 
575
        options.output = ColorfulOutputFormatter(options)
 
576
        options.output.slow_test_threshold = options.slow_test_threshold
 
577
    else:
 
578
        options.output = OutputFormatter(options)
 
579
 
 
580
    options.fail = False
 
581
 
 
582
    if positional:
 
583
        module_filter = positional.pop(0)
 
584
        if module_filter != '.':
 
585
            if options.module:
 
586
                options.module.append(module_filter)
 
587
            else:
 
588
                options.module = [module_filter]
 
589
 
 
590
        if positional:
 
591
            test_filter = positional.pop(0)
 
592
            if options.test:
 
593
                options.test.append(test_filter)
 
594
            else:
 
595
                options.test = [test_filter]
 
596
 
 
597
            if positional:
 
598
                parser.error("Too many positional arguments")
 
599
 
 
600
    options.ignore_dir = dict([(d,1) for d in options.ignore_dir])
 
601
    options.test_file_pattern = re.compile(options.test_file_pattern).search
 
602
    options.tests_pattern = re.compile(options.tests_pattern).search
 
603
    options.test = map(compile_filter, options.test or ('.'))
 
604
    options.module = map(compile_filter, options.module or ('.'))
 
605
 
 
606
    options.path = map(os.path.abspath, options.path or ())
 
607
    options.test_path = map(os.path.abspath, options.test_path or ())
 
608
    options.test_path += options.path
 
609
 
 
610
    options.test_path = ([(path, '') for path in options.test_path]
 
611
                         +
 
612
                         [(os.path.abspath(path), package)
 
613
                          for (path, package) in options.package_path or ()
 
614
                          ])
 
615
 
 
616
    if options.package:
 
617
        pkgmap = dict(options.test_path)
 
618
        options.package = [normalize_package(p, pkgmap)
 
619
                           for p in options.package]
 
620
 
 
621
    options.prefix = [(path + os.path.sep, package)
 
622
                      for (path, package) in options.test_path]
 
623
    if options.all:
 
624
        options.at_level = sys.maxint
 
625
 
 
626
    if options.unit and options.non_unit:
 
627
        # The test runner interprets this as "run only those tests that are
 
628
        # both unit and non-unit at the same time".  The user, however, wants
 
629
        # to run both unit and non-unit tests.  Disable the filtering so that
 
630
        # the user will get what she wants:
 
631
        options.unit = options.non_unit = False
 
632
 
 
633
    if options.unit:
 
634
        # XXX Argh.
 
635
        options.layer = ['zope.testing.testrunner.layer.UnitTests']
 
636
    if options.layer:
 
637
        options.layer = map(compile_filter, options.layer)
 
638
 
 
639
    options.layer = options.layer and dict([(l, 1) for l in options.layer])
 
640
 
 
641
    if options.usecompiled:
 
642
        options.keepbytecode = options.usecompiled
 
643
 
 
644
    if options.quiet:
 
645
        options.verbose = 0
 
646
 
 
647
    if options.report_refcounts and options.repeat < 2:
 
648
        print """\
 
649
        You must use the --repeat (-N) option to specify a repeat
 
650
        count greater than 1 when using the --report_refcounts (-r)
 
651
        option.
 
652
        """
 
653
        options.fail = True
 
654
        return options
 
655
 
 
656
 
 
657
    if options.report_refcounts and not hasattr(sys, "gettotalrefcount"):
 
658
        print """\
 
659
        The Python you are running was not configured
 
660
        with --with-pydebug. This is required to use
 
661
        the --report-refcounts option.
 
662
        """
 
663
        options.fail = True
 
664
        return options
 
665
 
 
666
    return options
 
667
 
 
668
def normalize_package(package, package_map={}):
 
669
    r"""Normalize package name passed to the --package option.
 
670
 
 
671
        >>> normalize_package('zope.testing')
 
672
        'zope.testing'
 
673
 
 
674
    Converts path names into package names for compatibility with the old
 
675
    test runner.
 
676
 
 
677
        >>> normalize_package('zope/testing')
 
678
        'zope.testing'
 
679
        >>> normalize_package('zope/testing/')
 
680
        'zope.testing'
 
681
        >>> normalize_package('zope\\testing')
 
682
        'zope.testing'
 
683
 
 
684
    Can use a map of absolute pathnames to package names
 
685
 
 
686
        >>> a = os.path.abspath
 
687
        >>> normalize_package('src/zope/testing/',
 
688
        ...                   {a('src'): ''})
 
689
        'zope.testing'
 
690
        >>> normalize_package('src/zope_testing/',
 
691
        ...                   {a('src/zope_testing'): 'zope.testing'})
 
692
        'zope.testing'
 
693
        >>> normalize_package('src/zope_something/tests',
 
694
        ...                   {a('src/zope_something'): 'zope.something',
 
695
        ...                    a('src'): ''})
 
696
        'zope.something.tests'
 
697
 
 
698
    """
 
699
    package = package.replace('\\', '/')
 
700
    if package.endswith('/'):
 
701
        package = package[:-1]
 
702
    bits = package.split('/')
 
703
    for n in range(len(bits), 0, -1):
 
704
        pkg = package_map.get(os.path.abspath('/'.join(bits[:n])))
 
705
        if pkg is not None:
 
706
            bits = bits[n:]
 
707
            if pkg:
 
708
                bits = [pkg] + bits
 
709
            return '.'.join(bits)
 
710
    return package.replace('/', '.')