Loading [MathJax]/extensions/tex2jax.js
The Gaudi Framework  master (d98a2936)
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
ProcessJobOptions.py
Go to the documentation of this file.
1 
11 import logging
12 import os
13 import re
14 import sys
15 import time
16 
17 _log = logging.getLogger(__name__)
18 
19 
20 class LogFormatter(logging.Formatter):
21  def __init__(self, fmt=None, datefmt=None, prefix="# ", with_time=False):
22  logging.Formatter.__init__(self, fmt, datefmt)
23  self.prefix = prefix
24  self.with_time = with_time
25 
26  def format(self, record):
27  fmsg = logging.Formatter.format(self, record)
28  prefix = self.prefix
29  if self.with_time:
30  prefix += "%f " % time.time()
31  if record.levelno >= logging.WARNING:
32  prefix += record.levelname + ": "
33  s = "\n".join([prefix + line for line in fmsg.splitlines()])
34  return s
35 
36 
37 class LogFilter(logging.Filter):
38  def __init__(self, name=""):
39  logging.Filter.__init__(self, name)
40  self.printing_level = 0
41  self.enabled = True
42  self.threshold = logging.WARNING
43 
44  def filter(self, record):
45  return record.levelno >= self.threshold or (
46  self.enabled and self.printing_level <= 0
47  )
48 
49  def printOn(self, step=1, force=False):
50  """
51  Decrease the printing_level of 'step' units. ( >0 means no print)
52  The level cannot go below 0, unless the force flag is set to True.
53  A negative value of the threshold disables subsequent "PrintOff"s.
54  """
55  if force:
56  self.printing_level -= step
57  else:
58  if self.printing_level > step:
59  self.printing_level -= step
60  else:
61  self.printing_level = 0
62 
63  def printOff(self, step=1):
64  """
65  Increase the printing_level of 'step' units. ( >0 means no print)
66  """
67  self.printing_level += step
68 
69  def disable(self, allowed=logging.WARNING):
70  self.enabled = False
71  self.threshold = allowed
72 
73  def enable(self, allowed=logging.WARNING):
74  self.enabled = True
75  self.threshold = allowed
76 
77 
78 class ConsoleHandler(logging.StreamHandler):
79  def __init__(self, stream=None, prefix=None, with_time=False):
80  if stream is None:
81  stream = sys.stdout
82  logging.StreamHandler.__init__(self, stream)
83  if prefix is None:
84  prefix = "# "
85  self._filter = LogFilter(_log.name)
86  self._formatter = LogFormatter(prefix=prefix, with_time=with_time)
87  self.setFormatter(self._formatter)
88  self.addFilter(self._filter)
89 
90  def setPrefix(self, prefix):
91  self._formatter.prefix = prefix
92 
93  def printOn(self, step=1, force=False):
94  """
95  Decrease the printing_level of 'step' units. ( >0 means no print)
96  The level cannot go below 0, unless the force flag is set to True.
97  A negative value of the threshold disables subsequent "PrintOff"s.
98  """
99  self._filter.printOn(step, force)
100 
101  def printOff(self, step=1):
102  """
103  Increase the printing_level of 'step' units. ( >0 means no print)
104  """
105  self._filter.printOff(step)
106 
107  def disable(self, allowed=logging.WARNING):
108  self._filter.disable(allowed)
109 
110  def enable(self, allowed=logging.WARNING):
111  self._filter.enable(allowed)
112 
113 
114 _consoleHandler = None
115 
116 
117 def GetConsoleHandler(prefix=None, stream=None, with_time=False):
118  global _consoleHandler
119  if _consoleHandler is None:
120  _consoleHandler = ConsoleHandler(
121  prefix=prefix, stream=stream, with_time=with_time
122  )
123  elif prefix is not None:
124  _consoleHandler.setPrefix(prefix)
125  return _consoleHandler
126 
127 
128 def InstallRootLoggingHandler(prefix=None, level=None, stream=None, with_time=False):
129  root_logger = logging.getLogger()
130  if not root_logger.handlers:
131  root_logger.addHandler(GetConsoleHandler(prefix, stream, with_time))
132  root_logger.setLevel(logging.WARNING)
133  if level is not None:
134  root_logger.setLevel(level)
135 
136 
137 def PrintOn(step=1, force=False):
138  GetConsoleHandler().printOn(step, force)
139 
140 
141 def PrintOff(step=1):
142  GetConsoleHandler().printOff(step)
143 
144 
145 class ParserError(RuntimeError):
146  pass
147 
148 
149 def _find_file(f):
150  # expand environment variables in the filename
151  f = os.path.expandvars(f)
152  if os.path.isfile(f):
153  return os.path.realpath(f)
154 
155  path = os.environ.get("JOBOPTSEARCHPATH", "").split(os.pathsep)
156  # find the full path to the option file
157  candidates = [d for d in path if os.path.isfile(os.path.join(d, f))]
158  if not candidates:
159  raise ParserError("Cannot find '%s' in %s" % (f, path))
160  return os.path.realpath(os.path.join(candidates[0], f))
161 
162 
163 _included_files = set()
164 
165 
167  if f in _included_files:
168  _log.warning("file '%s' already included, ignored.", f)
169  return False
170  _included_files.add(f)
171  return True
172 
173 
175  comment = re.compile(r"(//.*)$")
176  # non-perfect R-E to check if '//' is inside a string
177  # (a tokenizer would be better)
178  comment_in_string = re.compile(r'(["\']).*//.*\1')
179  directive = re.compile(r"^\s*#\s*([\w!]+)\s*(.*)\s*$")
180  comment_ml = (re.compile(r"/\*"), re.compile(r"\*/"))
181  statement_sep = ";"
182  reference = re.compile(r"^@([\w.]*)$")
183 
184  def __init__(self):
185  # parser level states
186  self.units = {}
187  self.defines = {}
188 
189  def _include(self, file, function):
190  file = _find_file(file)
191  if _to_be_included(file):
192  _log.info("--> Including file '%s'", file)
193  function(file)
194  _log.info("<-- End of file '%s'", file)
195 
196  def parse(self, file):
197  # states for the "translation unit"
198  statement = ""
199 
200  ifdef_level = 0
201  ifdef_skipping = False
202  ifdef_skipping_level = 0
203 
204  in_string = False
205 
206  f = open(_find_file(file))
207  l = f.readline()
208  if l.startswith("#!"):
209  # Skip the first line if it starts with "#!".
210  # It allows to use options files as scripts.
211  l = f.readline()
212 
213  while l:
214  l = (
215  l.rstrip() + "\n"
216  ) # normalize EOL chars (to avoid problems with DOS new-line on Unix)
217 
218  # single line comment
219  m = self.comment.search(l)
220  if m:
221  # check if the '//' is part of a string
222  m2 = self.comment_in_string.search(l)
223  # the '//' is part of a string if we find the quotes around it
224  # and they are not part of the comment itself
225  if not (m2 and m2.start() < m.start()):
226  # if it is not the case, we can remove the comment from the
227  # statement
228  l = l[: m.start()] + l[m.end() :]
229  # process directives
230  m = self.directive.search(l)
231  if m:
232  directive_name = m.group(1)
233  directive_arg = m.group(2).strip()
234  if directive_name == "include":
235  included_file = directive_arg.strip("'\"")
236  importOptions(included_file)
237  elif directive_name == "units":
238  units_file = directive_arg.strip("'\"")
239  self._include(units_file, self._parse_units)
240  elif directive_name in ["ifdef", "ifndef"]:
241  ifdef_skipping_level = ifdef_level
242  ifdef_level += 1
243  if directive_arg in self.defines:
244  ifdef_skipping = directive_name == "ifndef"
245  else:
246  ifdef_skipping = directive_name == "ifdef"
247  elif directive_name == "else":
248  ifdef_skipping = not ifdef_skipping
249  elif directive_name == "endif":
250  ifdef_level -= 1
251  if ifdef_skipping and ifdef_skipping_level == ifdef_level:
252  ifdef_skipping = False
253  elif directive_name == "pragma":
254  if not directive_arg:
255  l = f.readline()
256  continue
257  pragma = directive_arg.split()
258  if pragma[0] == "print":
259  if len(pragma) > 1:
260  if pragma[1].upper() in ["ON", "TRUE", "1"]:
261  PrintOn()
262  else:
263  PrintOff()
264  else:
265  _log.warning("unknown directive '%s'", directive_name)
266  l = f.readline()
267  continue
268 
269  if ifdef_skipping:
270  l = f.readline()
271  continue
272 
273  # multi-line comment
274  m = self.comment_ml[0].search(l)
275  if m:
276  l, l1 = l[: m.start()], l[m.end() :]
277  m = self.comment_ml[1].search(l1)
278  while not m:
279  l1 = f.readline()
280  if not l1:
281  break # EOF
282  m = self.comment_ml[1].search(l1)
283  if not l1 and not m:
284  raise ParserError(
285  "End Of File reached before end of multi-line comment"
286  )
287  l += l1[m.end() :]
288 
289  # if we are in a multiline string, we add to the statement
290  # everything until the next '"'
291  if in_string:
292  string_end = l.find('"')
293  if string_end >= 0:
294  statement += l[: string_end + 1]
295  l = l[string_end + 1 :]
296  in_string = False # the string ends here
297  else:
298  statement += l
299  l = ""
300  else: # check if we have a string
301  string_start = l.find('"')
302  if string_start >= 0:
303  string_end = l.find('"', string_start + 1)
304  if string_end >= 0:
305  # the string is opened and closed
306  statement += l[: string_end + 1]
307  l = l[string_end + 1 :]
308  else:
309  # the string is only opened
310  statement += l
311  in_string = True
312  l = f.readline()
313  continue
314 
315  if self.statement_sep in l:
316  i = l.index(self.statement_sep)
317  statement += l[:i]
318  self._eval_statement(statement.strip().replace("\n", "\\n"))
319  statement = l[i + 1 :]
320  # it may happen (bug #37479) that the rest of the statement
321  # contains a comment.
322  if statement.lstrip().startswith("//"):
323  statement = ""
324  else:
325  statement += l
326 
327  l = f.readline()
328 
329  def _parse_units(self, file):
330  for line in open(file):
331  if "//" in line:
332  line = line[: line.index("//")]
333  line = line.strip()
334  if not line:
335  continue
336  nunit, value = line.split("=")
337  factor, unit = nunit.split()
338  value = eval(value) / eval(factor)
339  self.units[unit] = value
340 
341  def _eval_statement(self, statement):
342  from GaudiKernel.Proxy.Configurable import (
343  Configurable,
344  ConfigurableGeneric,
345  PropertyReference,
346  )
347 
348  # statement = statement.replace("\n","").strip()
349  _log.info("%s%s", statement, self.statement_sep)
350 
351  property, value = statement.split("=", 1)
352 
353  inc = None
354  if property[-1] in ["+", "-"]:
355  inc = property[-1]
356  property = property[:-1]
357 
358  property = property.strip()
359  value = value.strip()
360 
361  # find the configurable to apply the property to
362  # parent_cfg = None
363  # while '.' in property:
364  # component, property = property.split('.',1)
365  # if parent_cfg:
366  # if hasattr(parent_cfg,component):
367  # cfg = getattr(parent_cfg,component)
368  # else:
369  # cfg = ConfigurableGeneric(component)
370  # setattr(parent_cfg,component,cfg)
371  # else:
372  # cfg = ConfigurableGeneric(component)
373  # parent_cfg = cfg
374 
375  # remove spaces around dots
376  property = ".".join([w.strip() for w in property.split(".")])
377  component, property = property.rsplit(".", 1)
378  if component in Configurable.allConfigurables:
379  cfg = Configurable.allConfigurables[component]
380  else:
381  cfg = ConfigurableGeneric(component)
382 
383  # value = os.path.expandvars(value)
384  value = value.replace("true", "True").replace("false", "False")
385  if value[0] == "{":
386  # Try to guess if the values looks like a dictionary
387  if ":" in value and not (
388  value[: value.index(":")].count('"') % 2
389  or value[: value.index(":")].count("'") % 2
390  ):
391  # for dictionaries, keep the surrounding {}
392  value = "{" + value[1:-1].replace("{", "[").replace("}", "]") + "}"
393  else: # otherwise replace all {} with []
394  value = value.replace("{", "[").replace("}", "]")
395 
396  # We must escape '\' because eval tends to interpret them
397  value = value.replace("\\", "\\\\")
398  # Restore special cases ('\n', '\t' and '\"') (see GAUDI-1001)
399  value = (
400  value.replace(r"\\n", r"\n").replace(r"\\t", r"\t").replace(r'\\"', r"\"")
401  )
402  # replace r'\n' and r'\t' that are outside double quoted strings
403  value = '"'.join(
404  [
405  (v if i % 2 else re.sub(r"\\[nt]", " ", v))
406  for i, v in enumerate(value.split('"'))
407  ]
408  )
409 
410  # interprete the @ operator
411  m = self.reference.match(value)
412  if m:
413  # this allows late binding of references
414  value = PropertyReference(m.group(1))
415  else:
416  value = eval(value, self.units)
417 
418  # if type(value) is str : value = os.path.expandvars(value)
419  # elif type(value) is list : value = [ type(item) is str and os.path.expandvars(item) or item for item in value ]
420 
421  if property not in cfg.__slots__ and not hasattr(cfg, property):
422  # check if the case of the property is wrong (old options are case insensitive)
423  lprop = property.lower()
424  for p in cfg.__slots__:
425  if lprop == p.lower():
426  _log.warning(
427  "property '%s' was requested for %s, but the correct spelling is '%s'",
428  property,
429  cfg.name(),
430  p,
431  )
432  property = p
433  break
434 
435  # consider the += and -=
436  if inc == "+":
437  if hasattr(cfg, property):
438  prop = getattr(cfg, property)
439  if isinstance(prop, dict):
440  for k in value:
441  prop[k] = value[k]
442  else:
443  prop += value
444  else:
445  setattr(cfg, property, value)
446  elif inc == "-":
447  if hasattr(cfg, property):
448  prop = getattr(cfg, property)
449  if isinstance(prop, dict):
450  for k in value:
451  if k in prop:
452  del prop[k]
453  else:
454  _log.warning(
455  "key '%s' not in %s.%s", k, cfg.name(), property
456  )
457  else:
458  for k in value:
459  if k in prop:
460  prop.remove(k)
461  else:
462  _log.warning(
463  "value '%s' not in %s.%s", k, cfg.name(), property
464  )
465  else:
466  setattr(cfg, property, value)
467 
468 
470  def __init__(self, new_path):
471  self.old_path = sys.path
472  sys.path = new_path
473 
474  def __del__(self):
475  sys.path = self.old_path
476 
477 
478 _parser = JobOptsParser()
479 
480 
481 def _import_python(file):
482  with open(file) as f:
483  code = compile(f.read(), file, "exec")
484  exec(code, {"__file__": file})
485 
486 
487 def _import_pickle(file):
488  import pickle
489 
490  input = open(file, "rb")
491  catalog = pickle.load(input)
492  _log.info("Unpickled %d configurables", len(catalog))
493 
494 
495 def _import_opts(file):
496  _parser.parse(file)
497 
498 
499 def _import_dict(data):
500  from GaudiKernel.Proxy.Configurable import Configurable, ConfigurableGeneric
501 
502  for property, value_repr in data.items():
503  component, property = property.rsplit(".", 1)
504  if component in Configurable.allConfigurables:
505  cfg = Configurable.allConfigurables[component]
506  else:
507  cfg = ConfigurableGeneric(component)
508  value = eval(value_repr)
509  setattr(cfg, property, value)
510 
511 
512 def _import_json(filename):
513  import json
514 
515  with open(filename) as f:
516  _import_dict(json.load(f))
517 
518 
519 _import_function_mapping = {
520  ".py": _import_python,
521  ".pkl": _import_pickle,
522  ".opts": _import_opts,
523  ".json": _import_json,
524 }
525 
526 try:
527  import yaml
528 
529  def _import_yaml(filename):
530  with open(filename) as f:
531  _import_dict(yaml.safe_load(f))
532 
533  _import_function_mapping[".yaml"] = _import_yaml
534  _import_function_mapping[".yml"] = _import_function_mapping[".yaml"]
535 except ImportError:
536  pass # yaml support is optional
537 
538 
539 def importOptions(optsfile):
540  # expand environment variables before checking the extension
541  optsfile = os.path.expandvars(optsfile)
542  # check the file type (extension)
543  dummy, ext = os.path.splitext(optsfile)
544  if ext in _import_function_mapping:
545  # check if the file has been already included
546  optsfile = _find_file(optsfile)
547  if _to_be_included(optsfile):
548  _log.info("--> Including file '%s'", optsfile)
549  # include the file
550  _import_function_mapping[ext](optsfile)
551  _log.info("<-- End of file '%s'", optsfile)
552  else:
553  raise ParserError("Unknown file type '%s' ('%s')" % (ext, optsfile))
554 
555 
556 # Import a file containing declaration of units.
557 # It is equivalent to:
558 #
559 # #units "unitsfile.opts"
560 #
561 
562 
563 def importUnits(unitsfile):
564  # expand environment variables
565  unitsfile = os.path.expandvars(unitsfile)
566  # we do not need to check the file type (extension) because it must be a
567  # units file
568  _parser._include(unitsfile, _parser._parse_units)
GaudiKernel.ProcessJobOptions.GetConsoleHandler
def GetConsoleHandler(prefix=None, stream=None, with_time=False)
Definition: ProcessJobOptions.py:117
GaudiKernel.ProcessJobOptions.JobOptsParser.parse
def parse(self, file)
Definition: ProcessJobOptions.py:196
GaudiKernel.ProcessJobOptions._import_dict
def _import_dict(data)
Definition: ProcessJobOptions.py:499
GaudiKernel.ProcessJobOptions._import_opts
def _import_opts(file)
Definition: ProcessJobOptions.py:495
GaudiKernel.ProcessJobOptions.JobOptsParser._parse_units
def _parse_units(self, file)
Definition: ProcessJobOptions.py:329
GaudiKernel.ProcessJobOptions.importUnits
def importUnits(unitsfile)
Definition: ProcessJobOptions.py:563
GaudiKernel.ProcessJobOptions.LogFormatter
Definition: ProcessJobOptions.py:20
GaudiKernel.ProcessJobOptions.ConsoleHandler.disable
def disable(self, allowed=logging.WARNING)
Definition: ProcessJobOptions.py:107
GaudiKernel.ProcessJobOptions.JobOptsParser.comment
comment
Definition: ProcessJobOptions.py:175
GaudiKernel.ProcessJobOptions._find_file
def _find_file(f)
Definition: ProcessJobOptions.py:149
GaudiKernel.ProcessJobOptions.LogFilter.disable
def disable(self, allowed=logging.WARNING)
Definition: ProcessJobOptions.py:69
GaudiKernel.ProcessJobOptions.LogFilter.printOff
def printOff(self, step=1)
Definition: ProcessJobOptions.py:63
GaudiKernel.ProcessJobOptions.ConsoleHandler._formatter
_formatter
Definition: ProcessJobOptions.py:86
GaudiKernel.ProcessJobOptions._TempSysPath.old_path
old_path
Definition: ProcessJobOptions.py:471
GaudiKernel.ProcessJobOptions.LogFilter.printing_level
printing_level
Definition: ProcessJobOptions.py:40
GaudiKernel.ProcessJobOptions._to_be_included
def _to_be_included(f)
Definition: ProcessJobOptions.py:166
GaudiKernel.ProcessJobOptions.JobOptsParser._include
def _include(self, file, function)
Definition: ProcessJobOptions.py:189
GaudiKernel.ProcessJobOptions.LogFilter.enabled
enabled
Definition: ProcessJobOptions.py:41
GaudiKernel.ProcessJobOptions.JobOptsParser.comment_ml
comment_ml
Definition: ProcessJobOptions.py:180
GaudiKernel.ProcessJobOptions._TempSysPath.__init__
def __init__(self, new_path)
Definition: ProcessJobOptions.py:470
GaudiKernel.ProcessJobOptions.LogFilter
Definition: ProcessJobOptions.py:37
GaudiKernel.ProcessJobOptions.JobOptsParser.__init__
def __init__(self)
Definition: ProcessJobOptions.py:184
GaudiKernel.ProcessJobOptions.ConsoleHandler._filter
_filter
Definition: ProcessJobOptions.py:85
GaudiKernel.ProcessJobOptions.ConsoleHandler.printOff
def printOff(self, step=1)
Definition: ProcessJobOptions.py:101
GaudiKernel.ProcessJobOptions._TempSysPath.__del__
def __del__(self)
Definition: ProcessJobOptions.py:474
GaudiKernel.ProcessJobOptions.LogFormatter.with_time
with_time
Definition: ProcessJobOptions.py:24
GaudiKernel.ProcessJobOptions._import_yaml
def _import_yaml(filename)
Definition: ProcessJobOptions.py:529
GaudiKernel.ProcessJobOptions.JobOptsParser.defines
defines
Definition: ProcessJobOptions.py:187
GaudiKernel.ProcessJobOptions.ConsoleHandler.setPrefix
def setPrefix(self, prefix)
Definition: ProcessJobOptions.py:90
GaudiKernel.ProcessJobOptions.JobOptsParser.units
units
Definition: ProcessJobOptions.py:186
GaudiKernel.ProcessJobOptions.LogFormatter.format
def format(self, record)
Definition: ProcessJobOptions.py:26
GaudiKernel.ProcessJobOptions.JobOptsParser.directive
directive
Definition: ProcessJobOptions.py:179
GaudiKernel.ProcessJobOptions.JobOptsParser
Definition: ProcessJobOptions.py:174
GaudiKernel.ProcessJobOptions._import_json
def _import_json(filename)
Definition: ProcessJobOptions.py:512
GaudiKernel.ProcessJobOptions.ConsoleHandler.printOn
def printOn(self, step=1, force=False)
Definition: ProcessJobOptions.py:93
GaudiKernel.ProcessJobOptions.InstallRootLoggingHandler
def InstallRootLoggingHandler(prefix=None, level=None, stream=None, with_time=False)
Definition: ProcessJobOptions.py:128
GaudiKernel.ProcessJobOptions.ConsoleHandler.enable
def enable(self, allowed=logging.WARNING)
Definition: ProcessJobOptions.py:110
GaudiKernel.ProcessJobOptions.LogFormatter.__init__
def __init__(self, fmt=None, datefmt=None, prefix="# ", with_time=False)
Definition: ProcessJobOptions.py:21
GaudiKernel.ProcessJobOptions.importOptions
def importOptions(optsfile)
Definition: ProcessJobOptions.py:539
GaudiKernel.ProcessJobOptions.LogFilter.enable
def enable(self, allowed=logging.WARNING)
Definition: ProcessJobOptions.py:73
GaudiKernel.ProcessJobOptions.JobOptsParser.statement_sep
statement_sep
Definition: ProcessJobOptions.py:181
GaudiKernel.ProcessJobOptions.ConsoleHandler
Definition: ProcessJobOptions.py:78
GaudiKernel.ProcessJobOptions._import_pickle
def _import_pickle(file)
Definition: ProcessJobOptions.py:487
GaudiKernel.ProcessJobOptions.LogFormatter.prefix
prefix
Definition: ProcessJobOptions.py:23
GaudiKernel.ProcessJobOptions.JobOptsParser._eval_statement
def _eval_statement(self, statement)
Definition: ProcessJobOptions.py:341
GaudiKernel.ProcessJobOptions._import_python
def _import_python(file)
Definition: ProcessJobOptions.py:481
GaudiKernel.ProcessJobOptions.LogFilter.__init__
def __init__(self, name="")
Definition: ProcessJobOptions.py:38
GaudiKernel.ProcessJobOptions._TempSysPath
Definition: ProcessJobOptions.py:469
GaudiKernel.ProcessJobOptions.JobOptsParser.comment_in_string
comment_in_string
Definition: ProcessJobOptions.py:178
GaudiKernel.ProcessJobOptions.PrintOff
def PrintOff(step=1)
Definition: ProcessJobOptions.py:141
GaudiKernel.ProcessJobOptions.JobOptsParser.reference
reference
Definition: ProcessJobOptions.py:182
GaudiKernel.ProcessJobOptions.LogFilter.printOn
def printOn(self, step=1, force=False)
Definition: ProcessJobOptions.py:49
GaudiKernel.ProcessJobOptions.ParserError
Definition: ProcessJobOptions.py:145
GaudiKernel.ProcessJobOptions.LogFilter.filter
def filter(self, record)
Definition: ProcessJobOptions.py:44
GaudiKernel.ProcessJobOptions.PrintOn
def PrintOn(step=1, force=False)
Definition: ProcessJobOptions.py:137
GaudiKernel.ProcessJobOptions.LogFilter.threshold
threshold
Definition: ProcessJobOptions.py:42
GaudiKernel.ProcessJobOptions.ConsoleHandler.__init__
def __init__(self, stream=None, prefix=None, with_time=False)
Definition: ProcessJobOptions.py:79