From 7c128a6cf6e20674c7bab31ff13f7480b42e6148 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Fri, 26 Nov 2021 19:09:54 -0500 Subject: docs: sample html report --- .../d_7b071bdc2a35fa80___init___py.html | 4 +- .../d_7b071bdc2a35fa80___main___py.html | 4 +- .../d_7b071bdc2a35fa80_backward_py.html | 8 +- doc/sample_html/d_7b071bdc2a35fa80_cogapp_py.html | 1546 ++++++++++---------- .../d_7b071bdc2a35fa80_makefiles_py.html | 4 +- .../d_7b071bdc2a35fa80_test_cogapp_py.html | 1013 +++++++------ .../d_7b071bdc2a35fa80_test_makefiles_py.html | 8 +- .../d_7b071bdc2a35fa80_test_whiteutils_py.html | 8 +- .../d_7b071bdc2a35fa80_whiteutils_py.html | 4 +- doc/sample_html/index.html | 54 +- doc/sample_html/status.json | 2 +- 11 files changed, 1400 insertions(+), 1255 deletions(-) (limited to 'doc/sample_html') diff --git a/doc/sample_html/d_7b071bdc2a35fa80___init___py.html b/doc/sample_html/d_7b071bdc2a35fa80___init___py.html index 02ab6f19..d2c07775 100644 --- a/doc/sample_html/d_7b071bdc2a35fa80___init___py.html +++ b/doc/sample_html/d_7b071bdc2a35fa80___init___py.html @@ -72,8 +72,8 @@ diff --git a/doc/sample_html/d_7b071bdc2a35fa80___main___py.html b/doc/sample_html/d_7b071bdc2a35fa80___main___py.html index b8c8069e..202c9462 100644 --- a/doc/sample_html/d_7b071bdc2a35fa80___main___py.html +++ b/doc/sample_html/d_7b071bdc2a35fa80___main___py.html @@ -68,8 +68,8 @@ diff --git a/doc/sample_html/d_7b071bdc2a35fa80_backward_py.html b/doc/sample_html/d_7b071bdc2a35fa80_backward_py.html index 625b7f70..8f9ba5e1 100644 --- a/doc/sample_html/d_7b071bdc2a35fa80_backward_py.html +++ b/doc/sample_html/d_7b071bdc2a35fa80_backward_py.html @@ -3,7 +3,7 @@ - Coverage for cogapp/backward.py: 69.23% + Coverage for cogapp/backward.py: 71.43% @@ -13,7 +13,7 @@

Coverage for cogapp/backward.py: - 69.23% + 71.43%

@@ -105,8 +105,8 @@ diff --git a/doc/sample_html/d_7b071bdc2a35fa80_cogapp_py.html b/doc/sample_html/d_7b071bdc2a35fa80_cogapp_py.html index f8a35e08..dd2bf3db 100644 --- a/doc/sample_html/d_7b071bdc2a35fa80_cogapp_py.html +++ b/doc/sample_html/d_7b071bdc2a35fa80_cogapp_py.html @@ -3,7 +3,7 @@ - Coverage for cogapp/cogapp.py: 49.50% + Coverage for cogapp/cogapp.py: 50.13% @@ -13,7 +13,7 @@

Coverage for cogapp/cogapp.py: - 49.50% + 50.13%

@@ -44,9 +44,9 @@

- 495 statements   - - + 510 statements   + +

@@ -63,7 +63,7 @@

2""" Cog content generation tool. 

3 http://nedbatchelder.com/code/cog 

4 

-

5 Copyright 2004-2019, Ned Batchelder. 

+

5 Copyright 2004-2021, Ned Batchelder. 

6""" 

7 

8from __future__ import absolute_import, print_function 

@@ -83,7 +83,7 @@

22 

23__all__ = ['Cog', 'CogUsageError', 'main'] 

24 

-

25__version__ = '3.2.0' 

+

25__version__ = '3.3.0' 

26 

27usage = """\ 

28cog - generate content with inlined Python code. 

@@ -104,7 +104,7 @@

43 -o OUTNAME Write the output to OUTNAME. 

44 -p PROLOGUE Prepend the generator source with PROLOGUE. Useful to insert an 

45 import line. Example: -p "import math" 

-

46 -P Use print() instead of outl for code output. 

+

46 -P Use print() instead of cog.outl() for code output. 

47 -r Replace the input file with the output. 

48 -s STRING Suffix all generated output lines with STRING. 

49 -U Write the output with Unix newlines (only LF line-endings). 

@@ -113,781 +113,803 @@

52 -x Excise all the generated output without running the generators. 

53 -z The end-output marker can be omitted, and is assumed at eof. 

54 -v Print the version of cog and exit. 

-

55 --verbosity=VERBOSITY 

-

56 Control the amount of output. 2 (the default) lists all files, 

-

57 1 lists only changed files, 0 lists no files. 

-

58 --markers='START END END-OUTPUT' 

-

59 The patterns surrounding cog inline instructions. Should 

-

60 include three values separated by spaces, the start, end, 

-

61 and end-output markers. Defaults to '[[[cog ]]] [[[end]]]'. 

-

62 -h Print this help. 

-

63""" 

-

64 

-

65# Other package modules 

-

66from .whiteutils import * 

-

67 

-

68class CogError(Exception): 

-

69 """ Any exception raised by Cog. 

-

70 """ 

-

71 def __init__(self, msg, file='', line=0): 

-

72 if file: 

-

73 Exception.__init__(self, "%s(%d): %s" % (file, line, msg)) 

-

74 else: 

-

75 Exception.__init__(self, msg) 

-

76 

-

77class CogUsageError(CogError): 

-

78 """ An error in usage of command-line arguments in cog. 

-

79 """ 

-

80 pass 

-

81 

-

82class CogInternalError(CogError): 

-

83 """ An error in the coding of Cog. Should never happen. 

-

84 """ 

-

85 pass 

-

86 

-

87class CogGeneratedError(CogError): 

-

88 """ An error raised by a user's cog generator. 

-

89 """ 

-

90 pass 

-

91 

-

92class CogUserException(CogError): 

-

93 """ An exception caught when running a user's cog generator. 

-

94 The argument is the traceback message to print. 

-

95 """ 

-

96 pass 

-

97 

-

98class Redirectable: 

-

99 """ An object with its own stdout and stderr files. 

-

100 """ 

-

101 def __init__(self): 

-

102 self.stdout = sys.stdout 

-

103 self.stderr = sys.stderr 

-

104 

-

105 def setOutput(self, stdout=None, stderr=None): 

-

106 """ Assign new files for standard out and/or standard error. 

-

107 """ 

-

108 if stdout: 108 ↛ 110line 108 didn't jump to line 110, because the condition on line 108 was never false

-

109 self.stdout = stdout 

-

110 if stderr: 110 ↛ 111line 110 didn't jump to line 111, because the condition on line 110 was never true

-

111 self.stderr = stderr 

-

112 

-

113 def prout(self, s, end="\n"): 

-

114 print(s, file=self.stdout, end=end) 

-

115 

-

116 def prerr(self, s, end="\n"): 

-

117 print(s, file=self.stderr, end=end) 

+

55 --check Check that the files would not change if run again. 

+

56 --markers='START END END-OUTPUT' 

+

57 The patterns surrounding cog inline instructions. Should 

+

58 include three values separated by spaces, the start, end, 

+

59 and end-output markers. Defaults to '[[[cog ]]] [[[end]]]'. 

+

60 --verbosity=VERBOSITY 

+

61 Control the amount of output. 2 (the default) lists all files, 

+

62 1 lists only changed files, 0 lists no files. 

+

63 -h Print this help. 

+

64""" 

+

65 

+

66# Other package modules 

+

67from .whiteutils import * 

+

68 

+

69class CogError(Exception): 

+

70 """ Any exception raised by Cog. 

+

71 """ 

+

72 def __init__(self, msg, file='', line=0): 

+

73 if file: 

+

74 Exception.__init__(self, "%s(%d): %s" % (file, line, msg)) 

+

75 else: 

+

76 Exception.__init__(self, msg) 

+

77 

+

78class CogUsageError(CogError): 

+

79 """ An error in usage of command-line arguments in cog. 

+

80 """ 

+

81 pass 

+

82 

+

83class CogInternalError(CogError): 

+

84 """ An error in the coding of Cog. Should never happen. 

+

85 """ 

+

86 pass 

+

87 

+

88class CogGeneratedError(CogError): 

+

89 """ An error raised by a user's cog generator. 

+

90 """ 

+

91 pass 

+

92 

+

93class CogUserException(CogError): 

+

94 """ An exception caught when running a user's cog generator. 

+

95 The argument is the traceback message to print. 

+

96 """ 

+

97 pass 

+

98 

+

99class CogCheckFailed(CogError): 

+

100 """ A --check failed. 

+

101 """ 

+

102 pass 

+

103 

+

104class Redirectable: 

+

105 """ An object with its own stdout and stderr files. 

+

106 """ 

+

107 def __init__(self): 

+

108 self.stdout = sys.stdout 

+

109 self.stderr = sys.stderr 

+

110 

+

111 def setOutput(self, stdout=None, stderr=None): 

+

112 """ Assign new files for standard out and/or standard error. 

+

113 """ 

+

114 if stdout: 114 ↛ 116line 114 didn't jump to line 116, because the condition on line 114 was never false

+

115 self.stdout = stdout 

+

116 if stderr: 116 ↛ 117line 116 didn't jump to line 117, because the condition on line 116 was never true

+

117 self.stderr = stderr 

118 

-

119 

-

120class CogGenerator(Redirectable): 

-

121 """ A generator pulled from a source file. 

-

122 """ 

-

123 def __init__(self, options=None): 

-

124 Redirectable.__init__(self) 

-

125 self.markers = [] 

-

126 self.lines = [] 

-

127 self.options = options or CogOptions() 

-

128 

-

129 def parseMarker(self, l): 

-

130 self.markers.append(l) 

-

131 

-

132 def parseLine(self, l): 

-

133 self.lines.append(l.strip('\n')) 

+

119 def prout(self, s, end="\n"): 

+

120 print(s, file=self.stdout, end=end) 

+

121 

+

122 def prerr(self, s, end="\n"): 

+

123 print(s, file=self.stderr, end=end) 

+

124 

+

125 

+

126class CogGenerator(Redirectable): 

+

127 """ A generator pulled from a source file. 

+

128 """ 

+

129 def __init__(self, options=None): 

+

130 Redirectable.__init__(self) 

+

131 self.markers = [] 

+

132 self.lines = [] 

+

133 self.options = options or CogOptions() 

134 

-

135 def getCode(self): 

-

136 """ Extract the executable Python code from the generator. 

-

137 """ 

-

138 # If the markers and lines all have the same prefix 

-

139 # (end-of-line comment chars, for example), 

-

140 # then remove it from all the lines. 

-

141 prefIn = commonPrefix(self.markers + self.lines) 

-

142 if prefIn: 

-

143 self.markers = [ l.replace(prefIn, '', 1) for l in self.markers ] 

-

144 self.lines = [ l.replace(prefIn, '', 1) for l in self.lines ] 

-

145 

-

146 return reindentBlock(self.lines, '') 

-

147 

-

148 def evaluate(self, cog, globals, fname): 

-

149 # figure out the right whitespace prefix for the output 

-

150 prefOut = whitePrefix(self.markers) 

+

135 def parseMarker(self, l): 

+

136 self.markers.append(l) 

+

137 

+

138 def parseLine(self, l): 

+

139 self.lines.append(l.strip('\n')) 

+

140 

+

141 def getCode(self): 

+

142 """ Extract the executable Python code from the generator. 

+

143 """ 

+

144 # If the markers and lines all have the same prefix 

+

145 # (end-of-line comment chars, for example), 

+

146 # then remove it from all the lines. 

+

147 prefIn = commonPrefix(self.markers + self.lines) 

+

148 if prefIn: 

+

149 self.markers = [ l.replace(prefIn, '', 1) for l in self.markers ] 

+

150 self.lines = [ l.replace(prefIn, '', 1) for l in self.lines ] 

151 

-

152 intext = self.getCode() 

-

153 if not intext: 

-

154 return '' 

-

155 

-

156 prologue = "import " + cog.cogmodulename + " as cog\n" 

-

157 if self.options.sPrologue: 157 ↛ 158line 157 didn't jump to line 158, because the condition on line 157 was never true

-

158 prologue += self.options.sPrologue + '\n' 

-

159 code = compile(prologue + intext, str(fname), 'exec') 

-

160 

-

161 # Make sure the "cog" module has our state. 

-

162 cog.cogmodule.msg = self.msg 

-

163 cog.cogmodule.out = self.out 

-

164 cog.cogmodule.outl = self.outl 

-

165 cog.cogmodule.error = self.error 

+

152 return reindentBlock(self.lines, '') 

+

153 

+

154 def evaluate(self, cog, globals, fname): 

+

155 # figure out the right whitespace prefix for the output 

+

156 prefOut = whitePrefix(self.markers) 

+

157 

+

158 intext = self.getCode() 

+

159 if not intext: 

+

160 return '' 

+

161 

+

162 prologue = "import " + cog.cogmodulename + " as cog\n" 

+

163 if self.options.sPrologue: 163 ↛ 164line 163 didn't jump to line 164, because the condition on line 163 was never true

+

164 prologue += self.options.sPrologue + '\n' 

+

165 code = compile(prologue + intext, str(fname), 'exec') 

166 

-

167 real_stdout = sys.stdout 

-

168 if self.options.bPrintOutput: 168 ↛ 169line 168 didn't jump to line 169, because the condition on line 168 was never true

-

169 sys.stdout = captured_stdout = StringIO() 

-

170 

-

171 self.outstring = '' 

-

172 try: 

-

173 eval(code, globals) 

-

174 except CogError: 174 ↛ 175line 174 didn't jump to line 175, because the exception caught by line 174 didn't happen

-

175 raise 

-

176 except: 

-

177 typ, err, tb = sys.exc_info() 

-

178 frames = (tuple(fr) for fr in traceback.extract_tb(tb.tb_next)) 

-

179 frames = find_cog_source(frames, prologue) 

-

180 msg = "".join(traceback.format_list(frames)) 

-

181 msg += "{}: {}".format(typ.__name__, err) 

-

182 raise CogUserException(msg) 

-

183 finally: 

-

184 sys.stdout = real_stdout 

-

185 

-

186 if self.options.bPrintOutput: 186 ↛ 187line 186 didn't jump to line 187, because the condition on line 186 was never true

-

187 self.outstring = captured_stdout.getvalue() 

-

188 

-

189 # We need to make sure that the last line in the output 

-

190 # ends with a newline, or it will be joined to the 

-

191 # end-output line, ruining cog's idempotency. 

-

192 if self.outstring and self.outstring[-1] != '\n': 

-

193 self.outstring += '\n' 

+

167 # Make sure the "cog" module has our state. 

+

168 cog.cogmodule.msg = self.msg 

+

169 cog.cogmodule.out = self.out 

+

170 cog.cogmodule.outl = self.outl 

+

171 cog.cogmodule.error = self.error 

+

172 

+

173 real_stdout = sys.stdout 

+

174 if self.options.bPrintOutput: 174 ↛ 175line 174 didn't jump to line 175, because the condition on line 174 was never true

+

175 sys.stdout = captured_stdout = StringIO() 

+

176 

+

177 self.outstring = '' 

+

178 try: 

+

179 eval(code, globals) 

+

180 except CogError: 180 ↛ 181line 180 didn't jump to line 181, because the exception caught by line 180 didn't happen

+

181 raise 

+

182 except: 

+

183 typ, err, tb = sys.exc_info() 

+

184 frames = (tuple(fr) for fr in traceback.extract_tb(tb.tb_next)) 

+

185 frames = find_cog_source(frames, prologue) 

+

186 msg = "".join(traceback.format_list(frames)) 

+

187 msg += "{}: {}".format(typ.__name__, err) 

+

188 raise CogUserException(msg) 

+

189 finally: 

+

190 sys.stdout = real_stdout 

+

191 

+

192 if self.options.bPrintOutput: 192 ↛ 193line 192 didn't jump to line 193, because the condition on line 192 was never true

+

193 self.outstring = captured_stdout.getvalue() 

194 

-

195 return reindentBlock(self.outstring, prefOut) 

-

196 

-

197 def msg(self, s): 

-

198 self.prout("Message: "+s) 

-

199 

-

200 def out(self, sOut='', dedent=False, trimblanklines=False): 

-

201 """ The cog.out function. 

-

202 """ 

-

203 if trimblanklines and ('\n' in sOut): 

-

204 lines = sOut.split('\n') 

-

205 if lines[0].strip() == '': 

-

206 del lines[0] 

-

207 if lines and lines[-1].strip() == '': 

-

208 del lines[-1] 

-

209 sOut = '\n'.join(lines)+'\n' 

-

210 if dedent: 

-

211 sOut = reindentBlock(sOut) 

-

212 self.outstring += sOut 

-

213 

-

214 def outl(self, sOut='', **kw): 

-

215 """ The cog.outl function. 

-

216 """ 

-

217 self.out(sOut, **kw) 

-

218 self.out('\n') 

+

195 # We need to make sure that the last line in the output 

+

196 # ends with a newline, or it will be joined to the 

+

197 # end-output line, ruining cog's idempotency. 

+

198 if self.outstring and self.outstring[-1] != '\n': 

+

199 self.outstring += '\n' 

+

200 

+

201 return reindentBlock(self.outstring, prefOut) 

+

202 

+

203 def msg(self, s): 

+

204 self.prout("Message: "+s) 

+

205 

+

206 def out(self, sOut='', dedent=False, trimblanklines=False): 

+

207 """ The cog.out function. 

+

208 """ 

+

209 if trimblanklines and ('\n' in sOut): 

+

210 lines = sOut.split('\n') 

+

211 if lines[0].strip() == '': 

+

212 del lines[0] 

+

213 if lines and lines[-1].strip() == '': 

+

214 del lines[-1] 

+

215 sOut = '\n'.join(lines)+'\n' 

+

216 if dedent: 

+

217 sOut = reindentBlock(sOut) 

+

218 self.outstring += sOut 

219 

-

220 def error(self, msg='Error raised by cog generator.'): 

-

221 """ The cog.error function. 

-

222 Instead of raising standard python errors, cog generators can use 

-

223 this function. It will display the error without a scary Python 

-

224 traceback. 

-

225 """ 

-

226 raise CogGeneratedError(msg) 

-

227 

-

228 

-

229class NumberedFileReader: 

-

230 """ A decorator for files that counts the readline()'s called. 

-

231 """ 

-

232 def __init__(self, f): 

-

233 self.f = f 

-

234 self.n = 0 

-

235 

-

236 def readline(self): 

-

237 l = self.f.readline() 

-

238 if l: 

-

239 self.n += 1 

-

240 return l 

+

220 def outl(self, sOut='', **kw): 

+

221 """ The cog.outl function. 

+

222 """ 

+

223 self.out(sOut, **kw) 

+

224 self.out('\n') 

+

225 

+

226 def error(self, msg='Error raised by cog generator.'): 

+

227 """ The cog.error function. 

+

228 Instead of raising standard python errors, cog generators can use 

+

229 this function. It will display the error without a scary Python 

+

230 traceback. 

+

231 """ 

+

232 raise CogGeneratedError(msg) 

+

233 

+

234 

+

235class NumberedFileReader: 

+

236 """ A decorator for files that counts the readline()'s called. 

+

237 """ 

+

238 def __init__(self, f): 

+

239 self.f = f 

+

240 self.n = 0 

241 

-

242 def linenumber(self): 

-

243 return self.n 

-

244 

-

245 

-

246class CogOptions: 

-

247 """ Options for a run of cog. 

-

248 """ 

-

249 def __init__(self): 

-

250 # Defaults for argument values. 

-

251 self.args = [] 

-

252 self.includePath = [] 

-

253 self.defines = {} 

-

254 self.bShowVersion = False 

-

255 self.sMakeWritableCmd = None 

-

256 self.bReplace = False 

-

257 self.bNoGenerate = False 

-

258 self.sOutputName = None 

-

259 self.bWarnEmpty = False 

-

260 self.bHashOutput = False 

-

261 self.bDeleteCode = False 

-

262 self.bEofCanBeEnd = False 

-

263 self.sSuffix = None 

-

264 self.bNewlines = False 

-

265 self.sBeginSpec = '[[[cog' 

-

266 self.sEndSpec = ']]]' 

-

267 self.sEndOutput = '[[[end]]]' 

-

268 self.sEncoding = "utf-8" 

-

269 self.verbosity = 2 

-

270 self.sPrologue = '' 

-

271 self.bPrintOutput = False 

-

272 

-

273 def __eq__(self, other): 

-

274 """ Comparison operator for tests to use. 

-

275 """ 

-

276 return self.__dict__ == other.__dict__ 

-

277 

-

278 def clone(self): 

-

279 """ Make a clone of these options, for further refinement. 

-

280 """ 

-

281 return copy.deepcopy(self) 

-

282 

-

283 def addToIncludePath(self, dirs): 

-

284 """ Add directories to the include path. 

-

285 """ 

-

286 dirs = dirs.split(os.pathsep) 

-

287 self.includePath.extend(dirs) 

-

288 

-

289 def parseArgs(self, argv): 

-

290 # Parse the command line arguments. 

-

291 try: 

-

292 opts, self.args = getopt.getopt( 

-

293 argv, 

-

294 'cdD:eI:n:o:rs:p:PUvw:xz', 

-

295 [ 

-

296 'markers=', 

-

297 'verbosity=', 

-

298 ] 

-

299 ) 

-

300 except getopt.error as msg: 

-

301 raise CogUsageError(msg) 

-

302 

-

303 # Handle the command line arguments. 

-

304 for o, a in opts: 

-

305 if o == '-c': 

-

306 self.bHashOutput = True 

-

307 elif o == '-d': 

-

308 self.bDeleteCode = True 

-

309 elif o == '-D': 

-

310 if a.count('=') < 1: 

-

311 raise CogUsageError("-D takes a name=value argument") 

-

312 name, value = a.split('=', 1) 

-

313 self.defines[name] = value 

-

314 elif o == '-e': 

-

315 self.bWarnEmpty = True 

-

316 elif o == '-I': 

-

317 self.addToIncludePath(os.path.abspath(a)) 

-

318 elif o == '-n': 

-

319 self.sEncoding = a 

-

320 elif o == '-o': 

-

321 self.sOutputName = a 

-

322 elif o == '-r': 

-

323 self.bReplace = True 

-

324 elif o == '-s': 

-

325 self.sSuffix = a 

-

326 elif o == '-p': 

-

327 self.sPrologue = a 

-

328 elif o == '-P': 

-

329 self.bPrintOutput = True 

-

330 elif o == '-U': 

-

331 self.bNewlines = True 

-

332 elif o == '-v': 

-

333 self.bShowVersion = True 

-

334 elif o == '-w': 

-

335 self.sMakeWritableCmd = a 

-

336 elif o == '-x': 

-

337 self.bNoGenerate = True 

-

338 elif o == '-z': 

-

339 self.bEofCanBeEnd = True 

-

340 elif o == '--markers': 

-

341 self._parse_markers(a) 

-

342 elif o == '--verbosity': 

-

343 self.verbosity = int(a) 

-

344 else: 

-

345 # Since getopt.getopt is given a list of possible flags, 

-

346 # this is an internal error. 

-

347 raise CogInternalError("Don't understand argument %s" % o) 

-

348 

-

349 def _parse_markers(self, val): 

-

350 try: 

-

351 self.sBeginSpec, self.sEndSpec, self.sEndOutput = val.split(' ') 

-

352 except ValueError: 

-

353 raise CogUsageError( 

-

354 '--markers requires 3 values separated by spaces, could not parse %r' % val 

-

355 ) 

-

356 

-

357 def validate(self): 

-

358 """ Does nothing if everything is OK, raises CogError's if it's not. 

-

359 """ 

-

360 if self.bReplace and self.bDeleteCode: 

-

361 raise CogUsageError("Can't use -d with -r (or you would delete all your source!)") 

-

362 

-

363 if self.bReplace and self.sOutputName: 

-

364 raise CogUsageError("Can't use -o with -r (they are opposites)") 

-

365 

+

242 def readline(self): 

+

243 l = self.f.readline() 

+

244 if l: 

+

245 self.n += 1 

+

246 return l 

+

247 

+

248 def linenumber(self): 

+

249 return self.n 

+

250 

+

251 

+

252class CogOptions: 

+

253 """ Options for a run of cog. 

+

254 """ 

+

255 def __init__(self): 

+

256 # Defaults for argument values. 

+

257 self.args = [] 

+

258 self.includePath = [] 

+

259 self.defines = {} 

+

260 self.bShowVersion = False 

+

261 self.sMakeWritableCmd = None 

+

262 self.bReplace = False 

+

263 self.bNoGenerate = False 

+

264 self.sOutputName = None 

+

265 self.bWarnEmpty = False 

+

266 self.bHashOutput = False 

+

267 self.bDeleteCode = False 

+

268 self.bEofCanBeEnd = False 

+

269 self.sSuffix = None 

+

270 self.bNewlines = False 

+

271 self.sBeginSpec = '[[[cog' 

+

272 self.sEndSpec = ']]]' 

+

273 self.sEndOutput = '[[[end]]]' 

+

274 self.sEncoding = "utf-8" 

+

275 self.verbosity = 2 

+

276 self.sPrologue = '' 

+

277 self.bPrintOutput = False 

+

278 self.bCheck = False 

+

279 

+

280 def __eq__(self, other): 

+

281 """ Comparison operator for tests to use. 

+

282 """ 

+

283 return self.__dict__ == other.__dict__ 

+

284 

+

285 def clone(self): 

+

286 """ Make a clone of these options, for further refinement. 

+

287 """ 

+

288 return copy.deepcopy(self) 

+

289 

+

290 def addToIncludePath(self, dirs): 

+

291 """ Add directories to the include path. 

+

292 """ 

+

293 dirs = dirs.split(os.pathsep) 

+

294 self.includePath.extend(dirs) 

+

295 

+

296 def parseArgs(self, argv): 

+

297 # Parse the command line arguments. 

+

298 try: 

+

299 opts, self.args = getopt.getopt( 

+

300 argv, 

+

301 'cdD:eI:n:o:rs:p:PUvw:xz', 

+

302 [ 

+

303 'check', 

+

304 'markers=', 

+

305 'verbosity=', 

+

306 ] 

+

307 ) 

+

308 except getopt.error as msg: 

+

309 raise CogUsageError(msg) 

+

310 

+

311 # Handle the command line arguments. 

+

312 for o, a in opts: 

+

313 if o == '-c': 

+

314 self.bHashOutput = True 

+

315 elif o == '-d': 

+

316 self.bDeleteCode = True 

+

317 elif o == '-D': 

+

318 if a.count('=') < 1: 

+

319 raise CogUsageError("-D takes a name=value argument") 

+

320 name, value = a.split('=', 1) 

+

321 self.defines[name] = value 

+

322 elif o == '-e': 

+

323 self.bWarnEmpty = True 

+

324 elif o == '-I': 

+

325 self.addToIncludePath(os.path.abspath(a)) 

+

326 elif o == '-n': 

+

327 self.sEncoding = a 

+

328 elif o == '-o': 

+

329 self.sOutputName = a 

+

330 elif o == '-r': 

+

331 self.bReplace = True 

+

332 elif o == '-s': 

+

333 self.sSuffix = a 

+

334 elif o == '-p': 

+

335 self.sPrologue = a 

+

336 elif o == '-P': 

+

337 self.bPrintOutput = True 

+

338 elif o == '-U': 

+

339 self.bNewlines = True 

+

340 elif o == '-v': 

+

341 self.bShowVersion = True 

+

342 elif o == '-w': 

+

343 self.sMakeWritableCmd = a 

+

344 elif o == '-x': 

+

345 self.bNoGenerate = True 

+

346 elif o == '-z': 

+

347 self.bEofCanBeEnd = True 

+

348 elif o == '--check': 

+

349 self.bCheck = True 

+

350 elif o == '--markers': 

+

351 self._parse_markers(a) 

+

352 elif o == '--verbosity': 

+

353 self.verbosity = int(a) 

+

354 else: 

+

355 # Since getopt.getopt is given a list of possible flags, 

+

356 # this is an internal error. 

+

357 raise CogInternalError("Don't understand argument %s" % o) 

+

358 

+

359 def _parse_markers(self, val): 

+

360 try: 

+

361 self.sBeginSpec, self.sEndSpec, self.sEndOutput = val.split(' ') 

+

362 except ValueError: 

+

363 raise CogUsageError( 

+

364 '--markers requires 3 values separated by spaces, could not parse %r' % val 

+

365 ) 

366 

-

367class Cog(Redirectable): 

-

368 """ The Cog engine. 

-

369 """ 

-

370 def __init__(self): 

-

371 Redirectable.__init__(self) 

-

372 self.options = CogOptions() 

-

373 self._fixEndOutputPatterns() 

-

374 self.cogmodulename = "cog" 

-

375 self.createCogModule() 

+

367 def validate(self): 

+

368 """ Does nothing if everything is OK, raises CogError's if it's not. 

+

369 """ 

+

370 if self.bReplace and self.bDeleteCode: 

+

371 raise CogUsageError("Can't use -d with -r (or you would delete all your source!)") 

+

372 

+

373 if self.bReplace and self.sOutputName: 

+

374 raise CogUsageError("Can't use -o with -r (they are opposites)") 

+

375 

376 

-

377 def _fixEndOutputPatterns(self): 

-

378 end_output = re.escape(self.options.sEndOutput) 

-

379 self.reEndOutput = re.compile(end_output + r'(?P<hashsect> *\(checksum: (?P<hash>[a-f0-9]+)\))') 

-

380 self.sEndFormat = self.options.sEndOutput + ' (checksum: %s)' 

-

381 

-

382 def showWarning(self, msg): 

-

383 self.prout("Warning: "+msg) 

-

384 

-

385 def isBeginSpecLine(self, s): 

-

386 return self.options.sBeginSpec in s 

+

377class Cog(Redirectable): 

+

378 """ The Cog engine. 

+

379 """ 

+

380 def __init__(self): 

+

381 Redirectable.__init__(self) 

+

382 self.options = CogOptions() 

+

383 self._fixEndOutputPatterns() 

+

384 self.cogmodulename = "cog" 

+

385 self.createCogModule() 

+

386 self.bCheckFailed = False 

387 

-

388 def isEndSpecLine(self, s): 

-

389 return self.options.sEndSpec in s and not self.isEndOutputLine(s) 

-

390 

-

391 def isEndOutputLine(self, s): 

-

392 return self.options.sEndOutput in s 

-

393 

-

394 def createCogModule(self): 

-

395 """ Make a cog "module" object so that imported Python modules 

-

396 can say "import cog" and get our state. 

-

397 """ 

-

398 class DummyModule(object): 

-

399 """Modules don't have to be anything special, just an object will do.""" 

-

400 pass 

-

401 self.cogmodule = DummyModule() 

-

402 self.cogmodule.path = [] 

-

403 

-

404 def openOutputFile(self, fname): 

-

405 """ Open an output file, taking all the details into account. 

-

406 """ 

-

407 opts = {} 

-

408 mode = "w" 

-

409 if PY3: 

-

410 opts['encoding'] = self.options.sEncoding 

-

411 if self.options.bNewlines: 

-

412 if PY3: 

-

413 opts['newline'] = "\n" 

-

414 else: 

-

415 mode = "wb" 

-

416 fdir = os.path.dirname(fname) 

-

417 if os.path.dirname(fdir) and not os.path.exists(fdir): 

-

418 os.makedirs(fdir) 

-

419 return open(fname, mode, **opts) 

-

420 

-

421 def openInputFile(self, fname): 

-

422 """ Open an input file. """ 

-

423 if fname == "-": 

-

424 return sys.stdin 

-

425 else: 

-

426 opts = {} 

-

427 if PY3: 

-

428 opts['encoding'] = self.options.sEncoding 

-

429 return open(fname, "r", **opts) 

-

430 

-

431 def processFile(self, fIn, fOut, fname=None, globals=None): 

-

432 """ Process an input file object to an output file object. 

-

433 fIn and fOut can be file objects, or file names. 

-

434 """ 

-

435 

-

436 sFileIn = fname or '' 

-

437 sFileOut = fname or '' 

-

438 fInToClose = fOutToClose = None 

-

439 # Convert filenames to files. 

-

440 if isinstance(fIn, string_types): 440 ↛ 442line 440 didn't jump to line 442, because the condition on line 440 was never true

-

441 # Open the input file. 

-

442 sFileIn = fIn 

-

443 fIn = fInToClose = self.openInputFile(fIn) 

-

444 if isinstance(fOut, string_types): 444 ↛ 446line 444 didn't jump to line 446, because the condition on line 444 was never true

-

445 # Open the output file. 

-

446 sFileOut = fOut 

-

447 fOut = fOutToClose = self.openOutputFile(fOut) 

-

448 

-

449 try: 

-

450 fIn = NumberedFileReader(fIn) 

-

451 

-

452 bSawCog = False 

-

453 

-

454 self.cogmodule.inFile = sFileIn 

-

455 self.cogmodule.outFile = sFileOut 

-

456 self.cogmodulename = 'cog_' + hashlib.md5(sFileOut.encode()).hexdigest() 

-

457 sys.modules[self.cogmodulename] = self.cogmodule 

-

458 # if "import cog" explicitly done in code by user, note threading will cause clashes. 

-

459 sys.modules['cog'] = self.cogmodule 

-

460 

-

461 # The globals dict we'll use for this file. 

-

462 if globals is None: 462 ↛ 466line 462 didn't jump to line 466, because the condition on line 462 was never false

-

463 globals = {} 

+

388 def _fixEndOutputPatterns(self): 

+

389 end_output = re.escape(self.options.sEndOutput) 

+

390 self.reEndOutput = re.compile(end_output + r'(?P<hashsect> *\(checksum: (?P<hash>[a-f0-9]+)\))') 

+

391 self.sEndFormat = self.options.sEndOutput + ' (checksum: %s)' 

+

392 

+

393 def showWarning(self, msg): 

+

394 self.prout("Warning: "+msg) 

+

395 

+

396 def isBeginSpecLine(self, s): 

+

397 return self.options.sBeginSpec in s 

+

398 

+

399 def isEndSpecLine(self, s): 

+

400 return self.options.sEndSpec in s and not self.isEndOutputLine(s) 

+

401 

+

402 def isEndOutputLine(self, s): 

+

403 return self.options.sEndOutput in s 

+

404 

+

405 def createCogModule(self): 

+

406 """ Make a cog "module" object so that imported Python modules 

+

407 can say "import cog" and get our state. 

+

408 """ 

+

409 class DummyModule(object): 

+

410 """Modules don't have to be anything special, just an object will do.""" 

+

411 pass 

+

412 self.cogmodule = DummyModule() 

+

413 self.cogmodule.path = [] 

+

414 

+

415 def openOutputFile(self, fname): 

+

416 """ Open an output file, taking all the details into account. 

+

417 """ 

+

418 opts = {} 

+

419 mode = "w" 

+

420 if PY3: 

+

421 opts['encoding'] = self.options.sEncoding 

+

422 if self.options.bNewlines: 

+

423 if PY3: 

+

424 opts['newline'] = "\n" 

+

425 else: 

+

426 mode = "wb" 

+

427 fdir = os.path.dirname(fname) 

+

428 if os.path.dirname(fdir) and not os.path.exists(fdir): 

+

429 os.makedirs(fdir) 

+

430 return open(fname, mode, **opts) 

+

431 

+

432 def openInputFile(self, fname): 

+

433 """ Open an input file. """ 

+

434 if fname == "-": 

+

435 return sys.stdin 

+

436 else: 

+

437 opts = {} 

+

438 if PY3: 

+

439 opts['encoding'] = self.options.sEncoding 

+

440 return open(fname, "r", **opts) 

+

441 

+

442 def processFile(self, fIn, fOut, fname=None, globals=None): 

+

443 """ Process an input file object to an output file object. 

+

444 fIn and fOut can be file objects, or file names. 

+

445 """ 

+

446 

+

447 sFileIn = fname or '' 

+

448 sFileOut = fname or '' 

+

449 fInToClose = fOutToClose = None 

+

450 # Convert filenames to files. 

+

451 if isinstance(fIn, string_types): 451 ↛ 453line 451 didn't jump to line 453, because the condition on line 451 was never true

+

452 # Open the input file. 

+

453 sFileIn = fIn 

+

454 fIn = fInToClose = self.openInputFile(fIn) 

+

455 if isinstance(fOut, string_types): 455 ↛ 457line 455 didn't jump to line 457, because the condition on line 455 was never true

+

456 # Open the output file. 

+

457 sFileOut = fOut 

+

458 fOut = fOutToClose = self.openOutputFile(fOut) 

+

459 

+

460 try: 

+

461 fIn = NumberedFileReader(fIn) 

+

462 

+

463 bSawCog = False 

464 

-

465 # If there are any global defines, put them in the globals. 

-

466 globals.update(self.options.defines) 

-

467 

-

468 # loop over generator chunks 

-

469 l = fIn.readline() 

-

470 while l: 

-

471 # Find the next spec begin 

-

472 while l and not self.isBeginSpecLine(l): 

-

473 if self.isEndSpecLine(l): 473 ↛ 474line 473 didn't jump to line 474, because the condition on line 473 was never true

-

474 raise CogError("Unexpected '%s'" % self.options.sEndSpec, 

-

475 file=sFileIn, line=fIn.linenumber()) 

-

476 if self.isEndOutputLine(l): 476 ↛ 477line 476 didn't jump to line 477, because the condition on line 476 was never true

-

477 raise CogError("Unexpected '%s'" % self.options.sEndOutput, 

-

478 file=sFileIn, line=fIn.linenumber()) 

-

479 fOut.write(l) 

-

480 l = fIn.readline() 

-

481 if not l: 

-

482 break 

-

483 if not self.options.bDeleteCode: 483 ↛ 487line 483 didn't jump to line 487, because the condition on line 483 was never false

-

484 fOut.write(l) 

-

485 

-

486 # l is the begin spec 

-

487 gen = CogGenerator(options=self.options) 

-

488 gen.setOutput(stdout=self.stdout) 

-

489 gen.parseMarker(l) 

-

490 firstLineNum = fIn.linenumber() 

-

491 self.cogmodule.firstLineNum = firstLineNum 

-

492 

-

493 # If the spec begin is also a spec end, then process the single 

-

494 # line of code inside. 

-

495 if self.isEndSpecLine(l): 

-

496 beg = l.find(self.options.sBeginSpec) 

-

497 end = l.find(self.options.sEndSpec) 

-

498 if beg > end: 

-

499 raise CogError("Cog code markers inverted", 

-

500 file=sFileIn, line=firstLineNum) 

-

501 else: 

-

502 sCode = l[beg+len(self.options.sBeginSpec):end].strip() 

-

503 gen.parseLine(sCode) 

-

504 else: 

-

505 # Deal with an ordinary code block. 

-

506 l = fIn.readline() 

-

507 

-

508 # Get all the lines in the spec 

-

509 while l and not self.isEndSpecLine(l): 

-

510 if self.isBeginSpecLine(l): 510 ↛ 511line 510 didn't jump to line 511, because the condition on line 510 was never true

-

511 raise CogError("Unexpected '%s'" % self.options.sBeginSpec, 

-

512 file=sFileIn, line=fIn.linenumber()) 

-

513 if self.isEndOutputLine(l): 513 ↛ 514line 513 didn't jump to line 514, because the condition on line 513 was never true

-

514 raise CogError("Unexpected '%s'" % self.options.sEndOutput, 

-

515 file=sFileIn, line=fIn.linenumber()) 

-

516 if not self.options.bDeleteCode: 516 ↛ 518line 516 didn't jump to line 518, because the condition on line 516 was never false

-

517 fOut.write(l) 

-

518 gen.parseLine(l) 

-

519 l = fIn.readline() 

-

520 if not l: 520 ↛ 521line 520 didn't jump to line 521, because the condition on line 520 was never true

-

521 raise CogError( 

-

522 "Cog block begun but never ended.", 

-

523 file=sFileIn, line=firstLineNum) 

-

524 

-

525 if not self.options.bDeleteCode: 525 ↛ 527line 525 didn't jump to line 527, because the condition on line 525 was never false

-

526 fOut.write(l) 

-

527 gen.parseMarker(l) 

-

528 

-

529 l = fIn.readline() 

-

530 

-

531 # Eat all the lines in the output section. While reading past 

-

532 # them, compute the md5 hash of the old output. 

-

533 previous = "" 

-

534 hasher = hashlib.md5() 

-

535 while l and not self.isEndOutputLine(l): 

-

536 if self.isBeginSpecLine(l): 536 ↛ 537line 536 didn't jump to line 537, because the condition on line 536 was never true

-

537 raise CogError("Unexpected '%s'" % self.options.sBeginSpec, 

-

538 file=sFileIn, line=fIn.linenumber()) 

-

539 if self.isEndSpecLine(l): 539 ↛ 540line 539 didn't jump to line 540, because the condition on line 539 was never true

-

540 raise CogError("Unexpected '%s'" % self.options.sEndSpec, 

-

541 file=sFileIn, line=fIn.linenumber()) 

-

542 previous += l 

-

543 hasher.update(to_bytes(l)) 

-

544 l = fIn.readline() 

-

545 curHash = hasher.hexdigest() 

-

546 

-

547 if not l and not self.options.bEofCanBeEnd: 547 ↛ 549line 547 didn't jump to line 549, because the condition on line 547 was never true

-

548 # We reached end of file before we found the end output line. 

-

549 raise CogError("Missing '%s' before end of file." % self.options.sEndOutput, 

-

550 file=sFileIn, line=fIn.linenumber()) 

-

551 

-

552 # Make the previous output available to the current code 

-

553 self.cogmodule.previous = previous 

-

554 

-

555 # Write the output of the spec to be the new output if we're 

-

556 # supposed to generate code. 

-

557 hasher = hashlib.md5() 

-

558 if not self.options.bNoGenerate: 558 ↛ 564line 558 didn't jump to line 564, because the condition on line 558 was never false

-

559 sFile = "<cog %s:%d>" % (sFileIn, firstLineNum) 

-

560 sGen = gen.evaluate(cog=self, globals=globals, fname=sFile) 

-

561 sGen = self.suffixLines(sGen) 

-

562 hasher.update(to_bytes(sGen)) 

-

563 fOut.write(sGen) 

-

564 newHash = hasher.hexdigest() 

+

465 self.cogmodule.inFile = sFileIn 

+

466 self.cogmodule.outFile = sFileOut 

+

467 self.cogmodulename = 'cog_' + hashlib.md5(sFileOut.encode()).hexdigest() 

+

468 sys.modules[self.cogmodulename] = self.cogmodule 

+

469 # if "import cog" explicitly done in code by user, note threading will cause clashes. 

+

470 sys.modules['cog'] = self.cogmodule 

+

471 

+

472 # The globals dict we'll use for this file. 

+

473 if globals is None: 473 ↛ 477line 473 didn't jump to line 477, because the condition on line 473 was never false

+

474 globals = {} 

+

475 

+

476 # If there are any global defines, put them in the globals. 

+

477 globals.update(self.options.defines) 

+

478 

+

479 # loop over generator chunks 

+

480 l = fIn.readline() 

+

481 while l: 

+

482 # Find the next spec begin 

+

483 while l and not self.isBeginSpecLine(l): 

+

484 if self.isEndSpecLine(l): 484 ↛ 485line 484 didn't jump to line 485, because the condition on line 484 was never true

+

485 raise CogError("Unexpected '%s'" % self.options.sEndSpec, 

+

486 file=sFileIn, line=fIn.linenumber()) 

+

487 if self.isEndOutputLine(l): 487 ↛ 488line 487 didn't jump to line 488, because the condition on line 487 was never true

+

488 raise CogError("Unexpected '%s'" % self.options.sEndOutput, 

+

489 file=sFileIn, line=fIn.linenumber()) 

+

490 fOut.write(l) 

+

491 l = fIn.readline() 

+

492 if not l: 

+

493 break 

+

494 if not self.options.bDeleteCode: 494 ↛ 498line 494 didn't jump to line 498, because the condition on line 494 was never false

+

495 fOut.write(l) 

+

496 

+

497 # l is the begin spec 

+

498 gen = CogGenerator(options=self.options) 

+

499 gen.setOutput(stdout=self.stdout) 

+

500 gen.parseMarker(l) 

+

501 firstLineNum = fIn.linenumber() 

+

502 self.cogmodule.firstLineNum = firstLineNum 

+

503 

+

504 # If the spec begin is also a spec end, then process the single 

+

505 # line of code inside. 

+

506 if self.isEndSpecLine(l): 

+

507 beg = l.find(self.options.sBeginSpec) 

+

508 end = l.find(self.options.sEndSpec) 

+

509 if beg > end: 

+

510 raise CogError("Cog code markers inverted", 

+

511 file=sFileIn, line=firstLineNum) 

+

512 else: 

+

513 sCode = l[beg+len(self.options.sBeginSpec):end].strip() 

+

514 gen.parseLine(sCode) 

+

515 else: 

+

516 # Deal with an ordinary code block. 

+

517 l = fIn.readline() 

+

518 

+

519 # Get all the lines in the spec 

+

520 while l and not self.isEndSpecLine(l): 

+

521 if self.isBeginSpecLine(l): 521 ↛ 522line 521 didn't jump to line 522, because the condition on line 521 was never true

+

522 raise CogError("Unexpected '%s'" % self.options.sBeginSpec, 

+

523 file=sFileIn, line=fIn.linenumber()) 

+

524 if self.isEndOutputLine(l): 524 ↛ 525line 524 didn't jump to line 525, because the condition on line 524 was never true

+

525 raise CogError("Unexpected '%s'" % self.options.sEndOutput, 

+

526 file=sFileIn, line=fIn.linenumber()) 

+

527 if not self.options.bDeleteCode: 527 ↛ 529line 527 didn't jump to line 529, because the condition on line 527 was never false

+

528 fOut.write(l) 

+

529 gen.parseLine(l) 

+

530 l = fIn.readline() 

+

531 if not l: 531 ↛ 532line 531 didn't jump to line 532, because the condition on line 531 was never true

+

532 raise CogError( 

+

533 "Cog block begun but never ended.", 

+

534 file=sFileIn, line=firstLineNum) 

+

535 

+

536 if not self.options.bDeleteCode: 536 ↛ 538line 536 didn't jump to line 538, because the condition on line 536 was never false

+

537 fOut.write(l) 

+

538 gen.parseMarker(l) 

+

539 

+

540 l = fIn.readline() 

+

541 

+

542 # Eat all the lines in the output section. While reading past 

+

543 # them, compute the md5 hash of the old output. 

+

544 previous = "" 

+

545 hasher = hashlib.md5() 

+

546 while l and not self.isEndOutputLine(l): 

+

547 if self.isBeginSpecLine(l): 547 ↛ 548line 547 didn't jump to line 548, because the condition on line 547 was never true

+

548 raise CogError("Unexpected '%s'" % self.options.sBeginSpec, 

+

549 file=sFileIn, line=fIn.linenumber()) 

+

550 if self.isEndSpecLine(l): 550 ↛ 551line 550 didn't jump to line 551, because the condition on line 550 was never true

+

551 raise CogError("Unexpected '%s'" % self.options.sEndSpec, 

+

552 file=sFileIn, line=fIn.linenumber()) 

+

553 previous += l 

+

554 hasher.update(to_bytes(l)) 

+

555 l = fIn.readline() 

+

556 curHash = hasher.hexdigest() 

+

557 

+

558 if not l and not self.options.bEofCanBeEnd: 558 ↛ 560line 558 didn't jump to line 560, because the condition on line 558 was never true

+

559 # We reached end of file before we found the end output line. 

+

560 raise CogError("Missing '%s' before end of file." % self.options.sEndOutput, 

+

561 file=sFileIn, line=fIn.linenumber()) 

+

562 

+

563 # Make the previous output available to the current code 

+

564 self.cogmodule.previous = previous 

565 

-

566 bSawCog = True 

-

567 

-

568 # Write the ending output line 

-

569 hashMatch = self.reEndOutput.search(l) 

-

570 if self.options.bHashOutput: 570 ↛ 571line 570 didn't jump to line 571, because the condition on line 570 was never true

-

571 if hashMatch: 

-

572 oldHash = hashMatch.groupdict()['hash'] 

-

573 if oldHash != curHash: 

-

574 raise CogError("Output has been edited! Delete old checksum to unprotect.", 

-

575 file=sFileIn, line=fIn.linenumber()) 

-

576 # Create a new end line with the correct hash. 

-

577 endpieces = l.split(hashMatch.group(0), 1) 

-

578 else: 

-

579 # There was no old hash, but we want a new hash. 

-

580 endpieces = l.split(self.options.sEndOutput, 1) 

-

581 l = (self.sEndFormat % newHash).join(endpieces) 

-

582 else: 

-

583 # We don't want hashes output, so if there was one, get rid of 

-

584 # it. 

-

585 if hashMatch: 585 ↛ 586line 585 didn't jump to line 586, because the condition on line 585 was never true

-

586 l = l.replace(hashMatch.groupdict()['hashsect'], '', 1) 

-

587 

-

588 if not self.options.bDeleteCode: 588 ↛ 590line 588 didn't jump to line 590, because the condition on line 588 was never false

-

589 fOut.write(l) 

-

590 l = fIn.readline() 

-

591 

-

592 if not bSawCog and self.options.bWarnEmpty: 592 ↛ 593line 592 didn't jump to line 593, because the condition on line 592 was never true

-

593 self.showWarning("no cog code found in %s" % sFileIn) 

-

594 finally: 

-

595 if fInToClose: 595 ↛ 596line 595 didn't jump to line 596, because the condition on line 595 was never true

-

596 fInToClose.close() 

-

597 if fOutToClose: 597 ↛ 598line 597 didn't jump to line 598, because the condition on line 597 was never true

-

598 fOutToClose.close() 

-

599 

-

600 

-

601 # A regex for non-empty lines, used by suffixLines. 

-

602 reNonEmptyLines = re.compile(r"^\s*\S+.*$", re.MULTILINE) 

-

603 

-

604 def suffixLines(self, text): 

-

605 """ Add suffixes to the lines in text, if our options desire it. 

-

606 text is many lines, as a single string. 

-

607 """ 

-

608 if self.options.sSuffix: 608 ↛ 610line 608 didn't jump to line 610, because the condition on line 608 was never true

-

609 # Find all non-blank lines, and add the suffix to the end. 

-

610 repl = r"\g<0>" + self.options.sSuffix.replace('\\', '\\\\') 

-

611 text = self.reNonEmptyLines.sub(repl, text) 

-

612 return text 

-

613 

-

614 def processString(self, sInput, fname=None): 

-

615 """ Process sInput as the text to cog. 

-

616 Return the cogged output as a string. 

-

617 """ 

-

618 fOld = StringIO(sInput) 

-

619 fNew = StringIO() 

-

620 self.processFile(fOld, fNew, fname=fname) 

-

621 return fNew.getvalue() 

-

622 

-

623 def replaceFile(self, sOldPath, sNewText): 

-

624 """ Replace file sOldPath with the contents sNewText 

-

625 """ 

-

626 if not os.access(sOldPath, os.W_OK): 

-

627 # Need to ensure we can write. 

-

628 if self.options.sMakeWritableCmd: 

-

629 # Use an external command to make the file writable. 

-

630 cmd = self.options.sMakeWritableCmd.replace('%s', sOldPath) 

-

631 self.stdout.write(os.popen(cmd).read()) 

-

632 if not os.access(sOldPath, os.W_OK): 

-

633 raise CogError("Couldn't make %s writable" % sOldPath) 

-

634 else: 

-

635 # Can't write! 

-

636 raise CogError("Can't overwrite %s" % sOldPath) 

-

637 f = self.openOutputFile(sOldPath) 

-

638 f.write(sNewText) 

-

639 f.close() 

-

640 

-

641 def saveIncludePath(self): 

-

642 self.savedInclude = self.options.includePath[:] 

-

643 self.savedSysPath = sys.path[:] 

-

644 

-

645 def restoreIncludePath(self): 

-

646 self.options.includePath = self.savedInclude 

-

647 self.cogmodule.path = self.options.includePath 

-

648 sys.path = self.savedSysPath 

-

649 

-

650 def addToIncludePath(self, includePath): 

-

651 self.cogmodule.path.extend(includePath) 

-

652 sys.path.extend(includePath) 

-

653 

-

654 def processOneFile(self, sFile): 

-

655 """ Process one filename through cog. 

-

656 """ 

-

657 

-

658 self.saveIncludePath() 

-

659 bNeedNewline = False 

+

566 # Write the output of the spec to be the new output if we're 

+

567 # supposed to generate code. 

+

568 hasher = hashlib.md5() 

+

569 if not self.options.bNoGenerate: 569 ↛ 575line 569 didn't jump to line 575, because the condition on line 569 was never false

+

570 sFile = "<cog %s:%d>" % (sFileIn, firstLineNum) 

+

571 sGen = gen.evaluate(cog=self, globals=globals, fname=sFile) 

+

572 sGen = self.suffixLines(sGen) 

+

573 hasher.update(to_bytes(sGen)) 

+

574 fOut.write(sGen) 

+

575 newHash = hasher.hexdigest() 

+

576 

+

577 bSawCog = True 

+

578 

+

579 # Write the ending output line 

+

580 hashMatch = self.reEndOutput.search(l) 

+

581 if self.options.bHashOutput: 581 ↛ 582line 581 didn't jump to line 582, because the condition on line 581 was never true

+

582 if hashMatch: 

+

583 oldHash = hashMatch.groupdict()['hash'] 

+

584 if oldHash != curHash: 

+

585 raise CogError("Output has been edited! Delete old checksum to unprotect.", 

+

586 file=sFileIn, line=fIn.linenumber()) 

+

587 # Create a new end line with the correct hash. 

+

588 endpieces = l.split(hashMatch.group(0), 1) 

+

589 else: 

+

590 # There was no old hash, but we want a new hash. 

+

591 endpieces = l.split(self.options.sEndOutput, 1) 

+

592 l = (self.sEndFormat % newHash).join(endpieces) 

+

593 else: 

+

594 # We don't want hashes output, so if there was one, get rid of 

+

595 # it. 

+

596 if hashMatch: 596 ↛ 597line 596 didn't jump to line 597, because the condition on line 596 was never true

+

597 l = l.replace(hashMatch.groupdict()['hashsect'], '', 1) 

+

598 

+

599 if not self.options.bDeleteCode: 599 ↛ 601line 599 didn't jump to line 601, because the condition on line 599 was never false

+

600 fOut.write(l) 

+

601 l = fIn.readline() 

+

602 

+

603 if not bSawCog and self.options.bWarnEmpty: 603 ↛ 604line 603 didn't jump to line 604, because the condition on line 603 was never true

+

604 self.showWarning("no cog code found in %s" % sFileIn) 

+

605 finally: 

+

606 if fInToClose: 606 ↛ 607line 606 didn't jump to line 607, because the condition on line 606 was never true

+

607 fInToClose.close() 

+

608 if fOutToClose: 608 ↛ 609line 608 didn't jump to line 609, because the condition on line 608 was never true

+

609 fOutToClose.close() 

+

610 

+

611 

+

612 # A regex for non-empty lines, used by suffixLines. 

+

613 reNonEmptyLines = re.compile(r"^\s*\S+.*$", re.MULTILINE) 

+

614 

+

615 def suffixLines(self, text): 

+

616 """ Add suffixes to the lines in text, if our options desire it. 

+

617 text is many lines, as a single string. 

+

618 """ 

+

619 if self.options.sSuffix: 619 ↛ 621line 619 didn't jump to line 621, because the condition on line 619 was never true

+

620 # Find all non-blank lines, and add the suffix to the end. 

+

621 repl = r"\g<0>" + self.options.sSuffix.replace('\\', '\\\\') 

+

622 text = self.reNonEmptyLines.sub(repl, text) 

+

623 return text 

+

624 

+

625 def processString(self, sInput, fname=None): 

+

626 """ Process sInput as the text to cog. 

+

627 Return the cogged output as a string. 

+

628 """ 

+

629 fOld = StringIO(sInput) 

+

630 fNew = StringIO() 

+

631 self.processFile(fOld, fNew, fname=fname) 

+

632 return fNew.getvalue() 

+

633 

+

634 def replaceFile(self, sOldPath, sNewText): 

+

635 """ Replace file sOldPath with the contents sNewText 

+

636 """ 

+

637 if not os.access(sOldPath, os.W_OK): 

+

638 # Need to ensure we can write. 

+

639 if self.options.sMakeWritableCmd: 

+

640 # Use an external command to make the file writable. 

+

641 cmd = self.options.sMakeWritableCmd.replace('%s', sOldPath) 

+

642 self.stdout.write(os.popen(cmd).read()) 

+

643 if not os.access(sOldPath, os.W_OK): 

+

644 raise CogError("Couldn't make %s writable" % sOldPath) 

+

645 else: 

+

646 # Can't write! 

+

647 raise CogError("Can't overwrite %s" % sOldPath) 

+

648 f = self.openOutputFile(sOldPath) 

+

649 f.write(sNewText) 

+

650 f.close() 

+

651 

+

652 def saveIncludePath(self): 

+

653 self.savedInclude = self.options.includePath[:] 

+

654 self.savedSysPath = sys.path[:] 

+

655 

+

656 def restoreIncludePath(self): 

+

657 self.options.includePath = self.savedInclude 

+

658 self.cogmodule.path = self.options.includePath 

+

659 sys.path = self.savedSysPath 

660 

-

661 try: 

-

662 self.addToIncludePath(self.options.includePath) 

-

663 # Since we know where the input file came from, 

-

664 # push its directory onto the include path. 

-

665 self.addToIncludePath([os.path.dirname(sFile)]) 

-

666 

-

667 # How we process the file depends on where the output is going. 

-

668 if self.options.sOutputName: 

-

669 self.processFile(sFile, self.options.sOutputName, sFile) 

-

670 elif self.options.bReplace: 

-

671 # We want to replace the cog file with the output, 

-

672 # but only if they differ. 

-

673 if self.options.verbosity >= 2: 

-

674 self.prout("Cogging %s" % sFile, end="") 

-

675 bNeedNewline = True 

-

676 

-

677 try: 

-

678 fOldFile = self.openInputFile(sFile) 

-

679 sOldText = fOldFile.read() 

-

680 fOldFile.close() 

-

681 sNewText = self.processString(sOldText, fname=sFile) 

-

682 if sOldText != sNewText: 

-

683 if self.options.verbosity >= 1: 

-

684 if self.options.verbosity < 2: 

-

685 self.prout("Cogging %s" % sFile, end="") 

-

686 self.prout(" (changed)") 

-

687 bNeedNewline = False 

-

688 self.replaceFile(sFile, sNewText) 

-

689 finally: 

-

690 # The try-finally block is so we can print a partial line 

-

691 # with the name of the file, and print (changed) on the 

-

692 # same line, but also make sure to break the line before 

-

693 # any traceback. 

-

694 if bNeedNewline: 

-

695 self.prout("") 

-

696 else: 

-

697 self.processFile(sFile, self.stdout, sFile) 

-

698 finally: 

-

699 self.restoreIncludePath() 

-

700 

-

701 def processWildcards(self, sFile): 

-

702 files = glob.glob(sFile) 

-

703 if files: 

-

704 for sMatchingFile in files: 

-

705 self.processOneFile(sMatchingFile) 

-

706 else: 

-

707 self.processOneFile(sFile) 

-

708 

-

709 def processFileList(self, sFileList): 

-

710 """ Process the files in a file list. 

-

711 """ 

-

712 flist = self.openInputFile(sFileList) 

-

713 lines = flist.readlines() 

-

714 flist.close() 

-

715 for l in lines: 

-

716 # Use shlex to parse the line like a shell. 

-

717 lex = shlex.shlex(l, posix=True) 

-

718 lex.whitespace_split = True 

-

719 lex.commenters = '#' 

-

720 # No escapes, so that backslash can be part of the path 

-

721 lex.escape = '' 

-

722 args = list(lex) 

-

723 if args: 

-

724 self.processArguments(args) 

-

725 

-

726 def processArguments(self, args): 

-

727 """ Process one command-line. 

-

728 """ 

-

729 saved_options = self.options 

-

730 self.options = self.options.clone() 

-

731 

-

732 self.options.parseArgs(args[1:]) 

-

733 self.options.validate() 

-

734 

-

735 if args[0][0] == '@': 

-

736 if self.options.sOutputName: 

-

737 raise CogUsageError("Can't use -o with @file") 

-

738 self.processFileList(args[0][1:]) 

-

739 else: 

-

740 self.processWildcards(args[0]) 

+

661 def addToIncludePath(self, includePath): 

+

662 self.cogmodule.path.extend(includePath) 

+

663 sys.path.extend(includePath) 

+

664 

+

665 def processOneFile(self, sFile): 

+

666 """ Process one filename through cog. 

+

667 """ 

+

668 

+

669 self.saveIncludePath() 

+

670 bNeedNewline = False 

+

671 

+

672 try: 

+

673 self.addToIncludePath(self.options.includePath) 

+

674 # Since we know where the input file came from, 

+

675 # push its directory onto the include path. 

+

676 self.addToIncludePath([os.path.dirname(sFile)]) 

+

677 

+

678 # How we process the file depends on where the output is going. 

+

679 if self.options.sOutputName: 

+

680 self.processFile(sFile, self.options.sOutputName, sFile) 

+

681 elif self.options.bReplace or self.options.bCheck: 

+

682 # We want to replace the cog file with the output, 

+

683 # but only if they differ. 

+

684 verb = "Cogging" if self.options.bReplace else "Checking" 

+

685 if self.options.verbosity >= 2: 

+

686 self.prout("%s %s" % (verb, sFile), end="") 

+

687 bNeedNewline = True 

+

688 

+

689 try: 

+

690 fOldFile = self.openInputFile(sFile) 

+

691 sOldText = fOldFile.read() 

+

692 fOldFile.close() 

+

693 sNewText = self.processString(sOldText, fname=sFile) 

+

694 if sOldText != sNewText: 

+

695 if self.options.verbosity >= 1: 

+

696 if self.options.verbosity < 2: 

+

697 self.prout("%s %s" % (verb, sFile), end="") 

+

698 self.prout(" (changed)") 

+

699 bNeedNewline = False 

+

700 if self.options.bReplace: 

+

701 self.replaceFile(sFile, sNewText) 

+

702 else: 

+

703 assert self.options.bCheck 

+

704 self.bCheckFailed = True 

+

705 finally: 

+

706 # The try-finally block is so we can print a partial line 

+

707 # with the name of the file, and print (changed) on the 

+

708 # same line, but also make sure to break the line before 

+

709 # any traceback. 

+

710 if bNeedNewline: 

+

711 self.prout("") 

+

712 else: 

+

713 self.processFile(sFile, self.stdout, sFile) 

+

714 finally: 

+

715 self.restoreIncludePath() 

+

716 

+

717 def processWildcards(self, sFile): 

+

718 files = glob.glob(sFile) 

+

719 if files: 

+

720 for sMatchingFile in files: 

+

721 self.processOneFile(sMatchingFile) 

+

722 else: 

+

723 self.processOneFile(sFile) 

+

724 

+

725 def processFileList(self, sFileList): 

+

726 """ Process the files in a file list. 

+

727 """ 

+

728 flist = self.openInputFile(sFileList) 

+

729 lines = flist.readlines() 

+

730 flist.close() 

+

731 for l in lines: 

+

732 # Use shlex to parse the line like a shell. 

+

733 lex = shlex.shlex(l, posix=True) 

+

734 lex.whitespace_split = True 

+

735 lex.commenters = '#' 

+

736 # No escapes, so that backslash can be part of the path 

+

737 lex.escape = '' 

+

738 args = list(lex) 

+

739 if args: 

+

740 self.processArguments(args) 

741 

-

742 self.options = saved_options 

-

743 

-

744 def callableMain(self, argv): 

-

745 """ All of command-line cog, but in a callable form. 

-

746 This is used by main. 

-

747 argv is the equivalent of sys.argv. 

-

748 """ 

-

749 argv = argv[1:] 

+

742 def processArguments(self, args): 

+

743 """ Process one command-line. 

+

744 """ 

+

745 saved_options = self.options 

+

746 self.options = self.options.clone() 

+

747 

+

748 self.options.parseArgs(args[1:]) 

+

749 self.options.validate() 

750 

-

751 # Provide help if asked for anywhere in the command line. 

-

752 if '-?' in argv or '-h' in argv: 

-

753 self.prerr(usage, end="") 

-

754 return 

-

755 

-

756 self.options.parseArgs(argv) 

-

757 self.options.validate() 

-

758 self._fixEndOutputPatterns() 

+

751 if args[0][0] == '@': 

+

752 if self.options.sOutputName: 

+

753 raise CogUsageError("Can't use -o with @file") 

+

754 self.processFileList(args[0][1:]) 

+

755 else: 

+

756 self.processWildcards(args[0]) 

+

757 

+

758 self.options = saved_options 

759 

-

760 if self.options.bShowVersion: 

-

761 self.prout("Cog version %s" % __version__) 

-

762 return 

-

763 

-

764 if self.options.args: 

-

765 for a in self.options.args: 

-

766 self.processArguments([a]) 

-

767 else: 

-

768 raise CogUsageError("No files to process") 

-

769 

-

770 def main(self, argv): 

-

771 """ Handle the command-line execution for cog. 

-

772 """ 

-

773 

-

774 try: 

-

775 self.callableMain(argv) 

-

776 return 0 

-

777 except CogUsageError as err: 

-

778 self.prerr(err) 

-

779 self.prerr("(for help use -?)") 

-

780 return 2 

-

781 except CogGeneratedError as err: 

-

782 self.prerr("Error: %s" % err) 

-

783 return 3 

-

784 except CogUserException as err: 

-

785 self.prerr("Traceback (most recent call last):") 

-

786 self.prerr(err.args[0]) 

-

787 return 4 

-

788 except CogError as err: 

-

789 self.prerr(err) 

-

790 return 1 

-

791 

+

760 def callableMain(self, argv): 

+

761 """ All of command-line cog, but in a callable form. 

+

762 This is used by main. 

+

763 argv is the equivalent of sys.argv. 

+

764 """ 

+

765 argv = argv[1:] 

+

766 

+

767 # Provide help if asked for anywhere in the command line. 

+

768 if '-?' in argv or '-h' in argv: 

+

769 self.prerr(usage, end="") 

+

770 return 

+

771 

+

772 self.options.parseArgs(argv) 

+

773 self.options.validate() 

+

774 self._fixEndOutputPatterns() 

+

775 

+

776 if self.options.bShowVersion: 

+

777 self.prout("Cog version %s" % __version__) 

+

778 return 

+

779 

+

780 if self.options.args: 

+

781 for a in self.options.args: 

+

782 self.processArguments([a]) 

+

783 else: 

+

784 raise CogUsageError("No files to process") 

+

785 

+

786 if self.bCheckFailed: 

+

787 raise CogCheckFailed("Check failed") 

+

788 

+

789 def main(self, argv): 

+

790 """ Handle the command-line execution for cog. 

+

791 """ 

792 

-

793def find_cog_source(frame_summary, prologue): 

-

794 """Find cog source lines in a frame summary list, for printing tracebacks. 

-

795 

-

796 Arguments: 

-

797 frame_summary: a list of 4-item tuples, as returned by traceback.extract_tb. 

-

798 prologue: the text of the code prologue. 

-

799 

-

800 Returns 

-

801 A list of 4-item tuples, updated to correct the cog entries. 

-

802 

-

803 """ 

-

804 prolines = prologue.splitlines() 

-

805 for filename, lineno, funcname, source in frame_summary: 

-

806 if not source: 806 ↛ 818line 806 didn't jump to line 818, because the condition on line 806 was never false

-

807 m = re.search(r"^<cog ([^:]+):(\d+)>$", filename) 

-

808 if m: 808 ↛ 809line 808 didn't jump to line 809, because the condition on line 808 was never true

-

809 if lineno <= len(prolines): 

-

810 filename = '<prologue>' 

-

811 source = prolines[lineno-1] 

-

812 lineno -= 1 # Because "import cog" is the first line in the prologue 

-

813 else: 

-

814 filename, coglineno = m.groups() 

-

815 coglineno = int(coglineno) 

-

816 lineno += coglineno - len(prolines) 

-

817 source = linecache.getline(filename, lineno).strip() 

-

818 yield filename, lineno, funcname, source 

-

819 

-

820 

-

821def main(): 

-

822 """Main function for entry_points to use.""" 

-

823 return Cog().main(sys.argv) 

+

793 try: 

+

794 self.callableMain(argv) 

+

795 return 0 

+

796 except CogUsageError as err: 

+

797 self.prerr(err) 

+

798 self.prerr("(for help use -h)") 

+

799 return 2 

+

800 except CogGeneratedError as err: 

+

801 self.prerr("Error: %s" % err) 

+

802 return 3 

+

803 except CogUserException as err: 

+

804 self.prerr("Traceback (most recent call last):") 

+

805 self.prerr(err.args[0]) 

+

806 return 4 

+

807 except CogCheckFailed as err: 

+

808 self.prerr(err) 

+

809 return 5 

+

810 except CogError as err: 

+

811 self.prerr(err) 

+

812 return 1 

+

813 

+

814 

+

815def find_cog_source(frame_summary, prologue): 

+

816 """Find cog source lines in a frame summary list, for printing tracebacks. 

+

817 

+

818 Arguments: 

+

819 frame_summary: a list of 4-item tuples, as returned by traceback.extract_tb. 

+

820 prologue: the text of the code prologue. 

+

821 

+

822 Returns 

+

823 A list of 4-item tuples, updated to correct the cog entries. 

+

824 

+

825 """ 

+

826 prolines = prologue.splitlines() 

+

827 for filename, lineno, funcname, source in frame_summary: 

+

828 if not source: 828 ↛ 840line 828 didn't jump to line 840, because the condition on line 828 was never false

+

829 m = re.search(r"^<cog ([^:]+):(\d+)>$", filename) 

+

830 if m: 830 ↛ 831line 830 didn't jump to line 831, because the condition on line 830 was never true

+

831 if lineno <= len(prolines): 

+

832 filename = '<prologue>' 

+

833 source = prolines[lineno-1] 

+

834 lineno -= 1 # Because "import cog" is the first line in the prologue 

+

835 else: 

+

836 filename, coglineno = m.groups() 

+

837 coglineno = int(coglineno) 

+

838 lineno += coglineno - len(prolines) 

+

839 source = linecache.getline(filename, lineno).strip() 

+

840 yield filename, lineno, funcname, source 

+

841 

+

842 

+

843def main(): 

+

844 """Main function for entry_points to use.""" 

+

845 return Cog().main(sys.argv) 

diff --git a/doc/sample_html/d_7b071bdc2a35fa80_makefiles_py.html b/doc/sample_html/d_7b071bdc2a35fa80_makefiles_py.html index 30d129f3..b078feb0 100644 --- a/doc/sample_html/d_7b071bdc2a35fa80_makefiles_py.html +++ b/doc/sample_html/d_7b071bdc2a35fa80_makefiles_py.html @@ -109,8 +109,8 @@ diff --git a/doc/sample_html/d_7b071bdc2a35fa80_test_cogapp_py.html b/doc/sample_html/d_7b071bdc2a35fa80_test_cogapp_py.html index cf7748b7..d0c97ef8 100644 --- a/doc/sample_html/d_7b071bdc2a35fa80_test_cogapp_py.html +++ b/doc/sample_html/d_7b071bdc2a35fa80_test_cogapp_py.html @@ -3,7 +3,7 @@ - Coverage for cogapp/test_cogapp.py: 29.94% + Coverage for cogapp/test_cogapp.py: 32.39% @@ -13,7 +13,7 @@

Coverage for cogapp/test_cogapp.py: - 29.94% + 32.39%

@@ -44,11 +44,11 @@

- 795 statements   - - - - + 849 statements   + + + +

@@ -62,7 +62,7 @@

1""" Test cogapp. 

2 http://nedbatchelder.com/code/cog 

3 

-

4 Copyright 2004-2019, Ned Batchelder. 

+

4 Copyright 2004-2021, Ned Batchelder. 

5""" 

6 

7from __future__ import absolute_import 

@@ -975,7 +975,7 @@

914 ret = main() 

915 self.assertEqual(ret, 2) 

916 stderr = sys.stderr.getvalue() 

-

917 self.assertEqual(stderr, 'option -Z not recognized\n(for help use -?)\n') 

+

917 self.assertEqual(stderr, 'option -Z not recognized\n(for help use -h)\n') 

918 

919 files = { 

920 'test.cog': """\ 

@@ -2127,454 +2127,577 @@

2066 assert results == [None] * numthreads 

2067 

2068 

-

2069class WritabilityTests(TestCaseWithTempDir): 

-

2070 

-

2071 d = { 

-

2072 'test.cog': """\ 

-

2073 //[[[cog 

-

2074 for fn in ['DoSomething', 'DoAnotherThing', 'DoLastThing']: 

-

2075 cog.outl("void %s();" % fn) 

-

2076 //]]] 

-

2077 //[[[end]]] 

-

2078 """, 

-

2079 

-

2080 'test.out': """\ 

-

2081 //[[[cog 

-

2082 for fn in ['DoSomething', 'DoAnotherThing', 'DoLastThing']: 

-

2083 cog.outl("void %s();" % fn) 

-

2084 //]]] 

-

2085 void DoSomething(); 

-

2086 void DoAnotherThing(); 

-

2087 void DoLastThing(); 

-

2088 //[[[end]]] 

-

2089 """, 

-

2090 } 

-

2091 

-

2092 if os.name == 'nt': #pragma: no cover 

-

2093 # for Windows 

-

2094 cmd_w_args = 'attrib -R %s' 

-

2095 cmd_w_asterisk = 'attrib -R *' 

-

2096 else: #pragma: no cover 

-

2097 # for unix-like 

-

2098 cmd_w_args = 'chmod +w %s' 

-

2099 cmd_w_asterisk = 'chmod +w *' 

-

2100 

-

2101 def setUp(self): 

-

2102 super(WritabilityTests, self).setUp() 

-

2103 makeFiles(self.d) 

-

2104 self.testcog = os.path.join(self.tempdir, 'test.cog') 

-

2105 os.chmod(self.testcog, stat.S_IREAD) # Make the file readonly. 

-

2106 assert not os.access(self.testcog, os.W_OK) 

+

2069class CheckTests(TestCaseWithTempDir): 

+

2070 def run_check(self, args, status=0): 

+

2071 actual_status = self.cog.main(['argv0', '--check'] + args) 

+

2072 print(self.output.getvalue()) 

+

2073 self.assertEqual(status, actual_status) 

+

2074 

+

2075 def assert_made_files_unchanged(self, d): 

+

2076 for name, content in d.items(): 

+

2077 content = reindentBlock(content) 

+

2078 if os.name == 'nt': 

+

2079 content = content.replace("\n", "\r\n") 

+

2080 self.assertFileContent(name, content) 

+

2081 

+

2082 def test_check_no_cog(self): 

+

2083 d = { 

+

2084 'hello.txt': """\ 

+

2085 Hello. 

+

2086 """, 

+

2087 } 

+

2088 makeFiles(d) 

+

2089 self.run_check(['hello.txt'], status=0) 

+

2090 self.assertEqual(self.output.getvalue(), "Checking hello.txt\n") 

+

2091 self.assert_made_files_unchanged(d) 

+

2092 

+

2093 def test_check_good(self): 

+

2094 d = { 

+

2095 'unchanged.cog': """\ 

+

2096 //[[[cog 

+

2097 cog.outl("hello world") 

+

2098 //]]] 

+

2099 hello world 

+

2100 //[[[end]]] 

+

2101 """, 

+

2102 } 

+

2103 makeFiles(d) 

+

2104 self.run_check(['unchanged.cog'], status=0) 

+

2105 self.assertEqual(self.output.getvalue(), "Checking unchanged.cog\n") 

+

2106 self.assert_made_files_unchanged(d) 

2107 

-

2108 def tearDown(self): 

-

2109 os.chmod(self.testcog, stat.S_IWRITE) # Make the file writable again. 

-

2110 super(WritabilityTests, self).tearDown() 

-

2111 

-

2112 def testReadonlyNoCommand(self): 

-

2113 with self.assertRaisesRegex(CogError, "^Can't overwrite test.cog$"): 

-

2114 self.cog.callableMain(['argv0', '-r', 'test.cog']) 

-

2115 assert not os.access(self.testcog, os.W_OK) 

-

2116 

-

2117 def testReadonlyWithCommand(self): 

-

2118 self.cog.callableMain(['argv0', '-r', '-w', self.cmd_w_args, 'test.cog']) 

-

2119 self.assertFilesSame('test.cog', 'test.out') 

-

2120 assert os.access(self.testcog, os.W_OK) 

-

2121 

-

2122 def testReadonlyWithCommandWithNoSlot(self): 

-

2123 self.cog.callableMain(['argv0', '-r', '-w', self.cmd_w_asterisk, 'test.cog']) 

-

2124 self.assertFilesSame('test.cog', 'test.out') 

-

2125 assert os.access(self.testcog, os.W_OK) 

-

2126 

-

2127 def testReadonlyWithIneffectualCommand(self): 

-

2128 with self.assertRaisesRegex(CogError, "^Couldn't make test.cog writable$"): 

-

2129 self.cog.callableMain(['argv0', '-r', '-w', 'echo %s', 'test.cog']) 

-

2130 assert not os.access(self.testcog, os.W_OK) 

-

2131 

-

2132 

-

2133class ChecksumTests(TestCaseWithTempDir): 

-

2134 

-

2135 def testCreateChecksumOutput(self): 

-

2136 d = { 

-

2137 'cog1.txt': """\ 

-

2138 //[[[cog 

-

2139 cog.outl("This line was generated.") 

-

2140 //]]] 

-

2141 This line was generated. 

-

2142 //[[[end]]] 

-

2143 This line was not. 

-

2144 """, 

-

2145 

-

2146 'cog1.out': """\ 

-

2147 //[[[cog 

-

2148 cog.outl("This line was generated.") 

-

2149 //]]] 

-

2150 This line was generated. 

-

2151 //[[[end]]] (checksum: 8adb13fb59b996a1c7f0065ea9f3d893) 

-

2152 This line was not. 

-

2153 """, 

-

2154 } 

-

2155 

-

2156 makeFiles(d) 

-

2157 self.cog.callableMain(['argv0', '-r', '-c', 'cog1.txt']) 

-

2158 self.assertFilesSame('cog1.txt', 'cog1.out') 

-

2159 

-

2160 def testCheckChecksumOutput(self): 

-

2161 d = { 

-

2162 'cog1.txt': """\ 

-

2163 //[[[cog 

-

2164 cog.outl("This line was newly") 

-

2165 cog.outl("generated by cog") 

-

2166 cog.outl("blah blah.") 

-

2167 //]]] 

-

2168 This line was generated. 

-

2169 //[[[end]]] (checksum: 8adb13fb59b996a1c7f0065ea9f3d893) 

-

2170 """, 

-

2171 

-

2172 'cog1.out': """\ 

-

2173 //[[[cog 

-

2174 cog.outl("This line was newly") 

-

2175 cog.outl("generated by cog") 

-

2176 cog.outl("blah blah.") 

-

2177 //]]] 

-

2178 This line was newly 

-

2179 generated by cog 

-

2180 blah blah. 

-

2181 //[[[end]]] (checksum: a8540982e5ad6b95c9e9a184b26f4346) 

-

2182 """, 

-

2183 } 

-

2184 

+

2108 def test_check_bad(self): 

+

2109 d = { 

+

2110 'changed.cog': """\ 

+

2111 //[[[cog 

+

2112 cog.outl("goodbye world") 

+

2113 //]]] 

+

2114 hello world 

+

2115 //[[[end]]] 

+

2116 """, 

+

2117 } 

+

2118 makeFiles(d) 

+

2119 self.run_check(['changed.cog'], status=5) 

+

2120 self.assertEqual(self.output.getvalue(), "Checking changed.cog (changed)\nCheck failed\n") 

+

2121 self.assert_made_files_unchanged(d) 

+

2122 

+

2123 def test_check_mixed(self): 

+

2124 d = { 

+

2125 'unchanged.cog': """\ 

+

2126 //[[[cog 

+

2127 cog.outl("hello world") 

+

2128 //]]] 

+

2129 hello world 

+

2130 //[[[end]]] 

+

2131 """, 

+

2132 'changed.cog': """\ 

+

2133 //[[[cog 

+

2134 cog.outl("goodbye world") 

+

2135 //]]] 

+

2136 hello world 

+

2137 //[[[end]]] 

+

2138 """, 

+

2139 } 

+

2140 makeFiles(d) 

+

2141 for verbosity, output in [ 

+

2142 ("0", "Check failed\n"), 

+

2143 ("1", "Checking changed.cog (changed)\nCheck failed\n"), 

+

2144 ("2", "Checking unchanged.cog\nChecking changed.cog (changed)\nCheck failed\n"), 

+

2145 ]: 

+

2146 self.newCog() 

+

2147 self.run_check(['--verbosity=%s' % verbosity, 'unchanged.cog', 'changed.cog'], status=5) 

+

2148 self.assertEqual(self.output.getvalue(), output) 

+

2149 self.assert_made_files_unchanged(d) 

+

2150 

+

2151 def test_check_with_good_checksum(self): 

+

2152 d = { 

+

2153 'good.txt': """\ 

+

2154 //[[[cog 

+

2155 cog.outl("This line was newly") 

+

2156 cog.outl("generated by cog") 

+

2157 cog.outl("blah blah.") 

+

2158 //]]] 

+

2159 This line was newly 

+

2160 generated by cog 

+

2161 blah blah. 

+

2162 //[[[end]]] (checksum: a8540982e5ad6b95c9e9a184b26f4346) 

+

2163 """, 

+

2164 } 

+

2165 makeFiles(d) 

+

2166 # Have to use -c with --check if there are checksums in the file. 

+

2167 self.run_check(['-c', 'good.txt'], status=0) 

+

2168 self.assertEqual(self.output.getvalue(), "Checking good.txt\n") 

+

2169 self.assert_made_files_unchanged(d) 

+

2170 

+

2171 def test_check_with_bad_checksum(self): 

+

2172 d = { 

+

2173 'bad.txt': """\ 

+

2174 //[[[cog 

+

2175 cog.outl("This line was newly") 

+

2176 cog.outl("generated by cog") 

+

2177 cog.outl("blah blah.") 

+

2178 //]]] 

+

2179 This line was newly 

+

2180 generated by cog 

+

2181 blah blah. 

+

2182 //[[[end]]] (checksum: a9999999e5ad6b95c9e9a184b26f4346) 

+

2183 """, 

+

2184 } 

2185 makeFiles(d) 

-

2186 self.cog.callableMain(['argv0', '-r', '-c', 'cog1.txt']) 

-

2187 self.assertFilesSame('cog1.txt', 'cog1.out') 

-

2188 

-

2189 def testRemoveChecksumOutput(self): 

-

2190 d = { 

-

2191 'cog1.txt': """\ 

-

2192 //[[[cog 

-

2193 cog.outl("This line was newly") 

-

2194 cog.outl("generated by cog") 

-

2195 cog.outl("blah blah.") 

-

2196 //]]] 

-

2197 This line was generated. 

-

2198 //[[[end]]] (checksum: 8adb13fb59b996a1c7f0065ea9f3d893) fooey 

-

2199 """, 

-

2200 

-

2201 'cog1.out': """\ 

-

2202 //[[[cog 

-

2203 cog.outl("This line was newly") 

-

2204 cog.outl("generated by cog") 

-

2205 cog.outl("blah blah.") 

-

2206 //]]] 

-

2207 This line was newly 

-

2208 generated by cog 

-

2209 blah blah. 

-

2210 //[[[end]]] fooey 

-

2211 """, 

-

2212 } 

-

2213 

-

2214 makeFiles(d) 

-

2215 self.cog.callableMain(['argv0', '-r', 'cog1.txt']) 

-

2216 self.assertFilesSame('cog1.txt', 'cog1.out') 

-

2217 

-

2218 def testTamperedChecksumOutput(self): 

-

2219 d = { 

-

2220 'cog1.txt': """\ 

-

2221 //[[[cog 

-

2222 cog.outl("This line was newly") 

-

2223 cog.outl("generated by cog") 

-

2224 cog.outl("blah blah.") 

-

2225 //]]] 

-

2226 Xhis line was newly 

-

2227 generated by cog 

-

2228 blah blah. 

-

2229 //[[[end]]] (checksum: a8540982e5ad6b95c9e9a184b26f4346) 

-

2230 """, 

-

2231 

-

2232 'cog2.txt': """\ 

-

2233 //[[[cog 

-

2234 cog.outl("This line was newly") 

-

2235 cog.outl("generated by cog") 

-

2236 cog.outl("blah blah.") 

-

2237 //]]] 

-

2238 This line was newly 

-

2239 generated by cog 

-

2240 blah blah! 

-

2241 //[[[end]]] (checksum: a8540982e5ad6b95c9e9a184b26f4346) 

-

2242 """, 

-

2243 

-

2244 'cog3.txt': """\ 

-

2245 //[[[cog 

-

2246 cog.outl("This line was newly") 

-

2247 cog.outl("generated by cog") 

-

2248 cog.outl("blah blah.") 

-

2249 //]]] 

-

2250 

-

2251 This line was newly 

-

2252 generated by cog 

-

2253 blah blah. 

-

2254 //[[[end]]] (checksum: a8540982e5ad6b95c9e9a184b26f4346) 

-

2255 """, 

-

2256 

-

2257 'cog4.txt': """\ 

-

2258 //[[[cog 

-

2259 cog.outl("This line was newly") 

-

2260 cog.outl("generated by cog") 

-

2261 cog.outl("blah blah.") 

-

2262 //]]] 

-

2263 This line was newly 

-

2264 generated by cog 

-

2265 blah blah.. 

-

2266 //[[[end]]] (checksum: a8540982e5ad6b95c9e9a184b26f4346) 

+

2186 # Have to use -c with --check if there are checksums in the file. 

+

2187 self.run_check(['-c', 'bad.txt'], status=1) 

+

2188 self.assertEqual(self.output.getvalue(), "Checking bad.txt\nbad.txt(9): Output has been edited! Delete old checksum to unprotect.\n") 

+

2189 self.assert_made_files_unchanged(d) 

+

2190 

+

2191 

+

2192class WritabilityTests(TestCaseWithTempDir): 

+

2193 

+

2194 d = { 

+

2195 'test.cog': """\ 

+

2196 //[[[cog 

+

2197 for fn in ['DoSomething', 'DoAnotherThing', 'DoLastThing']: 

+

2198 cog.outl("void %s();" % fn) 

+

2199 //]]] 

+

2200 //[[[end]]] 

+

2201 """, 

+

2202 

+

2203 'test.out': """\ 

+

2204 //[[[cog 

+

2205 for fn in ['DoSomething', 'DoAnotherThing', 'DoLastThing']: 

+

2206 cog.outl("void %s();" % fn) 

+

2207 //]]] 

+

2208 void DoSomething(); 

+

2209 void DoAnotherThing(); 

+

2210 void DoLastThing(); 

+

2211 //[[[end]]] 

+

2212 """, 

+

2213 } 

+

2214 

+

2215 if os.name == 'nt': 2215 ↛ 2217line 2215 didn't jump to line 2217, because the condition on line 2215 was never true

+

2216 # for Windows 

+

2217 cmd_w_args = 'attrib -R %s' 

+

2218 cmd_w_asterisk = 'attrib -R *' 

+

2219 else: 

+

2220 # for unix-like 

+

2221 cmd_w_args = 'chmod +w %s' 

+

2222 cmd_w_asterisk = 'chmod +w *' 

+

2223 

+

2224 def setUp(self): 

+

2225 super(WritabilityTests, self).setUp() 

+

2226 makeFiles(self.d) 

+

2227 self.testcog = os.path.join(self.tempdir, 'test.cog') 

+

2228 os.chmod(self.testcog, stat.S_IREAD) # Make the file readonly. 

+

2229 assert not os.access(self.testcog, os.W_OK) 

+

2230 

+

2231 def tearDown(self): 

+

2232 os.chmod(self.testcog, stat.S_IWRITE) # Make the file writable again. 

+

2233 super(WritabilityTests, self).tearDown() 

+

2234 

+

2235 def testReadonlyNoCommand(self): 

+

2236 with self.assertRaisesRegex(CogError, "^Can't overwrite test.cog$"): 

+

2237 self.cog.callableMain(['argv0', '-r', 'test.cog']) 

+

2238 assert not os.access(self.testcog, os.W_OK) 

+

2239 

+

2240 def testReadonlyWithCommand(self): 

+

2241 self.cog.callableMain(['argv0', '-r', '-w', self.cmd_w_args, 'test.cog']) 

+

2242 self.assertFilesSame('test.cog', 'test.out') 

+

2243 assert os.access(self.testcog, os.W_OK) 

+

2244 

+

2245 def testReadonlyWithCommandWithNoSlot(self): 

+

2246 self.cog.callableMain(['argv0', '-r', '-w', self.cmd_w_asterisk, 'test.cog']) 

+

2247 self.assertFilesSame('test.cog', 'test.out') 

+

2248 assert os.access(self.testcog, os.W_OK) 

+

2249 

+

2250 def testReadonlyWithIneffectualCommand(self): 

+

2251 with self.assertRaisesRegex(CogError, "^Couldn't make test.cog writable$"): 

+

2252 self.cog.callableMain(['argv0', '-r', '-w', 'echo %s', 'test.cog']) 

+

2253 assert not os.access(self.testcog, os.W_OK) 

+

2254 

+

2255 

+

2256class ChecksumTests(TestCaseWithTempDir): 

+

2257 

+

2258 def testCreateChecksumOutput(self): 

+

2259 d = { 

+

2260 'cog1.txt': """\ 

+

2261 //[[[cog 

+

2262 cog.outl("This line was generated.") 

+

2263 //]]] 

+

2264 This line was generated. 

+

2265 //[[[end]]] 

+

2266 This line was not. 

2267 """, 

2268 

-

2269 'cog5.txt': """\ 

+

2269 'cog1.out': """\ 

2270 //[[[cog 

-

2271 cog.outl("This line was newly") 

-

2272 cog.outl("generated by cog") 

-

2273 cog.outl("blah blah.") 

-

2274 //]]] 

-

2275 This line was newly 

-

2276 generated by cog 

-

2277 blah blah. 

-

2278 extra 

-

2279 //[[[end]]] (checksum: a8540982e5ad6b95c9e9a184b26f4346) 

-

2280 """, 

-

2281 

-

2282 'cog6.txt': """\ 

-

2283 //[[[cog 

-

2284 cog.outl("This line was newly") 

-

2285 cog.outl("generated by cog") 

-

2286 cog.outl("blah blah.") 

-

2287 //]]] 

-

2288 //[[[end]]] (checksum: a8540982e5ad6b95c9e9a184b26f4346) 

-

2289 """, 

-

2290 } 

-

2291 

-

2292 makeFiles(d) 

-

2293 with self.assertRaisesRegex(CogError, 

-

2294 r"^cog1.txt\(9\): Output has been edited! Delete old checksum to unprotect.$"): 

-

2295 self.cog.callableMain(['argv0', '-c', "cog1.txt"]) 

-

2296 with self.assertRaisesRegex(CogError, 

-

2297 r"^cog2.txt\(9\): Output has been edited! Delete old checksum to unprotect.$"): 

-

2298 self.cog.callableMain(['argv0', '-c', "cog2.txt"]) 

-

2299 with self.assertRaisesRegex(CogError, 

-

2300 r"^cog3.txt\(10\): Output has been edited! Delete old checksum to unprotect.$"): 

-

2301 self.cog.callableMain(['argv0', '-c', "cog3.txt"]) 

-

2302 with self.assertRaisesRegex(CogError, 

-

2303 r"^cog4.txt\(9\): Output has been edited! Delete old checksum to unprotect.$"): 

-

2304 self.cog.callableMain(['argv0', '-c', "cog4.txt"]) 

-

2305 with self.assertRaisesRegex(CogError, 

-

2306 r"^cog5.txt\(10\): Output has been edited! Delete old checksum to unprotect.$"): 

-

2307 self.cog.callableMain(['argv0', '-c', "cog5.txt"]) 

-

2308 with self.assertRaisesRegex(CogError, 

-

2309 r"^cog6.txt\(6\): Output has been edited! Delete old checksum to unprotect.$"): 

-

2310 self.cog.callableMain(['argv0', '-c', "cog6.txt"]) 

+

2271 cog.outl("This line was generated.") 

+

2272 //]]] 

+

2273 This line was generated. 

+

2274 //[[[end]]] (checksum: 8adb13fb59b996a1c7f0065ea9f3d893) 

+

2275 This line was not. 

+

2276 """, 

+

2277 } 

+

2278 

+

2279 makeFiles(d) 

+

2280 self.cog.callableMain(['argv0', '-r', '-c', 'cog1.txt']) 

+

2281 self.assertFilesSame('cog1.txt', 'cog1.out') 

+

2282 

+

2283 def testCheckChecksumOutput(self): 

+

2284 d = { 

+

2285 'cog1.txt': """\ 

+

2286 //[[[cog 

+

2287 cog.outl("This line was newly") 

+

2288 cog.outl("generated by cog") 

+

2289 cog.outl("blah blah.") 

+

2290 //]]] 

+

2291 This line was generated. 

+

2292 //[[[end]]] (checksum: 8adb13fb59b996a1c7f0065ea9f3d893) 

+

2293 """, 

+

2294 

+

2295 'cog1.out': """\ 

+

2296 //[[[cog 

+

2297 cog.outl("This line was newly") 

+

2298 cog.outl("generated by cog") 

+

2299 cog.outl("blah blah.") 

+

2300 //]]] 

+

2301 This line was newly 

+

2302 generated by cog 

+

2303 blah blah. 

+

2304 //[[[end]]] (checksum: a8540982e5ad6b95c9e9a184b26f4346) 

+

2305 """, 

+

2306 } 

+

2307 

+

2308 makeFiles(d) 

+

2309 self.cog.callableMain(['argv0', '-r', '-c', 'cog1.txt']) 

+

2310 self.assertFilesSame('cog1.txt', 'cog1.out') 

2311 

-

2312 def testArgvIsntModified(self): 

-

2313 argv = ['argv0', '-v'] 

-

2314 orig_argv = argv[:] 

-

2315 self.cog.callableMain(argv) 

-

2316 self.assertEqual(argv, orig_argv) 

-

2317 

-

2318 

-

2319class CustomMarkerTests(TestCaseWithTempDir): 

-

2320 

-

2321 def testCustomerMarkers(self): 

-

2322 d = { 

-

2323 'test.cog': """\ 

-

2324 //{{ 

-

2325 cog.outl("void %s();" % "MyFunction") 

-

2326 //}} 

-

2327 //{{end}} 

-

2328 """, 

-

2329 

-

2330 'test.out': """\ 

-

2331 //{{ 

-

2332 cog.outl("void %s();" % "MyFunction") 

-

2333 //}} 

-

2334 void MyFunction(); 

-

2335 //{{end}} 

-

2336 """, 

-

2337 } 

-

2338 

-

2339 makeFiles(d) 

-

2340 self.cog.callableMain([ 

-

2341 'argv0', '-r', 

-

2342 '--markers={{ }} {{end}}', 

-

2343 'test.cog' 

-

2344 ]) 

-

2345 self.assertFilesSame('test.cog', 'test.out') 

-

2346 

-

2347 def testTrulyWackyMarkers(self): 

-

2348 # Make sure the markers are properly re-escaped. 

-

2349 d = { 

-

2350 'test.cog': """\ 

-

2351 //**( 

-

2352 cog.outl("void %s();" % "MyFunction") 

-

2353 //**) 

-

2354 //**(end)** 

-

2355 """, 

-

2356 

-

2357 'test.out': """\ 

-

2358 //**( 

-

2359 cog.outl("void %s();" % "MyFunction") 

-

2360 //**) 

-

2361 void MyFunction(); 

-

2362 //**(end)** 

-

2363 """, 

-

2364 } 

-

2365 

-

2366 makeFiles(d) 

-

2367 self.cog.callableMain([ 

-

2368 'argv0', '-r', 

-

2369 '--markers=**( **) **(end)**', 

-

2370 'test.cog' 

-

2371 ]) 

-

2372 self.assertFilesSame('test.cog', 'test.out') 

+

2312 def testRemoveChecksumOutput(self): 

+

2313 d = { 

+

2314 'cog1.txt': """\ 

+

2315 //[[[cog 

+

2316 cog.outl("This line was newly") 

+

2317 cog.outl("generated by cog") 

+

2318 cog.outl("blah blah.") 

+

2319 //]]] 

+

2320 This line was generated. 

+

2321 //[[[end]]] (checksum: 8adb13fb59b996a1c7f0065ea9f3d893) fooey 

+

2322 """, 

+

2323 

+

2324 'cog1.out': """\ 

+

2325 //[[[cog 

+

2326 cog.outl("This line was newly") 

+

2327 cog.outl("generated by cog") 

+

2328 cog.outl("blah blah.") 

+

2329 //]]] 

+

2330 This line was newly 

+

2331 generated by cog 

+

2332 blah blah. 

+

2333 //[[[end]]] fooey 

+

2334 """, 

+

2335 } 

+

2336 

+

2337 makeFiles(d) 

+

2338 self.cog.callableMain(['argv0', '-r', 'cog1.txt']) 

+

2339 self.assertFilesSame('cog1.txt', 'cog1.out') 

+

2340 

+

2341 def testTamperedChecksumOutput(self): 

+

2342 d = { 

+

2343 'cog1.txt': """\ 

+

2344 //[[[cog 

+

2345 cog.outl("This line was newly") 

+

2346 cog.outl("generated by cog") 

+

2347 cog.outl("blah blah.") 

+

2348 //]]] 

+

2349 Xhis line was newly 

+

2350 generated by cog 

+

2351 blah blah. 

+

2352 //[[[end]]] (checksum: a8540982e5ad6b95c9e9a184b26f4346) 

+

2353 """, 

+

2354 

+

2355 'cog2.txt': """\ 

+

2356 //[[[cog 

+

2357 cog.outl("This line was newly") 

+

2358 cog.outl("generated by cog") 

+

2359 cog.outl("blah blah.") 

+

2360 //]]] 

+

2361 This line was newly 

+

2362 generated by cog 

+

2363 blah blah! 

+

2364 //[[[end]]] (checksum: a8540982e5ad6b95c9e9a184b26f4346) 

+

2365 """, 

+

2366 

+

2367 'cog3.txt': """\ 

+

2368 //[[[cog 

+

2369 cog.outl("This line was newly") 

+

2370 cog.outl("generated by cog") 

+

2371 cog.outl("blah blah.") 

+

2372 //]]] 

2373 

-

2374 def testChangeJustOneMarker(self): 

-

2375 d = { 

-

2376 'test.cog': """\ 

-

2377 //**( 

-

2378 cog.outl("void %s();" % "MyFunction") 

-

2379 //]]] 

-

2380 //[[[end]]] 

-

2381 """, 

-

2382 

-

2383 'test.out': """\ 

-

2384 //**( 

-

2385 cog.outl("void %s();" % "MyFunction") 

-

2386 //]]] 

-

2387 void MyFunction(); 

-

2388 //[[[end]]] 

-

2389 """, 

-

2390 } 

+

2374 This line was newly 

+

2375 generated by cog 

+

2376 blah blah. 

+

2377 //[[[end]]] (checksum: a8540982e5ad6b95c9e9a184b26f4346) 

+

2378 """, 

+

2379 

+

2380 'cog4.txt': """\ 

+

2381 //[[[cog 

+

2382 cog.outl("This line was newly") 

+

2383 cog.outl("generated by cog") 

+

2384 cog.outl("blah blah.") 

+

2385 //]]] 

+

2386 This line was newly 

+

2387 generated by cog 

+

2388 blah blah.. 

+

2389 //[[[end]]] (checksum: a8540982e5ad6b95c9e9a184b26f4346) 

+

2390 """, 

2391 

-

2392 makeFiles(d) 

-

2393 self.cog.callableMain([ 

-

2394 'argv0', '-r', 

-

2395 '--markers=**( ]]] [[[end]]]', 

-

2396 'test.cog' 

-

2397 ]) 

-

2398 self.assertFilesSame('test.cog', 'test.out') 

-

2399 

-

2400 

-

2401class BlakeTests(TestCaseWithTempDir): 

-

2402 

-

2403 # Blake Winton's contributions. 

-

2404 def testDeleteCode(self): 

-

2405 # -o sets the output file. 

-

2406 d = { 

-

2407 'test.cog': """\ 

-

2408 // This is my C++ file. 

-

2409 //[[[cog 

-

2410 fnames = ['DoSomething', 'DoAnotherThing', 'DoLastThing'] 

-

2411 for fn in fnames: 

-

2412 cog.outl("void %s();" % fn) 

-

2413 //]]] 

-

2414 Some Sample Code Here 

-

2415 //[[[end]]]Data Data 

-

2416 And Some More 

-

2417 """, 

-

2418 

-

2419 'test.out': """\ 

-

2420 // This is my C++ file. 

-

2421 void DoSomething(); 

-

2422 void DoAnotherThing(); 

-

2423 void DoLastThing(); 

-

2424 And Some More 

-

2425 """, 

-

2426 } 

-

2427 

-

2428 makeFiles(d) 

-

2429 self.cog.callableMain(['argv0', '-d', '-o', 'test.cogged', 'test.cog']) 

-

2430 self.assertFilesSame('test.cogged', 'test.out') 

-

2431 

-

2432 def testDeleteCodeWithDashRFails(self): 

-

2433 d = { 

-

2434 'test.cog': """\ 

-

2435 // This is my C++ file. 

-

2436 """ 

-

2437 } 

-

2438 

-

2439 makeFiles(d) 

-

2440 with self.assertRaisesRegex(CogUsageError, r"^Can't use -d with -r \(or you would delete all your source!\)$"): 

-

2441 self.cog.callableMain(['argv0', '-r', '-d', 'test.cog']) 

-

2442 

-

2443 def testSettingGlobals(self): 

-

2444 # Blake Winton contributed a way to set the globals that will be used in 

-

2445 # processFile(). 

-

2446 d = { 

-

2447 'test.cog': """\ 

-

2448 // This is my C++ file. 

-

2449 //[[[cog 

-

2450 for fn in fnames: 

-

2451 cog.outl("void %s();" % fn) 

-

2452 //]]] 

-

2453 Some Sample Code Here 

-

2454 //[[[end]]]""", 

-

2455 

-

2456 'test.out': """\ 

-

2457 // This is my C++ file. 

-

2458 void DoBlake(); 

-

2459 void DoWinton(); 

-

2460 void DoContribution(); 

-

2461 """, 

-

2462 } 

-

2463 

-

2464 makeFiles(d) 

-

2465 globals = {} 

-

2466 globals['fnames'] = ['DoBlake', 'DoWinton', 'DoContribution'] 

-

2467 self.cog.options.bDeleteCode = True 

-

2468 self.cog.processFile('test.cog', 'test.cogged', globals=globals) 

-

2469 self.assertFilesSame('test.cogged', 'test.out') 

-

2470 

-

2471 

-

2472class ErrorCallTests(TestCaseWithTempDir): 

-

2473 

-

2474 def testErrorCallHasNoTraceback(self): 

-

2475 # Test that cog.error() doesn't show a traceback. 

-

2476 d = { 

-

2477 'error.cog': """\ 

-

2478 //[[[cog 

-

2479 cog.error("Something Bad!") 

-

2480 //]]] 

-

2481 //[[[end]]] 

-

2482 """, 

-

2483 } 

-

2484 

-

2485 makeFiles(d) 

-

2486 self.cog.main(['argv0', '-r', 'error.cog']) 

-

2487 output = self.output.getvalue() 

-

2488 self.assertEqual(output, "Cogging error.cog\nError: Something Bad!\n") 

-

2489 

-

2490 def testRealErrorHasTraceback(self): 

-

2491 # Test that a genuine error does show a traceback. 

-

2492 d = { 

-

2493 'error.cog': """\ 

-

2494 //[[[cog 

-

2495 raise RuntimeError("Hey!") 

-

2496 //]]] 

-

2497 //[[[end]]] 

-

2498 """, 

-

2499 } 

-

2500 

-

2501 makeFiles(d) 

-

2502 self.cog.main(['argv0', '-r', 'error.cog']) 

-

2503 output = self.output.getvalue() 

-

2504 msg = 'Actual output:\n' + output 

-

2505 self.assertTrue(output.startswith("Cogging error.cog\nTraceback (most recent"), msg) 

-

2506 self.assertIn("RuntimeError: Hey!", output) 

-

2507 

-

2508 

-

2509# Things not yet tested: 

-

2510# - A bad -w command (currently fails silently). 

+

2392 'cog5.txt': """\ 

+

2393 //[[[cog 

+

2394 cog.outl("This line was newly") 

+

2395 cog.outl("generated by cog") 

+

2396 cog.outl("blah blah.") 

+

2397 //]]] 

+

2398 This line was newly 

+

2399 generated by cog 

+

2400 blah blah. 

+

2401 extra 

+

2402 //[[[end]]] (checksum: a8540982e5ad6b95c9e9a184b26f4346) 

+

2403 """, 

+

2404 

+

2405 'cog6.txt': """\ 

+

2406 //[[[cog 

+

2407 cog.outl("This line was newly") 

+

2408 cog.outl("generated by cog") 

+

2409 cog.outl("blah blah.") 

+

2410 //]]] 

+

2411 //[[[end]]] (checksum: a8540982e5ad6b95c9e9a184b26f4346) 

+

2412 """, 

+

2413 } 

+

2414 

+

2415 makeFiles(d) 

+

2416 with self.assertRaisesRegex(CogError, 

+

2417 r"^cog1.txt\(9\): Output has been edited! Delete old checksum to unprotect.$"): 

+

2418 self.cog.callableMain(['argv0', '-c', "cog1.txt"]) 

+

2419 with self.assertRaisesRegex(CogError, 

+

2420 r"^cog2.txt\(9\): Output has been edited! Delete old checksum to unprotect.$"): 

+

2421 self.cog.callableMain(['argv0', '-c', "cog2.txt"]) 

+

2422 with self.assertRaisesRegex(CogError, 

+

2423 r"^cog3.txt\(10\): Output has been edited! Delete old checksum to unprotect.$"): 

+

2424 self.cog.callableMain(['argv0', '-c', "cog3.txt"]) 

+

2425 with self.assertRaisesRegex(CogError, 

+

2426 r"^cog4.txt\(9\): Output has been edited! Delete old checksum to unprotect.$"): 

+

2427 self.cog.callableMain(['argv0', '-c', "cog4.txt"]) 

+

2428 with self.assertRaisesRegex(CogError, 

+

2429 r"^cog5.txt\(10\): Output has been edited! Delete old checksum to unprotect.$"): 

+

2430 self.cog.callableMain(['argv0', '-c', "cog5.txt"]) 

+

2431 with self.assertRaisesRegex(CogError, 

+

2432 r"^cog6.txt\(6\): Output has been edited! Delete old checksum to unprotect.$"): 

+

2433 self.cog.callableMain(['argv0', '-c', "cog6.txt"]) 

+

2434 

+

2435 def testArgvIsntModified(self): 

+

2436 argv = ['argv0', '-v'] 

+

2437 orig_argv = argv[:] 

+

2438 self.cog.callableMain(argv) 

+

2439 self.assertEqual(argv, orig_argv) 

+

2440 

+

2441 

+

2442class CustomMarkerTests(TestCaseWithTempDir): 

+

2443 

+

2444 def testCustomerMarkers(self): 

+

2445 d = { 

+

2446 'test.cog': """\ 

+

2447 //{{ 

+

2448 cog.outl("void %s();" % "MyFunction") 

+

2449 //}} 

+

2450 //{{end}} 

+

2451 """, 

+

2452 

+

2453 'test.out': """\ 

+

2454 //{{ 

+

2455 cog.outl("void %s();" % "MyFunction") 

+

2456 //}} 

+

2457 void MyFunction(); 

+

2458 //{{end}} 

+

2459 """, 

+

2460 } 

+

2461 

+

2462 makeFiles(d) 

+

2463 self.cog.callableMain([ 

+

2464 'argv0', '-r', 

+

2465 '--markers={{ }} {{end}}', 

+

2466 'test.cog' 

+

2467 ]) 

+

2468 self.assertFilesSame('test.cog', 'test.out') 

+

2469 

+

2470 def testTrulyWackyMarkers(self): 

+

2471 # Make sure the markers are properly re-escaped. 

+

2472 d = { 

+

2473 'test.cog': """\ 

+

2474 //**( 

+

2475 cog.outl("void %s();" % "MyFunction") 

+

2476 //**) 

+

2477 //**(end)** 

+

2478 """, 

+

2479 

+

2480 'test.out': """\ 

+

2481 //**( 

+

2482 cog.outl("void %s();" % "MyFunction") 

+

2483 //**) 

+

2484 void MyFunction(); 

+

2485 //**(end)** 

+

2486 """, 

+

2487 } 

+

2488 

+

2489 makeFiles(d) 

+

2490 self.cog.callableMain([ 

+

2491 'argv0', '-r', 

+

2492 '--markers=**( **) **(end)**', 

+

2493 'test.cog' 

+

2494 ]) 

+

2495 self.assertFilesSame('test.cog', 'test.out') 

+

2496 

+

2497 def testChangeJustOneMarker(self): 

+

2498 d = { 

+

2499 'test.cog': """\ 

+

2500 //**( 

+

2501 cog.outl("void %s();" % "MyFunction") 

+

2502 //]]] 

+

2503 //[[[end]]] 

+

2504 """, 

+

2505 

+

2506 'test.out': """\ 

+

2507 //**( 

+

2508 cog.outl("void %s();" % "MyFunction") 

+

2509 //]]] 

+

2510 void MyFunction(); 

+

2511 //[[[end]]] 

+

2512 """, 

+

2513 } 

+

2514 

+

2515 makeFiles(d) 

+

2516 self.cog.callableMain([ 

+

2517 'argv0', '-r', 

+

2518 '--markers=**( ]]] [[[end]]]', 

+

2519 'test.cog' 

+

2520 ]) 

+

2521 self.assertFilesSame('test.cog', 'test.out') 

+

2522 

+

2523 

+

2524class BlakeTests(TestCaseWithTempDir): 

+

2525 

+

2526 # Blake Winton's contributions. 

+

2527 def testDeleteCode(self): 

+

2528 # -o sets the output file. 

+

2529 d = { 

+

2530 'test.cog': """\ 

+

2531 // This is my C++ file. 

+

2532 //[[[cog 

+

2533 fnames = ['DoSomething', 'DoAnotherThing', 'DoLastThing'] 

+

2534 for fn in fnames: 

+

2535 cog.outl("void %s();" % fn) 

+

2536 //]]] 

+

2537 Some Sample Code Here 

+

2538 //[[[end]]]Data Data 

+

2539 And Some More 

+

2540 """, 

+

2541 

+

2542 'test.out': """\ 

+

2543 // This is my C++ file. 

+

2544 void DoSomething(); 

+

2545 void DoAnotherThing(); 

+

2546 void DoLastThing(); 

+

2547 And Some More 

+

2548 """, 

+

2549 } 

+

2550 

+

2551 makeFiles(d) 

+

2552 self.cog.callableMain(['argv0', '-d', '-o', 'test.cogged', 'test.cog']) 

+

2553 self.assertFilesSame('test.cogged', 'test.out') 

+

2554 

+

2555 def testDeleteCodeWithDashRFails(self): 

+

2556 d = { 

+

2557 'test.cog': """\ 

+

2558 // This is my C++ file. 

+

2559 """ 

+

2560 } 

+

2561 

+

2562 makeFiles(d) 

+

2563 with self.assertRaisesRegex(CogUsageError, r"^Can't use -d with -r \(or you would delete all your source!\)$"): 

+

2564 self.cog.callableMain(['argv0', '-r', '-d', 'test.cog']) 

+

2565 

+

2566 def testSettingGlobals(self): 

+

2567 # Blake Winton contributed a way to set the globals that will be used in 

+

2568 # processFile(). 

+

2569 d = { 

+

2570 'test.cog': """\ 

+

2571 // This is my C++ file. 

+

2572 //[[[cog 

+

2573 for fn in fnames: 

+

2574 cog.outl("void %s();" % fn) 

+

2575 //]]] 

+

2576 Some Sample Code Here 

+

2577 //[[[end]]]""", 

+

2578 

+

2579 'test.out': """\ 

+

2580 // This is my C++ file. 

+

2581 void DoBlake(); 

+

2582 void DoWinton(); 

+

2583 void DoContribution(); 

+

2584 """, 

+

2585 } 

+

2586 

+

2587 makeFiles(d) 

+

2588 globals = {} 

+

2589 globals['fnames'] = ['DoBlake', 'DoWinton', 'DoContribution'] 

+

2590 self.cog.options.bDeleteCode = True 

+

2591 self.cog.processFile('test.cog', 'test.cogged', globals=globals) 

+

2592 self.assertFilesSame('test.cogged', 'test.out') 

+

2593 

+

2594 

+

2595class ErrorCallTests(TestCaseWithTempDir): 

+

2596 

+

2597 def testErrorCallHasNoTraceback(self): 

+

2598 # Test that cog.error() doesn't show a traceback. 

+

2599 d = { 

+

2600 'error.cog': """\ 

+

2601 //[[[cog 

+

2602 cog.error("Something Bad!") 

+

2603 //]]] 

+

2604 //[[[end]]] 

+

2605 """, 

+

2606 } 

+

2607 

+

2608 makeFiles(d) 

+

2609 self.cog.main(['argv0', '-r', 'error.cog']) 

+

2610 output = self.output.getvalue() 

+

2611 self.assertEqual(output, "Cogging error.cog\nError: Something Bad!\n") 

+

2612 

+

2613 def testRealErrorHasTraceback(self): 

+

2614 # Test that a genuine error does show a traceback. 

+

2615 d = { 

+

2616 'error.cog': """\ 

+

2617 //[[[cog 

+

2618 raise RuntimeError("Hey!") 

+

2619 //]]] 

+

2620 //[[[end]]] 

+

2621 """, 

+

2622 } 

+

2623 

+

2624 makeFiles(d) 

+

2625 self.cog.main(['argv0', '-r', 'error.cog']) 

+

2626 output = self.output.getvalue() 

+

2627 msg = 'Actual output:\n' + output 

+

2628 self.assertTrue(output.startswith("Cogging error.cog\nTraceback (most recent"), msg) 

+

2629 self.assertIn("RuntimeError: Hey!", output) 

+

2630 

+

2631 

+

2632# Things not yet tested: 

+

2633# - A bad -w command (currently fails silently). 

diff --git a/doc/sample_html/d_7b071bdc2a35fa80_test_makefiles_py.html b/doc/sample_html/d_7b071bdc2a35fa80_test_makefiles_py.html index 2e440600..e45693f1 100644 --- a/doc/sample_html/d_7b071bdc2a35fa80_test_makefiles_py.html +++ b/doc/sample_html/d_7b071bdc2a35fa80_test_makefiles_py.html @@ -3,7 +3,7 @@ - Coverage for cogapp/test_makefiles.py: 23.38% + Coverage for cogapp/test_makefiles.py: 25.32% @@ -13,7 +13,7 @@

Coverage for cogapp/test_makefiles.py: - 23.38% + 25.32%

@@ -185,8 +185,8 @@ diff --git a/doc/sample_html/d_7b071bdc2a35fa80_test_whiteutils_py.html b/doc/sample_html/d_7b071bdc2a35fa80_test_whiteutils_py.html index 382d4328..e539b437 100644 --- a/doc/sample_html/d_7b071bdc2a35fa80_test_whiteutils_py.html +++ b/doc/sample_html/d_7b071bdc2a35fa80_test_whiteutils_py.html @@ -3,7 +3,7 @@ - Coverage for cogapp/test_whiteutils.py: 27.54% + Coverage for cogapp/test_whiteutils.py: 33.33% @@ -13,7 +13,7 @@

Coverage for cogapp/test_whiteutils.py: - 27.54% + 33.33%

@@ -164,8 +164,8 @@ diff --git a/doc/sample_html/d_7b071bdc2a35fa80_whiteutils_py.html b/doc/sample_html/d_7b071bdc2a35fa80_whiteutils_py.html index 187d03fa..cca6ab3d 100644 --- a/doc/sample_html/d_7b071bdc2a35fa80_whiteutils_py.html +++ b/doc/sample_html/d_7b071bdc2a35fa80_whiteutils_py.html @@ -136,8 +136,8 @@ diff --git a/doc/sample_html/index.html b/doc/sample_html/index.html index 38db8906..56059e41 100644 --- a/doc/sample_html/index.html +++ b/doc/sample_html/index.html @@ -2,7 +2,7 @@ - Coverage report + Cog coverage @@ -10,8 +10,8 @@
-

Coverage report: - 40.00% +

Cog coverage: + 41.39%

@@ -75,18 +75,18 @@ 22 6 0 - 4 + 6 2 - 69.23% + 71.43% cogapp/cogapp.py - 495 - 219 + 510 + 230 1 - 208 + 240 30 - 49.50% + 50.13% cogapp/makefiles.py @@ -99,30 +99,30 @@ cogapp/test_cogapp.py - 795 - 553 - 8 - 20 - 0 - 29.94% + 849 + 595 + 2 + 68 + 1 + 32.39% cogapp/test_makefiles.py 71 53 0 - 6 + 8 0 - 23.38% + 25.32% cogapp/test_whiteutils.py 69 50 0 + 6 0 - 0 - 27.54% + 33.33% cogapp/whiteutils.py @@ -137,12 +137,12 @@ Total - 1529 - 909 - 9 - 286 - 36 - 40.00% + 1598 + 962 + 3 + 376 + 37 + 41.39% @@ -153,8 +153,8 @@ diff --git a/doc/sample_html/status.json b/doc/sample_html/status.json index 1e4e99a5..1d66eeef 100644 --- a/doc/sample_html/status.json +++ b/doc/sample_html/status.json @@ -1 +1 @@ -{"format":2,"version":"6.1.2","globals":"39f446cd732e316017c8c9fa061ccf97","files":{"d_7b071bdc2a35fa80___init___py":{"hash":"1fc4f9498f460d6c93280e8962ee0c0f","index":{"nums":[2,1,2,0,0,0,0,0],"html_filename":"d_7b071bdc2a35fa80___init___py.html","relative_filename":"cogapp/__init__.py"}},"d_7b071bdc2a35fa80___main___py":{"hash":"ffe6befa655d4d0b0b31eb0c73811311","index":{"nums":[2,1,3,0,3,0,0,0],"html_filename":"d_7b071bdc2a35fa80___main___py.html","relative_filename":"cogapp/__main__.py"}},"d_7b071bdc2a35fa80_backward_py":{"hash":"32afb71b2a11dd4b8ca4ed66b6815d42","index":{"nums":[2,1,22,0,6,4,2,2],"html_filename":"d_7b071bdc2a35fa80_backward_py.html","relative_filename":"cogapp/backward.py"}},"d_7b071bdc2a35fa80_cogapp_py":{"hash":"436496c809378ac1ec6dffa35b3ce048","index":{"nums":[2,1,495,1,219,208,30,136],"html_filename":"d_7b071bdc2a35fa80_cogapp_py.html","relative_filename":"cogapp/cogapp.py"}},"d_7b071bdc2a35fa80_makefiles_py":{"hash":"85ec1064ff86d94238a8d7b76a2178a5","index":{"nums":[2,1,27,0,20,14,0,14],"html_filename":"d_7b071bdc2a35fa80_makefiles_py.html","relative_filename":"cogapp/makefiles.py"}},"d_7b071bdc2a35fa80_test_cogapp_py":{"hash":"0734976cc61e29b326701651bb685257","index":{"nums":[2,1,795,8,553,20,0,18],"html_filename":"d_7b071bdc2a35fa80_test_cogapp_py.html","relative_filename":"cogapp/test_cogapp.py"}},"d_7b071bdc2a35fa80_test_makefiles_py":{"hash":"647f7dc911c97a6e646a91c3300a25ff","index":{"nums":[2,1,71,0,53,6,0,6],"html_filename":"d_7b071bdc2a35fa80_test_makefiles_py.html","relative_filename":"cogapp/test_makefiles.py"}},"d_7b071bdc2a35fa80_test_whiteutils_py":{"hash":"9476b26e42e6169b1857cfe7f29bf954","index":{"nums":[2,1,69,0,50,0,0,0],"html_filename":"d_7b071bdc2a35fa80_test_whiteutils_py.html","relative_filename":"cogapp/test_whiteutils.py"}},"d_7b071bdc2a35fa80_whiteutils_py":{"hash":"cf00c3e6149e4b80a2d01b6919c066a4","index":{"nums":[2,1,45,0,5,34,4,4],"html_filename":"d_7b071bdc2a35fa80_whiteutils_py.html","relative_filename":"cogapp/whiteutils.py"}}}} \ No newline at end of file +{"format":2,"version":"6.2","globals":"52cb72f3924a33d71af8091d7ac2a5fb","files":{"d_7b071bdc2a35fa80___init___py":{"hash":"1fc4f9498f460d6c93280e8962ee0c0f","index":{"nums":[2,1,2,0,0,0,0,0],"html_filename":"d_7b071bdc2a35fa80___init___py.html","relative_filename":"cogapp/__init__.py"}},"d_7b071bdc2a35fa80___main___py":{"hash":"ffe6befa655d4d0b0b31eb0c73811311","index":{"nums":[2,1,3,0,3,0,0,0],"html_filename":"d_7b071bdc2a35fa80___main___py.html","relative_filename":"cogapp/__main__.py"}},"d_7b071bdc2a35fa80_backward_py":{"hash":"32afb71b2a11dd4b8ca4ed66b6815d42","index":{"nums":[2,1,22,0,6,6,2,2],"html_filename":"d_7b071bdc2a35fa80_backward_py.html","relative_filename":"cogapp/backward.py"}},"d_7b071bdc2a35fa80_cogapp_py":{"hash":"c5b18ac239f8f04191337a10704f8e08","index":{"nums":[2,1,510,1,230,240,30,144],"html_filename":"d_7b071bdc2a35fa80_cogapp_py.html","relative_filename":"cogapp/cogapp.py"}},"d_7b071bdc2a35fa80_makefiles_py":{"hash":"85ec1064ff86d94238a8d7b76a2178a5","index":{"nums":[2,1,27,0,20,14,0,14],"html_filename":"d_7b071bdc2a35fa80_makefiles_py.html","relative_filename":"cogapp/makefiles.py"}},"d_7b071bdc2a35fa80_test_cogapp_py":{"hash":"82b220d267ede50852b661433613c61b","index":{"nums":[2,1,849,2,595,68,1,25],"html_filename":"d_7b071bdc2a35fa80_test_cogapp_py.html","relative_filename":"cogapp/test_cogapp.py"}},"d_7b071bdc2a35fa80_test_makefiles_py":{"hash":"647f7dc911c97a6e646a91c3300a25ff","index":{"nums":[2,1,71,0,53,8,0,6],"html_filename":"d_7b071bdc2a35fa80_test_makefiles_py.html","relative_filename":"cogapp/test_makefiles.py"}},"d_7b071bdc2a35fa80_test_whiteutils_py":{"hash":"9476b26e42e6169b1857cfe7f29bf954","index":{"nums":[2,1,69,0,50,6,0,0],"html_filename":"d_7b071bdc2a35fa80_test_whiteutils_py.html","relative_filename":"cogapp/test_whiteutils.py"}},"d_7b071bdc2a35fa80_whiteutils_py":{"hash":"cf00c3e6149e4b80a2d01b6919c066a4","index":{"nums":[2,1,45,0,5,34,4,4],"html_filename":"d_7b071bdc2a35fa80_whiteutils_py.html","relative_filename":"cogapp/whiteutils.py"}}}} \ No newline at end of file -- cgit v1.2.1