257 lines
6.5 KiB
Python
257 lines
6.5 KiB
Python
import textwrap
|
|
|
|
from pyflakes import messages as m
|
|
from pyflakes.test.test_other import Test as TestOther
|
|
from pyflakes.test.test_imports import Test as TestImports
|
|
from pyflakes.test.test_undefined_names import Test as TestUndefinedNames
|
|
from pyflakes.test.harness import TestCase, skip
|
|
|
|
|
|
class _DoctestMixin(object):
|
|
|
|
withDoctest = True
|
|
|
|
def doctestify(self, input):
|
|
lines = []
|
|
for line in textwrap.dedent(input).splitlines():
|
|
if line.strip() == '':
|
|
pass
|
|
elif (line.startswith(' ') or
|
|
line.startswith('except:') or
|
|
line.startswith('except ') or
|
|
line.startswith('finally:') or
|
|
line.startswith('else:') or
|
|
line.startswith('elif ')):
|
|
line = "... %s" % line
|
|
else:
|
|
line = ">>> %s" % line
|
|
lines.append(line)
|
|
doctestificator = textwrap.dedent('''\
|
|
def doctest_something():
|
|
"""
|
|
%s
|
|
"""
|
|
''')
|
|
return doctestificator % "\n ".join(lines)
|
|
|
|
def flakes(self, input, *args, **kw):
|
|
return super(_DoctestMixin, self).flakes(self.doctestify(input), *args, **kw)
|
|
|
|
|
|
class Test(TestCase):
|
|
|
|
withDoctest = True
|
|
|
|
def test_importBeforeDoctest(self):
|
|
self.flakes("""
|
|
import foo
|
|
|
|
def doctest_stuff():
|
|
'''
|
|
>>> foo
|
|
'''
|
|
""")
|
|
|
|
@skip("todo")
|
|
def test_importBeforeAndInDoctest(self):
|
|
self.flakes('''
|
|
import foo
|
|
|
|
def doctest_stuff():
|
|
"""
|
|
>>> import foo
|
|
>>> foo
|
|
"""
|
|
|
|
foo
|
|
''', m.RedefinedWhileUnused)
|
|
|
|
def test_importInDoctestAndAfter(self):
|
|
self.flakes('''
|
|
def doctest_stuff():
|
|
"""
|
|
>>> import foo
|
|
>>> foo
|
|
"""
|
|
|
|
import foo
|
|
foo()
|
|
''')
|
|
|
|
def test_offsetInDoctests(self):
|
|
exc = self.flakes('''
|
|
|
|
def doctest_stuff():
|
|
"""
|
|
>>> x # line 5
|
|
"""
|
|
|
|
''', m.UndefinedName).messages[0]
|
|
self.assertEqual(exc.lineno, 5)
|
|
self.assertEqual(exc.col, 12)
|
|
|
|
def test_offsetInLambdasInDoctests(self):
|
|
exc = self.flakes('''
|
|
|
|
def doctest_stuff():
|
|
"""
|
|
>>> lambda: x # line 5
|
|
"""
|
|
|
|
''', m.UndefinedName).messages[0]
|
|
self.assertEqual(exc.lineno, 5)
|
|
self.assertEqual(exc.col, 20)
|
|
|
|
def test_offsetAfterDoctests(self):
|
|
exc = self.flakes('''
|
|
|
|
def doctest_stuff():
|
|
"""
|
|
>>> x = 5
|
|
"""
|
|
|
|
x
|
|
|
|
''', m.UndefinedName).messages[0]
|
|
self.assertEqual(exc.lineno, 8)
|
|
self.assertEqual(exc.col, 0)
|
|
|
|
def test_syntaxErrorInDoctest(self):
|
|
exceptions = self.flakes(
|
|
'''
|
|
def doctest_stuff():
|
|
"""
|
|
>>> from # line 4
|
|
>>> fortytwo = 42
|
|
>>> except Exception:
|
|
"""
|
|
''',
|
|
m.DoctestSyntaxError,
|
|
m.DoctestSyntaxError,
|
|
m.DoctestSyntaxError).messages
|
|
exc = exceptions[0]
|
|
self.assertEqual(exc.lineno, 4)
|
|
self.assertEqual(exc.col, 26)
|
|
exc = exceptions[1]
|
|
self.assertEqual(exc.lineno, 5)
|
|
self.assertEqual(exc.col, 16)
|
|
exc = exceptions[2]
|
|
self.assertEqual(exc.lineno, 6)
|
|
self.assertEqual(exc.col, 18)
|
|
|
|
def test_indentationErrorInDoctest(self):
|
|
exc = self.flakes('''
|
|
def doctest_stuff():
|
|
"""
|
|
>>> if True:
|
|
... pass
|
|
"""
|
|
''', m.DoctestSyntaxError).messages[0]
|
|
self.assertEqual(exc.lineno, 5)
|
|
self.assertEqual(exc.col, 16)
|
|
|
|
def test_offsetWithMultiLineArgs(self):
|
|
(exc1, exc2) = self.flakes(
|
|
'''
|
|
def doctest_stuff(arg1,
|
|
arg2,
|
|
arg3):
|
|
"""
|
|
>>> assert
|
|
>>> this
|
|
"""
|
|
''',
|
|
m.DoctestSyntaxError,
|
|
m.UndefinedName).messages
|
|
self.assertEqual(exc1.lineno, 6)
|
|
self.assertEqual(exc1.col, 19)
|
|
self.assertEqual(exc2.lineno, 7)
|
|
self.assertEqual(exc2.col, 12)
|
|
|
|
def test_doctestCanReferToFunction(self):
|
|
self.flakes("""
|
|
def foo():
|
|
'''
|
|
>>> foo
|
|
'''
|
|
""")
|
|
|
|
def test_doctestCanReferToClass(self):
|
|
self.flakes("""
|
|
class Foo():
|
|
'''
|
|
>>> Foo
|
|
'''
|
|
def bar(self):
|
|
'''
|
|
>>> Foo
|
|
'''
|
|
""")
|
|
|
|
def test_noOffsetSyntaxErrorInDoctest(self):
|
|
exceptions = self.flakes(
|
|
'''
|
|
def buildurl(base, *args, **kwargs):
|
|
"""
|
|
>>> buildurl('/blah.php', ('a', '&'), ('b', '=')
|
|
'/blah.php?a=%26&b=%3D'
|
|
>>> buildurl('/blah.php', a='&', 'b'='=')
|
|
'/blah.php?b=%3D&a=%26'
|
|
"""
|
|
pass
|
|
''',
|
|
m.DoctestSyntaxError,
|
|
m.DoctestSyntaxError).messages
|
|
exc = exceptions[0]
|
|
self.assertEqual(exc.lineno, 4)
|
|
exc = exceptions[1]
|
|
self.assertEqual(exc.lineno, 6)
|
|
|
|
def test_singleUnderscoreInDoctest(self):
|
|
self.flakes('''
|
|
def func():
|
|
"""A docstring
|
|
|
|
>>> func()
|
|
1
|
|
>>> _
|
|
1
|
|
"""
|
|
return 1
|
|
''')
|
|
|
|
|
|
class TestOther(_DoctestMixin, TestOther):
|
|
pass
|
|
|
|
|
|
class TestImports(_DoctestMixin, TestImports):
|
|
|
|
def test_futureImport(self):
|
|
"""XXX This test can't work in a doctest"""
|
|
|
|
def test_futureImportUsed(self):
|
|
"""XXX This test can't work in a doctest"""
|
|
|
|
|
|
class TestUndefinedNames(_DoctestMixin, TestUndefinedNames):
|
|
|
|
def test_doubleNestingReportsClosestName(self):
|
|
"""
|
|
Lines in doctest are a bit different so we can't use the test
|
|
from TestUndefinedNames
|
|
"""
|
|
exc = self.flakes('''
|
|
def a():
|
|
x = 1
|
|
def b():
|
|
x = 2 # line 7 in the file
|
|
def c():
|
|
x
|
|
x = 3
|
|
return x
|
|
return x
|
|
return x
|
|
''', m.UndefinedLocal).messages[0]
|
|
self.assertEqual(exc.message_args, ('x', 7))
|