From 7b9ae37426a8aaa560062c24f7a8fa95d15140c1 Mon Sep 17 00:00:00 2001 From: Frank Winklmeier <fwinkl@cern> Date: Thu, 19 Nov 2020 16:29:42 +0100 Subject: [PATCH] TrigValTools: Add python-only step to TrigValSteering Add a `PyStep` class that allows to implement Python-only "steps" via a user-defined function. --- .../python/TrigValSteering/CheckSteps.py | 7 ++- .../python/TrigValSteering/PyStep.py | 52 +++++++++++++++++++ .../test/test_unit_trigvalsteering.py | 32 ++++++++---- 3 files changed, 80 insertions(+), 11 deletions(-) create mode 100644 Trigger/TrigValidation/TrigValTools/python/TrigValSteering/PyStep.py diff --git a/Trigger/TrigValidation/TrigValTools/python/TrigValSteering/CheckSteps.py b/Trigger/TrigValidation/TrigValTools/python/TrigValSteering/CheckSteps.py index 4793d995a300..d90b6afcf43a 100644 --- a/Trigger/TrigValidation/TrigValTools/python/TrigValSteering/CheckSteps.py +++ b/Trigger/TrigValidation/TrigValTools/python/TrigValSteering/CheckSteps.py @@ -13,6 +13,7 @@ import json import glob from TrigValTools.TrigValSteering.Step import Step, get_step_from_list +from TrigValTools.TrigValSteering.ExecStep import ExecStep from TrigValTools.TrigValSteering.Common import art_input_eos, art_input_cvmfs, running_in_CI class RefComparisonStep(Step): @@ -629,16 +630,18 @@ class MessageCountStep(Step): self.print_on_fail = self.required if self.print_on_fail: self.args += ' --saveAll' + + max_events = test.exec_steps[0].max_events if isinstance(test.exec_steps[0], ExecStep) else 0 if 'WARNING' not in self.thresholds: self.thresholds['WARNING'] = 0 if 'INFO' not in self.thresholds: - self.thresholds['INFO'] = test.exec_steps[0].max_events + self.thresholds['INFO'] = max_events if 'DEBUG' not in self.thresholds: self.thresholds['DEBUG'] = 0 if 'VERBOSE' not in self.thresholds: self.thresholds['VERBOSE'] = 0 if 'other' not in self.thresholds: - self.thresholds['other'] = test.exec_steps[0].max_events + self.thresholds['other'] = max_events super(MessageCountStep, self).configure(test) def run(self, dry_run=False): diff --git a/Trigger/TrigValidation/TrigValTools/python/TrigValSteering/PyStep.py b/Trigger/TrigValidation/TrigValTools/python/TrigValSteering/PyStep.py new file mode 100644 index 000000000000..da63a80e5227 --- /dev/null +++ b/Trigger/TrigValidation/TrigValTools/python/TrigValSteering/PyStep.py @@ -0,0 +1,52 @@ +# +# Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration +# + +""" +Step implemented as python function +""" + +from TrigValTools.TrigValSteering.Step import Step +import contextlib +import sys + +class PyStep(Step): + """Step calling a python function""" + + def __init__(self, func, name=None): + super(PyStep, self).__init__(name) + self.func = func + self.output_stream = Step.OutputStream.STDOUT_ONLY + if self.name is None: + self.name = self.func.__name__ + + def run(self, dry_run=False): + + self.log.info('Running %s step', self.name) + + dest = sys.stdout + if self.output_stream == self.OutputStream.NO_PRINT: + dest = None + elif self.output_stream in [self.OutputStream.FILE_ONLY, self.OutputStream.FILE_AND_STDOUT]: + dest = open(self.get_log_file_name(), 'w') + + if dry_run: + self.result = 0 + else: + try: + with contextlib.redirect_stdout(dest), contextlib.redirect_stderr(dest): + self.result = self.func() + + # Poor man's implementation of 'tee' + if self.output_stream == self.OutputStream.FILE_AND_STDOUT: + dest.close() + print(open(dest.name).read()) + + # In case function does not return a value, assume success + if self.result is None: + self.result = 0 + except Exception as e: + self.log.error('Exception calling %s: %s', self.func.__name__, e) + self.result = 1 + + return self.result, f'# (internal) {self.func.__name__}' diff --git a/Trigger/TrigValidation/TrigValTools/test/test_unit_trigvalsteering.py b/Trigger/TrigValidation/TrigValTools/test/test_unit_trigvalsteering.py index 26356441e80a..27d7073e4726 100755 --- a/Trigger/TrigValidation/TrigValTools/test/test_unit_trigvalsteering.py +++ b/Trigger/TrigValidation/TrigValTools/test/test_unit_trigvalsteering.py @@ -4,7 +4,7 @@ # This is not an ART test. This is a unit test of the framework used for # steering Trigger ART tests. -from TrigValTools.TrigValSteering import Test, ExecStep, CheckSteps, Common +from TrigValTools.TrigValSteering import Test, ExecStep, CheckSteps, PyStep, Common import logging import os @@ -26,19 +26,33 @@ for test_type in ['athena','athenaHLT','Reco_tf','Trig_reco_tf']: ex.args = '--help' test.exec_steps.append(ex) +def hello(): + print('### Hello World') + +def hello_throw(): + raise RuntimeError('Hello World') + +test.exec_steps.append(PyStep.PyStep(hello, name='hello_stdout')) +test.exec_steps.append(PyStep.PyStep(hello_throw)) +s = PyStep.PyStep(hello, name='hello_file') +s.output_stream = s.OutputStream.FILE_AND_STDOUT +test.exec_steps.append(s) + + test.art_type = 'build' test.check_steps = CheckSteps.default_check_steps(test) -regtest_ref_text = [ - '### athena.log ###', - '### athena.Test_athena.log ###', - '### athenaHLT.Test_athenaHLT.log ###', - '### Reco_tf.Test_Reco_tf.log ###', - '### Trig_reco_tf.Test_Trig_reco_tf.log ###', -] +regtest_ref_text = """\ +### athena.log ### +### athena.Test_athena.log ### +### athenaHLT.Test_athenaHLT.log ### +### Reco_tf.Test_Reco_tf.log ### +### Trig_reco_tf.Test_Trig_reco_tf.log ### +### hello_file.log ### +### Hello World""" with open('regtest.ref','w') as f: - f.write('\n'.join(regtest_ref_text)) + f.write(regtest_ref_text) refcomp = CheckSteps.RegTestStep('RefComp') refcomp.input_base_name = 'athena.merged' -- GitLab