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