1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
|
#!/usr/bin/env python3
import os
import sys
import argparse
import fnmatch
import FWCore.ParameterSet.Config as cms
import HLTrigger.Configuration.Tools.pipe as pipe
import HLTrigger.Configuration.Tools.options as options
from HLTrigger.Configuration.extend_argparse import *
def getPathList(args):
if isinstance(args.menu, options.ConnectionHLTMenu):
# cmd to download HLT configuration
cmdline = 'hltConfigFromDB'
if args.menu.run:
cmdline += f' --runNumber {args.menu.run}'
else:
cmdline += f' --{args.menu.database} --{args.menu.version} --configName {args.menu.name}'
cmdline += ' --noedsources --noes --noservices'
if args.proxy:
cmdline += f' --dbproxy --dbproxyhost {args.proxy_host} --dbproxyport {args.proxy_port}'
else:
# use edmConfigDump to ensure the config can be executed
cmdline = f'edmConfigDump {args.menu}'
# load HLT configuration
try:
foo = {'process': None}
exec(pipe.pipe(cmdline).decode(), foo)
process = foo['process']
except:
raise Exception(f'query did not return a valid python file:\n query="{cmdline}"')
if not isinstance(process, cms.Process):
raise Exception(f'query did not return a valid HLT menu:\n query="{cmdline}"')
usePaths, useEndPaths = False, False
# Paths only
if args.selection == 'paths':
usePaths = True
# EndPaths only
elif args.selection == 'endpaths':
useEndPaths = True
# Paths and EndPaths ('all')
elif args.selection == 'all':
usePaths, useEndPaths = True, True
# invalid value
else:
raise RuntimeError(f'ERROR: invalid value for option "--selection" (must be "paths", "endpaths", or "all"): {args.selection}')
path_keep_rules = []
for path_keep_rule in args.path_keep_rules.split(','):
if not path_keep_rule:
continue
keep_rule = not path_keep_rule.startswith('-')
pattern_idx = 0 if keep_rule else 1
rule_pattern = path_keep_rule[pattern_idx:]
path_keep_rules += [(keep_rule, rule_pattern)]
ret = []
for pathDict in [
process.paths_() if usePaths else None,
process.endpaths_() if useEndPaths else None,
]:
if pathDict == None:
continue
for pathName in pathDict:
# keep or drop the Path based on whether or not
# its name complies with the patterns in path_keep_rules (if any)
keepPath = not path_keep_rules
for (keep_rule, rule_pattern) in path_keep_rules:
if fnmatch.fnmatch(pathName, rule_pattern):
keepPath = keep_rule
if not keepPath:
continue
if args.no_dependent_paths:
# do not include "dependent paths", i.e. paths that depend on the result of other paths in the same job
# the current criterion to identify a path as "dependent" is that
# (1) the path contains a "TriggerResultsFilter" module and
# (2) the latter module uses the TriggerResults of the current process, and has a non-empty list of "triggerConditions"
path = pathDict[pathName]
pathIsDependent = False
isPath = isinstance(path, cms.Path)
for moduleName in path.moduleNames():
module = getattr(process, moduleName)
if module.type_() != 'TriggerResultsFilter' or (hasattr(module, 'triggerConditions') and len(module.triggerConditions) == 0):
continue
usesPathStatus = hasattr(module, 'usePathStatus') and module.usePathStatus
usesTrigResOfCurrentProcess = hasattr(module, 'hltResults') and module.hltResults.getProcessName() in [process.name_(), '@currentProcess']+['']*(not isPath)
if isPath:
if usesPathStatus:
pathIsDependent = True
elif usesTrigResOfCurrentProcess:
# The Path contains a TriggerResultsFilter with usePathStatus=False and forcing access to the TriggerResults of the current Process.
# - This is not supported, and should result in a runtime error when using cmsRun.
# - Here, a warning is returned to stderr, and the Path is omitted from the output list.
warning_msg = 'WARNING -- the cms.Path named "'+pathName+'" will be ignored.'
warning_msg += '\n'+' '*12+'- It contains a "TriggerResultsFilter" attempting to access the "TriggerResults" of the current Process (module: "'+moduleName+'").'
warning_msg += '\n'+' '*12+'- This is not supported, and should result in a runtime error when using cmsRun. Please check again the HLT configuration.'
print(warning_msg, file=sys.stderr)
pathIsDependent = True
else:
pathIsDependent = usesPathStatus or usesTrigResOfCurrentProcess
if pathIsDependent:
break
if pathIsDependent:
continue
ret.append(pathName)
return ret
# define an argparse parser to parse our options
textwidth = int( 80 )
try:
textwidth = int( os.popen("stty size", "r").read().split()[1] )
except:
pass
formatter = FixedWidthFormatter( HelpFormatterRespectNewlines, width = textwidth )
# read defaults
defaults = options.HLTProcessOptions()
def hltMenu(name):
return name if os.path.isfile(name) else options.ConnectionHLTMenu(name)
parser = argparse.ArgumentParser(
description = 'List all the Paths and EndPaths of an HLT configuration.',
argument_default = argparse.SUPPRESS,
formatter_class = formatter,
add_help = False )
# required argument
parser.add_argument('menu',
action = 'store',
type = hltMenu,
metavar = 'MENU',
help = 'HLT menu (can be a local cmsRun configuration file, or the name of a configuration in the ConfDB database).\nFor ConfDB configurations, supported formats are:\n- /path/to/configuration[/Vn]\n- [[{v1|v2|v3}/]{run3|run2|online|adg}:]/path/to/configuration[/Vn]\n- run:runnumber\nThe possible converters are "v1", "v2, and "v3" (default).\nThe possible databases are\n"run3" (default, used for offline development in Run 3),\n"run2" (used for accessing Run-2 offline development menus),\n"online" (used to extract online menus from inside Point 5) and\n"adg" (used to extract the online menus from outside Point 5).\nIf no menu version is specified, the latest one is automatically used.\nIf "run:" is used instead, the HLT menu used for the given run number is looked up and used.\nNote: other converters and databases exist, but they are only for expert/special use.' )
# options
parser.add_argument('--dbproxy',
dest = 'proxy',
action = 'store_true',
default = defaults.proxy,
help = 'Use a socks proxy to connect outside CERN network (default: False)' )
parser.add_argument('--dbproxyport',
dest = 'proxy_port',
action = 'store',
metavar = 'PROXYPORT',
default = defaults.proxy_port,
help = 'Port of the socks proxy (default: 8080)' )
parser.add_argument('--dbproxyhost',
dest = 'proxy_host',
action = 'store',
metavar = 'PROXYHOST',
default = defaults.proxy_host,
help = 'Host of the socks proxy (default: "localhost")' )
group = parser.add_mutually_exclusive_group()
group.add_argument('-p', '--only-paths',
dest = 'selection',
action = 'store_const',
const = 'paths',
help = 'List only Paths' )
group.add_argument('-e', '--only-endpaths',
dest = 'selection',
action = 'store_const',
const = 'endpaths',
help = 'List only EndPaths' )
group.add_argument('-a', '--all',
dest = 'selection',
action = 'store_const',
const = 'all',
default = 'all',
help = 'List Paths and EndPaths (default)' )
parser.add_argument('--no-dependent-paths',
dest = 'no_dependent_paths',
action = 'store_true',
default = False,
help = 'Do not list paths which depend on the result of other paths (default: false)' )
parser.add_argument('-s', '--select-paths',
dest = 'path_keep_rules',
action = 'store',
default = '',
help = 'Comma-separated list of Path-name patterns (incl. wildcards) to select a subset of Paths using fnmatch.\nIf a Path-name pattern starts with the dash character (-), the Paths whose name matches that pattern are not selected.\nThe patterns are ordered: a given pattern can override previous ones (example: "*,-Foo,*" retains all Paths)\n(default: empty, meaning all Paths are kept)')
# redefine "--help" to be the last option, and use a customized message
parser.add_argument('-h', '--help',
action = 'help',
help = 'Show this help message and exit' )
# parse command line arguments and options
args = parser.parse_args()
paths = getPathList(args)
for path in paths:
print(path)
|