9 from lxml.builder
import E
10 from IPython
import get_ipython
11 from .
import core
as b2core
12 import multiprocessing
15 from ROOT
import Belle2
18 _process_warning =
False
21 def _create_pathhtml(path, name="Path", details=None):
22 """Create an html fragment for a given Path object"""
23 size = len(path.modules())
24 fragment = E.div(f
"{name} with {size} modules")
25 if details
is not None:
26 fragment.append(details)
28 module_list = E.ol(style=
"list-style-type:decimal; font-style:normal;")
29 for m
in path.modules():
32 tname = f
" (type \"{tname}\")" if tname != name
else ""
33 module = E.li(
"Module ", E.b(name), tname)
34 detail_list = E.ul(style=
"margin:0em 0em 0.5em 0em")
35 for p
in m.available_params():
37 detail_list.append(E.li(E.code(f
"{p.name} = {p.values}")))
38 for c
in m.get_all_conditions():
39 after = str(c.get_after_path())
40 details = E.span(
" (condition: ", E.code(f
"{c.get_operator()} {c.get_value()}"),
", afterwards:", E.code(after),
')')
41 detail_list.append(E.li(_create_pathhtml(c.get_path(),
"Conditional Path", details=details),
42 style=
"list-style-type: disclosure-closed"))
43 if len(detail_list) > 0:
44 module.append(detail_list)
46 module_list.append(module)
47 if len(module_list) > 0:
48 fragment.append(module_list)
52 def print_path_html(path):
53 """Print a path (and all sub paths) as html"""
54 return etree.tostring(_create_pathhtml(path,
"basf2.Path")).decode()
57 def print_module_html(module):
58 """Print a module (and its parameters) as well as the description"""
61 tname = f
" (type {tname})" if tname != name
else ""
62 module_html = E.div(
"basf2.Module ", E.b(name), tname, E.p(module.description),
63 E.style(
"table.b2module * { text-align: left !important; }"))
64 cols = [
"parameter",
"type",
"default",
"current",
"changed",
"is required"]
65 if len(module.available_params()) > 0:
67 for p
in module.available_params():
68 params.append(E.tr(E.td(p.name), E.td(E.code(str(p.type))), E.td(E.code(str(p.default))), E.td(E.code(str(p.values))),
69 E.td(E.b(
"yes")
if p.setInSteering
else "no"),
70 E.td(E.b(
"yes")
if p.forceInSteering
else "no")))
71 params.append(E.tr(E.td(), E.td(p.description, colspan=
"5")))
73 module_html.append(E.table(E.thead(E.tr(*[E.th(e)
for e
in cols])), params, **{
"class":
"b2module"}))
75 return etree.tostring(module_html).decode()
78 def enable_notebooksupport():
80 Small function to enable some notebook compatibility.
81 Mostly make sure that log messages are shown correctly (they are C++ so they need some special love to show up).
85 b2core.logging.reset()
86 b2core.logging.add_console(
True)
87 b2core.logging.enable_python_logging =
True
93 html_formatter = get_ipython().display_formatter.formatters[
'text/html']
94 html_formatter.for_type(b2core.Path, print_path_html)
95 html_formatter.for_type(b2core.Module, print_module_html)
98 def _child_process(pipe, path, max_events):
99 """Execute process() in a child process but send the persistent datastore objects back to the parent"""
101 b2core.process(path, max_events)
104 for name
in [
"ProcessStatistics"]:
107 if storeobj.isValid():
108 return_objects[name] = str(ROOT.TBufferJSON.ToJSON(storeobj.obj()))
109 pipe.send(return_objects)
113 def process(path, max_event=0):
115 Start processing events using the modules in the given `basf2.Path` object.
117 Can be called multiple times in one steering file.
119 This is a convenience wrapper which will automatically call the
120 `process()` function in a separate process to prevent FATAL errors from killing
124 As processing is done in a separate process the global state of the notebook
125 cannot be modified. For example a python modules collecting information will appear to be
126 empty after execution and global variables will also not be modified.
128 If you need to modify the state of the notebook during processing you need to call
132 path: The path with which the processing starts
133 max_event: The maximal number of events which will be processed, 0 for no limit
138 global _process_warning
139 if not _process_warning:
140 _process_warning =
True
141 b2core.B2INFO(
"process() called in a Jupyter Notebook. See help(basf2.process) for caveats")
144 ctx = multiprocessing.get_context(
"fork")
145 nanny, child = ctx.Pipe()
146 process = ctx.Process(target=_child_process, args=(child, path, max_event))
149 if process.exitcode != 0:
150 raise RuntimeError(
"Event processing was not successful")
151 return_objects = nanny.recv()
153 datastore.setInitializeActive(
True)
155 for name, value
in return_objects.items():
157 if value
is not None:
158 storeobj.registerInDataStore()
160 obj = ROOT.TBufferJSON.ConvertFromJSON(value)
161 ROOT.SetOwnership(obj,
False)
162 storeobj.assign(obj,
True)
164 datastore.setInitializeActive(
False)
static DataStore & Instance()
Instance of singleton Store.
a (simplified) python wrapper for StoreObjPtr.