| 396 |
farthen |
1 |
#!/usr/bin/env python
|
|
|
2 |
#
|
|
|
3 |
#
|
|
|
4 |
# Copyright 2010 TheSeven, benedikt93, Farthen
|
|
|
5 |
#
|
|
|
6 |
#
|
| 427 |
farthen |
7 |
# This file is part of emCORE.
|
| 396 |
farthen |
8 |
#
|
| 427 |
farthen |
9 |
# emCORE is free software: you can redistribute it and/or
|
| 396 |
farthen |
10 |
# modify it under the terms of the GNU General Public License as
|
|
|
11 |
# published by the Free Software Foundation, either version 2 of the
|
|
|
12 |
# License, or (at your option) any later version.
|
|
|
13 |
#
|
| 427 |
farthen |
14 |
# emCORE is distributed in the hope that it will be useful,
|
| 396 |
farthen |
15 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
16 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
17 |
# See the GNU General Public License for more details.
|
|
|
18 |
#
|
|
|
19 |
# You should have received a copy of the GNU General Public License
|
| 427 |
farthen |
20 |
# along with emCORE. If not, see <http://www.gnu.org/licenses/>.
|
| 396 |
farthen |
21 |
#
|
|
|
22 |
#
|
|
|
23 |
|
|
|
24 |
"""
|
|
|
25 |
This file includes some reusable functions and classes that might be useful
|
|
|
26 |
to all python scripts
|
|
|
27 |
"""
|
|
|
28 |
|
|
|
29 |
import sys
|
| 427 |
farthen |
30 |
import libemcoredata
|
| 396 |
farthen |
31 |
|
|
|
32 |
class Logger(object):
|
|
|
33 |
"""
|
|
|
34 |
Simple stdout logger.
|
| 401 |
farthen |
35 |
Loglevel 3 is most verbose, Loglevel 0: Only log something if there is an error.
|
|
|
36 |
Loglevel -1 means that nothing is logged.
|
| 396 |
farthen |
37 |
The log function doesn't care about the loglevel and always logs to stdout.
|
|
|
38 |
"""
|
| 401 |
farthen |
39 |
def __init__(self, loglevel = 2, target = "stdout", logfile = "tools.log"):
|
| 400 |
farthen |
40 |
"""
|
|
|
41 |
loglevel: Possible values: 0 (only errors), 1 (warnings), 2 (info,
|
|
|
42 |
recommended for production use), 3 and more (debug)
|
|
|
43 |
logfile: File to log to if using the target = "file"
|
|
|
44 |
target: Default logging target. Can be "stdout", "file" or "string"
|
|
|
45 |
"""
|
|
|
46 |
self.loglevel = loglevel
|
|
|
47 |
self.logfile = logfile
|
|
|
48 |
self.target = target
|
| 396 |
farthen |
49 |
|
| 400 |
farthen |
50 |
def log(self, text, indent = 0, target = None):
|
| 401 |
farthen |
51 |
if self.loglevel >= 0:
|
|
|
52 |
if target is None: target = self.target
|
|
|
53 |
text = (indent * " ") + text
|
|
|
54 |
text = text.replace("\n", "\n" + (indent * " "), text.count("\n") - 1)
|
|
|
55 |
if target == "stdout":
|
|
|
56 |
sys.stdout.write(text)
|
|
|
57 |
elif target == "file":
|
|
|
58 |
with open(self.logfile, 'a') as f:
|
|
|
59 |
f.write(text)
|
|
|
60 |
f.close()
|
|
|
61 |
elif target == "string":
|
|
|
62 |
return text
|
| 396 |
farthen |
63 |
|
| 400 |
farthen |
64 |
def debug(self, text, indent = 0, target = None):
|
| 396 |
farthen |
65 |
if self.loglevel >= 3:
|
|
|
66 |
self.log("DEBUG: " + text, indent, target)
|
|
|
67 |
|
| 400 |
farthen |
68 |
def info(self, text, indent = 0, target = None):
|
| 396 |
farthen |
69 |
if self.loglevel >= 2:
|
|
|
70 |
self.log(text, indent, target)
|
|
|
71 |
|
| 400 |
farthen |
72 |
def warn(self, text, indent = 0, target = None):
|
| 396 |
farthen |
73 |
if self.loglevel >= 1:
|
|
|
74 |
self.log("WARNING: " + text, indent, target)
|
|
|
75 |
|
| 400 |
farthen |
76 |
def error(self, text, indent = 0, target = None):
|
| 401 |
farthen |
77 |
if self.loglevel >= 0:
|
|
|
78 |
self.log("ERROR: " + text, indent, target)
|
| 396 |
farthen |
79 |
|
|
|
80 |
|
|
|
81 |
class Bunch(dict):
|
|
|
82 |
"""
|
|
|
83 |
This is a dict whose items can also be accessed with
|
|
|
84 |
bunchinstance.something.
|
|
|
85 |
"""
|
|
|
86 |
def __init__(self, **kw):
|
|
|
87 |
dict.__init__(self, kw)
|
|
|
88 |
self.__dict__ = self
|
|
|
89 |
|
|
|
90 |
def __getstate__(self):
|
|
|
91 |
return self
|
|
|
92 |
|
|
|
93 |
def __setstate__(self, state):
|
|
|
94 |
self.update(state)
|
|
|
95 |
self.__dict__ = self
|
|
|
96 |
|
|
|
97 |
|
|
|
98 |
class Error(Exception):
|
|
|
99 |
def __init__(self, value=None):
|
|
|
100 |
self.value = value
|
|
|
101 |
def __str__(self):
|
|
|
102 |
if self.value != None:
|
|
|
103 |
return repr(self.value)
|
|
|
104 |
|
|
|
105 |
|
| 398 |
farthen |
106 |
def gethwname(id):
|
|
|
107 |
try:
|
| 427 |
farthen |
108 |
hwtype = libemcoredata.hwtypes[id]
|
| 398 |
farthen |
109 |
except KeyError:
|
|
|
110 |
hwtype = "UNKNOWN (ID = " + self._hex(id) + ")"
|
|
|
111 |
return hwtype
|
|
|
112 |
|
|
|
113 |
|
| 396 |
farthen |
114 |
def trimdoc(docstring):
|
|
|
115 |
"""
|
|
|
116 |
Trims whitespace from docstrings
|
|
|
117 |
"""
|
|
|
118 |
if not docstring:
|
|
|
119 |
return ''
|
|
|
120 |
# Convert tabs to spaces (following the normal Python rules)
|
|
|
121 |
# and split into a list of lines:
|
|
|
122 |
lines = docstring.expandtabs().splitlines()
|
|
|
123 |
# Determine minimum indentation (first line doesn't count):
|
|
|
124 |
indent = sys.maxint
|
|
|
125 |
for line in lines[1:]:
|
|
|
126 |
stripped = line.lstrip()
|
|
|
127 |
if stripped:
|
|
|
128 |
indent = min(indent, len(line) - len(stripped))
|
|
|
129 |
# Remove indentation (first line is special):
|
|
|
130 |
trimmed = [lines[0].strip()]
|
|
|
131 |
if indent < sys.maxint:
|
|
|
132 |
for line in lines[1:]:
|
|
|
133 |
trimmed.append(line[indent:].rstrip())
|
|
|
134 |
# Strip off trailing and leading blank lines:
|
|
|
135 |
while trimmed and not trimmed[-1]:
|
|
|
136 |
trimmed.pop()
|
|
|
137 |
while trimmed and not trimmed[0]:
|
|
|
138 |
trimmed.pop(0)
|
|
|
139 |
# Return a single string:
|
|
|
140 |
return '\n'.join(trimmed)
|
|
|
141 |
|
|
|
142 |
|
|
|
143 |
def getfuncdoc(funcdict):
|
|
|
144 |
"""
|
|
|
145 |
Extracts important information from a dict of functions like the
|
|
|
146 |
docstring and arguments and returns them in a human readable format
|
|
|
147 |
"""
|
|
|
148 |
import inspect
|
|
|
149 |
import re
|
|
|
150 |
functions = Bunch()
|
|
|
151 |
for function in funcdict:
|
|
|
152 |
function = funcdict[function].func
|
|
|
153 |
docinfo = Bunch()
|
|
|
154 |
name = function.__name__
|
|
|
155 |
args = inspect.getargspec(function)[0]
|
|
|
156 |
docinfo['varargs'] = False
|
|
|
157 |
if inspect.getargspec(function)[1]:
|
|
|
158 |
docinfo['varargs'] = True
|
|
|
159 |
kwargvalues = inspect.getargspec(function)[3]
|
|
|
160 |
kwargs = Bunch()
|
|
|
161 |
if args:
|
|
|
162 |
if kwargvalues:
|
|
|
163 |
argnum = len(args) - len(kwargvalues)
|
|
|
164 |
kwargnum = len(kwargvalues)
|
|
|
165 |
kwargs = dict(zip(args[argnum:], kwargvalues))
|
|
|
166 |
else:
|
|
|
167 |
argnum = len(args)
|
|
|
168 |
else:
|
|
|
169 |
argnum = 0
|
|
|
170 |
docinfo['args'] = args[1:argnum]
|
|
|
171 |
docinfo['kwargs'] = kwargs
|
|
|
172 |
if function.__doc__:
|
|
|
173 |
# strip unneccessary whitespace
|
|
|
174 |
docinfo['documentation'] = trimdoc(function.__doc__)
|
|
|
175 |
else:
|
|
|
176 |
docinfo['documentation'] = None
|
|
|
177 |
functions[name] = docinfo
|
|
|
178 |
return functions
|
|
|
179 |
|
|
|
180 |
|
|
|
181 |
def gendoc(funcdict, indentwidth = 4, logtarget = "string"):
|
|
|
182 |
logger = Logger()
|
|
|
183 |
doc = getfuncdoc(funcdict)
|
|
|
184 |
ret = ""
|
|
|
185 |
for function in sorted(doc.items()):
|
|
|
186 |
function = function[0]
|
|
|
187 |
ret += logger.log("def " + function + "(", target = logtarget)
|
|
|
188 |
counter = 0
|
|
|
189 |
if doc[function]['args']:
|
|
|
190 |
for arg in doc[function]['args']:
|
|
|
191 |
if counter > 0:
|
|
|
192 |
sys.stdout.write(", ")
|
|
|
193 |
counter += 1
|
|
|
194 |
ret += logger.log(arg, target = logtarget)
|
|
|
195 |
if doc[function]['kwargs']:
|
|
|
196 |
for kwarg, kwargvalue in doc[function]['kwargs'].items():
|
|
|
197 |
if counter > 0:
|
|
|
198 |
sys.stdout.write(", ")
|
|
|
199 |
counter += 1
|
|
|
200 |
ret += logger.log(kwarg + "=" + str(kwargvalue), target = logtarget)
|
|
|
201 |
if doc[function]['varargs']:
|
|
|
202 |
ret += logger.log("*argv", target = logtarget)
|
|
|
203 |
ret += logger.log("):\n", target = logtarget)
|
|
|
204 |
if doc[function]['documentation']:
|
|
|
205 |
ret += logger.log("\"\"\"\n", indent = indentwidth, target = logtarget)
|
|
|
206 |
ret += logger.log(trimdoc(doc[function]['documentation']) + "\n", indent = 2 * indentwidth, target = logtarget)
|
|
|
207 |
ret += logger.log("\"\"\"\n", indent = indentwidth, target = logtarget)
|
|
|
208 |
ret += logger.log("\n", target = logtarget)
|
|
|
209 |
return ret
|