Belle II Software  release-05-02-19
json_objects.py
1 import json
2 import enum
3 import functools
4 
5 # todo: shouldn't I call super().__init__() or similar to make sure that I
6 # execute code from mother classes?? This seems to only have been done for
7 # some of the subclasses here... /klieret
8 
9 """
10 Define datatypes for later serialization by json
11 """
12 
13 # todo: write a short overview over the many classes and their relationships here /klieret
14 
15 # ==============================================================================
16 # Data classes
17 # ==============================================================================
18 
19 
20 class JsonBase:
21 
22  """
23  Base object for all json-serializable objects of the validation suite
24  """
25  pass
26 
27 
29 
30  """
31  Contains information about a specific revision
32  """
33 
34  def __init__(self, label, git_hash=None, creation_date=None, packages=None,
35  creation_timezone=None):
36  """
37  Create a new Revision object and fill all members
38  """
39 
40 
41  self.label = label
42 
43 
45  self.creation_date = creation_date
46 
47 
48  self.creation_timezone = creation_timezone
49 
50 
52  self.git_hash = git_hash
53 
54 
56  self.most_recent = False
57 
58 
59  self.packages = [] if (packages is None) else packages
60 
61 
63 
64  """
65  Container for a list of revisions
66  """
67 
68  def __init__(self, revisions):
69  """
70  Create a new Revisions object and fill all members
71  """
72 
73 
74  self.revisions = revisions
75 
76 
78 
79  """
80  Contains information about a script and its execution output
81  """
82 
83  def __init__(self, name, path, status, log_url=None, return_code=None):
84  """
85  Create a new Script object and fill all members
86  """
87 
88 
89  self.name = name
90 
91  self.path = path
92 
95  self.status = status
96 
98  self.log_url = log_url
99 
101  self.return_code = return_code
102 
103 
105 
106  """
107  Wrapper for a file containing a set of plots, only
108  root files up to now
109  """
110 
111  def __init__(self, package, title, rootfile, plots, description=""):
112  """
113  Create a new PlotFile object and fill all members
114  """
115 
116 
117  self.package = package
118 
119  self.title = title
120 
121  self.rootfile = rootfile
122 
123  self.plots = plots
124 
125  self.description = description
126 
127  self.n_shifter_plots = sum([not plot.is_expert for plot in self.plots])
128 
129 
130 class Plot(JsonBase):
131 
132  """
133  Wrapper for one specfic plot.
134  """
135 
136  def __init__(self, is_expert=False, description=None, check=None,
137  contact=None, width=None, height=None):
138  """
139  Create a new Plot object and fill all members
140  """
141 
142 
143  self.is_expert = is_expert
144 
145  self.description = description
146 
147  self.check = check
148 
149  self.contact = contact
150 
151  self.width = width
152 
153  self.height = height
154 
155 
157 
158  """
159  Wrapper for NTuple lists. This is not a graphical plot, but a list of
160  values
161  """
162 
163  def __init__(self, is_expert=False, description=None, check=None):
164  """
165  Create a new NTuple object and fill all members
166  """
167 
168 
169  self.is_expert = is_expert
170 
171  self.description = description
172 
173  self.check = check
174 
175 
177 
178  """
179  Wrapper for user HTML Content. This is not a graphical plot but HTML
180  code which will be directly output on the validation website.
181 
182  """
183 
184  def __init__(self, is_expert=False, description=None, check=None):
185  """
186  Create a new NTuple object and fill all members
187  """
188 
189 
190  self.is_expert = is_expert
191 
192  self.description = description
193 
194  self.check = check
195 
196 
198 
199  """
200  One high-level package of the validation suites which contains a set of
201  scripts and output plot files
202  """
203 
204  def __init__(self, name, plotfiles=None, scriptfiles=None, fail_count=0):
205  """
206  Create a new NTuple object and fill all members
207  """
208 
209  if not plotfiles:
210  plotfiles = []
211  if not scriptfiles:
212  scriptfiles = []
213 
214 
215  self.name = name
216 
217  self.plotfiles = plotfiles
218 
219  self.scriptfiles = scriptfiles
220 
221  self.visible = True
222 
223  self.fail_count = fail_count
224 
225 
226 class ComparisonState(enum.Enum):
227 
228  """
229  Enum to classify the comparison result of two validation plots
230  """
231 
232 
234  NotCompared = "not_compared"
235 
237  NotSupported = "not_supported"
238 
240  FailureTechnical = "technical_failure"
241 
243  FailureStastical = "statistical_failure"
244 
246  Equal = "equal"
247 
248 
250 
251  """
252  Contains the comparison result of two plots
253  """
254 
255  def __init__(self, state, chi2):
256  """
257  Create a new ComparisonResult object and fill all members
258  """
259 
260 
261  self.state = state
262 
263  self.chi2 = chi2
264 
265 
267 
268  """
269  Contains information about a file containing plots and the comparison which
270  have been performed for the content of this file
271  """
272 
273  def __init__(
274  self,
275  package,
276  title,
277  rootfile,
278  compared_revisions=None,
279  plots=None,
280  has_reference=False,
281  ntuples=None,
282  html_content=None,
283  description=None,
284  ):
285  """
286  Create a new ComparisonPlotFile object and fill all members
287  """
288 
289  if not plots:
290  plots = []
291  if not ntuples:
292  ntuples = []
293  if not html_content:
294  html_content = []
295 
296  super().__init__(package, title, rootfile, plots,
297  description=description)
298 
299  self.compared_revision = compared_revisions
300 
301  self.ntuples = ntuples
302 
303  self.html_content = html_content
304 
305 
306  self.has_reference = has_reference
307 
308 
309  self.comparison_error = len([
310  plt for plt in self.plots if plt.comparison_result == "error"
311  ])
312 
313  self.comparison_error_shifter = len([
314  plt for plt in self.plots
315  if (not plt.is_expert) and plt.comparison_result == "error"
316  ])
317 
318  self.comparison_warning = len([
319  plt for plt in self.plots if plt.comparison_result == "warning"
320  ])
321 
324  plt for plt in self.plots
325  if (not plt.is_expert) and plt.comparison_result == "warning"
326  ])
327 
328 
329  self.n_shifter_ntuples = sum([
330  not tuple.is_expert for tuple in self.ntuples
331  ])
332 
333 
334  self.show_shifter = bool(
335  self.n_shifter_plots or
336  self.n_shifter_ntuples or
337  self.html_content
338  )
339 
340 
342 
343  """
344  One individual plot including its comparison outcome.
345  """
346 
347  def __init__(
348  self,
349  title,
350  comparison_result=None,
351  png_filename=None,
352  pdf_filename=None,
353  contact=None,
354  description=None,
355  check=None,
356  is_expert=None,
357  plot_path=None,
358  comparison_text=None,
359  height=None,
360  width=None,
361  warnings=None):
362  """
363  Create a new ComparisonPlot object and fill all members
364  """
365 
366  # todo: move more into the base class
367  super().__init__(
368  is_expert=is_expert,
369  description=description,
370  check=check,
371  contact=contact,
372  height=height,
373  width=width
374  )
375 
376  self.title = title
377 
378 
379  self.comparison_result = comparison_result
380 
381 
382  self.comparison_text = comparison_text
383 
384 
385  self.png_filename = png_filename
386 
387 
388  self.pdf_filename = pdf_filename
389 
390 
392  self.plot_path = plot_path
393 
394 
395  if warnings is None:
396  warnings = []
397  self.warnings = warnings
398 
399 
401 
402  """
403  Comparison outcome for NTuples
404  """
405 
406  def __init__(
407  self,
408  title,
409  contact=None,
410  description=None,
411  check=None,
412  is_expert=None,
413  json_file_path=None):
414  """
415  Create a new ComparisonNTuple object and fill all members
416  """
417 
418  # todo: move more into the base class
419  super().__init__(
420  is_expert=is_expert,
421  description=description,
422  check=check
423  )
424 
425  self.title = title
426 
427  self.contact = contact
428 
430  self.json_file_path = json_file_path
431 
432 
434 
435  """
436  Compiled HTLM Content
437  """
438 
439  def __init__(
440  self,
441  title,
442  contact=None,
443  description=None,
444  check=None,
445  is_expert=None,
446  html_content=None):
447  """
448  Create a new ComparisonNTuple object and fill all members
449  """
450 
451  # todo: move more into the base class
452  super().__init__(is_expert=is_expert, description=description, check=check)
453 
454  self.title = title
455 
456  self.contact = contact
457 
459  self.html_content = html_content
460 
461 
463 
464  """
465  Information about a Package which was used in a comparison operation
466  """
467 
468  def __init__(self, name, plotfiles=None, scriptfiles=None,
469  ntuplefiles=None):
470  """
471  Create a new ComparisonPackage object and fill all members
472  """
473 
474  if not plotfiles:
475  plotfiles = []
476  if not scriptfiles:
477  scriptfiles = []
478  if not ntuplefiles:
479  ntuplefiles = []
480 
481  super().__init__(name, plotfiles=plotfiles, scriptfiles=scriptfiles)
482 
483 
484  self.comparison_error = sum([
485  pf.comparison_error for pf in plotfiles
486  ])
487 
488  self.comparison_error_shifter = sum([
489  pf.comparison_error_shifter for pf in plotfiles
490  ])
491 
492  self.comparison_warning = sum([
493  pf.comparison_warning for pf in plotfiles
494  ])
495 
497  self.comparison_warning_shifter = sum([
498  pf.comparison_warning_shifter for pf in plotfiles
499  ])
500 
501 
503 
504  """
505  Revision information enriched by the information gained during
506  a comparison.
507  """
508 
509  def __init__(self, label, git_hash=None, creation_date=None, color=None):
510  """
511  Create a new ComparisonRevision object and fill all members
512  """
513 
514  # todo: creation_date
515  super().__init__(label, git_hash=git_hash, creation_date=None)
516 
518  self.color = color
519 
520 
522 
523  """
524  Contains information and plots generated for comparisons
525  between revisions
526  """
527 
528  def __init__(self, revisions=None, packages=None):
529  """
530  Create a new ComparisonRevision object and fill all members
531  """
532 
533  if not revisions:
534  revisions = []
535  if not packages:
536  packages = []
537 
538 
539  self.revisions = revisions
540 
541  self.packages = packages
542  sorted_revs = sorted(revisions, key=lambda x: x.label)
543 
544  self.label = functools.reduce(
545  lambda x, y: x + "_" + y.label,
546  sorted_revs, ""
547  )[1:]
548 
549 
550 # ==============================================================================
551 # Functions
552 # ==============================================================================
553 
554 def dump(file_name, obj):
555  """
556  Output a tree of objects into a json file
557  """
558 
559  with open(file_name, 'w+') as f:
560  json.dump(dump_rec(obj), f, sort_keys=True, indent=4)
561 
562 
563 def dumps(obj):
564  """
565  Convert a tree of python objects into a json file
566  """
567 
568  kk = dump_rec(obj)
569  return json.dumps(kk, sort_keys=True, indent=4)
570 
571 
572 def dump_rec(top_object):
573  """
574  Recursive generating of dictionary from a tree
575  of JsonBase objects
576  """
577 
578  this_dict = {}
579  # iterate through the dictionary of the top object
580  for (k, v) in top_object.__dict__.items():
581 
582  # list which needs special handing ?
583  if isinstance(v, list):
584  obj_list = []
585  for it in v:
586  # one of our object's in the list, which needs
587  # special treatment?
588  if isinstance(it, JsonBase):
589  # yen, recurse in to the object
590  obj_list.append(dump_rec(it))
591  else:
592  # no, just add value to list
593  obj_list.append(it)
594 
595  # store compiled list with corresponding key
596  this_dict[k] = obj_list
597  # one of our objects, which might be nested and
598  # needs special treatment ?
599  elif isinstance(v, JsonBase):
600  this_dict[k] = dump_rec(v)
601  # treat enum classes
602  elif isinstance(v, enum.Enum):
603  this_dict[k] = v.value
604  # regular value, just store with correct key
605  else:
606  this_dict[k] = v
607  return this_dict
json_objects.ComparisonPlot.pdf_filename
pdf_filename
the filename of the pdf file plotted with the comparison graphs
Definition: json_objects.py:374
json_objects.PlotFile.title
title
Display name of this file.
Definition: json_objects.py:119
json_objects.NTuple
Definition: json_objects.py:156
json_objects.ComparisonPlotFile.show_shifter
show_shifter
Show to shifter, i.e.
Definition: json_objects.py:323
json_objects.Comparison
Definition: json_objects.py:521
json_objects.NTuple.is_expert
is_expert
true if this is marked as an expert-only ntuple list
Definition: json_objects.py:169
json_objects.ComparisonPlot.comparison_result
comparison_result
text string for the comparison outcome
Definition: json_objects.py:365
json_objects.Package.scriptfiles
scriptfiles
scripts which were run or skipped as this package was executed
Definition: json_objects.py:219
json_objects.ComparisonResult.state
state
a string containing a description of the comparison's outcome
Definition: json_objects.py:261
json_objects.ComparisonNTuple
Definition: json_objects.py:400
json_objects.Comparison.__init__
def __init__(self, revisions=None, packages=None)
Definition: json_objects.py:528
json_objects.PlotFile.package
package
name of the package which created this file
Definition: json_objects.py:117
json_objects.Revision.__init__
def __init__(self, label, git_hash=None, creation_date=None, packages=None, creation_timezone=None)
Definition: json_objects.py:34
json_objects.ComparisonPlotFile.html_content
html_content
user's html content
Definition: json_objects.py:292
json_objects.Revision.packages
packages
list of packages contained in this revision
Definition: json_objects.py:58
json_objects.Revisions.__init__
def __init__(self, revisions)
Definition: json_objects.py:68
json_objects.Package
Definition: json_objects.py:197
json_objects.Revision.most_recent
most_recent
is this the most recent revision in the list this revision is contained ?
Definition: json_objects.py:55
json_objects.Revision.creation_timezone
creation_timezone
timezone used by the creation date
Definition: json_objects.py:47
json_objects.ComparisonRevision.color
color
the color which was used for this revision in the comparison plots
Definition: json_objects.py:518
json_objects.ComparisonPlot
Definition: json_objects.py:341
json_objects.ComparisonPackage.__init__
def __init__(self, name, plotfiles=None, scriptfiles=None, ntuplefiles=None)
Definition: json_objects.py:468
json_objects.HtmlContent.description
description
telling description for this HTML code
Definition: json_objects.py:192
json_objects.PlotFile.n_shifter_plots
n_shifter_plots
Number of shifter plots.
Definition: json_objects.py:127
json_objects.ComparisonHtmlContent.__init__
def __init__(self, title, contact=None, description=None, check=None, is_expert=None, html_content=None)
Definition: json_objects.py:439
json_objects.Plot.__init__
def __init__(self, is_expert=False, description=None, check=None, contact=None, width=None, height=None)
Definition: json_objects.py:136
json_objects.ComparisonPlotFile.comparison_error_shifter
comparison_error_shifter
the number of failed comparisons of shifter plots in this file
Definition: json_objects.py:302
json_objects.ComparisonRevision.__init__
def __init__(self, label, git_hash=None, creation_date=None, color=None)
Definition: json_objects.py:509
json_objects.ComparisonPlotFile
Definition: json_objects.py:266
json_objects.ComparisonResult.chi2
chi2
the chi2 value computed during the comparison
Definition: json_objects.py:263
json_objects.PlotFile
Definition: json_objects.py:104
json_objects.Revision.label
label
label (or tag) used to display this revision
Definition: json_objects.py:40
json_objects.ComparisonPlotFile.ntuples
ntuples
the ntuples which were compared
Definition: json_objects.py:290
json_objects.ComparisonPackage
Definition: json_objects.py:462
json_objects.Revision.creation_date
creation_date
date when the validation output of this revision was created, as datetime object
Definition: json_objects.py:44
json_objects.ComparisonPlot.title
title
tile used to display this plot
Definition: json_objects.py:362
json_objects.Script.log_url
log_url
location where the log output of the script execution can be found
Definition: json_objects.py:98
json_objects.ComparisonHtmlContent.html_content
html_content
path to the json file which contains the individual numbers of the ntuple
Definition: json_objects.py:452
json_objects.ComparisonHtmlContent.contact
contact
name of contact person
Definition: json_objects.py:449
json_objects.Plot
Definition: json_objects.py:130
json_objects.Comparison.revisions
revisions
the list of revisions used in this comparison
Definition: json_objects.py:539
json_objects.ComparisonPackage.comparison_warning_shifter
comparison_warning_shifter
the number of comparisons of shifter plots which resulted in a warning
Definition: json_objects.py:496
json_objects.ComparisonPlot.comparison_text
comparison_text
verbose text describing the outcome of the comparison
Definition: json_objects.py:368
json_objects.ComparisonPlotFile.n_shifter_ntuples
n_shifter_ntuples
Number of shifter ntuples.
Definition: json_objects.py:318
json_objects.ComparisonPlotFile.has_reference
has_reference
true if a reference file is available for this plot file
Definition: json_objects.py:295
json_objects.ComparisonRevision
Definition: json_objects.py:502
json_objects.Package.name
name
name of the package
Definition: json_objects.py:215
json_objects.Revision
Definition: json_objects.py:28
json_objects.Script.status
status
Output status of the script execution, can be one of the strings "failed", "finished",...
Definition: json_objects.py:95
json_objects.ComparisonResult.__init__
def __init__(self, state, chi2)
Definition: json_objects.py:255
json_objects.PlotFile.__init__
def __init__(self, package, title, rootfile, plots, description="")
Definition: json_objects.py:111
json_objects.Package.fail_count
fail_count
contains the number how many scripts failed to execute with error
Definition: json_objects.py:223
json_objects.HtmlContent.check
check
what should be checked for in this HTML code
Definition: json_objects.py:194
json_objects.Comparison.label
label
the unique label of this comparison
Definition: json_objects.py:544
json_objects.Plot.description
description
telling description for this plot
Definition: json_objects.py:144
json_objects.ComparisonNTuple.contact
contact
name of contact person
Definition: json_objects.py:420
json_objects.ComparisonState
Definition: json_objects.py:226
json_objects.Revisions.revisions
revisions
the actual list
Definition: json_objects.py:74
json_objects.Plot.width
width
width of the plot in pixels
Definition: json_objects.py:150
json_objects.Script.name
name
the name of the script file
Definition: json_objects.py:89
json_objects.Revision.git_hash
git_hash
The git commit hash which has the HEAD while the validation scripts were executed.
Definition: json_objects.py:51
json_objects.NTuple.check
check
what should be checked for in this ntuple ?
Definition: json_objects.py:173
json_objects.ComparisonPlot.png_filename
png_filename
the filename of the png file plotted with the comparison graphs
Definition: json_objects.py:371
json_objects.ComparisonHtmlContent
Definition: json_objects.py:433
json_objects.ComparisonNTuple.title
title
Text used as title for the ntuple item.
Definition: json_objects.py:418
json_objects.Revisions
Definition: json_objects.py:62
json_objects.PlotFile.rootfile
rootfile
filename of the root file
Definition: json_objects.py:121
json_objects.ComparisonNTuple.json_file_path
json_file_path
path to the json file which contains the individual numbers of the ntuple (must be relative to html d...
Definition: json_objects.py:423
json_objects.ComparisonResult
Definition: json_objects.py:249
json_objects.JsonBase
Definition: json_objects.py:20
json_objects.HtmlContent.__init__
def __init__(self, is_expert=False, description=None, check=None)
Definition: json_objects.py:184
json_objects.ComparisonNTuple.__init__
def __init__(self, title, contact=None, description=None, check=None, is_expert=None, json_file_path=None)
Definition: json_objects.py:406
json_objects.Script
Definition: json_objects.py:77
json_objects.ComparisonPlotFile.compared_revision
compared_revision
label of the revision which were used in this comparison
Definition: json_objects.py:288
json_objects.Package.__init__
def __init__(self, name, plotfiles=None, scriptfiles=None, fail_count=0)
Definition: json_objects.py:204
json_objects.Script.__init__
def __init__(self, name, path, status, log_url=None, return_code=None)
Definition: json_objects.py:83
json_objects.ComparisonPlotFile.comparison_warning_shifter
comparison_warning_shifter
the number of comparisons of shifter plots in this file which resulted in a warning
Definition: json_objects.py:312
json_objects.Comparison.packages
packages
the list of packages looked at in this comparison
Definition: json_objects.py:541
json_objects.ComparisonPlot.plot_path
plot_path
path were the png and pdf files are located (relative to the html directory; has to end with trailing...
Definition: json_objects.py:378
json_objects.Plot.check
check
What should be checked for in this plot ?
Definition: json_objects.py:146
json_objects.ComparisonPackage.comparison_warning
comparison_warning
the number of comparisons which resulted in a warning
Definition: json_objects.py:491
json_objects.PlotFile.description
description
Description of plot file.
Definition: json_objects.py:125
json_objects.ComparisonPlot.warnings
warnings
Warnings ("no contact" person etc.)
Definition: json_objects.py:383
json_objects.Plot.is_expert
is_expert
true if this is marked as an expert-only plot
Definition: json_objects.py:142
json_objects.NTuple.description
description
telling description for this ntuple
Definition: json_objects.py:171
json_objects.NTuple.__init__
def __init__(self, is_expert=False, description=None, check=None)
Definition: json_objects.py:163
json_objects.Script.path
path
path the script file is located
Definition: json_objects.py:91
json_objects.Script.return_code
return_code
integer which is the return code of the script execution
Definition: json_objects.py:101
json_objects.HtmlContent.is_expert
is_expert
true if this is marked as an expert-only HTML code
Definition: json_objects.py:190
json_objects.ComparisonPlotFile.__init__
def __init__(self, package, title, rootfile, compared_revisions=None, plots=None, has_reference=False, ntuples=None, html_content=None, description=None)
Definition: json_objects.py:273
json_objects.ComparisonPackage.comparison_error_shifter
comparison_error_shifter
the number of failed comparisons of shifter plots in this package
Definition: json_objects.py:487
json_objects.Package.plotfiles
plotfiles
list of plotfiles which were produced by the scripts in this package
Definition: json_objects.py:217
json_objects.HtmlContent
Definition: json_objects.py:176
json_objects.Plot.height
height
height of the plot in pixels
Definition: json_objects.py:152
json_objects.ComparisonPlotFile.comparison_error
comparison_error
the number of failed comparisons in this file
Definition: json_objects.py:298
json_objects.ComparisonPackage.comparison_error
comparison_error
the number of failed comparisons in this package
Definition: json_objects.py:483
json_objects.ComparisonPlot.__init__
def __init__(self, title, comparison_result=None, png_filename=None, pdf_filename=None, contact=None, description=None, check=None, is_expert=None, plot_path=None, comparison_text=None, height=None, width=None, warnings=None)
Definition: json_objects.py:347
json_objects.Plot.contact
contact
Who is the contact person for this plot ?
Definition: json_objects.py:148
json_objects.ComparisonHtmlContent.title
title
Text used as title for the ntuple item.
Definition: json_objects.py:447
json_objects.PlotFile.plots
plots
list of plots which are contained inside this plot file
Definition: json_objects.py:123
json_objects.Package.visible
visible
true if this package is displayed on the default validation website
Definition: json_objects.py:221
json_objects.ComparisonPlotFile.comparison_warning
comparison_warning
the number of comparisons which resulted in a warning
Definition: json_objects.py:307