def __call__(self, test_state): """Invoke this Phase, passing in the appropriate args. By default, an openhtf.TestApi is passed as the first positional arg, but if the 'requires_state' option is set, then a test_state.TestState is passed instead. If no positional args are expected, then neither is passed in. In any case, keyword args are passed in based on extra_kwargs, set via with_args(), combined with plugs (plugs override extra_kwargs). Args: test_state: test_state.TestState for the currently executing Test. Returns: The return value from calling the underlying function. """ kwargs = dict(self.extra_kwargs) kwargs.update(test_state.plug_manager.provide_plugs( (plug.name, plug.cls) for plug in self.plugs if plug.update_kwargs)) if sys.version_info[0] < 3: arg_info = inspect.getargspec(self.func) keywords = arg_info.keywords else: arg_info = inspect.getfullargspec(self.func) keywords = arg_info.varkw # Pass in test_api if the phase takes *args, or **kwargs with at least 1 # positional, or more positional args than we have keyword args. if arg_info.varargs or (keywords and len(arg_info.args) >= 1) or ( len(arg_info.args) > len(kwargs)): # Underlying function has room for test_api as an arg. If it doesn't # expect it but we miscounted args, we'll get another error farther down. old_logger = test_state.logger # The logging module has a module _lock instance that is a threading.RLock # instance; it can cause deadlocks in Python 2.7 when a KillableThread is # killed while its release method is running. with threads.safe_lock_release_context(logging._lock): # pylint: disable=protected-access # Update test_state's logger so that it is a phase-specific one. record_logger = logs.get_record_logger_for(test_state.execution_uid) test_state.logger = record_logger.getChild('phase').getChild(self.name) try: args = [] if self.options.requires_state: args.append(test_state) else: args.append(test_state.test_api) if self.options.run_under_pdb: return pdb.runcall(self.func, *args, **kwargs) else: return self.func(*args, **kwargs) finally: test_state.logger = old_logger if self.options.run_under_pdb: return pdb.runcall(self.func, **kwargs) else: return self.func(**kwargs)
def handle(self, record): # logging.Handler objects have an internal lock attribute that is a # threading.RLock instance; it can cause deadlocks in Python 2.7 when a # KillableThread is killed while its release method is running. with threads.safe_lock_release_context(self.lock): return super(RecordHandler, self).handle(record)