Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(225)

Side by Side Diff: third_party/logilab/common/pytest.py

Issue 739393004: Revert "Revert "pylint: upgrade to 1.3.1"" (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/depot_tools/
Patch Set: Created 6 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « third_party/logilab/common/pyro_ext.py ('k') | third_party/logilab/common/registry.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 # copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved. 1 # copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
2 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr 2 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
3 # 3 #
4 # This file is part of logilab-common. 4 # This file is part of logilab-common.
5 # 5 #
6 # logilab-common is free software: you can redistribute it and/or modify it unde r 6 # logilab-common is free software: you can redistribute it and/or modify it unde r
7 # the terms of the GNU Lesser General Public License as published by the Free 7 # the terms of the GNU Lesser General Public License as published by the Free
8 # Software Foundation, either version 2.1 of the License, or (at your option) an y 8 # Software Foundation, either version 2.1 of the License, or (at your option) an y
9 # later version. 9 # later version.
10 # 10 #
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
85 def titi(test): 85 def titi(test):
86 pass 86 pass
87 87
88 you can filter the function with a simple python expression 88 you can filter the function with a simple python expression
89 89
90 * ``toto`` and ``titi`` match ``rouge`` 90 * ``toto`` and ``titi`` match ``rouge``
91 * ``toto``, ``tata`` and ``titi``, match ``rouge or carre`` 91 * ``toto``, ``tata`` and ``titi``, match ``rouge or carre``
92 * ``tata`` and ``titi`` match``rouge ^ carre`` 92 * ``tata`` and ``titi`` match``rouge ^ carre``
93 * ``titi`` match ``rouge and not carre`` 93 * ``titi`` match ``rouge and not carre``
94 """ 94 """
95
96 from __future__ import print_function
97
95 __docformat__ = "restructuredtext en" 98 __docformat__ = "restructuredtext en"
96 99
97 PYTEST_DOC = """%prog [OPTIONS] [testfile [testpattern]] 100 PYTEST_DOC = """%prog [OPTIONS] [testfile [testpattern]]
98 101
99 examples: 102 examples:
100 103
101 pytest path/to/mytests.py 104 pytest path/to/mytests.py
102 pytest path/to/mytests.py TheseTests 105 pytest path/to/mytests.py TheseTests
103 pytest path/to/mytests.py TheseTests.test_thisone 106 pytest path/to/mytests.py TheseTests.test_thisone
104 pytest path/to/mytests.py -m '(not long and database) or regr' 107 pytest path/to/mytests.py -m '(not long and database) or regr'
105 108
106 pytest one (will run both test_thisone and test_thatone) 109 pytest one (will run both test_thisone and test_thatone)
107 pytest path/to/mytests.py -s not (will skip test_notthisone) 110 pytest path/to/mytests.py -s not (will skip test_notthisone)
108
109 pytest --coverage test_foo.py
110 (only if logilab.devtools is available)
111 """ 111 """
112 112
113 ENABLE_DBC = False 113 ENABLE_DBC = False
114 FILE_RESTART = ".pytest.restart" 114 FILE_RESTART = ".pytest.restart"
115 115
116 import os, sys, re 116 import os, sys, re
117 import os.path as osp 117 import os.path as osp
118 from time import time, clock 118 from time import time, clock
119 import warnings 119 import warnings
120 import types 120 import types
121 from inspect import isgeneratorfunction, isclass
121 122
122 from logilab.common.fileutils import abspath_listdir 123 from logilab.common.fileutils import abspath_listdir
123 from logilab.common import textutils 124 from logilab.common import textutils
124 from logilab.common import testlib, STD_BLACKLIST 125 from logilab.common import testlib, STD_BLACKLIST
125 # use the same unittest module as testlib 126 # use the same unittest module as testlib
126 from logilab.common.testlib import unittest, start_interactive_mode 127 from logilab.common.testlib import unittest, start_interactive_mode
127 from logilab.common.compat import any
128 import doctest 128 import doctest
129 129
130 import unittest as unittest_legacy 130 import unittest as unittest_legacy
131 if not getattr(unittest_legacy, "__package__", None): 131 if not getattr(unittest_legacy, "__package__", None):
132 try: 132 try:
133 import unittest2.suite as unittest_suite 133 import unittest2.suite as unittest_suite
134 except ImportError: 134 except ImportError:
135 sys.exit("You have to install python-unittest2 to use this module") 135 sys.exit("You have to install python-unittest2 to use this module")
136 else: 136 else:
137 import unittest.suite as unittest_suite 137 import unittest.suite as unittest_suite
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
199 def this_is_a_testdir(dirpath): 199 def this_is_a_testdir(dirpath):
200 """returns True if `filename` seems to be a test directory""" 200 """returns True if `filename` seems to be a test directory"""
201 return TESTDIR_RE.match(osp.basename(dirpath)) 201 return TESTDIR_RE.match(osp.basename(dirpath))
202 202
203 203
204 def load_pytest_conf(path, parser): 204 def load_pytest_conf(path, parser):
205 """loads a ``pytestconf.py`` file and update default parser 205 """loads a ``pytestconf.py`` file and update default parser
206 and / or tester. 206 and / or tester.
207 """ 207 """
208 namespace = {} 208 namespace = {}
209 execfile(path, namespace) 209 exec(open(path, 'rb').read(), namespace)
210 if 'update_parser' in namespace: 210 if 'update_parser' in namespace:
211 namespace['update_parser'](parser) 211 namespace['update_parser'](parser)
212 return namespace.get('CustomPyTester', PyTester) 212 return namespace.get('CustomPyTester', PyTester)
213 213
214 214
215 def project_root(parser, projdir=os.getcwd()): 215 def project_root(parser, projdir=os.getcwd()):
216 """try to find project's root and add it to sys.path""" 216 """try to find project's root and add it to sys.path"""
217 previousdir = curdir = osp.abspath(projdir) 217 previousdir = curdir = osp.abspath(projdir)
218 testercls = PyTester 218 testercls = PyTester
219 conf_file_path = osp.join(curdir, CONF_FILE) 219 conf_file_path = osp.join(curdir, CONF_FILE)
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
302 This is used to avoid strange side-effects when using the 302 This is used to avoid strange side-effects when using the
303 testall() mode of pytest. 303 testall() mode of pytest.
304 For instance, if we run pytest on this tree:: 304 For instance, if we run pytest on this tree::
305 305
306 A/test/test_utils.py 306 A/test/test_utils.py
307 B/test/test_utils.py 307 B/test/test_utils.py
308 308
309 we **have** to clean sys.modules to make sure the correct test_utils 309 we **have** to clean sys.modules to make sure the correct test_utils
310 module is ran in B 310 module is ran in B
311 """ 311 """
312 for modname, mod in sys.modules.items(): 312 for modname, mod in list(sys.modules.items()):
313 if mod is None: 313 if mod is None:
314 continue 314 continue
315 if not hasattr(mod, '__file__'): 315 if not hasattr(mod, '__file__'):
316 # this is the case of some built-in modules like sys, imp, marshal 316 # this is the case of some built-in modules like sys, imp, marshal
317 continue 317 continue
318 modfile = mod.__file__ 318 modfile = mod.__file__
319 # if modfile is not an absolute path, it was probably loaded locally 319 # if modfile is not an absolute path, it was probably loaded locally
320 # during the tests 320 # during the tests
321 if not osp.isabs(modfile) or modfile.startswith(testdir): 321 if not osp.isabs(modfile) or modfile.startswith(testdir):
322 del sys.modules[modname] 322 del sys.modules[modname]
323 323
324 324
325 325
326 class PyTester(object): 326 class PyTester(object):
327 """encapsulates testrun logic""" 327 """encapsulates testrun logic"""
328 328
329 def __init__(self, cvg, options): 329 def __init__(self, cvg, options):
330 self.report = GlobalTestReport() 330 self.report = GlobalTestReport()
331 self.cvg = cvg 331 self.cvg = cvg
332 self.options = options 332 self.options = options
333 self.firstwrite = True 333 self.firstwrite = True
334 self._errcode = None 334 self._errcode = None
335 335
336 def show_report(self): 336 def show_report(self):
337 """prints the report and returns appropriate exitcode""" 337 """prints the report and returns appropriate exitcode"""
338 # everything has been ran, print report 338 # everything has been ran, print report
339 print "*" * 79 339 print("*" * 79)
340 print self.report 340 print(self.report)
341 341
342 def get_errcode(self): 342 def get_errcode(self):
343 # errcode set explicitly 343 # errcode set explicitly
344 if self._errcode is not None: 344 if self._errcode is not None:
345 return self._errcode 345 return self._errcode
346 return self.report.failures + self.report.errors 346 return self.report.failures + self.report.errors
347 347
348 def set_errcode(self, errcode): 348 def set_errcode(self, errcode):
349 self._errcode = errcode 349 self._errcode = errcode
350 errcode = property(get_errcode, set_errcode) 350 errcode = property(get_errcode, set_errcode)
351 351
352 def testall(self, exitfirst=False): 352 def testall(self, exitfirst=False):
353 """walks through current working directory, finds something 353 """walks through current working directory, finds something
354 which can be considered as a testdir and runs every test there 354 which can be considered as a testdir and runs every test there
355 """ 355 """
356 here = os.getcwd() 356 here = os.getcwd()
357 for dirname, dirs, _ in os.walk(here): 357 for dirname, dirs, _ in os.walk(here):
358 for skipped in STD_BLACKLIST: 358 for skipped in STD_BLACKLIST:
359 if skipped in dirs: 359 if skipped in dirs:
360 dirs.remove(skipped) 360 dirs.remove(skipped)
361 basename = osp.basename(dirname) 361 basename = osp.basename(dirname)
362 if this_is_a_testdir(basename): 362 if this_is_a_testdir(basename):
363 print "going into", dirname 363 print("going into", dirname)
364 # we found a testdir, let's explore it ! 364 # we found a testdir, let's explore it !
365 if not self.testonedir(dirname, exitfirst): 365 if not self.testonedir(dirname, exitfirst):
366 break 366 break
367 dirs[:] = [] 367 dirs[:] = []
368 if self.report.ran == 0: 368 if self.report.ran == 0:
369 print "no test dir found testing here:", here 369 print("no test dir found testing here:", here)
370 # if no test was found during the visit, consider 370 # if no test was found during the visit, consider
371 # the local directory as a test directory even if 371 # the local directory as a test directory even if
372 # it doesn't have a traditional test directory name 372 # it doesn't have a traditional test directory name
373 self.testonedir(here) 373 self.testonedir(here)
374 374
375 def testonedir(self, testdir, exitfirst=False): 375 def testonedir(self, testdir, exitfirst=False):
376 """finds each testfile in the `testdir` and runs it 376 """finds each testfile in the `testdir` and runs it
377 377
378 return true when all tests has been executed, false if exitfirst and 378 return true when all tests has been executed, false if exitfirst and
379 some test has failed. 379 some test has failed.
380 """ 380 """
381 for filename in abspath_listdir(testdir): 381 for filename in abspath_listdir(testdir):
382 if this_is_a_testfile(filename): 382 if this_is_a_testfile(filename):
383 if self.options.exitfirst and not self.options.restart: 383 if self.options.exitfirst and not self.options.restart:
384 # overwrite restart file 384 # overwrite restart file
385 try: 385 try:
386 restartfile = open(FILE_RESTART, "w") 386 restartfile = open(FILE_RESTART, "w")
387 restartfile.close() 387 restartfile.close()
388 except Exception, e: 388 except Exception:
389 print >> sys.__stderr__, "Error while overwriting \ 389 print("Error while overwriting succeeded test file :",
390 succeeded test file :", osp.join(os.getcwd(), FILE_RESTART) 390 osp.join(os.getcwd(), FILE_RESTART),
391 raise e 391 file=sys.__stderr__)
392 raise
392 # run test and collect information 393 # run test and collect information
393 prog = self.testfile(filename, batchmode=True) 394 prog = self.testfile(filename, batchmode=True)
394 if exitfirst and (prog is None or not prog.result.wasSuccessful( )): 395 if exitfirst and (prog is None or not prog.result.wasSuccessful( )):
395 return False 396 return False
396 self.firstwrite = True 397 self.firstwrite = True
397 # clean local modules 398 # clean local modules
398 remove_local_modules_from_sys(testdir) 399 remove_local_modules_from_sys(testdir)
399 return True 400 return True
400 401
401 def testfile(self, filename, batchmode=False): 402 def testfile(self, filename, batchmode=False):
402 """runs every test in `filename` 403 """runs every test in `filename`
403 404
404 :param filename: an absolute path pointing to a unittest file 405 :param filename: an absolute path pointing to a unittest file
405 """ 406 """
406 here = os.getcwd() 407 here = os.getcwd()
407 dirname = osp.dirname(filename) 408 dirname = osp.dirname(filename)
408 if dirname: 409 if dirname:
409 os.chdir(dirname) 410 os.chdir(dirname)
410 # overwrite restart file if it has not been done already 411 # overwrite restart file if it has not been done already
411 if self.options.exitfirst and not self.options.restart and self.firstwri te: 412 if self.options.exitfirst and not self.options.restart and self.firstwri te:
412 try: 413 try:
413 restartfile = open(FILE_RESTART, "w") 414 restartfile = open(FILE_RESTART, "w")
414 restartfile.close() 415 restartfile.close()
415 except Exception, e: 416 except Exception:
416 print >> sys.__stderr__, "Error while overwriting \ 417 print("Error while overwriting succeeded test file :",
417 succeeded test file :", osp.join(os.getcwd(), FILE_RESTART) 418 osp.join(os.getcwd(), FILE_RESTART), file=sys.__stderr__)
418 raise e 419 raise
419 modname = osp.basename(filename)[:-3] 420 modname = osp.basename(filename)[:-3]
420 try: 421 print((' %s ' % osp.basename(filename)).center(70, '='),
421 print >> sys.stderr, (' %s ' % osp.basename(filename)).center(70, '=') 422 file=sys.__stderr__)
422 except TypeError: # < py 2.4 bw compat
423 print >> sys.stderr, (' %s ' % osp.basename(filename)).center(70)
424 try: 423 try:
425 tstart, cstart = time(), clock() 424 tstart, cstart = time(), clock()
426 try: 425 try:
427 testprog = SkipAwareTestProgram(modname, batchmode=batchmode, cv g=self.cvg, 426 testprog = SkipAwareTestProgram(modname, batchmode=batchmode, cv g=self.cvg,
428 options=self.options, outstream =sys.stderr) 427 options=self.options, outstream =sys.stderr)
429 except KeyboardInterrupt: 428 except KeyboardInterrupt:
430 raise 429 raise
431 except SystemExit, exc: 430 except SystemExit as exc:
432 self.errcode = exc.code 431 self.errcode = exc.code
433 raise 432 raise
434 except testlib.SkipTest: 433 except testlib.SkipTest:
435 print "Module skipped:", filename 434 print("Module skipped:", filename)
436 self.report.skip_module(filename) 435 self.report.skip_module(filename)
437 return None 436 return None
438 except Exception: 437 except Exception:
439 self.report.failed_to_test_module(filename) 438 self.report.failed_to_test_module(filename)
440 print >> sys.stderr, 'unhandled exception occurred while testing ', modname 439 print('unhandled exception occurred while testing', modname,
440 file=sys.stderr)
441 import traceback 441 import traceback
442 traceback.print_exc(file=sys.stderr) 442 traceback.print_exc(file=sys.stderr)
443 return None 443 return None
444 444
445 tend, cend = time(), clock() 445 tend, cend = time(), clock()
446 ttime, ctime = (tend - tstart), (cend - cstart) 446 ttime, ctime = (tend - tstart), (cend - cstart)
447 self.report.feed(filename, testprog.result, ttime, ctime) 447 self.report.feed(filename, testprog.result, ttime, ctime)
448 return testprog 448 return testprog
449 finally: 449 finally:
450 if dirname: 450 if dirname:
(...skipping 30 matching lines...) Expand all
481 from django.test.utils import create_test_db 481 from django.test.utils import create_test_db
482 setup_test_environment() 482 setup_test_environment()
483 create_test_db(verbosity=0) 483 create_test_db(verbosity=0)
484 self.dbname = self.settings.TEST_DATABASE_NAME 484 self.dbname = self.settings.TEST_DATABASE_NAME
485 485
486 def after_testfile(self): 486 def after_testfile(self):
487 # Those imports must be done **after** setup_environ was called 487 # Those imports must be done **after** setup_environ was called
488 from django.test.utils import teardown_test_environment 488 from django.test.utils import teardown_test_environment
489 from django.test.utils import destroy_test_db 489 from django.test.utils import destroy_test_db
490 teardown_test_environment() 490 teardown_test_environment()
491 print 'destroying', self.dbname 491 print('destroying', self.dbname)
492 destroy_test_db(self.dbname, verbosity=0) 492 destroy_test_db(self.dbname, verbosity=0)
493 493
494 def testall(self, exitfirst=False): 494 def testall(self, exitfirst=False):
495 """walks through current working directory, finds something 495 """walks through current working directory, finds something
496 which can be considered as a testdir and runs every test there 496 which can be considered as a testdir and runs every test there
497 """ 497 """
498 for dirname, dirs, files in os.walk(os.getcwd()): 498 for dirname, dirs, files in os.walk(os.getcwd()):
499 for skipped in ('CVS', '.svn', '.hg'): 499 for skipped in ('CVS', '.svn', '.hg'):
500 if skipped in dirs: 500 if skipped in dirs:
501 dirs.remove(skipped) 501 dirs.remove(skipped)
502 if 'tests.py' in files: 502 if 'tests.py' in files:
503 if not self.testonedir(dirname, exitfirst): 503 if not self.testonedir(dirname, exitfirst):
504 break 504 break
505 dirs[:] = [] 505 dirs[:] = []
506 else: 506 else:
507 basename = osp.basename(dirname) 507 basename = osp.basename(dirname)
508 if basename in ('test', 'tests'): 508 if basename in ('test', 'tests'):
509 print "going into", dirname 509 print("going into", dirname)
510 # we found a testdir, let's explore it ! 510 # we found a testdir, let's explore it !
511 if not self.testonedir(dirname, exitfirst): 511 if not self.testonedir(dirname, exitfirst):
512 break 512 break
513 dirs[:] = [] 513 dirs[:] = []
514 514
515 def testonedir(self, testdir, exitfirst=False): 515 def testonedir(self, testdir, exitfirst=False):
516 """finds each testfile in the `testdir` and runs it 516 """finds each testfile in the `testdir` and runs it
517 517
518 return true when all tests has been executed, false if exitfirst and 518 return true when all tests has been executed, false if exitfirst and
519 some test has failed. 519 some test has failed.
(...skipping 20 matching lines...) Expand all
540 """runs every test in `filename` 540 """runs every test in `filename`
541 541
542 :param filename: an absolute path pointing to a unittest file 542 :param filename: an absolute path pointing to a unittest file
543 """ 543 """
544 here = os.getcwd() 544 here = os.getcwd()
545 dirname = osp.dirname(filename) 545 dirname = osp.dirname(filename)
546 if dirname: 546 if dirname:
547 os.chdir(dirname) 547 os.chdir(dirname)
548 self.load_django_settings(dirname) 548 self.load_django_settings(dirname)
549 modname = osp.basename(filename)[:-3] 549 modname = osp.basename(filename)[:-3]
550 print >>sys.stderr, (' %s ' % osp.basename(filename)).center(70, '=') 550 print((' %s ' % osp.basename(filename)).center(70, '='),
551 file=sys.stderr)
551 try: 552 try:
552 try: 553 try:
553 tstart, cstart = time(), clock() 554 tstart, cstart = time(), clock()
554 self.before_testfile() 555 self.before_testfile()
555 testprog = SkipAwareTestProgram(modname, batchmode=batchmode, cv g=self.cvg) 556 testprog = SkipAwareTestProgram(modname, batchmode=batchmode, cv g=self.cvg)
556 tend, cend = time(), clock() 557 tend, cend = time(), clock()
557 ttime, ctime = (tend - tstart), (cend - cstart) 558 ttime, ctime = (tend - tstart), (cend - cstart)
558 self.report.feed(filename, testprog.result, ttime, ctime) 559 self.report.feed(filename, testprog.result, ttime, ctime)
559 return testprog 560 return testprog
560 except SystemExit: 561 except SystemExit:
561 raise 562 raise
562 except Exception, exc: 563 except Exception as exc:
563 import traceback 564 import traceback
564 traceback.print_exc() 565 traceback.print_exc()
565 self.report.failed_to_test_module(filename) 566 self.report.failed_to_test_module(filename)
566 print 'unhandled exception occurred while testing', modname 567 print('unhandled exception occurred while testing', modname)
567 print 'error: %s' % exc 568 print('error: %s' % exc)
568 return None 569 return None
569 finally: 570 finally:
570 self.after_testfile() 571 self.after_testfile()
571 if dirname: 572 if dirname:
572 os.chdir(here) 573 os.chdir(here)
573 574
574 575
575 def make_parser(): 576 def make_parser():
576 """creates the OptionParser instance 577 """creates the OptionParser instance
577 """ 578 """
(...skipping 19 matching lines...) Expand all
597 # pytest options 598 # pytest options
598 parser.add_option('-t', dest='testdir', default=None, 599 parser.add_option('-t', dest='testdir', default=None,
599 help="directory where the tests will be found") 600 help="directory where the tests will be found")
600 parser.add_option('-d', dest='dbc', default=False, 601 parser.add_option('-d', dest='dbc', default=False,
601 action="store_true", help="enable design-by-contract") 602 action="store_true", help="enable design-by-contract")
602 # unittest_main options provided and passed through pytest 603 # unittest_main options provided and passed through pytest
603 parser.add_option('-v', '--verbose', callback=rebuild_cmdline, 604 parser.add_option('-v', '--verbose', callback=rebuild_cmdline,
604 action="callback", help="Verbose output") 605 action="callback", help="Verbose output")
605 parser.add_option('-i', '--pdb', callback=rebuild_and_store, 606 parser.add_option('-i', '--pdb', callback=rebuild_and_store,
606 dest="pdb", action="callback", 607 dest="pdb", action="callback",
607 help="Enable test failure inspection (conflicts with --cov erage)") 608 help="Enable test failure inspection")
608 parser.add_option('-x', '--exitfirst', callback=rebuild_and_store, 609 parser.add_option('-x', '--exitfirst', callback=rebuild_and_store,
609 dest="exitfirst", default=False, 610 dest="exitfirst", default=False,
610 action="callback", help="Exit on first failure " 611 action="callback", help="Exit on first failure "
611 "(only make sense when pytest run one test file)") 612 "(only make sense when pytest run one test file)")
612 parser.add_option('-R', '--restart', callback=rebuild_and_store, 613 parser.add_option('-R', '--restart', callback=rebuild_and_store,
613 dest="restart", default=False, 614 dest="restart", default=False,
614 action="callback", 615 action="callback",
615 help="Restart tests from where it failed (implies exitfirs t) " 616 help="Restart tests from where it failed (implies exitfirs t) "
616 "(only make sense if tests previously ran with exitfirst only)") 617 "(only make sense if tests previously ran with exitfirst only)")
617 parser.add_option('--color', callback=rebuild_cmdline, 618 parser.add_option('--color', callback=rebuild_cmdline,
618 action="callback", 619 action="callback",
619 help="colorize tracebacks") 620 help="colorize tracebacks")
620 parser.add_option('-s', '--skip', 621 parser.add_option('-s', '--skip',
621 # XXX: I wish I could use the callback action but it 622 # XXX: I wish I could use the callback action but it
622 # doesn't seem to be able to get the value 623 # doesn't seem to be able to get the value
623 # associated to the option 624 # associated to the option
624 action="store", dest="skipped", default=None, 625 action="store", dest="skipped", default=None,
625 help="test names matching this name will be skipped " 626 help="test names matching this name will be skipped "
626 "to skip several patterns, use commas") 627 "to skip several patterns, use commas")
627 parser.add_option('-q', '--quiet', callback=rebuild_cmdline, 628 parser.add_option('-q', '--quiet', callback=rebuild_cmdline,
628 action="callback", help="Minimal output") 629 action="callback", help="Minimal output")
629 parser.add_option('-P', '--profile', default=None, dest='profile', 630 parser.add_option('-P', '--profile', default=None, dest='profile',
630 help="Profile execution and store data in the given file") 631 help="Profile execution and store data in the given file")
631 parser.add_option('-m', '--match', default=None, dest='tags_pattern', 632 parser.add_option('-m', '--match', default=None, dest='tags_pattern',
632 help="only execute test whose tag match the current patter n") 633 help="only execute test whose tag match the current patter n")
633 634
634 try:
635 from logilab.devtools.lib.coverage import Coverage
636 parser.add_option('--coverage', dest="coverage", default=False,
637 action="store_true",
638 help="run tests with pycoverage (conflicts with --pdb) ")
639 except ImportError:
640 pass
641
642 if DJANGO_FOUND: 635 if DJANGO_FOUND:
643 parser.add_option('-J', '--django', dest='django', default=False, 636 parser.add_option('-J', '--django', dest='django', default=False,
644 action="store_true", 637 action="store_true",
645 help='use pytest for django test cases') 638 help='use pytest for django test cases')
646 return parser 639 return parser
647 640
648 641
649 def parseargs(parser): 642 def parseargs(parser):
650 """Parse the command line and return (options processed), (options to pass t o 643 """Parse the command line and return (options processed), (options to pass t o
651 unittest_main()), (explicitfile or None). 644 unittest_main()), (explicitfile or None).
652 """ 645 """
653 # parse the command line 646 # parse the command line
654 options, args = parser.parse_args() 647 options, args = parser.parse_args()
655 if options.pdb and getattr(options, 'coverage', False):
656 parser.error("'pdb' and 'coverage' options are exclusive")
657 filenames = [arg for arg in args if arg.endswith('.py')] 648 filenames = [arg for arg in args if arg.endswith('.py')]
658 if filenames: 649 if filenames:
659 if len(filenames) > 1: 650 if len(filenames) > 1:
660 parser.error("only one filename is acceptable") 651 parser.error("only one filename is acceptable")
661 explicitfile = filenames[0] 652 explicitfile = filenames[0]
662 args.remove(explicitfile) 653 args.remove(explicitfile)
663 else: 654 else:
664 explicitfile = None 655 explicitfile = None
665 # someone wants DBC 656 # someone wants DBC
666 testlib.ENABLE_DBC = options.dbc 657 testlib.ENABLE_DBC = options.dbc
667 newargs = parser.newargs 658 newargs = parser.newargs
668 if options.skipped: 659 if options.skipped:
669 newargs.extend(['--skip', options.skipped]) 660 newargs.extend(['--skip', options.skipped])
670 # restart implies exitfirst 661 # restart implies exitfirst
671 if options.restart: 662 if options.restart:
672 options.exitfirst = True 663 options.exitfirst = True
673 # append additional args to the new sys.argv and let unittest_main 664 # append additional args to the new sys.argv and let unittest_main
674 # do the rest 665 # do the rest
675 newargs += args 666 newargs += args
676 return options, explicitfile 667 return options, explicitfile
677 668
678 669
679 670
680 def run(): 671 def run():
681 parser = make_parser() 672 parser = make_parser()
682 rootdir, testercls = project_root(parser) 673 rootdir, testercls = project_root(parser)
683 options, explicitfile = parseargs(parser) 674 options, explicitfile = parseargs(parser)
684 # mock a new command line 675 # mock a new command line
685 sys.argv[1:] = parser.newargs 676 sys.argv[1:] = parser.newargs
686 covermode = getattr(options, 'coverage', None)
687 cvg = None 677 cvg = None
688 if not '' in sys.path: 678 if not '' in sys.path:
689 sys.path.insert(0, '') 679 sys.path.insert(0, '')
690 if covermode:
691 # control_import_coverage(rootdir)
692 from logilab.devtools.lib.coverage import Coverage
693 cvg = Coverage([rootdir])
694 cvg.erase()
695 cvg.start()
696 if DJANGO_FOUND and options.django: 680 if DJANGO_FOUND and options.django:
697 tester = DjangoTester(cvg, options) 681 tester = DjangoTester(cvg, options)
698 else: 682 else:
699 tester = testercls(cvg, options) 683 tester = testercls(cvg, options)
700 if explicitfile: 684 if explicitfile:
701 cmd, args = tester.testfile, (explicitfile,) 685 cmd, args = tester.testfile, (explicitfile,)
702 elif options.testdir: 686 elif options.testdir:
703 cmd, args = tester.testonedir, (options.testdir, options.exitfirst) 687 cmd, args = tester.testonedir, (options.testdir, options.exitfirst)
704 else: 688 else:
705 cmd, args = tester.testall, (options.exitfirst,) 689 cmd, args = tester.testall, (options.exitfirst,)
706 try: 690 try:
707 try: 691 try:
708 if options.profile: 692 if options.profile:
709 import hotshot 693 import hotshot
710 prof = hotshot.Profile(options.profile) 694 prof = hotshot.Profile(options.profile)
711 prof.runcall(cmd, *args) 695 prof.runcall(cmd, *args)
712 prof.close() 696 prof.close()
713 print 'profile data saved in', options.profile 697 print('profile data saved in', options.profile)
714 else: 698 else:
715 cmd(*args) 699 cmd(*args)
716 except SystemExit: 700 except SystemExit:
717 raise 701 raise
718 except: 702 except:
719 import traceback 703 import traceback
720 traceback.print_exc() 704 traceback.print_exc()
721 finally: 705 finally:
722 if covermode:
723 cvg.stop()
724 cvg.save()
725 tester.show_report() 706 tester.show_report()
726 if covermode:
727 print 'coverage information stored, use it with pycoverage -ra'
728 sys.exit(tester.errcode) 707 sys.exit(tester.errcode)
729 708
730 class SkipAwareTestProgram(unittest.TestProgram): 709 class SkipAwareTestProgram(unittest.TestProgram):
731 # XXX: don't try to stay close to unittest.py, use optparse 710 # XXX: don't try to stay close to unittest.py, use optparse
732 USAGE = """\ 711 USAGE = """\
733 Usage: %(progName)s [options] [test] [...] 712 Usage: %(progName)s [options] [test] [...]
734 713
735 Options: 714 Options:
736 -h, --help Show this message 715 -h, --help Show this message
737 -v, --verbose Verbose output 716 -v, --verbose Verbose output
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
809 self.test = self.module.suite() 788 self.test = self.module.suite()
810 else: 789 else:
811 self.test = self.testLoader.loadTestsFromModule(self.module) 790 self.test = self.testLoader.loadTestsFromModule(self.module)
812 return 791 return
813 if len(args) > 0: 792 if len(args) > 0:
814 self.test_pattern = args[0] 793 self.test_pattern = args[0]
815 self.testNames = args 794 self.testNames = args
816 else: 795 else:
817 self.testNames = (self.defaultTest, ) 796 self.testNames = (self.defaultTest, )
818 self.createTests() 797 self.createTests()
819 except getopt.error, msg: 798 except getopt.error as msg:
820 self.usageExit(msg) 799 self.usageExit(msg)
821 800
822 def runTests(self): 801 def runTests(self):
823 if self.profile_name: 802 if self.profile_name:
824 import cProfile 803 import cProfile
825 cProfile.runctx('self._runTests()', globals(), locals(), self.profil e_name ) 804 cProfile.runctx('self._runTests()', globals(), locals(), self.profil e_name )
826 else: 805 else:
827 return self._runTests() 806 return self._runTests()
828 807
829 def _runTests(self): 808 def _runTests(self):
(...skipping 28 matching lines...) Expand all
858 if getattr(self.options, 'restart', False): 837 if getattr(self.options, 'restart', False):
859 # retrieve succeeded tests from FILE_RESTART 838 # retrieve succeeded tests from FILE_RESTART
860 try: 839 try:
861 restartfile = open(FILE_RESTART, 'r') 840 restartfile = open(FILE_RESTART, 'r')
862 try: 841 try:
863 succeededtests = list(elem.rstrip('\n\r') for elem in 842 succeededtests = list(elem.rstrip('\n\r') for elem in
864 restartfile.readlines()) 843 restartfile.readlines())
865 removeSucceededTests(self.test, succeededtests) 844 removeSucceededTests(self.test, succeededtests)
866 finally: 845 finally:
867 restartfile.close() 846 restartfile.close()
868 except Exception, ex: 847 except Exception as ex:
869 raise Exception("Error while reading succeeded tests into %s: %s " 848 raise Exception("Error while reading succeeded tests into %s: %s "
870 % (osp.join(os.getcwd(), FILE_RESTART), ex)) 849 % (osp.join(os.getcwd(), FILE_RESTART), ex))
871 850
872 result = self.testRunner.run(self.test) 851 result = self.testRunner.run(self.test)
873 # help garbage collection: we want TestSuite, which hold refs to every 852 # help garbage collection: we want TestSuite, which hold refs to every
874 # executed TestCase, to be gc'ed 853 # executed TestCase, to be gc'ed
875 del self.test 854 del self.test
876 if getattr(result, "debuggers", None) and \ 855 if getattr(result, "debuggers", None) and \
877 getattr(self, "pdbmode", None): 856 getattr(self, "pdbmode", None):
878 start_interactive_mode(result) 857 start_interactive_mode(result)
(...skipping 21 matching lines...) Expand all
900 879
901 def _this_is_skipped(self, testedname): 880 def _this_is_skipped(self, testedname):
902 return any([(pat in testedname) for pat in self.skipped_patterns]) 881 return any([(pat in testedname) for pat in self.skipped_patterns])
903 882
904 def _runcondition(self, test, skipgenerator=True): 883 def _runcondition(self, test, skipgenerator=True):
905 if isinstance(test, testlib.InnerTest): 884 if isinstance(test, testlib.InnerTest):
906 testname = test.name 885 testname = test.name
907 else: 886 else:
908 if isinstance(test, testlib.TestCase): 887 if isinstance(test, testlib.TestCase):
909 meth = test._get_test_method() 888 meth = test._get_test_method()
910 func = meth.im_func 889 testname = '%s.%s' % (test.__name__, meth.__name__)
911 testname = '%s.%s' % (meth.im_class.__name__, func.__name__)
912 elif isinstance(test, types.FunctionType): 890 elif isinstance(test, types.FunctionType):
913 func = test 891 func = test
914 testname = func.__name__ 892 testname = func.__name__
915 elif isinstance(test, types.MethodType): 893 elif isinstance(test, types.MethodType):
916 func = test.im_func 894 cls = test.__self__.__class__
917 testname = '%s.%s' % (test.im_class.__name__, func.__name__) 895 testname = '%s.%s' % (cls.__name__, test.__name__)
918 else: 896 else:
919 return True # Not sure when this happens 897 return True # Not sure when this happens
920 if testlib.is_generator(test) and skipgenerator: 898 if isgeneratorfunction(test) and skipgenerator:
921 return self.does_match_tags(test) # Let inner tests decide at ru n time 899 return self.does_match_tags(test) # Let inner tests decide at ru n time
922 if self._this_is_skipped(testname): 900 if self._this_is_skipped(testname):
923 return False # this was explicitly skipped 901 return False # this was explicitly skipped
924 if self.test_pattern is not None: 902 if self.test_pattern is not None:
925 try: 903 try:
926 classpattern, testpattern = self.test_pattern.split('.') 904 classpattern, testpattern = self.test_pattern.split('.')
927 klass, name = testname.split('.') 905 klass, name = testname.split('.')
928 if classpattern not in klass or testpattern not in name: 906 if classpattern not in klass or testpattern not in name:
929 return False 907 return False
930 except ValueError: 908 except ValueError:
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after
1018 # and to provide callable capability 996 # and to provide callable capability
1019 def loadTestsFromNames(self, names, module=None): 997 def loadTestsFromNames(self, names, module=None):
1020 suites = [] 998 suites = []
1021 for name in names: 999 for name in names:
1022 suites.extend(self.loadTestsFromName(name, module)) 1000 suites.extend(self.loadTestsFromName(name, module))
1023 return self.suiteClass(suites) 1001 return self.suiteClass(suites)
1024 1002
1025 def _collect_tests(self, module): 1003 def _collect_tests(self, module):
1026 tests = {} 1004 tests = {}
1027 for obj in vars(module).values(): 1005 for obj in vars(module).values():
1028 if (issubclass(type(obj), (types.ClassType, type)) and 1006 if isclass(obj) and issubclass(obj, unittest.TestCase):
1029 issubclass(obj, unittest.TestCase)):
1030 classname = obj.__name__ 1007 classname = obj.__name__
1031 if classname[0] == '_' or self._this_is_skipped(classname): 1008 if classname[0] == '_' or self._this_is_skipped(classname):
1032 continue 1009 continue
1033 methodnames = [] 1010 methodnames = []
1034 # obj is a TestCase class 1011 # obj is a TestCase class
1035 for attrname in dir(obj): 1012 for attrname in dir(obj):
1036 if attrname.startswith(self.testMethodPrefix): 1013 if attrname.startswith(self.testMethodPrefix):
1037 attr = getattr(obj, attrname) 1014 attr = getattr(obj, attrname)
1038 if callable(attr): 1015 if callable(attr):
1039 methodnames.append(attrname) 1016 methodnames.append(attrname)
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after
1168 1145
1169 if sys.version_info >= (2, 4): 1146 if sys.version_info >= (2, 4):
1170 doctest.DocTestCase.__bases__ = (testlib.TestCase,) 1147 doctest.DocTestCase.__bases__ = (testlib.TestCase,)
1171 # XXX check python2.6 compatibility 1148 # XXX check python2.6 compatibility
1172 #doctest.DocTestCase._cleanups = [] 1149 #doctest.DocTestCase._cleanups = []
1173 #doctest.DocTestCase._out = [] 1150 #doctest.DocTestCase._out = []
1174 else: 1151 else:
1175 unittest.FunctionTestCase.__bases__ = (testlib.TestCase,) 1152 unittest.FunctionTestCase.__bases__ = (testlib.TestCase,)
1176 unittest.TestSuite.run = _ts_run 1153 unittest.TestSuite.run = _ts_run
1177 unittest.TestSuite._wrapped_run = _ts_wrapped_run 1154 unittest.TestSuite._wrapped_run = _ts_wrapped_run
OLDNEW
« no previous file with comments | « third_party/logilab/common/pyro_ext.py ('k') | third_party/logilab/common/registry.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698