mirror of
https://github.com/davidhalter/parso.git
synced 2025-12-08 21:54:54 +08:00
Try to add syntax errors to pep8 normalizing.
This commit is contained in:
@@ -7,6 +7,7 @@ class Normalizer(object):
|
|||||||
self.issues = []
|
self.issues = []
|
||||||
|
|
||||||
def walk(self, node):
|
def walk(self, node):
|
||||||
|
self.initialize(node)
|
||||||
value = self.visit(node)
|
value = self.visit(node)
|
||||||
self.finalize()
|
self.finalize()
|
||||||
return value
|
return value
|
||||||
@@ -27,6 +28,9 @@ class Normalizer(object):
|
|||||||
def visit_leaf(self, leaf):
|
def visit_leaf(self, leaf):
|
||||||
return leaf.prefix + leaf.value
|
return leaf.prefix + leaf.value
|
||||||
|
|
||||||
|
def initialize(self, node):
|
||||||
|
pass
|
||||||
|
|
||||||
def finalize(self):
|
def finalize(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
from contextlib import contextmanager
|
from contextlib import contextmanager
|
||||||
|
|
||||||
from parso.normalizer import Normalizer, NormalizerConfig
|
from parso.normalizer import Normalizer, NormalizerConfig, Issue
|
||||||
|
|
||||||
|
_BLOCK_STMTS = ('if_stmt', 'while_stmt', 'for_stmt', 'try_stmt', 'with_stmt')
|
||||||
|
# This is the maximal block size given by python.
|
||||||
|
_MAX_BLOCK_SIZE = 20
|
||||||
|
|
||||||
class CompressNormalizer(Normalizer):
|
class CompressNormalizer(Normalizer):
|
||||||
"""
|
"""
|
||||||
@@ -11,6 +14,23 @@ class CompressNormalizer(Normalizer):
|
|||||||
return leaf.prefix + leaf.value
|
return leaf.prefix + leaf.value
|
||||||
|
|
||||||
|
|
||||||
|
class Context(object):
|
||||||
|
def __init__(self, scope, parent_context=None):
|
||||||
|
self.blocks = []
|
||||||
|
|
||||||
|
@contextmanager
|
||||||
|
def add_block(self, node):
|
||||||
|
self.blocks.append(node)
|
||||||
|
yield
|
||||||
|
self.blocks.pop()
|
||||||
|
|
||||||
|
@contextmanager
|
||||||
|
def add_context(self, node):
|
||||||
|
self.blocks.append(node)
|
||||||
|
yield Context(node, parent_context=self)
|
||||||
|
self.blocks.pop()
|
||||||
|
|
||||||
|
|
||||||
class ErrorFinder(Normalizer):
|
class ErrorFinder(Normalizer):
|
||||||
"""
|
"""
|
||||||
Searches for errors in the syntax tree.
|
Searches for errors in the syntax tree.
|
||||||
@@ -19,37 +39,49 @@ class ErrorFinder(Normalizer):
|
|||||||
super(ErrorFinder, self).__init__(*args, **kwargs)
|
super(ErrorFinder, self).__init__(*args, **kwargs)
|
||||||
self._error_dict = {}
|
self._error_dict = {}
|
||||||
|
|
||||||
|
def initialize(self, node):
|
||||||
|
from parso.python.tree import search_ancestor
|
||||||
|
parent_scope = search_ancestor(node, 'classdef', 'funcdef', 'file_input')
|
||||||
|
self._context = Context(parent_scope)
|
||||||
|
|
||||||
@contextmanager
|
@contextmanager
|
||||||
def visit_node(self, node):
|
def visit_node(self, node):
|
||||||
if node.type == 'error_node':
|
if node.type == 'error_node':
|
||||||
leaf = node.get_next_leaf()
|
leaf = node.get_next_leaf()
|
||||||
self._add_error(901, "Syntax Error", leaf)
|
self._add_syntax_error("Syntax Error", leaf)
|
||||||
|
elif node.type in _BLOCK_STMTS:
|
||||||
|
with self._context.add_block(node):
|
||||||
|
yield
|
||||||
|
return
|
||||||
|
elif node.type in ('classdef', 'funcdef'):
|
||||||
|
context = self._context
|
||||||
|
with self._context.add_context(node) as new_context:
|
||||||
|
if len(context.blocks) == _MAX_BLOCK_SIZE:
|
||||||
|
self._add_syntax_error("Too many statically nested blocks", node)
|
||||||
|
self._context = new_context
|
||||||
|
yield
|
||||||
|
self._context = context
|
||||||
|
return
|
||||||
|
|
||||||
yield
|
yield
|
||||||
|
|
||||||
def visit_leaf(self, leaf):
|
def visit_leaf(self, leaf):
|
||||||
if leaf.type == 'error_leaf':
|
if leaf.type == 'error_leaf':
|
||||||
self._add_error(901, "Syntax Error", leaf)
|
self._add_syntax_error("Syntax Error", leaf)
|
||||||
|
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
|
def _add_syntax_error(self, message, node):
|
||||||
|
self._add_error(901, message, node)
|
||||||
|
|
||||||
def _add_error(self, code, message, node):
|
def _add_error(self, code, message, node):
|
||||||
|
# Check if the issues are on the same line.
|
||||||
line = node.start_pos[0]
|
line = node.start_pos[0]
|
||||||
self._error_dict.setdefault(line, (code, message, node))
|
self._error_dict.setdefault(line, (code, message, node))
|
||||||
|
|
||||||
def finalize(self):
|
def finalize(self):
|
||||||
for code, message, node in self._error_dict.values():
|
for code, message, node in self._error_dict.values():
|
||||||
self.add_issue(code, message, node)
|
self.issues.append(Issue(node, code, message))
|
||||||
|
|
||||||
def add_issue(self, code, message, node):
|
|
||||||
# Check if the issues are on the same line.
|
|
||||||
prev = node.get_previous_leaf()
|
|
||||||
if prev is not None and prev.type == 'error_leaf':
|
|
||||||
# There's already an error nearby. There's a huge chance they are
|
|
||||||
# related, so don't report this one.
|
|
||||||
return
|
|
||||||
|
|
||||||
super(ErrorFinder, self).add_issue(code, message, node)
|
|
||||||
|
|
||||||
|
|
||||||
class ErrorFinderConfig(NormalizerConfig):
|
class ErrorFinderConfig(NormalizerConfig):
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import re
|
import re
|
||||||
from contextlib import contextmanager
|
from contextlib import contextmanager
|
||||||
|
|
||||||
from parso.normalizer import Normalizer, Rule, NormalizerConfig
|
from parso.python.normalizer import ErrorFinder, ErrorFinderConfig
|
||||||
|
from parso.normalizer import Rule
|
||||||
|
|
||||||
|
|
||||||
_IMPORT_TYPES = ('import_name', 'import_from')
|
_IMPORT_TYPES = ('import_name', 'import_from')
|
||||||
@@ -147,7 +148,7 @@ def _is_magic_name(name):
|
|||||||
return name.value.startswith('__') and name.value.startswith('__')
|
return name.value.startswith('__') and name.value.startswith('__')
|
||||||
|
|
||||||
|
|
||||||
class PEP8Normalizer(Normalizer):
|
class PEP8Normalizer(ErrorFinder):
|
||||||
def __init__(self, config):
|
def __init__(self, config):
|
||||||
super(PEP8Normalizer, self).__init__(config)
|
super(PEP8Normalizer, self).__init__(config)
|
||||||
self._previous_part = None
|
self._previous_part = None
|
||||||
@@ -172,6 +173,10 @@ class PEP8Normalizer(Normalizer):
|
|||||||
|
|
||||||
@contextmanager
|
@contextmanager
|
||||||
def visit_node(self, node):
|
def visit_node(self, node):
|
||||||
|
with super(PEP8Normalizer, self).visit_node(node):
|
||||||
|
return self._visit_node(node)
|
||||||
|
|
||||||
|
def _visit_node(self, node):
|
||||||
typ = node.type
|
typ = node.type
|
||||||
|
|
||||||
if typ in 'import_name':
|
if typ in 'import_name':
|
||||||
@@ -329,6 +334,7 @@ class PEP8Normalizer(Normalizer):
|
|||||||
self._newline_count = 0
|
self._newline_count = 0
|
||||||
|
|
||||||
def visit_leaf(self, leaf):
|
def visit_leaf(self, leaf):
|
||||||
|
super(PEP8Normalizer, self).visit_leaf(leaf)
|
||||||
for part in leaf._split_prefix():
|
for part in leaf._split_prefix():
|
||||||
if part.type == 'spacing':
|
if part.type == 'spacing':
|
||||||
# This part is used for the part call after for.
|
# This part is used for the part call after for.
|
||||||
@@ -684,7 +690,7 @@ class PEP8Normalizer(Normalizer):
|
|||||||
super(PEP8Normalizer, self).add_issue(code, message, node)
|
super(PEP8Normalizer, self).add_issue(code, message, node)
|
||||||
|
|
||||||
|
|
||||||
class PEP8NormalizerConfig(NormalizerConfig):
|
class PEP8NormalizerConfig(ErrorFinderConfig):
|
||||||
normalizer_class = PEP8Normalizer
|
normalizer_class = PEP8Normalizer
|
||||||
"""
|
"""
|
||||||
Normalizing to PEP8. Not really implemented, yet.
|
Normalizing to PEP8. Not really implemented, yet.
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
for a in 'abc':
|
for a in 'abc':
|
||||||
for b in 'xyz':
|
for b in 'xyz':
|
||||||
print a # indented with 8 spaces
|
print(a) # indented with 8 spaces
|
||||||
# TODO currently not an error, because the indentation matches.
|
#: E901:1
|
||||||
print(b) # indented with 1 tab
|
print(b) # indented with 1 tab
|
||||||
if True:
|
if True:
|
||||||
#: E101:0
|
#: E101:0
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ if False:
|
|||||||
pass
|
pass
|
||||||
print
|
print
|
||||||
print
|
print
|
||||||
|
#: E901:4
|
||||||
print
|
print
|
||||||
mimetype = 'application/x-directory'
|
mimetype = 'application/x-directory'
|
||||||
#: E111:5
|
#: E111:5
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
print "E121", (
|
abc = "E121", (
|
||||||
#: E121:2
|
#: E121:2
|
||||||
"dent")
|
"dent")
|
||||||
print "E122", (
|
abc = "E122", (
|
||||||
#: E121:0
|
#: E121:0
|
||||||
"dent")
|
"dent")
|
||||||
my_list = [
|
my_list = [
|
||||||
@@ -9,11 +9,11 @@ my_list = [
|
|||||||
4, 5, 6,
|
4, 5, 6,
|
||||||
#: E123
|
#: E123
|
||||||
]
|
]
|
||||||
print "E124", ("visual",
|
abc = "E124", ("visual",
|
||||||
"indent_two"
|
"indent_two"
|
||||||
#: E124:14
|
#: E124:14
|
||||||
)
|
)
|
||||||
print "E124", ("visual",
|
abc = "E124", ("visual",
|
||||||
"indent_five"
|
"indent_five"
|
||||||
#: E124:0
|
#: E124:0
|
||||||
)
|
)
|
||||||
@@ -25,19 +25,19 @@ if (row < 0 or self.moduleCount <= row or
|
|||||||
col < 0 or self.moduleCount <= col):
|
col < 0 or self.moduleCount <= col):
|
||||||
raise Exception("%s,%s - %s" % (row, col, self.moduleCount))
|
raise Exception("%s,%s - %s" % (row, col, self.moduleCount))
|
||||||
|
|
||||||
print "E126", (
|
abc = "E126", (
|
||||||
#: E126:12
|
#: E126:12
|
||||||
"dent")
|
"dent")
|
||||||
print "E126", (
|
abc = "E126", (
|
||||||
#: E126:8
|
#: E126:8
|
||||||
"dent")
|
"dent")
|
||||||
print "E127", ("over-",
|
abc = "E127", ("over-",
|
||||||
#: E127:18
|
#: E127:18
|
||||||
"over-indent")
|
"over-indent")
|
||||||
print "E128", ("visual",
|
abc = "E128", ("visual",
|
||||||
#: E128:4
|
#: E128:4
|
||||||
"hanging")
|
"hanging")
|
||||||
print "E128", ("under-",
|
abc = "E128", ("under-",
|
||||||
#: E128:14
|
#: E128:14
|
||||||
"under-indent")
|
"under-indent")
|
||||||
|
|
||||||
@@ -63,7 +63,7 @@ rv.update(dict.fromkeys((
|
|||||||
abricot = 3 + \
|
abricot = 3 + \
|
||||||
4 + \
|
4 + \
|
||||||
5 + 6
|
5 + 6
|
||||||
print "hello", (
|
abc = "hello", (
|
||||||
|
|
||||||
"there",
|
"there",
|
||||||
#: E126:5
|
#: E126:5
|
||||||
|
|||||||
@@ -55,32 +55,32 @@ if start[1] > end_col and not (
|
|||||||
"indented for visual indent")
|
"indented for visual indent")
|
||||||
|
|
||||||
|
|
||||||
print "OK", ("visual",
|
abc = "OK", ("visual",
|
||||||
"indent")
|
"indent")
|
||||||
|
|
||||||
print "Okay", ("visual",
|
abc = "Okay", ("visual",
|
||||||
"indent_three"
|
"indent_three"
|
||||||
)
|
)
|
||||||
|
|
||||||
print "a-ok", (
|
abc = "a-ok", (
|
||||||
"there",
|
"there",
|
||||||
"dude",
|
"dude",
|
||||||
)
|
)
|
||||||
|
|
||||||
print "hello", (
|
abc = "hello", (
|
||||||
"there",
|
"there",
|
||||||
"dude")
|
"dude")
|
||||||
|
|
||||||
print "hello", (
|
abc = "hello", (
|
||||||
|
|
||||||
"there",
|
"there",
|
||||||
# "john",
|
# "john",
|
||||||
"dude")
|
"dude")
|
||||||
|
|
||||||
print "hello", (
|
abc = "hello", (
|
||||||
"there", "dude")
|
"there", "dude")
|
||||||
|
|
||||||
print "hello", (
|
abc = "hello", (
|
||||||
"there", "dude",
|
"there", "dude",
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -196,12 +196,12 @@ if bar:
|
|||||||
if ((foo.bar("baz") and
|
if ((foo.bar("baz") and
|
||||||
foo.bar("frop")
|
foo.bar("frop")
|
||||||
)):
|
)):
|
||||||
print "yes"
|
print("yes")
|
||||||
|
|
||||||
# also ok, but starting to look like LISP
|
# also ok, but starting to look like LISP
|
||||||
if ((foo.bar("baz") and
|
if ((foo.bar("baz") and
|
||||||
foo.bar("frop"))):
|
foo.bar("frop"))):
|
||||||
print "yes"
|
print("yes")
|
||||||
|
|
||||||
#: E129+1:4 E127+2:9
|
#: E129+1:4 E127+2:9
|
||||||
if (a == 2 or
|
if (a == 2 or
|
||||||
@@ -223,7 +223,7 @@ if length > options.max_line_length:
|
|||||||
# blub
|
# blub
|
||||||
|
|
||||||
|
|
||||||
print 'l.{line}\t{pos}\t{name}\t{text}'.format(
|
asd = 'l.{line}\t{pos}\t{name}\t{text}'.format(
|
||||||
line=token[2][0],
|
line=token[2][0],
|
||||||
pos=pos,
|
pos=pos,
|
||||||
name=tokenize.tok_name[token[0]],
|
name=tokenize.tok_name[token[0]],
|
||||||
|
|||||||
@@ -83,9 +83,6 @@ help = "print total number of errors " \
|
|||||||
help = u"print total number of errors " \
|
help = u"print total number of errors " \
|
||||||
u"to standard error"
|
u"to standard error"
|
||||||
|
|
||||||
help = ur"print total number of errors " \
|
|
||||||
ur"to standard error"
|
|
||||||
|
|
||||||
help = b"print total number of errors " \
|
help = b"print total number of errors " \
|
||||||
b"to standard error"
|
b"to standard error"
|
||||||
|
|
||||||
@@ -187,6 +184,8 @@ try: %s -d5
|
|||||||
''' % sys.argv[0])
|
''' % sys.argv[0])
|
||||||
|
|
||||||
|
|
||||||
|
# The try statement above was not finished.
|
||||||
|
#: E901
|
||||||
d = { # comment
|
d = { # comment
|
||||||
1: 2
|
1: 2
|
||||||
}
|
}
|
||||||
@@ -284,7 +283,7 @@ some_hash = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
print dedent(
|
abc = dedent(
|
||||||
'''
|
'''
|
||||||
mkdir -p ./{build}/
|
mkdir -p ./{build}/
|
||||||
mv ./build/ ./{build}/%(revision)s/
|
mv ./build/ ./{build}/%(revision)s/
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ if True:
|
|||||||
or another_very_long_variable_name:
|
or another_very_long_variable_name:
|
||||||
raise Exception()
|
raise Exception()
|
||||||
|
|
||||||
|
#: E901+1:8 E901+5
|
||||||
dictionary = [
|
dictionary = [
|
||||||
"is": {
|
"is": {
|
||||||
# Might be a E122:4, but is not because the code is invalid Python.
|
# Might be a E122:4, but is not because the code is invalid Python.
|
||||||
@@ -40,7 +41,7 @@ setup('',
|
|||||||
|
|
||||||
|
|
||||||
#: E123+2:4 E291:15
|
#: E123+2:4 E291:15
|
||||||
print "E123", (
|
abc = "E123", (
|
||||||
"bad", "hanging", "close"
|
"bad", "hanging", "close"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ for foo in """
|
|||||||
123
|
123
|
||||||
""".strip().split():
|
""".strip().split():
|
||||||
print(foo)
|
print(foo)
|
||||||
print dedent(
|
abc = dedent(
|
||||||
'''
|
'''
|
||||||
mkdir -p ./{build}/
|
mkdir -p ./{build}/
|
||||||
mv ./build/ ./{build}/%(revision)s/
|
mv ./build/ ./{build}/%(revision)s/
|
||||||
|
|||||||
@@ -35,18 +35,18 @@ result = [
|
|||||||
|
|
||||||
#: E203:9
|
#: E203:9
|
||||||
if x == 4 :
|
if x == 4 :
|
||||||
print x, y
|
print(x, y)
|
||||||
x, y = y, x
|
x, y = y, x
|
||||||
if x == 4:
|
if x == 4:
|
||||||
#: E203:12 E702:13
|
#: E203:12 E702:13
|
||||||
a = x, y ; x, y = y, x
|
a = x, y ; x, y = y, x
|
||||||
if x == 4:
|
if x == 4:
|
||||||
print x, y
|
print(x, y)
|
||||||
#: E203:12
|
#: E203:12
|
||||||
x, y = y , x
|
x, y = y , x
|
||||||
# Okay
|
# Okay
|
||||||
if x == 4:
|
if x == 4:
|
||||||
print x, y
|
print(x, y)
|
||||||
x, y = y, x
|
x, y = y, x
|
||||||
a[b1, :] == a[b1, ...]
|
a[b1, :] == a[b1, ...]
|
||||||
a[b1, :1] == 3
|
a[b1, :1] == 3
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ True and False
|
|||||||
if 1:
|
if 1:
|
||||||
pass
|
pass
|
||||||
# Syntax Error, no indentation
|
# Syntax Error, no indentation
|
||||||
|
#: E901+1
|
||||||
if 1:
|
if 1:
|
||||||
pass
|
pass
|
||||||
#: E223:8
|
#: E223:8
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ def _get_error_list(code, version=None):
|
|||||||
('?', [(1, 0)]),
|
('?', [(1, 0)]),
|
||||||
('??', [(1, 0)]),
|
('??', [(1, 0)]),
|
||||||
('? ?', [(1, 0)]),
|
('? ?', [(1, 0)]),
|
||||||
('?\n?', [(1, 0)]),
|
('?\n?', [(1, 0), (2, 0)]),
|
||||||
('? * ?', [(1, 0)]),
|
('? * ?', [(1, 0)]),
|
||||||
('1 + * * 2', [(1, 4)]),
|
('1 + * * 2', [(1, 4)]),
|
||||||
('?\n1\n?', [(1, 0), (3, 0)]),
|
('?\n1\n?', [(1, 0), (3, 0)]),
|
||||||
|
|||||||
Reference in New Issue
Block a user