diff options
Diffstat (limited to 'pyflakes/test/test_api.py')
-rw-r--r-- | pyflakes/test/test_api.py | 215 |
1 files changed, 72 insertions, 143 deletions
diff --git a/pyflakes/test/test_api.py b/pyflakes/test/test_api.py index 3d93591..d0795a0 100644 --- a/pyflakes/test/test_api.py +++ b/pyflakes/test/test_api.py @@ -3,6 +3,7 @@ Tests for L{pyflakes.scripts.pyflakes}. """ import contextlib +import io import os import sys import shutil @@ -20,14 +21,6 @@ from pyflakes.api import ( ) from pyflakes.test.harness import TestCase, skipIf -if sys.version_info < (3,): - from cStringIO import StringIO -else: - from io import StringIO - unichr = chr - -ERROR_HAS_COL_NUM = ERROR_HAS_LAST_LINE = sys.version_info >= (3, 2) or PYPY - def withStderrTo(stderr, f, *args, **kwargs): """ @@ -40,7 +33,7 @@ def withStderrTo(stderr, f, *args, **kwargs): sys.stderr = outer -class Node(object): +class Node: """ Mock an AST node. """ @@ -49,32 +42,14 @@ class Node(object): self.col_offset = col_offset -class SysStreamCapturing(object): - - """ - Context manager capturing sys.stdin, sys.stdout and sys.stderr. +class SysStreamCapturing: + """Context manager capturing sys.stdin, sys.stdout and sys.stderr. The file handles are replaced with a StringIO object. - On environments that support it, the StringIO object uses newlines - set to os.linesep. Otherwise newlines are converted from \\n to - os.linesep during __exit__. """ - def _create_StringIO(self, buffer=None): - # Python 3 has a newline argument - try: - return StringIO(buffer, newline=os.linesep) - except TypeError: - self._newline = True - # Python 2 creates an input only stream when buffer is not None - if buffer is None: - return StringIO() - else: - return StringIO(buffer) - def __init__(self, stdin): - self._newline = False - self._stdin = self._create_StringIO(stdin or '') + self._stdin = io.StringIO(stdin or '', newline=os.linesep) def __enter__(self): self._orig_stdin = sys.stdin @@ -82,8 +57,8 @@ class SysStreamCapturing(object): self._orig_stderr = sys.stderr sys.stdin = self._stdin - sys.stdout = self._stdout_stringio = self._create_StringIO() - sys.stderr = self._stderr_stringio = self._create_StringIO() + sys.stdout = self._stdout_stringio = io.StringIO(newline=os.linesep) + sys.stderr = self._stderr_stringio = io.StringIO(newline=os.linesep) return self @@ -91,16 +66,12 @@ class SysStreamCapturing(object): self.output = self._stdout_stringio.getvalue() self.error = self._stderr_stringio.getvalue() - if self._newline and os.linesep != '\n': - self.output = self.output.replace('\n', os.linesep) - self.error = self.error.replace('\n', os.linesep) - sys.stdin = self._orig_stdin sys.stdout = self._orig_stdout sys.stderr = self._orig_stderr -class LoggingReporter(object): +class LoggingReporter: """ Implementation of Reporter that just appends any error to a list. """ @@ -190,10 +161,6 @@ class TestIterSourceCode(TestCase): with open(os.path.join(self.tempdir, 'c'), 'w') as fd: fd.write('hello\nworld\n') - python2 = os.path.join(self.tempdir, 'd') - with open(python2, 'w') as fd: - fd.write('#!/usr/bin/env python2\n') - python3 = os.path.join(self.tempdir, 'e') with open(python3, 'w') as fd: fd.write('#!/usr/bin/env python3\n') @@ -206,10 +173,6 @@ class TestIterSourceCode(TestCase): with open(python3args, 'w') as fd: fd.write('#!/usr/bin/python3 -u\n') - python2u = os.path.join(self.tempdir, 'h') - with open(python2u, 'w') as fd: - fd.write('#!/usr/bin/python2u\n') - python3d = os.path.join(self.tempdir, 'i') with open(python3d, 'w') as fd: fd.write('#!/usr/local/bin/python3d\n') @@ -218,10 +181,6 @@ class TestIterSourceCode(TestCase): with open(python38m, 'w') as fd: fd.write('#! /usr/bin/env python3.8m\n') - python27 = os.path.join(self.tempdir, 'k') - with open(python27, 'w') as fd: - fd.write('#!/usr/bin/python2.7 \n') - # Should NOT be treated as Python source notfirst = os.path.join(self.tempdir, 'l') with open(notfirst, 'w') as fd: @@ -229,8 +188,10 @@ class TestIterSourceCode(TestCase): self.assertEqual( sorted(iterSourceCode([self.tempdir])), - sorted([python, python2, python3, pythonw, python3args, python2u, - python3d, python38m, python27])) + sorted([ + python, python3, pythonw, python3args, python3d, + python38m, + ])) def test_multipleDirectories(self): """ @@ -269,7 +230,7 @@ class TestReporter(TestCase): number, error message, actual line of source and a caret pointing to where the error is. """ - err = StringIO() + err = io.StringIO() reporter = Reporter(None, err) reporter.syntaxError('foo.py', 'a problem', 3, 8 if sys.version_info >= (3, 8) else 7, @@ -285,7 +246,7 @@ class TestReporter(TestCase): C{syntaxError} doesn't include a caret pointing to the error if C{offset} is passed as C{None}. """ - err = StringIO() + err = io.StringIO() reporter = Reporter(None, err) reporter.syntaxError('foo.py', 'a problem', 3, None, 'bad line of source') @@ -300,7 +261,7 @@ class TestReporter(TestCase): line. The offset is adjusted so that it is relative to the start of the last line. """ - err = StringIO() + err = io.StringIO() lines = [ 'bad line of source', 'more bad lines of source', @@ -319,7 +280,7 @@ class TestReporter(TestCase): """ C{unexpectedError} reports an error processing a source file. """ - err = StringIO() + err = io.StringIO() reporter = Reporter(None, err) reporter.unexpectedError('source.py', 'error message') self.assertEqual('source.py: error message\n', err.getvalue()) @@ -329,11 +290,11 @@ class TestReporter(TestCase): C{flake} reports a code warning from Pyflakes. It is exactly the str() of a L{pyflakes.messages.Message}. """ - out = StringIO() + out = io.StringIO() reporter = Reporter(out, None) message = UnusedImport('foo.py', Node(42), 'bar') reporter.flake(message) - self.assertEqual(out.getvalue(), "%s\n" % (message,)) + self.assertEqual(out.getvalue(), f"{message}\n") class CheckTests(TestCase): @@ -363,7 +324,7 @@ class CheckTests(TestCase): @param path: A path to a file to check. @param errorList: A list of errors expected to be printed to stderr. """ - err = StringIO() + err = io.StringIO() count = withStderrTo(err, checkPath, path) self.assertEqual( (count, err.getvalue()), (len(errorList), ''.join(errorList))) @@ -496,10 +457,10 @@ def baz(): self.assertHasErrors( sourcePath, ["""\ -%s:2:%s: invalid syntax +{}:2:{}: invalid syntax \tfoo = -%s -""" % (sourcePath, column, last_line)]) +{} +""".format(sourcePath, column, last_line)]) def test_nonDefaultFollowsDefaultSyntaxError(self): """ @@ -512,27 +473,24 @@ def foo(bar=baz, bax): pass """ with self.makeTempFile(source) as sourcePath: - if ERROR_HAS_LAST_LINE: - if PYPY: - column = 7 - elif sys.version_info >= (3, 10): - column = 18 - elif sys.version_info >= (3, 9): - column = 21 - elif sys.version_info >= (3, 8): - column = 9 - else: - column = 8 - last_line = ' ' * (column - 1) + '^\n' - columnstr = '%d:' % column + if PYPY: + column = 7 + elif sys.version_info >= (3, 10): + column = 18 + elif sys.version_info >= (3, 9): + column = 21 + elif sys.version_info >= (3, 8): + column = 9 else: - last_line = columnstr = '' + column = 8 + last_line = ' ' * (column - 1) + '^\n' + columnstr = '%d:' % column self.assertHasErrors( sourcePath, ["""\ -%s:1:%s non-default argument follows default argument +{}:1:{} non-default argument follows default argument def foo(bar=baz, bax): -%s""" % (sourcePath, columnstr, last_line)]) +{}""".format(sourcePath, columnstr, last_line)]) def test_nonKeywordAfterKeywordSyntaxError(self): """ @@ -544,59 +502,43 @@ def foo(bar=baz, bax): foo(bar=baz, bax) """ with self.makeTempFile(source) as sourcePath: - if ERROR_HAS_LAST_LINE: - if PYPY: - column = 12 - elif sys.version_info >= (3, 9): - column = 17 - elif sys.version_info >= (3, 8): - column = 14 - else: - column = 13 - last_line = ' ' * (column - 1) + '^\n' - columnstr = '%d:' % column + if PYPY: + column = 12 + elif sys.version_info >= (3, 9): + column = 17 + elif sys.version_info >= (3, 8): + column = 14 else: - last_line = columnstr = '' + column = 13 + last_line = ' ' * (column - 1) + '^\n' + columnstr = '%d:' % column - if sys.version_info >= (3, 5): - message = 'positional argument follows keyword argument' - else: - message = 'non-keyword arg after keyword arg' + message = 'positional argument follows keyword argument' self.assertHasErrors( sourcePath, ["""\ -%s:1:%s %s +{}:1:{} {} foo(bar=baz, bax) -%s""" % (sourcePath, columnstr, message, last_line)]) +{}""".format(sourcePath, columnstr, message, last_line)]) def test_invalidEscape(self): """ The invalid escape syntax raises ValueError in Python 2 """ - ver = sys.version_info # ValueError: invalid \x escape with self.makeTempFile(r"foo = '\xyz'") as sourcePath: - if ver < (3,): - decoding_error = "%s: problem decoding source\n" % (sourcePath,) + position_end = 1 + if PYPY: + column = 5 + elif sys.version_info >= (3, 9): + column = 13 else: - position_end = 1 - if PYPY: - column = 5 - elif ver >= (3, 9): - column = 13 - else: - column = 7 - # Column has been "fixed" since 3.2.4 and 3.3.1 - if ver < (3, 2, 4) or ver[:3] == (3, 3, 0): - position_end = 2 - - if ERROR_HAS_LAST_LINE: - last_line = '%s^\n' % (' ' * (column - 1)) - else: - last_line = '' - - decoding_error = """\ + column = 7 + + last_line = '%s^\n' % (' ' * (column - 1)) + + decoding_error = """\ %s:1:%d: (unicode error) 'unicodeescape' codec can't decode bytes \ in position 0-%d: truncated \\xXX escape foo = '\\xyz' @@ -637,7 +579,7 @@ foo = '\\xyz' """ If source file declares the correct encoding, no error is reported. """ - SNOWMAN = unichr(0x2603) + SNOWMAN = chr(0x2603) source = ("""\ # coding: utf-8 x = "%s" @@ -657,40 +599,28 @@ x = "%s" If a source file contains bytes which cannot be decoded, this is reported on stderr. """ - SNOWMAN = unichr(0x2603) + SNOWMAN = chr(0x2603) source = ("""\ # coding: ascii x = "%s" """ % SNOWMAN).encode('utf-8') with self.makeTempFile(source) as sourcePath: - if PYPY and sys.version_info < (3, ): - message = ('\'ascii\' codec can\'t decode byte 0xe2 ' - 'in position 21: ordinal not in range(128)') - result = """\ -%s:0:0: %s -x = "\xe2\x98\x83" - ^\n""" % (sourcePath, message) - - else: - message = 'problem decoding source' - result = "%s: problem decoding source\n" % (sourcePath,) - self.assertHasErrors( - sourcePath, [result]) + sourcePath, [f"{sourcePath}: problem decoding source\n"]) def test_misencodedFileUTF16(self): """ If a source file contains bytes which cannot be decoded, this is reported on stderr. """ - SNOWMAN = unichr(0x2603) + SNOWMAN = chr(0x2603) source = ("""\ # coding: ascii x = "%s" """ % SNOWMAN).encode('utf-16') with self.makeTempFile(source) as sourcePath: self.assertHasErrors( - sourcePath, ["%s: problem decoding source\n" % (sourcePath,)]) + sourcePath, [f"{sourcePath}: problem decoding source\n"]) def test_checkRecursive(self): """ @@ -702,10 +632,10 @@ x = "%s" os.mkdir(os.path.join(tempdir, 'foo')) file1 = os.path.join(tempdir, 'foo', 'bar.py') with open(file1, 'wb') as fd: - fd.write("import baz\n".encode('ascii')) + fd.write(b"import baz\n") file2 = os.path.join(tempdir, 'baz.py') with open(file2, 'wb') as fd: - fd.write("import contraband".encode('ascii')) + fd.write(b"import contraband") log = [] reporter = LoggingReporter(log) warnings = checkRecursive([tempdir], reporter) @@ -760,9 +690,8 @@ class IntegrationTests(TestCase): stdout=subprocess.PIPE, stderr=subprocess.PIPE) (stdout, stderr) = p.communicate() rv = p.wait() - if sys.version_info >= (3,): - stdout = stdout.decode('utf-8') - stderr = stderr.decode('utf-8') + stdout = stdout.decode('utf-8') + stderr = stderr.decode('utf-8') return (stdout, stderr, rv) def test_goodFile(self): @@ -780,10 +709,10 @@ class IntegrationTests(TestCase): and the warnings are printed to stdout. """ with open(self.tempfilepath, 'wb') as fd: - fd.write("import contraband\n".encode('ascii')) + fd.write(b"import contraband\n") d = self.runPyflakes([self.tempfilepath]) expected = UnusedImport(self.tempfilepath, Node(1), 'contraband') - self.assertEqual(d, ("%s%s" % (expected, os.linesep), '', 1)) + self.assertEqual(d, (f"{expected}{os.linesep}", '', 1)) def test_errors_io(self): """ @@ -792,8 +721,8 @@ class IntegrationTests(TestCase): printed to stderr. """ d = self.runPyflakes([self.tempfilepath]) - error_msg = '%s: No such file or directory%s' % (self.tempfilepath, - os.linesep) + error_msg = '{}: No such file or directory{}'.format(self.tempfilepath, + os.linesep) self.assertEqual(d, ('', error_msg, 1)) def test_errors_syntax(self): @@ -803,7 +732,7 @@ class IntegrationTests(TestCase): printed to stderr. """ with open(self.tempfilepath, 'wb') as fd: - fd.write("import".encode('ascii')) + fd.write(b"import") d = self.runPyflakes([self.tempfilepath]) error_msg = '{0}:1:{2}: invalid syntax{1}import{1} {3}^{1}'.format( self.tempfilepath, os.linesep, 6 if PYPY else 7, '' if PYPY else ' ') @@ -815,7 +744,7 @@ class IntegrationTests(TestCase): """ d = self.runPyflakes([], stdin='import contraband') expected = UnusedImport('<stdin>', Node(1), 'contraband') - self.assertEqual(d, ("%s%s" % (expected, os.linesep), '', 1)) + self.assertEqual(d, (f"{expected}{os.linesep}", '', 1)) class TestMain(IntegrationTests): |