LSSTApplications  11.0-13-gbb96280,12.1.rc1,12.1.rc1+1,12.1.rc1+2,12.1.rc1+5,12.1.rc1+8,12.1.rc1-1-g06d7636+1,12.1.rc1-1-g253890b+5,12.1.rc1-1-g3d31b68+7,12.1.rc1-1-g3db6b75+1,12.1.rc1-1-g5c1385a+3,12.1.rc1-1-g83b2247,12.1.rc1-1-g90cb4cf+6,12.1.rc1-1-g91da24b+3,12.1.rc1-2-g3521f8a,12.1.rc1-2-g39433dd+4,12.1.rc1-2-g486411b+2,12.1.rc1-2-g4c2be76,12.1.rc1-2-gc9c0491,12.1.rc1-2-gda2cd4f+6,12.1.rc1-3-g3391c73+2,12.1.rc1-3-g8c1bd6c+1,12.1.rc1-3-gcf4b6cb+2,12.1.rc1-4-g057223e+1,12.1.rc1-4-g19ed13b+2,12.1.rc1-4-g30492a7
LSSTDataManagementBasePackage
history.py
Go to the documentation of this file.
1 #
2 # LSST Data Management System
3 # Copyright 2008, 2009, 2010 LSST Corporation.
4 #
5 # This product includes software developed by the
6 # LSST Project (http://www.lsst.org/).
7 #
8 # This program is free software: you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation, either version 3 of the License, or
11 # (at your option) any later version.
12 #
13 # This program is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU General Public License for more details.
17 #
18 # You should have received a copy of the LSST License Statement and
19 # the GNU General Public License along with this program. If not,
20 # see <http://www.lsstcorp.org/LegalNotices/>.
21 #
22 from __future__ import print_function
23 from builtins import str
24 from builtins import object
25 
26 import os
27 import re
28 import sys
29 
30 # -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
31 
32 
33 class Color(object):
34  categories = dict(
35  NAME="blue",
36  VALUE="yellow",
37  FILE="green",
38  TEXT="red",
39  FUNCTION_NAME="blue",
40  )
41 
42  colors = {
43  "black": 0,
44  "red": 1,
45  "green": 2,
46  "yellow": 3,
47  "blue": 4,
48  "magenta": 5,
49  "cyan": 6,
50  "white": 7,
51  }
52 
53  _colorize = True
54 
55  def __init__(self, text, category):
56  """Return a string that should display as coloured on a conformant terminal"""
57  try:
58  color = Color.categories[category]
59  except KeyError:
60  raise RuntimeError("Unknown category: %s" % category)
61 
62  self.rawText = str(text)
63  x = color.lower().split(";")
64  self.color, bold = x.pop(0), False
65  if x:
66  props = x.pop(0)
67  if props in ("bold",):
68  bold = True
69 
70  try:
71  self._code = "%s" % (30 + Color.colors[self.color])
72  except KeyError:
73  raise RuntimeError("Unknown colour: %s" % self.color)
74 
75  if bold:
76  self._code += ";1"
77 
78  @staticmethod
79  def colorize(val=None):
80  """Should I colour strings? With an argument, set the value"""
81 
82  if val is not None:
83  Color._colorize = val
84 
85  if isinstance(val, dict):
86  unknown = []
87  for k in val:
88  if k in Color.categories:
89  if val[k] in Color.colors:
90  Color.categories[k] = val[k]
91  else:
92  print("Unknown colour %s for category %s" % (val[k], k), file=sys.stderr)
93  else:
94  unknown.append(k)
95 
96  if unknown:
97  print("Unknown colourizing category: %s" % " ".join(unknown), file=sys.stderr)
98 
99  return Color._colorize
100 
101  def __str__(self):
102  if not self.colorize():
103  return self.rawText
104 
105  base = "\033["
106 
107  prefix = base + self._code + "m"
108  suffix = base + "m"
109 
110  return prefix + self.rawText + suffix
111 
112 
113 def _colorize(text, category):
114  text = Color(text, category)
115  return str(text)
116 
117 # -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
118 
119 
120 class StackFrame(object):
121  def __init__(self, stackTrace):
122  self.fileName = stackTrace[0]
123  self.lineNumber = stackTrace[1]
124  self.functionName = stackTrace[2]
125  self.text = stackTrace[3]
126 
127  self.fileName = re.sub(r'.*/python/lsst/', "", self.fileName)
128 
129 # -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
130 
131 
132 def format(config, name=None, writeSourceLine=True, prefix="", verbose=False):
133  """Format the history record for config.name"""
134 
135  if name is None:
136  for i, name in enumerate(config.history.keys()):
137  if i > 0:
138  print()
139  print(format(config, name))
140 
141  outputs = []
142  for value, tb, label in config.history[name]:
143  output = []
144  for frame in [StackFrame(t) for t in tb]:
145  if frame.functionName in ("__new__", "__set__", "__setattr__", "execfile", "wrapper") or \
146  os.path.split(frame.fileName)[1] in ("argparse.py", "argumentParser.py"):
147  if not verbose:
148  continue
149 
150  line = []
151  if writeSourceLine:
152  line.append(["%s" % ("%s:%d" % (frame.fileName, frame.lineNumber)), "FILE", ])
153 
154  line.append([frame.text, "TEXT", ])
155  if False:
156  line.append([frame.functionName, "FUNCTION_NAME", ])
157 
158  output.append(line)
159 
160  outputs.append([value, output])
161  #
162  # Find the maximum widths of the value and file:lineNo fields
163  #
164  if writeSourceLine:
165  sourceLengths = []
166  for value, output in outputs:
167  sourceLengths.append(max([len(x[0][0]) for x in output]))
168  sourceLength = max(sourceLengths)
169 
170  valueLength = len(prefix) + max([len(str(value)) for value, output in outputs])
171  #
172  # actually generate the config history
173  #
174  msg = []
175  fullname = "%s.%s" % (config._name, name) if config._name is not None else name
176  msg.append(_colorize(re.sub(r"^root\.", "", fullname), "NAME"))
177  for value, output in outputs:
178  line = prefix + _colorize("%-*s" % (valueLength, value), "VALUE") + " "
179  for i, vt in enumerate(output):
180  if writeSourceLine:
181  vt[0][0] = "%-*s" % (sourceLength, vt[0][0])
182 
183  output[i] = " ".join([_colorize(v, t) for v, t in vt])
184 
185  line += ("\n%*s" % (valueLength + 1, "")).join(output)
186  msg.append(line)
187 
188  return "\n".join(msg)