Belle II Software  release-08-01-10
utilities.py
1 
8 
9 import basf2
10 
11 import os
12 import os.path
13 import sys
14 import argparse
15 import collections
16 
17 
18 class ArgumentParser(argparse.ArgumentParser):
19 
20  """An argparse.Argument parse slightly changed such
21  that it always prints an extended help message incase of a parsing error."""
22 
23  def error(self, message):
24  """Method invoked when a parsing error occured.
25  Writes an extended help over the base ArgumentParser.
26  """
27  self.print_help()
28  sys.stderr.write('error: %s\n' % message)
29  sys.exit(2)
30 
31 
32 class NonstrictChoices(list):
33 
34  """Class that instances can be given to an argparse.ArgumentParser.add_argument as choices keyword argument.
35 
36  The explicit choices stated during construction of this object are just suggestions but all other values are
37  excepted as well.
38  """
39 
40  def __contains__(self, value):
41  """Test for correctness of the choices.
42  Always returns true since all choices should be valid not only the ones stated at construction of this object.
43  """
44  return True
45 
46  def __iter__(self):
47  """Displays all explicit values and a final "..." to indicate more choices might be possible."""
48  # Append an ellipses to indicate that there are more choices.
49  copy = list(super().__iter__())
50  copy.append('...')
51  return iter(copy)
52 
53  def __str__(self):
54  """Displays all explicit values and a final "..." to indicate more choices might be possible."""
55  # Append an ellipses to indicate that there are more choices.
56  copy = list(self)
57  copy.append('...')
58  return str(copy)
59 
60 
61 def find_file(file_path):
62  # dec_file_path = Belle2.FileSystem.findFile(generator_module)
63  belle2_local_dir = os.environ.get("BELLE2_LOCAL_DIR", None)
64  if belle2_local_dir:
65  local_file_path = os.path.join(belle2_local_dir, file_path)
66  if os.path.exists(local_file_path) and os.path.isfile(local_file_path):
67  return local_file_path
68 
69  belle2_central_dir = os.environ.get("BELLE2_RELEASE_DIR", None)
70  if belle2_central_dir:
71  central_file_path = os.path.join(belle2_central_dir, file_path)
72  if os.path.exists(central_file_path) and os.path.isfile(central_file_path):
73  return central_file_path
74 
75  if os.path.exists(file_path) and os.path.isfile(file_path):
76  return file_path
77 
78  return None
79 
80 
81 def extend_path(path,
82  module,
83  module_by_short_name={},
84  allow_function_import=False):
85  """Convenience adder function that can resolve addtional short hand module names from a dictionary"""
86  if isinstance(module, basf2.Module):
87  # A module instance
88  path.add_module(module)
89 
90  elif isinstance(module, str):
91  # A module name of a short name as defined in the forwarded dictionary
92  if allow_function_import:
93  if "." in module:
94  # Allow imports from the local directory
95  sys.path.append(os.getcwd())
96 
97  py_module_name, function_name = module.rsplit(".", 1)
98  try:
99  import importlib
100  py_module = importlib.import_module(py_module_name)
101  except ImportError:
102  pass
103  else:
104  py_function = getattr(py_module, function_name)
105  py_function(path)
106  return
107 
108  if module in module_by_short_name:
109  short_name = module
110  module = module_by_short_name[short_name]
111  # module is a short name
112  # resolve it and add it
113  extend_path(path, module, module_by_short_name)
114  else:
115  # module is a module name from basf2
116  path.add_module(module)
117 
118  elif callable(module):
119  # A convenience function or a module class
120  try:
121  if issubclass(module, basf2.Module):
122  # module is a module class
123  # create an instance and add it to the path
124  module_instance = module()
125  path.add_module(module_instance)
126  return
127  except TypeError:
128  pass
129 
130  # module is not a module class
131  # try it as a convenience function that add modules to the path
132  module(path)
133 
134  elif isinstance(module, collections.Iterable):
135  # A list of modules or basf2.Path
136  modules = module
137  for module in modules:
138  extend_path(path, module, module_by_short_name)
139  else:
140  message_template = """
141 '%s of type %s is neither
142 * a module instance
143 * a module (python) class
144 * a module name
145 * a add_* function
146 * a short name resolveable from %s.'
147 * an iterable of the above (e.g. basf2.Path)
148 """
149  raise ValueError(message_template % (module,
150  type(module),
151  module_by_short_name.keys()))
152 
153 
154 def get_module_param(module, name):
155  parameters = module.available_params()
156  for parameter in parameters:
157  if name == parameter.name:
158  return parameter.values
159  else:
160  raise AttributeError('%s module does not have a parameter named %s' % (module, name))