From 2a711f250fd2e32e488b771e7dbca7aef0e53600 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Fri, 23 Sep 2011 08:23:58 -0400 Subject: Latest sample output. --- doc/sample_html/cogapp_cogapp.html | 3002 ++++++++++++++++++------------------ 1 file changed, 1501 insertions(+), 1501 deletions(-) (limited to 'doc/sample_html/cogapp_cogapp.html') diff --git a/doc/sample_html/cogapp_cogapp.html b/doc/sample_html/cogapp_cogapp.html index 7812c5b0..e80b413a 100644 --- a/doc/sample_html/cogapp_cogapp.html +++ b/doc/sample_html/cogapp_cogapp.html @@ -1,1501 +1,1501 @@ - - - - - - - - Coverage for cogapp\cogapp: 51% - - - - - - - - - - - -
- -

Hot-keys on this page

-
-

- r - m - x - p   toggle line displays -

-

- j - k   next/prev highlighted chunk -

-

- 0   (zero) top of page -

-

- 1   (one) first highlighted chunk -

-
-
- -
- - - - - -
-

1

-

2

-

3

-

4

-

5

-

6

-

7

-

8

-

9

-

10

-

11

-

12

-

13

-

14

-

15

-

16

-

17

-

18

-

19

-

20

-

21

-

22

-

23

-

24

-

25

-

26

-

27

-

28

-

29

-

30

-

31

-

32

-

33

-

34

-

35

-

36

-

37

-

38

-

39

-

40

-

41

-

42

-

43

-

44

-

45

-

46

-

47

-

48

-

49

-

50

-

51

-

52

-

53

-

54

-

55

-

56

-

57

-

58

-

59

-

60

-

61

-

62

-

63

-

64

-

65

-

66

-

67

-

68

-

69

-

70

-

71

-

72

-

73

-

74

-

75

-

76

-

77

-

78

-

79

-

80

-

81

-

82

-

83

-

84

-

85

-

86

-

87

-

88

-

89

-

90

-

91

-

92

-

93

-

94

-

95

-

96

-

97

-

98

-

99

-

100

-

101

-

102

-

103

-

104

-

105

-

106

-

107

-

108

-

109

-

110

-

111

-

112

-

113

-

114

-

115

-

116

-

117

-

118

-

119

-

120

-

121

-

122

-

123

-

124

-

125

-

126

-

127

-

128

-

129

-

130

-

131

-

132

-

133

-

134

-

135

-

136

-

137

-

138

-

139

-

140

-

141

-

142

-

143

-

144

-

145

-

146

-

147

-

148

-

149

-

150

-

151

-

152

-

153

-

154

-

155

-

156

-

157

-

158

-

159

-

160

-

161

-

162

-

163

-

164

-

165

-

166

-

167

-

168

-

169

-

170

-

171

-

172

-

173

-

174

-

175

-

176

-

177

-

178

-

179

-

180

-

181

-

182

-

183

-

184

-

185

-

186

-

187

-

188

-

189

-

190

-

191

-

192

-

193

-

194

-

195

-

196

-

197

-

198

-

199

-

200

-

201

-

202

-

203

-

204

-

205

-

206

-

207

-

208

-

209

-

210

-

211

-

212

-

213

-

214

-

215

-

216

-

217

-

218

-

219

-

220

-

221

-

222

-

223

-

224

-

225

-

226

-

227

-

228

-

229

-

230

-

231

-

232

-

233

-

234

-

235

-

236

-

237

-

238

-

239

-

240

-

241

-

242

-

243

-

244

-

245

-

246

-

247

-

248

-

249

-

250

-

251

-

252

-

253

-

254

-

255

-

256

-

257

-

258

-

259

-

260

-

261

-

262

-

263

-

264

-

265

-

266

-

267

-

268

-

269

-

270

-

271

-

272

-

273

-

274

-

275

-

276

-

277

-

278

-

279

-

280

-

281

-

282

-

283

-

284

-

285

-

286

-

287

-

288

-

289

-

290

-

291

-

292

-

293

-

294

-

295

-

296

-

297

-

298

-

299

-

300

-

301

-

302

-

303

-

304

-

305

-

306

-

307

-

308

-

309

-

310

-

311

-

312

-

313

-

314

-

315

-

316

-

317

-

318

-

319

-

320

-

321

-

322

-

323

-

324

-

325

-

326

-

327

-

328

-

329

-

330

-

331

-

332

-

333

-

334

-

335

-

336

-

337

-

338

-

339

-

340

-

341

-

342

-

343

-

344

-

345

-

346

-

347

-

348

-

349

-

350

-

351

-

352

-

353

-

354

-

355

-

356

-

357

-

358

-

359

-

360

-

361

-

362

-

363

-

364

-

365

-

366

-

367

-

368

-

369

-

370

-

371

-

372

-

373

-

374

-

375

-

376

-

377

-

378

-

379

-

380

-

381

-

382

-

383

-

384

-

385

-

386

-

387

-

388

-

389

-

390

-

391

-

392

-

393

-

394

-

395

-

396

-

397

-

398

-

399

-

400

-

401

-

402

-

403

-

404

-

405

-

406

-

407

-

408

-

409

-

410

-

411

-

412

-

413

-

414

-

415

-

416

-

417

-

418

-

419

-

420

-

421

-

422

-

423

-

424

-

425

-

426

-

427

-

428

-

429

-

430

-

431

-

432

-

433

-

434

-

435

-

436

-

437

-

438

-

439

-

440

-

441

-

442

-

443

-

444

-

445

-

446

-

447

-

448

-

449

-

450

-

451

-

452

-

453

-

454

-

455

-

456

-

457

-

458

-

459

-

460

-

461

-

462

-

463

-

464

-

465

-

466

-

467

-

468

-

469

-

470

-

471

-

472

-

473

-

474

-

475

-

476

-

477

-

478

-

479

-

480

-

481

-

482

-

483

-

484

-

485

-

486

-

487

-

488

-

489

-

490

-

491

-

492

-

493

-

494

-

495

-

496

-

497

-

498

-

499

-

500

-

501

-

502

-

503

-

504

-

505

-

506

-

507

-

508

-

509

-

510

-

511

-

512

-

513

-

514

-

515

-

516

-

517

-

518

-

519

-

520

-

521

-

522

-

523

-

524

-

525

-

526

-

527

-

528

-

529

-

530

-

531

-

532

-

533

-

534

-

535

-

536

-

537

-

538

-

539

-

540

-

541

-

542

-

543

-

544

-

545

-

546

-

547

-

548

-

549

-

550

-

551

-

552

-

553

-

554

-

555

-

556

-

557

-

558

-

559

-

560

-

561

-

562

-

563

-

564

-

565

-

566

-

567

-

568

-

569

-

570

-

571

-

572

-

573

-

574

-

575

-

576

-

577

-

578

-

579

-

580

-

581

-

582

-

583

-

584

-

585

-

586

-

587

-

588

-

589

-

590

-

591

-

592

-

593

-

594

-

595

-

596

-

597

-

598

-

599

-

600

-

601

-

602

-

603

-

604

-

605

-

606

-

607

-

608

-

609

-

610

-

611

-

612

-

613

-

614

-

615

-

616

-

617

-

618

-

619

-

620

-

621

-

622

-

623

-

624

-

625

-

626

-

627

-

628

-

629

-

630

-

631

-

632

-

633

-

634

-

635

-

636

-

637

-

638

-

639

-

640

-

641

-

642

-

643

-

644

-

645

-

646

-

647

-

648

-

649

-

650

-

651

-

652

-

653

-

654

-

655

-

656

-

657

-

658

-

659

-

660

-

661

-

662

-

663

-

664

-

665

-

666

-

667

-

668

-

669

-

670

-

671

-

672

-

673

-

674

-

675

-

676

-

677

-

678

-

679

-

680

-

681

-

682

-

683

-

684

-

685

-

686

-

687

-

688

-

689

-

690

-

691

-

692

-

693

-

694

-

695

-

696

-

697

-

698

-

699

-

700

-

701

-

702

-

703

-

704

-

705

-

706

-

707

-

708

-

709

- -
-

""" Cog code generation tool. 

-

    http://nedbatchelder.com/code/cog 

-

     

-

    Copyright 2004-2009, Ned Batchelder. 

-

""" 

-

 

-

import copy, getopt, imp, os, re, shlex, string, sys, traceback 

-

from cStringIO import StringIO 

-

 

-

# The recommended way to compute md5's changed in Python 2.5 

-

try: 

-

    import hashlib 

-

    hash_factory = hashlib.md5 

-

except ImportError: 

-

    import md5 

-

    hash_factory = md5.new 

-

 

-

__all__ = ['Cog', 'CogUsageError'] 

-

 

-

__version__ = '2.2'       # History at the end of the file. 

-

 

-

usage = """\ 

-

cog - generate code with inlined Python code. 

-

 

-

cog [OPTIONS] [INFILE | @FILELIST] ... 

-

 

-

INFILE is the name of an input file. 

-

FILELIST is the name of a text file containing file names or 

-

    other @FILELISTs. 

-

 

-

OPTIONS: 

-

    -c          Checksum the output to protect it against accidental change. 

-

    -d          Delete the generator code from the output file. 

-

    -D name=val Define a global string available to your generator code. 

-

    -e          Warn if a file has no cog code in it. 

-

    -I PATH     Add PATH to the list of directories for data files and modules. 

-

    -o OUTNAME  Write the output to OUTNAME. 

-

    -r          Replace the input file with the output. 

-

    -s STRING   Suffix all generated output lines with STRING. 

-

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

-

    -w CMD      Use CMD if the output file needs to be made writable. 

-

                    A %s in the CMD will be filled with the filename. 

-

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

-

    -z          The [[[end]]] marker can be omitted, and is assumed at eof. 

-

    -v          Print the version of cog and exit. 

-

    -h          Print this help. 

-

""" 

-

 

-

# Other package modules 

-

from whiteutils import * 

-

 

-

class CogError(Exception): 

-

    """ Any exception raised by Cog. 

-

    """ 

-

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

-

59        if file: 

-

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

-

        else: 

-

            Exception.__init__(self, msg) 

-

 

-

class CogUsageError(CogError): 

-

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

-

    """ 

-

    pass    #pragma: no cover 

-

 

-

class CogInternalError(CogError): 

-

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

-

    """ 

-

    pass    #pragma: no cover 

-

 

-

class CogGeneratedError(CogError): 

-

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

-

    """ 

-

    pass    #pragma: no cover 

-

 

-

class Redirectable: 

-

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

-

    """ 

-

    def __init__(self): 

-

        self.stdout = sys.stdout 

-

        self.stderr = sys.stderr 

-

 

-

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

-

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

-

        """ 

-

88        if stdout: 

-

            self.stdout = stdout 

-

89        if stderr: 

-

            self.stderr = stderr 

-

 

-

class CogGenerator(Redirectable): 

-

    """ A generator pulled from a source file. 

-

    """ 

-

    def __init__(self): 

-

        Redirectable.__init__(self) 

-

        self.markers = [] 

-

        self.lines = [] 

-

 

-

    def parseMarker(self, l): 

-

        self.markers.append(l) 

-

 

-

    def parseLine(self, l): 

-

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

-

 

-

    def getCode(self): 

-

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

-

        """ 

-

        # If the markers and lines all have the same prefix 

-

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

-

        # then remove it from all the lines. 

-

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

-

        if prefIn: 

-

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

-

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

-

 

-

        return reindentBlock(self.lines, '') 

-

 

-

    def evaluate(self, cog, globals, fname='cog generator'): 

-

        # figure out the right whitespace prefix for the output 

-

        prefOut = whitePrefix(self.markers) 

-

 

-

        intext = self.getCode() 

-

        if not intext: 

-

            return '' 

-

 

-

        # In Python 2.2, the last line has to end in a newline. 

-

        intext = "import cog\n" + intext + "\n" 

-

        code = compile(intext, str(fname), 'exec') 

-

 

-

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

-

        cog.cogmodule.msg = self.msg 

-

        cog.cogmodule.out = self.out 

-

        cog.cogmodule.outl = self.outl 

-

        cog.cogmodule.error = self.error 

-

 

-

        self.outstring = '' 

-

        eval(code, globals) 

-

 

-

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

-

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

-

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

-

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

-

            self.outstring += '\n' 

-

 

-

        return reindentBlock(self.outstring, prefOut) 

-

 

-

    def msg(self, s): 

-

        print >>self.stdout, "Message: "+s 

-

 

-

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

-

        """ The cog.out function. 

-

        """ 

-

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

-

            lines = sOut.split('\n') 

-

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

-

                del lines[0] 

-

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

-

                del lines[-1] 

-

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

-

        if dedent: 

-

            sOut = reindentBlock(sOut) 

-

        self.outstring += sOut 

-

 

-

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

-

        """ The cog.outl function. 

-

        """ 

-

        self.out(sOut, **kw) 

-

        self.out('\n') 

-

 

-

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

-

        """ The cog.error function. 

-

            Instead of raising standard python errors, cog generators can use 

-

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

-

            traceback. 

-

        """ 

-

        raise CogGeneratedError(msg) 

-

 

-

 

-

class NumberedFileReader: 

-

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

-

    """ 

-

    def __init__(self, f): 

-

        self.f = f 

-

        self.n = 0 

-

 

-

    def readline(self): 

-

        l = self.f.readline() 

-

        if l: 

-

            self.n += 1 

-

        return l 

-

 

-

    def linenumber(self): 

-

        return self.n 

-

 

-

 

-

class CogOptions: 

-

    """ Options for a run of cog. 

-

    """ 

-

    def __init__(self): 

-

        # Defaults for argument values. 

-

        self.args = [] 

-

        self.includePath = [] 

-

        self.defines = {} 

-

        self.bShowVersion = False 

-

        self.sMakeWritableCmd = None 

-

        self.bReplace = False 

-

        self.bNoGenerate = False 

-

        self.sOutputName = None 

-

        self.bWarnEmpty = False 

-

        self.bHashOutput = False 

-

        self.bDeleteCode = False 

-

        self.bEofCanBeEnd = False 

-

        self.sSuffix = None 

-

        self.bNewlines = False 

-

 

-

    def __cmp__(self, other): 

-

        """ Comparison operator for tests to use. 

-

        """ 

-

        return self.__dict__.__cmp__(other.__dict__) 

-

 

-

    def clone(self): 

-

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

-

        """ 

-

        return copy.deepcopy(self) 

-

 

-

    def addToIncludePath(self, dirs): 

-

        """ Add directories to the include path. 

-

        """ 

-

        dirs = dirs.split(os.pathsep) 

-

        self.includePath.extend(dirs) 

-

 

-

    def parseArgs(self, argv): 

-

        # Parse the command line arguments. 

-

        try: 

-

            opts, self.args = getopt.getopt(argv, 'cdD:eI:o:rs:Uvw:xz') 

-

        except getopt.error, msg: 

-

            raise CogUsageError(msg) 

-

 

-

        # Handle the command line arguments. 

-

        for o, a in opts: 

-

            if o == '-c': 

-

                self.bHashOutput = True 

-

            elif o == '-d': 

-

                self.bDeleteCode = True 

-

            elif o == '-D': 

-

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

-

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

-

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

-

                self.defines[name] = value 

-

            elif o == '-e': 

-

                self.bWarnEmpty = True 

-

            elif o == '-I': 

-

                self.addToIncludePath(a) 

-

            elif o == '-o': 

-

                self.sOutputName = a 

-

            elif o == '-r': 

-

                self.bReplace = True 

-

            elif o == '-s': 

-

                self.sSuffix = a 

-

            elif o == '-U': 

-

                self.bNewlines = True 

-

            elif o == '-v': 

-

                self.bShowVersion = True 

-

            elif o == '-w': 

-

                self.sMakeWritableCmd = a 

-

            elif o == '-x': 

-

                self.bNoGenerate = True 

-

            elif o == '-z': 

-

                self.bEofCanBeEnd = True 

-

            else: 

-

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

-

                # this is an internal error. 

-

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

-

 

-

    def validate(self): 

-

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

-

        """ 

-

        if self.bReplace and self.bDeleteCode: 

-

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

-

 

-

        if self.bReplace and self.sOutputName: 

-

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

-

 

-

 

-

class Cog(Redirectable): 

-

    """ The Cog engine. 

-

    """ 

-

    def __init__(self): 

-

        Redirectable.__init__(self) 

-

        self.sBeginSpec = '[[[cog' 

-

        self.sEndSpec = ']]]' 

-

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

-

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

-

        self.sEndFormat = '[[[end]]] (checksum: %s)' 

-

 

-

        self.options = CogOptions() 

-

        self.sOutputMode = 'w' 

-

 

-

        self.installCogModule() 

-

 

-

    def showWarning(self, msg): 

-

        print >>self.stdout, "Warning:", msg 

-

 

-

    def isBeginSpecLine(self, s): 

-

        return string.find(s, self.sBeginSpec) >= 0 

-

 

-

    def isEndSpecLine(self, s): 

-

        return string.find(s, self.sEndSpec) >= 0 and \ 

-

            not self.isEndOutputLine(s) 

-

 

-

    def isEndOutputLine(self, s): 

-

        return string.find(s, self.sEndOutput) >= 0 

-

 

-

    def installCogModule(self): 

-

        """ Magic mumbo-jumbo so that imported Python modules 

-

            can say "import cog" and get our state. 

-

        """ 

-

        self.cogmodule = imp.new_module('cog') 

-

        self.cogmodule.path = [] 

-

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

-

 

-

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

-

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

-

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

-

        """ 

-

 

-

        sFileIn = fname or '' 

-

        sFileOut = fname or '' 

-

        fInToClose = fOutToClose = None 

-

        # Convert filenames to files. 

-

333        if isinstance(fIn, basestring): 

-

            # Open the input file. 

-

            sFileIn = fIn 

-

            fIn = fInToClose = open(fIn, 'r') 

-

337        if isinstance(fOut, basestring): 

-

            # Open the output file. 

-

            sFileOut = fOut 

-

            fOut = fOutToClose = open(fOut, self.sOutputMode) 

-

 

-

        try: 

-

            fIn = NumberedFileReader(fIn) 

-

 

-

            bSawCog = False 

-

 

-

            self.cogmodule.inFile = sFileIn 

-

            self.cogmodule.outFile = sFileOut 

-

 

-

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

-

353            if globals is None: 

-

                globals = {} 

-

 

-

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

-

            globals.update(self.options.defines) 

-

 

-

            # loop over generator chunks 

-

            l = fIn.readline() 

-

            while l: 

-

                # Find the next spec begin 

-

                while l and not self.isBeginSpecLine(l): 

-

361                    if self.isEndSpecLine(l): 

-

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

-

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

-

364                    if self.isEndOutputLine(l): 

-

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

-

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

-

                    fOut.write(l) 

-

                    l = fIn.readline() 

-

                if not l: 

-

                    break 

-

374                if not self.options.bDeleteCode: 

-

                    fOut.write(l) 

-

 

-

                # l is the begin spec 

-

                gen = CogGenerator() 

-

                gen.setOutput(stdout=self.stdout) 

-

                gen.parseMarker(l) 

-

                firstLineNum = fIn.linenumber() 

-

                self.cogmodule.firstLineNum = firstLineNum 

-

 

-

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

-

                # line of code inside. 

-

                if self.isEndSpecLine(l): 

-

                    beg = string.find(l, self.sBeginSpec) 

-

                    end = string.find(l, self.sEndSpec) 

-

                    if beg > end: 

-

                        raise CogError("Cog code markers inverted", 

-

                            file=sFileIn, line=firstLineNum) 

-

                    else: 

-

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

-

                        gen.parseLine(sCode) 

-

                else: 

-

                    # Deal with an ordinary code block. 

-

                    l = fIn.readline() 

-

 

-

                    # Get all the lines in the spec 

-

                    while l and not self.isEndSpecLine(l): 

-

398                        if self.isBeginSpecLine(l): 

-

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

-

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

-

401                        if self.isEndOutputLine(l): 

-

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

-

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

-

405                        if not self.options.bDeleteCode: 

-

                            fOut.write(l) 

-

                        gen.parseLine(l) 

-

                        l = fIn.readline() 

-

408                    if not l: 

-

                        raise CogError( 

-

                            "Cog block begun but never ended.", 

-

                            file=sFileIn, line=firstLineNum) 

-

 

-

414                    if not self.options.bDeleteCode: 

-

                        fOut.write(l) 

-

                    gen.parseMarker(l) 

-

 

-

                l = fIn.readline() 

-

 

-

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

-

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

-

                hasher = hash_factory() 

-

                while l and not self.isEndOutputLine(l): 

-

423                    if self.isBeginSpecLine(l): 

-

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

-

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

-

426                    if self.isEndSpecLine(l): 

-

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

-

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

-

                    hasher.update(l) 

-

                    l = fIn.readline() 

-

                curHash = hasher.hexdigest() 

-

 

-

434                if not l and not self.options.bEofCanBeEnd: 

-

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

-

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

-

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

-

 

-

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

-

                # supposed to generate code. 

-

                hasher = hash_factory() 

-

446                if not self.options.bNoGenerate: 

-

                    sFile = "%s+%d" % (sFileIn, firstLineNum) 

-

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

-

                    sGen = self.suffixLines(sGen) 

-

                    hasher.update(sGen) 

-

                    fOut.write(sGen) 

-

                newHash = hasher.hexdigest() 

-

 

-

                bSawCog = True 

-

 

-

                # Write the ending output line 

-

                hashMatch = self.reEndOutput.search(l) 

-

453                if self.options.bHashOutput: 

-

                    if hashMatch: 

-

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

-

                        if oldHash != curHash: 

-

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

-

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

-

                        # Create a new end line with the correct hash. 

-

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

-

                    else: 

-

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

-

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

-

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

-

                else: 

-

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

-

                    # it. 

-

468                    if hashMatch: 

-

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

-

 

-

472                if not self.options.bDeleteCode: 

-

                    fOut.write(l) 

-

                l = fIn.readline() 

-

 

-

475            if not bSawCog and self.options.bWarnEmpty: 

-

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

-

        finally: 

-

478            if fInToClose: 

-

                fInToClose.close() 

-

480            if fOutToClose: 

-

                fOutToClose.close() 

-

 

-

 

-

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

-

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

-

 

-

    def suffixLines(self, text): 

-

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

-

            text is many lines, as a single string. 

-

        """ 

-

492        if self.options.sSuffix: 

-

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

-

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

-

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

-

        return text 

-

 

-

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

-

        """ Process sInput as the text to cog. 

-

            Return the cogged output as a string. 

-

        """ 

-

        fOld = StringIO(sInput) 

-

        fNew = StringIO() 

-

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

-

        return fNew.getvalue() 

-

 

-

    def replaceFile(self, sOldPath, sNewText): 

-

        """ Replace file sOldPath with the contents sNewText 

-

        """ 

-

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

-

            # Need to ensure we can write. 

-

            if self.options.sMakeWritableCmd: 

-

                # Use an external command to make the file writable. 

-

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

-

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

-

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

-

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

-

            else: 

-

                # Can't write! 

-

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

-

        f = open(sOldPath, self.sOutputMode) 

-

        f.write(sNewText) 

-

        f.close() 

-

 

-

    def saveIncludePath(self): 

-

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

-

        self.savedSysPath = sys.path[:] 

-

 

-

    def restoreIncludePath(self): 

-

        self.options.includePath = self.savedInclude 

-

        self.cogmodule.path = self.options.includePath 

-

        sys.path = self.savedSysPath 

-

 

-

    def addToIncludePath(self, includePath): 

-

        self.cogmodule.path.extend(includePath) 

-

        sys.path.extend(includePath) 

-

 

-

    def processOneFile(self, sFile): 

-

        """ Process one filename through cog. 

-

        """ 

-

 

-

        self.saveIncludePath() 

-

 

-

        try: 

-

            self.addToIncludePath(self.options.includePath) 

-

            # Since we know where the input file came from, 

-

            # push its directory onto the include path. 

-

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

-

 

-

            # Set the file output mode based on whether we want \n or native 

-

            # line endings. 

-

            self.sOutputMode = 'w' 

-

            if self.options.bNewlines: 

-

                self.sOutputMode = 'wb' 

-

 

-

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

-

            if self.options.sOutputName: 

-

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

-

            elif self.options.bReplace: 

-

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

-

                # but only if they differ. 

-

                print >>self.stdout, "Cogging %s" % sFile, 

-

                bNeedNewline = True 

-

 

-

                try: 

-

                    fOldFile = open(sFile) 

-

                    sOldText = fOldFile.read() 

-

                    fOldFile.close() 

-

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

-

                    if sOldText != sNewText: 

-

                        print >>self.stdout, "  (changed)" 

-

                        bNeedNewline = False 

-

                        self.replaceFile(sFile, sNewText) 

-

                finally: 

-

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

-

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

-

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

-

                    # any traceback. 

-

                    if bNeedNewline: 

-

                        print >>self.stdout 

-

            else: 

-

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

-

        finally: 

-

            self.restoreIncludePath() 

-

 

-

    def processFileList(self, sFileList): 

-

        """ Process the files in a file list. 

-

        """ 

-

        flist = open(sFileList) 

-

        lines = flist.readlines() 

-

        flist.close() 

-

        for l in lines: 

-

            # Use shlex to parse the line like a shell. 

-

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

-

            lex.whitespace_split = True 

-

            lex.commenters = '#' 

-

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

-

            lex.escape = '' 

-

            args = list(lex) 

-

            if args: 

-

                self.processArguments(args) 

-

 

-

    def processArguments(self, args): 

-

        """ Process one command-line. 

-

        """ 

-

        saved_options = self.options 

-

        self.options = self.options.clone() 

-

 

-

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

-

        self.options.validate() 

-

 

-

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

-

            if self.options.sOutputName: 

-

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

-

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

-

        else: 

-

            self.processOneFile(args[0]) 

-

 

-

        self.options = saved_options 

-

 

-

    def callableMain(self, argv): 

-

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

-

            This is used by main. 

-

            argv is the equivalent of sys.argv. 

-

        """ 

-

        argv0 = argv.pop(0) 

-

 

-

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

-

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

-

            print >>self.stderr, usage, 

-

            return 

-

 

-

        self.options.parseArgs(argv) 

-

        self.options.validate() 

-

 

-

        if self.options.bShowVersion: 

-

            print >>self.stdout, "Cog version %s" % __version__ 

-

            return 

-

 

-

        if self.options.args: 

-

            for a in self.options.args: 

-

                self.processArguments([a]) 

-

        else: 

-

            raise CogUsageError("No files to process") 

-

 

-

    def main(self, argv): 

-

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

-

        """ 

-

 

-

        try: 

-

            self.callableMain(argv) 

-

            return 0 

-

        except CogUsageError, err: 

-

            print >>self.stderr, err 

-

            print >>self.stderr, "(for help use -?)" 

-

            return 2 

-

        except CogGeneratedError, err: 

-

            print >>self.stderr, "Error: %s" % err 

-

            return 3 

-

        except CogError, err: 

-

            print >>self.stderr, err 

-

            return 1 

-

        except: 

-

            traceback.print_exc(None, self.stderr) 

-

            return 1 

-

 

-

# History: 

-

# 20040210: First public version. 

-

# 20040220: Text preceding the start and end marker are removed from Python lines. 

-

#           -v option on the command line shows the version. 

-

# 20040311: Make sure the last line of output is properly ended with a newline. 

-

# 20040605: Fixed some blank line handling in cog. 

-

#           Fixed problems with assigning to xml elements in handyxml. 

-

# 20040621: Changed all line-ends to LF from CRLF. 

-

# 20041002: Refactor some option handling to simplify unittesting the options. 

-

# 20041118: cog.out and cog.outl have optional string arguments. 

-

# 20041119: File names weren't being properly passed around for warnings, etc. 

-

# 20041122: Added cog.firstLineNum: a property with the line number of the [[[cog line. 

-

#           Added cog.inFile and cog.outFile: the names of the input and output file. 

-

# 20041218: Single-line cog generators, with start marker and end marker on 

-

#           the same line. 

-

# 20041230: Keep a single globals dict for all the code fragments in a single 

-

#           file so they can share state. 

-

# 20050206: Added the -x switch to remove all generated output. 

-

# 20050218: Now code can be on the marker lines as well. 

-

# 20050219: Added -c switch to checksum the output so that edits can be 

-

#           detected before they are obliterated. 

-

# 20050521: Added cog.error, contributed by Alexander Belchenko. 

-

# 20050720: Added code deletion and settable globals contributed by Blake Winton. 

-

# 20050724: Many tweaks to improve code coverage. 

-

# 20050726: Error messages are now printed with no traceback. 

-

#           Code can no longer appear on the marker lines, 

-

#               except for single-line style. 

-

#           -z allows omission of the [[[end]]] marker, and it will be assumed 

-

#               at the end of the file. 

-

# 20050729: Refactor option parsing into a separate class, in preparation for 

-

#               future features. 

-

# 20050805: The cogmodule.path wasn't being properly maintained. 

-

# 20050808: Added the -D option to define a global value. 

-

# 20050810: The %s in the -w command is dealt with more robustly. 

-

#           Added the -s option to suffix output lines with a marker. 

-

# 20050817: Now @files can have arguments on each line to change the cog's 

-

#               behavior for that line. 

-

# 20051006: Version 2.0 

-

# 20080521: -U options lets you create Unix newlines on Windows.  Thanks, 

-

#               Alexander Belchenko. 

-

# 20080522: It's now ok to have -d with output to stdout, and now we validate 

-

#               the args after each line of an @file. 

-

# 20090520: Use hashlib where it's available, to avoid a warning. 

-

#           Use the builtin compile() instead of compiler, for Jython. 

-

#           Explicitly close files we opened, Jython likes this. 

- -
-
- - - - - + + + + + + + + Coverage for cogapp\cogapp: 64% + + + + + + + + + + + +
+ +

Hot-keys on this page

+
+

+ r + m + x + p   toggle line displays +

+

+ j + k   next/prev highlighted chunk +

+

+ 0   (zero) top of page +

+

+ 1   (one) first highlighted chunk +

+
+
+ +
+ + + + + +
+

1

+

2

+

3

+

4

+

5

+

6

+

7

+

8

+

9

+

10

+

11

+

12

+

13

+

14

+

15

+

16

+

17

+

18

+

19

+

20

+

21

+

22

+

23

+

24

+

25

+

26

+

27

+

28

+

29

+

30

+

31

+

32

+

33

+

34

+

35

+

36

+

37

+

38

+

39

+

40

+

41

+

42

+

43

+

44

+

45

+

46

+

47

+

48

+

49

+

50

+

51

+

52

+

53

+

54

+

55

+

56

+

57

+

58

+

59

+

60

+

61

+

62

+

63

+

64

+

65

+

66

+

67

+

68

+

69

+

70

+

71

+

72

+

73

+

74

+

75

+

76

+

77

+

78

+

79

+

80

+

81

+

82

+

83

+

84

+

85

+

86

+

87

+

88

+

89

+

90

+

91

+

92

+

93

+

94

+

95

+

96

+

97

+

98

+

99

+

100

+

101

+

102

+

103

+

104

+

105

+

106

+

107

+

108

+

109

+

110

+

111

+

112

+

113

+

114

+

115

+

116

+

117

+

118

+

119

+

120

+

121

+

122

+

123

+

124

+

125

+

126

+

127

+

128

+

129

+

130

+

131

+

132

+

133

+

134

+

135

+

136

+

137

+

138

+

139

+

140

+

141

+

142

+

143

+

144

+

145

+

146

+

147

+

148

+

149

+

150

+

151

+

152

+

153

+

154

+

155

+

156

+

157

+

158

+

159

+

160

+

161

+

162

+

163

+

164

+

165

+

166

+

167

+

168

+

169

+

170

+

171

+

172

+

173

+

174

+

175

+

176

+

177

+

178

+

179

+

180

+

181

+

182

+

183

+

184

+

185

+

186

+

187

+

188

+

189

+

190

+

191

+

192

+

193

+

194

+

195

+

196

+

197

+

198

+

199

+

200

+

201

+

202

+

203

+

204

+

205

+

206

+

207

+

208

+

209

+

210

+

211

+

212

+

213

+

214

+

215

+

216

+

217

+

218

+

219

+

220

+

221

+

222

+

223

+

224

+

225

+

226

+

227

+

228

+

229

+

230

+

231

+

232

+

233

+

234

+

235

+

236

+

237

+

238

+

239

+

240

+

241

+

242

+

243

+

244

+

245

+

246

+

247

+

248

+

249

+

250

+

251

+

252

+

253

+

254

+

255

+

256

+

257

+

258

+

259

+

260

+

261

+

262

+

263

+

264

+

265

+

266

+

267

+

268

+

269

+

270

+

271

+

272

+

273

+

274

+

275

+

276

+

277

+

278

+

279

+

280

+

281

+

282

+

283

+

284

+

285

+

286

+

287

+

288

+

289

+

290

+

291

+

292

+

293

+

294

+

295

+

296

+

297

+

298

+

299

+

300

+

301

+

302

+

303

+

304

+

305

+

306

+

307

+

308

+

309

+

310

+

311

+

312

+

313

+

314

+

315

+

316

+

317

+

318

+

319

+

320

+

321

+

322

+

323

+

324

+

325

+

326

+

327

+

328

+

329

+

330

+

331

+

332

+

333

+

334

+

335

+

336

+

337

+

338

+

339

+

340

+

341

+

342

+

343

+

344

+

345

+

346

+

347

+

348

+

349

+

350

+

351

+

352

+

353

+

354

+

355

+

356

+

357

+

358

+

359

+

360

+

361

+

362

+

363

+

364

+

365

+

366

+

367

+

368

+

369

+

370

+

371

+

372

+

373

+

374

+

375

+

376

+

377

+

378

+

379

+

380

+

381

+

382

+

383

+

384

+

385

+

386

+

387

+

388

+

389

+

390

+

391

+

392

+

393

+

394

+

395

+

396

+

397

+

398

+

399

+

400

+

401

+

402

+

403

+

404

+

405

+

406

+

407

+

408

+

409

+

410

+

411

+

412

+

413

+

414

+

415

+

416

+

417

+

418

+

419

+

420

+

421

+

422

+

423

+

424

+

425

+

426

+

427

+

428

+

429

+

430

+

431

+

432

+

433

+

434

+

435

+

436

+

437

+

438

+

439

+

440

+

441

+

442

+

443

+

444

+

445

+

446

+

447

+

448

+

449

+

450

+

451

+

452

+

453

+

454

+

455

+

456

+

457

+

458

+

459

+

460

+

461

+

462

+

463

+

464

+

465

+

466

+

467

+

468

+

469

+

470

+

471

+

472

+

473

+

474

+

475

+

476

+

477

+

478

+

479

+

480

+

481

+

482

+

483

+

484

+

485

+

486

+

487

+

488

+

489

+

490

+

491

+

492

+

493

+

494

+

495

+

496

+

497

+

498

+

499

+

500

+

501

+

502

+

503

+

504

+

505

+

506

+

507

+

508

+

509

+

510

+

511

+

512

+

513

+

514

+

515

+

516

+

517

+

518

+

519

+

520

+

521

+

522

+

523

+

524

+

525

+

526

+

527

+

528

+

529

+

530

+

531

+

532

+

533

+

534

+

535

+

536

+

537

+

538

+

539

+

540

+

541

+

542

+

543

+

544

+

545

+

546

+

547

+

548

+

549

+

550

+

551

+

552

+

553

+

554

+

555

+

556

+

557

+

558

+

559

+

560

+

561

+

562

+

563

+

564

+

565

+

566

+

567

+

568

+

569

+

570

+

571

+

572

+

573

+

574

+

575

+

576

+

577

+

578

+

579

+

580

+

581

+

582

+

583

+

584

+

585

+

586

+

587

+

588

+

589

+

590

+

591

+

592

+

593

+

594

+

595

+

596

+

597

+

598

+

599

+

600

+

601

+

602

+

603

+

604

+

605

+

606

+

607

+

608

+

609

+

610

+

611

+

612

+

613

+

614

+

615

+

616

+

617

+

618

+

619

+

620

+

621

+

622

+

623

+

624

+

625

+

626

+

627

+

628

+

629

+

630

+

631

+

632

+

633

+

634

+

635

+

636

+

637

+

638

+

639

+

640

+

641

+

642

+

643

+

644

+

645

+

646

+

647

+

648

+

649

+

650

+

651

+

652

+

653

+

654

+

655

+

656

+

657

+

658

+

659

+

660

+

661

+

662

+

663

+

664

+

665

+

666

+

667

+

668

+

669

+

670

+

671

+

672

+

673

+

674

+

675

+

676

+

677

+

678

+

679

+

680

+

681

+

682

+

683

+

684

+

685

+

686

+

687

+

688

+

689

+

690

+

691

+

692

+

693

+

694

+

695

+

696

+

697

+

698

+

699

+

700

+

701

+

702

+

703

+

704

+

705

+

706

+

707

+

708

+

709

+ +
+

""" Cog code generation tool. 

+

    http://nedbatchelder.com/code/cog 

+

     

+

    Copyright 2004-2009, Ned Batchelder. 

+

""" 

+

 

+

import copy, getopt, imp, os, re, shlex, string, sys, traceback 

+

from cStringIO import StringIO 

+

 

+

# The recommended way to compute md5's changed in Python 2.5 

+

try: 

+

    import hashlib 

+

    hash_factory = hashlib.md5 

+

except ImportError: 

+

    import md5 

+

    hash_factory = md5.new 

+

 

+

__all__ = ['Cog', 'CogUsageError'] 

+

 

+

__version__ = '2.2'       # History at the end of the file. 

+

 

+

usage = """\ 

+

cog - generate code with inlined Python code. 

+

 

+

cog [OPTIONS] [INFILE | @FILELIST] ... 

+

 

+

INFILE is the name of an input file. 

+

FILELIST is the name of a text file containing file names or 

+

    other @FILELISTs. 

+

 

+

OPTIONS: 

+

    -c          Checksum the output to protect it against accidental change. 

+

    -d          Delete the generator code from the output file. 

+

    -D name=val Define a global string available to your generator code. 

+

    -e          Warn if a file has no cog code in it. 

+

    -I PATH     Add PATH to the list of directories for data files and modules. 

+

    -o OUTNAME  Write the output to OUTNAME. 

+

    -r          Replace the input file with the output. 

+

    -s STRING   Suffix all generated output lines with STRING. 

+

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

+

    -w CMD      Use CMD if the output file needs to be made writable. 

+

                    A %s in the CMD will be filled with the filename. 

+

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

+

    -z          The [[[end]]] marker can be omitted, and is assumed at eof. 

+

    -v          Print the version of cog and exit. 

+

    -h          Print this help. 

+

""" 

+

 

+

# Other package modules 

+

from whiteutils import * 

+

 

+

class CogError(Exception): 

+

    """ Any exception raised by Cog. 

+

    """ 

+

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

+

59        if file: 

+

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

+

        else: 

+

            Exception.__init__(self, msg) 

+

 

+

class CogUsageError(CogError): 

+

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

+

    """ 

+

    pass    #pragma: no cover 

+

 

+

class CogInternalError(CogError): 

+

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

+

    """ 

+

    pass    #pragma: no cover 

+

 

+

class CogGeneratedError(CogError): 

+

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

+

    """ 

+

    pass    #pragma: no cover 

+

 

+

class Redirectable: 

+

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

+

    """ 

+

    def __init__(self): 

+

        self.stdout = sys.stdout 

+

        self.stderr = sys.stderr 

+

 

+

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

+

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

+

        """ 

+

88        if stdout: 

+

            self.stdout = stdout 

+

89        if stderr: 

+

            self.stderr = stderr 

+

 

+

class CogGenerator(Redirectable): 

+

    """ A generator pulled from a source file. 

+

    """ 

+

    def __init__(self): 

+

        Redirectable.__init__(self) 

+

        self.markers = [] 

+

        self.lines = [] 

+

 

+

    def parseMarker(self, l): 

+

        self.markers.append(l) 

+

 

+

    def parseLine(self, l): 

+

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

+

 

+

    def getCode(self): 

+

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

+

        """ 

+

        # If the markers and lines all have the same prefix 

+

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

+

        # then remove it from all the lines. 

+

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

+

        if prefIn: 

+

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

+

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

+

 

+

        return reindentBlock(self.lines, '') 

+

 

+

    def evaluate(self, cog, globals, fname='cog generator'): 

+

        # figure out the right whitespace prefix for the output 

+

        prefOut = whitePrefix(self.markers) 

+

 

+

        intext = self.getCode() 

+

        if not intext: 

+

            return '' 

+

 

+

        # In Python 2.2, the last line has to end in a newline. 

+

        intext = "import cog\n" + intext + "\n" 

+

        code = compile(intext, str(fname), 'exec') 

+

 

+

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

+

        cog.cogmodule.msg = self.msg 

+

        cog.cogmodule.out = self.out 

+

        cog.cogmodule.outl = self.outl 

+

        cog.cogmodule.error = self.error 

+

 

+

        self.outstring = '' 

+

        eval(code, globals) 

+

 

+

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

+

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

+

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

+

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

+

            self.outstring += '\n' 

+

 

+

        return reindentBlock(self.outstring, prefOut) 

+

 

+

    def msg(self, s): 

+

        print >>self.stdout, "Message: "+s 

+

 

+

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

+

        """ The cog.out function. 

+

        """ 

+

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

+

            lines = sOut.split('\n') 

+

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

+

                del lines[0] 

+

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

+

                del lines[-1] 

+

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

+

        if dedent: 

+

            sOut = reindentBlock(sOut) 

+

        self.outstring += sOut 

+

 

+

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

+

        """ The cog.outl function. 

+

        """ 

+

        self.out(sOut, **kw) 

+

        self.out('\n') 

+

 

+

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

+

        """ The cog.error function. 

+

            Instead of raising standard python errors, cog generators can use 

+

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

+

            traceback. 

+

        """ 

+

        raise CogGeneratedError(msg) 

+

 

+

 

+

class NumberedFileReader: 

+

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

+

    """ 

+

    def __init__(self, f): 

+

        self.f = f 

+

        self.n = 0 

+

 

+

    def readline(self): 

+

        l = self.f.readline() 

+

        if l: 

+

            self.n += 1 

+

        return l 

+

 

+

    def linenumber(self): 

+

        return self.n 

+

 

+

 

+

class CogOptions: 

+

    """ Options for a run of cog. 

+

    """ 

+

    def __init__(self): 

+

        # Defaults for argument values. 

+

        self.args = [] 

+

        self.includePath = [] 

+

        self.defines = {} 

+

        self.bShowVersion = False 

+

        self.sMakeWritableCmd = None 

+

        self.bReplace = False 

+

        self.bNoGenerate = False 

+

        self.sOutputName = None 

+

        self.bWarnEmpty = False 

+

        self.bHashOutput = False 

+

        self.bDeleteCode = False 

+

        self.bEofCanBeEnd = False 

+

        self.sSuffix = None 

+

        self.bNewlines = False 

+

 

+

    def __cmp__(self, other): 

+

        """ Comparison operator for tests to use. 

+

        """ 

+

        return self.__dict__.__cmp__(other.__dict__) 

+

 

+

    def clone(self): 

+

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

+

        """ 

+

        return copy.deepcopy(self) 

+

 

+

    def addToIncludePath(self, dirs): 

+

        """ Add directories to the include path. 

+

        """ 

+

        dirs = dirs.split(os.pathsep) 

+

        self.includePath.extend(dirs) 

+

 

+

    def parseArgs(self, argv): 

+

        # Parse the command line arguments. 

+

        try: 

+

            opts, self.args = getopt.getopt(argv, 'cdD:eI:o:rs:Uvw:xz') 

+

        except getopt.error, msg: 

+

            raise CogUsageError(msg) 

+

 

+

        # Handle the command line arguments. 

+

        for o, a in opts: 

+

            if o == '-c': 

+

                self.bHashOutput = True 

+

            elif o == '-d': 

+

                self.bDeleteCode = True 

+

            elif o == '-D': 

+

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

+

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

+

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

+

                self.defines[name] = value 

+

            elif o == '-e': 

+

                self.bWarnEmpty = True 

+

            elif o == '-I': 

+

                self.addToIncludePath(a) 

+

            elif o == '-o': 

+

                self.sOutputName = a 

+

            elif o == '-r': 

+

                self.bReplace = True 

+

            elif o == '-s': 

+

                self.sSuffix = a 

+

            elif o == '-U': 

+

                self.bNewlines = True 

+

            elif o == '-v': 

+

                self.bShowVersion = True 

+

            elif o == '-w': 

+

                self.sMakeWritableCmd = a 

+

            elif o == '-x': 

+

                self.bNoGenerate = True 

+

            elif o == '-z': 

+

                self.bEofCanBeEnd = True 

+

            else: 

+

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

+

                # this is an internal error. 

+

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

+

 

+

    def validate(self): 

+

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

+

        """ 

+

        if self.bReplace and self.bDeleteCode: 

+

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

+

 

+

        if self.bReplace and self.sOutputName: 

+

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

+

 

+

 

+

class Cog(Redirectable): 

+

    """ The Cog engine. 

+

    """ 

+

    def __init__(self): 

+

        Redirectable.__init__(self) 

+

        self.sBeginSpec = '[[[cog' 

+

        self.sEndSpec = ']]]' 

+

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

+

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

+

        self.sEndFormat = '[[[end]]] (checksum: %s)' 

+

 

+

        self.options = CogOptions() 

+

        self.sOutputMode = 'w' 

+

 

+

        self.installCogModule() 

+

 

+

    def showWarning(self, msg): 

+

        print >>self.stdout, "Warning:", msg 

+

 

+

    def isBeginSpecLine(self, s): 

+

        return string.find(s, self.sBeginSpec) >= 0 

+

 

+

    def isEndSpecLine(self, s): 

+

        return string.find(s, self.sEndSpec) >= 0 and \ 

+

            not self.isEndOutputLine(s) 

+

 

+

    def isEndOutputLine(self, s): 

+

        return string.find(s, self.sEndOutput) >= 0 

+

 

+

    def installCogModule(self): 

+

        """ Magic mumbo-jumbo so that imported Python modules 

+

            can say "import cog" and get our state. 

+

        """ 

+

        self.cogmodule = imp.new_module('cog') 

+

        self.cogmodule.path = [] 

+

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

+

 

+

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

+

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

+

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

+

        """ 

+

 

+

        sFileIn = fname or '' 

+

        sFileOut = fname or '' 

+

        fInToClose = fOutToClose = None 

+

        # Convert filenames to files. 

+

333        if isinstance(fIn, basestring): 

+

            # Open the input file. 

+

            sFileIn = fIn 

+

            fIn = fInToClose = open(fIn, 'r') 

+

337        if isinstance(fOut, basestring): 

+

            # Open the output file. 

+

            sFileOut = fOut 

+

            fOut = fOutToClose = open(fOut, self.sOutputMode) 

+

 

+

        try: 

+

            fIn = NumberedFileReader(fIn) 

+

 

+

            bSawCog = False 

+

 

+

            self.cogmodule.inFile = sFileIn 

+

            self.cogmodule.outFile = sFileOut 

+

 

+

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

+

353            if globals is None: 

+

                globals = {} 

+

 

+

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

+

            globals.update(self.options.defines) 

+

 

+

            # loop over generator chunks 

+

            l = fIn.readline() 

+

            while l: 

+

                # Find the next spec begin 

+

                while l and not self.isBeginSpecLine(l): 

+

361                    if self.isEndSpecLine(l): 

+

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

+

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

+

364                    if self.isEndOutputLine(l): 

+

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

+

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

+

                    fOut.write(l) 

+

                    l = fIn.readline() 

+

                if not l: 

+

                    break 

+

374                if not self.options.bDeleteCode: 

+

                    fOut.write(l) 

+

 

+

                # l is the begin spec 

+

                gen = CogGenerator() 

+

                gen.setOutput(stdout=self.stdout) 

+

                gen.parseMarker(l) 

+

                firstLineNum = fIn.linenumber() 

+

                self.cogmodule.firstLineNum = firstLineNum 

+

 

+

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

+

                # line of code inside. 

+

                if self.isEndSpecLine(l): 

+

                    beg = string.find(l, self.sBeginSpec) 

+

                    end = string.find(l, self.sEndSpec) 

+

                    if beg > end: 

+

                        raise CogError("Cog code markers inverted", 

+

                            file=sFileIn, line=firstLineNum) 

+

                    else: 

+

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

+

                        gen.parseLine(sCode) 

+

                else: 

+

                    # Deal with an ordinary code block. 

+

                    l = fIn.readline() 

+

 

+

                    # Get all the lines in the spec 

+

                    while l and not self.isEndSpecLine(l): 

+

398                        if self.isBeginSpecLine(l): 

+

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

+

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

+

401                        if self.isEndOutputLine(l): 

+

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

+

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

+

405                        if not self.options.bDeleteCode: 

+

                            fOut.write(l) 

+

                        gen.parseLine(l) 

+

                        l = fIn.readline() 

+

408                    if not l: 

+

                        raise CogError( 

+

                            "Cog block begun but never ended.", 

+

                            file=sFileIn, line=firstLineNum) 

+

 

+

414                    if not self.options.bDeleteCode: 

+

                        fOut.write(l) 

+

                    gen.parseMarker(l) 

+

 

+

                l = fIn.readline() 

+

 

+

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

+

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

+

                hasher = hash_factory() 

+

                while l and not self.isEndOutputLine(l): 

+

423                    if self.isBeginSpecLine(l): 

+

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

+

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

+

426                    if self.isEndSpecLine(l): 

+

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

+

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

+

                    hasher.update(l) 

+

                    l = fIn.readline() 

+

                curHash = hasher.hexdigest() 

+

 

+

434                if not l and not self.options.bEofCanBeEnd: 

+

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

+

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

+

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

+

 

+

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

+

                # supposed to generate code. 

+

                hasher = hash_factory() 

+

446                if not self.options.bNoGenerate: 

+

                    sFile = "%s+%d" % (sFileIn, firstLineNum) 

+

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

+

                    sGen = self.suffixLines(sGen) 

+

                    hasher.update(sGen) 

+

                    fOut.write(sGen) 

+

                newHash = hasher.hexdigest() 

+

 

+

                bSawCog = True 

+

 

+

                # Write the ending output line 

+

                hashMatch = self.reEndOutput.search(l) 

+

453                if self.options.bHashOutput: 

+

                    if hashMatch: 

+

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

+

                        if oldHash != curHash: 

+

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

+

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

+

                        # Create a new end line with the correct hash. 

+

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

+

                    else: 

+

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

+

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

+

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

+

                else: 

+

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

+

                    # it. 

+

468                    if hashMatch: 

+

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

+

 

+

472                if not self.options.bDeleteCode: 

+

                    fOut.write(l) 

+

                l = fIn.readline() 

+

 

+

475            if not bSawCog and self.options.bWarnEmpty: 

+

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

+

        finally: 

+

478            if fInToClose: 

+

                fInToClose.close() 

+

480            if fOutToClose: 

+

                fOutToClose.close() 

+

 

+

 

+

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

+

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

+

 

+

    def suffixLines(self, text): 

+

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

+

            text is many lines, as a single string. 

+

        """ 

+

492        if self.options.sSuffix: 

+

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

+

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

+

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

+

        return text 

+

 

+

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

+

        """ Process sInput as the text to cog. 

+

            Return the cogged output as a string. 

+

        """ 

+

        fOld = StringIO(sInput) 

+

        fNew = StringIO() 

+

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

+

        return fNew.getvalue() 

+

 

+

    def replaceFile(self, sOldPath, sNewText): 

+

        """ Replace file sOldPath with the contents sNewText 

+

        """ 

+

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

+

            # Need to ensure we can write. 

+

            if self.options.sMakeWritableCmd: 

+

                # Use an external command to make the file writable. 

+

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

+

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

+

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

+

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

+

            else: 

+

                # Can't write! 

+

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

+

        f = open(sOldPath, self.sOutputMode) 

+

        f.write(sNewText) 

+

        f.close() 

+

 

+

    def saveIncludePath(self): 

+

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

+

        self.savedSysPath = sys.path[:] 

+

 

+

    def restoreIncludePath(self): 

+

        self.options.includePath = self.savedInclude 

+

        self.cogmodule.path = self.options.includePath 

+

        sys.path = self.savedSysPath 

+

 

+

    def addToIncludePath(self, includePath): 

+

        self.cogmodule.path.extend(includePath) 

+

        sys.path.extend(includePath) 

+

 

+

    def processOneFile(self, sFile): 

+

        """ Process one filename through cog. 

+

        """ 

+

 

+

        self.saveIncludePath() 

+

 

+

        try: 

+

            self.addToIncludePath(self.options.includePath) 

+

            # Since we know where the input file came from, 

+

            # push its directory onto the include path. 

+

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

+

 

+

            # Set the file output mode based on whether we want \n or native 

+

            # line endings. 

+

            self.sOutputMode = 'w' 

+

            if self.options.bNewlines: 

+

                self.sOutputMode = 'wb' 

+

 

+

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

+

            if self.options.sOutputName: 

+

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

+

            elif self.options.bReplace: 

+

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

+

                # but only if they differ. 

+

                print >>self.stdout, "Cogging %s" % sFile, 

+

                bNeedNewline = True 

+

 

+

                try: 

+

                    fOldFile = open(sFile) 

+

                    sOldText = fOldFile.read() 

+

                    fOldFile.close() 

+

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

+

                    if sOldText != sNewText: 

+

                        print >>self.stdout, "  (changed)" 

+

                        bNeedNewline = False 

+

                        self.replaceFile(sFile, sNewText) 

+

                finally: 

+

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

+

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

+

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

+

                    # any traceback. 

+

                    if bNeedNewline: 

+

                        print >>self.stdout 

+

            else: 

+

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

+

        finally: 

+

            self.restoreIncludePath() 

+

 

+

    def processFileList(self, sFileList): 

+

        """ Process the files in a file list. 

+

        """ 

+

        flist = open(sFileList) 

+

        lines = flist.readlines() 

+

        flist.close() 

+

        for l in lines: 

+

            # Use shlex to parse the line like a shell. 

+

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

+

            lex.whitespace_split = True 

+

            lex.commenters = '#' 

+

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

+

            lex.escape = '' 

+

            args = list(lex) 

+

            if args: 

+

                self.processArguments(args) 

+

 

+

    def processArguments(self, args): 

+

        """ Process one command-line. 

+

        """ 

+

        saved_options = self.options 

+

        self.options = self.options.clone() 

+

 

+

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

+

        self.options.validate() 

+

 

+

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

+

            if self.options.sOutputName: 

+

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

+

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

+

        else: 

+

            self.processOneFile(args[0]) 

+

 

+

        self.options = saved_options 

+

 

+

    def callableMain(self, argv): 

+

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

+

            This is used by main. 

+

            argv is the equivalent of sys.argv. 

+

        """ 

+

        argv0 = argv.pop(0) 

+

 

+

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

+

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

+

            print >>self.stderr, usage, 

+

            return 

+

 

+

        self.options.parseArgs(argv) 

+

        self.options.validate() 

+

 

+

        if self.options.bShowVersion: 

+

            print >>self.stdout, "Cog version %s" % __version__ 

+

            return 

+

 

+

        if self.options.args: 

+

            for a in self.options.args: 

+

                self.processArguments([a]) 

+

        else: 

+

            raise CogUsageError("No files to process") 

+

 

+

    def main(self, argv): 

+

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

+

        """ 

+

 

+

        try: 

+

            self.callableMain(argv) 

+

            return 0 

+

        except CogUsageError, err: 

+

            print >>self.stderr, err 

+

            print >>self.stderr, "(for help use -?)" 

+

            return 2 

+

        except CogGeneratedError, err: 

+

            print >>self.stderr, "Error: %s" % err 

+

            return 3 

+

        except CogError, err: 

+

            print >>self.stderr, err 

+

            return 1 

+

        except: 

+

            traceback.print_exc(None, self.stderr) 

+

            return 1 

+

 

+

# History: 

+

# 20040210: First public version. 

+

# 20040220: Text preceding the start and end marker are removed from Python lines. 

+

#           -v option on the command line shows the version. 

+

# 20040311: Make sure the last line of output is properly ended with a newline. 

+

# 20040605: Fixed some blank line handling in cog. 

+

#           Fixed problems with assigning to xml elements in handyxml. 

+

# 20040621: Changed all line-ends to LF from CRLF. 

+

# 20041002: Refactor some option handling to simplify unittesting the options. 

+

# 20041118: cog.out and cog.outl have optional string arguments. 

+

# 20041119: File names weren't being properly passed around for warnings, etc. 

+

# 20041122: Added cog.firstLineNum: a property with the line number of the [[[cog line. 

+

#           Added cog.inFile and cog.outFile: the names of the input and output file. 

+

# 20041218: Single-line cog generators, with start marker and end marker on 

+

#           the same line. 

+

# 20041230: Keep a single globals dict for all the code fragments in a single 

+

#           file so they can share state. 

+

# 20050206: Added the -x switch to remove all generated output. 

+

# 20050218: Now code can be on the marker lines as well. 

+

# 20050219: Added -c switch to checksum the output so that edits can be 

+

#           detected before they are obliterated. 

+

# 20050521: Added cog.error, contributed by Alexander Belchenko. 

+

# 20050720: Added code deletion and settable globals contributed by Blake Winton. 

+

# 20050724: Many tweaks to improve code coverage. 

+

# 20050726: Error messages are now printed with no traceback. 

+

#           Code can no longer appear on the marker lines, 

+

#               except for single-line style. 

+

#           -z allows omission of the [[[end]]] marker, and it will be assumed 

+

#               at the end of the file. 

+

# 20050729: Refactor option parsing into a separate class, in preparation for 

+

#               future features. 

+

# 20050805: The cogmodule.path wasn't being properly maintained. 

+

# 20050808: Added the -D option to define a global value. 

+

# 20050810: The %s in the -w command is dealt with more robustly. 

+

#           Added the -s option to suffix output lines with a marker. 

+

# 20050817: Now @files can have arguments on each line to change the cog's 

+

#               behavior for that line. 

+

# 20051006: Version 2.0 

+

# 20080521: -U options lets you create Unix newlines on Windows.  Thanks, 

+

#               Alexander Belchenko. 

+

# 20080522: It's now ok to have -d with output to stdout, and now we validate 

+

#               the args after each line of an @file. 

+

# 20090520: Use hashlib where it's available, to avoid a warning. 

+

#           Use the builtin compile() instead of compiler, for Jython. 

+

#           Explicitly close files we opened, Jython likes this. 

+ +
+
+ + + + + -- cgit v1.2.1