Refactor the Rule class a bit.

This commit is contained in:
Dave Halter
2017-08-16 18:17:51 +02:00
parent 51f2de28c6
commit 412da07893
3 changed files with 61 additions and 21 deletions

View File

@@ -44,6 +44,8 @@ class Normalizer(object):
class NormalizerConfig(object):
normalizer_class = Normalizer
rule_value_map = {}
rule_type_map = {}
def create_normalizer(self, grammar):
if self.normalizer_class is None:
@@ -52,21 +54,30 @@ class NormalizerConfig(object):
return self.normalizer_class(grammar, self)
@classmethod
def register_rule(cls, rule):
def register_rule(cls, **kwargs):
"""
Use it as a class decorator:
>>> normalizer = NormalizerConfig()
>>> @normalizer.register_rule
>>> @normalizer.register_rule(value='foo')
... class MyRule(Rule):
... error_code = 42
"""
try:
rules = cls.rules
except AttributeError:
rules = cls.rules = []
rules.append(rule)
return rule
return cls._register_rule(**kwargs)
@classmethod
def _register_rule(cls, value=None, type=None):
if value is None and type is None:
raise ValueError("You must register at least something.")
def decorator(func):
if value is not None:
cls.rule_value_map[value] = func
if type is not None:
cls.rule_type_map[type] = func
return func
return decorator
class Issue(object):
@@ -93,4 +104,24 @@ class Issue(object):
class Rule(object):
error_code = None
message = None
type = None
def check(self, node):
raise NotImplementedError()
def get_error_node(self, node):
return node
def add_error(self, error_code=None, message=None):
if error_code is None:
error_code = self.error_code
if error_code is None:
raise ValueError("The error code on the class is not set.")
if message is None:
message = self.message
if message is None:
raise ValueError("The message on the class is not set.")
def feed_node(self, node):
if self.check(node):
error_node = self.get_error_node(node)

View File

@@ -4,7 +4,7 @@ import warnings
import re
from contextlib import contextmanager
from parso.normalizer import Normalizer, NormalizerConfig, Issue
from parso.normalizer import Normalizer, NormalizerConfig, Issue, Rule
from parso.python.tree import search_ancestor
_BLOCK_STMTS = ('if_stmt', 'while_stmt', 'for_stmt', 'try_stmt', 'with_stmt')
@@ -671,9 +671,6 @@ class ErrorFinder(Normalizer):
and leaf.get_next_leaf() != 'from' \
and self._version == (3, 5):
self._add_syntax_error("'yield' inside async function", leaf.parent)
elif leaf.value == 'await':
if not self._context.is_async_funcdef():
self._add_syntax_error("'await' outside async function", leaf.parent)
elif leaf.value == 'from' and leaf.parent.type == 'yield_arg' \
and self._context.is_async_funcdef():
yield_ = leaf.parent.parent
@@ -783,3 +780,22 @@ class ErrorFinder(Normalizer):
class ErrorFinderConfig(NormalizerConfig):
normalizer_class = ErrorFinder
class SyntaxRule(Rule):
code = 901
class IndentationRule(Rule):
code = 903
@ErrorFinderConfig.register_rule(value='await')
class AwaitOutsideAsync(SyntaxRule):
message = "'await' outside async function"
def check_leaf_value(self, leaf):
return not self._context.is_async_funcdef()
def get_error_node(self, node):
return node.parent # Return the whole await statement.

View File

@@ -712,17 +712,10 @@ class PEP8NormalizerConfig(ErrorFinderConfig):
self.spaces_before_comment = spaces_before_comment
@PEP8NormalizerConfig.register_rule
class FooRule(Rule):
pass
@PEP8NormalizerConfig.register_rule
@PEP8NormalizerConfig.register_rule(type='endmarker')
class BlankLineAtEnd(Rule):
code = 392
message = 'Blank line at end of file'
leaf_event = ['endmarker']
def check(self, leaf):
return self._newline_count >= 2