From 8603e0485333af6704e0cd0770f565fc2d716569 Mon Sep 17 00:00:00 2001 From: Ned Batchelder Date: Sat, 5 Dec 2009 16:29:33 -0500 Subject: Last touches for 3.2 final. --- doc/sample_html/README.txt | 4 +- doc/sample_html/_ned_py_path.html | 1711 ++++++------ doc/sample_html/cogapp_cogapp.html | 1881 ++++++------- doc/sample_html/cogapp_makefiles.html | 165 +- doc/sample_html/cogapp_test_cogapp.html | 4333 +++++++++++++++-------------- doc/sample_html/cogapp_whiteutils.html | 217 +- doc/sample_html/coverage_html.js | 64 + doc/sample_html/index.html | 204 +- doc/sample_html/jquery.tablesorter.min.js | 2 + doc/sample_html/style.css | 88 +- 10 files changed, 4419 insertions(+), 4250 deletions(-) create mode 100644 doc/sample_html/coverage_html.js create mode 100644 doc/sample_html/jquery.tablesorter.min.js (limited to 'doc/sample_html') diff --git a/doc/sample_html/README.txt b/doc/sample_html/README.txt index c1e4982..2890fb9 100644 --- a/doc/sample_html/README.txt +++ b/doc/sample_html/README.txt @@ -1,5 +1,5 @@ This directory was made with:: cd C:\ned\cog\trunk - coverage -e -x cogapp\test_cogapp.py CogTestsInMemory - coverage -b -i -d htmlcov + coverage run --branch cogapp\test_cogapp.py CogTestsInMemory + coverage html -i -d htmlcov diff --git a/doc/sample_html/_ned_py_path.html b/doc/sample_html/_ned_py_path.html index 78637ee..0a60bbe 100644 --- a/doc/sample_html/_ned_py_path.html +++ b/doc/sample_html/_ned_py_path.html @@ -1,19 +1,21 @@ - + + Coverage for c:\ned\py\path - - + @@ -22,13 +24,16 @@ function toggle_lines(btn, cls) { @@ -68,34 +73,34 @@ function toggle_lines(btn, cls) {

29

30

31

-

32

+

32

33

-

34

+

34

35

-

36

-

37

+

36

+

37

38

39

-

40

-

41

-

42

-

43

+

40

+

41

+

42

+

43

44

45

46

47

-

48

-

49

+

48

+

49

50

51

52

53

-

54

-

55

-

56

+

54

+

55

+

56

57

58

-

59

+

59

60

61

62

@@ -104,18 +109,18 @@ function toggle_lines(btn, cls) {

65

66

67

-

68

+

68

69

70

71

-

72

+

72

73

74

-

75

+

75

76

77

78

-

79

+

79

80

81

82

@@ -124,26 +129,26 @@ function toggle_lines(btn, cls) {

85

86

87

-

88

+

88

89

-

90

+

90

91

92

-

93

+

93

94

95

96

97

-

98

-

99

-

100

-

101

-

102

-

103

-

104

-

105

+

98

+

99

+

100

+

101

+

102

+

103

+

104

+

105

106

-

107

+

107

108

109

110

@@ -152,33 +157,33 @@ function toggle_lines(btn, cls) {

113

114

115

-

116

+

116

117

118

119

-

120

+

120

121

122

123

-

124

+

124

125

126

127

-

128

+

128

129

130

131

132

133

134

-

135

+

135

136

137

138

139

140

141

-

142

+

142

143

144

145

@@ -186,22 +191,22 @@ function toggle_lines(btn, cls) {

147

148

149

-

150

+

150

151

152

153

-

154

+

154

155

156

157

158

159

-

160

+

160

161

162

163

164

-

165

+

165

166

167

168

@@ -211,7 +216,7 @@ function toggle_lines(btn, cls) {

172

173

174

-

175

+

175

176

177

178

@@ -228,7 +233,7 @@ function toggle_lines(btn, cls) {

189

190

191

-

192

+

192

193

194

195

@@ -236,28 +241,28 @@ function toggle_lines(btn, cls) {

197

198

199

-

200

-

201

+

200

+

201

202

203

204

-

205

+

205

206

207

208

-

209

+

209

210

211

212

213

-

214

+

214

215

216

217

218

219

220

-

221

+

221

222

223

224

@@ -279,14 +284,14 @@ function toggle_lines(btn, cls) {

240

241

242

-

243

+

243

244

245

246

247

248

249

-

250

+

250

251

252

253

@@ -326,7 +331,7 @@ function toggle_lines(btn, cls) {

287

288

289

-

290

+

290

291

292

293

@@ -342,7 +347,7 @@ function toggle_lines(btn, cls) {

303

304

305

-

306

+

306

307

308

309

@@ -355,7 +360,7 @@ function toggle_lines(btn, cls) {

316

317

318

-

319

+

319

320

321

322

@@ -368,7 +373,7 @@ function toggle_lines(btn, cls) {

329

330

331

-

332

+

332

333

334

335

@@ -385,7 +390,7 @@ function toggle_lines(btn, cls) {

346

347

348

-

349

+

349

350

351

352

@@ -399,7 +404,7 @@ function toggle_lines(btn, cls) {

360

361

362

-

363

+

363

364

365

366

@@ -415,7 +420,7 @@ function toggle_lines(btn, cls) {

376

377

378

-

379

+

379

380

381

382

@@ -423,7 +428,7 @@ function toggle_lines(btn, cls) {

384

385

386

-

387

+

387

388

389

390

@@ -436,11 +441,11 @@ function toggle_lines(btn, cls) {

397

398

399

-

400

+

400

401

402

403

-

404

+

404

405

406

407

@@ -448,7 +453,7 @@ function toggle_lines(btn, cls) {

409

410

411

-

412

+

412

413

414

415

@@ -464,7 +469,7 @@ function toggle_lines(btn, cls) {

425

426

427

-

428

+

428

429

430

431

@@ -497,7 +502,7 @@ function toggle_lines(btn, cls) {

458

459

460

-

461

+

461

462

463

464

@@ -548,7 +553,7 @@ function toggle_lines(btn, cls) {

509

510

511

-

512

+

512

513

514

515

@@ -574,7 +579,7 @@ function toggle_lines(btn, cls) {

535

536

537

-

538

+

538

539

540

541

@@ -602,101 +607,101 @@ function toggle_lines(btn, cls) {

563

564

565

-

566

-

567

-

568

-

569

-

570

-

571

+

566

+

567

+

568

+

569

+

570

+

571

572

-

573

+

573

574

575

-

576

-

577

+

576

+

577

578

579

580

-

581

-

582

+

581

+

582

583

584

585

-

586

-

587

-

588

+

586

+

587

+

588

589

590

591

-

592

-

593

+

592

+

593

594

595

596

-

597

-

598

+

597

+

598

599

600

601

602

603

604

-

605

+

605

606

607

608

-

609

+

609

610

611

612

-

613

+

613

614

615

616

617

-

618

+

618

619

620

621

622

623

624

-

625

+

625

626

627

628

-

629

+

629

630

631

-

632

+

632

633

634

635

-

636

+

636

637

638

-

639

+

639

640

641

642

643

644

-

645

+

645

646

647

-

648

+

648

649

650

-

651

+

651

652

653

-

654

+

654

655

656

657

658

659

-

660

+

660

661

662

663

@@ -704,26 +709,26 @@ function toggle_lines(btn, cls) {

665

666

667

-

668

+

668

669

670

-

671

+

671

672

673

674

675

676

-

677

+

677

678

679

680

681

-

682

+

682

683

684

685

686

-

687

+

687

688

689

690

@@ -745,759 +750,759 @@ function toggle_lines(btn, cls) {

706

707

708

-

709

-

710

-

711

-

712

-

713

-

714

-

715

-

716

-

717

+

709

+

710

+

711

+

712

+

713

+

714

+

715

+

716

+

717

718

719

720

721

-

722

+

722

723

724

725

-

726

-

727

+

726

+

727

728

729

-

""" path.py - An object representing a path to a file or directory. 

-

 

-

Example: 

-

 

-

from path import path 

-

d = path('/home/guido/bin') 

-

for f in d.files('*.py'): 

-

    f.chmod(0755) 

-

 

-

This module requires Python 2.2 or later. 

-

 

-

 

-

URL:     http://www.jorendorff.com/articles/python/path 

-

Author:  Jason Orendorff <jason@jorendorff.com> (and others - see the url!) 

-

Date:    29 Feb 2004 

-

""" 

-

 

-

 

-

# TODO 

-

#   - Bug in write_text().  It doesn't support Universal newline mode. 

-

#   - Better error message in listdir() when self isn't a 

-

#     directory. (On Windows, the error message really sucks.) 

-

#   - Make sure everything has a good docstring. 

-

#   - Add methods for regex find and replace. 

-

#   - guess_content_type() method? 

-

#   - Perhaps support arguments to touch(). 

-

#   - Could add split() and join() methods that generate warnings. 

-

#   - Note:  __add__() technically has a bug, I think, where 

-

#     it doesn't play nice with other types that implement 

-

#     __radd__().  Test this. 

-

 

-

from __future__ import generators 

-

 

-

import sys, os, fnmatch, glob, shutil, codecs 

-

 

-

__version__ = '2.0.2' 

-

__all__ = ['path'] 

-

 

-

# Pre-2.3 support.  Are unicode filenames supported? 

-

_base = str 

-

try: 

-

    if os.path.supports_unicode_filenames: 

-

        _base = unicode 

-

except AttributeError: 

-

    pass 

-

 

-

# Pre-2.3 workaround for basestring. 

-

try: 

-

    basestring 

-

except NameError: 

-

    basestring = (str, unicode) 

-

 

-

# Universal newline support 

-

_textmode = 'r' 

-

if hasattr(file, 'newlines'): 

-

    _textmode = 'U' 

-

 

-

 

-

class path(_base): 

-

    """ Represents a filesystem path. 

-

 

-

    For documentation on individual methods, consult their 

-

    counterparts in os.path. 

-

    """ 

-

 

-

    # --- Special Python methods. 

-

 

-

    def __repr__(self): 

-

        return 'path(%s)' % _base.__repr__(self) 

-

 

-

    # Adding a path and a string yields a path. 

-

    def __add__(self, more): 

-

        return path(_base(self) + more) 

-

 

-

    def __radd__(self, other): 

-

        return path(other + _base(self)) 

-

 

-

    # The / operator joins paths. 

-

    def __div__(self, rel): 

-

        """ fp.__div__(rel) == fp / rel == fp.joinpath(rel) 

-

 

-

        Join two path components, adding a separator character if 

-

        needed. 

-

        """ 

-

        return path(os.path.join(self, rel)) 

-

 

-

    # Make the / operator work even when true division is enabled. 

-

    __truediv__ = __div__ 

-

 

-

    def getcwd(): 

-

        """ Return the current working directory as a path object. """ 

-

        return path(os.getcwd()) 

-

    getcwd = staticmethod(getcwd) 

-

 

-

 

-

    # --- Operations on path strings. 

-

 

-

    def abspath(self):       return path(os.path.abspath(self)) 

-

    def normcase(self):      return path(os.path.normcase(self)) 

-

    def normpath(self):      return path(os.path.normpath(self)) 

-

    def realpath(self):      return path(os.path.realpath(self)) 

-

    def expanduser(self):    return path(os.path.expanduser(self)) 

-

    def expandvars(self):    return path(os.path.expandvars(self)) 

-

    def dirname(self):       return path(os.path.dirname(self)) 

-

    basename = os.path.basename 

-

 

-

    def expand(self): 

-

        """ Clean up a filename by calling expandvars(), 

-

        expanduser(), and normpath() on it. 

-

 

-

        This is commonly everything needed to clean up a filename 

-

        read from a configuration file, for example. 

-

        """ 

-

        return self.expandvars().expanduser().normpath() 

-

 

-

    def _get_namebase(self): 

-

        base, ext = os.path.splitext(self.name) 

-

        return base 

-

 

-

    def _get_ext(self): 

-

        f, ext = os.path.splitext(_base(self)) 

-

        return ext 

-

 

-

    def _get_drive(self): 

-

        drive, r = os.path.splitdrive(self) 

-

        return path(drive) 

-

 

-

    parent = property( 

-

        dirname, None, None, 

-

        """ This path's parent directory, as a new path object. 

-

 

-

        For example, path('/usr/local/lib/libpython.so').parent == path('/usr/local/lib') 

-

        """) 

-

 

-

    name = property( 

-

        basename, None, None, 

-

        """ The name of this file or directory without the full path. 

-

 

-

        For example, path('/usr/local/lib/libpython.so').name == 'libpython.so' 

-

        """) 

-

 

-

    namebase = property( 

-

        _get_namebase, None, None, 

-

        """ The same as path.name, but with one file extension stripped off. 

-

 

-

        For example, path('/home/guido/python.tar.gz').name     == 'python.tar.gz', 

-

        but          path('/home/guido/python.tar.gz').namebase == 'python.tar' 

-

        """) 

-

 

-

    ext = property( 

-

        _get_ext, None, None, 

-

        """ The file extension, for example '.py'. """) 

-

 

-

    drive = property( 

-

        _get_drive, None, None, 

-

        """ The drive specifier, for example 'C:'. 

-

        This is always empty on systems that don't use drive specifiers. 

-

        """) 

-

 

-

    def splitpath(self): 

-

        """ p.splitpath() -> Return (p.parent, p.name). """ 

-

        parent, child = os.path.split(self) 

-

        return path(parent), child 

-

 

-

    def splitdrive(self): 

-

        """ p.splitdrive() -> Return (p.drive, <the rest of p>). 

-

 

-

        Split the drive specifier from this path.  If there is 

-

        no drive specifier, p.drive is empty, so the return value 

-

        is simply (path(''), p).  This is always the case on Unix. 

-

        """ 

-

        drive, rel = os.path.splitdrive(self) 

-

        return path(drive), rel 

-

 

-

    def splitext(self): 

-

        """ p.splitext() -> Return (p.stripext(), p.ext). 

-

 

-

        Split the filename extension from this path and return 

-

        the two parts.  Either part may be empty. 

-

 

-

        The extension is everything from '.' to the end of the 

-

        last path segment.  This has the property that if 

-

        (a, b) == p.splitext(), then a + b == p. 

-

        """ 

-

        # Cast to plain string using _base because Python 2.2 

-

        # implementations of os.path.splitext use "for c in path:..." 

-

        # which means something different when applied to a path 

-

        # object. 

-

        filename, ext = os.path.splitext(_base(self)) 

-

        return path(filename), ext 

-

 

-

    def stripext(self): 

-

        """ p.stripext() -> Remove one file extension from the path. 

-

 

-

        For example, path('/home/guido/python.tar.gz').stripext() 

-

        returns path('/home/guido/python.tar'). 

-

        """ 

-

        return self.splitext()[0] 

-

 

-

    if hasattr(os.path, 'splitunc'): 

-

        def splitunc(self): 

-

            unc, rest = os.path.splitunc(self) 

-

            return path(unc), rest 

-

 

-

        def _get_uncshare(self): 

-

            unc, r = os.path.splitunc(self) 

-

            return path(unc) 

-

 

-

        uncshare = property( 

-

            _get_uncshare, None, None, 

-

            """ The UNC mount point for this path. 

-

            This is empty for paths on local drives. """) 

-

 

-

    def joinpath(self, *args): 

-

        """ Join two or more path components, adding a separator 

-

        character (os.sep) if needed.  Returns a new path 

-

        object. 

-

        """ 

-

        return path(os.path.join(self, *args)) 

-

 

-

    def splitall(self): 

-

        """ Return a list of the path components in this path. 

-

 

-

        The first item in the list will be a path.  Its value will be 

-

        either os.curdir, os.pardir, empty, or the root directory of 

-

        this path (for example, '/' or 'C:\\').  The other items in 

-

        the list will be strings. 

-

 

-

        path.path.joinpath(*result) will yield the original path. 

-

        """ 

-

        parts = [] 

-

        loc = self 

-

        while loc != os.curdir and loc != os.pardir: 

-

            prev = loc 

-

            loc, child = prev.splitpath() 

-

            if loc == prev: 

-

                break 

-

            parts.append(child) 

-

        parts.append(loc) 

-

        parts.reverse() 

-

        return parts 

-

 

-

    def relpath(self): 

-

        """ Return this path as a relative path, 

-

        based from the current working directory. 

-

        """ 

-

        cwd = path(os.getcwd()) 

-

        return cwd.relpathto(self) 

-

 

-

    def relpathto(self, dest): 

-

        """ Return a relative path from self to dest. 

-

 

-

        If there is no relative path from self to dest, for example if 

-

        they reside on different drives in Windows, then this returns 

-

        dest.abspath(). 

-

        """ 

-

        origin = self.abspath() 

-

        dest = path(dest).abspath() 

-

 

-

        orig_list = origin.normcase().splitall() 

-

        # Don't normcase dest!  We want to preserve the case. 

-

        dest_list = dest.splitall() 

-

 

-

        if orig_list[0] != os.path.normcase(dest_list[0]): 

-

            # Can't get here from there. 

-

            return dest 

-

 

-

        # Find the location where the two paths start to differ. 

-

        i = 0 

-

        for start_seg, dest_seg in zip(orig_list, dest_list): 

-

            if start_seg != os.path.normcase(dest_seg): 

-

                break 

-

            i += 1 

-

 

-

        # Now i is the point where the two paths diverge. 

-

        # Need a certain number of "os.pardir"s to work up 

-

        # from the origin to the point of divergence. 

-

        segments = [os.pardir] * (len(orig_list) - i) 

-

        # Need to add the diverging part of dest_list. 

-

        segments += dest_list[i:] 

-

        if len(segments) == 0: 

-

            # If they happen to be identical, use os.curdir. 

-

            return path(os.curdir) 

-

        else: 

-

            return path(os.path.join(*segments)) 

-

 

-

 

-

    # --- Listing, searching, walking, and matching 

-

 

-

    def listdir(self, pattern=None): 

-

        """ D.listdir() -> List of items in this directory. 

-

 

-

        Use D.files() or D.dirs() instead if you want a listing 

-

        of just files or just subdirectories. 

-

 

-

        The elements of the list are path objects. 

-

 

-

        With the optional 'pattern' argument, this only lists 

-

        items whose names match the given pattern. 

-

        """ 

-

        names = os.listdir(self) 

-

        if pattern is not None: 

-

            names = fnmatch.filter(names, pattern) 

-

        return [self / child for child in names] 

-

 

-

    def dirs(self, pattern=None): 

-

        """ D.dirs() -> List of this directory's subdirectories. 

-

 

-

        The elements of the list are path objects. 

-

        This does not walk recursively into subdirectories 

-

        (but see path.walkdirs). 

-

 

-

        With the optional 'pattern' argument, this only lists 

-

        directories whose names match the given pattern.  For 

-

        example, d.dirs('build-*'). 

-

        """ 

-

        return [p for p in self.listdir(pattern) if p.isdir()] 

-

 

-

    def files(self, pattern=None): 

-

        """ D.files() -> List of the files in this directory. 

-

 

-

        The elements of the list are path objects. 

-

        This does not walk into subdirectories (see path.walkfiles). 

-

 

-

        With the optional 'pattern' argument, this only lists files 

-

        whose names match the given pattern.  For example, 

-

        d.files('*.pyc'). 

-

        """ 

-

 

-

        return [p for p in self.listdir(pattern) if p.isfile()] 

-

 

-

    def walk(self, pattern=None): 

-

        """ D.walk() -> iterator over files and subdirs, recursively. 

-

 

-

        The iterator yields path objects naming each child item of 

-

        this directory and its descendants.  This requires that 

-

        D.isdir(). 

-

 

-

        This performs a depth-first traversal of the directory tree. 

-

        Each directory is returned just before all its children. 

-

        """ 

-

        for child in self.listdir(): 

-

            if pattern is None or child.fnmatch(pattern): 

-

                yield child 

-

            if child.isdir(): 

-

                for item in child.walk(pattern): 

-

                    yield item 

-

 

-

    def walkdirs(self, pattern=None): 

-

        """ D.walkdirs() -> iterator over subdirs, recursively. 

-

 

-

        With the optional 'pattern' argument, this yields only 

-

        directories whose names match the given pattern.  For 

-

        example, mydir.walkdirs('*test') yields only directories 

-

        with names ending in 'test'. 

-

        """ 

-

        for child in self.dirs(): 

-

            if pattern is None or child.fnmatch(pattern): 

-

                yield child 

-

            for subsubdir in child.walkdirs(pattern): 

-

                yield subsubdir 

-

 

-

    def walkfiles(self, pattern=None): 

-

        """ D.walkfiles() -> iterator over files in D, recursively. 

-

 

-

        The optional argument, pattern, limits the results to files 

-

        with names that match the pattern.  For example, 

-

        mydir.walkfiles('*.tmp') yields only files with the .tmp 

-

        extension. 

-

        """ 

-

        for child in self.listdir(): 

-

            if child.isfile(): 

-

                if pattern is None or child.fnmatch(pattern): 

-

                    yield child 

-

            elif child.isdir(): 

-

                for f in child.walkfiles(pattern): 

-

                    yield f 

-

 

-

    def fnmatch(self, pattern): 

-

        """ Return True if self.name matches the given pattern. 

-

 

-

        pattern - A filename pattern with wildcards, 

-

            for example '*.py'. 

-

        """ 

-

        return fnmatch.fnmatch(self.name, pattern) 

-

 

-

    def glob(self, pattern): 

-

        """ Return a list of path objects that match the pattern. 

-

 

-

        pattern - a path relative to this directory, with wildcards. 

-

 

-

        For example, path('/users').glob('*/bin/*') returns a list 

-

        of all the files users have in their bin directories. 

-

        """ 

-

        return map(path, glob.glob(_base(self / pattern))) 

-

 

-

 

-

    # --- Reading or writing an entire file at once. 

-

 

-

    def open(self, mode='r'): 

-

        """ Open this file.  Return a file object. """ 

-

        return file(self, mode) 

-

 

-

    def bytes(self): 

-

        """ Open this file, read all bytes, return them as a string. """ 

-

        f = self.open('rb') 

-

        try: 

-

            return f.read() 

-

        finally: 

-

            f.close() 

-

 

-

    def write_bytes(self, bytes, append=False): 

-

        """ Open this file and write the given bytes to it. 

-

 

-

        Default behavior is to overwrite any existing file. 

-

        Call this with write_bytes(bytes, append=True) to append instead. 

-

        """ 

-

        if append: 

-

            mode = 'ab' 

-

        else: 

-

            mode = 'wb' 

-

        f = self.open(mode) 

-

        try: 

-

            f.write(bytes) 

-

        finally: 

-

            f.close() 

-

 

-

    def text(self, encoding=None, errors='strict'): 

-

        """ Open this file, read it in, return the content as a string. 

-

 

-

        This uses 'U' mode in Python 2.3 and later, so '\r\n' and '\r' 

-

        are automatically translated to '\n'. 

-

 

-

        Optional arguments: 

-

 

-

        encoding - The Unicode encoding (or character set) of 

-

            the file.  If present, the content of the file is 

-

            decoded and returned as a unicode object; otherwise 

-

            it is returned as an 8-bit str. 

-

        errors - How to handle Unicode errors; see help(str.decode) 

-

            for the options.  Default is 'strict'. 

-

        """ 

-

        if encoding is None: 

-

            # 8-bit 

-

            f = self.open(_textmode) 

-

            try: 

-

                return f.read() 

-

            finally: 

-

                f.close() 

-

        else: 

-

            # Unicode 

-

            f = codecs.open(self, 'r', encoding, errors) 

-

            # (Note - Can't use 'U' mode here, since codecs.open 

-

            # doesn't support 'U' mode, even in Python 2.3.) 

-

            try: 

-

                t = f.read() 

-

            finally: 

-

                f.close() 

-

            return t.replace(u'\r\n', u'\n').replace(u'\r', u'\n') 

-

 

-

    def write_text(self, text, encoding=None, errors='strict', append=False): 

-

        """ Write the given text to this file. 

-

 

-

        The default behavior is to overwrite any existing file; 

-

        to append instead, use the 'append=True' keyword argument. 

-

 

-

        There are two differences between path.write_text() and 

-

        path.write_bytes(): Unicode handling and newline handling. 

-

 

-

        --- Unicode 

-

 

-

        If 'text' isn't Unicode, this essentially just does 

-

        open(self, 'w').write(text).  The 'encoding' and 'errors' 

-

        arguments are ignored. 

-

 

-

        If 'text' is Unicode, it is first converted to bytes using the 

-

        specified 'encoding' (or the default encoding if 'encoding' 

-

        isn't specified).  The 'errors' argument applies only to this 

-

        conversion. 

-

 

-

        --- Newlines 

-

 

-

        write_text() converts from programmer-friendly newlines 

-

        (always '\n') to platform-specific newlines (see os.linesep; 

-

        on Windows, for example, the end-of-line marker is '\r\n'). 

-

        This applies to Unicode text the same as to 8-bit text. 

-

 

-

        Because of this conversion, the text should only contain plain 

-

        newlines ('\n'), just like the return value of path.text(). 

-

        If the text contains the characters '\r\n', it may be written 

-

        as '\r\r\n' or '\r\r' depending on your platform.  (This is 

-

        exactly the same as when you open a file for writing with 

-

        fopen(filename, "w") in C or file(filename, 'w') in Python.) 

-

        """ 

-

        if isinstance(text, unicode): 

-

            text = text.replace(u'\n', os.linesep) 

-

            if encoding is None: 

-

                encoding = sys.getdefaultencoding() 

-

            bytes = text.encode(encoding, errors) 

-

            self.write_bytes(bytes, append) 

-

        else: 

-

            if append: 

-

                mode = 'a' 

-

            else: 

-

                mode = 'w' 

-

            f = self.open(mode) 

-

            try: 

-

                f.write(text) 

-

            finally: 

-

                f.close() 

-

 

-

    def lines(self, encoding=None, errors='strict', retain=True): 

-

        """ Open this file, read all lines, return them in a list. 

-

 

-

        Optional arguments: 

-

            encoding - The Unicode encoding (or character set) of 

-

                the file.  The default is None, meaning the content 

-

                of the file is read as 8-bit characters and returned 

-

                as a list of (non-Unicode) str objects. 

-

            errors - How to handle Unicode errors; see help(str.decode) 

-

                for the options.  Default is 'strict' 

-

            retain - If true, retain newline characters; but all newline 

-

                character combinations ('\r', '\n', '\r\n') are 

-

                translated to '\n'.  If false, newline characters are 

-

                stripped off.  Default is True. 

-

 

-

        This uses 'U' mode in Python 2.3 and later. 

-

        """ 

-

        if encoding is None and retain: 

-

            f = self.open(_textmode) 

-

            try: 

-

                return f.readlines() 

-

            finally: 

-

                f.close() 

-

        else: 

-

            return self.text(encoding, errors).splitlines(retain) 

-

 

-

    def write_lines(self, lines, encoding=None, errors='strict', 

-

                    linesep=os.linesep): 

-

        """ Overwrite this file with the given lines of text. 

-

 

-

        lines - A list of strings. 

-

        encoding - A Unicode encoding to use.  This applies only if 

-

            'lines' contains any Unicode strings. 

-

        errors - How to handle errors in Unicode encoding.  This 

-

            also applies only to Unicode strings. 

-

        linesep - A character sequence that will be added at the 

-

            end of every line that doesn't already have it. 

-

        """ 

-

        f = self.open('wb') 

-

        try: 

-

            for line in lines: 

-

                if not line.endswith(linesep): 

-

                    line += linesep 

-

                if isinstance(line, unicode): 

-

                    if encoding is None: 

-

                        encoding = sys.getdefaultencoding() 

-

                    line = line.encode(encoding, errors=errors) 

-

                f.write(line) 

-

        finally: 

-

            f.close() 

-

 

-

 

-

    # --- Methods for querying the filesystem. 

-

 

-

    exists = os.path.exists 

-

    isabs = os.path.isabs 

-

    isdir = os.path.isdir 

-

    isfile = os.path.isfile 

-

    islink = os.path.islink 

-

    ismount = os.path.ismount 

-

 

-

    if hasattr(os.path, 'samefile'): 

-

        samefile = os.path.samefile 

-

 

-

    getatime = os.path.getatime 

-

    atime = property( 

-

        getatime, None, None, 

-

        """ Last access time of the file. """) 

-

 

-

    getmtime = os.path.getmtime 

-

    mtime = property( 

-

        getmtime, None, None, 

-

        """ Last-modified time of the file. """) 

-

 

-

    if hasattr(os.path, 'getctime'): 

-

        getctime = os.path.getctime 

-

        ctime = property( 

-

            getctime, None, None, 

-

            """ Creation time of the file. """) 

-

 

-

    getsize = os.path.getsize 

-

    size = property( 

-

        getsize, None, None, 

-

        """ Size of the file, in bytes. """) 

-

 

-

    if hasattr(os, 'access'): 

-

        def access(self, mode): 

-

            """ Return true if current user has access to this path. 

-

 

-

            mode - One of the constants os.F_OK, os.R_OK, os.W_OK, os.X_OK 

-

            """ 

-

            return os.access(self, mode) 

-

 

-

    def stat(self): 

-

        """ Perform a stat() system call on this path. """ 

-

        return os.stat(self) 

-

 

-

    def lstat(self): 

-

        """ Like path.stat(), but do not follow symbolic links. """ 

-

        return os.lstat(self) 

-

 

-

    if hasattr(os, 'statvfs'): 

-

        def statvfs(self): 

-

            """ Perform a statvfs() system call on this path. """ 

-

            return os.statvfs(self) 

-

 

-

    if hasattr(os, 'pathconf'): 

-

        def pathconf(self, name): 

-

            return os.pathconf(self, name) 

-

 

-

 

-

    # --- Modifying operations on files and directories 

-

 

-

    def utime(self, times): 

-

        """ Set the access and modified times of this file. """ 

-

        os.utime(self, times) 

-

 

-

    def chmod(self, mode): 

-

        os.chmod(self, mode) 

-

 

-

    if hasattr(os, 'chown'): 

-

        def chown(self, uid, gid): 

-

            os.chown(self, uid, gid) 

-

 

-

    def rename(self, new): 

-

        os.rename(self, new) 

-

 

-

    def renames(self, new): 

-

        os.renames(self, new) 

-

 

-

 

-

    # --- Create/delete operations on directories 

-

 

-

    def mkdir(self, mode=0777): 

-

        os.mkdir(self, mode) 

-

 

-

    def makedirs(self, mode=0777): 

-

        os.makedirs(self, mode) 

-

 

-

    def rmdir(self): 

-

        os.rmdir(self) 

-

 

-

    def removedirs(self): 

-

        os.removedirs(self) 

-

 

-

 

-

    # --- Modifying operations on files 

-

 

-

    def touch(self): 

-

        """ Set the access/modified times of this file to the current time. 

-

        Create the file if it does not exist. 

-

        """ 

-

        fd = os.open(self, os.O_WRONLY | os.O_CREAT, 0666) 

-

        os.close(fd) 

-

        os.utime(self, None) 

-

 

-

    def remove(self): 

-

        os.remove(self) 

-

 

-

    def unlink(self): 

-

        os.unlink(self) 

-

 

-

 

-

    # --- Links 

-

 

-

    if hasattr(os, 'link'): 

-

        def link(self, newpath): 

-

            """ Create a hard link at 'newpath', pointing to this file. """ 

-

            os.link(self, newpath) 

-

 

-

    if hasattr(os, 'symlink'): 

-

        def symlink(self, newlink): 

-

            """ Create a symbolic link at 'newlink', pointing here. """ 

-

            os.symlink(self, newlink) 

-

 

-

    if hasattr(os, 'readlink'): 

-

        def readlink(self): 

-

            """ Return the path to which this symbolic link points. 

-

 

-

            The result may be an absolute or a relative path. 

-

            """ 

-

            return path(os.readlink(self)) 

-

 

-

        def readlinkabs(self): 

-

            """ Return the path to which this symbolic link points. 

-

 

-

            The result is always an absolute path. 

-

            """ 

-

            p = self.readlink() 

-

            if p.isabs(): 

-

                return p 

-

            else: 

-

                return (self.parent / p).abspath() 

-

 

-

 

-

    # --- High-level functions from shutil 

-

 

-

    copyfile = shutil.copyfile 

-

    copymode = shutil.copymode 

-

    copystat = shutil.copystat 

-

    copy = shutil.copy 

-

    copy2 = shutil.copy2 

-

    copytree = shutil.copytree 

-

    if hasattr(shutil, 'move'): 

-

        move = shutil.move 

-

    rmtree = shutil.rmtree 

-

 

-

 

-

    # --- Special stuff from os 

-

 

-

    if hasattr(os, 'chroot'): 

-

        def chroot(self): 

-

            os.chroot(self) 

-

 

-

    if hasattr(os, 'startfile'): 

-

        def startfile(self): 

-

            os.startfile(self) 

-

 

+

""" path.py - An object representing a path to a file or directory. 

+

 

+

Example: 

+

 

+

from path import path 

+

d = path('/home/guido/bin') 

+

for f in d.files('*.py'): 

+

    f.chmod(0755) 

+

 

+

This module requires Python 2.2 or later. 

+

 

+

 

+

URL:     http://www.jorendorff.com/articles/python/path 

+

Author:  Jason Orendorff <jason@jorendorff.com> (and others - see the url!) 

+

Date:    29 Feb 2004 

+

""" 

+

 

+

 

+

# TODO 

+

#   - Bug in write_text().  It doesn't support Universal newline mode. 

+

#   - Better error message in listdir() when self isn't a 

+

#     directory. (On Windows, the error message really sucks.) 

+

#   - Make sure everything has a good docstring. 

+

#   - Add methods for regex find and replace. 

+

#   - guess_content_type() method? 

+

#   - Perhaps support arguments to touch(). 

+

#   - Could add split() and join() methods that generate warnings. 

+

#   - Note:  __add__() technically has a bug, I think, where 

+

#     it doesn't play nice with other types that implement 

+

#     __radd__().  Test this. 

+

 

+

from __future__ import generators 

+

 

+

import sys, os, fnmatch, glob, shutil, codecs 

+

 

+

__version__ = '2.0.2' 

+

__all__ = ['path'] 

+

 

+

# Pre-2.3 support.  Are unicode filenames supported? 

+

_base = str 

+

try: 

+

48    if os.path.supports_unicode_filenames: 

+

        _base = unicode 

+

except AttributeError: 

+

    pass 

+

 

+

# Pre-2.3 workaround for basestring. 

+

try: 

+

    basestring 

+

except NameError: 

+

    basestring = (str, unicode) 

+

 

+

# Universal newline support 

+

_textmode = 'r' 

+

59if hasattr(file, 'newlines'): 

+

    _textmode = 'U' 

+

 

+

 

+

class path(_base): 

+

    """ Represents a filesystem path. 

+

 

+

    For documentation on individual methods, consult their 

+

    counterparts in os.path. 

+

    """ 

+

 

+

    # --- Special Python methods. 

+

 

+

    def __repr__(self): 

+

        return 'path(%s)' % _base.__repr__(self) 

+

 

+

    # Adding a path and a string yields a path. 

+

    def __add__(self, more): 

+

        return path(_base(self) + more) 

+

 

+

    def __radd__(self, other): 

+

        return path(other + _base(self)) 

+

 

+

    # The / operator joins paths. 

+

    def __div__(self, rel): 

+

        """ fp.__div__(rel) == fp / rel == fp.joinpath(rel) 

+

 

+

        Join two path components, adding a separator character if 

+

        needed. 

+

        """ 

+

        return path(os.path.join(self, rel)) 

+

 

+

    # Make the / operator work even when true division is enabled. 

+

    __truediv__ = __div__ 

+

 

+

    def getcwd(): 

+

        """ Return the current working directory as a path object. """ 

+

        return path(os.getcwd()) 

+

    getcwd = staticmethod(getcwd) 

+

 

+

 

+

    # --- Operations on path strings. 

+

 

+

exit    def abspath(self):       return path(os.path.abspath(self)) 

+

exit    def normcase(self):      return path(os.path.normcase(self)) 

+

exit    def normpath(self):      return path(os.path.normpath(self)) 

+

exit    def realpath(self):      return path(os.path.realpath(self)) 

+

exit    def expanduser(self):    return path(os.path.expanduser(self)) 

+

exit    def expandvars(self):    return path(os.path.expandvars(self)) 

+

exit    def dirname(self):       return path(os.path.dirname(self)) 

+

    basename = os.path.basename 

+

 

+

    def expand(self): 

+

        """ Clean up a filename by calling expandvars(), 

+

        expanduser(), and normpath() on it. 

+

 

+

        This is commonly everything needed to clean up a filename 

+

        read from a configuration file, for example. 

+

        """ 

+

        return self.expandvars().expanduser().normpath() 

+

 

+

    def _get_namebase(self): 

+

        base, ext = os.path.splitext(self.name) 

+

        return base 

+

 

+

    def _get_ext(self): 

+

        f, ext = os.path.splitext(_base(self)) 

+

        return ext 

+

 

+

    def _get_drive(self): 

+

        drive, r = os.path.splitdrive(self) 

+

        return path(drive) 

+

 

+

    parent = property( 

+

        dirname, None, None, 

+

        """ This path's parent directory, as a new path object. 

+

 

+

        For example, path('/usr/local/lib/libpython.so').parent == path('/usr/local/lib') 

+

        """) 

+

 

+

    name = property( 

+

        basename, None, None, 

+

        """ The name of this file or directory without the full path. 

+

 

+

        For example, path('/usr/local/lib/libpython.so').name == 'libpython.so' 

+

        """) 

+

 

+

    namebase = property( 

+

        _get_namebase, None, None, 

+

        """ The same as path.name, but with one file extension stripped off. 

+

 

+

        For example, path('/home/guido/python.tar.gz').name     == 'python.tar.gz', 

+

        but          path('/home/guido/python.tar.gz').namebase == 'python.tar' 

+

        """) 

+

 

+

    ext = property( 

+

        _get_ext, None, None, 

+

        """ The file extension, for example '.py'. """) 

+

 

+

    drive = property( 

+

        _get_drive, None, None, 

+

        """ The drive specifier, for example 'C:'. 

+

        This is always empty on systems that don't use drive specifiers. 

+

        """) 

+

 

+

    def splitpath(self): 

+

        """ p.splitpath() -> Return (p.parent, p.name). """ 

+

        parent, child = os.path.split(self) 

+

        return path(parent), child 

+

 

+

    def splitdrive(self): 

+

        """ p.splitdrive() -> Return (p.drive, <the rest of p>). 

+

 

+

        Split the drive specifier from this path.  If there is 

+

        no drive specifier, p.drive is empty, so the return value 

+

        is simply (path(''), p).  This is always the case on Unix. 

+

        """ 

+

        drive, rel = os.path.splitdrive(self) 

+

        return path(drive), rel 

+

 

+

    def splitext(self): 

+

        """ p.splitext() -> Return (p.stripext(), p.ext). 

+

 

+

        Split the filename extension from this path and return 

+

        the two parts.  Either part may be empty. 

+

 

+

        The extension is everything from '.' to the end of the 

+

        last path segment.  This has the property that if 

+

        (a, b) == p.splitext(), then a + b == p. 

+

        """ 

+

        # Cast to plain string using _base because Python 2.2 

+

        # implementations of os.path.splitext use "for c in path:..." 

+

        # which means something different when applied to a path 

+

        # object. 

+

        filename, ext = os.path.splitext(_base(self)) 

+

        return path(filename), ext 

+

 

+

    def stripext(self): 

+

        """ p.stripext() -> Remove one file extension from the path. 

+

 

+

        For example, path('/home/guido/python.tar.gz').stripext() 

+

        returns path('/home/guido/python.tar'). 

+

        """ 

+

        return self.splitext()[0] 

+

 

+

214    if hasattr(os.path, 'splitunc'): 

+

        def splitunc(self): 

+

            unc, rest = os.path.splitunc(self) 

+

            return path(unc), rest 

+

 

+

        def _get_uncshare(self): 

+

            unc, r = os.path.splitunc(self) 

+

            return path(unc) 

+

 

+

        uncshare = property( 

+

            _get_uncshare, None, None, 

+

            """ The UNC mount point for this path. 

+

            This is empty for paths on local drives. """) 

+

 

+

    def joinpath(self, *args): 

+

        """ Join two or more path components, adding a separator 

+

        character (os.sep) if needed.  Returns a new path 

+

        object. 

+

        """ 

+

        return path(os.path.join(self, *args)) 

+

 

+

    def splitall(self): 

+

        """ Return a list of the path components in this path. 

+

 

+

        The first item in the list will be a path.  Its value will be 

+

        either os.curdir, os.pardir, empty, or the root directory of 

+

        this path (for example, '/' or 'C:\\').  The other items in 

+

        the list will be strings. 

+

 

+

        path.path.joinpath(*result) will yield the original path. 

+

        """ 

+

        parts = [] 

+

        loc = self 

+

        while loc != os.curdir and loc != os.pardir: 

+

            prev = loc 

+

            loc, child = prev.splitpath() 

+

            if loc == prev: 

+

                break 

+

            parts.append(child) 

+

        parts.append(loc) 

+

        parts.reverse() 

+

        return parts 

+

 

+

    def relpath(self): 

+

        """ Return this path as a relative path, 

+

        based from the current working directory. 

+

        """ 

+

        cwd = path(os.getcwd()) 

+

        return cwd.relpathto(self) 

+

 

+

    def relpathto(self, dest): 

+

        """ Return a relative path from self to dest. 

+

 

+

        If there is no relative path from self to dest, for example if 

+

        they reside on different drives in Windows, then this returns 

+

        dest.abspath(). 

+

        """ 

+

        origin = self.abspath() 

+

        dest = path(dest).abspath() 

+

 

+

        orig_list = origin.normcase().splitall() 

+

        # Don't normcase dest!  We want to preserve the case. 

+

        dest_list = dest.splitall() 

+

 

+

        if orig_list[0] != os.path.normcase(dest_list[0]): 

+

            # Can't get here from there. 

+

            return dest 

+

 

+

        # Find the location where the two paths start to differ. 

+

        i = 0 

+

        for start_seg, dest_seg in zip(orig_list, dest_list): 

+

            if start_seg != os.path.normcase(dest_seg): 

+

                break 

+

            i += 1 

+

 

+

        # Now i is the point where the two paths diverge. 

+

        # Need a certain number of "os.pardir"s to work up 

+

        # from the origin to the point of divergence. 

+

        segments = [os.pardir] * (len(orig_list) - i) 

+

        # Need to add the diverging part of dest_list. 

+

        segments += dest_list[i:] 

+

        if len(segments) == 0: 

+

            # If they happen to be identical, use os.curdir. 

+

            return path(os.curdir) 

+

        else: 

+

            return path(os.path.join(*segments)) 

+

 

+

 

+

    # --- Listing, searching, walking, and matching 

+

 

+

    def listdir(self, pattern=None): 

+

        """ D.listdir() -> List of items in this directory. 

+

 

+

        Use D.files() or D.dirs() instead if you want a listing 

+

        of just files or just subdirectories. 

+

 

+

        The elements of the list are path objects. 

+

 

+

        With the optional 'pattern' argument, this only lists 

+

        items whose names match the given pattern. 

+

        """ 

+

        names = os.listdir(self) 

+

        if pattern is not None: 

+

            names = fnmatch.filter(names, pattern) 

+

        return [self / child for child in names] 

+

 

+

    def dirs(self, pattern=None): 

+

        """ D.dirs() -> List of this directory's subdirectories. 

+

 

+

        The elements of the list are path objects. 

+

        This does not walk recursively into subdirectories 

+

        (but see path.walkdirs). 

+

 

+

        With the optional 'pattern' argument, this only lists 

+

        directories whose names match the given pattern.  For 

+

        example, d.dirs('build-*'). 

+

        """ 

+

        return [p for p in self.listdir(pattern) if p.isdir()] 

+

 

+

    def files(self, pattern=None): 

+

        """ D.files() -> List of the files in this directory. 

+

 

+

        The elements of the list are path objects. 

+

        This does not walk into subdirectories (see path.walkfiles). 

+

 

+

        With the optional 'pattern' argument, this only lists files 

+

        whose names match the given pattern.  For example, 

+

        d.files('*.pyc'). 

+

        """ 

+

 

+

        return [p for p in self.listdir(pattern) if p.isfile()] 

+

 

+

    def walk(self, pattern=None): 

+

        """ D.walk() -> iterator over files and subdirs, recursively. 

+

 

+

        The iterator yields path objects naming each child item of 

+

        this directory and its descendants.  This requires that 

+

        D.isdir(). 

+

 

+

        This performs a depth-first traversal of the directory tree. 

+

        Each directory is returned just before all its children. 

+

        """ 

+

        for child in self.listdir(): 

+

            if pattern is None or child.fnmatch(pattern): 

+

                yield child 

+

            if child.isdir(): 

+

                for item in child.walk(pattern): 

+

                    yield item 

+

 

+

    def walkdirs(self, pattern=None): 

+

        """ D.walkdirs() -> iterator over subdirs, recursively. 

+

 

+

        With the optional 'pattern' argument, this yields only 

+

        directories whose names match the given pattern.  For 

+

        example, mydir.walkdirs('*test') yields only directories 

+

        with names ending in 'test'. 

+

        """ 

+

        for child in self.dirs(): 

+

            if pattern is None or child.fnmatch(pattern): 

+

                yield child 

+

            for subsubdir in child.walkdirs(pattern): 

+

                yield subsubdir 

+

 

+

    def walkfiles(self, pattern=None): 

+

        """ D.walkfiles() -> iterator over files in D, recursively. 

+

 

+

        The optional argument, pattern, limits the results to files 

+

        with names that match the pattern.  For example, 

+

        mydir.walkfiles('*.tmp') yields only files with the .tmp 

+

        extension. 

+

        """ 

+

        for child in self.listdir(): 

+

            if child.isfile(): 

+

                if pattern is None or child.fnmatch(pattern): 

+

                    yield child 

+

            elif child.isdir(): 

+

                for f in child.walkfiles(pattern): 

+

                    yield f 

+

 

+

    def fnmatch(self, pattern): 

+

        """ Return True if self.name matches the given pattern. 

+

 

+

        pattern - A filename pattern with wildcards, 

+

            for example '*.py'. 

+

        """ 

+

        return fnmatch.fnmatch(self.name, pattern) 

+

 

+

    def glob(self, pattern): 

+

        """ Return a list of path objects that match the pattern. 

+

 

+

        pattern - a path relative to this directory, with wildcards. 

+

 

+

        For example, path('/users').glob('*/bin/*') returns a list 

+

        of all the files users have in their bin directories. 

+

        """ 

+

        return map(path, glob.glob(_base(self / pattern))) 

+

 

+

 

+

    # --- Reading or writing an entire file at once. 

+

 

+

    def open(self, mode='r'): 

+

        """ Open this file.  Return a file object. """ 

+

        return file(self, mode) 

+

 

+

    def bytes(self): 

+

        """ Open this file, read all bytes, return them as a string. """ 

+

        f = self.open('rb') 

+

        try: 

+

            return f.read() 

+

        finally: 

+

            f.close() 

+

 

+

    def write_bytes(self, bytes, append=False): 

+

        """ Open this file and write the given bytes to it. 

+

 

+

        Default behavior is to overwrite any existing file. 

+

        Call this with write_bytes(bytes, append=True) to append instead. 

+

        """ 

+

        if append: 

+

            mode = 'ab' 

+

        else: 

+

            mode = 'wb' 

+

        f = self.open(mode) 

+

        try: 

+

            f.write(bytes) 

+

        finally: 

+

            f.close() 

+

 

+

    def text(self, encoding=None, errors='strict'): 

+

        """ Open this file, read it in, return the content as a string. 

+

 

+

        This uses 'U' mode in Python 2.3 and later, so '\r\n' and '\r' 

+

        are automatically translated to '\n'. 

+

 

+

        Optional arguments: 

+

 

+

        encoding - The Unicode encoding (or character set) of 

+

            the file.  If present, the content of the file is 

+

            decoded and returned as a unicode object; otherwise 

+

            it is returned as an 8-bit str. 

+

        errors - How to handle Unicode errors; see help(str.decode) 

+

            for the options.  Default is 'strict'. 

+

        """ 

+

        if encoding is None: 

+

            # 8-bit 

+

            f = self.open(_textmode) 

+

            try: 

+

                return f.read() 

+

            finally: 

+

                f.close() 

+

        else: 

+

            # Unicode 

+

            f = codecs.open(self, 'r', encoding, errors) 

+

            # (Note - Can't use 'U' mode here, since codecs.open 

+

            # doesn't support 'U' mode, even in Python 2.3.) 

+

            try: 

+

                t = f.read() 

+

            finally: 

+

                f.close() 

+

            return t.replace(u'\r\n', u'\n').replace(u'\r', u'\n') 

+

 

+

    def write_text(self, text, encoding=None, errors='strict', append=False): 

+

        """ Write the given text to this file. 

+

 

+

        The default behavior is to overwrite any existing file; 

+

        to append instead, use the 'append=True' keyword argument. 

+

 

+

        There are two differences between path.write_text() and 

+

        path.write_bytes(): Unicode handling and newline handling. 

+

 

+

        --- Unicode 

+

 

+

        If 'text' isn't Unicode, this essentially just does 

+

        open(self, 'w').write(text).  The 'encoding' and 'errors' 

+

        arguments are ignored. 

+

 

+

        If 'text' is Unicode, it is first converted to bytes using the 

+

        specified 'encoding' (or the default encoding if 'encoding' 

+

        isn't specified).  The 'errors' argument applies only to this 

+

        conversion. 

+

 

+

        --- Newlines 

+

 

+

        write_text() converts from programmer-friendly newlines 

+

        (always '\n') to platform-specific newlines (see os.linesep; 

+

        on Windows, for example, the end-of-line marker is '\r\n'). 

+

        This applies to Unicode text the same as to 8-bit text. 

+

 

+

        Because of this conversion, the text should only contain plain 

+

        newlines ('\n'), just like the return value of path.text(). 

+

        If the text contains the characters '\r\n', it may be written 

+

        as '\r\r\n' or '\r\r' depending on your platform.  (This is 

+

        exactly the same as when you open a file for writing with 

+

        fopen(filename, "w") in C or file(filename, 'w') in Python.) 

+

        """ 

+

        if isinstance(text, unicode): 

+

            text = text.replace(u'\n', os.linesep) 

+

            if encoding is None: 

+

                encoding = sys.getdefaultencoding() 

+

            bytes = text.encode(encoding, errors) 

+

            self.write_bytes(bytes, append) 

+

        else: 

+

            if append: 

+

                mode = 'a' 

+

            else: 

+

                mode = 'w' 

+

            f = self.open(mode) 

+

            try: 

+

                f.write(text) 

+

            finally: 

+

                f.close() 

+

 

+

    def lines(self, encoding=None, errors='strict', retain=True): 

+

        """ Open this file, read all lines, return them in a list. 

+

 

+

        Optional arguments: 

+

            encoding - The Unicode encoding (or character set) of 

+

                the file.  The default is None, meaning the content 

+

                of the file is read as 8-bit characters and returned 

+

                as a list of (non-Unicode) str objects. 

+

            errors - How to handle Unicode errors; see help(str.decode) 

+

                for the options.  Default is 'strict' 

+

            retain - If true, retain newline characters; but all newline 

+

                character combinations ('\r', '\n', '\r\n') are 

+

                translated to '\n'.  If false, newline characters are 

+

                stripped off.  Default is True. 

+

 

+

        This uses 'U' mode in Python 2.3 and later. 

+

        """ 

+

        if encoding is None and retain: 

+

            f = self.open(_textmode) 

+

            try: 

+

                return f.readlines() 

+

            finally: 

+

                f.close() 

+

        else: 

+

            return self.text(encoding, errors).splitlines(retain) 

+

 

+

    def write_lines(self, lines, encoding=None, errors='strict', 

+

                    linesep=os.linesep): 

+

        """ Overwrite this file with the given lines of text. 

+

 

+

        lines - A list of strings. 

+

        encoding - A Unicode encoding to use.  This applies only if 

+

            'lines' contains any Unicode strings. 

+

        errors - How to handle errors in Unicode encoding.  This 

+

            also applies only to Unicode strings. 

+

        linesep - A character sequence that will be added at the 

+

            end of every line that doesn't already have it. 

+

        """ 

+

        f = self.open('wb') 

+

        try: 

+

            for line in lines: 

+

                if not line.endswith(linesep): 

+

                    line += linesep 

+

                if isinstance(line, unicode): 

+

                    if encoding is None: 

+

                        encoding = sys.getdefaultencoding() 

+

                    line = line.encode(encoding, errors=errors) 

+

                f.write(line) 

+

        finally: 

+

            f.close() 

+

 

+

 

+

    # --- Methods for querying the filesystem. 

+

 

+

    exists = os.path.exists 

+

    isabs = os.path.isabs 

+

    isdir = os.path.isdir 

+

    isfile = os.path.isfile 

+

    islink = os.path.islink 

+

    ismount = os.path.ismount 

+

 

+

574    if hasattr(os.path, 'samefile'): 

+

        samefile = os.path.samefile 

+

 

+

    getatime = os.path.getatime 

+

    atime = property( 

+

        getatime, None, None, 

+

        """ Last access time of the file. """) 

+

 

+

    getmtime = os.path.getmtime 

+

    mtime = property( 

+

        getmtime, None, None, 

+

        """ Last-modified time of the file. """) 

+

 

+

592    if hasattr(os.path, 'getctime'): 

+

        getctime = os.path.getctime 

+

        ctime = property( 

+

            getctime, None, None, 

+

            """ Creation time of the file. """) 

+

 

+

    getsize = os.path.getsize 

+

    size = property( 

+

        getsize, None, None, 

+

        """ Size of the file, in bytes. """) 

+

 

+

605    if hasattr(os, 'access'): 

+

        def access(self, mode): 

+

            """ Return true if current user has access to this path. 

+

 

+

            mode - One of the constants os.F_OK, os.R_OK, os.W_OK, os.X_OK 

+

            """ 

+

            return os.access(self, mode) 

+

 

+

    def stat(self): 

+

        """ Perform a stat() system call on this path. """ 

+

        return os.stat(self) 

+

 

+

    def lstat(self): 

+

        """ Like path.stat(), but do not follow symbolic links. """ 

+

        return os.lstat(self) 

+

 

+

614    if hasattr(os, 'statvfs'): 

+

        def statvfs(self): 

+

            """ Perform a statvfs() system call on this path. """ 

+

            return os.statvfs(self) 

+

 

+

619    if hasattr(os, 'pathconf'): 

+

        def pathconf(self, name): 

+

            return os.pathconf(self, name) 

+

 

+

 

+

    # --- Modifying operations on files and directories 

+

 

+

    def utime(self, times): 

+

        """ Set the access and modified times of this file. """ 

+

        os.utime(self, times) 

+

 

+

    def chmod(self, mode): 

+

        os.chmod(self, mode) 

+

 

+

633    if hasattr(os, 'chown'): 

+

        def chown(self, uid, gid): 

+

            os.chown(self, uid, gid) 

+

 

+

    def rename(self, new): 

+

        os.rename(self, new) 

+

 

+

    def renames(self, new): 

+

        os.renames(self, new) 

+

 

+

 

+

    # --- Create/delete operations on directories 

+

 

+

    def mkdir(self, mode=0777): 

+

        os.mkdir(self, mode) 

+

 

+

    def makedirs(self, mode=0777): 

+

        os.makedirs(self, mode) 

+

 

+

    def rmdir(self): 

+

        os.rmdir(self) 

+

 

+

    def removedirs(self): 

+

        os.removedirs(self) 

+

 

+

 

+

    # --- Modifying operations on files 

+

 

+

    def touch(self): 

+

        """ Set the access/modified times of this file to the current time. 

+

        Create the file if it does not exist. 

+

        """ 

+

        fd = os.open(self, os.O_WRONLY | os.O_CREAT, 0666) 

+

        os.close(fd) 

+

        os.utime(self, None) 

+

 

+

    def remove(self): 

+

        os.remove(self) 

+

 

+

    def unlink(self): 

+

        os.unlink(self) 

+

 

+

 

+

    # --- Links 

+

 

+

678    if hasattr(os, 'link'): 

+

        def link(self, newpath): 

+

            """ Create a hard link at 'newpath', pointing to this file. """ 

+

            os.link(self, newpath) 

+

 

+

683    if hasattr(os, 'symlink'): 

+

        def symlink(self, newlink): 

+

            """ Create a symbolic link at 'newlink', pointing here. """ 

+

            os.symlink(self, newlink) 

+

 

+

688    if hasattr(os, 'readlink'): 

+

        def readlink(self): 

+

            """ Return the path to which this symbolic link points. 

+

 

+

            The result may be an absolute or a relative path. 

+

            """ 

+

            return path(os.readlink(self)) 

+

 

+

        def readlinkabs(self): 

+

            """ Return the path to which this symbolic link points. 

+

 

+

            The result is always an absolute path. 

+

            """ 

+

            p = self.readlink() 

+

            if p.isabs(): 

+

                return p 

+

            else: 

+

                return (self.parent / p).abspath() 

+

 

+

 

+

    # --- High-level functions from shutil 

+

 

+

    copyfile = shutil.copyfile 

+

    copymode = shutil.copymode 

+

    copystat = shutil.copystat 

+

    copy = shutil.copy 

+

    copy2 = shutil.copy2 

+

    copytree = shutil.copytree 

+

717    if hasattr(shutil, 'move'): 

+

        move = shutil.move 

+

    rmtree = shutil.rmtree 

+

 

+

 

+

    # --- Special stuff from os 

+

 

+

723    if hasattr(os, 'chroot'): 

+

        def chroot(self): 

+

            os.chroot(self) 

+

 

+

exit    if hasattr(os, 'startfile'): 

+

        def startfile(self): 

+

            os.startfile(self) 

+

 

diff --git a/doc/sample_html/cogapp_cogapp.html b/doc/sample_html/cogapp_cogapp.html index 555756f..df5b434 100644 --- a/doc/sample_html/cogapp_cogapp.html +++ b/doc/sample_html/cogapp_cogapp.html @@ -1,19 +1,21 @@ - + + Coverage for cogapp\cogapp - - + @@ -22,13 +24,16 @@ function toggle_lines(btn, cls) { @@ -43,22 +48,22 @@ function toggle_lines(btn, cls) {

4

5

6

-

7

-

8

+

7

+

8

9

10

-

11

-

12

-

13

+

11

+

12

+

13

14

15

16

17

-

18

+

18

19

-

20

+

20

21

-

22

+

22

23

24

25

@@ -86,127 +91,127 @@ function toggle_lines(btn, cls) {

47

48

49

-

50

+

50

51

-

52

+

52

53

54

-

55

-

56

-

57

+

55

+

56

+

57

58

59

60

-

61

+

61

62

63

64

65

-

66

+

66

67

68

69

70

-

71

+

71

72

73

74

75

-

76

+

76

77

78

-

79

-

80

-

81

+

79

+

80

+

81

82

-

83

+

83

84

85

-

86

-

87

-

88

+

86

+

87

+

88

89

90

-

91

+

91

92

93

-

94

-

95

-

96

-

97

+

94

+

95

+

96

+

97

98

-

99

-

100

+

99

+

100

101

-

102

-

103

+

102

+

103

104

-

105

+

105

106

107

108

109

110

-

111

-

112

-

113

-

114

+

111

+

112

+

113

+

114

115

-

116

+

116

117

-

118

+

118

119

-

120

+

120

121

-

122

-

123

-

124

+

122

+

123

+

124

125

126

-

127

-

128

+

127

+

128

129

130

-

131

-

132

-

133

-

134

+

131

+

132

+

133

+

134

135

-

136

-

137

+

136

+

137

138

139

140

141

-

142

-

143

+

142

+

143

144

-

145

+

145

146

-

147

+

147

148

149

-

150

+

150

151

152

-

153

-

154

-

155

-

156

-

157

-

158

-

159

-

160

-

161

-

162

+

153

+

154

+

155

+

156

+

157

+

158

+

159

+

160

+

161

+

162

163

-

164

+

164

165

166

-

167

-

168

+

167

+

168

169

-

170

+

170

171

172

173

@@ -215,60 +220,60 @@ function toggle_lines(btn, cls) {

176

177

178

-

179

+

179

180

181

-

182

-

183

-

184

+

182

+

183

+

184

185

-

186

-

187

-

188

-

189

-

190

+

186

+

187

+

188

+

189

+

190

191

-

192

-

193

+

192

+

193

194

195

-

196

+

196

197

198

-

199

+

199

200

-

201

-

202

-

203

-

204

-

205

-

206

-

207

-

208

-

209

-

210

-

211

-

212

-

213

-

214

+

201

+

202

+

203

+

204

+

205

+

206

+

207

+

208

+

209

+

210

+

211

+

212

+

213

+

214

215

-

216

+

216

217

218

219

220

-

221

+

221

222

223

224

225

-

226

+

226

227

228

229

230

231

-

232

+

232

233

234

235

@@ -311,7 +316,7 @@ function toggle_lines(btn, cls) {

272

273

274

-

275

+

275

276

277

278

@@ -321,174 +326,174 @@ function toggle_lines(btn, cls) {

282

283

284

-

285

+

285

286

287

-

288

-

289

-

290

-

291

-

292

-

293

-

294

+

288

+

289

+

290

+

291

+

292

+

293

+

294

295

-

296

-

297

+

296

+

297

298

-

299

+

299

300

-

301

+

301

302

303

-

304

-

305

+

304

+

305

306

-

307

-

308

+

307

+

308

309

310

-

311

-

312

+

311

+

312

313

-

314

+

314

315

316

317

-

318

-

319

-

320

+

318

+

319

+

320

321

-

322

+

322

323

324

325

326

-

327

-

328

-

329

+

327

+

328

+

329

330

-

331

+

331

332

333

334

-

335

+

335

336

337

338

339

-

340

-

341

+

340

+

341

342

-

343

+

343

344

-

345

-

346

+

345

+

346

347

348

-

349

-

350

+

349

+

350

351

352

-

353

+

353

354

355

-

356

-

357

+

356

+

357

358

-

359

-

360

+

359

+

360

361

362

-

363

+

363

364

365

-

366

-

367

-

368

-

369

-

370

-

371

+

366

+

367

+

368

+

369

+

370

+

371

372

373

-

374

-

375

-

376

-

377

-

378

+

374

+

375

+

376

+

377

+

378

379

380

381

-

382

-

383

-

384

-

385

-

386

+

382

+

383

+

384

+

385

+

386

387

388

-

389

-

390

+

389

+

390

391

392

-

393

+

393

394

395

-

396

-

397

+

396

+

397

398

399

-

400

+

400

401

402

-

403

-

404

-

405

-

406

-

407

+

403

+

404

+

405

+

406

+

407

408

409

410

411

-

412

-

413

-

414

+

412

+

413

+

414

415

-

416

+

416

417

418

419

-

420

-

421

-

422

+

420

+

421

+

422

423

424

-

425

+

425

426

427

-

428

-

429

-

430

+

428

+

429

+

430

431

-

432

+

432

433

434

435

436

437

438

-

439

-

440

-

441

-

442

-

443

-

444

-

445

-

446

+

439

+

440

+

441

+

442

+

443

+

444

+

445

+

446

447

-

448

+

448

449

450

-

451

-

452

+

451

+

452

453

454

455

@@ -503,45 +508,45 @@ function toggle_lines(btn, cls) {

464

465

466

-

467

+

467

468

469

-

470

-

471

-

472

+

470

+

471

+

472

473

-

474

+

474

475

476

-

477

+

477

478

-

479

+

479

480

481

482

483

-

484

+

484

485

-

486

+

486

487

488

489

-

490

+

490

491

492

493

-

494

+

494

495

-

496

+

496

497

498

499

-

500

-

501

-

502

-

503

+

500

+

501

+

502

+

503

504

-

505

+

505

506

507

508

@@ -559,20 +564,20 @@ function toggle_lines(btn, cls) {

520

521

522

-

523

+

523

524

525

526

-

527

+

527

528

529

530

531

-

532

+

532

533

534

535

-

536

+

536

537

538

539

@@ -620,7 +625,7 @@ function toggle_lines(btn, cls) {

581

582

583

-

584

+

584

585

586

587

@@ -637,7 +642,7 @@ function toggle_lines(btn, cls) {

598

599

600

-

601

+

601

602

603

604

@@ -655,7 +660,7 @@ function toggle_lines(btn, cls) {

616

617

618

-

619

+

619

620

621

622

@@ -680,7 +685,7 @@ function toggle_lines(btn, cls) {

641

642

643

-

644

+

644

645

646

647

@@ -749,715 +754,715 @@ function toggle_lines(btn, cls) { -

""" 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): 

-

        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. 

-

        """ 

-

        if stdout: 

-

            self.stdout = stdout 

-

        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] 

-

            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. 

-

        if isinstance(fIn, basestring): 

-

            # Open the input file. 

-

            sFileIn = fIn 

-

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

-

        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. 

-

            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): 

-

                    if self.isEndSpecLine(l): 

-

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

-

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

-

                    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 

-

                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): 

-

                        if self.isBeginSpecLine(l): 

-

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

-

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

-

                        if self.isEndOutputLine(l): 

-

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

-

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

-

                        if not self.options.bDeleteCode: 

-

                            fOut.write(l) 

-

                        gen.parseLine(l) 

-

                        l = fIn.readline() 

-

                    if not l: 

-

                        raise CogError( 

-

                            "Cog block begun but never ended.", 

-

                            file=sFileIn, line=firstLineNum) 

-

 

-

                    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): 

-

                    if self.isBeginSpecLine(l): 

-

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

-

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

-

                    if self.isEndSpecLine(l): 

-

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

-

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

-

                    hasher.update(l) 

-

                    l = fIn.readline() 

-

                curHash = hasher.hexdigest() 

-

 

-

                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() 

-

                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) 

-

                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. 

-

                    if hashMatch: 

-

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

-

 

-

                if not self.options.bDeleteCode: 

-

                    fOut.write(l) 

-

                l = fIn.readline() 

-

 

-

            if not bSawCog and self.options.bWarnEmpty: 

-

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

-

        finally: 

-

            if fInToClose: 

-

                fInToClose.close() 

-

            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. 

-

        """ 

-

        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. 

+

""" 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. 

diff --git a/doc/sample_html/cogapp_makefiles.html b/doc/sample_html/cogapp_makefiles.html index 4d50521..8dfb26b 100644 --- a/doc/sample_html/cogapp_makefiles.html +++ b/doc/sample_html/cogapp_makefiles.html @@ -1,19 +1,21 @@ - + + Coverage for cogapp\makefiles - - + @@ -22,13 +24,16 @@ function toggle_lines(btn, cls) { @@ -43,13 +48,13 @@ function toggle_lines(btn, cls) {

4

5

6

-

7

-

8

+

7

+

8

9

-

10

-

11

+

10

+

11

12

-

13

+

13

14

15

16

@@ -69,7 +74,7 @@ function toggle_lines(btn, cls) {

30

31

32

-

33

+

33

34

35

36

@@ -104,70 +109,70 @@ function toggle_lines(btn, cls) { -

""" Dictionary-to-filetree functions, to create test files for testing. 

-

    http://nedbatchelder.com/code/cog 

-

     

-

    Copyright 2004-2009, Ned Batchelder. 

-

""" 

-

 

-

import path     # Non-standard, from http://www.jorendorff.com/articles/python/path 

-

from whiteutils import reindentBlock 

-

 

-

__version__ = '1.0.20040126' 

-

__all__ = ['makeFiles', 'removeFiles'] 

-

 

-

def makeFiles(d, basedir='.', raw=False): 

-

    """ Create files from the dictionary d, in the directory named by dirpath. 

-

    """ 

-

    dirpath = path.path(basedir) 

-

    for name, contents in d.items(): 

-

        child = dirpath / name 

-

        if isinstance(contents, basestring): 

-

            mode = 'w' 

-

            if raw: 

-

                mode = 'wb' 

-

            f = open(child, mode) 

-

            if not raw: 

-

                contents = reindentBlock(contents) 

-

            f.write(contents) 

-

            f.close() 

-

        else: 

-

            if not child.exists(): 

-

                child.mkdir() 

-

            makeFiles(contents, child, raw=raw) 

-

 

-

def removeFiles(d, basedir='.'): 

-

    """ Remove the files created by makeFiles. 

-

        Directories are removed if they are empty. 

-

    """ 

-

    dirpath = path.path(basedir) 

-

    for name, contents in d.items(): 

-

        child = dirpath / name 

-

        if isinstance(contents, basestring): 

-

            child.remove() 

-

        else: 

-

            removeFiles(contents, child) 

-

            if not child.files() and not child.dirs(): 

-

                child.rmdir() 

-

 

-

if __name__ == '__main__':      #pragma: no cover 

-

    # Try it a little. 

-

    d = { 

-

        'test_makefiles': { 

-

            'hey.txt': """\ 

-

                        This is hey.txt. 

-

                        It's very simple. 

-

                        """, 

-

            'subdir': { 

-

                'fooey': """\ 

-

                            # Fooey 

-

                                Kablooey 

-

                            Ew. 

-

                            """ 

-

            } 

-

        } 

-

    } 

-

    makeFiles(d) 

+

""" Dictionary-to-filetree functions, to create test files for testing. 

+

    http://nedbatchelder.com/code/cog 

+

     

+

    Copyright 2004-2009, Ned Batchelder. 

+

""" 

+

 

+

import path     # Non-standard, from http://www.jorendorff.com/articles/python/path 

+

from whiteutils import reindentBlock 

+

 

+

__version__ = '1.0.20040126' 

+

__all__ = ['makeFiles', 'removeFiles'] 

+

 

+

def makeFiles(d, basedir='.', raw=False): 

+

    """ Create files from the dictionary d, in the directory named by dirpath. 

+

    """ 

+

    dirpath = path.path(basedir) 

+

    for name, contents in d.items(): 

+

        child = dirpath / name 

+

        if isinstance(contents, basestring): 

+

            mode = 'w' 

+

            if raw: 

+

                mode = 'wb' 

+

            f = open(child, mode) 

+

            if not raw: 

+

                contents = reindentBlock(contents) 

+

            f.write(contents) 

+

            f.close() 

+

        else: 

+

            if not child.exists(): 

+

                child.mkdir() 

+

            makeFiles(contents, child, raw=raw) 

+

 

+

def removeFiles(d, basedir='.'): 

+

    """ Remove the files created by makeFiles. 

+

        Directories are removed if they are empty. 

+

    """ 

+

    dirpath = path.path(basedir) 

+

    for name, contents in d.items(): 

+

        child = dirpath / name 

+

        if isinstance(contents, basestring): 

+

            child.remove() 

+

        else: 

+

            removeFiles(contents, child) 

+

            if not child.files() and not child.dirs(): 

+

                child.rmdir() 

+

 

+

if __name__ == '__main__':      #pragma: no cover 

+

    # Try it a little. 

+

    d = { 

+

        'test_makefiles': { 

+

            'hey.txt': """\ 

+

                        This is hey.txt. 

+

                        It's very simple. 

+

                        """, 

+

            'subdir': { 

+

                'fooey': """\ 

+

                            # Fooey 

+

                                Kablooey 

+

                            Ew. 

+

                            """ 

+

            } 

+

        } 

+

    } 

+

    makeFiles(d) 

diff --git a/doc/sample_html/cogapp_test_cogapp.html b/doc/sample_html/cogapp_test_cogapp.html index 23355ae..2efc88e 100644 --- a/doc/sample_html/cogapp_test_cogapp.html +++ b/doc/sample_html/cogapp_test_cogapp.html @@ -1,19 +1,21 @@ - + + Coverage for cogapp\test_cogapp - - + @@ -26,9 +28,12 @@ function toggle_lines(btn, cls) {

587 statements - 195 run + 195 run 17 excluded 392 missing + + 0 partial +

@@ -43,32 +48,32 @@ function toggle_lines(btn, cls) {

4

5

6

-

7

-

8

-

9

-

10

-

11

-

12

-

13

-

14

+

7

+

8

+

9

+

10

+

11

+

12

+

13

+

14

15

-

16

+

16

17

18

-

19

+

19

20

21

22

-

23

-

24

-

25

-

26

-

27

+

23

+

24

+

25

+

26

+

27

28

29

-

30

+

30

31

-

32

+

32

33

34

35

@@ -79,12 +84,12 @@ function toggle_lines(btn, cls) {

40

41

42

-

43

+

43

44

45

46

-

47

-

48

+

47

+

48

49

50

51

@@ -92,11 +97,11 @@ function toggle_lines(btn, cls) {

53

54

55

-

56

-

57

+

56

+

57

58

-

59

-

60

+

59

+

60

61

62

63

@@ -108,7 +113,7 @@ function toggle_lines(btn, cls) {

69

70

71

-

72

+

72

73

74

75

@@ -122,12 +127,12 @@ function toggle_lines(btn, cls) {

83

84

85

-

86

+

86

87

-

88

+

88

89

90

-

91

+

91

92

93

94

@@ -135,12 +140,12 @@ function toggle_lines(btn, cls) {

96

97

98

-

99

-

100

+

99

+

100

101

-

102

+

102

103

-

104

+

104

105

106

107

@@ -159,11 +164,11 @@ function toggle_lines(btn, cls) {

120

121

122

-

123

-

124

+

123

+

124

125

-

126

-

127

+

126

+

127

128

129

130

@@ -177,11 +182,11 @@ function toggle_lines(btn, cls) {

138

139

140

-

141

-

142

+

141

+

142

143

-

144

-

145

+

144

+

145

146

147

148

@@ -196,13 +201,13 @@ function toggle_lines(btn, cls) {

157

158

159

-

160

-

161

+

160

+

161

162

-

163

+

163

164

165

-

166

+

166

167

168

169

@@ -214,11 +219,11 @@ function toggle_lines(btn, cls) {

175

176

177

-

178

-

179

+

178

+

179

180

-

181

-

182

+

181

+

182

183

184

185

@@ -232,11 +237,11 @@ function toggle_lines(btn, cls) {

193

194

195

-

196

-

197

+

196

+

197

198

-

199

-

200

+

199

+

200

201

202

203

@@ -248,11 +253,11 @@ function toggle_lines(btn, cls) {

209

210

211

-

212

-

213

+

212

+

213

214

-

215

-

216

+

215

+

216

217

218

219

@@ -265,11 +270,11 @@ function toggle_lines(btn, cls) {

226

227

228

-

229

-

230

+

229

+

230

231

-

232

-

233

+

232

+

233

234

235

236

@@ -283,13 +288,13 @@ function toggle_lines(btn, cls) {

244

245

246

-

247

-

248

+

247

+

248

249

-

250

+

250

251

252

-

253

+

253

254

255

256

@@ -301,12 +306,12 @@ function toggle_lines(btn, cls) {

262

263

264

-

265

-

266

+

265

+

266

267

-

268

+

268

269

-

270

+

270

271

272

273

@@ -315,14 +320,14 @@ function toggle_lines(btn, cls) {

276

277

278

-

279

-

280

+

279

+

280

281

-

282

+

282

283

284

285

-

286

+

286

287

288

289

@@ -335,14 +340,14 @@ function toggle_lines(btn, cls) {

296

297

298

-

299

-

300

+

299

+

300

301

-

302

+

302

303

304

305

-

306

+

306

307

308

309

@@ -360,11 +365,11 @@ function toggle_lines(btn, cls) {

321

322

323

-

324

-

325

+

324

+

325

326

-

327

-

328

+

327

+

328

329

330

331

@@ -379,11 +384,11 @@ function toggle_lines(btn, cls) {

340

341

342

-

343

-

344

+

343

+

344

345

-

346

-

347

+

346

+

347

348

349

350

@@ -391,7 +396,7 @@ function toggle_lines(btn, cls) {

352

353

354

-

355

+

355

356

357

358

@@ -399,24 +404,24 @@ function toggle_lines(btn, cls) {

360

361

362

-

363

-

364

+

363

+

364

365

-

366

-

367

+

366

+

367

368

369

370

371

372

373

-

374

+

374

375

376

377

378

-

379

-

380

+

379

+

380

381

382

383

@@ -426,7 +431,7 @@ function toggle_lines(btn, cls) {

387

388

389

-

390

+

390

391

392

393

@@ -437,14 +442,14 @@ function toggle_lines(btn, cls) {

398

399

400

-

401

-

402

+

401

+

402

403

-

404

+

404

405

406

407

-

408

+

408

409

410

411

@@ -453,7 +458,7 @@ function toggle_lines(btn, cls) {

414

415

416

-

417

+

417

418

419

420

@@ -464,7 +469,7 @@ function toggle_lines(btn, cls) {

425

426

427

-

428

+

428

429

430

431

@@ -472,18 +477,18 @@ function toggle_lines(btn, cls) {

433

434

435

-

436

+

436

437

438

439

440

-

441

+

441

442

443

444

445

446

-

447

+

447

448

449

450

@@ -491,7 +496,7 @@ function toggle_lines(btn, cls) {

452

453

454

-

455

+

455

456

457

458

@@ -511,7 +516,7 @@ function toggle_lines(btn, cls) {

472

473

474

-

475

+

475

476

477

478

@@ -526,7 +531,7 @@ function toggle_lines(btn, cls) {

487

488

489

-

490

+

490

491

492

493

@@ -541,7 +546,7 @@ function toggle_lines(btn, cls) {

502

503

504

-

505

+

505

506

507

508

@@ -560,7 +565,7 @@ function toggle_lines(btn, cls) {

521

522

523

-

524

+

524

525

526

527

@@ -583,7 +588,7 @@ function toggle_lines(btn, cls) {

544

545

546

-

547

+

547

548

549

550

@@ -606,11 +611,11 @@ function toggle_lines(btn, cls) {

567

568

569

-

570

+

570

571

572

573

-

574

+

574

575

576

577

@@ -621,7 +626,7 @@ function toggle_lines(btn, cls) {

582

583

584

-

585

+

585

586

587

588

@@ -632,7 +637,7 @@ function toggle_lines(btn, cls) {

593

594

595

-

596

+

596

597

598

599

@@ -650,12 +655,12 @@ function toggle_lines(btn, cls) {

611

612

613

-

614

+

614

615

616

617

618

-

619

+

619

620

621

622

@@ -663,19 +668,19 @@ function toggle_lines(btn, cls) {

624

625

626

-

627

+

627

628

629

630

631

-

632

+

632

633

634

635

636

637

638

-

639

+

639

640

641

642

@@ -683,7 +688,7 @@ function toggle_lines(btn, cls) {

644

645

646

-

647

+

647

648

649

650

@@ -691,7 +696,7 @@ function toggle_lines(btn, cls) {

652

653

654

-

655

+

655

656

657

658

@@ -699,7 +704,7 @@ function toggle_lines(btn, cls) {

660

661

662

-

663

+

663

664

665

666

@@ -707,7 +712,7 @@ function toggle_lines(btn, cls) {

668

669

670

-

671

+

671

672

673

674

@@ -717,9 +722,9 @@ function toggle_lines(btn, cls) {

678

679

680

-

681

+

681

682

-

683

+

683

684

685

686

@@ -727,7 +732,7 @@ function toggle_lines(btn, cls) {

688

689

690

-

691

+

691

692

693

694

@@ -735,15 +740,15 @@ function toggle_lines(btn, cls) {

696

697

698

-

699

+

699

700

701

702

703

-

704

+

704

705

706

-

707

+

707

708

709

710

@@ -753,9 +758,9 @@ function toggle_lines(btn, cls) {

714

715

716

-

717

+

717

718

-

719

+

719

720

721

722

@@ -763,7 +768,7 @@ function toggle_lines(btn, cls) {

724

725

726

-

727

+

727

728

729

730

@@ -773,25 +778,25 @@ function toggle_lines(btn, cls) {

734

735

736

-

737

+

737

738

739

740

741

-

742

+

742

743

744

745

746

747

-

748

+

748

749

750

751

752

753

754

-

755

+

755

756

757

758

@@ -801,7 +806,7 @@ function toggle_lines(btn, cls) {

762

763

764

-

765

+

765

766

767

768

@@ -833,14 +838,14 @@ function toggle_lines(btn, cls) {

794

795

796

-

797

+

797

798

799

800

801

-

802

+

802

803

-

804

+

804

805

806

807

@@ -872,7 +877,7 @@ function toggle_lines(btn, cls) {

833

834

835

-

836

+

836

837

838

839

@@ -903,7 +908,7 @@ function toggle_lines(btn, cls) {

864

865

866

-

867

+

867

868

869

870

@@ -950,7 +955,7 @@ function toggle_lines(btn, cls) {

911

912

913

-

914

+

914

915

916

917

@@ -1001,7 +1006,7 @@ function toggle_lines(btn, cls) {

962

963

964

-

965

+

965

966

967

968

@@ -1043,7 +1048,7 @@ function toggle_lines(btn, cls) {

1004

1005

1006

-

1007

+

1007

1008

1009

1010

@@ -1063,7 +1068,7 @@ function toggle_lines(btn, cls) {

1024

1025

1026

-

1027

+

1027

1028

1029

1030

@@ -1109,10 +1114,10 @@ function toggle_lines(btn, cls) {

1070

1071

1072

-

1073

+

1073

1074

1075

-

1076

+

1076

1077

1078

1079

@@ -1121,7 +1126,7 @@ function toggle_lines(btn, cls) {

1082

1083

1084

-

1085

+

1085

1086

1087

1088

@@ -1130,38 +1135,38 @@ function toggle_lines(btn, cls) {

1091

1092

1093

-

1094

+

1094

1095

1096

1097

1098

-

1099

+

1099

1100

1101

1102

1103

-

1104

+

1104

1105

1106

1107

1108

-

1109

+

1109

1110

1111

1112

1113

1114

-

1115

+

1115

1116

1117

1118

1119

1120

-

1121

+

1121

1122

1123

1124

-

1125

+

1125

1126

1127

1128

@@ -1172,8 +1177,8 @@ function toggle_lines(btn, cls) {

1133

1134

1135

-

1136

-

1137

+

1136

+

1137

1138

1139

1140

@@ -1219,36 +1224,36 @@ function toggle_lines(btn, cls) {

1180

1181

1182

-

1183

+

1183

1184

1185

1186

1187

-

1188

+

1188

1189

1190

1191

1192

1193

-

1194

+

1194

1195

1196

1197

1198

1199

-

1200

+

1200

1201

1202

1203

1204

1205

-

1206

+

1206

1207

1208

1209

1210

1211

-

1212

+

1212

1213

1214

1215

@@ -1290,7 +1295,7 @@ function toggle_lines(btn, cls) {

1251

1252

1253

-

1254

+

1254

1255

1256

1257

@@ -1324,9 +1329,9 @@ function toggle_lines(btn, cls) {

1285

1286

1287

-

1288

+

1288

1289

-

1290

+

1290

1291

1292

1293

@@ -1356,7 +1361,7 @@ function toggle_lines(btn, cls) {

1317

1318

1319

-

1320

+

1320

1321

1322

1323

@@ -1390,7 +1395,7 @@ function toggle_lines(btn, cls) {

1351

1352

1353

-

1354

+

1354

1355

1356

1357

@@ -1444,7 +1449,7 @@ function toggle_lines(btn, cls) {

1405

1406

1407

-

1408

+

1408

1409

1410

1411

@@ -1486,7 +1491,7 @@ function toggle_lines(btn, cls) {

1447

1448

1449

-

1450

+

1450

1451

1452

1453

@@ -1498,7 +1503,7 @@ function toggle_lines(btn, cls) {

1459

1460

1461

-

1462

+

1462

1463

1464

1465

@@ -1523,7 +1528,7 @@ function toggle_lines(btn, cls) {

1484

1485

1486

-

1487

+

1487

1488

1489

1490

@@ -1562,7 +1567,7 @@ function toggle_lines(btn, cls) {

1523

1524

1525

-

1526

+

1526

1527

1528

1529

@@ -1579,7 +1584,7 @@ function toggle_lines(btn, cls) {

1540

1541

1542

-

1543

+

1543

1544

1545

1546

@@ -1604,7 +1609,7 @@ function toggle_lines(btn, cls) {

1565

1566

1567

-

1568

+

1568

1569

1570

1571

@@ -1624,7 +1629,7 @@ function toggle_lines(btn, cls) {

1585

1586

1587

-

1588

+

1588

1589

1590

1591

@@ -1642,9 +1647,9 @@ function toggle_lines(btn, cls) {

1603

1604

1605

-

1606

+

1606

1607

-

1608

+

1608

1609

1610

1611

@@ -1674,42 +1679,42 @@ function toggle_lines(btn, cls) {

1635

1636

1637

-

1638

+

1638

1639

1640

1641

1642

1643

1644

-

1645

+

1645

1646

1647

1648

-

1649

+

1649

1650

1651

1652

1653

1654

-

1655

+

1655

1656

1657

1658

1659

-

1660

+

1660

1661

1662

1663

1664

-

1665

+

1665

1666

1667

1668

1669

1670

-

1671

+

1671

1672

-

1673

+

1673

1674

1675

1676

@@ -1734,7 +1739,7 @@ function toggle_lines(btn, cls) {

1695

1696

1697

-

1698

+

1698

1699

1700

1701

@@ -1763,7 +1768,7 @@ function toggle_lines(btn, cls) {

1724

1725

1726

-

1727

+

1727

1728

1729

1730

@@ -1792,7 +1797,7 @@ function toggle_lines(btn, cls) {

1753

1754

1755

-

1756

+

1756

1757

1758

1759

@@ -1886,10 +1891,10 @@ function toggle_lines(btn, cls) {

1847

1848

1849

-

1850

+

1850

1851

1852

-

1853

+

1853

1854

1855

1856

@@ -1917,7 +1922,7 @@ function toggle_lines(btn, cls) {

1878

1879

1880

-

1881

+

1881

1882

1883

1884

@@ -1927,7 +1932,7 @@ function toggle_lines(btn, cls) {

1888

1889

1890

-

1891

+

1891

1892

1893

1894

@@ -1955,9 +1960,9 @@ function toggle_lines(btn, cls) {

1916

1917

1918

-

1919

+

1919

1920

-

1921

+

1921

1922

1923

1924

@@ -1973,7 +1978,7 @@ function toggle_lines(btn, cls) {

1934

1935

1936

-

1937

+

1937

1938

1939

1940

@@ -2000,1966 +2005,1966 @@ function toggle_lines(btn, cls) { -

""" Test cogapp. 

-

    http://nedbatchelder.com/code/cog 

-

     

-

    Copyright 2004-2009, Ned Batchelder. 

-

""" 

-

 

-

import unittest 

-

import os, random, re, StringIO, stat, sys, tempfile 

-

import path     # Non-standard, from http://www.jorendorff.com/articles/python/path 

-

from cogapp import Cog, CogOptions, CogGenerator 

-

from cogapp import CogError, CogUsageError, CogGeneratedError 

-

from cogapp import usage, __version__ 

-

from whiteutils import reindentBlock 

-

from makefiles import * 

-

 

-

class TestCase(unittest.TestCase): 

-

    """ Base class for all Cog test cases.  Adds utility methods I like. 

-

    """ 

-

    def assertRaisesMsg(self, excClass, msg, callableObj, *args, **kwargs): 

-

        """ Just like unittest.TestCase.assertRaises, 

-

            but checks that the message is right too. 

-

        """ 

-

        try: 

-

            callableObj(*args, **kwargs) 

-

        except excClass, exc: 

-

            excMsg = str(exc) 

-

            if not msg: 

-

                # No message provided: it passes. 

-

                return  #pragma: no cover 

-

            elif excMsg == msg: 

-

                # Message provided, and we got the right message: it passes. 

-

                return 

-

            else:   #pragma: no cover 

-

                # Message provided, and it didn't match: fail! 

-

                raise self.failureException("Right exception, wrong message: got '%s' expected '%s'" % (excMsg, msg)) 

-

        else:   #pragma: no cover 

-

            if hasattr(excClass,'__name__'): 

-

                excName = excClass.__name__ 

-

            else: 

-

                excName = str(excClass) 

-

            raise self.failureException("Expected to raise %s, didn't get an exception at all" % excName) 

-

 

-

class CogTestsInMemory(TestCase): 

-

    """ Test cases for cogapp.Cog() 

-

    """ 

-

 

-

    def testNoCog(self): 

-

        strings = [ 

-

            '', 

-

            ' ', 

-

            ' \t \t \tx', 

-

            'hello', 

-

            'the cat\nin the\nhat.', 

-

            'Horton\n\tHears A\n\t\tWho' 

-

            ] 

-

        for s in strings: 

-

            self.assertEqual(Cog().processString(s), s) 

-

 

-

    def testSimple(self): 

-

        infile = """\ 

-

            Some text. 

-

            //[[[cog 

-

            import cog 

-

            cog.outl("This is line one\\n") 

-

            cog.outl("This is line two") 

-

            //]]] 

-

            gobbledegook. 

-

            //[[[end]]] 

-

            epilogue. 

-

            """ 

-

 

-

        outfile = """\ 

-

            Some text. 

-

            //[[[cog 

-

            import cog 

-

            cog.outl("This is line one\\n") 

-

            cog.outl("This is line two") 

-

            //]]] 

-

            This is line one 

-

 

-

            This is line two 

-

            //[[[end]]] 

-

            epilogue. 

-

            """ 

-

 

-

        self.assertEqual(Cog().processString(infile), outfile) 

-

 

-

    def testEmptyCog(self): 

-

        # The cog clause can be totally empty.  Not sure why you'd want it, 

-

        # but it works. 

-

        infile = """\ 

-

            hello 

-

            //[[[cog 

-

            //]]] 

-

            //[[[end]]] 

-

            goodbye 

-

            """ 

-

 

-

        infile = reindentBlock(infile) 

-

        self.assertEqual(Cog().processString(infile), infile) 

-

 

-

    def testMultipleCogs(self): 

-

        # One file can have many cog chunks, even abutting each other. 

-

        infile = """\ 

-

            //[[[cog 

-

            cog.out("chunk1") 

-

            //]]] 

-

            chunk1 

-

            //[[[end]]] 

-

            //[[[cog 

-

            cog.out("chunk2") 

-

            //]]] 

-

            chunk2 

-

            //[[[end]]] 

-

            between chunks 

-

            //[[[cog 

-

            cog.out("chunk3") 

-

            //]]] 

-

            chunk3 

-

            //[[[end]]] 

-

            """ 

-

 

-

        infile = reindentBlock(infile) 

-

        self.assertEqual(Cog().processString(infile), infile) 

-

 

-

    def testTrimBlankLines(self): 

-

        infile = """\ 

-

            //[[[cog 

-

            cog.out("This is line one\\n", trimblanklines=True) 

-

            cog.out(''' 

-

                This is line two 

-

            ''', dedent=True, trimblanklines=True) 

-

            cog.outl("This is line three", trimblanklines=True) 

-

            //]]] 

-

            This is line one 

-

            This is line two 

-

            This is line three 

-

            //[[[end]]] 

-

            """ 

-

 

-

        infile = reindentBlock(infile) 

-

        self.assertEqual(Cog().processString(infile), infile) 

-

 

-

    def testTrimEmptyBlankLines(self): 

-

        infile = """\ 

-

            //[[[cog 

-

            cog.out("This is line one\\n", trimblanklines=True) 

-

            cog.out(''' 

-

                This is line two 

-

            ''', dedent=True, trimblanklines=True) 

-

            cog.out('', dedent=True, trimblanklines=True) 

-

            cog.outl("This is line three", trimblanklines=True) 

-

            //]]] 

-

            This is line one 

-

            This is line two 

-

            This is line three 

-

            //[[[end]]] 

-

            """ 

-

 

-

        infile = reindentBlock(infile) 

-

        self.assertEqual(Cog().processString(infile), infile) 

-

 

-

    def test22EndOfLine(self): 

-

        # In Python 2.2, this cog file was not parsing because the 

-

        # last line is indented but didn't end with a newline. 

-

        infile = """\ 

-

            //[[[cog 

-

            import cog 

-

            for i in range(3): 

-

                cog.out("%d\\n" % i) 

-

            //]]] 

-

            0 

-

            1 

-

            2 

-

            //[[[end]]] 

-

            """ 

-

 

-

        infile = reindentBlock(infile) 

-

        self.assertEqual(Cog().processString(infile), infile) 

-

 

-

    def testIndentedCode(self): 

-

        infile = """\ 

-

            first line 

-

                [[[cog 

-

                import cog 

-

                for i in range(3): 

-

                    cog.out("xx%d\\n" % i) 

-

                ]]] 

-

                xx0 

-

                xx1 

-

                xx2 

-

                [[[end]]] 

-

            last line 

-

            """ 

-

 

-

        infile = reindentBlock(infile) 

-

        self.assertEqual(Cog().processString(infile), infile) 

-

 

-

    def testPrefixedCode(self): 

-

        infile = """\ 

-

            --[[[cog 

-

            --import cog 

-

            --for i in range(3): 

-

            --    cog.out("xx%d\\n" % i) 

-

            --]]] 

-

            xx0 

-

            xx1 

-

            xx2 

-

            --[[[end]]] 

-

            """ 

-

 

-

        infile = reindentBlock(infile) 

-

        self.assertEqual(Cog().processString(infile), infile) 

-

 

-

    def testPrefixedIndentedCode(self): 

-

        infile = """\ 

-

            prologue 

-

            --[[[cog 

-

            --   import cog 

-

            --   for i in range(3): 

-

            --       cog.out("xy%d\\n" % i) 

-

            --]]] 

-

            xy0 

-

            xy1 

-

            xy2 

-

            --[[[end]]] 

-

            """ 

-

 

-

        infile = reindentBlock(infile) 

-

        self.assertEqual(Cog().processString(infile), infile) 

-

 

-

    def testBogusPrefixMatch(self): 

-

        infile = """\ 

-

            prologue 

-

            #[[[cog 

-

                import cog 

-

                # This comment should not be clobbered by removing the pound sign. 

-

                for i in range(3): 

-

                    cog.out("xy%d\\n" % i) 

-

            #]]] 

-

            xy0 

-

            xy1 

-

            xy2 

-

            #[[[end]]] 

-

            """ 

-

 

-

        infile = reindentBlock(infile) 

-

        self.assertEqual(Cog().processString(infile), infile) 

-

 

-

    def testNoFinalNewline(self): 

-

        # If the cog'ed output has no final newline, 

-

        # it shouldn't eat up the cog terminator. 

-

        infile = """\ 

-

            prologue 

-

            [[[cog 

-

                import cog 

-

                for i in range(3): 

-

                    cog.out("%d" % i) 

-

            ]]] 

-

            012 

-

            [[[end]]] 

-

            epilogue 

-

            """ 

-

 

-

        infile = reindentBlock(infile) 

-

        self.assertEqual(Cog().processString(infile), infile) 

-

 

-

    def testNoOutputAtAll(self): 

-

        # If there is absolutely no cog output, that's ok. 

-

        infile = """\ 

-

            prologue 

-

            [[[cog 

-

                i = 1 

-

            ]]] 

-

            [[[end]]] 

-

            epilogue 

-

            """ 

-

 

-

        infile = reindentBlock(infile) 

-

        self.assertEqual(Cog().processString(infile), infile) 

-

 

-

    def testPurelyBlankLine(self): 

-

        # If there is a blank line in the cog code with no whitespace 

-

        # prefix, that should be OK. 

-

 

-

        infile = """\ 

-

            prologue 

-

                [[[cog 

-

                    import sys 

-

                    cog.out("Hello") 

-

            $ 

-

                    cog.out("There") 

-

                ]]] 

-

                HelloThere 

-

                [[[end]]] 

-

            epilogue 

-

            """ 

-

 

-

        infile = reindentBlock(infile.replace('$', '')) 

-

        self.assertEqual(Cog().processString(infile), infile) 

-

 

-

    def testEmptyOutl(self): 

-

        # Alexander Belchenko suggested the string argument to outl should 

-

        # be optional.  Does it work? 

-

 

-

        infile = """\ 

-

            prologue 

-

            [[[cog 

-

                cog.outl("x") 

-

                cog.outl() 

-

                cog.outl("y") 

-

                cog.outl(trimblanklines=True) 

-

                cog.outl("z") 

-

            ]]] 

-

            x 

-

 

-

            y 

-

             

-

            z 

-

            [[[end]]] 

-

            epilogue 

-

            """ 

-

 

-

        infile = reindentBlock(infile) 

-

        self.assertEqual(Cog().processString(infile), infile) 

-

 

-

    def testFirstLineNum(self): 

-

        infile = """\ 

-

            fooey 

-

            [[[cog 

-

                cog.outl("started at line number %d" % cog.firstLineNum) 

-

            ]]] 

-

            started at line number 2 

-

            [[[end]]] 

-

            blah blah 

-

            [[[cog 

-

                cog.outl("and again at line %d" % cog.firstLineNum) 

-

            ]]] 

-

            and again at line 8 

-

            [[[end]]] 

-

            """ 

-

 

-

        infile = reindentBlock(infile) 

-

        self.assertEqual(Cog().processString(infile), infile) 

-

 

-

    def testCompactOneLineCode(self): 

-

        infile = """\ 

-

            first line 

-

            hey: [[[cog cog.outl("hello %d" % (3*3*3*3)) ]]] looky! 

-

            get rid of this! 

-

            [[[end]]] 

-

            last line 

-

            """ 

-

 

-

        outfile = """\ 

-

            first line 

-

            hey: [[[cog cog.outl("hello %d" % (3*3*3*3)) ]]] looky! 

-

            hello 81 

-

            [[[end]]] 

-

            last line 

-

            """ 

-

 

-

        infile = reindentBlock(infile) 

-

        self.assertEqual(Cog().processString(infile), reindentBlock(outfile)) 

-

 

-

    def testInsideOutCompact(self): 

-

        infile = """\ 

-

            first line 

-

            hey?: ]]] what is this? [[[cog strange! 

-

            get rid of this! 

-

            [[[end]]] 

-

            last line 

-

            """ 

-

        self.assertRaisesMsg(CogError, 

-

             "infile.txt(2): Cog code markers inverted", 

-

             Cog().processString, 

-

             reindentBlock(infile), "infile.txt") 

-

 

-

    def testSharingGlobals(self): 

-

        infile = """\ 

-

            first line 

-

            hey: [[[cog s="hey there" ]]] looky! 

-

            [[[end]]] 

-

            more literal junk. 

-

            [[[cog cog.outl(s) ]]] 

-

            [[[end]]] 

-

            last line 

-

            """ 

-

 

-

        outfile = """\ 

-

            first line 

-

            hey: [[[cog s="hey there" ]]] looky! 

-

            [[[end]]] 

-

            more literal junk. 

-

            [[[cog cog.outl(s) ]]] 

-

            hey there 

-

            [[[end]]] 

-

            last line 

-

            """ 

-

 

-

        infile = reindentBlock(infile) 

-

        self.assertEqual(Cog().processString(infile), reindentBlock(outfile)) 

-

 

-

class CogOptionsTests(TestCase): 

-

    """ Test the CogOptions class. 

-

    """ 

-

 

-

    def testEquality(self): 

-

        o = CogOptions() 

-

        p = CogOptions() 

-

        self.assertEqual(o, p) 

-

        o.parseArgs(['-r']) 

-

        self.assertNotEqual(o, p) 

-

        p.parseArgs(['-r']) 

-

        self.assertEqual(o, p) 

-

 

-

    def testCloning(self): 

-

        o = CogOptions() 

-

        o.parseArgs(['-I', 'fooey', '-I', 'booey', '-s', ' /*x*/']) 

-

        p = o.clone() 

-

        self.assertEqual(o, p) 

-

        p.parseArgs(['-I', 'huey', '-D', 'foo=quux']) 

-

        self.assertNotEqual(o, p) 

-

        q = CogOptions() 

-

        q.parseArgs(['-I', 'fooey', '-I', 'booey', '-s', ' /*x*/', '-I', 'huey', '-D', 'foo=quux']) 

-

        self.assertEqual(p, q) 

-

 

-

    def testCombiningFlags(self): 

-

        # Single-character flags can be combined. 

-

        o = CogOptions() 

-

        o.parseArgs(['-e', '-r', '-z']) 

-

        p = CogOptions() 

-

        p.parseArgs(['-erz']) 

-

        self.assertEqual(o, p) 

-

 

-

class FileStructureTests(TestCase): 

-

    """ Test cases to check that we're properly strict about the structure 

-

        of files. 

-

    """ 

-

 

-

    def isBad(self, infile, msg=None): 

-

        infile = reindentBlock(infile) 

-

        self.assertRaisesMsg(CogError, 

-

            msg, 

-

            Cog().processString, (infile), 'infile.txt') 

-

 

-

    def testBeginNoEnd(self): 

-

        infile = """\ 

-

            Fooey 

-

            #[[[cog 

-

                cog.outl('hello') 

-

            """ 

-

        self.isBad(infile, "infile.txt(2): Cog block begun but never ended.") 

-

 

-

    def testNoEoo(self): 

-

        infile = """\ 

-

            Fooey 

-

            #[[[cog 

-

                cog.outl('hello') 

-

            #]]] 

-

            """ 

-

        self.isBad(infile, "infile.txt(4): Missing '[[[end]]]' before end of file.") 

-

 

-

        infile2 = """\ 

-

            Fooey 

-

            #[[[cog 

-

                cog.outl('hello') 

-

            #]]] 

-

            #[[[cog 

-

                cog.outl('goodbye') 

-

            #]]] 

-

            """ 

-

        self.isBad(infile2, "infile.txt(5): Unexpected '[[[cog'") 

-

 

-

    def testStartWithEnd(self): 

-

        infile = """\ 

-

            #]]] 

-

            """ 

-

        self.isBad(infile, "infile.txt(1): Unexpected ']]]'") 

-

 

-

        infile2 = """\ 

-

            #[[[cog 

-

                cog.outl('hello') 

-

            #]]] 

-

            #[[[end]]]     

-

            #]]] 

-

            """ 

-

        self.isBad(infile2, "infile.txt(5): Unexpected ']]]'") 

-

 

-

    def testStartWithEoo(self): 

-

        infile = """\ 

-

            #[[[end]]] 

-

            """ 

-

        self.isBad(infile, "infile.txt(1): Unexpected '[[[end]]]'") 

-

 

-

        infile2 = """\ 

-

            #[[[cog 

-

                cog.outl('hello') 

-

            #]]] 

-

            #[[[end]]] 

-

            #[[[end]]] 

-

            """ 

-

        self.isBad(infile2, "infile.txt(5): Unexpected '[[[end]]]'") 

-

 

-

    def testNoEnd(self): 

-

        infile = """\ 

-

            #[[[cog 

-

                cog.outl("hello") 

-

            #[[[end]]] 

-

            """ 

-

        self.isBad(infile, "infile.txt(3): Unexpected '[[[end]]]'") 

-

 

-

        infile2 = """\ 

-

            #[[[cog 

-

                cog.outl('hello') 

-

            #]]] 

-

            #[[[end]]] 

-

            #[[[cog 

-

                cog.outl("hello") 

-

            #[[[end]]] 

-

            """ 

-

        self.isBad(infile2, "infile.txt(7): Unexpected '[[[end]]]'") 

-

 

-

    def testTwoBegins(self): 

-

        infile = """\ 

-

            #[[[cog 

-

            #[[[cog 

-

                cog.outl("hello") 

-

            #]]] 

-

            #[[[end]]] 

-

            """ 

-

        self.isBad(infile, "infile.txt(2): Unexpected '[[[cog'") 

-

 

-

        infile2 = """\ 

-

            #[[[cog 

-

                cog.outl("hello") 

-

            #]]] 

-

            #[[[end]]] 

-

            #[[[cog 

-

            #[[[cog 

-

                cog.outl("hello") 

-

            #]]] 

-

            #[[[end]]] 

-

            """ 

-

        self.isBad(infile2, "infile.txt(6): Unexpected '[[[cog'") 

-

 

-

    def testTwoEnds(self): 

-

        infile = """\ 

-

            #[[[cog 

-

                cog.outl("hello") 

-

            #]]] 

-

            #]]] 

-

            #[[[end]]] 

-

            """ 

-

        self.isBad(infile, "infile.txt(4): Unexpected ']]]'") 

-

 

-

        infile2 = """\ 

-

            #[[[cog 

-

                cog.outl("hello") 

-

            #]]] 

-

            #[[[end]]] 

-

            #[[[cog 

-

                cog.outl("hello") 

-

            #]]] 

-

            #]]] 

-

            #[[[end]]] 

-

            """ 

-

        self.isBad(infile2, "infile.txt(8): Unexpected ']]]'") 

-

 

-

class CogErrorTests(TestCase): 

-

    """ Test cases for cog.error(). 

-

    """ 

-

 

-

    def testErrorMsg(self): 

-

        infile = """\ 

-

            [[[cog cog.error("This ain't right!")]]] 

-

            [[[end]]] 

-

            """ 

-

 

-

        infile = reindentBlock(infile) 

-

        self.assertRaisesMsg(CogGeneratedError, 

-

            "This ain't right!", 

-

            Cog().processString, (infile)) 

-

 

-

    def testErrorNoMsg(self): 

-

        infile = """\ 

-

            [[[cog cog.error()]]] 

-

            [[[end]]] 

-

            """ 

-

 

-

        infile = reindentBlock(infile) 

-

        self.assertRaisesMsg(CogGeneratedError, 

-

            "Error raised by cog generator.", 

-

            Cog().processString, (infile)) 

-

 

-

    def testNoErrorIfErrorNotCalled(self): 

-

        infile = """\ 

-

            --[[[cog 

-

            --import cog 

-

            --for i in range(3): 

-

            --    if i > 10: 

-

            --        cog.error("Something is amiss!") 

-

            --    cog.out("xx%d\\n" % i) 

-

            --]]] 

-

            xx0 

-

            xx1 

-

            xx2 

-

            --[[[end]]] 

-

            """ 

-

 

-

        infile = reindentBlock(infile) 

-

        self.assertEqual(Cog().processString(infile), infile) 

-

 

-

class CogGeneratorGetCodeTests(TestCase): 

-

    """ Unit tests against CogGenerator to see if its getCode() method works 

-

        properly. 

-

    """ 

-

 

-

    def setUp(self): 

-

        """ All tests get a generator to use, and short same-length names for 

-

            the functions we're going to use. 

-

        """ 

-

        self.gen = CogGenerator() 

-

        self.m = self.gen.parseMarker 

-

        self.l = self.gen.parseLine 

-

 

-

    def testEmpty(self): 

-

        self.m('// [[[cog') 

-

        self.m('// ]]]') 

-

        self.assertEqual(self.gen.getCode(), '') 

-

 

-

    def testSimple(self): 

-

        self.m('// [[[cog') 

-

        self.l('  print "hello"') 

-

        self.l('  print "bye"') 

-

        self.m('// ]]]') 

-

        self.assertEqual(self.gen.getCode(), 'print "hello"\nprint "bye"') 

-

 

-

    def testCompressed1(self): 

-

        # For a while, I supported compressed code blocks, but no longer. 

-

        self.m('// [[[cog: print """') 

-

        self.l('// hello') 

-

        self.l('// bye') 

-

        self.m('// """)]]]') 

-

        self.assertEqual(self.gen.getCode(), 'hello\nbye') 

-

 

-

    def testCompressed2(self): 

-

        # For a while, I supported compressed code blocks, but no longer. 

-

        self.m('// [[[cog: print """') 

-

        self.l('hello') 

-

        self.l('bye') 

-

        self.m('// """)]]]') 

-

        self.assertEqual(self.gen.getCode(), 'hello\nbye') 

-

 

-

    def testCompressed3(self): 

-

        # For a while, I supported compressed code blocks, but no longer. 

-

        self.m('// [[[cog') 

-

        self.l('print """hello') 

-

        self.l('bye') 

-

        self.m('// """)]]]') 

-

        self.assertEqual(self.gen.getCode(), 'print """hello\nbye') 

-

 

-

    def testCompressed4(self): 

-

        # For a while, I supported compressed code blocks, but no longer. 

-

        self.m('// [[[cog: print """') 

-

        self.l('hello') 

-

        self.l('bye""")') 

-

        self.m('// ]]]') 

-

        self.assertEqual(self.gen.getCode(), 'hello\nbye""")') 

-

 

-

    def testNoCommonPrefixForMarkers(self): 

-

        # It's important to be able to use #if 0 to hide lines from a 

-

        # C++ compiler. 

-

        self.m('#if 0 //[[[cog') 

-

        self.l('\timport cog, sys') 

-

        self.l('') 

-

        self.l('\tprint sys.argv') 

-

        self.m('#endif //]]]') 

-

        self.assertEqual(self.gen.getCode(), 'import cog, sys\n\nprint sys.argv') 

-

 

-

class TestCaseWithTempDir(TestCase): 

-

 

-

    def newCog(self): 

-

        """ Initialize the cog members for another run. 

-

        """ 

-

        # Create a cog engine, and catch its output. 

-

        self.cog = Cog() 

-

        self.output = StringIO.StringIO() 

-

        self.cog.setOutput(stdout=self.output, stderr=self.output) 

-

 

-

    def setUp(self): 

-

        # Create a temporary directory. 

-

        self.tempdir = path.path(tempfile.gettempdir()) / ('testcog_tempdir_' + str(random.random())[2:]) 

-

        self.tempdir.mkdir() 

-

        self.olddir = os.getcwd() 

-

        os.chdir(self.tempdir) 

-

        self.newCog() 

-

 

-

    def tearDown(self): 

-

        os.chdir(self.olddir) 

-

        # Get rid of the temporary directory. 

-

        self.tempdir.rmtree() 

-

 

-

    def assertFilesSame(self, sFName1, sFName2): 

-

        self.assertEqual((self.tempdir / sFName1).text(), (self.tempdir / sFName2).text()) 

-

 

-

    def assertFileContent(self, sFName, sContent): 

-

        sAbsName = self.tempdir / sFName 

-

        f = open(sAbsName, 'rb') 

-

        try: 

-

            sFileContent = f.read() 

-

        finally: 

-

            f.close() 

-

        self.assertEqual(sFileContent, sContent) 

-

 

-

 

-

class ArgumentHandlingTests(TestCaseWithTempDir): 

-

 

-

    def testArgumentFailure(self): 

-

        # Return value 2 means usage problem. 

-

        assert(self.cog.main(['argv0', '-j']) == 2) 

-

        output = self.output.getvalue() 

-

        assert(output.find("option -j not recognized") >= 0) 

-

        self.assertRaises(CogUsageError, self.cog.callableMain, (['argv0'])) 

-

        self.assertRaises(CogUsageError, self.cog.callableMain, (['argv0', '-j'])) 

-

 

-

    def testNoDashOAndAtFile(self): 

-

        d = { 

-

            'cogfiles.txt': """\ 

-

                # Please run cog 

-

                """ 

-

            } 

-

 

-

        makeFiles(d) 

-

        self.assertRaises(CogUsageError, self.cog.callableMain, (['argv0', '-o', 'foo', '@cogfiles.txt'])) 

-

 

-

    def testDashV(self): 

-

        assert(self.cog.main(['argv0', '-v']) == 0) 

-

        output = self.output.getvalue() 

-

        self.assertEqual('Cog version %s\n' % __version__, output) 

-

 

-

    def producesHelp(self, args): 

-

        self.newCog() 

-

        argv = ['argv0'] + args.split() 

-

        assert(self.cog.main(argv) == 0) 

-

        self.assertEquals(usage, self.output.getvalue()) 

-

 

-

    def testDashH(self): 

-

        # -h or -? anywhere on the command line should just print help. 

-

        self.producesHelp("-h") 

-

        self.producesHelp("-?") 

-

        self.producesHelp("fooey.txt -h") 

-

        self.producesHelp("-o -r @fooey.txt -? @booey.txt") 

-

 

-

    def testDashOAndDashR(self): 

-

        d = { 

-

            'cogfile.txt': """\ 

-

                # Please run cog 

-

                """ 

-

            } 

-

 

-

        makeFiles(d) 

-

        self.assertRaises(CogUsageError, self.cog.callableMain, (['argv0', '-o', 'foo', '-r', 'cogfile.txt'])) 

-

 

-

    def testDashZ(self): 

-

        d = { 

-

            'test.cog': """\ 

-

                // This is my C++ file. 

-

                //[[[cog 

-

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

-

                for fn in fnames: 

-

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

-

                //]]] 

-

                """, 

-

 

-

            'test.out': """\ 

-

                // This is my C++ file. 

-

                //[[[cog 

-

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

-

                for fn in fnames: 

-

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

-

                //]]] 

-

                void DoSomething(); 

-

                void DoAnotherThing(); 

-

                void DoLastThing(); 

-

                """, 

-

            } 

-

 

-

        makeFiles(d) 

-

        self.assertRaisesMsg( 

-

            CogError, "test.cog(6): Missing '[[[end]]]' before end of file.", 

-

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

-

        self.newCog() 

-

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

-

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

-

 

-

    def testBadDashD(self): 

-

        self.assertRaises(CogUsageError, self.cog.callableMain, (['argv0', '-Dfooey', 'cog.txt'])) 

-

        self.assertRaises(CogUsageError, self.cog.callableMain, (['argv0', '-D', 'fooey', 'cog.txt'])) 

-

 

-

 

-

class TestFileHandling(TestCaseWithTempDir): 

-

 

-

    def testSimple(self): 

-

        d = { 

-

            'test.cog': """\ 

-

                // This is my C++ file. 

-

                //[[[cog 

-

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

-

                for fn in fnames: 

-

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

-

                //]]] 

-

                //[[[end]]] 

-

                """, 

-

 

-

            'test.out': """\ 

-

                // This is my C++ file. 

-

                //[[[cog 

-

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

-

                for fn in fnames: 

-

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

-

                //]]] 

-

                void DoSomething(); 

-

                void DoAnotherThing(); 

-

                void DoLastThing(); 

-

                //[[[end]]] 

-

                """, 

-

            } 

-

 

-

        makeFiles(d) 

-

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

-

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

-

        output = self.output.getvalue() 

-

        assert(output.find("(changed)") >= 0) 

-

 

-

    def testOutputFile(self): 

-

        # -o sets the output file. 

-

        d = { 

-

            'test.cog': """\ 

-

                // This is my C++ file. 

-

                //[[[cog 

-

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

-

                for fn in fnames: 

-

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

-

                //]]] 

-

                //[[[end]]] 

-

                """, 

-

 

-

            'test.out': """\ 

-

                // This is my C++ file. 

-

                //[[[cog 

-

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

-

                for fn in fnames: 

-

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

-

                //]]] 

-

                void DoSomething(); 

-

                void DoAnotherThing(); 

-

                void DoLastThing(); 

-

                //[[[end]]] 

-

                """, 

-

            } 

-

 

-

        makeFiles(d) 

-

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

-

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

-

 

-

    def testAtFile(self): 

-

        d = { 

-

            'one.cog': """\ 

-

                //[[[cog 

-

                cog.outl("hello world") 

-

                //]]] 

-

                //[[[end]]] 

-

                """, 

-

 

-

            'one.out': """\ 

-

                //[[[cog 

-

                cog.outl("hello world") 

-

                //]]] 

-

                hello world 

-

                //[[[end]]] 

-

                """, 

-

 

-

            'two.cog': """\ 

-

                //[[[cog 

-

                cog.outl("goodbye cruel world") 

-

                //]]] 

-

                //[[[end]]] 

-

                """, 

-

 

-

            'two.out': """\ 

-

                //[[[cog 

-

                cog.outl("goodbye cruel world") 

-

                //]]] 

-

                goodbye cruel world 

-

                //[[[end]]] 

-

                """, 

-

 

-

            'cogfiles.txt': """\ 

-

                # Please run cog 

-

                one.cog 

-

                 

-

                two.cog 

-

                """ 

-

            } 

-

 

-

        makeFiles(d) 

-

        self.cog.callableMain(['argv0', '-r', '@cogfiles.txt']) 

-

        self.assertFilesSame('one.cog', 'one.out') 

-

        self.assertFilesSame('two.cog', 'two.out') 

-

        output = self.output.getvalue() 

-

        assert(output.find("(changed)") >= 0) 

-

 

-

    def testNestedAtFile(self): 

-

        d = { 

-

            'one.cog': """\ 

-

                //[[[cog 

-

                cog.outl("hello world") 

-

                //]]] 

-

                //[[[end]]] 

-

                """, 

-

 

-

            'one.out': """\ 

-

                //[[[cog 

-

                cog.outl("hello world") 

-

                //]]] 

-

                hello world 

-

                //[[[end]]] 

-

                """, 

-

 

-

            'two.cog': """\ 

-

                //[[[cog 

-

                cog.outl("goodbye cruel world") 

-

                //]]] 

-

                //[[[end]]] 

-

                """, 

-

 

-

            'two.out': """\ 

-

                //[[[cog 

-

                cog.outl("goodbye cruel world") 

-

                //]]] 

-

                goodbye cruel world 

-

                //[[[end]]] 

-

                """, 

-

 

-

            'cogfiles.txt': """\ 

-

                # Please run cog 

-

                one.cog 

-

                @cogfiles2.txt 

-

                """, 

-

 

-

            'cogfiles2.txt': """\ 

-

                # This one too, please. 

-

                two.cog 

-

                """, 

-

            } 

-

 

-

        makeFiles(d) 

-

        self.cog.callableMain(['argv0', '-r', '@cogfiles.txt']) 

-

        self.assertFilesSame('one.cog', 'one.out') 

-

        self.assertFilesSame('two.cog', 'two.out') 

-

        output = self.output.getvalue() 

-

        assert(output.find("(changed)") >= 0) 

-

 

-

    def testAtFileWithArgs(self): 

-

        d = { 

-

            'both.cog': """\ 

-

                //[[[cog 

-

                cog.outl("one: %s" % globals().has_key('one')) 

-

                cog.outl("two: %s" % globals().has_key('two')) 

-

                //]]] 

-

                //[[[end]]] 

-

                """, 

-

 

-

            'one.out': """\ 

-

                //[[[cog 

-

                cog.outl("one: %s" % globals().has_key('one')) 

-

                cog.outl("two: %s" % globals().has_key('two')) 

-

                //]]] 

-

                one: True // ONE 

-

                two: False // ONE 

-

                //[[[end]]] 

-

                """, 

-

 

-

            'two.out': """\ 

-

                //[[[cog 

-

                cog.outl("one: %s" % globals().has_key('one')) 

-

                cog.outl("two: %s" % globals().has_key('two')) 

-

                //]]] 

-

                one: False // TWO 

-

                two: True // TWO 

-

                //[[[end]]] 

-

                """, 

-

 

-

            'cogfiles.txt': """\ 

-

                # Please run cog 

-

                both.cog -o both.one -s ' // ONE' -D one=x 

-

                both.cog -o both.two -s ' // TWO' -D two=x 

-

                """ 

-

            } 

-

 

-

        makeFiles(d) 

-

        self.cog.callableMain(['argv0', '@cogfiles.txt']) 

-

        self.assertFilesSame('both.one', 'one.out') 

-

        self.assertFilesSame('both.two', 'two.out') 

-

 

-

    def testAtFileWithBadArgCombo(self): 

-

        d = { 

-

            'both.cog': """\ 

-

                //[[[cog 

-

                cog.outl("one: %s" % globals().has_key('one')) 

-

                cog.outl("two: %s" % globals().has_key('two')) 

-

                //]]] 

-

                //[[[end]]] 

-

                """, 

-

 

-

            'cogfiles.txt': """\ 

-

                # Please run cog 

-

                both.cog  

-

                both.cog -d # This is bad: -r and -d 

-

                """ 

-

            } 

-

 

-

        makeFiles(d) 

-

        self.assertRaises(CogUsageError, self.cog.callableMain, (['argv0', '-r', '@cogfiles.txt'])) 

-

 

-

    def testAtFileWithTrickyFilenames(self): 

-

        d = { 

-

            'one 1.cog': """\ 

-

                //[[[cog cog.outl("hello world") ]]] 

-

                """, 

-

 

-

            'one.out': """\ 

-

                //[[[cog cog.outl("hello world") ]]] 

-

                hello world //xxx 

-

                """, 

-

 

-

            'subdir': { 

-

                'subback.cog': """\ 

-

                    //[[[cog cog.outl("down deep with backslashes") ]]] 

-

                    """, 

-

 

-

                'subfwd.cog': """\ 

-

                    //[[[cog cog.outl("down deep with slashes") ]]] 

-

                    """, 

-

                }, 

-

 

-

            'subback.out': """\ 

-

                //[[[cog cog.outl("down deep with backslashes") ]]] 

-

                down deep with backslashes //yyy 

-

                """, 

-

 

-

            'subfwd.out': """\ 

-

                //[[[cog cog.outl("down deep with slashes") ]]] 

-

                down deep with slashes //zzz 

-

                """, 

-

 

-

            'cogfiles.txt': """\ 

-

                # Please run cog 

-

                'one 1.cog' -s ' //xxx' 

-

                subdir\subback.cog -s ' //yyy' 

-

                subdir/subfwd.cog -s ' //zzz' 

-

                """ 

-

            } 

-

 

-

        makeFiles(d) 

-

        self.cog.callableMain(['argv0', '-z', '-r', '@cogfiles.txt']) 

-

        self.assertFilesSame('one 1.cog', 'one.out') 

-

        self.assertFilesSame('subdir/subback.cog', 'subback.out') 

-

        self.assertFilesSame('subdir/subfwd.cog', 'subfwd.out') 

-

 

-

 

-

class CogTestLineEndings(TestCaseWithTempDir): 

-

    """Tests for -U option (force LF line-endings in output).""" 

-

 

-

    lines_in = ['Some text.', 

-

                '//[[[cog', 

-

                'cog.outl("Cog text")', 

-

                '//]]]', 

-

                'gobbledegook.', 

-

                '//[[[end]]]', 

-

                'epilogue.', 

-

                ''] 

-

 

-

    lines_out = ['Some text.', 

-

                 '//[[[cog', 

-

                 'cog.outl("Cog text")', 

-

                 '//]]]', 

-

                 'Cog text', 

-

                 '//[[[end]]]', 

-

                 'epilogue.', 

-

                 ''] 

-

 

-

    def testOutputNativeEol(self): 

-

        makeFiles({'infile': '\n'.join(self.lines_in)}) 

-

        self.cog.callableMain(['argv0', '-o', 'outfile', 'infile']) 

-

        self.assertFileContent('outfile', os.linesep.join(self.lines_out)) 

-

 

-

    def testOutputLfEol(self): 

-

        makeFiles({'infile': '\n'.join(self.lines_in)}) 

-

        self.cog.callableMain(['argv0', '-U', '-o', 'outfile', 'infile']) 

-

        self.assertFileContent('outfile', '\n'.join(self.lines_out)) 

-

 

-

    def testReplaceNativeEol(self): 

-

        makeFiles({'test.cog': '\n'.join(self.lines_in)}) 

-

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

-

        self.assertFileContent('test.cog', os.linesep.join(self.lines_out)) 

-

 

-

    def testReplaceLfEol(self): 

-

        makeFiles({'test.cog': '\n'.join(self.lines_in)}) 

-

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

-

        self.assertFileContent('test.cog', '\n'.join(self.lines_out)) 

-

 

-

 

-

class TestCaseWithImports(TestCaseWithTempDir): 

-

    """ When running tests which import modules, the sys.modules list 

-

        leaks from one test to the next.  This test case class scrubs 

-

        the list after each run to keep the tests isolated from each other. 

-

    """ 

-

 

-

    def setUp(self): 

-

        TestCaseWithTempDir.setUp(self) 

-

        self.sysmodulekeys = list(sys.modules) 

-

 

-

    def tearDown(self): 

-

        modstoscrub = [ 

-

            modname 

-

            for modname in sys.modules 

-

            if modname not in self.sysmodulekeys 

-

            ] 

-

        for modname in modstoscrub: 

-

            del sys.modules[modname] 

-

        TestCaseWithTempDir.tearDown(self) 

-

 

-

 

-

class CogIncludeTests(TestCaseWithImports): 

-

    dincludes = { 

-

        'test.cog': """\ 

-

            //[[[cog 

-

                import mymodule 

-

            //]]] 

-

            //[[[end]]] 

-

            """, 

-

 

-

        'test.out': """\ 

-

            //[[[cog 

-

                import mymodule 

-

            //]]] 

-

            Hello from mymodule 

-

            //[[[end]]] 

-

            """, 

-

 

-

        'test2.out': """\ 

-

            //[[[cog 

-

                import mymodule 

-

            //]]] 

-

            Hello from mymodule in inc2 

-

            //[[[end]]] 

-

            """, 

-

 

-

        'include': { 

-

            'mymodule.py': """\ 

-

                import cog 

-

                cog.outl("Hello from mymodule") 

-

                """ 

-

            }, 

-

 

-

        'inc2': { 

-

            'mymodule.py': """\ 

-

                import cog 

-

                cog.outl("Hello from mymodule in inc2") 

-

                """ 

-

            }, 

-

 

-

        'inc3': { 

-

            'someothermodule.py': """\ 

-

                import cog 

-

                cog.outl("This is some other module.") 

-

                """ 

-

            }, 

-

        } 

-

 

-

    def testNeedIncludePath(self): 

-

        # Try it without the -I, to see that an ImportError happens. 

-

        makeFiles(self.dincludes) 

-

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

-

 

-

    def testIncludePath(self): 

-

        # Test that -I adds include directories properly. 

-

        makeFiles(self.dincludes) 

-

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

-

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

-

 

-

    def testTwoIncludePaths(self): 

-

        # Test that two -I's add include directories properly. 

-

        makeFiles(self.dincludes) 

-

        self.cog.callableMain(['argv0', '-r', '-I', 'include', '-I', 'inc2', 'test.cog']) 

-

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

-

 

-

    def testTwoIncludePaths2(self): 

-

        # Test that two -I's add include directories properly. 

-

        makeFiles(self.dincludes) 

-

        self.cog.callableMain(['argv0', '-r', '-I', 'inc2', '-I', 'include', 'test.cog']) 

-

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

-

 

-

    def testUselessIncludePath(self): 

-

        # Test that the search will continue past the first directory. 

-

        makeFiles(self.dincludes) 

-

        self.cog.callableMain(['argv0', '-r', '-I', 'inc3', '-I', 'include', 'test.cog']) 

-

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

-

 

-

    def testSysPathIsUnchanged(self): 

-

        d = { 

-

            'bad.cog': """\ 

-

                //[[[cog cog.error("Oh no!") ]]] 

-

                //[[[end]]] 

-

                """, 

-

            'good.cog': """\ 

-

                //[[[cog cog.outl("Oh yes!") ]]] 

-

                //[[[end]]] 

-

                """, 

-

            } 

-

 

-

        makeFiles(d) 

-

        # Is it unchanged just by creating a cog engine? 

-

        oldsyspath = sys.path[:] 

-

        self.newCog() 

-

        self.assertEqual(oldsyspath, sys.path) 

-

        # Is it unchanged for a successful run? 

-

        self.newCog() 

-

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

-

        self.assertEqual(oldsyspath, sys.path) 

-

        # Is it unchanged for a successful run with includes? 

-

        self.newCog() 

-

        self.cog.callableMain(['argv0', '-r', '-I', 'xyzzy', 'good.cog']) 

-

        self.assertEqual(oldsyspath, sys.path) 

-

        # Is it unchanged for a successful run with two includes? 

-

        self.newCog() 

-

        self.cog.callableMain(['argv0', '-r', '-I', 'xyzzy', '-I', 'quux', 'good.cog']) 

-

        self.assertEqual(oldsyspath, sys.path) 

-

        # Is it unchanged for a failed run? 

-

        self.newCog() 

-

        self.assertRaises(CogError, self.cog.callableMain, (['argv0', '-r', 'bad.cog'])) 

-

        self.assertEqual(oldsyspath, sys.path) 

-

        # Is it unchanged for a failed run with includes? 

-

        self.newCog() 

-

        self.assertRaises(CogError, self.cog.callableMain, (['argv0', '-r', '-I', 'xyzzy', 'bad.cog'])) 

-

        self.assertEqual(oldsyspath, sys.path) 

-

        # Is it unchanged for a failed run with two includes? 

-

        self.newCog() 

-

        self.assertRaises(CogError, self.cog.callableMain, (['argv0', '-r', '-I', 'xyzzy', '-I', 'quux', 'bad.cog'])) 

-

        self.assertEqual(oldsyspath, sys.path) 

-

 

-

    def testSubDirectories(self): 

-

        # Test that relative paths on the command line work, with includes. 

-

 

-

        d = { 

-

            'code': { 

-

                'test.cog': """\ 

-

                    //[[[cog 

-

                        import mysubmodule 

-

                    //]]] 

-

                    //[[[end]]] 

-

                    """, 

-

 

-

                'test.out': """\ 

-

                    //[[[cog 

-

                        import mysubmodule 

-

                    //]]] 

-

                    Hello from mysubmodule 

-

                    //[[[end]]] 

-

                    """, 

-

 

-

                'mysubmodule.py': """\ 

-

                    import cog 

-

                    cog.outl("Hello from mysubmodule") 

-

                    """ 

-

                } 

-

            } 

-

 

-

        makeFiles(d) 

-

        # We should be able to invoke cog without the -I switch, and it will 

-

        # auto-include the current directory 

-

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

-

        self.assertFilesSame('code/test.cog', 'code/test.out') 

-

 

-

 

-

class CogTestsInFiles(TestCaseWithTempDir): 

-

 

-

    def testWarnIfNoCogCode(self): 

-

        # Test that the -e switch warns if there is no Cog code. 

-

        d = { 

-

            'with.cog': """\ 

-

                //[[[cog 

-

                cog.outl("hello world") 

-

                //]]] 

-

                hello world 

-

                //[[[end]]] 

-

                """, 

-

 

-

            'without.cog': """\ 

-

                There's no cog 

-

                code in this file. 

-

                """, 

-

            } 

-

 

-

        makeFiles(d) 

-

        self.cog.callableMain(['argv0', '-e', 'with.cog']) 

-

        output = self.output.getvalue() 

-

        assert(output.find("Warning") < 0) 

-

        self.newCog() 

-

        self.cog.callableMain(['argv0', '-e', 'without.cog']) 

-

        output = self.output.getvalue() 

-

        assert(output.find("Warning: no cog code found in without.cog") >= 0) 

-

        self.newCog() 

-

        self.cog.callableMain(['argv0', 'without.cog']) 

-

        output = self.output.getvalue() 

-

        assert(output.find("Warning") < 0) 

-

 

-

    def testFileNameProps(self): 

-

        d = { 

-

            'cog1.txt': """\ 

-

                //[[[cog 

-

                cog.outl("This is %s in, %s out" % (cog.inFile, cog.outFile)) 

-

                //]]] 

-

                this is cog1.txt in, cog1.txt out 

-

                [[[end]]] 

-

                """, 

-

 

-

            'cog1.out': """\ 

-

                //[[[cog 

-

                cog.outl("This is %s in, %s out" % (cog.inFile, cog.outFile)) 

-

                //]]] 

-

                This is cog1.txt in, cog1.txt out 

-

                [[[end]]] 

-

                """, 

-

 

-

            'cog1out.out': """\ 

-

                //[[[cog 

-

                cog.outl("This is %s in, %s out" % (cog.inFile, cog.outFile)) 

-

                //]]] 

-

                This is cog1.txt in, cog1out.txt out 

-

                [[[end]]] 

-

                """, 

-

            } 

-

 

-

        makeFiles(d) 

-

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

-

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

-

        self.newCog() 

-

        self.cog.callableMain(['argv0', '-o', 'cog1out.txt', 'cog1.txt']) 

-

        self.assertFilesSame('cog1out.txt', 'cog1out.out') 

-

 

-

    def testGlobalsDontCrossFiles(self): 

-

        # Make sure that global values don't get shared between files. 

-

        d = { 

-

            'one.cog': """\ 

-

                //[[[cog s = "This was set in one.cog" ]]] 

-

                //[[[end]]] 

-

                //[[[cog cog.outl(s) ]]] 

-

                //[[[end]]] 

-

                """, 

-

 

-

            'one.out': """\ 

-

                //[[[cog s = "This was set in one.cog" ]]] 

-

                //[[[end]]] 

-

                //[[[cog cog.outl(s) ]]] 

-

                This was set in one.cog 

-

                //[[[end]]] 

-

                """, 

-

 

-

            'two.cog': """\ 

-

                //[[[cog 

-

                try: 

-

                    cog.outl(s) 

-

                except NameError: 

-

                    cog.outl("s isn't set!") 

-

                //]]] 

-

                //[[[end]]] 

-

                """, 

-

 

-

            'two.out': """\ 

-

                //[[[cog 

-

                try: 

-

                    cog.outl(s) 

-

                except NameError: 

-

                    cog.outl("s isn't set!") 

-

                //]]] 

-

                s isn't set! 

-

                //[[[end]]] 

-

                """, 

-

 

-

            'cogfiles.txt': """\ 

-

                # Please run cog 

-

                one.cog 

-

                 

-

                two.cog 

-

                """ 

-

            } 

-

 

-

        makeFiles(d) 

-

        self.cog.callableMain(['argv0', '-r', '@cogfiles.txt']) 

-

        self.assertFilesSame('one.cog', 'one.out') 

-

        self.assertFilesSame('two.cog', 'two.out') 

-

        output = self.output.getvalue() 

-

        assert(output.find("(changed)") >= 0) 

-

 

-

    def testRemoveGeneratedOutput(self): 

-

        d = { 

-

            'cog1.txt': """\ 

-

                //[[[cog 

-

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

-

                //]]] 

-

                This line was generated. 

-

                //[[[end]]] 

-

                This line was not. 

-

                """, 

-

 

-

            'cog1.out': """\ 

-

                //[[[cog 

-

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

-

                //]]] 

-

                //[[[end]]] 

-

                This line was not. 

-

                """, 

-

 

-

            'cog1.out2': """\ 

-

                //[[[cog 

-

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

-

                //]]] 

-

                This line was generated. 

-

                //[[[end]]] 

-

                This line was not. 

-

                """, 

-

            } 

-

 

-

        makeFiles(d) 

-

        # Remove generated output. 

-

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

-

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

-

        self.newCog() 

-

        # Regenerate the generated output. 

-

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

-

        self.assertFilesSame('cog1.txt', 'cog1.out2') 

-

        self.newCog() 

-

        # Remove the generated output again. 

-

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

-

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

-

 

-

    def testMsgCall(self): 

-

        infile = """\ 

-

            #[[[cog 

-

                cog.msg("Hello there!") 

-

            #]]] 

-

            #[[[end]]] 

-

            """ 

-

        infile = reindentBlock(infile) 

-

        self.assertEqual(self.cog.processString(infile), infile) 

-

        output = self.output.getvalue() 

-

        self.assertEqual(output, "Message: Hello there!\n") 

-

 

-

    def testErrorMessageHasNoTraceback(self): 

-

        # Test that a Cog error is printed to stderr with no traceback. 

-

 

-

        d = { 

-

            'cog1.txt': """\ 

-

                //[[[cog 

-

                cog.outl("This line was newly") 

-

                cog.outl("generated by cog") 

-

                cog.outl("blah blah.") 

-

                //]]] 

-

                Xhis line was newly 

-

                generated by cog 

-

                blah blah. 

-

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

-

                """, 

-

            } 

-

 

-

        makeFiles(d) 

-

        stderr = StringIO.StringIO() 

-

        self.cog.setOutput(stderr=stderr) 

-

        self.cog.main(['argv0', '-c', '-r', "cog1.txt"]) 

-

        output = self.output.getvalue() 

-

        self.assertEqual(self.output.getvalue(), "Cogging cog1.txt\n") 

-

        self.assertEqual(stderr.getvalue(), "cog1.txt(9): Output has been edited! Delete old checksum to unprotect.\n") 

-

 

-

    def testDashD(self): 

-

        d = { 

-

            'test.cog': """\ 

-

                --[[[cog cog.outl("Defined fooey as " + fooey) ]]] 

-

                --[[[end]]] 

-

                """, 

-

 

-

            'test.kablooey': """\ 

-

                --[[[cog cog.outl("Defined fooey as " + fooey) ]]] 

-

                Defined fooey as kablooey 

-

                --[[[end]]] 

-

                """, 

-

 

-

            'test.einstein': """\ 

-

                --[[[cog cog.outl("Defined fooey as " + fooey) ]]] 

-

                Defined fooey as e=mc2 

-

                --[[[end]]] 

-

                """, 

-

            } 

-

 

-

        makeFiles(d) 

-

        self.cog.callableMain(['argv0', '-r', '-D', 'fooey=kablooey', 'test.cog']) 

-

        self.assertFilesSame('test.cog', 'test.kablooey') 

-

        makeFiles(d) 

-

        self.cog.callableMain(['argv0', '-r', '-Dfooey=kablooey', 'test.cog']) 

-

        self.assertFilesSame('test.cog', 'test.kablooey') 

-

        makeFiles(d) 

-

        self.cog.callableMain(['argv0', '-r', '-Dfooey=e=mc2', 'test.cog']) 

-

        self.assertFilesSame('test.cog', 'test.einstein') 

-

        makeFiles(d) 

-

        self.cog.callableMain(['argv0', '-r', '-Dbar=quux', '-Dfooey=kablooey', 'test.cog']) 

-

        self.assertFilesSame('test.cog', 'test.kablooey') 

-

        makeFiles(d) 

-

        self.cog.callableMain(['argv0', '-r', '-Dfooey=kablooey', '-Dbar=quux', 'test.cog']) 

-

        self.assertFilesSame('test.cog', 'test.kablooey') 

-

        makeFiles(d) 

-

        self.cog.callableMain(['argv0', '-r', '-Dfooey=gooey', '-Dfooey=kablooey', 'test.cog']) 

-

        self.assertFilesSame('test.cog', 'test.kablooey') 

-

 

-

    def testOutputToStdout(self): 

-

        d = { 

-

            'test.cog': """\ 

-

                --[[[cog cog.outl('Hey there!') ]]] 

-

                --[[[end]]] 

-

                """ 

-

            } 

-

 

-

        makeFiles(d) 

-

        stderr = StringIO.StringIO() 

-

        self.cog.setOutput(stderr=stderr) 

-

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

-

        output = self.output.getvalue() 

-

        outerr = stderr.getvalue() 

-

        self.assertEqual(output, "--[[[cog cog.outl('Hey there!') ]]]\nHey there!\n--[[[end]]]\n") 

-

        self.assertEqual(outerr, "") 

-

 

-

    def testSuffixOutputLines(self): 

-

        d = { 

-

            'test.cog': """\ 

-

                Hey there. 

-

                ;[[[cog cog.outl('a\\nb\\n   \\nc') ]]] 

-

                ;[[[end]]] 

-

                Good bye. 

-

                """, 

-

 

-

            'test.out': """\ 

-

                Hey there. 

-

                ;[[[cog cog.outl('a\\nb\\n   \\nc') ]]] 

-

                a (foo) 

-

                b (foo) 

-

                    

-

                c (foo) 

-

                ;[[[end]]] 

-

                Good bye. 

-

                """, 

-

            } 

-

 

-

        makeFiles(d) 

-

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

-

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

-

 

-

    def testEmptySuffix(self): 

-

        d = { 

-

            'test.cog': """\ 

-

                ;[[[cog cog.outl('a\\nb\\nc') ]]] 

-

                ;[[[end]]] 

-

                """, 

-

 

-

            'test.out': """\ 

-

                ;[[[cog cog.outl('a\\nb\\nc') ]]] 

-

                a 

-

                b 

-

                c 

-

                ;[[[end]]] 

-

                """, 

-

            } 

-

 

-

        makeFiles(d) 

-

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

-

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

-

 

-

    def testHellishSuffix(self): 

-

        d = { 

-

            'test.cog': """\ 

-

                ;[[[cog cog.outl('a\\n\\nb') ]]] 

-

                """, 

-

 

-

            'test.out': """\ 

-

                ;[[[cog cog.outl('a\\n\\nb') ]]] 

-

                a /\\n*+([)]>< 

-

                 

-

                b /\\n*+([)]>< 

-

                """, 

-

            } 

-

 

-

        makeFiles(d) 

-

        self.cog.callableMain(['argv0', '-z', '-r', '-s', r' /\n*+([)]><', 'test.cog']) 

-

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

-

 

-

class WritabilityTests(TestCaseWithTempDir): 

-

 

-

    d = { 

-

        'test.cog': """\ 

-

            //[[[cog 

-

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

-

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

-

            //]]] 

-

            //[[[end]]] 

-

            """, 

-

 

-

        'test.out': """\ 

-

            //[[[cog 

-

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

-

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

-

            //]]] 

-

            void DoSomething(); 

-

            void DoAnotherThing(); 

-

            void DoLastThing(); 

-

            //[[[end]]] 

-

            """, 

-

        } 

-

 

-

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

-

        # for Windows 

-

        cmd_w_args = 'attrib -R %s' 

-

        cmd_w_asterisk = 'attrib -R *' 

-

    else:   # pragma: no cover 

-

        # for unix-like 

-

        cmd_w_args = 'chmod +w %s' 

-

        cmd_w_asterisk = 'chmod +w *' 

-

 

-

    def setUp(self): 

-

        TestCaseWithTempDir.setUp(self) 

-

        makeFiles(self.d) 

-

        self.testcog = self.tempdir / 'test.cog' 

-

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

-

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

-

 

-

    def tearDown(self): 

-

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

-

        TestCaseWithTempDir.tearDown(self) 

-

 

-

    def testReadonlyNoCommand(self): 

-

        self.assertRaisesMsg( 

-

            CogError, "Can't overwrite test.cog", 

-

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

-

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

-

 

-

    def testReadonlyWithCommand(self): 

-

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

-

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

-

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

-

 

-

    def testReadonlyWithCommandWithNoSlot(self): 

-

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

-

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

-

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

-

 

-

    def testReadonlyWithIneffectualCommand(self): 

-

        self.assertRaisesMsg( 

-

            CogError, "Couldn't make test.cog writable", 

-

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

-

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

-

 

-

class ChecksumTests(TestCaseWithTempDir): 

-

 

-

    def testCreateChecksumOutput(self): 

-

        d = { 

-

            'cog1.txt': """\ 

-

                //[[[cog 

-

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

-

                //]]] 

-

                This line was generated. 

-

                //[[[end]]] 

-

                This line was not. 

-

                """, 

-

 

-

            'cog1.out': """\ 

-

                //[[[cog 

-

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

-

                //]]] 

-

                This line was generated. 

-

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

-

                This line was not. 

-

                """, 

-

            } 

-

 

-

        makeFiles(d) 

-

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

-

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

-

 

-

    def testCheckChecksumOutput(self): 

-

        d = { 

-

            'cog1.txt': """\ 

-

                //[[[cog 

-

                cog.outl("This line was newly") 

-

                cog.outl("generated by cog") 

-

                cog.outl("blah blah.") 

-

                //]]] 

-

                This line was generated. 

-

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

-

                """, 

-

 

-

            'cog1.out': """\ 

-

                //[[[cog 

-

                cog.outl("This line was newly") 

-

                cog.outl("generated by cog") 

-

                cog.outl("blah blah.") 

-

                //]]] 

-

                This line was newly 

-

                generated by cog 

-

                blah blah. 

-

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

-

                """, 

-

            } 

-

 

-

        makeFiles(d) 

-

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

-

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

-

 

-

    def testRemoveChecksumOutput(self): 

-

        d = { 

-

            'cog1.txt': """\ 

-

                //[[[cog 

-

                cog.outl("This line was newly") 

-

                cog.outl("generated by cog") 

-

                cog.outl("blah blah.") 

-

                //]]] 

-

                This line was generated. 

-

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

-

                """, 

-

 

-

            'cog1.out': """\ 

-

                //[[[cog 

-

                cog.outl("This line was newly") 

-

                cog.outl("generated by cog") 

-

                cog.outl("blah blah.") 

-

                //]]] 

-

                This line was newly 

-

                generated by cog 

-

                blah blah. 

-

                //[[[end]]] fooey 

-

                """, 

-

            } 

-

 

-

        makeFiles(d) 

-

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

-

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

-

 

-

    def testTamperedChecksumOutput(self): 

-

        d = { 

-

            'cog1.txt': """\ 

-

                //[[[cog 

-

                cog.outl("This line was newly") 

-

                cog.outl("generated by cog") 

-

                cog.outl("blah blah.") 

-

                //]]] 

-

                Xhis line was newly 

-

                generated by cog 

-

                blah blah. 

-

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

-

                """, 

-

 

-

            'cog2.txt': """\ 

-

                //[[[cog 

-

                cog.outl("This line was newly") 

-

                cog.outl("generated by cog") 

-

                cog.outl("blah blah.") 

-

                //]]] 

-

                This line was newly 

-

                generated by cog 

-

                blah blah! 

-

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

-

                """, 

-

 

-

            'cog3.txt': """\ 

-

                //[[[cog 

-

                cog.outl("This line was newly") 

-

                cog.outl("generated by cog") 

-

                cog.outl("blah blah.") 

-

                //]]] 

-

                 

-

                This line was newly 

-

                generated by cog 

-

                blah blah. 

-

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

-

                """, 

-

 

-

            'cog4.txt': """\ 

-

                //[[[cog 

-

                cog.outl("This line was newly") 

-

                cog.outl("generated by cog") 

-

                cog.outl("blah blah.") 

-

                //]]] 

-

                This line was newly 

-

                generated by cog 

-

                blah blah.. 

-

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

-

                """, 

-

 

-

            'cog5.txt': """\ 

-

                //[[[cog 

-

                cog.outl("This line was newly") 

-

                cog.outl("generated by cog") 

-

                cog.outl("blah blah.") 

-

                //]]] 

-

                This line was newly 

-

                generated by cog 

-

                blah blah. 

-

                extra 

-

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

-

                """, 

-

 

-

            'cog6.txt': """\ 

-

                //[[[cog 

-

                cog.outl("This line was newly") 

-

                cog.outl("generated by cog") 

-

                cog.outl("blah blah.") 

-

                //]]] 

-

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

-

                """, 

-

            } 

-

 

-

        makeFiles(d) 

-

        self.assertRaisesMsg(CogError, 

-

            "cog1.txt(9): Output has been edited! Delete old checksum to unprotect.", 

-

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

-

        self.assertRaisesMsg(CogError, 

-

            "cog2.txt(9): Output has been edited! Delete old checksum to unprotect.", 

-

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

-

        self.assertRaisesMsg(CogError, 

-

            "cog3.txt(10): Output has been edited! Delete old checksum to unprotect.", 

-

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

-

        self.assertRaisesMsg(CogError, 

-

            "cog4.txt(9): Output has been edited! Delete old checksum to unprotect.", 

-

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

-

        self.assertRaisesMsg(CogError, 

-

            "cog5.txt(10): Output has been edited! Delete old checksum to unprotect.", 

-

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

-

        self.assertRaisesMsg(CogError, 

-

            "cog6.txt(6): Output has been edited! Delete old checksum to unprotect.", 

-

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

-

 

-

class BlakeTests(TestCaseWithTempDir): 

-

 

-

    # Blake Winton's contributions.         

-

    def testDeleteCode(self): 

-

        # -o sets the output file. 

-

        d = { 

-

            'test.cog': """\ 

-

                // This is my C++ file. 

-

                //[[[cog 

-

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

-

                for fn in fnames: 

-

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

-

                //]]] 

-

                Some Sample Code Here 

-

                //[[[end]]]Data Data 

-

                And Some More 

-

                """, 

-

 

-

            'test.out': """\ 

-

                // This is my C++ file. 

-

                void DoSomething(); 

-

                void DoAnotherThing(); 

-

                void DoLastThing(); 

-

                And Some More 

-

                """, 

-

            } 

-

 

-

        makeFiles(d) 

-

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

-

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

-

 

-

    def testDeleteCodeWithDashRFails(self): 

-

        d = { 

-

            'test.cog': """\ 

-

                // This is my C++ file. 

-

                """ 

-

            } 

-

 

-

        makeFiles(d) 

-

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

-

 

-

    def testSettingGlobals(self): 

-

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

-

        # processFile(). 

-

        d = { 

-

            'test.cog': """\ 

-

                // This is my C++ file. 

-

                //[[[cog 

-

                for fn in fnames: 

-

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

-

                //]]] 

-

                Some Sample Code Here 

-

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

-

 

-

            'test.out': """\ 

-

                // This is my C++ file. 

-

                void DoBlake(); 

-

                void DoWinton(); 

-

                void DoContribution(); 

-

                """, 

-

            } 

-

 

-

        makeFiles(d) 

-

        globals = {} 

-

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

-

        self.cog.options.bDeleteCode = True 

-

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

-

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

-

 

-

class ErrorCallTests(TestCaseWithTempDir): 

-

 

-

    def testErrorCallHasNoTraceback(self): 

-

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

-

        d = { 

-

            'error.cog': """\ 

-

                //[[[cog 

-

                cog.error("Something Bad!") 

-

                //]]] 

-

                //[[[end]]] 

-

                """, 

-

            } 

-

 

-

        makeFiles(d) 

-

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

-

        output = self.output.getvalue() 

-

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

-

 

-

    def testRealErrorHasTraceback(self): 

-

        # Test that a genuine error does show a traceback. 

-

        d = { 

-

            'error.cog': """\ 

-

                //[[[cog 

-

                raise RuntimeError("Hey!") 

-

                //]]] 

-

                //[[[end]]] 

-

                """, 

-

            } 

-

 

-

        makeFiles(d) 

-

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

-

        output = self.output.getvalue() 

-

        msg = 'Actual output:\n' + output 

-

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

-

        self.assert_(output.find("RuntimeError: Hey!") > 0, msg) 

-

 

-

 

-

if __name__ == '__main__':      #pragma: no cover 

-

    unittest.main() 

-

 

-

# Things not yet tested: 

-

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

+

""" Test cogapp. 

+

    http://nedbatchelder.com/code/cog 

+

     

+

    Copyright 2004-2009, Ned Batchelder. 

+

""" 

+

 

+

import unittest 

+

import os, random, re, StringIO, stat, sys, tempfile 

+

import path     # Non-standard, from http://www.jorendorff.com/articles/python/path 

+

from cogapp import Cog, CogOptions, CogGenerator 

+

from cogapp import CogError, CogUsageError, CogGeneratedError 

+

from cogapp import usage, __version__ 

+

from whiteutils import reindentBlock 

+

from makefiles import * 

+

 

+

class TestCase(unittest.TestCase): 

+

    """ Base class for all Cog test cases.  Adds utility methods I like. 

+

    """ 

+

    def assertRaisesMsg(self, excClass, msg, callableObj, *args, **kwargs): 

+

        """ Just like unittest.TestCase.assertRaises, 

+

            but checks that the message is right too. 

+

        """ 

+

        try: 

+

            callableObj(*args, **kwargs) 

+

        except excClass, exc: 

+

            excMsg = str(exc) 

+

            if not msg: 

+

                # No message provided: it passes. 

+

                return  #pragma: no cover 

+

            elif excMsg == msg: 

+

                # Message provided, and we got the right message: it passes. 

+

                return 

+

            else:   #pragma: no cover 

+

                # Message provided, and it didn't match: fail! 

+

                raise self.failureException("Right exception, wrong message: got '%s' expected '%s'" % (excMsg, msg)) 

+

        else:   #pragma: no cover 

+

            if hasattr(excClass,'__name__'): 

+

                excName = excClass.__name__ 

+

            else: 

+

                excName = str(excClass) 

+

            raise self.failureException("Expected to raise %s, didn't get an exception at all" % excName) 

+

 

+

class CogTestsInMemory(TestCase): 

+

    """ Test cases for cogapp.Cog() 

+

    """ 

+

 

+

    def testNoCog(self): 

+

        strings = [ 

+

            '', 

+

            ' ', 

+

            ' \t \t \tx', 

+

            'hello', 

+

            'the cat\nin the\nhat.', 

+

            'Horton\n\tHears A\n\t\tWho' 

+

            ] 

+

        for s in strings: 

+

            self.assertEqual(Cog().processString(s), s) 

+

 

+

    def testSimple(self): 

+

        infile = """\ 

+

            Some text. 

+

            //[[[cog 

+

            import cog 

+

            cog.outl("This is line one\\n") 

+

            cog.outl("This is line two") 

+

            //]]] 

+

            gobbledegook. 

+

            //[[[end]]] 

+

            epilogue. 

+

            """ 

+

 

+

        outfile = """\ 

+

            Some text. 

+

            //[[[cog 

+

            import cog 

+

            cog.outl("This is line one\\n") 

+

            cog.outl("This is line two") 

+

            //]]] 

+

            This is line one 

+

 

+

            This is line two 

+

            //[[[end]]] 

+

            epilogue. 

+

            """ 

+

 

+

        self.assertEqual(Cog().processString(infile), outfile) 

+

 

+

    def testEmptyCog(self): 

+

        # The cog clause can be totally empty.  Not sure why you'd want it, 

+

        # but it works. 

+

        infile = """\ 

+

            hello 

+

            //[[[cog 

+

            //]]] 

+

            //[[[end]]] 

+

            goodbye 

+

            """ 

+

 

+

        infile = reindentBlock(infile) 

+

        self.assertEqual(Cog().processString(infile), infile) 

+

 

+

    def testMultipleCogs(self): 

+

        # One file can have many cog chunks, even abutting each other. 

+

        infile = """\ 

+

            //[[[cog 

+

            cog.out("chunk1") 

+

            //]]] 

+

            chunk1 

+

            //[[[end]]] 

+

            //[[[cog 

+

            cog.out("chunk2") 

+

            //]]] 

+

            chunk2 

+

            //[[[end]]] 

+

            between chunks 

+

            //[[[cog 

+

            cog.out("chunk3") 

+

            //]]] 

+

            chunk3 

+

            //[[[end]]] 

+

            """ 

+

 

+

        infile = reindentBlock(infile) 

+

        self.assertEqual(Cog().processString(infile), infile) 

+

 

+

    def testTrimBlankLines(self): 

+

        infile = """\ 

+

            //[[[cog 

+

            cog.out("This is line one\\n", trimblanklines=True) 

+

            cog.out(''' 

+

                This is line two 

+

            ''', dedent=True, trimblanklines=True) 

+

            cog.outl("This is line three", trimblanklines=True) 

+

            //]]] 

+

            This is line one 

+

            This is line two 

+

            This is line three 

+

            //[[[end]]] 

+

            """ 

+

 

+

        infile = reindentBlock(infile) 

+

        self.assertEqual(Cog().processString(infile), infile) 

+

 

+

    def testTrimEmptyBlankLines(self): 

+

        infile = """\ 

+

            //[[[cog 

+

            cog.out("This is line one\\n", trimblanklines=True) 

+

            cog.out(''' 

+

                This is line two 

+

            ''', dedent=True, trimblanklines=True) 

+

            cog.out('', dedent=True, trimblanklines=True) 

+

            cog.outl("This is line three", trimblanklines=True) 

+

            //]]] 

+

            This is line one 

+

            This is line two 

+

            This is line three 

+

            //[[[end]]] 

+

            """ 

+

 

+

        infile = reindentBlock(infile) 

+

        self.assertEqual(Cog().processString(infile), infile) 

+

 

+

    def test22EndOfLine(self): 

+

        # In Python 2.2, this cog file was not parsing because the 

+

        # last line is indented but didn't end with a newline. 

+

        infile = """\ 

+

            //[[[cog 

+

            import cog 

+

            for i in range(3): 

+

                cog.out("%d\\n" % i) 

+

            //]]] 

+

            0 

+

            1 

+

            2 

+

            //[[[end]]] 

+

            """ 

+

 

+

        infile = reindentBlock(infile) 

+

        self.assertEqual(Cog().processString(infile), infile) 

+

 

+

    def testIndentedCode(self): 

+

        infile = """\ 

+

            first line 

+

                [[[cog 

+

                import cog 

+

                for i in range(3): 

+

                    cog.out("xx%d\\n" % i) 

+

                ]]] 

+

                xx0 

+

                xx1 

+

                xx2 

+

                [[[end]]] 

+

            last line 

+

            """ 

+

 

+

        infile = reindentBlock(infile) 

+

        self.assertEqual(Cog().processString(infile), infile) 

+

 

+

    def testPrefixedCode(self): 

+

        infile = """\ 

+

            --[[[cog 

+

            --import cog 

+

            --for i in range(3): 

+

            --    cog.out("xx%d\\n" % i) 

+

            --]]] 

+

            xx0 

+

            xx1 

+

            xx2 

+

            --[[[end]]] 

+

            """ 

+

 

+

        infile = reindentBlock(infile) 

+

        self.assertEqual(Cog().processString(infile), infile) 

+

 

+

    def testPrefixedIndentedCode(self): 

+

        infile = """\ 

+

            prologue 

+

            --[[[cog 

+

            --   import cog 

+

            --   for i in range(3): 

+

            --       cog.out("xy%d\\n" % i) 

+

            --]]] 

+

            xy0 

+

            xy1 

+

            xy2 

+

            --[[[end]]] 

+

            """ 

+

 

+

        infile = reindentBlock(infile) 

+

        self.assertEqual(Cog().processString(infile), infile) 

+

 

+

    def testBogusPrefixMatch(self): 

+

        infile = """\ 

+

            prologue 

+

            #[[[cog 

+

                import cog 

+

                # This comment should not be clobbered by removing the pound sign. 

+

                for i in range(3): 

+

                    cog.out("xy%d\\n" % i) 

+

            #]]] 

+

            xy0 

+

            xy1 

+

            xy2 

+

            #[[[end]]] 

+

            """ 

+

 

+

        infile = reindentBlock(infile) 

+

        self.assertEqual(Cog().processString(infile), infile) 

+

 

+

    def testNoFinalNewline(self): 

+

        # If the cog'ed output has no final newline, 

+

        # it shouldn't eat up the cog terminator. 

+

        infile = """\ 

+

            prologue 

+

            [[[cog 

+

                import cog 

+

                for i in range(3): 

+

                    cog.out("%d" % i) 

+

            ]]] 

+

            012 

+

            [[[end]]] 

+

            epilogue 

+

            """ 

+

 

+

        infile = reindentBlock(infile) 

+

        self.assertEqual(Cog().processString(infile), infile) 

+

 

+

    def testNoOutputAtAll(self): 

+

        # If there is absolutely no cog output, that's ok. 

+

        infile = """\ 

+

            prologue 

+

            [[[cog 

+

                i = 1 

+

            ]]] 

+

            [[[end]]] 

+

            epilogue 

+

            """ 

+

 

+

        infile = reindentBlock(infile) 

+

        self.assertEqual(Cog().processString(infile), infile) 

+

 

+

    def testPurelyBlankLine(self): 

+

        # If there is a blank line in the cog code with no whitespace 

+

        # prefix, that should be OK. 

+

 

+

        infile = """\ 

+

            prologue 

+

                [[[cog 

+

                    import sys 

+

                    cog.out("Hello") 

+

            $ 

+

                    cog.out("There") 

+

                ]]] 

+

                HelloThere 

+

                [[[end]]] 

+

            epilogue 

+

            """ 

+

 

+

        infile = reindentBlock(infile.replace('$', '')) 

+

        self.assertEqual(Cog().processString(infile), infile) 

+

 

+

    def testEmptyOutl(self): 

+

        # Alexander Belchenko suggested the string argument to outl should 

+

        # be optional.  Does it work? 

+

 

+

        infile = """\ 

+

            prologue 

+

            [[[cog 

+

                cog.outl("x") 

+

                cog.outl() 

+

                cog.outl("y") 

+

                cog.outl(trimblanklines=True) 

+

                cog.outl("z") 

+

            ]]] 

+

            x 

+

 

+

            y 

+

             

+

            z 

+

            [[[end]]] 

+

            epilogue 

+

            """ 

+

 

+

        infile = reindentBlock(infile) 

+

        self.assertEqual(Cog().processString(infile), infile) 

+

 

+

    def testFirstLineNum(self): 

+

        infile = """\ 

+

            fooey 

+

            [[[cog 

+

                cog.outl("started at line number %d" % cog.firstLineNum) 

+

            ]]] 

+

            started at line number 2 

+

            [[[end]]] 

+

            blah blah 

+

            [[[cog 

+

                cog.outl("and again at line %d" % cog.firstLineNum) 

+

            ]]] 

+

            and again at line 8 

+

            [[[end]]] 

+

            """ 

+

 

+

        infile = reindentBlock(infile) 

+

        self.assertEqual(Cog().processString(infile), infile) 

+

 

+

    def testCompactOneLineCode(self): 

+

        infile = """\ 

+

            first line 

+

            hey: [[[cog cog.outl("hello %d" % (3*3*3*3)) ]]] looky! 

+

            get rid of this! 

+

            [[[end]]] 

+

            last line 

+

            """ 

+

 

+

        outfile = """\ 

+

            first line 

+

            hey: [[[cog cog.outl("hello %d" % (3*3*3*3)) ]]] looky! 

+

            hello 81 

+

            [[[end]]] 

+

            last line 

+

            """ 

+

 

+

        infile = reindentBlock(infile) 

+

        self.assertEqual(Cog().processString(infile), reindentBlock(outfile)) 

+

 

+

    def testInsideOutCompact(self): 

+

        infile = """\ 

+

            first line 

+

            hey?: ]]] what is this? [[[cog strange! 

+

            get rid of this! 

+

            [[[end]]] 

+

            last line 

+

            """ 

+

        self.assertRaisesMsg(CogError, 

+

             "infile.txt(2): Cog code markers inverted", 

+

             Cog().processString, 

+

             reindentBlock(infile), "infile.txt") 

+

 

+

    def testSharingGlobals(self): 

+

        infile = """\ 

+

            first line 

+

            hey: [[[cog s="hey there" ]]] looky! 

+

            [[[end]]] 

+

            more literal junk. 

+

            [[[cog cog.outl(s) ]]] 

+

            [[[end]]] 

+

            last line 

+

            """ 

+

 

+

        outfile = """\ 

+

            first line 

+

            hey: [[[cog s="hey there" ]]] looky! 

+

            [[[end]]] 

+

            more literal junk. 

+

            [[[cog cog.outl(s) ]]] 

+

            hey there 

+

            [[[end]]] 

+

            last line 

+

            """ 

+

 

+

        infile = reindentBlock(infile) 

+

        self.assertEqual(Cog().processString(infile), reindentBlock(outfile)) 

+

 

+

class CogOptionsTests(TestCase): 

+

    """ Test the CogOptions class. 

+

    """ 

+

 

+

    def testEquality(self): 

+

        o = CogOptions() 

+

        p = CogOptions() 

+

        self.assertEqual(o, p) 

+

        o.parseArgs(['-r']) 

+

        self.assertNotEqual(o, p) 

+

        p.parseArgs(['-r']) 

+

        self.assertEqual(o, p) 

+

 

+

    def testCloning(self): 

+

        o = CogOptions() 

+

        o.parseArgs(['-I', 'fooey', '-I', 'booey', '-s', ' /*x*/']) 

+

        p = o.clone() 

+

        self.assertEqual(o, p) 

+

        p.parseArgs(['-I', 'huey', '-D', 'foo=quux']) 

+

        self.assertNotEqual(o, p) 

+

        q = CogOptions() 

+

        q.parseArgs(['-I', 'fooey', '-I', 'booey', '-s', ' /*x*/', '-I', 'huey', '-D', 'foo=quux']) 

+

        self.assertEqual(p, q) 

+

 

+

    def testCombiningFlags(self): 

+

        # Single-character flags can be combined. 

+

        o = CogOptions() 

+

        o.parseArgs(['-e', '-r', '-z']) 

+

        p = CogOptions() 

+

        p.parseArgs(['-erz']) 

+

        self.assertEqual(o, p) 

+

 

+

class FileStructureTests(TestCase): 

+

    """ Test cases to check that we're properly strict about the structure 

+

        of files. 

+

    """ 

+

 

+

    def isBad(self, infile, msg=None): 

+

        infile = reindentBlock(infile) 

+

        self.assertRaisesMsg(CogError, 

+

            msg, 

+

            Cog().processString, (infile), 'infile.txt') 

+

 

+

    def testBeginNoEnd(self): 

+

        infile = """\ 

+

            Fooey 

+

            #[[[cog 

+

                cog.outl('hello') 

+

            """ 

+

        self.isBad(infile, "infile.txt(2): Cog block begun but never ended.") 

+

 

+

    def testNoEoo(self): 

+

        infile = """\ 

+

            Fooey 

+

            #[[[cog 

+

                cog.outl('hello') 

+

            #]]] 

+

            """ 

+

        self.isBad(infile, "infile.txt(4): Missing '[[[end]]]' before end of file.") 

+

 

+

        infile2 = """\ 

+

            Fooey 

+

            #[[[cog 

+

                cog.outl('hello') 

+

            #]]] 

+

            #[[[cog 

+

                cog.outl('goodbye') 

+

            #]]] 

+

            """ 

+

        self.isBad(infile2, "infile.txt(5): Unexpected '[[[cog'") 

+

 

+

    def testStartWithEnd(self): 

+

        infile = """\ 

+

            #]]] 

+

            """ 

+

        self.isBad(infile, "infile.txt(1): Unexpected ']]]'") 

+

 

+

        infile2 = """\ 

+

            #[[[cog 

+

                cog.outl('hello') 

+

            #]]] 

+

            #[[[end]]]     

+

            #]]] 

+

            """ 

+

        self.isBad(infile2, "infile.txt(5): Unexpected ']]]'") 

+

 

+

    def testStartWithEoo(self): 

+

        infile = """\ 

+

            #[[[end]]] 

+

            """ 

+

        self.isBad(infile, "infile.txt(1): Unexpected '[[[end]]]'") 

+

 

+

        infile2 = """\ 

+

            #[[[cog 

+

                cog.outl('hello') 

+

            #]]] 

+

            #[[[end]]] 

+

            #[[[end]]] 

+

            """ 

+

        self.isBad(infile2, "infile.txt(5): Unexpected '[[[end]]]'") 

+

 

+

    def testNoEnd(self): 

+

        infile = """\ 

+

            #[[[cog 

+

                cog.outl("hello") 

+

            #[[[end]]] 

+

            """ 

+

        self.isBad(infile, "infile.txt(3): Unexpected '[[[end]]]'") 

+

 

+

        infile2 = """\ 

+

            #[[[cog 

+

                cog.outl('hello') 

+

            #]]] 

+

            #[[[end]]] 

+

            #[[[cog 

+

                cog.outl("hello") 

+

            #[[[end]]] 

+

            """ 

+

        self.isBad(infile2, "infile.txt(7): Unexpected '[[[end]]]'") 

+

 

+

    def testTwoBegins(self): 

+

        infile = """\ 

+

            #[[[cog 

+

            #[[[cog 

+

                cog.outl("hello") 

+

            #]]] 

+

            #[[[end]]] 

+

            """ 

+

        self.isBad(infile, "infile.txt(2): Unexpected '[[[cog'") 

+

 

+

        infile2 = """\ 

+

            #[[[cog 

+

                cog.outl("hello") 

+

            #]]] 

+

            #[[[end]]] 

+

            #[[[cog 

+

            #[[[cog 

+

                cog.outl("hello") 

+

            #]]] 

+

            #[[[end]]] 

+

            """ 

+

        self.isBad(infile2, "infile.txt(6): Unexpected '[[[cog'") 

+

 

+

    def testTwoEnds(self): 

+

        infile = """\ 

+

            #[[[cog 

+

                cog.outl("hello") 

+

            #]]] 

+

            #]]] 

+

            #[[[end]]] 

+

            """ 

+

        self.isBad(infile, "infile.txt(4): Unexpected ']]]'") 

+

 

+

        infile2 = """\ 

+

            #[[[cog 

+

                cog.outl("hello") 

+

            #]]] 

+

            #[[[end]]] 

+

            #[[[cog 

+

                cog.outl("hello") 

+

            #]]] 

+

            #]]] 

+

            #[[[end]]] 

+

            """ 

+

        self.isBad(infile2, "infile.txt(8): Unexpected ']]]'") 

+

 

+

class CogErrorTests(TestCase): 

+

    """ Test cases for cog.error(). 

+

    """ 

+

 

+

    def testErrorMsg(self): 

+

        infile = """\ 

+

            [[[cog cog.error("This ain't right!")]]] 

+

            [[[end]]] 

+

            """ 

+

 

+

        infile = reindentBlock(infile) 

+

        self.assertRaisesMsg(CogGeneratedError, 

+

            "This ain't right!", 

+

            Cog().processString, (infile)) 

+

 

+

    def testErrorNoMsg(self): 

+

        infile = """\ 

+

            [[[cog cog.error()]]] 

+

            [[[end]]] 

+

            """ 

+

 

+

        infile = reindentBlock(infile) 

+

        self.assertRaisesMsg(CogGeneratedError, 

+

            "Error raised by cog generator.", 

+

            Cog().processString, (infile)) 

+

 

+

    def testNoErrorIfErrorNotCalled(self): 

+

        infile = """\ 

+

            --[[[cog 

+

            --import cog 

+

            --for i in range(3): 

+

            --    if i > 10: 

+

            --        cog.error("Something is amiss!") 

+

            --    cog.out("xx%d\\n" % i) 

+

            --]]] 

+

            xx0 

+

            xx1 

+

            xx2 

+

            --[[[end]]] 

+

            """ 

+

 

+

        infile = reindentBlock(infile) 

+

        self.assertEqual(Cog().processString(infile), infile) 

+

 

+

class CogGeneratorGetCodeTests(TestCase): 

+

    """ Unit tests against CogGenerator to see if its getCode() method works 

+

        properly. 

+

    """ 

+

 

+

    def setUp(self): 

+

        """ All tests get a generator to use, and short same-length names for 

+

            the functions we're going to use. 

+

        """ 

+

        self.gen = CogGenerator() 

+

        self.m = self.gen.parseMarker 

+

        self.l = self.gen.parseLine 

+

 

+

    def testEmpty(self): 

+

        self.m('// [[[cog') 

+

        self.m('// ]]]') 

+

        self.assertEqual(self.gen.getCode(), '') 

+

 

+

    def testSimple(self): 

+

        self.m('// [[[cog') 

+

        self.l('  print "hello"') 

+

        self.l('  print "bye"') 

+

        self.m('// ]]]') 

+

        self.assertEqual(self.gen.getCode(), 'print "hello"\nprint "bye"') 

+

 

+

    def testCompressed1(self): 

+

        # For a while, I supported compressed code blocks, but no longer. 

+

        self.m('// [[[cog: print """') 

+

        self.l('// hello') 

+

        self.l('// bye') 

+

        self.m('// """)]]]') 

+

        self.assertEqual(self.gen.getCode(), 'hello\nbye') 

+

 

+

    def testCompressed2(self): 

+

        # For a while, I supported compressed code blocks, but no longer. 

+

        self.m('// [[[cog: print """') 

+

        self.l('hello') 

+

        self.l('bye') 

+

        self.m('// """)]]]') 

+

        self.assertEqual(self.gen.getCode(), 'hello\nbye') 

+

 

+

    def testCompressed3(self): 

+

        # For a while, I supported compressed code blocks, but no longer. 

+

        self.m('// [[[cog') 

+

        self.l('print """hello') 

+

        self.l('bye') 

+

        self.m('// """)]]]') 

+

        self.assertEqual(self.gen.getCode(), 'print """hello\nbye') 

+

 

+

    def testCompressed4(self): 

+

        # For a while, I supported compressed code blocks, but no longer. 

+

        self.m('// [[[cog: print """') 

+

        self.l('hello') 

+

        self.l('bye""")') 

+

        self.m('// ]]]') 

+

        self.assertEqual(self.gen.getCode(), 'hello\nbye""")') 

+

 

+

    def testNoCommonPrefixForMarkers(self): 

+

        # It's important to be able to use #if 0 to hide lines from a 

+

        # C++ compiler. 

+

        self.m('#if 0 //[[[cog') 

+

        self.l('\timport cog, sys') 

+

        self.l('') 

+

        self.l('\tprint sys.argv') 

+

        self.m('#endif //]]]') 

+

        self.assertEqual(self.gen.getCode(), 'import cog, sys\n\nprint sys.argv') 

+

 

+

class TestCaseWithTempDir(TestCase): 

+

 

+

    def newCog(self): 

+

        """ Initialize the cog members for another run. 

+

        """ 

+

        # Create a cog engine, and catch its output. 

+

        self.cog = Cog() 

+

        self.output = StringIO.StringIO() 

+

        self.cog.setOutput(stdout=self.output, stderr=self.output) 

+

 

+

    def setUp(self): 

+

        # Create a temporary directory. 

+

        self.tempdir = path.path(tempfile.gettempdir()) / ('testcog_tempdir_' + str(random.random())[2:]) 

+

        self.tempdir.mkdir() 

+

        self.olddir = os.getcwd() 

+

        os.chdir(self.tempdir) 

+

        self.newCog() 

+

 

+

    def tearDown(self): 

+

        os.chdir(self.olddir) 

+

        # Get rid of the temporary directory. 

+

        self.tempdir.rmtree() 

+

 

+

    def assertFilesSame(self, sFName1, sFName2): 

+

        self.assertEqual((self.tempdir / sFName1).text(), (self.tempdir / sFName2).text()) 

+

 

+

    def assertFileContent(self, sFName, sContent): 

+

        sAbsName = self.tempdir / sFName 

+

        f = open(sAbsName, 'rb') 

+

        try: 

+

            sFileContent = f.read() 

+

        finally: 

+

            f.close() 

+

        self.assertEqual(sFileContent, sContent) 

+

 

+

 

+

class ArgumentHandlingTests(TestCaseWithTempDir): 

+

 

+

    def testArgumentFailure(self): 

+

        # Return value 2 means usage problem. 

+

        assert(self.cog.main(['argv0', '-j']) == 2) 

+

        output = self.output.getvalue() 

+

        assert(output.find("option -j not recognized") >= 0) 

+

        self.assertRaises(CogUsageError, self.cog.callableMain, (['argv0'])) 

+

        self.assertRaises(CogUsageError, self.cog.callableMain, (['argv0', '-j'])) 

+

 

+

    def testNoDashOAndAtFile(self): 

+

        d = { 

+

            'cogfiles.txt': """\ 

+

                # Please run cog 

+

                """ 

+

            } 

+

 

+

        makeFiles(d) 

+

        self.assertRaises(CogUsageError, self.cog.callableMain, (['argv0', '-o', 'foo', '@cogfiles.txt'])) 

+

 

+

    def testDashV(self): 

+

        assert(self.cog.main(['argv0', '-v']) == 0) 

+

        output = self.output.getvalue() 

+

        self.assertEqual('Cog version %s\n' % __version__, output) 

+

 

+

    def producesHelp(self, args): 

+

        self.newCog() 

+

        argv = ['argv0'] + args.split() 

+

        assert(self.cog.main(argv) == 0) 

+

        self.assertEquals(usage, self.output.getvalue()) 

+

 

+

    def testDashH(self): 

+

        # -h or -? anywhere on the command line should just print help. 

+

        self.producesHelp("-h") 

+

        self.producesHelp("-?") 

+

        self.producesHelp("fooey.txt -h") 

+

        self.producesHelp("-o -r @fooey.txt -? @booey.txt") 

+

 

+

    def testDashOAndDashR(self): 

+

        d = { 

+

            'cogfile.txt': """\ 

+

                # Please run cog 

+

                """ 

+

            } 

+

 

+

        makeFiles(d) 

+

        self.assertRaises(CogUsageError, self.cog.callableMain, (['argv0', '-o', 'foo', '-r', 'cogfile.txt'])) 

+

 

+

    def testDashZ(self): 

+

        d = { 

+

            'test.cog': """\ 

+

                // This is my C++ file. 

+

                //[[[cog 

+

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

+

                for fn in fnames: 

+

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

+

                //]]] 

+

                """, 

+

 

+

            'test.out': """\ 

+

                // This is my C++ file. 

+

                //[[[cog 

+

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

+

                for fn in fnames: 

+

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

+

                //]]] 

+

                void DoSomething(); 

+

                void DoAnotherThing(); 

+

                void DoLastThing(); 

+

                """, 

+

            } 

+

 

+

        makeFiles(d) 

+

        self.assertRaisesMsg( 

+

            CogError, "test.cog(6): Missing '[[[end]]]' before end of file.", 

+

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

+

        self.newCog() 

+

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

+

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

+

 

+

    def testBadDashD(self): 

+

        self.assertRaises(CogUsageError, self.cog.callableMain, (['argv0', '-Dfooey', 'cog.txt'])) 

+

        self.assertRaises(CogUsageError, self.cog.callableMain, (['argv0', '-D', 'fooey', 'cog.txt'])) 

+

 

+

 

+

class TestFileHandling(TestCaseWithTempDir): 

+

 

+

    def testSimple(self): 

+

        d = { 

+

            'test.cog': """\ 

+

                // This is my C++ file. 

+

                //[[[cog 

+

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

+

                for fn in fnames: 

+

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

+

                //]]] 

+

                //[[[end]]] 

+

                """, 

+

 

+

            'test.out': """\ 

+

                // This is my C++ file. 

+

                //[[[cog 

+

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

+

                for fn in fnames: 

+

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

+

                //]]] 

+

                void DoSomething(); 

+

                void DoAnotherThing(); 

+

                void DoLastThing(); 

+

                //[[[end]]] 

+

                """, 

+

            } 

+

 

+

        makeFiles(d) 

+

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

+

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

+

        output = self.output.getvalue() 

+

        assert(output.find("(changed)") >= 0) 

+

 

+

    def testOutputFile(self): 

+

        # -o sets the output file. 

+

        d = { 

+

            'test.cog': """\ 

+

                // This is my C++ file. 

+

                //[[[cog 

+

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

+

                for fn in fnames: 

+

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

+

                //]]] 

+

                //[[[end]]] 

+

                """, 

+

 

+

            'test.out': """\ 

+

                // This is my C++ file. 

+

                //[[[cog 

+

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

+

                for fn in fnames: 

+

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

+

                //]]] 

+

                void DoSomething(); 

+

                void DoAnotherThing(); 

+

                void DoLastThing(); 

+

                //[[[end]]] 

+

                """, 

+

            } 

+

 

+

        makeFiles(d) 

+

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

+

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

+

 

+

    def testAtFile(self): 

+

        d = { 

+

            'one.cog': """\ 

+

                //[[[cog 

+

                cog.outl("hello world") 

+

                //]]] 

+

                //[[[end]]] 

+

                """, 

+

 

+

            'one.out': """\ 

+

                //[[[cog 

+

                cog.outl("hello world") 

+

                //]]] 

+

                hello world 

+

                //[[[end]]] 

+

                """, 

+

 

+

            'two.cog': """\ 

+

                //[[[cog 

+

                cog.outl("goodbye cruel world") 

+

                //]]] 

+

                //[[[end]]] 

+

                """, 

+

 

+

            'two.out': """\ 

+

                //[[[cog 

+

                cog.outl("goodbye cruel world") 

+

                //]]] 

+

                goodbye cruel world 

+

                //[[[end]]] 

+

                """, 

+

 

+

            'cogfiles.txt': """\ 

+

                # Please run cog 

+

                one.cog 

+

                 

+

                two.cog 

+

                """ 

+

            } 

+

 

+

        makeFiles(d) 

+

        self.cog.callableMain(['argv0', '-r', '@cogfiles.txt']) 

+

        self.assertFilesSame('one.cog', 'one.out') 

+

        self.assertFilesSame('two.cog', 'two.out') 

+

        output = self.output.getvalue() 

+

        assert(output.find("(changed)") >= 0) 

+

 

+

    def testNestedAtFile(self): 

+

        d = { 

+

            'one.cog': """\ 

+

                //[[[cog 

+

                cog.outl("hello world") 

+

                //]]] 

+

                //[[[end]]] 

+

                """, 

+

 

+

            'one.out': """\ 

+

                //[[[cog 

+

                cog.outl("hello world") 

+

                //]]] 

+

                hello world 

+

                //[[[end]]] 

+

                """, 

+

 

+

            'two.cog': """\ 

+

                //[[[cog 

+

                cog.outl("goodbye cruel world") 

+

                //]]] 

+

                //[[[end]]] 

+

                """, 

+

 

+

            'two.out': """\ 

+

                //[[[cog 

+

                cog.outl("goodbye cruel world") 

+

                //]]] 

+

                goodbye cruel world 

+

                //[[[end]]] 

+

                """, 

+

 

+

            'cogfiles.txt': """\ 

+

                # Please run cog 

+

                one.cog 

+

                @cogfiles2.txt 

+

                """, 

+

 

+

            'cogfiles2.txt': """\ 

+

                # This one too, please. 

+

                two.cog 

+

                """, 

+

            } 

+

 

+

        makeFiles(d) 

+

        self.cog.callableMain(['argv0', '-r', '@cogfiles.txt']) 

+

        self.assertFilesSame('one.cog', 'one.out') 

+

        self.assertFilesSame('two.cog', 'two.out') 

+

        output = self.output.getvalue() 

+

        assert(output.find("(changed)") >= 0) 

+

 

+

    def testAtFileWithArgs(self): 

+

        d = { 

+

            'both.cog': """\ 

+

                //[[[cog 

+

                cog.outl("one: %s" % globals().has_key('one')) 

+

                cog.outl("two: %s" % globals().has_key('two')) 

+

                //]]] 

+

                //[[[end]]] 

+

                """, 

+

 

+

            'one.out': """\ 

+

                //[[[cog 

+

                cog.outl("one: %s" % globals().has_key('one')) 

+

                cog.outl("two: %s" % globals().has_key('two')) 

+

                //]]] 

+

                one: True // ONE 

+

                two: False // ONE 

+

                //[[[end]]] 

+

                """, 

+

 

+

            'two.out': """\ 

+

                //[[[cog 

+

                cog.outl("one: %s" % globals().has_key('one')) 

+

                cog.outl("two: %s" % globals().has_key('two')) 

+

                //]]] 

+

                one: False // TWO 

+

                two: True // TWO 

+

                //[[[end]]] 

+

                """, 

+

 

+

            'cogfiles.txt': """\ 

+

                # Please run cog 

+

                both.cog -o both.one -s ' // ONE' -D one=x 

+

                both.cog -o both.two -s ' // TWO' -D two=x 

+

                """ 

+

            } 

+

 

+

        makeFiles(d) 

+

        self.cog.callableMain(['argv0', '@cogfiles.txt']) 

+

        self.assertFilesSame('both.one', 'one.out') 

+

        self.assertFilesSame('both.two', 'two.out') 

+

 

+

    def testAtFileWithBadArgCombo(self): 

+

        d = { 

+

            'both.cog': """\ 

+

                //[[[cog 

+

                cog.outl("one: %s" % globals().has_key('one')) 

+

                cog.outl("two: %s" % globals().has_key('two')) 

+

                //]]] 

+

                //[[[end]]] 

+

                """, 

+

 

+

            'cogfiles.txt': """\ 

+

                # Please run cog 

+

                both.cog  

+

                both.cog -d # This is bad: -r and -d 

+

                """ 

+

            } 

+

 

+

        makeFiles(d) 

+

        self.assertRaises(CogUsageError, self.cog.callableMain, (['argv0', '-r', '@cogfiles.txt'])) 

+

 

+

    def testAtFileWithTrickyFilenames(self): 

+

        d = { 

+

            'one 1.cog': """\ 

+

                //[[[cog cog.outl("hello world") ]]] 

+

                """, 

+

 

+

            'one.out': """\ 

+

                //[[[cog cog.outl("hello world") ]]] 

+

                hello world //xxx 

+

                """, 

+

 

+

            'subdir': { 

+

                'subback.cog': """\ 

+

                    //[[[cog cog.outl("down deep with backslashes") ]]] 

+

                    """, 

+

 

+

                'subfwd.cog': """\ 

+

                    //[[[cog cog.outl("down deep with slashes") ]]] 

+

                    """, 

+

                }, 

+

 

+

            'subback.out': """\ 

+

                //[[[cog cog.outl("down deep with backslashes") ]]] 

+

                down deep with backslashes //yyy 

+

                """, 

+

 

+

            'subfwd.out': """\ 

+

                //[[[cog cog.outl("down deep with slashes") ]]] 

+

                down deep with slashes //zzz 

+

                """, 

+

 

+

            'cogfiles.txt': """\ 

+

                # Please run cog 

+

                'one 1.cog' -s ' //xxx' 

+

                subdir\subback.cog -s ' //yyy' 

+

                subdir/subfwd.cog -s ' //zzz' 

+

                """ 

+

            } 

+

 

+

        makeFiles(d) 

+

        self.cog.callableMain(['argv0', '-z', '-r', '@cogfiles.txt']) 

+

        self.assertFilesSame('one 1.cog', 'one.out') 

+

        self.assertFilesSame('subdir/subback.cog', 'subback.out') 

+

        self.assertFilesSame('subdir/subfwd.cog', 'subfwd.out') 

+

 

+

 

+

class CogTestLineEndings(TestCaseWithTempDir): 

+

    """Tests for -U option (force LF line-endings in output).""" 

+

 

+

    lines_in = ['Some text.', 

+

                '//[[[cog', 

+

                'cog.outl("Cog text")', 

+

                '//]]]', 

+

                'gobbledegook.', 

+

                '//[[[end]]]', 

+

                'epilogue.', 

+

                ''] 

+

 

+

    lines_out = ['Some text.', 

+

                 '//[[[cog', 

+

                 'cog.outl("Cog text")', 

+

                 '//]]]', 

+

                 'Cog text', 

+

                 '//[[[end]]]', 

+

                 'epilogue.', 

+

                 ''] 

+

 

+

    def testOutputNativeEol(self): 

+

        makeFiles({'infile': '\n'.join(self.lines_in)}) 

+

        self.cog.callableMain(['argv0', '-o', 'outfile', 'infile']) 

+

        self.assertFileContent('outfile', os.linesep.join(self.lines_out)) 

+

 

+

    def testOutputLfEol(self): 

+

        makeFiles({'infile': '\n'.join(self.lines_in)}) 

+

        self.cog.callableMain(['argv0', '-U', '-o', 'outfile', 'infile']) 

+

        self.assertFileContent('outfile', '\n'.join(self.lines_out)) 

+

 

+

    def testReplaceNativeEol(self): 

+

        makeFiles({'test.cog': '\n'.join(self.lines_in)}) 

+

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

+

        self.assertFileContent('test.cog', os.linesep.join(self.lines_out)) 

+

 

+

    def testReplaceLfEol(self): 

+

        makeFiles({'test.cog': '\n'.join(self.lines_in)}) 

+

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

+

        self.assertFileContent('test.cog', '\n'.join(self.lines_out)) 

+

 

+

 

+

class TestCaseWithImports(TestCaseWithTempDir): 

+

    """ When running tests which import modules, the sys.modules list 

+

        leaks from one test to the next.  This test case class scrubs 

+

        the list after each run to keep the tests isolated from each other. 

+

    """ 

+

 

+

    def setUp(self): 

+

        TestCaseWithTempDir.setUp(self) 

+

        self.sysmodulekeys = list(sys.modules) 

+

 

+

    def tearDown(self): 

+

        modstoscrub = [ 

+

            modname 

+

            for modname in sys.modules 

+

            if modname not in self.sysmodulekeys 

+

            ] 

+

        for modname in modstoscrub: 

+

            del sys.modules[modname] 

+

        TestCaseWithTempDir.tearDown(self) 

+

 

+

 

+

class CogIncludeTests(TestCaseWithImports): 

+

    dincludes = { 

+

        'test.cog': """\ 

+

            //[[[cog 

+

                import mymodule 

+

            //]]] 

+

            //[[[end]]] 

+

            """, 

+

 

+

        'test.out': """\ 

+

            //[[[cog 

+

                import mymodule 

+

            //]]] 

+

            Hello from mymodule 

+

            //[[[end]]] 

+

            """, 

+

 

+

        'test2.out': """\ 

+

            //[[[cog 

+

                import mymodule 

+

            //]]] 

+

            Hello from mymodule in inc2 

+

            //[[[end]]] 

+

            """, 

+

 

+

        'include': { 

+

            'mymodule.py': """\ 

+

                import cog 

+

                cog.outl("Hello from mymodule") 

+

                """ 

+

            }, 

+

 

+

        'inc2': { 

+

            'mymodule.py': """\ 

+

                import cog 

+

                cog.outl("Hello from mymodule in inc2") 

+

                """ 

+

            }, 

+

 

+

        'inc3': { 

+

            'someothermodule.py': """\ 

+

                import cog 

+

                cog.outl("This is some other module.") 

+

                """ 

+

            }, 

+

        } 

+

 

+

    def testNeedIncludePath(self): 

+

        # Try it without the -I, to see that an ImportError happens. 

+

        makeFiles(self.dincludes) 

+

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

+

 

+

    def testIncludePath(self): 

+

        # Test that -I adds include directories properly. 

+

        makeFiles(self.dincludes) 

+

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

+

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

+

 

+

    def testTwoIncludePaths(self): 

+

        # Test that two -I's add include directories properly. 

+

        makeFiles(self.dincludes) 

+

        self.cog.callableMain(['argv0', '-r', '-I', 'include', '-I', 'inc2', 'test.cog']) 

+

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

+

 

+

    def testTwoIncludePaths2(self): 

+

        # Test that two -I's add include directories properly. 

+

        makeFiles(self.dincludes) 

+

        self.cog.callableMain(['argv0', '-r', '-I', 'inc2', '-I', 'include', 'test.cog']) 

+

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

+

 

+

    def testUselessIncludePath(self): 

+

        # Test that the search will continue past the first directory. 

+

        makeFiles(self.dincludes) 

+

        self.cog.callableMain(['argv0', '-r', '-I', 'inc3', '-I', 'include', 'test.cog']) 

+

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

+

 

+

    def testSysPathIsUnchanged(self): 

+

        d = { 

+

            'bad.cog': """\ 

+

                //[[[cog cog.error("Oh no!") ]]] 

+

                //[[[end]]] 

+

                """, 

+

            'good.cog': """\ 

+

                //[[[cog cog.outl("Oh yes!") ]]] 

+

                //[[[end]]] 

+

                """, 

+

            } 

+

 

+

        makeFiles(d) 

+

        # Is it unchanged just by creating a cog engine? 

+

        oldsyspath = sys.path[:] 

+

        self.newCog() 

+

        self.assertEqual(oldsyspath, sys.path) 

+

        # Is it unchanged for a successful run? 

+

        self.newCog() 

+

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

+

        self.assertEqual(oldsyspath, sys.path) 

+

        # Is it unchanged for a successful run with includes? 

+

        self.newCog() 

+

        self.cog.callableMain(['argv0', '-r', '-I', 'xyzzy', 'good.cog']) 

+

        self.assertEqual(oldsyspath, sys.path) 

+

        # Is it unchanged for a successful run with two includes? 

+

        self.newCog() 

+

        self.cog.callableMain(['argv0', '-r', '-I', 'xyzzy', '-I', 'quux', 'good.cog']) 

+

        self.assertEqual(oldsyspath, sys.path) 

+

        # Is it unchanged for a failed run? 

+

        self.newCog() 

+

        self.assertRaises(CogError, self.cog.callableMain, (['argv0', '-r', 'bad.cog'])) 

+

        self.assertEqual(oldsyspath, sys.path) 

+

        # Is it unchanged for a failed run with includes? 

+

        self.newCog() 

+

        self.assertRaises(CogError, self.cog.callableMain, (['argv0', '-r', '-I', 'xyzzy', 'bad.cog'])) 

+

        self.assertEqual(oldsyspath, sys.path) 

+

        # Is it unchanged for a failed run with two includes? 

+

        self.newCog() 

+

        self.assertRaises(CogError, self.cog.callableMain, (['argv0', '-r', '-I', 'xyzzy', '-I', 'quux', 'bad.cog'])) 

+

        self.assertEqual(oldsyspath, sys.path) 

+

 

+

    def testSubDirectories(self): 

+

        # Test that relative paths on the command line work, with includes. 

+

 

+

        d = { 

+

            'code': { 

+

                'test.cog': """\ 

+

                    //[[[cog 

+

                        import mysubmodule 

+

                    //]]] 

+

                    //[[[end]]] 

+

                    """, 

+

 

+

                'test.out': """\ 

+

                    //[[[cog 

+

                        import mysubmodule 

+

                    //]]] 

+

                    Hello from mysubmodule 

+

                    //[[[end]]] 

+

                    """, 

+

 

+

                'mysubmodule.py': """\ 

+

                    import cog 

+

                    cog.outl("Hello from mysubmodule") 

+

                    """ 

+

                } 

+

            } 

+

 

+

        makeFiles(d) 

+

        # We should be able to invoke cog without the -I switch, and it will 

+

        # auto-include the current directory 

+

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

+

        self.assertFilesSame('code/test.cog', 'code/test.out') 

+

 

+

 

+

class CogTestsInFiles(TestCaseWithTempDir): 

+

 

+

    def testWarnIfNoCogCode(self): 

+

        # Test that the -e switch warns if there is no Cog code. 

+

        d = { 

+

            'with.cog': """\ 

+

                //[[[cog 

+

                cog.outl("hello world") 

+

                //]]] 

+

                hello world 

+

                //[[[end]]] 

+

                """, 

+

 

+

            'without.cog': """\ 

+

                There's no cog 

+

                code in this file. 

+

                """, 

+

            } 

+

 

+

        makeFiles(d) 

+

        self.cog.callableMain(['argv0', '-e', 'with.cog']) 

+

        output = self.output.getvalue() 

+

        assert(output.find("Warning") < 0) 

+

        self.newCog() 

+

        self.cog.callableMain(['argv0', '-e', 'without.cog']) 

+

        output = self.output.getvalue() 

+

        assert(output.find("Warning: no cog code found in without.cog") >= 0) 

+

        self.newCog() 

+

        self.cog.callableMain(['argv0', 'without.cog']) 

+

        output = self.output.getvalue() 

+

        assert(output.find("Warning") < 0) 

+

 

+

    def testFileNameProps(self): 

+

        d = { 

+

            'cog1.txt': """\ 

+

                //[[[cog 

+

                cog.outl("This is %s in, %s out" % (cog.inFile, cog.outFile)) 

+

                //]]] 

+

                this is cog1.txt in, cog1.txt out 

+

                [[[end]]] 

+

                """, 

+

 

+

            'cog1.out': """\ 

+

                //[[[cog 

+

                cog.outl("This is %s in, %s out" % (cog.inFile, cog.outFile)) 

+

                //]]] 

+

                This is cog1.txt in, cog1.txt out 

+

                [[[end]]] 

+

                """, 

+

 

+

            'cog1out.out': """\ 

+

                //[[[cog 

+

                cog.outl("This is %s in, %s out" % (cog.inFile, cog.outFile)) 

+

                //]]] 

+

                This is cog1.txt in, cog1out.txt out 

+

                [[[end]]] 

+

                """, 

+

            } 

+

 

+

        makeFiles(d) 

+

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

+

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

+

        self.newCog() 

+

        self.cog.callableMain(['argv0', '-o', 'cog1out.txt', 'cog1.txt']) 

+

        self.assertFilesSame('cog1out.txt', 'cog1out.out') 

+

 

+

    def testGlobalsDontCrossFiles(self): 

+

        # Make sure that global values don't get shared between files. 

+

        d = { 

+

            'one.cog': """\ 

+

                //[[[cog s = "This was set in one.cog" ]]] 

+

                //[[[end]]] 

+

                //[[[cog cog.outl(s) ]]] 

+

                //[[[end]]] 

+

                """, 

+

 

+

            'one.out': """\ 

+

                //[[[cog s = "This was set in one.cog" ]]] 

+

                //[[[end]]] 

+

                //[[[cog cog.outl(s) ]]] 

+

                This was set in one.cog 

+

                //[[[end]]] 

+

                """, 

+

 

+

            'two.cog': """\ 

+

                //[[[cog 

+

                try: 

+

                    cog.outl(s) 

+

                except NameError: 

+

                    cog.outl("s isn't set!") 

+

                //]]] 

+

                //[[[end]]] 

+

                """, 

+

 

+

            'two.out': """\ 

+

                //[[[cog 

+

                try: 

+

                    cog.outl(s) 

+

                except NameError: 

+

                    cog.outl("s isn't set!") 

+

                //]]] 

+

                s isn't set! 

+

                //[[[end]]] 

+

                """, 

+

 

+

            'cogfiles.txt': """\ 

+

                # Please run cog 

+

                one.cog 

+

                 

+

                two.cog 

+

                """ 

+

            } 

+

 

+

        makeFiles(d) 

+

        self.cog.callableMain(['argv0', '-r', '@cogfiles.txt']) 

+

        self.assertFilesSame('one.cog', 'one.out') 

+

        self.assertFilesSame('two.cog', 'two.out') 

+

        output = self.output.getvalue() 

+

        assert(output.find("(changed)") >= 0) 

+

 

+

    def testRemoveGeneratedOutput(self): 

+

        d = { 

+

            'cog1.txt': """\ 

+

                //[[[cog 

+

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

+

                //]]] 

+

                This line was generated. 

+

                //[[[end]]] 

+

                This line was not. 

+

                """, 

+

 

+

            'cog1.out': """\ 

+

                //[[[cog 

+

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

+

                //]]] 

+

                //[[[end]]] 

+

                This line was not. 

+

                """, 

+

 

+

            'cog1.out2': """\ 

+

                //[[[cog 

+

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

+

                //]]] 

+

                This line was generated. 

+

                //[[[end]]] 

+

                This line was not. 

+

                """, 

+

            } 

+

 

+

        makeFiles(d) 

+

        # Remove generated output. 

+

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

+

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

+

        self.newCog() 

+

        # Regenerate the generated output. 

+

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

+

        self.assertFilesSame('cog1.txt', 'cog1.out2') 

+

        self.newCog() 

+

        # Remove the generated output again. 

+

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

+

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

+

 

+

    def testMsgCall(self): 

+

        infile = """\ 

+

            #[[[cog 

+

                cog.msg("Hello there!") 

+

            #]]] 

+

            #[[[end]]] 

+

            """ 

+

        infile = reindentBlock(infile) 

+

        self.assertEqual(self.cog.processString(infile), infile) 

+

        output = self.output.getvalue() 

+

        self.assertEqual(output, "Message: Hello there!\n") 

+

 

+

    def testErrorMessageHasNoTraceback(self): 

+

        # Test that a Cog error is printed to stderr with no traceback. 

+

 

+

        d = { 

+

            'cog1.txt': """\ 

+

                //[[[cog 

+

                cog.outl("This line was newly") 

+

                cog.outl("generated by cog") 

+

                cog.outl("blah blah.") 

+

                //]]] 

+

                Xhis line was newly 

+

                generated by cog 

+

                blah blah. 

+

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

+

                """, 

+

            } 

+

 

+

        makeFiles(d) 

+

        stderr = StringIO.StringIO() 

+

        self.cog.setOutput(stderr=stderr) 

+

        self.cog.main(['argv0', '-c', '-r', "cog1.txt"]) 

+

        output = self.output.getvalue() 

+

        self.assertEqual(self.output.getvalue(), "Cogging cog1.txt\n") 

+

        self.assertEqual(stderr.getvalue(), "cog1.txt(9): Output has been edited! Delete old checksum to unprotect.\n") 

+

 

+

    def testDashD(self): 

+

        d = { 

+

            'test.cog': """\ 

+

                --[[[cog cog.outl("Defined fooey as " + fooey) ]]] 

+

                --[[[end]]] 

+

                """, 

+

 

+

            'test.kablooey': """\ 

+

                --[[[cog cog.outl("Defined fooey as " + fooey) ]]] 

+

                Defined fooey as kablooey 

+

                --[[[end]]] 

+

                """, 

+

 

+

            'test.einstein': """\ 

+

                --[[[cog cog.outl("Defined fooey as " + fooey) ]]] 

+

                Defined fooey as e=mc2 

+

                --[[[end]]] 

+

                """, 

+

            } 

+

 

+

        makeFiles(d) 

+

        self.cog.callableMain(['argv0', '-r', '-D', 'fooey=kablooey', 'test.cog']) 

+

        self.assertFilesSame('test.cog', 'test.kablooey') 

+

        makeFiles(d) 

+

        self.cog.callableMain(['argv0', '-r', '-Dfooey=kablooey', 'test.cog']) 

+

        self.assertFilesSame('test.cog', 'test.kablooey') 

+

        makeFiles(d) 

+

        self.cog.callableMain(['argv0', '-r', '-Dfooey=e=mc2', 'test.cog']) 

+

        self.assertFilesSame('test.cog', 'test.einstein') 

+

        makeFiles(d) 

+

        self.cog.callableMain(['argv0', '-r', '-Dbar=quux', '-Dfooey=kablooey', 'test.cog']) 

+

        self.assertFilesSame('test.cog', 'test.kablooey') 

+

        makeFiles(d) 

+

        self.cog.callableMain(['argv0', '-r', '-Dfooey=kablooey', '-Dbar=quux', 'test.cog']) 

+

        self.assertFilesSame('test.cog', 'test.kablooey') 

+

        makeFiles(d) 

+

        self.cog.callableMain(['argv0', '-r', '-Dfooey=gooey', '-Dfooey=kablooey', 'test.cog']) 

+

        self.assertFilesSame('test.cog', 'test.kablooey') 

+

 

+

    def testOutputToStdout(self): 

+

        d = { 

+

            'test.cog': """\ 

+

                --[[[cog cog.outl('Hey there!') ]]] 

+

                --[[[end]]] 

+

                """ 

+

            } 

+

 

+

        makeFiles(d) 

+

        stderr = StringIO.StringIO() 

+

        self.cog.setOutput(stderr=stderr) 

+

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

+

        output = self.output.getvalue() 

+

        outerr = stderr.getvalue() 

+

        self.assertEqual(output, "--[[[cog cog.outl('Hey there!') ]]]\nHey there!\n--[[[end]]]\n") 

+

        self.assertEqual(outerr, "") 

+

 

+

    def testSuffixOutputLines(self): 

+

        d = { 

+

            'test.cog': """\ 

+

                Hey there. 

+

                ;[[[cog cog.outl('a\\nb\\n   \\nc') ]]] 

+

                ;[[[end]]] 

+

                Good bye. 

+

                """, 

+

 

+

            'test.out': """\ 

+

                Hey there. 

+

                ;[[[cog cog.outl('a\\nb\\n   \\nc') ]]] 

+

                a (foo) 

+

                b (foo) 

+

                    

+

                c (foo) 

+

                ;[[[end]]] 

+

                Good bye. 

+

                """, 

+

            } 

+

 

+

        makeFiles(d) 

+

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

+

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

+

 

+

    def testEmptySuffix(self): 

+

        d = { 

+

            'test.cog': """\ 

+

                ;[[[cog cog.outl('a\\nb\\nc') ]]] 

+

                ;[[[end]]] 

+

                """, 

+

 

+

            'test.out': """\ 

+

                ;[[[cog cog.outl('a\\nb\\nc') ]]] 

+

                a 

+

                b 

+

                c 

+

                ;[[[end]]] 

+

                """, 

+

            } 

+

 

+

        makeFiles(d) 

+

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

+

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

+

 

+

    def testHellishSuffix(self): 

+

        d = { 

+

            'test.cog': """\ 

+

                ;[[[cog cog.outl('a\\n\\nb') ]]] 

+

                """, 

+

 

+

            'test.out': """\ 

+

                ;[[[cog cog.outl('a\\n\\nb') ]]] 

+

                a /\\n*+([)]>< 

+

                 

+

                b /\\n*+([)]>< 

+

                """, 

+

            } 

+

 

+

        makeFiles(d) 

+

        self.cog.callableMain(['argv0', '-z', '-r', '-s', r' /\n*+([)]><', 'test.cog']) 

+

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

+

 

+

class WritabilityTests(TestCaseWithTempDir): 

+

 

+

    d = { 

+

        'test.cog': """\ 

+

            //[[[cog 

+

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

+

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

+

            //]]] 

+

            //[[[end]]] 

+

            """, 

+

 

+

        'test.out': """\ 

+

            //[[[cog 

+

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

+

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

+

            //]]] 

+

            void DoSomething(); 

+

            void DoAnotherThing(); 

+

            void DoLastThing(); 

+

            //[[[end]]] 

+

            """, 

+

        } 

+

 

+

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

+

        # for Windows 

+

        cmd_w_args = 'attrib -R %s' 

+

        cmd_w_asterisk = 'attrib -R *' 

+

    else:   # pragma: no cover 

+

        # for unix-like 

+

        cmd_w_args = 'chmod +w %s' 

+

        cmd_w_asterisk = 'chmod +w *' 

+

 

+

    def setUp(self): 

+

        TestCaseWithTempDir.setUp(self) 

+

        makeFiles(self.d) 

+

        self.testcog = self.tempdir / 'test.cog' 

+

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

+

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

+

 

+

    def tearDown(self): 

+

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

+

        TestCaseWithTempDir.tearDown(self) 

+

 

+

    def testReadonlyNoCommand(self): 

+

        self.assertRaisesMsg( 

+

            CogError, "Can't overwrite test.cog", 

+

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

+

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

+

 

+

    def testReadonlyWithCommand(self): 

+

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

+

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

+

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

+

 

+

    def testReadonlyWithCommandWithNoSlot(self): 

+

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

+

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

+

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

+

 

+

    def testReadonlyWithIneffectualCommand(self): 

+

        self.assertRaisesMsg( 

+

            CogError, "Couldn't make test.cog writable", 

+

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

+

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

+

 

+

class ChecksumTests(TestCaseWithTempDir): 

+

 

+

    def testCreateChecksumOutput(self): 

+

        d = { 

+

            'cog1.txt': """\ 

+

                //[[[cog 

+

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

+

                //]]] 

+

                This line was generated. 

+

                //[[[end]]] 

+

                This line was not. 

+

                """, 

+

 

+

            'cog1.out': """\ 

+

                //[[[cog 

+

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

+

                //]]] 

+

                This line was generated. 

+

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

+

                This line was not. 

+

                """, 

+

            } 

+

 

+

        makeFiles(d) 

+

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

+

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

+

 

+

    def testCheckChecksumOutput(self): 

+

        d = { 

+

            'cog1.txt': """\ 

+

                //[[[cog 

+

                cog.outl("This line was newly") 

+

                cog.outl("generated by cog") 

+

                cog.outl("blah blah.") 

+

                //]]] 

+

                This line was generated. 

+

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

+

                """, 

+

 

+

            'cog1.out': """\ 

+

                //[[[cog 

+

                cog.outl("This line was newly") 

+

                cog.outl("generated by cog") 

+

                cog.outl("blah blah.") 

+

                //]]] 

+

                This line was newly 

+

                generated by cog 

+

                blah blah. 

+

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

+

                """, 

+

            } 

+

 

+

        makeFiles(d) 

+

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

+

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

+

 

+

    def testRemoveChecksumOutput(self): 

+

        d = { 

+

            'cog1.txt': """\ 

+

                //[[[cog 

+

                cog.outl("This line was newly") 

+

                cog.outl("generated by cog") 

+

                cog.outl("blah blah.") 

+

                //]]] 

+

                This line was generated. 

+

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

+

                """, 

+

 

+

            'cog1.out': """\ 

+

                //[[[cog 

+

                cog.outl("This line was newly") 

+

                cog.outl("generated by cog") 

+

                cog.outl("blah blah.") 

+

                //]]] 

+

                This line was newly 

+

                generated by cog 

+

                blah blah. 

+

                //[[[end]]] fooey 

+

                """, 

+

            } 

+

 

+

        makeFiles(d) 

+

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

+

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

+

 

+

    def testTamperedChecksumOutput(self): 

+

        d = { 

+

            'cog1.txt': """\ 

+

                //[[[cog 

+

                cog.outl("This line was newly") 

+

                cog.outl("generated by cog") 

+

                cog.outl("blah blah.") 

+

                //]]] 

+

                Xhis line was newly 

+

                generated by cog 

+

                blah blah. 

+

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

+

                """, 

+

 

+

            'cog2.txt': """\ 

+

                //[[[cog 

+

                cog.outl("This line was newly") 

+

                cog.outl("generated by cog") 

+

                cog.outl("blah blah.") 

+

                //]]] 

+

                This line was newly 

+

                generated by cog 

+

                blah blah! 

+

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

+

                """, 

+

 

+

            'cog3.txt': """\ 

+

                //[[[cog 

+

                cog.outl("This line was newly") 

+

                cog.outl("generated by cog") 

+

                cog.outl("blah blah.") 

+

                //]]] 

+

                 

+

                This line was newly 

+

                generated by cog 

+

                blah blah. 

+

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

+

                """, 

+

 

+

            'cog4.txt': """\ 

+

                //[[[cog 

+

                cog.outl("This line was newly") 

+

                cog.outl("generated by cog") 

+

                cog.outl("blah blah.") 

+

                //]]] 

+

                This line was newly 

+

                generated by cog 

+

                blah blah.. 

+

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

+

                """, 

+

 

+

            'cog5.txt': """\ 

+

                //[[[cog 

+

                cog.outl("This line was newly") 

+

                cog.outl("generated by cog") 

+

                cog.outl("blah blah.") 

+

                //]]] 

+

                This line was newly 

+

                generated by cog 

+

                blah blah. 

+

                extra 

+

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

+

                """, 

+

 

+

            'cog6.txt': """\ 

+

                //[[[cog 

+

                cog.outl("This line was newly") 

+

                cog.outl("generated by cog") 

+

                cog.outl("blah blah.") 

+

                //]]] 

+

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

+

                """, 

+

            } 

+

 

+

        makeFiles(d) 

+

        self.assertRaisesMsg(CogError, 

+

            "cog1.txt(9): Output has been edited! Delete old checksum to unprotect.", 

+

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

+

        self.assertRaisesMsg(CogError, 

+

            "cog2.txt(9): Output has been edited! Delete old checksum to unprotect.", 

+

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

+

        self.assertRaisesMsg(CogError, 

+

            "cog3.txt(10): Output has been edited! Delete old checksum to unprotect.", 

+

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

+

        self.assertRaisesMsg(CogError, 

+

            "cog4.txt(9): Output has been edited! Delete old checksum to unprotect.", 

+

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

+

        self.assertRaisesMsg(CogError, 

+

            "cog5.txt(10): Output has been edited! Delete old checksum to unprotect.", 

+

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

+

        self.assertRaisesMsg(CogError, 

+

            "cog6.txt(6): Output has been edited! Delete old checksum to unprotect.", 

+

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

+

 

+

class BlakeTests(TestCaseWithTempDir): 

+

 

+

    # Blake Winton's contributions.         

+

    def testDeleteCode(self): 

+

        # -o sets the output file. 

+

        d = { 

+

            'test.cog': """\ 

+

                // This is my C++ file. 

+

                //[[[cog 

+

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

+

                for fn in fnames: 

+

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

+

                //]]] 

+

                Some Sample Code Here 

+

                //[[[end]]]Data Data 

+

                And Some More 

+

                """, 

+

 

+

            'test.out': """\ 

+

                // This is my C++ file. 

+

                void DoSomething(); 

+

                void DoAnotherThing(); 

+

                void DoLastThing(); 

+

                And Some More 

+

                """, 

+

            } 

+

 

+

        makeFiles(d) 

+

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

+

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

+

 

+

    def testDeleteCodeWithDashRFails(self): 

+

        d = { 

+

            'test.cog': """\ 

+

                // This is my C++ file. 

+

                """ 

+

            } 

+

 

+

        makeFiles(d) 

+

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

+

 

+

    def testSettingGlobals(self): 

+

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

+

        # processFile(). 

+

        d = { 

+

            'test.cog': """\ 

+

                // This is my C++ file. 

+

                //[[[cog 

+

                for fn in fnames: 

+

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

+

                //]]] 

+

                Some Sample Code Here 

+

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

+

 

+

            'test.out': """\ 

+

                // This is my C++ file. 

+

                void DoBlake(); 

+

                void DoWinton(); 

+

                void DoContribution(); 

+

                """, 

+

            } 

+

 

+

        makeFiles(d) 

+

        globals = {} 

+

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

+

        self.cog.options.bDeleteCode = True 

+

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

+

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

+

 

+

class ErrorCallTests(TestCaseWithTempDir): 

+

 

+

    def testErrorCallHasNoTraceback(self): 

+

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

+

        d = { 

+

            'error.cog': """\ 

+

                //[[[cog 

+

                cog.error("Something Bad!") 

+

                //]]] 

+

                //[[[end]]] 

+

                """, 

+

            } 

+

 

+

        makeFiles(d) 

+

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

+

        output = self.output.getvalue() 

+

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

+

 

+

    def testRealErrorHasTraceback(self): 

+

        # Test that a genuine error does show a traceback. 

+

        d = { 

+

            'error.cog': """\ 

+

                //[[[cog 

+

                raise RuntimeError("Hey!") 

+

                //]]] 

+

                //[[[end]]] 

+

                """, 

+

            } 

+

 

+

        makeFiles(d) 

+

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

+

        output = self.output.getvalue() 

+

        msg = 'Actual output:\n' + output 

+

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

+

        self.assert_(output.find("RuntimeError: Hey!") > 0, msg) 

+

 

+

 

+

if __name__ == '__main__':      #pragma: no cover 

+

    unittest.main() 

+

 

+

# Things not yet tested: 

+

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

diff --git a/doc/sample_html/cogapp_whiteutils.html b/doc/sample_html/cogapp_whiteutils.html index b2aaf86..3fbdc30 100644 --- a/doc/sample_html/cogapp_whiteutils.html +++ b/doc/sample_html/cogapp_whiteutils.html @@ -1,19 +1,21 @@ - + + Coverage for cogapp\whiteutils - - + @@ -26,9 +28,12 @@ function toggle_lines(btn, cls) {

37 statements - 34 run + 34 run 0 excluded 3 missing + + 2 partial +

@@ -43,129 +48,129 @@ function toggle_lines(btn, cls) {

4

5

6

-

7

+

7

8

-

9

+

9

10

11

12

13

-

14

+

14

15

-

16

+

16

17

18

19

-

20

+

20

21

22

23

-

24

-

25

-

26

+

24

+

25

+

26

27

28

-

29

+

29

30

-

31

+

31

32

33

34

35

-

36

-

37

-

38

-

39

-

40

-

41

-

42

-

43

-

44

-

45

-

46

+

36

+

37

+

38

+

39

+

40

+

41

+

42

+

43

+

44

+

45

+

46

47

-

48

+

48

49

50

-

51

+

51

52

-

53

-

54

-

55

-

56

-

57

-

58

-

59

-

60

-

61

-

62

-

63

+

53

+

54

+

55

+

56

+

57

+

58

+

59

+

60

+

61

+

62

+

63

-

""" Indentation utilities for Cog. 

-

    http://nedbatchelder.com/code/cog 

-

     

-

    Copyright 2004-2009, Ned Batchelder. 

-

""" 

-

 

-

import re 

-

 

-

def whitePrefix(strings): 

-

    """ Determine the whitespace prefix common to all non-blank lines 

-

        in the argument list. 

-

    """ 

-

    # Remove all blank lines from the list 

-

    strings = [s for s in strings if s.strip() != ''] 

-

 

-

    if not strings: return '' 

-

 

-

    # Find initial whitespace chunk in the first line. 

-

    # This is the best prefix we can hope for. 

-

    prefix = re.match(r'\s*', strings[0]).group(0) 

-

 

-

    # Loop over the other strings, keeping only as much of 

-

    # the prefix as matches each string. 

-

    for s in strings: 

-

        for i in range(len(prefix)): 

-

            if prefix[i] != s[i]: 

-

                prefix = prefix[:i] 

-

                break 

-

    return prefix 

-

 

-

def reindentBlock(lines, newIndent=''): 

-

    """ Take a block of text as a string or list of lines. 

-

        Remove any common whitespace indentation. 

-

        Re-indent using newIndent, and return it as a single string. 

-

    """ 

-

    if isinstance(lines, basestring): 

-

        lines = lines.split('\n') 

-

    oldIndent = whitePrefix(lines) 

-

    outLines = [] 

-

    for l in lines: 

-

        if oldIndent: 

-

            l = l.replace(oldIndent, '', 1) 

-

        if l and newIndent: 

-

            l = newIndent + l 

-

        outLines.append(l) 

-

    return '\n'.join(outLines) 

-

 

-

def commonPrefix(strings): 

-

    """ Find the longest string that is a prefix of all the strings. 

-

    """ 

-

    if not strings: 

-

        return '' 

-

    prefix = strings[0] 

-

    for s in strings: 

-

        if len(s) < len(prefix): 

-

            prefix = prefix[:len(s)] 

-

        if not prefix: 

-

            return '' 

-

        for i in range(len(prefix)): 

-

            if prefix[i] != s[i]: 

-

                prefix = prefix[:i] 

-

                break 

-

    return prefix 

+

""" Indentation utilities for Cog. 

+

    http://nedbatchelder.com/code/cog 

+

     

+

    Copyright 2004-2009, Ned Batchelder. 

+

""" 

+

 

+

import re 

+

 

+

def whitePrefix(strings): 

+

    """ Determine the whitespace prefix common to all non-blank lines 

+

        in the argument list. 

+

    """ 

+

    # Remove all blank lines from the list 

+

    strings = [s for s in strings if s.strip() != ''] 

+

 

+

    if not strings: return '' 

+

 

+

    # Find initial whitespace chunk in the first line. 

+

    # This is the best prefix we can hope for. 

+

    prefix = re.match(r'\s*', strings[0]).group(0) 

+

 

+

    # Loop over the other strings, keeping only as much of 

+

    # the prefix as matches each string. 

+

    for s in strings: 

+

        for i in range(len(prefix)): 

+

27            if prefix[i] != s[i]: 

+

                prefix = prefix[:i] 

+

                break 

+

    return prefix 

+

 

+

def reindentBlock(lines, newIndent=''): 

+

    """ Take a block of text as a string or list of lines. 

+

        Remove any common whitespace indentation. 

+

        Re-indent using newIndent, and return it as a single string. 

+

    """ 

+

    if isinstance(lines, basestring): 

+

        lines = lines.split('\n') 

+

    oldIndent = whitePrefix(lines) 

+

    outLines = [] 

+

    for l in lines: 

+

        if oldIndent: 

+

            l = l.replace(oldIndent, '', 1) 

+

        if l and newIndent: 

+

            l = newIndent + l 

+

        outLines.append(l) 

+

    return '\n'.join(outLines) 

+

 

+

def commonPrefix(strings): 

+

    """ Find the longest string that is a prefix of all the strings. 

+

    """ 

+

52    if not strings: 

+

        return '' 

+

    prefix = strings[0] 

+

    for s in strings: 

+

        if len(s) < len(prefix): 

+

            prefix = prefix[:len(s)] 

+

        if not prefix: 

+

            return '' 

+

        for i in range(len(prefix)): 

+

            if prefix[i] != s[i]: 

+

                prefix = prefix[:i] 

+

                break 

+

    return prefix 

diff --git a/doc/sample_html/coverage_html.js b/doc/sample_html/coverage_html.js new file mode 100644 index 0000000..c0abab8 --- /dev/null +++ b/doc/sample_html/coverage_html.js @@ -0,0 +1,64 @@ +// Coverage.py HTML report browser code. + +// Loaded on index.html +function index_page_ready($) { + // Look for a cookie containing previous sort settings: + sort_list = []; + cookie_name = "COVERAGE_INDEX_SORT"; + + // This almost makes it worth installing the jQuery cookie plugin: + if (document.cookie.indexOf(cookie_name) > -1) { + cookies = document.cookie.split(";"); + for (var i=0; i < cookies.length; i++) { + parts = cookies[i].split("=") + + if ($.trim(parts[0]) == cookie_name && parts[1]) { + sort_list = eval("[[" + parts[1] + "]]"); + break; + } + } + } + + // Create a new widget which exists only to save and restore + // the sort order: + $.tablesorter.addWidget({ + id: "persistentSort", + + // Format is called by the widget before displaying: + format: function(table) { + if (table.config.sortList.length == 0 && sort_list.length > 0) { + // This table hasn't been sorted before - we'll use + // our stored settings: + jQuery(table).trigger('sorton', [sort_list]); + } + else { + // This is not the first load - something has + // already defined sorting so we'll just update + // our stored value to match: + sort_list = table.config.sortList; + } + } + }); + + // Configure our tablesorter to handle the variable number of + // columns produced depending on report options: + var headers = {}; + var col_count = jQuery("table.index > thead > tr > th").length; + + headers[0] = { sorter: 'text' }; + for (var i = 1; i < col_count-1; i++) { + headers[i] = { sorter: 'digit' }; + } + headers[col_count-1] = { sorter: 'percent' }; + + // Enable the table sorter: + $("table.index").tablesorter({ + widgets: ['persistentSort'], + headers: headers + }); + + // Watch for page unload events so we can save the final sort settings: + $(window).unload(function() { + document.cookie = cookie_name + "=" + sort_list.toString() + "; path=/" + }); +} diff --git a/doc/sample_html/index.html b/doc/sample_html/index.html index c44d355..dd78fe4 100644 --- a/doc/sample_html/index.html +++ b/doc/sample_html/index.html @@ -1,86 +1,128 @@ - + - -Coverage report - - - + + + Coverage report + + + + + + + - + -
- - - - - - - - +
+
Modulestatementsrunexcludedcoverage
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Modulestatementsrunexcludedbranchesbr execcoverage
Total13265682330510441%
c:\ned\py\path28611401042235%
cogapp\cogapp38721931535451%
cogapp\makefiles296316013%
cogapp\test_cogapp587195174233%
cogapp\whiteutils37340282692%
+
- - c:\ned\py\path - 286 - 114 - 0 - 40% - - - - cogapp\cogapp - 387 - 219 - 3 - 57% - - - - cogapp\makefiles - 29 - 6 - 3 - 21% - - - - cogapp\test_cogapp - 587 - 195 - 17 - 33% - - - - cogapp\whiteutils - 37 - 34 - 0 - 92% - - - -Total -1326 -568 -23 -43% - - - - - - - + + diff --git a/doc/sample_html/jquery.tablesorter.min.js b/doc/sample_html/jquery.tablesorter.min.js new file mode 100644 index 0000000..64c7007 --- /dev/null +++ b/doc/sample_html/jquery.tablesorter.min.js @@ -0,0 +1,2 @@ + +(function($){$.extend({tablesorter:new function(){var parsers=[],widgets=[];this.defaults={cssHeader:"header",cssAsc:"headerSortUp",cssDesc:"headerSortDown",sortInitialOrder:"asc",sortMultiSortKey:"shiftKey",sortForce:null,sortAppend:null,textExtraction:"simple",parsers:{},widgets:[],widgetZebra:{css:["even","odd"]},headers:{},widthFixed:false,cancelSelection:true,sortList:[],headerList:[],dateFormat:"us",decimal:'.',debug:false};function benchmark(s,d){log(s+","+(new Date().getTime()-d.getTime())+"ms");}this.benchmark=benchmark;function log(s){if(typeof console!="undefined"&&typeof console.debug!="undefined"){console.log(s);}else{alert(s);}}function buildParserCache(table,$headers){if(table.config.debug){var parsersDebug="";}var rows=table.tBodies[0].rows;if(table.tBodies[0].rows[0]){var list=[],cells=rows[0].cells,l=cells.length;for(var i=0;i1){arr=arr.concat(checkCellColSpan(table,headerArr,row++));}else{if(table.tHead.length==1||(cell.rowSpan>1||!r[row+1])){arr.push(cell);}}}return arr;};function checkHeaderMetadata(cell){if(($.metadata)&&($(cell).metadata().sorter===false)){return true;};return false;}function checkHeaderOptions(table,i){if((table.config.headers[i])&&(table.config.headers[i].sorter===false)){return true;};return false;}function applyWidget(table){var c=table.config.widgets;var l=c.length;for(var i=0;i');$("tr:first td",table.tBodies[0]).each(function(){colgroup.append($('').css('width',$(this).width()));});$(table).prepend(colgroup);};}function updateHeaderSortCount(table,sortList){var c=table.config,l=sortList.length;for(var i=0;ib)?1:0));};function sortTextDesc(a,b){return((ba)?1:0));};function sortNumeric(a,b){return a-b;};function sortNumericDesc(a,b){return b-a;};function getCachedSortType(parsers,i){return parsers[i].type;};this.construct=function(settings){return this.each(function(){if(!this.tHead||!this.tBodies)return;var $this,$document,$headers,cache,config,shiftDown=0,sortOrder;this.config={};config=$.extend(this.config,$.tablesorter.defaults,settings);$this=$(this);$headers=buildHeaders(this);this.config.parsers=buildParserCache(this,$headers);cache=buildCache(this);var sortCSS=[config.cssDesc,config.cssAsc];fixColumnWidth(this);$headers.click(function(e){$this.trigger("sortStart");var totalRows=($this[0].tBodies[0]&&$this[0].tBodies[0].rows.length)||0;if(!this.sortDisabled&&totalRows>0){var $cell=$(this);var i=this.column;this.order=this.count++%2;if(!e[config.sortMultiSortKey]){config.sortList=[];if(config.sortForce!=null){var a=config.sortForce;for(var j=0;j0){$this.trigger("sorton",[config.sortList]);}applyWidget(this);});};this.addParser=function(parser){var l=parsers.length,a=true;for(var i=0;i