From e36601b92ad2354ade134288d9e097a098513a64 Mon Sep 17 00:00:00 2001 From: Tim Vergenz Date: Wed, 24 Apr 2024 22:12:58 -0400 Subject: [PATCH 1/3] refactor: reformat Python code via ruff --- .pre-commit-config.yaml | 6 + cogapp/__init__.py | 6 +- cogapp/cogapp.py | 283 ++++----- cogapp/makefiles.py | 15 +- cogapp/test_cogapp.py | 1153 ++++++++++++++++++------------------- cogapp/test_makefiles.py | 76 +-- cogapp/test_whiteutils.py | 119 ++-- cogapp/utils.py | 14 +- cogapp/whiteutils.py | 37 +- docs/conf.py | 18 +- 10 files changed, 863 insertions(+), 864 deletions(-) create mode 100644 .pre-commit-config.yaml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..1417062 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,6 @@ +repos: + +- repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.4.1 + hooks: + - id: ruff-format diff --git a/cogapp/__init__.py b/cogapp/__init__.py index f0aa578..d710539 100644 --- a/cogapp/__init__.py +++ b/cogapp/__init__.py @@ -1,7 +1,7 @@ -""" Cog content generation tool. - http://nedbatchelder.com/code/cog +"""Cog content generation tool. +http://nedbatchelder.com/code/cog - Copyright 2004-2024, Ned Batchelder. +Copyright 2004-2024, Ned Batchelder. """ from .cogapp import Cog, CogUsageError, main diff --git a/cogapp/cogapp.py b/cogapp/cogapp.py index 0e0c86a..7770421 100644 --- a/cogapp/cogapp.py +++ b/cogapp/cogapp.py @@ -1,5 +1,4 @@ -""" Cog content generation tool. -""" +"""Cog content generation tool.""" import copy import getopt @@ -61,45 +60,52 @@ -h Print this help. """ + class CogError(Exception): - """ Any exception raised by Cog. - """ - def __init__(self, msg, file='', line=0): + """Any exception raised by Cog.""" + + def __init__(self, msg, file="", line=0): if file: super().__init__(f"{file}({line}): {msg}") else: super().__init__(msg) + class CogUsageError(CogError): - """ An error in usage of command-line arguments in cog. - """ + """An error in usage of command-line arguments in cog.""" + pass + class CogInternalError(CogError): - """ An error in the coding of Cog. Should never happen. - """ + """An error in the coding of Cog. Should never happen.""" + pass + class CogGeneratedError(CogError): - """ An error raised by a user's cog generator. - """ + """An error raised by a user's cog generator.""" + pass + class CogUserException(CogError): - """ An exception caught when running a user's cog generator. - The argument is the traceback message to print. + """An exception caught when running a user's cog generator. + The argument is the traceback message to print. """ + pass + class CogCheckFailed(CogError): - """ A --check failed. - """ + """A --check failed.""" + pass class CogGenerator(Redirectable): - """ A generator pulled from a source file. - """ + """A generator pulled from a source file.""" + def __init__(self, options=None): super().__init__() self.markers = [] @@ -110,20 +116,19 @@ def parseMarker(self, l): self.markers.append(l) def parseLine(self, l): - self.lines.append(l.strip('\n')) + self.lines.append(l.strip("\n")) def getCode(self): - """ Extract the executable Python code from the generator. - """ + """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 ] + 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, '') + return reindentBlock(self.lines, "") def evaluate(self, cog, globals, fname): # figure out the right whitespace prefix for the output @@ -131,12 +136,12 @@ def evaluate(self, cog, globals, fname): intext = self.getCode() if not intext: - return '' + return "" prologue = "import " + cog.cogmodulename + " as cog\n" if self.options.sPrologue: - prologue += self.options.sPrologue + '\n' - code = compile(prologue + intext, str(fname), 'exec') + prologue += self.options.sPrologue + "\n" + code = compile(prologue + intext, str(fname), "exec") # Make sure the "cog" module has our state. cog.cogmodule.msg = self.msg @@ -148,7 +153,7 @@ def evaluate(self, cog, globals, fname): if self.options.bPrintOutput: sys.stdout = captured_stdout = io.StringIO() - self.outstring = '' + self.outstring = "" try: eval(code, globals) except CogError: @@ -169,46 +174,44 @@ def evaluate(self, cog, globals, fname): # 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' + if self.outstring and self.outstring[-1] != "\n": + self.outstring += "\n" return reindentBlock(self.outstring, prefOut) def msg(self, s): - self.prout("Message: "+s) + self.prout("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() == '': + 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() == '': + if lines and lines[-1].strip() == "": del lines[-1] - sOut = '\n'.join(lines)+'\n' + sOut = "\n".join(lines) + "\n" if dedent: sOut = reindentBlock(sOut) self.outstring += sOut - def outl(self, sOut='', **kw): - """ The cog.outl function. - """ + def outl(self, sOut="", **kw): + """The cog.outl function.""" self.out(sOut, **kw) - self.out('\n') + 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. + 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 CogOptions: - """ Options for a run of cog. - """ + """Options for a run of cog.""" + def __init__(self): # Defaults for argument values. self.args = [] @@ -225,28 +228,25 @@ def __init__(self): self.bEofCanBeEnd = False self.sSuffix = None self.bNewlines = False - self.sBeginSpec = '[[[cog' - self.sEndSpec = ']]]' - self.sEndOutput = '[[[end]]]' + self.sBeginSpec = "[[[cog" + self.sEndSpec = "]]]" + self.sEndOutput = "[[[end]]]" self.sEncoding = "utf-8" self.verbosity = 2 - self.sPrologue = '' + self.sPrologue = "" self.bPrintOutput = False self.bCheck = False def __eq__(self, other): - """ Comparison operator for tests to use. - """ + """Comparison operator for tests to use.""" return self.__dict__ == other.__dict__ def clone(self): - """ Make a clone of these options, for further refinement. - """ + """Make a clone of these options, for further refinement.""" return copy.deepcopy(self) def addToIncludePath(self, dirs): - """ Add directories to the include path. - """ + """Add directories to the include path.""" dirs = dirs.split(os.pathsep) self.includePath.extend(dirs) @@ -255,58 +255,58 @@ def parseArgs(self, argv): try: opts, self.args = getopt.getopt( argv, - 'cdD:eI:n:o:rs:p:PUvw:xz', + "cdD:eI:n:o:rs:p:PUvw:xz", [ - 'check', - 'markers=', - 'verbosity=', - ] + "check", + "markers=", + "verbosity=", + ], ) except getopt.error as msg: raise CogUsageError(msg) # Handle the command line arguments. for o, a in opts: - if o == '-c': + if o == "-c": self.bHashOutput = True - elif o == '-d': + elif o == "-d": self.bDeleteCode = True - elif o == '-D': - if a.count('=') < 1: + elif o == "-D": + if a.count("=") < 1: raise CogUsageError("-D takes a name=value argument") - name, value = a.split('=', 1) + name, value = a.split("=", 1) self.defines[name] = value - elif o == '-e': + elif o == "-e": self.bWarnEmpty = True - elif o == '-I': + elif o == "-I": self.addToIncludePath(os.path.abspath(a)) - elif o == '-n': + elif o == "-n": self.sEncoding = a - elif o == '-o': + elif o == "-o": self.sOutputName = a - elif o == '-r': + elif o == "-r": self.bReplace = True - elif o == '-s': + elif o == "-s": self.sSuffix = a - elif o == '-p': + elif o == "-p": self.sPrologue = a - elif o == '-P': + elif o == "-P": self.bPrintOutput = True - elif o == '-U': + elif o == "-U": self.bNewlines = True - elif o == '-v': + elif o == "-v": self.bShowVersion = True - elif o == '-w': + elif o == "-w": self.sMakeWritableCmd = a - elif o == '-x': + elif o == "-x": self.bNoGenerate = True - elif o == '-z': + elif o == "-z": self.bEofCanBeEnd = True - elif o == '--check': + elif o == "--check": self.bCheck = True - elif o == '--markers': + elif o == "--markers": self._parse_markers(a) - elif o == '--verbosity': + elif o == "--verbosity": self.verbosity = int(a) else: # Since getopt.getopt is given a list of possible flags, @@ -322,18 +322,19 @@ def _parse_markers(self, val): ) def validate(self): - """ Does nothing if everything is OK, raises CogError's if it's not. - """ + """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!)") + 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. - """ + """The Cog engine.""" + def __init__(self): super().__init__() self.options = CogOptions() @@ -344,7 +345,9 @@ def __init__(self): def _fixEndOutputPatterns(self): end_output = re.escape(self.options.sEndOutput) - self.reEndOutput = re.compile(end_output + r"(?P *\(checksum: (?P[a-f0-9]+)\))") + self.reEndOutput = re.compile( + end_output + r"(?P *\(checksum: (?P[a-f0-9]+)\))" + ) self.sEndFormat = self.options.sEndOutput + " (checksum: %s)" def showWarning(self, msg): @@ -360,18 +363,17 @@ def isEndOutputLine(self, s): return self.options.sEndOutput in s def createCogModule(self): - """ Make a cog "module" object so that imported Python modules - can say "import cog" and get our state. + """Make a cog "module" object so that imported Python modules + can say "import cog" and get our state. """ self.cogmodule = types.SimpleNamespace() self.cogmodule.path = [] def openOutputFile(self, fname): - """ Open an output file, taking all the details into account. - """ + """Open an output file, taking all the details into account.""" opts = {} mode = "w" - opts['encoding'] = self.options.sEncoding + opts["encoding"] = self.options.sEncoding if self.options.bNewlines: opts["newline"] = "\n" fdir = os.path.dirname(fname) @@ -380,20 +382,19 @@ def openOutputFile(self, fname): return open(fname, mode, **opts) def openInputFile(self, fname): - """ Open an input file. - """ + """Open an input file.""" if fname == "-": return sys.stdin else: return open(fname, encoding=self.options.sEncoding) 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. + """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 '' + sFileIn = fname or "" + sFileOut = fname or "" fInToClose = fOutToClose = None # Convert filenames to files. if isinstance(fIn, (bytes, str)): @@ -412,10 +413,10 @@ def processFile(self, fIn, fOut, fname=None, globals=None): self.cogmodule.inFile = sFileIn self.cogmodule.outFile = sFileOut - self.cogmodulename = 'cog_' + md5(sFileOut.encode()).hexdigest() + self.cogmodulename = "cog_" + md5(sFileOut.encode()).hexdigest() sys.modules[self.cogmodulename] = self.cogmodule # if "import cog" explicitly done in code by user, note threading will cause clashes. - sys.modules['cog'] = self.cogmodule + sys.modules["cog"] = self.cogmodule # The globals dict we'll use for this file. if globals is None: @@ -461,10 +462,11 @@ def processFile(self, fIn, fOut, fname=None, globals=None): beg = l.find(self.options.sBeginSpec) end = l.find(self.options.sEndSpec) if beg > end: - raise CogError("Cog code markers inverted", - file=sFileIn, line=firstLineNum) + raise CogError( + "Cog code markers inverted", file=sFileIn, line=firstLineNum + ) else: - sCode = l[beg+len(self.options.sBeginSpec):end].strip() + sCode = l[beg + len(self.options.sBeginSpec) : end].strip() gen.parseLine(sCode) else: # Deal with an ordinary code block. @@ -491,7 +493,9 @@ def processFile(self, fIn, fOut, fname=None, globals=None): if not l: raise CogError( "Cog block begun but never ended.", - file=sFileIn, line=firstLineNum) + file=sFileIn, + line=firstLineNum, + ) if not self.options.bDeleteCode: fOut.write(l) @@ -549,10 +553,13 @@ def processFile(self, fIn, fOut, fname=None, globals=None): hashMatch = self.reEndOutput.search(l) if self.options.bHashOutput: if hashMatch: - oldHash = hashMatch['hash'] + oldHash = hashMatch["hash"] if oldHash != curHash: - raise CogError("Output has been edited! Delete old checksum to unprotect.", - file=sFileIn, line=fIn.linenumber()) + 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: @@ -563,7 +570,7 @@ def processFile(self, fIn, fOut, fname=None, globals=None): # We don't want hashes output, so if there was one, get rid of # it. if hashMatch: - l = l.replace(hashMatch['hashsect'], '', 1) + l = l.replace(hashMatch["hashsect"], "", 1) if not self.options.bDeleteCode: fOut.write(l) @@ -577,23 +584,22 @@ def processFile(self, fIn, fOut, fname=None, globals=None): if fOutToClose: fOutToClose.close() - # A regex for non-empty lines, used by suffixLines. reNonEmptyLines = re.compile(r"^\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. + """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('\\', '\\\\') + 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. + """Process sInput as the text to cog. + Return the cogged output as a string. """ fOld = io.StringIO(sInput) fNew = io.StringIO() @@ -601,13 +607,12 @@ def processString(self, sInput, fname=None): return fNew.getvalue() def replaceFile(self, sOldPath, sNewText): - """ Replace file sOldPath with the contents 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) + cmd = self.options.sMakeWritableCmd.replace("%s", sOldPath) with os.popen(cmd) as cmdout: self.stdout.write(cmdout.read()) if not os.access(sOldPath, os.W_OK): @@ -633,8 +638,7 @@ def addToIncludePath(self, includePath): sys.path.extend(includePath) def processOneFile(self, sFile): - """ Process one filename through cog. - """ + """Process one filename through cog.""" self.saveIncludePath() bNeedNewline = False @@ -693,8 +697,7 @@ def processWildcards(self, sFile): self.processOneFile(sFile) def processFileList(self, sFileList): - """ Process the files in a file list. - """ + """Process the files in a file list.""" flist = self.openInputFile(sFileList) lines = flist.readlines() flist.close() @@ -702,27 +705,26 @@ def processFileList(self, sFileList): # Use shlex to parse the line like a shell. lex = shlex.shlex(l, posix=True) lex.whitespace_split = True - lex.commenters = '#' + lex.commenters = "#" # No escapes, so that backslash can be part of the path - lex.escape = '' + lex.escape = "" args = list(lex) if args: self.processArguments(args) def processArguments(self, args): - """ Process one command-line. - """ + """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 args[0][0] == "@": if self.options.sOutputName: raise CogUsageError("Can't use -o with @file") self.processFileList(args[0][1:]) - elif args[0][0] == '&': + elif args[0][0] == "&": if self.options.sOutputName: raise CogUsageError("Can't use -o with &file") file_list = args[0][1:] @@ -734,14 +736,14 @@ def processArguments(self, args): 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. + """All of command-line cog, but in a callable form. + This is used by main. + argv is the equivalent of sys.argv. """ argv = argv[1:] # Provide help if asked for anywhere in the command line. - if '-?' in argv or '-h' in argv: + if "-?" in argv or "-h" in argv: self.prerr(usage, end="") return @@ -763,8 +765,7 @@ def callableMain(self, argv): raise CogCheckFailed("Check failed") def main(self, argv): - """ Handle the command-line execution for cog. - """ + """Handle the command-line execution for cog.""" try: self.callableMain(argv) @@ -805,9 +806,11 @@ def find_cog_source(frame_summary, prologue): m = re.search(r"^$", filename) if m: if lineno <= len(prolines): - filename = '' - source = prolines[lineno-1] - lineno -= 1 # Because "import cog" is the first line in the prologue + filename = "" + source = prolines[lineno - 1] + lineno -= ( + 1 # Because "import cog" is the first line in the prologue + ) else: filename, coglineno = m.groups() coglineno = int(coglineno) diff --git a/cogapp/makefiles.py b/cogapp/makefiles.py index 5dae266..d3d604f 100644 --- a/cogapp/makefiles.py +++ b/cogapp/makefiles.py @@ -1,14 +1,12 @@ -""" Dictionary-to-filetree functions, to create test files for testing. -""" +"""Dictionary-to-filetree functions, to create test files for testing.""" import os.path from .whiteutils import reindentBlock -def makeFiles(d, basedir='.'): - """ Create files from the dictionary `d`, in the directory named by `basedir`. - """ +def makeFiles(d, basedir="."): + """Create files from the dictionary `d`, in the directory named by `basedir`.""" for name, contents in d.items(): child = os.path.join(basedir, name) if isinstance(contents, (bytes, str)): @@ -22,9 +20,10 @@ def makeFiles(d, basedir='.'): os.mkdir(child) makeFiles(contents, child) -def removeFiles(d, basedir='.'): - """ Remove the files created by makeFiles. - Directories are removed if they are empty. + +def removeFiles(d, basedir="."): + """Remove the files created by makeFiles. + Directories are removed if they are empty. """ for name, contents in d.items(): child = os.path.join(basedir, name) diff --git a/cogapp/test_cogapp.py b/cogapp/test_cogapp.py index 3a04750..2972b6a 100644 --- a/cogapp/test_cogapp.py +++ b/cogapp/test_cogapp.py @@ -1,5 +1,4 @@ -""" Test cogapp. -""" +"""Test cogapp.""" import io import os @@ -21,18 +20,17 @@ class CogTestsInMemory(TestCase): - """ Test cases for cogapp.Cog() - """ + """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' - ] + "", + " ", + " \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) @@ -323,7 +321,7 @@ def testPurelyBlankLine(self): epilogue """ - infile = reindentBlock(infile.replace('$', '')) + infile = reindentBlock(infile.replace("$", "")) self.assertEqual(Cog().processString(infile), infile) def testEmptyOutl(self): @@ -399,7 +397,9 @@ def testInsideOutCompact(self): [[[end]]] last line """ - with self.assertRaisesRegex(CogError, r"^infile.txt\(2\): Cog code markers inverted$"): + with self.assertRaisesRegex( + CogError, r"^infile.txt\(2\): Cog code markers inverted$" + ): Cog().processString(reindentBlock(infile), "infile.txt") def testSharingGlobals(self): @@ -467,61 +467,73 @@ def testCogPrevious(self): class CogOptionsTests(TestCase): - """ Test the CogOptions class. - """ + """Test the CogOptions class.""" def testEquality(self): o = CogOptions() p = CogOptions() self.assertEqual(o, p) - o.parseArgs(['-r']) + o.parseArgs(["-r"]) self.assertNotEqual(o, p) - p.parseArgs(['-r']) + p.parseArgs(["-r"]) self.assertEqual(o, p) def testCloning(self): o = CogOptions() - o.parseArgs(['-I', 'fooey', '-I', 'booey', '-s', ' /*x*/']) + o.parseArgs(["-I", "fooey", "-I", "booey", "-s", " /*x*/"]) p = o.clone() self.assertEqual(o, p) - p.parseArgs(['-I', 'huey', '-D', 'foo=quux']) + 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']) + 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']) + o.parseArgs(["-e", "-r", "-z"]) p = CogOptions() - p.parseArgs(['-erz']) + p.parseArgs(["-erz"]) self.assertEqual(o, p) def testMarkers(self): o = CogOptions() - o._parse_markers('a b c') - self.assertEqual('a', o.sBeginSpec) - self.assertEqual('b', o.sEndSpec) - self.assertEqual('c', o.sEndOutput) + o._parse_markers("a b c") + self.assertEqual("a", o.sBeginSpec) + self.assertEqual("b", o.sEndSpec) + self.assertEqual("c", o.sEndOutput) def testMarkersSwitch(self): o = CogOptions() - o.parseArgs(['--markers', 'a b c']) - self.assertEqual('a', o.sBeginSpec) - self.assertEqual('b', o.sEndSpec) - self.assertEqual('c', o.sEndOutput) + o.parseArgs(["--markers", "a b c"]) + self.assertEqual("a", o.sBeginSpec) + self.assertEqual("b", o.sEndSpec) + self.assertEqual("c", o.sEndOutput) class FileStructureTests(TestCase): - """ Test cases to check that we're properly strict about the structure - of files. + """Test cases to check that we're properly strict about the structure + of files. """ def isBad(self, infile, msg=None): infile = reindentBlock(infile) - with self.assertRaisesRegex(CogError, "^"+re.escape(msg)+"$"): - Cog().processString(infile, 'infile.txt') + with self.assertRaisesRegex(CogError, "^" + re.escape(msg) + "$"): + Cog().processString(infile, "infile.txt") def testBeginNoEnd(self): infile = """\ @@ -648,8 +660,7 @@ def testTwoEnds(self): class CogErrorTests(TestCase): - """ Test cases for cog.error(). - """ + """Test cases for cog.error().""" def testErrorMsg(self): infile = """\ @@ -668,7 +679,9 @@ def testErrorNoMsg(self): """ infile = reindentBlock(infile) - with self.assertRaisesRegex(CogGeneratedError, "^Error raised by cog generator.$"): + with self.assertRaisesRegex( + CogGeneratedError, "^Error raised by cog generator.$" + ): Cog().processString(infile) def testNoErrorIfErrorNotCalled(self): @@ -691,78 +704,76 @@ def testNoErrorIfErrorNotCalled(self): class CogGeneratorGetCodeTests(TestCase): - """ Unit tests against CogGenerator to see if its getCode() method works - properly. + """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. + """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(), '') + self.m("// [[[cog") + self.m("// ]]]") + self.assertEqual(self.gen.getCode(), "") def testSimple(self): - self.m('// [[[cog') + self.m("// [[[cog") self.l(' print "hello"') self.l(' print "bye"') - self.m('// ]]]') + 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.l("// hello") + self.l("// bye") self.m('// """)]]]') - self.assertEqual(self.gen.getCode(), 'hello\nbye') + 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.l("hello") + self.l("bye") self.m('// """)]]]') - self.assertEqual(self.gen.getCode(), 'hello\nbye') + 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.m("// [[[cog") self.l('print """hello') - self.l('bye') + 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("hello") self.l('bye""")') - self.m('// ]]]') + 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') + 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. - """ + """Initialize the cog members for another run.""" # Create a cog engine, and catch its output. self.cog = Cog() self.output = io.StringIO() @@ -770,7 +781,9 @@ def newCog(self): def setUp(self): # Create a temporary directory. - self.tempdir = os.path.join(tempfile.gettempdir(), 'testcog_tempdir_' + str(random.random())[2:]) + self.tempdir = os.path.join( + tempfile.gettempdir(), "testcog_tempdir_" + str(random.random())[2:] + ) os.mkdir(self.tempdir) self.olddir = os.getcwd() os.chdir(self.tempdir) @@ -782,49 +795,48 @@ def tearDown(self): shutil.rmtree(self.tempdir) def assertFilesSame(self, sFName1, sFName2): - with open(os.path.join(self.tempdir, sFName1), 'rb') as f1: + with open(os.path.join(self.tempdir, sFName1), "rb") as f1: text1 = f1.read() - with open(os.path.join(self.tempdir, sFName2), 'rb') as f2: + with open(os.path.join(self.tempdir, sFName2), "rb") as f2: text2 = f2.read() self.assertEqual(text1, text2) def assertFileContent(self, fname, content): absname = os.path.join(self.tempdir, fname) - with open(absname, 'rb') as f: + with open(absname, "rb") as f: file_content = f.read() self.assertEqual(file_content, content.encode("utf-8")) class ArgumentHandlingTests(TestCaseWithTempDir): - def testArgumentFailure(self): # Return value 2 means usage problem. - self.assertEqual(self.cog.main(['argv0', '-j']), 2) + self.assertEqual(self.cog.main(["argv0", "-j"]), 2) output = self.output.getvalue() self.assertIn("option -j not recognized", output) with self.assertRaisesRegex(CogUsageError, r"^No files to process$"): - self.cog.callableMain(['argv0']) + self.cog.callableMain(["argv0"]) with self.assertRaisesRegex(CogUsageError, r"^option -j not recognized$"): - self.cog.callableMain(['argv0', '-j']) + self.cog.callableMain(["argv0", "-j"]) def testNoDashOAndAtFile(self): makeFiles({"cogfiles.txt": "# Please run cog"}) with self.assertRaisesRegex(CogUsageError, r"^Can't use -o with @file$"): - self.cog.callableMain(['argv0', '-o', 'foo', '@cogfiles.txt']) + self.cog.callableMain(["argv0", "-o", "foo", "@cogfiles.txt"]) def testNoDashOAndAmpFile(self): makeFiles({"cogfiles.txt": "# Please run cog"}) with self.assertRaisesRegex(CogUsageError, r"^Can't use -o with &file$"): - self.cog.callableMain(['argv0', '-o', 'foo', '&cogfiles.txt']) + self.cog.callableMain(["argv0", "-o", "foo", "&cogfiles.txt"]) def testDashV(self): - self.assertEqual(self.cog.main(['argv0', '-v']), 0) + self.assertEqual(self.cog.main(["argv0", "-v"]), 0) output = self.output.getvalue() - self.assertEqual('Cog version %s\n' % __version__, output) + self.assertEqual("Cog version %s\n" % __version__, output) def producesHelp(self, args): self.newCog() - argv = ['argv0'] + args.split() + argv = ["argv0"] + args.split() self.assertEqual(self.cog.main(argv), 0) self.assertEqual(usage, self.output.getvalue()) @@ -837,18 +849,20 @@ def testDashH(self): def testDashOAndDashR(self): d = { - 'cogfile.txt': """\ + "cogfile.txt": """\ # Please run cog """ - } + } makeFiles(d) - with self.assertRaisesRegex(CogUsageError, r"^Can't use -o with -r \(they are opposites\)$"): - self.cog.callableMain(['argv0', '-o', 'foo', '-r', 'cogfile.txt']) + with self.assertRaisesRegex( + CogUsageError, r"^Can't use -o with -r \(they are opposites\)$" + ): + self.cog.callableMain(["argv0", "-o", "foo", "-r", "cogfile.txt"]) def testDashZ(self): d = { - 'test.cog': """\ + "test.cog": """\ // This is my C++ file. //[[[cog fnames = ['DoSomething', 'DoAnotherThing', 'DoLastThing'] @@ -856,8 +870,7 @@ def testDashZ(self): cog.outl("void %s();" % fn) //]]] """, - - 'test.out': """\ + "test.out": """\ // This is my C++ file. //[[[cog fnames = ['DoSomething', 'DoAnotherThing', 'DoLastThing'] @@ -868,26 +881,34 @@ def testDashZ(self): void DoAnotherThing(); void DoLastThing(); """, - } + } makeFiles(d) - with self.assertRaisesRegex(CogError, r"^test.cog\(6\): Missing '\[\[\[end\]\]\]' before end of file.$"): - self.cog.callableMain(['argv0', '-r', 'test.cog']) + with self.assertRaisesRegex( + CogError, r"^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') + self.cog.callableMain(["argv0", "-r", "-z", "test.cog"]) + self.assertFilesSame("test.cog", "test.out") def testBadDashD(self): with self.assertRaisesRegex(CogUsageError, r"^-D takes a name=value argument$"): - self.cog.callableMain(['argv0', '-Dfooey', 'cog.txt']) + self.cog.callableMain(["argv0", "-Dfooey", "cog.txt"]) with self.assertRaisesRegex(CogUsageError, r"^-D takes a name=value argument$"): - self.cog.callableMain(['argv0', '-D', 'fooey', 'cog.txt']) + self.cog.callableMain(["argv0", "-D", "fooey", "cog.txt"]) def testBadMarkers(self): - with self.assertRaisesRegex(CogUsageError, r"^--markers requires 3 values separated by spaces, could not parse 'X'$"): - self.cog.callableMain(['argv0', '--markers=X']) - with self.assertRaisesRegex(CogUsageError, r"^--markers requires 3 values separated by spaces, could not parse 'A B C D'$"): - self.cog.callableMain(['argv0', '--markers=A B C D']) + with self.assertRaisesRegex( + CogUsageError, + r"^--markers requires 3 values separated by spaces, could not parse 'X'$", + ): + self.cog.callableMain(["argv0", "--markers=X"]) + with self.assertRaisesRegex( + CogUsageError, + r"^--markers requires 3 values separated by spaces, could not parse 'A B C D'$", + ): + self.cog.callableMain(["argv0", "--markers=A B C D"]) class TestMain(TestCaseWithTempDir): @@ -900,7 +921,7 @@ def setUp(self): def tearDown(self): sys.stderr = self.old_stderr sys.argv = self.old_argv - sys.modules.pop('mycode', None) + sys.modules.pop("mycode", None) super().tearDown() def test_main_function(self): @@ -908,10 +929,10 @@ def test_main_function(self): ret = main() self.assertEqual(ret, 2) stderr = sys.stderr.getvalue() - self.assertEqual(stderr, 'option -Z not recognized\n(for help use -h)\n') + self.assertEqual(stderr, "option -Z not recognized\n(for help use -h)\n") files = { - 'test.cog': """\ + "test.cog": """\ //[[[cog def func(): import mycode @@ -924,12 +945,11 @@ def func(): //]]] //[[[end]]] """, - - 'mycode.py': """\ + "mycode.py": """\ def boom(): [][0] """, - } + } def test_error_report(self): self.check_error_report() @@ -971,12 +991,10 @@ def test_error_in_prologue(self): assert expected == sys.stderr.getvalue() - class TestFileHandling(TestCaseWithTempDir): - def testSimple(self): d = { - 'test.cog': """\ + "test.cog": """\ // This is my C++ file. //[[[cog fnames = ['DoSomething', 'DoAnotherThing', 'DoLastThing'] @@ -985,8 +1003,7 @@ def testSimple(self): //]]] //[[[end]]] """, - - 'test.out': """\ + "test.out": """\ // This is my C++ file. //[[[cog fnames = ['DoSomething', 'DoAnotherThing', 'DoLastThing'] @@ -998,17 +1015,17 @@ def testSimple(self): void DoLastThing(); //[[[end]]] """, - } + } makeFiles(d) - self.cog.callableMain(['argv0', '-r', 'test.cog']) - self.assertFilesSame('test.cog', 'test.out') + self.cog.callableMain(["argv0", "-r", "test.cog"]) + self.assertFilesSame("test.cog", "test.out") output = self.output.getvalue() self.assertIn("(changed)", output) def testPrintOutput(self): d = { - 'test.cog': """\ + "test.cog": """\ // This is my C++ file. //[[[cog fnames = ['DoSomething', 'DoAnotherThing', 'DoLastThing'] @@ -1017,8 +1034,7 @@ def testPrintOutput(self): //]]] //[[[end]]] """, - - 'test.out': """\ + "test.out": """\ // This is my C++ file. //[[[cog fnames = ['DoSomething', 'DoAnotherThing', 'DoLastThing'] @@ -1030,17 +1046,17 @@ def testPrintOutput(self): void DoLastThing(); //[[[end]]] """, - } + } makeFiles(d) - self.cog.callableMain(['argv0', '-rP', 'test.cog']) - self.assertFilesSame('test.cog', 'test.out') + self.cog.callableMain(["argv0", "-rP", "test.cog"]) + self.assertFilesSame("test.cog", "test.out") output = self.output.getvalue() self.assertIn("(changed)", output) def testWildcards(self): d = { - 'test.cog': """\ + "test.cog": """\ // This is my C++ file. //[[[cog fnames = ['DoSomething', 'DoAnotherThing', 'DoLastThing'] @@ -1049,8 +1065,7 @@ def testWildcards(self): //]]] //[[[end]]] """, - - 'test2.cog': """\ + "test2.cog": """\ // This is my C++ file. //[[[cog fnames = ['DoSomething', 'DoAnotherThing', 'DoLastThing'] @@ -1059,8 +1074,7 @@ def testWildcards(self): //]]] //[[[end]]] """, - - 'test.out': """\ + "test.out": """\ // This is my C++ file. //[[[cog fnames = ['DoSomething', 'DoAnotherThing', 'DoLastThing'] @@ -1072,8 +1086,7 @@ def testWildcards(self): void DoLastThing(); //[[[end]]] """, - - 'not_this_one.cog': """\ + "not_this_one.cog": """\ // This is my C++ file. //[[[cog fnames = ['DoSomething', 'DoAnotherThing', 'DoLastThing'] @@ -1082,8 +1095,7 @@ def testWildcards(self): //]]] //[[[end]]] """, - - 'not_this_one.out': """\ + "not_this_one.out": """\ // This is my C++ file. //[[[cog fnames = ['DoSomething', 'DoAnotherThing', 'DoLastThing'] @@ -1092,20 +1104,20 @@ def testWildcards(self): //]]] //[[[end]]] """, - } + } makeFiles(d) - self.cog.callableMain(['argv0', '-r', 't*.cog']) - self.assertFilesSame('test.cog', 'test.out') - self.assertFilesSame('test2.cog', 'test.out') - self.assertFilesSame('not_this_one.cog', 'not_this_one.out') + self.cog.callableMain(["argv0", "-r", "t*.cog"]) + self.assertFilesSame("test.cog", "test.out") + self.assertFilesSame("test2.cog", "test.out") + self.assertFilesSame("not_this_one.cog", "not_this_one.out") output = self.output.getvalue() self.assertIn("(changed)", output) def testOutputFile(self): # -o sets the output file. d = { - 'test.cog': """\ + "test.cog": """\ // This is my C++ file. //[[[cog fnames = ['DoSomething', 'DoAnotherThing', 'DoLastThing'] @@ -1114,8 +1126,7 @@ def testOutputFile(self): //]]] //[[[end]]] """, - - 'test.out': """\ + "test.out": """\ // This is my C++ file. //[[[cog fnames = ['DoSomething', 'DoAnotherThing', 'DoLastThing'] @@ -1127,121 +1138,111 @@ def testOutputFile(self): void DoLastThing(); //[[[end]]] """, - } + } makeFiles(d) - self.cog.callableMain(['argv0', '-o', 'in/a/dir/test.cogged', 'test.cog']) - self.assertFilesSame('in/a/dir/test.cogged', 'test.out') + self.cog.callableMain(["argv0", "-o", "in/a/dir/test.cogged", "test.cog"]) + self.assertFilesSame("in/a/dir/test.cogged", "test.out") def testAtFile(self): d = { - 'one.cog': """\ + "one.cog": """\ //[[[cog cog.outl("hello world") //]]] //[[[end]]] """, - - 'one.out': """\ + "one.out": """\ //[[[cog cog.outl("hello world") //]]] hello world //[[[end]]] """, - - 'two.cog': """\ + "two.cog": """\ //[[[cog cog.outl("goodbye cruel world") //]]] //[[[end]]] """, - - 'two.out': """\ + "two.out": """\ //[[[cog cog.outl("goodbye cruel world") //]]] goodbye cruel world //[[[end]]] """, - - 'cogfiles.txt': """\ + "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') + self.cog.callableMain(["argv0", "-r", "@cogfiles.txt"]) + self.assertFilesSame("one.cog", "one.out") + self.assertFilesSame("two.cog", "two.out") output = self.output.getvalue() self.assertIn("(changed)", output) def testNestedAtFile(self): d = { - 'one.cog': """\ + "one.cog": """\ //[[[cog cog.outl("hello world") //]]] //[[[end]]] """, - - 'one.out': """\ + "one.out": """\ //[[[cog cog.outl("hello world") //]]] hello world //[[[end]]] """, - - 'two.cog': """\ + "two.cog": """\ //[[[cog cog.outl("goodbye cruel world") //]]] //[[[end]]] """, - - 'two.out': """\ + "two.out": """\ //[[[cog cog.outl("goodbye cruel world") //]]] goodbye cruel world //[[[end]]] """, - - 'cogfiles.txt': """\ + "cogfiles.txt": """\ # Please run cog one.cog @cogfiles2.txt """, - - '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') + self.cog.callableMain(["argv0", "-r", "@cogfiles.txt"]) + self.assertFilesSame("one.cog", "one.out") + self.assertFilesSame("two.cog", "two.out") output = self.output.getvalue() self.assertIn("(changed)", output) def testAtFileWithArgs(self): d = { - 'both.cog': """\ + "both.cog": """\ //[[[cog cog.outl("one: %s" % ('one' in globals())) cog.outl("two: %s" % ('two' in globals())) //]]] //[[[end]]] """, - - 'one.out': """\ + "one.out": """\ //[[[cog cog.outl("one: %s" % ('one' in globals())) cog.outl("two: %s" % ('two' in globals())) @@ -1250,8 +1251,7 @@ def testAtFileWithArgs(self): two: False // ONE //[[[end]]] """, - - 'two.out': """\ + "two.out": """\ //[[[cog cog.outl("one: %s" % ('one' in globals())) cog.outl("two: %s" % ('two' in globals())) @@ -1260,39 +1260,40 @@ def testAtFileWithArgs(self): two: True // TWO //[[[end]]] """, - - 'cogfiles.txt': """\ + "cogfiles.txt": """\ # Please run cog both.cog -o in/a/dir/both.one -s ' // ONE' -D one=x both.cog -o in/a/dir/both.two -s ' // TWO' -D two=x - """ - } + """, + } makeFiles(d) - self.cog.callableMain(['argv0', '@cogfiles.txt']) - self.assertFilesSame('in/a/dir/both.one', 'one.out') - self.assertFilesSame('in/a/dir/both.two', 'two.out') + self.cog.callableMain(["argv0", "@cogfiles.txt"]) + self.assertFilesSame("in/a/dir/both.one", "one.out") + self.assertFilesSame("in/a/dir/both.two", "two.out") def testAtFileWithBadArgCombo(self): d = { - 'both.cog': """\ + "both.cog": """\ //[[[cog cog.outl("one: %s" % ('one' in globals())) cog.outl("two: %s" % ('two' in globals())) //]]] //[[[end]]] """, - - 'cogfiles.txt': """\ + "cogfiles.txt": """\ # Please run cog both.cog both.cog -d # This is bad: -r and -d - """ - } + """, + } makeFiles(d) - with self.assertRaisesRegex(CogUsageError, r"^Can't use -d with -r \(or you would delete all your source!\)$"): - self.cog.callableMain(['argv0', '-r', '@cogfiles.txt']) + with self.assertRaisesRegex( + CogUsageError, + r"^Can't use -d with -r \(or you would delete all your source!\)$", + ): + self.cog.callableMain(["argv0", "-r", "@cogfiles.txt"]) def testAtFileWithTrickyFilenames(self): def fix_backslashes(files_txt): @@ -1302,109 +1303,100 @@ def fix_backslashes(files_txt): return files_txt d = { - 'one 1.cog': """\ + "one 1.cog": """\ //[[[cog cog.outl("hello world") ]]] """, - - 'one.out': """\ + "one.out": """\ //[[[cog cog.outl("hello world") ]]] hello world //xxx """, - - 'subdir': { - 'subback.cog': """\ + "subdir": { + "subback.cog": """\ //[[[cog cog.outl("down deep with backslashes") ]]] """, - - 'subfwd.cog': """\ + "subfwd.cog": """\ //[[[cog cog.outl("down deep with slashes") ]]] """, - }, - - 'subback.out': """\ + }, + "subback.out": """\ //[[[cog cog.outl("down deep with backslashes") ]]] down deep with backslashes //yyy """, - - 'subfwd.out': """\ + "subfwd.out": """\ //[[[cog cog.outl("down deep with slashes") ]]] down deep with slashes //zzz """, - - 'cogfiles.txt': fix_backslashes("""\ + "cogfiles.txt": fix_backslashes("""\ # 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') + 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") def testAmpFile(self): d = { - 'code': { - 'files_to_cog': """\ + "code": { + "files_to_cog": """\ # A locally resolved file name. test.cog """, - - 'test.cog': """\ + "test.cog": """\ //[[[cog import myampsubmodule //]]] //[[[end]]] """, - - 'test.out': """\ + "test.out": """\ //[[[cog import myampsubmodule //]]] Hello from myampsubmodule //[[[end]]] """, - - 'myampsubmodule.py': """\ + "myampsubmodule.py": """\ import cog cog.outl("Hello from myampsubmodule") - """ - } + """, } + } makeFiles(d) print(os.path.abspath("code/test.out")) - self.cog.callableMain(['argv0', '-r', '&code/files_to_cog']) - self.assertFilesSame('code/test.cog', 'code/test.out') + self.cog.callableMain(["argv0", "-r", "&code/files_to_cog"]) + self.assertFilesSame("code/test.cog", "code/test.out") def run_with_verbosity(self, verbosity): d = { - 'unchanged.cog': """\ + "unchanged.cog": """\ //[[[cog cog.outl("hello world") //]]] hello world //[[[end]]] """, - - 'changed.cog': """\ + "changed.cog": """\ //[[[cog cog.outl("goodbye cruel world") //]]] //[[[end]]] """, - - 'cogfiles.txt': """\ + "cogfiles.txt": """\ unchanged.cog changed.cog - """ - } + """, + } makeFiles(d) - self.cog.callableMain(['argv0', '-r', '--verbosity='+verbosity, '@cogfiles.txt']) + self.cog.callableMain( + ["argv0", "-r", "--verbosity=" + verbosity, "@cogfiles.txt"] + ) output = self.output.getvalue() return output @@ -1418,64 +1410,68 @@ def test_verbosity1(self): def test_verbosity2(self): output = self.run_with_verbosity("2") - self.assertEqual(output, "Cogging unchanged.cog\nCogging changed.cog (changed)\n") + self.assertEqual( + output, "Cogging unchanged.cog\nCogging changed.cog (changed)\n" + ) 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.', - ''] + 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)) + 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)) + 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)) + 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)) + 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 CogTestCharacterEncoding(TestCaseWithTempDir): - def testSimple(self): d = { - 'test.cog': b"""\ + "test.cog": b"""\ // This is my C++ file. //[[[cog cog.outl("// Unicode: \xe1\x88\xb4 (U+1234)") //]]] //[[[end]]] """, - - 'test.out': b"""\ + "test.out": b"""\ // This is my C++ file. //[[[cog cog.outl("// Unicode: \xe1\x88\xb4 (U+1234)") @@ -1483,25 +1479,24 @@ def testSimple(self): // Unicode: \xe1\x88\xb4 (U+1234) //[[[end]]] """.replace(b"\n", os.linesep.encode()), - } + } makeFiles(d) - self.cog.callableMain(['argv0', '-r', 'test.cog']) - self.assertFilesSame('test.cog', 'test.out') + self.cog.callableMain(["argv0", "-r", "test.cog"]) + self.assertFilesSame("test.cog", "test.out") output = self.output.getvalue() self.assertIn("(changed)", output) def testFileEncodingOption(self): d = { - 'test.cog': b"""\ + "test.cog": b"""\ // \xca\xee\xe4\xe8\xf0\xe2\xea\xe0 Windows //[[[cog cog.outl("\xd1\xfa\xe5\xf8\xfc \xe5\xf9\xb8 \xfd\xf2\xe8\xf5 \xec\xff\xe3\xea\xe8\xf5 \xf4\xf0\xe0\xed\xf6\xf3\xe7\xf1\xea\xe8\xf5 \xe1\xf3\xeb\xee\xea \xe4\xe0 \xe2\xfb\xef\xe5\xe9 \xf7\xe0\xfe") //]]] //[[[end]]] """, - - 'test.out': b"""\ + "test.out": b"""\ // \xca\xee\xe4\xe8\xf0\xe2\xea\xe0 Windows //[[[cog cog.outl("\xd1\xfa\xe5\xf8\xfc \xe5\xf9\xb8 \xfd\xf2\xe8\xf5 \xec\xff\xe3\xea\xe8\xf5 \xf4\xf0\xe0\xed\xf6\xf3\xe7\xf1\xea\xe8\xf5 \xe1\xf3\xeb\xee\xea \xe4\xe0 \xe2\xfb\xef\xe5\xe9 \xf7\xe0\xfe") @@ -1509,19 +1504,19 @@ def testFileEncodingOption(self): \xd1\xfa\xe5\xf8\xfc \xe5\xf9\xb8 \xfd\xf2\xe8\xf5 \xec\xff\xe3\xea\xe8\xf5 \xf4\xf0\xe0\xed\xf6\xf3\xe7\xf1\xea\xe8\xf5 \xe1\xf3\xeb\xee\xea \xe4\xe0 \xe2\xfb\xef\xe5\xe9 \xf7\xe0\xfe //[[[end]]] """.replace(b"\n", os.linesep.encode()), - } + } makeFiles(d) - self.cog.callableMain(['argv0', '-n', 'cp1251', '-r', 'test.cog']) - self.assertFilesSame('test.cog', 'test.out') + self.cog.callableMain(["argv0", "-n", "cp1251", "-r", "test.cog"]) + self.assertFilesSame("test.cog", "test.out") output = self.output.getvalue() self.assertIn("(changed)", output) 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. + """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): @@ -1530,10 +1525,8 @@ def setUp(self): def tearDown(self): modstoscrub = [ - modname - for modname in sys.modules - if modname not in self.sysmodulekeys - ] + modname for modname in sys.modules if modname not in self.sysmodulekeys + ] for modname in modstoscrub: del sys.modules[modname] super().tearDown() @@ -1541,93 +1534,94 @@ def tearDown(self): class CogIncludeTests(TestCaseWithImports): dincludes = { - 'test.cog': """\ + "test.cog": """\ //[[[cog import mymodule //]]] //[[[end]]] """, - - 'test.out': """\ + "test.out": """\ //[[[cog import mymodule //]]] Hello from mymodule //[[[end]]] """, - - 'test2.out': """\ + "test2.out": """\ //[[[cog import mymodule //]]] Hello from mymodule in inc2 //[[[end]]] """, - - 'include': { - 'mymodule.py': """\ + "include": { + "mymodule.py": """\ import cog cog.outl("Hello from mymodule") """ - }, - - 'inc2': { - 'mymodule.py': """\ + }, + "inc2": { + "mymodule.py": """\ import cog cog.outl("Hello from mymodule in inc2") """ - }, - - 'inc3': { - 'someothermodule.py': """\ + }, + "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) msg = "(ImportError|ModuleNotFoundError): No module named '?mymodule'?" with self.assertRaisesRegex(CogUserException, msg): - self.cog.callableMain(['argv0', '-r', 'test.cog']) + 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') + 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') + 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') + 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') + self.cog.callableMain( + ["argv0", "-r", "-I", "inc3", "-I", "include", "test.cog"] + ) + self.assertFilesSame("test.cog", "test.out") def testSysPathIsUnchanged(self): d = { - 'bad.cog': """\ + "bad.cog": """\ //[[[cog cog.error("Oh no!") ]]] //[[[end]]] """, - 'good.cog': """\ + "good.cog": """\ //[[[cog cog.outl("Oh yes!") ]]] //[[[end]]] """, - } + } makeFiles(d) # Is it unchanged just by creating a cog engine? @@ -1636,151 +1630,145 @@ def testSysPathIsUnchanged(self): self.assertEqual(oldsyspath, sys.path) # Is it unchanged for a successful run? self.newCog() - self.cog.callableMain(['argv0', '-r', 'good.cog']) + 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.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.cog.callableMain(["argv0", "-r", "-I", "xyzzy", "-I", "quux", "good.cog"]) self.assertEqual(oldsyspath, sys.path) # Is it unchanged for a failed run? self.newCog() with self.assertRaisesRegex(CogError, r"^Oh no!$"): - self.cog.callableMain(['argv0', '-r', 'bad.cog']) + self.cog.callableMain(["argv0", "-r", "bad.cog"]) self.assertEqual(oldsyspath, sys.path) # Is it unchanged for a failed run with includes? self.newCog() with self.assertRaisesRegex(CogError, r"^Oh no!$"): - self.cog.callableMain(['argv0', '-r', '-I', 'xyzzy', 'bad.cog']) + 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() with self.assertRaisesRegex(CogError, r"^Oh no!$"): - self.cog.callableMain(['argv0', '-r', '-I', 'xyzzy', '-I', 'quux', 'bad.cog']) + 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': """\ + "code": { + "test.cog": """\ //[[[cog import mysubmodule //]]] //[[[end]]] """, - - 'test.out': """\ + "test.out": """\ //[[[cog import mysubmodule //]]] Hello from mysubmodule //[[[end]]] """, - - 'mysubmodule.py': """\ + "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') + 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': """\ + "with.cog": """\ //[[[cog cog.outl("hello world") //]]] hello world //[[[end]]] """, - - 'without.cog': """\ + "without.cog": """\ There's no cog code in this file. """, - } + } makeFiles(d) - self.cog.callableMain(['argv0', '-e', 'with.cog']) + self.cog.callableMain(["argv0", "-e", "with.cog"]) output = self.output.getvalue() self.assertNotIn("Warning", output) self.newCog() - self.cog.callableMain(['argv0', '-e', 'without.cog']) + self.cog.callableMain(["argv0", "-e", "without.cog"]) output = self.output.getvalue() self.assertIn("Warning: no cog code found in without.cog", output) self.newCog() - self.cog.callableMain(['argv0', 'without.cog']) + self.cog.callableMain(["argv0", "without.cog"]) output = self.output.getvalue() self.assertNotIn("Warning", output) def testFileNameProps(self): d = { - 'cog1.txt': """\ + "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': """\ + "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': """\ + "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.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') + 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': """\ + "one.cog": """\ //[[[cog s = "This was set in one.cog" ]]] //[[[end]]] //[[[cog cog.outl(s) ]]] //[[[end]]] """, - - 'one.out': """\ + "one.out": """\ //[[[cog s = "This was set in one.cog" ]]] //[[[end]]] //[[[cog cog.outl(s) ]]] This was set in one.cog //[[[end]]] """, - - 'two.cog': """\ + "two.cog": """\ //[[[cog try: cog.outl(s) @@ -1789,8 +1777,7 @@ def testGlobalsDontCrossFiles(self): //]]] //[[[end]]] """, - - 'two.out': """\ + "two.out": """\ //[[[cog try: cog.outl(s) @@ -1800,25 +1787,24 @@ def testGlobalsDontCrossFiles(self): s isn't set! //[[[end]]] """, - - 'cogfiles.txt': """\ + "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') + self.cog.callableMain(["argv0", "-r", "@cogfiles.txt"]) + self.assertFilesSame("one.cog", "one.out") + self.assertFilesSame("two.cog", "two.out") output = self.output.getvalue() self.assertIn("(changed)", output) def testRemoveGeneratedOutput(self): d = { - 'cog1.txt': """\ + "cog1.txt": """\ //[[[cog cog.outl("This line was generated.") //]]] @@ -1826,16 +1812,14 @@ def testRemoveGeneratedOutput(self): //[[[end]]] This line was not. """, - - 'cog1.out': """\ + "cog1.out": """\ //[[[cog cog.outl("This line was generated.") //]]] //[[[end]]] This line was not. """, - - 'cog1.out2': """\ + "cog1.out2": """\ //[[[cog cog.outl("This line was generated.") //]]] @@ -1843,20 +1827,20 @@ def testRemoveGeneratedOutput(self): //[[[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.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.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') + self.cog.callableMain(["argv0", "-r", "-x", "cog1.txt"]) + self.assertFilesSame("cog1.txt", "cog1.out") def testMsgCall(self): infile = """\ @@ -1874,7 +1858,7 @@ def testErrorMessageHasNoTraceback(self): # Test that a Cog error is printed to stderr with no traceback. d = { - 'cog1.txt': """\ + "cog1.txt": """\ //[[[cog cog.outl("This line was newly") cog.outl("generated by cog") @@ -1885,81 +1869,92 @@ def testErrorMessageHasNoTraceback(self): blah blah. //[[[end]]] (checksum: a8540982e5ad6b95c9e9a184b26f4346) """, - } + } makeFiles(d) stderr = io.StringIO() self.cog.setOutput(stderr=stderr) - self.cog.main(['argv0', '-c', '-r', "cog1.txt"]) + self.cog.main(["argv0", "-c", "-r", "cog1.txt"]) 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") + self.assertEqual( + stderr.getvalue(), + "cog1.txt(9): Output has been edited! Delete old checksum to unprotect.\n", + ) def testDashD(self): d = { - 'test.cog': """\ + "test.cog": """\ --[[[cog cog.outl("Defined fooey as " + fooey) ]]] --[[[end]]] """, - - 'test.kablooey': """\ + "test.kablooey": """\ --[[[cog cog.outl("Defined fooey as " + fooey) ]]] Defined fooey as kablooey --[[[end]]] """, - - 'test.einstein': """\ + "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') + 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') + 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') + 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') + 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') + 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') + self.cog.callableMain( + ["argv0", "-r", "-Dfooey=gooey", "-Dfooey=kablooey", "test.cog"] + ) + self.assertFilesSame("test.cog", "test.kablooey") def testOutputToStdout(self): d = { - 'test.cog': """\ + "test.cog": """\ --[[[cog cog.outl('Hey there!') ]]] --[[[end]]] """ - } + } makeFiles(d) stderr = io.StringIO() self.cog.setOutput(stderr=stderr) - self.cog.callableMain(['argv0', 'test.cog']) + 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( + output, "--[[[cog cog.outl('Hey there!') ]]]\nHey there!\n--[[[end]]]\n" + ) self.assertEqual(outerr, "") def testReadFromStdin(self): stdin = io.StringIO("--[[[cog cog.outl('Wow') ]]]\n--[[[end]]]\n") + def restore_stdin(old_stdin): sys.stdin = old_stdin + self.addCleanup(restore_stdin, sys.stdin) sys.stdin = stdin stderr = io.StringIO() self.cog.setOutput(stderr=stderr) - self.cog.callableMain(['argv0', '-']) + self.cog.callableMain(["argv0", "-"]) output = self.output.getvalue() outerr = stderr.getvalue() self.assertEqual(output, "--[[[cog cog.outl('Wow') ]]]\nWow\n--[[[end]]]\n") @@ -1967,90 +1962,86 @@ def restore_stdin(old_stdin): def testSuffixOutputLines(self): d = { - 'test.cog': """\ + "test.cog": """\ Hey there. ;[[[cog cog.outl('a\\nb\\n \\nc') ]]] ;[[[end]]] Good bye. """, - - 'test.out': """\ + "test.out": """\ Hey there. ;[[[cog cog.outl('a\\nb\\n \\nc') ]]] a (foo) b (foo) """ # These three trailing spaces are important. - # The suffix is not applied to completely blank lines. - """ + # The suffix is not applied to completely blank lines. + """ c (foo) ;[[[end]]] Good bye. """, - } + } makeFiles(d) - self.cog.callableMain(['argv0', '-r', '-s', ' (foo)', 'test.cog']) - self.assertFilesSame('test.cog', 'test.out') + self.cog.callableMain(["argv0", "-r", "-s", " (foo)", "test.cog"]) + self.assertFilesSame("test.cog", "test.out") def testEmptySuffix(self): d = { - 'test.cog': """\ + "test.cog": """\ ;[[[cog cog.outl('a\\nb\\nc') ]]] ;[[[end]]] """, - - 'test.out': """\ + "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') + self.cog.callableMain(["argv0", "-r", "-s", "", "test.cog"]) + self.assertFilesSame("test.cog", "test.out") def testHellishSuffix(self): d = { - 'test.cog': """\ + "test.cog": """\ ;[[[cog cog.outl('a\\n\\nb') ]]] """, - - 'test.out': """\ + "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') + self.cog.callableMain(["argv0", "-z", "-r", "-s", r" /\n*+([)]><", "test.cog"]) + self.assertFilesSame("test.cog", "test.out") def testPrologue(self): d = { - 'test.cog': """\ + "test.cog": """\ Some text. //[[[cog cog.outl(str(math.sqrt(2))[:12])]]] //[[[end]]] epilogue. """, - - 'test.out': """\ + "test.out": """\ Some text. //[[[cog cog.outl(str(math.sqrt(2))[:12])]]] 1.4142135623 //[[[end]]] epilogue. """, - } + } makeFiles(d) - self.cog.callableMain(['argv0', '-r', '-p', 'import math', 'test.cog']) - self.assertFilesSame('test.cog', 'test.out') + self.cog.callableMain(["argv0", "-r", "-p", "import math", "test.cog"]) + self.assertFilesSame("test.cog", "test.out") def testThreads(self): # Test that the implicitly imported cog module is actually different for @@ -2059,13 +2050,13 @@ def testThreads(self): d = {} for i in range(numthreads): - d[f'f{i}.cog'] = ( - "x\n" * i + - "[[[cog\n" + - f"assert cog.firstLineNum == int(FIRST) == {i+1}\n" + - "]]]\n" + - "[[[end]]]\n" - ) + d[f"f{i}.cog"] = ( + "x\n" * i + + "[[[cog\n" + + f"assert cog.firstLineNum == int(FIRST) == {i+1}\n" + + "]]]\n" + + "[[[end]]]\n" + ) makeFiles(d) results = [] @@ -2073,15 +2064,17 @@ def testThreads(self): def thread_main(num): try: ret = Cog().main( - ['cog.py', '-r', '-D', f'FIRST={num+1}', f'f{num}.cog'] - ) + ["cog.py", "-r", "-D", f"FIRST={num+1}", f"f{num}.cog"] + ) assert ret == 0 - except Exception as exc: # pragma: no cover (only happens on test failure) + except Exception as exc: # pragma: no cover (only happens on test failure) results.append(exc) else: results.append(None) - ts = [threading.Thread(target=thread_main, args=(i,)) for i in range(numthreads)] + ts = [ + threading.Thread(target=thread_main, args=(i,)) for i in range(numthreads) + ] for t in ts: t.start() for t in ts: @@ -2091,89 +2084,96 @@ def thread_main(num): class CheckTests(TestCaseWithTempDir): def run_check(self, args, status=0): - actual_status = self.cog.main(['argv0', '--check'] + args) + actual_status = self.cog.main(["argv0", "--check"] + args) print(self.output.getvalue()) self.assertEqual(status, actual_status) def assert_made_files_unchanged(self, d): for name, content in d.items(): content = reindentBlock(content) - if os.name == 'nt': + if os.name == "nt": content = content.replace("\n", "\r\n") self.assertFileContent(name, content) def test_check_no_cog(self): d = { - 'hello.txt': """\ + "hello.txt": """\ Hello. """, - } + } makeFiles(d) - self.run_check(['hello.txt'], status=0) + self.run_check(["hello.txt"], status=0) self.assertEqual(self.output.getvalue(), "Checking hello.txt\n") self.assert_made_files_unchanged(d) def test_check_good(self): d = { - 'unchanged.cog': """\ + "unchanged.cog": """\ //[[[cog cog.outl("hello world") //]]] hello world //[[[end]]] """, - } + } makeFiles(d) - self.run_check(['unchanged.cog'], status=0) + self.run_check(["unchanged.cog"], status=0) self.assertEqual(self.output.getvalue(), "Checking unchanged.cog\n") self.assert_made_files_unchanged(d) def test_check_bad(self): d = { - 'changed.cog': """\ + "changed.cog": """\ //[[[cog cog.outl("goodbye world") //]]] hello world //[[[end]]] """, - } + } makeFiles(d) - self.run_check(['changed.cog'], status=5) - self.assertEqual(self.output.getvalue(), "Checking changed.cog (changed)\nCheck failed\n") + self.run_check(["changed.cog"], status=5) + self.assertEqual( + self.output.getvalue(), "Checking changed.cog (changed)\nCheck failed\n" + ) self.assert_made_files_unchanged(d) def test_check_mixed(self): d = { - 'unchanged.cog': """\ + "unchanged.cog": """\ //[[[cog cog.outl("hello world") //]]] hello world //[[[end]]] """, - 'changed.cog': """\ + "changed.cog": """\ //[[[cog cog.outl("goodbye world") //]]] hello world //[[[end]]] """, - } + } makeFiles(d) for verbosity, output in [ ("0", "Check failed\n"), ("1", "Checking changed.cog (changed)\nCheck failed\n"), - ("2", "Checking unchanged.cog\nChecking changed.cog (changed)\nCheck failed\n"), + ( + "2", + "Checking unchanged.cog\nChecking changed.cog (changed)\nCheck failed\n", + ), ]: self.newCog() - self.run_check(['--verbosity=%s' % verbosity, 'unchanged.cog', 'changed.cog'], status=5) + self.run_check( + ["--verbosity=%s" % verbosity, "unchanged.cog", "changed.cog"], status=5 + ) self.assertEqual(self.output.getvalue(), output) self.assert_made_files_unchanged(d) def test_check_with_good_checksum(self): d = { - 'good.txt': """\ + "good.txt": """\ //[[[cog cog.outl("This line was newly") cog.outl("generated by cog") @@ -2184,16 +2184,16 @@ def test_check_with_good_checksum(self): blah blah. //[[[end]]] (checksum: a8540982e5ad6b95c9e9a184b26f4346) """, - } + } makeFiles(d) # Have to use -c with --check if there are checksums in the file. - self.run_check(['-c', 'good.txt'], status=0) + self.run_check(["-c", "good.txt"], status=0) self.assertEqual(self.output.getvalue(), "Checking good.txt\n") self.assert_made_files_unchanged(d) def test_check_with_bad_checksum(self): d = { - 'bad.txt': """\ + "bad.txt": """\ //[[[cog cog.outl("This line was newly") cog.outl("generated by cog") @@ -2204,26 +2204,27 @@ def test_check_with_bad_checksum(self): blah blah. //[[[end]]] (checksum: a9999999e5ad6b95c9e9a184b26f4346) """, - } + } makeFiles(d) # Have to use -c with --check if there are checksums in the file. - self.run_check(['-c', 'bad.txt'], status=1) - self.assertEqual(self.output.getvalue(), "Checking bad.txt\nbad.txt(9): Output has been edited! Delete old checksum to unprotect.\n") + self.run_check(["-c", "bad.txt"], status=1) + self.assertEqual( + self.output.getvalue(), + "Checking bad.txt\nbad.txt(9): Output has been edited! Delete old checksum to unprotect.\n", + ) self.assert_made_files_unchanged(d) class WritabilityTests(TestCaseWithTempDir): - d = { - 'test.cog': """\ + "test.cog": """\ //[[[cog for fn in ['DoSomething', 'DoAnotherThing', 'DoLastThing']: cog.outl("void %s();" % fn) //]]] //[[[end]]] """, - - 'test.out': """\ + "test.out": """\ //[[[cog for fn in ['DoSomething', 'DoAnotherThing', 'DoLastThing']: cog.outl("void %s();" % fn) @@ -2233,54 +2234,53 @@ class WritabilityTests(TestCaseWithTempDir): void DoLastThing(); //[[[end]]] """, - } + } - if os.name == 'nt': + if os.name == "nt": # for Windows - cmd_w_args = 'attrib -R %s' - cmd_w_asterisk = 'attrib -R *' + cmd_w_args = "attrib -R %s" + cmd_w_asterisk = "attrib -R *" else: # for unix-like - cmd_w_args = 'chmod +w %s' - cmd_w_asterisk = 'chmod +w *' + cmd_w_args = "chmod +w %s" + cmd_w_asterisk = "chmod +w *" def setUp(self): super().setUp() makeFiles(self.d) - self.testcog = os.path.join(self.tempdir, 'test.cog') - os.chmod(self.testcog, stat.S_IREAD) # Make the file readonly. + self.testcog = os.path.join(self.tempdir, "test.cog") + os.chmod(self.testcog, stat.S_IREAD) # Make the file readonly. assert not os.access(self.testcog, os.W_OK) def tearDown(self): - os.chmod(self.testcog, stat.S_IWRITE) # Make the file writable again. + os.chmod(self.testcog, stat.S_IWRITE) # Make the file writable again. super().tearDown() def testReadonlyNoCommand(self): with self.assertRaisesRegex(CogError, "^Can't overwrite test.cog$"): - self.cog.callableMain(['argv0', '-r', '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') + 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') + 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): with self.assertRaisesRegex(CogError, "^Couldn't make test.cog writable$"): - self.cog.callableMain(['argv0', '-r', '-w', 'echo %s', 'test.cog']) + 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': """\ + "cog1.txt": """\ //[[[cog cog.outl("This line was generated.") //]]] @@ -2288,8 +2288,7 @@ def testCreateChecksumOutput(self): //[[[end]]] This line was not. """, - - 'cog1.out': """\ + "cog1.out": """\ //[[[cog cog.outl("This line was generated.") //]]] @@ -2297,15 +2296,15 @@ def testCreateChecksumOutput(self): //[[[end]]] (checksum: 8adb13fb59b996a1c7f0065ea9f3d893) This line was not. """, - } + } makeFiles(d) - self.cog.callableMain(['argv0', '-r', '-c', 'cog1.txt']) - self.assertFilesSame('cog1.txt', 'cog1.out') + self.cog.callableMain(["argv0", "-r", "-c", "cog1.txt"]) + self.assertFilesSame("cog1.txt", "cog1.out") def testCheckChecksumOutput(self): d = { - 'cog1.txt': """\ + "cog1.txt": """\ //[[[cog cog.outl("This line was newly") cog.outl("generated by cog") @@ -2314,8 +2313,7 @@ def testCheckChecksumOutput(self): This line was generated. //[[[end]]] (checksum: 8adb13fb59b996a1c7f0065ea9f3d893) """, - - 'cog1.out': """\ + "cog1.out": """\ //[[[cog cog.outl("This line was newly") cog.outl("generated by cog") @@ -2326,15 +2324,15 @@ def testCheckChecksumOutput(self): blah blah. //[[[end]]] (checksum: a8540982e5ad6b95c9e9a184b26f4346) """, - } + } makeFiles(d) - self.cog.callableMain(['argv0', '-r', '-c', 'cog1.txt']) - self.assertFilesSame('cog1.txt', 'cog1.out') + self.cog.callableMain(["argv0", "-r", "-c", "cog1.txt"]) + self.assertFilesSame("cog1.txt", "cog1.out") def testRemoveChecksumOutput(self): d = { - 'cog1.txt': """\ + "cog1.txt": """\ //[[[cog cog.outl("This line was newly") cog.outl("generated by cog") @@ -2343,8 +2341,7 @@ def testRemoveChecksumOutput(self): This line was generated. //[[[end]]] (checksum: 8adb13fb59b996a1c7f0065ea9f3d893) fooey """, - - 'cog1.out': """\ + "cog1.out": """\ //[[[cog cog.outl("This line was newly") cog.outl("generated by cog") @@ -2355,15 +2352,15 @@ def testRemoveChecksumOutput(self): blah blah. //[[[end]]] fooey """, - } + } makeFiles(d) - self.cog.callableMain(['argv0', '-r', 'cog1.txt']) - self.assertFilesSame('cog1.txt', 'cog1.out') + self.cog.callableMain(["argv0", "-r", "cog1.txt"]) + self.assertFilesSame("cog1.txt", "cog1.out") def testTamperedChecksumOutput(self): d = { - 'cog1.txt': """\ + "cog1.txt": """\ //[[[cog cog.outl("This line was newly") cog.outl("generated by cog") @@ -2374,8 +2371,7 @@ def testTamperedChecksumOutput(self): blah blah. //[[[end]]] (checksum: a8540982e5ad6b95c9e9a184b26f4346) """, - - 'cog2.txt': """\ + "cog2.txt": """\ //[[[cog cog.outl("This line was newly") cog.outl("generated by cog") @@ -2386,8 +2382,7 @@ def testTamperedChecksumOutput(self): blah blah! //[[[end]]] (checksum: a8540982e5ad6b95c9e9a184b26f4346) """, - - 'cog3.txt': """\ + "cog3.txt": """\ //[[[cog cog.outl("This line was newly") cog.outl("generated by cog") @@ -2399,8 +2394,7 @@ def testTamperedChecksumOutput(self): blah blah. //[[[end]]] (checksum: a8540982e5ad6b95c9e9a184b26f4346) """, - - 'cog4.txt': """\ + "cog4.txt": """\ //[[[cog cog.outl("This line was newly") cog.outl("generated by cog") @@ -2411,8 +2405,7 @@ def testTamperedChecksumOutput(self): blah blah.. //[[[end]]] (checksum: a8540982e5ad6b95c9e9a184b26f4346) """, - - 'cog5.txt': """\ + "cog5.txt": """\ //[[[cog cog.outl("This line was newly") cog.outl("generated by cog") @@ -2424,8 +2417,7 @@ def testTamperedChecksumOutput(self): extra //[[[end]]] (checksum: a8540982e5ad6b95c9e9a184b26f4346) """, - - 'cog6.txt': """\ + "cog6.txt": """\ //[[[cog cog.outl("This line was newly") cog.outl("generated by cog") @@ -2433,124 +2425,123 @@ def testTamperedChecksumOutput(self): //]]] //[[[end]]] (checksum: a8540982e5ad6b95c9e9a184b26f4346) """, - } + } makeFiles(d) - with self.assertRaisesRegex(CogError, - r"^cog1.txt\(9\): Output has been edited! Delete old checksum to unprotect.$"): - self.cog.callableMain(['argv0', '-c', "cog1.txt"]) - with self.assertRaisesRegex(CogError, - r"^cog2.txt\(9\): Output has been edited! Delete old checksum to unprotect.$"): - self.cog.callableMain(['argv0', '-c', "cog2.txt"]) - with self.assertRaisesRegex(CogError, - r"^cog3.txt\(10\): Output has been edited! Delete old checksum to unprotect.$"): - self.cog.callableMain(['argv0', '-c', "cog3.txt"]) - with self.assertRaisesRegex(CogError, - r"^cog4.txt\(9\): Output has been edited! Delete old checksum to unprotect.$"): - self.cog.callableMain(['argv0', '-c', "cog4.txt"]) - with self.assertRaisesRegex(CogError, - r"^cog5.txt\(10\): Output has been edited! Delete old checksum to unprotect.$"): - self.cog.callableMain(['argv0', '-c', "cog5.txt"]) - with self.assertRaisesRegex(CogError, - r"^cog6.txt\(6\): Output has been edited! Delete old checksum to unprotect.$"): - self.cog.callableMain(['argv0', '-c', "cog6.txt"]) + with self.assertRaisesRegex( + CogError, + r"^cog1.txt\(9\): Output has been edited! Delete old checksum to unprotect.$", + ): + self.cog.callableMain(["argv0", "-c", "cog1.txt"]) + with self.assertRaisesRegex( + CogError, + r"^cog2.txt\(9\): Output has been edited! Delete old checksum to unprotect.$", + ): + self.cog.callableMain(["argv0", "-c", "cog2.txt"]) + with self.assertRaisesRegex( + CogError, + r"^cog3.txt\(10\): Output has been edited! Delete old checksum to unprotect.$", + ): + self.cog.callableMain(["argv0", "-c", "cog3.txt"]) + with self.assertRaisesRegex( + CogError, + r"^cog4.txt\(9\): Output has been edited! Delete old checksum to unprotect.$", + ): + self.cog.callableMain(["argv0", "-c", "cog4.txt"]) + with self.assertRaisesRegex( + CogError, + r"^cog5.txt\(10\): Output has been edited! Delete old checksum to unprotect.$", + ): + self.cog.callableMain(["argv0", "-c", "cog5.txt"]) + with self.assertRaisesRegex( + CogError, + r"^cog6.txt\(6\): Output has been edited! Delete old checksum to unprotect.$", + ): + self.cog.callableMain(["argv0", "-c", "cog6.txt"]) def testArgvIsntModified(self): - argv = ['argv0', '-v'] + argv = ["argv0", "-v"] orig_argv = argv[:] self.cog.callableMain(argv) self.assertEqual(argv, orig_argv) class CustomMarkerTests(TestCaseWithTempDir): - def testCustomerMarkers(self): d = { - 'test.cog': """\ + "test.cog": """\ //{{ cog.outl("void %s();" % "MyFunction") //}} //{{end}} """, - - 'test.out': """\ + "test.out": """\ //{{ cog.outl("void %s();" % "MyFunction") //}} void MyFunction(); //{{end}} """, - } + } makeFiles(d) - self.cog.callableMain([ - 'argv0', '-r', - '--markers={{ }} {{end}}', - 'test.cog' - ]) - self.assertFilesSame('test.cog', 'test.out') + self.cog.callableMain(["argv0", "-r", "--markers={{ }} {{end}}", "test.cog"]) + self.assertFilesSame("test.cog", "test.out") def testTrulyWackyMarkers(self): # Make sure the markers are properly re-escaped. d = { - 'test.cog': """\ + "test.cog": """\ //**( cog.outl("void %s();" % "MyFunction") //**) //**(end)** """, - - 'test.out': """\ + "test.out": """\ //**( cog.outl("void %s();" % "MyFunction") //**) void MyFunction(); //**(end)** """, - } + } makeFiles(d) - self.cog.callableMain([ - 'argv0', '-r', - '--markers=**( **) **(end)**', - 'test.cog' - ]) - self.assertFilesSame('test.cog', 'test.out') + self.cog.callableMain( + ["argv0", "-r", "--markers=**( **) **(end)**", "test.cog"] + ) + self.assertFilesSame("test.cog", "test.out") def testChangeJustOneMarker(self): d = { - 'test.cog': """\ + "test.cog": """\ //**( cog.outl("void %s();" % "MyFunction") //]]] //[[[end]]] """, - - 'test.out': """\ + "test.out": """\ //**( cog.outl("void %s();" % "MyFunction") //]]] void MyFunction(); //[[[end]]] """, - } + } makeFiles(d) - self.cog.callableMain([ - 'argv0', '-r', - '--markers=**( ]]] [[[end]]]', - 'test.cog' - ]) - self.assertFilesSame('test.cog', 'test.out') + self.cog.callableMain( + ["argv0", "-r", "--markers=**( ]]] [[[end]]]", "test.cog"] + ) + self.assertFilesSame("test.cog", "test.out") class BlakeTests(TestCaseWithTempDir): - # Blake Winton's contributions. def testDeleteCode(self): # -o sets the output file. d = { - 'test.cog': """\ + "test.cog": """\ // This is my C++ file. //[[[cog fnames = ['DoSomething', 'DoAnotherThing', 'DoLastThing'] @@ -2561,36 +2552,38 @@ def testDeleteCode(self): //[[[end]]]Data Data And Some More """, - - 'test.out': """\ + "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') + self.cog.callableMain(["argv0", "-d", "-o", "test.cogged", "test.cog"]) + self.assertFilesSame("test.cogged", "test.out") def testDeleteCodeWithDashRFails(self): d = { - 'test.cog': """\ + "test.cog": """\ // This is my C++ file. """ - } + } makeFiles(d) - with self.assertRaisesRegex(CogUsageError, r"^Can't use -d with -r \(or you would delete all your source!\)$"): - self.cog.callableMain(['argv0', '-r', '-d', 'test.cog']) + with self.assertRaisesRegex( + CogUsageError, + r"^Can't use -d with -r \(or you would delete all your source!\)$", + ): + 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': """\ + "test.cog": """\ // This is my C++ file. //[[[cog for fn in fnames: @@ -2598,57 +2591,57 @@ def testSettingGlobals(self): //]]] Some Sample Code Here //[[[end]]]""", - - 'test.out': """\ + "test.out": """\ // This is my C++ file. void DoBlake(); void DoWinton(); void DoContribution(); """, - } + } makeFiles(d) globals = {} - globals['fnames'] = ['DoBlake', 'DoWinton', 'DoContribution'] + 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') + 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': """\ + "error.cog": """\ //[[[cog cog.error("Something Bad!") //]]] //[[[end]]] """, - } + } makeFiles(d) - self.cog.main(['argv0', '-r', 'error.cog']) + 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': """\ + "error.cog": """\ //[[[cog raise RuntimeError("Hey!") //]]] //[[[end]]] """, - } + } makeFiles(d) - self.cog.main(['argv0', '-r', 'error.cog']) + self.cog.main(["argv0", "-r", "error.cog"]) output = self.output.getvalue() - msg = 'Actual output:\n' + output - self.assertTrue(output.startswith("Cogging error.cog\nTraceback (most recent"), msg) + msg = "Actual output:\n" + output + self.assertTrue( + output.startswith("Cogging error.cog\nTraceback (most recent"), msg + ) self.assertIn("RuntimeError: Hey!", output) diff --git a/cogapp/test_makefiles.py b/cogapp/test_makefiles.py index 806ff86..ab2796a 100644 --- a/cogapp/test_makefiles.py +++ b/cogapp/test_makefiles.py @@ -1,5 +1,4 @@ -""" Test the cogapp.makefiles modules -""" +"""Test the cogapp.makefiles modules""" import shutil import os @@ -11,10 +10,9 @@ class SimpleTests(TestCase): - def setUp(self): # Create a temporary directory. - my_dir = 'testmakefiles_tempdir_' + str(random.random())[2:] + my_dir = "testmakefiles_tempdir_" + str(random.random())[2:] self.tempdir = os.path.join(tempfile.gettempdir(), my_dir) os.mkdir(self.tempdir) @@ -27,38 +25,38 @@ def exists(self, dname, fname): def checkFilesExist(self, d, dname): for fname in d.keys(): - assert(self.exists(dname, fname)) + assert self.exists(dname, fname) if type(d[fname]) == type({}): self.checkFilesExist(d[fname], os.path.join(dname, fname)) def checkFilesDontExist(self, d, dname): for fname in d.keys(): - assert(not self.exists(dname, fname)) + assert not self.exists(dname, fname) def testOneFile(self): - fname = 'foo.txt' - notfname = 'not_here.txt' - d = { fname: "howdy" } - assert(not self.exists(self.tempdir, fname)) - assert(not self.exists(self.tempdir, notfname)) + fname = "foo.txt" + notfname = "not_here.txt" + d = {fname: "howdy"} + assert not self.exists(self.tempdir, fname) + assert not self.exists(self.tempdir, notfname) makefiles.makeFiles(d, self.tempdir) - assert(self.exists(self.tempdir, fname)) - assert(not self.exists(self.tempdir, notfname)) + assert self.exists(self.tempdir, fname) + assert not self.exists(self.tempdir, notfname) makefiles.removeFiles(d, self.tempdir) - assert(not self.exists(self.tempdir, fname)) - assert(not self.exists(self.tempdir, notfname)) + assert not self.exists(self.tempdir, fname) + assert not self.exists(self.tempdir, notfname) def testManyFiles(self): d = { - 'top1.txt': "howdy", - 'top2.txt': "hello", - 'sub': { - 'sub1.txt': "inside", - 'sub2.txt': "inside2", - }, - } + "top1.txt": "howdy", + "top2.txt": "hello", + "sub": { + "sub1.txt": "inside", + "sub2.txt": "inside2", + }, + } self.checkFilesDontExist(d, self.tempdir) makefiles.makeFiles(d, self.tempdir) @@ -68,18 +66,18 @@ def testManyFiles(self): def testOverlapping(self): d1 = { - 'top1.txt': "howdy", - 'sub': { - 'sub1.txt': "inside", - }, - } + "top1.txt": "howdy", + "sub": { + "sub1.txt": "inside", + }, + } d2 = { - 'top2.txt': "hello", - 'sub': { - 'sub2.txt': "inside2", - }, - } + "top2.txt": "hello", + "sub": { + "sub2.txt": "inside2", + }, + } self.checkFilesDontExist(d1, self.tempdir) self.checkFilesDontExist(d2, self.tempdir) @@ -93,15 +91,15 @@ def testOverlapping(self): self.checkFilesDontExist(d2, self.tempdir) def testContents(self): - fname = 'bar.txt' + fname = "bar.txt" cont0 = "I am bar.txt" - d = { fname: cont0 } + d = {fname: cont0} makefiles.makeFiles(d, self.tempdir) with open(os.path.join(self.tempdir, fname)) as fcont1: - assert(fcont1.read() == cont0) + assert fcont1.read() == cont0 def testDedent(self): - fname = 'dedent.txt' + fname = "dedent.txt" d = { fname: """\ This is dedent.txt @@ -109,7 +107,9 @@ def testDedent(self): spaced in. OK. """, - } + } makefiles.makeFiles(d, self.tempdir) with open(os.path.join(self.tempdir, fname)) as fcont: - assert(fcont.read() == "This is dedent.txt\n\tTabbed in.\n spaced in.\nOK.\n") + assert ( + fcont.read() == "This is dedent.txt\n\tTabbed in.\n spaced in.\nOK.\n" + ) diff --git a/cogapp/test_whiteutils.py b/cogapp/test_whiteutils.py index bbfaaf5..9551e4e 100644 --- a/cogapp/test_whiteutils.py +++ b/cogapp/test_whiteutils.py @@ -1,5 +1,4 @@ -""" Test the cogapp.whiteutils module. -""" +"""Test the cogapp.whiteutils module.""" from unittest import TestCase @@ -7,91 +6,91 @@ class WhitePrefixTests(TestCase): - """ Test cases for cogapp.whiteutils. - """ + """Test cases for cogapp.whiteutils.""" + def testSingleLine(self): - self.assertEqual(whitePrefix(['']), '') - self.assertEqual(whitePrefix([' ']), '') - self.assertEqual(whitePrefix(['x']), '') - self.assertEqual(whitePrefix([' x']), ' ') - self.assertEqual(whitePrefix(['\tx']), '\t') - self.assertEqual(whitePrefix([' x']), ' ') - self.assertEqual(whitePrefix([' \t \tx ']), ' \t \t') + self.assertEqual(whitePrefix([""]), "") + self.assertEqual(whitePrefix([" "]), "") + self.assertEqual(whitePrefix(["x"]), "") + self.assertEqual(whitePrefix([" x"]), " ") + self.assertEqual(whitePrefix(["\tx"]), "\t") + self.assertEqual(whitePrefix([" x"]), " ") + self.assertEqual(whitePrefix([" \t \tx "]), " \t \t") def testMultiLine(self): - self.assertEqual(whitePrefix([' x',' x',' x']), ' ') - self.assertEqual(whitePrefix([' y',' y',' y']), ' ') - self.assertEqual(whitePrefix([' y',' y',' y']), ' ') + self.assertEqual(whitePrefix([" x", " x", " x"]), " ") + self.assertEqual(whitePrefix([" y", " y", " y"]), " ") + self.assertEqual(whitePrefix([" y", " y", " y"]), " ") def testBlankLinesAreIgnored(self): - self.assertEqual(whitePrefix([' x',' x','',' x']), ' ') - self.assertEqual(whitePrefix(['',' x',' x',' x']), ' ') - self.assertEqual(whitePrefix([' x',' x',' x','']), ' ') - self.assertEqual(whitePrefix([' x',' x',' ',' x']), ' ') + self.assertEqual(whitePrefix([" x", " x", "", " x"]), " ") + self.assertEqual(whitePrefix(["", " x", " x", " x"]), " ") + self.assertEqual(whitePrefix([" x", " x", " x", ""]), " ") + self.assertEqual(whitePrefix([" x", " x", " ", " x"]), " ") def testTabCharacters(self): - self.assertEqual(whitePrefix(['\timport sys', '', '\tprint sys.argv']), '\t') + self.assertEqual(whitePrefix(["\timport sys", "", "\tprint sys.argv"]), "\t") def testDecreasingLengths(self): - self.assertEqual(whitePrefix([' x',' x',' x']), ' ') - self.assertEqual(whitePrefix([' x',' x',' x']), ' ') + self.assertEqual(whitePrefix([" x", " x", " x"]), " ") + self.assertEqual(whitePrefix([" x", " x", " x"]), " ") class ReindentBlockTests(TestCase): - """ Test cases for cogapp.reindentBlock. - """ + """Test cases for cogapp.reindentBlock.""" + def testNonTermLine(self): - self.assertEqual(reindentBlock(''), '') - self.assertEqual(reindentBlock('x'), 'x') - self.assertEqual(reindentBlock(' x'), 'x') - self.assertEqual(reindentBlock(' x'), 'x') - self.assertEqual(reindentBlock('\tx'), 'x') - self.assertEqual(reindentBlock('x', ' '), ' x') - self.assertEqual(reindentBlock('x', '\t'), '\tx') - self.assertEqual(reindentBlock(' x', ' '), ' x') - self.assertEqual(reindentBlock(' x', '\t'), '\tx') - self.assertEqual(reindentBlock(' x', ' '), ' x') + self.assertEqual(reindentBlock(""), "") + self.assertEqual(reindentBlock("x"), "x") + self.assertEqual(reindentBlock(" x"), "x") + self.assertEqual(reindentBlock(" x"), "x") + self.assertEqual(reindentBlock("\tx"), "x") + self.assertEqual(reindentBlock("x", " "), " x") + self.assertEqual(reindentBlock("x", "\t"), "\tx") + self.assertEqual(reindentBlock(" x", " "), " x") + self.assertEqual(reindentBlock(" x", "\t"), "\tx") + self.assertEqual(reindentBlock(" x", " "), " x") def testSingleLine(self): - self.assertEqual(reindentBlock('\n'), '\n') - self.assertEqual(reindentBlock('x\n'), 'x\n') - self.assertEqual(reindentBlock(' x\n'), 'x\n') - self.assertEqual(reindentBlock(' x\n'), 'x\n') - self.assertEqual(reindentBlock('\tx\n'), 'x\n') - self.assertEqual(reindentBlock('x\n', ' '), ' x\n') - self.assertEqual(reindentBlock('x\n', '\t'), '\tx\n') - self.assertEqual(reindentBlock(' x\n', ' '), ' x\n') - self.assertEqual(reindentBlock(' x\n', '\t'), '\tx\n') - self.assertEqual(reindentBlock(' x\n', ' '), ' x\n') + self.assertEqual(reindentBlock("\n"), "\n") + self.assertEqual(reindentBlock("x\n"), "x\n") + self.assertEqual(reindentBlock(" x\n"), "x\n") + self.assertEqual(reindentBlock(" x\n"), "x\n") + self.assertEqual(reindentBlock("\tx\n"), "x\n") + self.assertEqual(reindentBlock("x\n", " "), " x\n") + self.assertEqual(reindentBlock("x\n", "\t"), "\tx\n") + self.assertEqual(reindentBlock(" x\n", " "), " x\n") + self.assertEqual(reindentBlock(" x\n", "\t"), "\tx\n") + self.assertEqual(reindentBlock(" x\n", " "), " x\n") def testRealBlock(self): self.assertEqual( - reindentBlock('\timport sys\n\n\tprint sys.argv\n'), - 'import sys\n\nprint sys.argv\n' - ) + reindentBlock("\timport sys\n\n\tprint sys.argv\n"), + "import sys\n\nprint sys.argv\n", + ) class CommonPrefixTests(TestCase): - """ Test cases for cogapp.commonPrefix. - """ + """Test cases for cogapp.commonPrefix.""" + def testDegenerateCases(self): - self.assertEqual(commonPrefix([]), '') - self.assertEqual(commonPrefix(['']), '') - self.assertEqual(commonPrefix(['','','','','']), '') - self.assertEqual(commonPrefix(['cat in the hat']), 'cat in the hat') + self.assertEqual(commonPrefix([]), "") + self.assertEqual(commonPrefix([""]), "") + self.assertEqual(commonPrefix(["", "", "", "", ""]), "") + self.assertEqual(commonPrefix(["cat in the hat"]), "cat in the hat") def testNoCommonPrefix(self): - self.assertEqual(commonPrefix(['a','b']), '') - self.assertEqual(commonPrefix(['a','b','c','d','e','f']), '') - self.assertEqual(commonPrefix(['a','a','a','a','a','x']), '') + self.assertEqual(commonPrefix(["a", "b"]), "") + self.assertEqual(commonPrefix(["a", "b", "c", "d", "e", "f"]), "") + self.assertEqual(commonPrefix(["a", "a", "a", "a", "a", "x"]), "") def testUsualCases(self): - self.assertEqual(commonPrefix(['ab', 'ac']), 'a') - self.assertEqual(commonPrefix(['aab', 'aac']), 'aa') - self.assertEqual(commonPrefix(['aab', 'aab', 'aab', 'aac']), 'aa') + self.assertEqual(commonPrefix(["ab", "ac"]), "a") + self.assertEqual(commonPrefix(["aab", "aac"]), "aa") + self.assertEqual(commonPrefix(["aab", "aab", "aab", "aac"]), "aa") def testBlankLine(self): - self.assertEqual(commonPrefix(['abc', 'abx', '', 'aby']), '') + self.assertEqual(commonPrefix(["abc", "abx", "", "aby"]), "") def testDecreasingLengths(self): - self.assertEqual(commonPrefix(['abcd', 'abc', 'ab']), 'ab') + self.assertEqual(commonPrefix(["abcd", "abc", "ab"]), "ab") diff --git a/cogapp/utils.py b/cogapp/utils.py index 7f08997..8c008b9 100644 --- a/cogapp/utils.py +++ b/cogapp/utils.py @@ -1,5 +1,4 @@ -""" Utilities for cog. -""" +"""Utilities for cog.""" import contextlib import functools @@ -17,15 +16,14 @@ class Redirectable: - """ An object with its own stdout and stderr files. - """ + """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. - """ + """Assign new files for standard out and/or standard error.""" if stdout: self.stdout = stdout if stderr: @@ -39,8 +37,8 @@ def prerr(self, s, end="\n"): class NumberedFileReader: - """ A decorator for files that counts the readline()'s called. - """ + """A decorator for files that counts the readline()'s called.""" + def __init__(self, f): self.f = f self.n = 0 diff --git a/cogapp/whiteutils.py b/cogapp/whiteutils.py index abde0d2..d7d10de 100644 --- a/cogapp/whiteutils.py +++ b/cogapp/whiteutils.py @@ -1,21 +1,21 @@ -""" Indentation utilities for Cog. -""" +"""Indentation utilities for Cog.""" import re def whitePrefix(strings): - """ Determine the whitespace prefix common to all non-blank lines - in the argument list. + """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() != ''] + strings = [s for s in strings if s.strip() != ""] - if not strings: return '' + if not strings: + return "" # Find initial whitespace chunk in the first line. # This is the best prefix we can hope for. - pat = r'\s*' + pat = r"\s*" if isinstance(strings[0], bytes): pat = pat.encode("utf-8") prefix = re.match(pat, strings[0]).group(0) @@ -29,14 +29,15 @@ def whitePrefix(strings): 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. + +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. """ - sep, nothing = '\n', '' + sep, nothing = "\n", "" if isinstance(lines, bytes): - sep, nothing = b'\n', b'' + sep, nothing = b"\n", b"" if isinstance(lines, (bytes, str)): lines = lines.split(sep) oldIndent = whitePrefix(lines) @@ -49,17 +50,17 @@ def reindentBlock(lines, newIndent=''): outLines.append(l) return sep.join(outLines) + def commonPrefix(strings): - """ Find the longest string that is a prefix of all the strings. - """ + """Find the longest string that is a prefix of all the strings.""" if not strings: - return '' + return "" prefix = strings[0] for s in strings: if len(s) < len(prefix): - prefix = prefix[:len(s)] + prefix = prefix[: len(s)] if not prefix: - return '' + return "" for i in range(len(prefix)): if prefix[i] != s[i]: prefix = prefix[:i] diff --git a/docs/conf.py b/docs/conf.py index 2f923e7..b6f783c 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -6,23 +6,23 @@ # -- Project information ----------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information -project = 'cog' -copyright = '2004–2024, Ned Batchelder' -author = 'Ned Batchelder' -release = '3.4.1' +project = "cog" +copyright = "2004–2024, Ned Batchelder" +author = "Ned Batchelder" +release = "3.4.1" # -- General configuration --------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration extensions = [] -templates_path = ['_templates'] -exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] +templates_path = ["_templates"] +exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] -language = 'en' +language = "en" # -- Options for HTML output ------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output -html_theme = 'alabaster' -html_static_path = ['_static'] +html_theme = "alabaster" +html_static_path = ["_static"] From 66bee8e5ed7442281d3506018526fe8070c62074 Mon Sep 17 00:00:00 2001 From: Tim Vergenz Date: Thu, 25 Apr 2024 15:06:56 -0400 Subject: [PATCH 2/3] refactor: add code formatting to ci --- .github/workflows/ci.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index aaaec1e..e8a16a1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,6 +16,15 @@ concurrency: cancel-in-progress: true jobs: + + format: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: chartboost/ruff-action@v1 + with: + args: 'format --check' + tests: name: "Python ${{ matrix.python }} on ${{ matrix.os }}" runs-on: "${{ matrix.os }}-${{ matrix.os-version || 'latest' }}" From 8c27640abd400d3bbdbc5077caf8c52b14f385b4 Mon Sep 17 00:00:00 2001 From: Tim Vergenz Date: Thu, 25 Apr 2024 15:17:57 -0400 Subject: [PATCH 3/3] refactor: add .git-blame-ignore-revs Per https://github.com/nedbat/cog/issues/32#issuecomment-2077793648 --- .git-blame-ignore-revs | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .git-blame-ignore-revs diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs new file mode 100644 index 0000000..a4ce99d --- /dev/null +++ b/.git-blame-ignore-revs @@ -0,0 +1,2 @@ +# introduced `ruff format` +e36601b92ad2354ade13​4288d9e097a098513a64