python/mach_commands.py

Fri, 16 Jan 2015 18:13:44 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Fri, 16 Jan 2015 18:13:44 +0100
branch
TOR_BUG_9701
changeset 14
925c144e1f1f
permissions
-rw-r--r--

Integrate suggestion from review to improve consistency with existing code.

michael@0 1 # This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 # License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
michael@0 4
michael@0 5 from __future__ import print_function, unicode_literals
michael@0 6
michael@0 7 import argparse
michael@0 8 import glob
michael@0 9 import logging
michael@0 10 import mozpack.path
michael@0 11 import os
michael@0 12 import sys
michael@0 13
michael@0 14 from mozbuild.base import (
michael@0 15 MachCommandBase,
michael@0 16 )
michael@0 17
michael@0 18 from mach.decorators import (
michael@0 19 CommandArgument,
michael@0 20 CommandProvider,
michael@0 21 Command,
michael@0 22 )
michael@0 23
michael@0 24
michael@0 25 @CommandProvider
michael@0 26 class MachCommands(MachCommandBase):
michael@0 27 @Command('python', category='devenv',
michael@0 28 allow_all_args=True,
michael@0 29 description='Run Python.')
michael@0 30 @CommandArgument('args', nargs=argparse.REMAINDER)
michael@0 31 def python(self, args):
michael@0 32 # Avoid logging the command
michael@0 33 self.log_manager.terminal_handler.setLevel(logging.CRITICAL)
michael@0 34
michael@0 35 self._activate_virtualenv()
michael@0 36
michael@0 37 return self.run_process([self.virtualenv_manager.python_path] + args,
michael@0 38 pass_thru=True, # Allow user to run Python interactively.
michael@0 39 ensure_exit_code=False, # Don't throw on non-zero exit code.
michael@0 40 # Note: subprocess requires native strings in os.environ on Windows
michael@0 41 append_env={b'PYTHONDONTWRITEBYTECODE': str('1')})
michael@0 42
michael@0 43 @Command('python-test', category='testing',
michael@0 44 description='Run Python unit tests.')
michael@0 45 @CommandArgument('--verbose',
michael@0 46 default=False,
michael@0 47 action='store_true',
michael@0 48 help='Verbose output.')
michael@0 49 @CommandArgument('--stop',
michael@0 50 default=False,
michael@0 51 action='store_true',
michael@0 52 help='Stop running tests after the first error or failure.')
michael@0 53 @CommandArgument('tests', nargs='+',
michael@0 54 metavar='TEST',
michael@0 55 help='Tests to run. Each test can be a single file or a directory.')
michael@0 56 def python_test(self, tests, verbose=False, stop=False):
michael@0 57 self._activate_virtualenv()
michael@0 58
michael@0 59 # Python's unittest, and in particular discover, has problems with
michael@0 60 # clashing namespaces when importing multiple test modules. What follows
michael@0 61 # is a simple way to keep environments separate, at the price of
michael@0 62 # launching Python multiple times. This also runs tests via mozunit,
michael@0 63 # which produces output in the format Mozilla infrastructure expects.
michael@0 64 return_code = 0
michael@0 65 files = []
michael@0 66 for test in tests:
michael@0 67 if test.endswith('.py') and os.path.isfile(test):
michael@0 68 files.append(test)
michael@0 69 elif os.path.isfile(test + '.py'):
michael@0 70 files.append(test + '.py')
michael@0 71 elif os.path.isdir(test):
michael@0 72 files += glob.glob(mozpack.path.join(test, 'test*.py'))
michael@0 73 files += glob.glob(mozpack.path.join(test, 'unit*.py'))
michael@0 74 else:
michael@0 75 self.log(logging.WARN, 'python-test', {'test': test},
michael@0 76 'TEST-UNEXPECTED-FAIL | Invalid test: {test}')
michael@0 77 if stop:
michael@0 78 return 1
michael@0 79
michael@0 80 for f in files:
michael@0 81 file_displayed_test = [] # Used as a boolean.
michael@0 82 def _line_handler(line):
michael@0 83 if not file_displayed_test and line.startswith('TEST-'):
michael@0 84 file_displayed_test.append(True)
michael@0 85
michael@0 86 inner_return_code = self.run_process(
michael@0 87 [self.virtualenv_manager.python_path, f],
michael@0 88 ensure_exit_code=False, # Don't throw on non-zero exit code.
michael@0 89 log_name='python-test',
michael@0 90 # subprocess requires native strings in os.environ on Windows
michael@0 91 append_env={b'PYTHONDONTWRITEBYTECODE': str('1')},
michael@0 92 line_handler=_line_handler)
michael@0 93 return_code += inner_return_code
michael@0 94
michael@0 95 if not file_displayed_test:
michael@0 96 self.log(logging.WARN, 'python-test', {'file': f},
michael@0 97 'TEST-UNEXPECTED-FAIL | No test output (missing mozunit.main() call?): {file}')
michael@0 98
michael@0 99 if verbose:
michael@0 100 if inner_return_code != 0:
michael@0 101 self.log(logging.INFO, 'python-test', {'file': f},
michael@0 102 'Test failed: {file}')
michael@0 103 else:
michael@0 104 self.log(logging.INFO, 'python-test', {'file': f},
michael@0 105 'Test passed: {file}')
michael@0 106 if stop and return_code > 0:
michael@0 107 return 1
michael@0 108
michael@0 109 return 0 if return_code == 0 else 1

mercurial