diff --git a/CHANGELOG.rst b/CHANGELOG.rst index b0c7ca0..468d6fc 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -3,9 +3,11 @@ Changelog --------- -0.4.1 (2019-06-05) +0.5.0 (2019-06-05) ++++++++++++++++++ +- **Breaking Change** comp_for is now called sync_comp_for for all Python + versions to be compatible with the Python 3.8 Grammar - Added .pyi stubs for a lot of the parso API - Small FileIO changes diff --git a/parso/normalizer.py b/parso/normalizer.py index 9a3e82e..b076fe5 100644 --- a/parso/normalizer.py +++ b/parso/normalizer.py @@ -41,8 +41,8 @@ class Normalizer(use_metaclass(_NormalizerMeta)): except AttributeError: return self.visit_leaf(node) else: - with self.visit_node(node): - return ''.join(self.visit(child) for child in children) + with self.visit_node(node): + return ''.join(self.visit(child) for child in children) @contextmanager def visit_node(self, node): @@ -147,7 +147,6 @@ class Issue(object): return '<%s: %s>' % (self.__class__.__name__, self.code) - class Rule(object): code = None message = None diff --git a/parso/python/errors.py b/parso/python/errors.py index 6dd6175..b6e6e5e 100644 --- a/parso/python/errors.py +++ b/parso/python/errors.py @@ -953,20 +953,17 @@ class _CheckAssignmentRule(SyntaxRule): self.add_issue(node, message=message) -@ErrorFinder.register_rule(type='comp_for') @ErrorFinder.register_rule(type='sync_comp_for') class _CompForRule(_CheckAssignmentRule): message = "asynchronous comprehension outside of an asynchronous function" def is_issue(self, node): - # Some of the nodes here are already used, so no else if - if node.type != 'comp_for' or self._normalizer.version < (3, 8): - # comp_for was replaced by sync_comp_for in Python 3.8. - expr_list = node.children[1 + int(node.children[0] == 'async')] - if expr_list.type != 'expr_list': # Already handled. - self._check_assignment(expr_list) + expr_list = node.children[1] + print(expr_list) + if expr_list.type != 'expr_list': # Already handled. + self._check_assignment(expr_list) - return node.children[0] == 'async' \ + return node.parent.children[0] == 'async' \ and not self._normalizer.context.is_async_funcdef() diff --git a/parso/python/grammar27.txt b/parso/python/grammar27.txt index 359f12b..ddb6847 100644 --- a/parso/python/grammar27.txt +++ b/parso/python/grammar27.txt @@ -107,7 +107,7 @@ atom: ('(' [yield_expr|testlist_comp] ')' | NAME | NUMBER | strings) strings: STRING+ listmaker: test ( list_for | (',' test)* [','] ) -testlist_comp: test ( comp_for | (',' test)* [','] ) +testlist_comp: test ( sync_comp_for | (',' test)* [','] ) lambdef: 'lambda' [varargslist] ':' test trailer: '(' [arglist] ')' | '[' subscriptlist ']' | '.' NAME subscriptlist: subscript (',' subscript)* [','] @@ -115,8 +115,8 @@ subscript: '.' '.' '.' | test | [test] ':' [test] [sliceop] sliceop: ':' [test] exprlist: expr (',' expr)* [','] testlist: test (',' test)* [','] -dictorsetmaker: ( (test ':' test (comp_for | (',' test ':' test)* [','])) | - (test (comp_for | (',' test)* [','])) ) +dictorsetmaker: ( (test ':' test (sync_comp_for | (',' test ':' test)* [','])) | + (test (sync_comp_for | (',' test)* [','])) ) classdef: 'class' NAME ['(' [testlist] ')'] ':' suite @@ -125,14 +125,14 @@ arglist: (argument ',')* (argument [','] |'**' test) # The reason that keywords are test nodes instead of NAME is that using NAME # results in an ambiguity. ast.c makes sure it's a NAME. -argument: test [comp_for] | test '=' test +argument: test [sync_comp_for] | test '=' test list_iter: list_for | list_if list_for: 'for' exprlist 'in' testlist_safe [list_iter] list_if: 'if' old_test [list_iter] -comp_iter: comp_for | comp_if -comp_for: 'for' exprlist 'in' or_test [comp_iter] +comp_iter: sync_comp_for | comp_if +sync_comp_for: 'for' exprlist 'in' or_test [comp_iter] comp_if: 'if' old_test [comp_iter] testlist1: test (',' test)* diff --git a/parso/python/grammar33.txt b/parso/python/grammar33.txt index 3a55809..787a166 100644 --- a/parso/python/grammar33.txt +++ b/parso/python/grammar33.txt @@ -105,15 +105,15 @@ atom: ('(' [yield_expr|testlist_comp] ')' | '{' [dictorsetmaker] '}' | NAME | NUMBER | strings | '...' | 'None' | 'True' | 'False') strings: STRING+ -testlist_comp: (test|star_expr) ( comp_for | (',' (test|star_expr))* [','] ) +testlist_comp: (test|star_expr) ( sync_comp_for | (',' (test|star_expr))* [','] ) trailer: '(' [arglist] ')' | '[' subscriptlist ']' | '.' NAME subscriptlist: subscript (',' subscript)* [','] subscript: test | [test] ':' [test] [sliceop] sliceop: ':' [test] exprlist: (expr|star_expr) (',' (expr|star_expr))* [','] testlist: test (',' test)* [','] -dictorsetmaker: ( (test ':' test (comp_for | (',' test ':' test)* [','])) | - (test (comp_for | (',' test)* [','])) ) +dictorsetmaker: ( (test ':' test (sync_comp_for | (',' test ':' test)* [','])) | + (test (sync_comp_for | (',' test)* [','])) ) classdef: 'class' NAME ['(' [arglist] ')'] ':' suite @@ -122,9 +122,9 @@ arglist: (argument ',')* (argument [','] |'**' test) # The reason that keywords are test nodes instead of NAME is that using NAME # results in an ambiguity. ast.c makes sure it's a NAME. -argument: test [comp_for] | test '=' test # Really [keyword '='] test -comp_iter: comp_for | comp_if -comp_for: 'for' exprlist 'in' or_test [comp_iter] +argument: test [sync_comp_for] | test '=' test # Really [keyword '='] test +comp_iter: sync_comp_for | comp_if +sync_comp_for: 'for' exprlist 'in' or_test [comp_iter] comp_if: 'if' test_nocond [comp_iter] # not used in grammar, but may appear in "node" passed from Parser to Compiler diff --git a/parso/python/grammar34.txt b/parso/python/grammar34.txt index 324bba1..2b497d5 100644 --- a/parso/python/grammar34.txt +++ b/parso/python/grammar34.txt @@ -105,15 +105,15 @@ atom: ('(' [yield_expr|testlist_comp] ')' | '{' [dictorsetmaker] '}' | NAME | NUMBER | strings | '...' | 'None' | 'True' | 'False') strings: STRING+ -testlist_comp: (test|star_expr) ( comp_for | (',' (test|star_expr))* [','] ) +testlist_comp: (test|star_expr) ( sync_comp_for | (',' (test|star_expr))* [','] ) trailer: '(' [arglist] ')' | '[' subscriptlist ']' | '.' NAME subscriptlist: subscript (',' subscript)* [','] subscript: test | [test] ':' [test] [sliceop] sliceop: ':' [test] exprlist: (expr|star_expr) (',' (expr|star_expr))* [','] testlist: test (',' test)* [','] -dictorsetmaker: ( (test ':' test (comp_for | (',' test ':' test)* [','])) | - (test (comp_for | (',' test)* [','])) ) +dictorsetmaker: ( (test ':' test (sync_comp_for | (',' test ':' test)* [','])) | + (test (sync_comp_for | (',' test)* [','])) ) classdef: 'class' NAME ['(' [arglist] ')'] ':' suite @@ -122,9 +122,9 @@ arglist: (argument ',')* (argument [','] |'**' test) # The reason that keywords are test nodes instead of NAME is that using NAME # results in an ambiguity. ast.c makes sure it's a NAME. -argument: test [comp_for] | test '=' test # Really [keyword '='] test -comp_iter: comp_for | comp_if -comp_for: 'for' exprlist 'in' or_test [comp_iter] +argument: test [sync_comp_for] | test '=' test # Really [keyword '='] test +comp_iter: sync_comp_for | comp_if +sync_comp_for: 'for' exprlist 'in' or_test [comp_iter] comp_if: 'if' test_nocond [comp_iter] # not used in grammar, but may appear in "node" passed from Parser to Compiler diff --git a/parso/python/grammar35.txt b/parso/python/grammar35.txt index 5868b8f..e2ee9c7 100644 --- a/parso/python/grammar35.txt +++ b/parso/python/grammar35.txt @@ -112,7 +112,7 @@ atom: ('(' [yield_expr|testlist_comp] ')' | '{' [dictorsetmaker] '}' | NAME | NUMBER | strings | '...' | 'None' | 'True' | 'False') strings: STRING+ -testlist_comp: (test|star_expr) ( comp_for | (',' (test|star_expr))* [','] ) +testlist_comp: (test|star_expr) ( sync_comp_for | (',' (test|star_expr))* [','] ) trailer: '(' [arglist] ')' | '[' subscriptlist ']' | '.' NAME subscriptlist: subscript (',' subscript)* [','] subscript: test | [test] ':' [test] [sliceop] @@ -120,9 +120,9 @@ sliceop: ':' [test] exprlist: (expr|star_expr) (',' (expr|star_expr))* [','] testlist: test (',' test)* [','] dictorsetmaker: ( ((test ':' test | '**' expr) - (comp_for | (',' (test ':' test | '**' expr))* [','])) | + (sync_comp_for | (',' (test ':' test | '**' expr))* [','])) | ((test | star_expr) - (comp_for | (',' (test | star_expr))* [','])) ) + (sync_comp_for | (',' (test | star_expr))* [','])) ) classdef: 'class' NAME ['(' [arglist] ')'] ':' suite @@ -137,13 +137,13 @@ arglist: argument (',' argument)* [','] # Illegal combinations and orderings are blocked in ast.c: # multiple (test comp_for) arguments are blocked; keyword unpackings # that precede iterable unpackings are blocked; etc. -argument: ( test [comp_for] | +argument: ( test [sync_comp_for] | test '=' test | '**' test | '*' test ) -comp_iter: comp_for | comp_if -comp_for: 'for' exprlist 'in' or_test [comp_iter] +comp_iter: sync_comp_for | comp_if +sync_comp_for: 'for' exprlist 'in' or_test [comp_iter] comp_if: 'if' test_nocond [comp_iter] # not used in grammar, but may appear in "node" passed from Parser to Compiler diff --git a/parso/python/grammar36.txt b/parso/python/grammar36.txt index b82c1fe..3e1e3e2 100644 --- a/parso/python/grammar36.txt +++ b/parso/python/grammar36.txt @@ -140,7 +140,8 @@ argument: ( test [comp_for] | '*' test ) comp_iter: comp_for | comp_if -comp_for: ['async'] 'for' exprlist 'in' or_test [comp_iter] +sync_comp_for: 'for' exprlist 'in' or_test [comp_iter] +comp_for: ['async'] sync_comp_for comp_if: 'if' test_nocond [comp_iter] # not used in grammar, but may appear in "node" passed from Parser to Compiler diff --git a/parso/python/grammar37.txt b/parso/python/grammar37.txt index 77300fd..3090b93 100644 --- a/parso/python/grammar37.txt +++ b/parso/python/grammar37.txt @@ -138,7 +138,8 @@ argument: ( test [comp_for] | '*' test ) comp_iter: comp_for | comp_if -comp_for: ['async'] 'for' exprlist 'in' or_test [comp_iter] +sync_comp_for: 'for' exprlist 'in' or_test [comp_iter] +comp_for: ['async'] sync_comp_for comp_if: 'if' test_nocond [comp_iter] # not used in grammar, but may appear in "node" passed from Parser to Compiler diff --git a/parso/python/parser.py b/parso/python/parser.py index d98eccd..46bdc77 100644 --- a/parso/python/parser.py +++ b/parso/python/parser.py @@ -39,13 +39,13 @@ class Parser(BaseParser): 'for_stmt': tree.ForStmt, 'while_stmt': tree.WhileStmt, 'try_stmt': tree.TryStmt, - 'comp_for': tree.CompFor, + 'sync_comp_for': tree.SyncCompFor, # Not sure if this is the best idea, but IMO it's the easiest way to # avoid extreme amounts of work around the subtle difference of 2/3 # grammar in list comoprehensions. - 'list_for': tree.CompFor, + 'list_for': tree.SyncCompFor, # Same here. This just exists in Python 2.6. - 'gen_for': tree.CompFor, + 'gen_for': tree.SyncCompFor, 'decorator': tree.Decorator, 'lambdef': tree.Lambda, 'old_lambdef': tree.Lambda, diff --git a/parso/python/tree.py b/parso/python/tree.py index d0206d7..5dcf5b3 100644 --- a/parso/python/tree.py +++ b/parso/python/tree.py @@ -55,7 +55,7 @@ _FLOW_CONTAINERS = set(['if_stmt', 'while_stmt', 'for_stmt', 'try_stmt', _RETURN_STMT_CONTAINERS = set(['suite', 'simple_stmt']) | _FLOW_CONTAINERS _FUNC_CONTAINERS = set(['suite', 'simple_stmt', 'decorated']) | _FLOW_CONTAINERS _GET_DEFINITION_TYPES = set([ - 'expr_stmt', 'comp_for', 'with_stmt', 'for_stmt', 'import_name', + 'expr_stmt', 'sync_comp_for', 'with_stmt', 'for_stmt', 'import_name', 'import_from', 'param' ]) _IMPORTS = set(['import_name', 'import_from']) @@ -1192,8 +1192,8 @@ class Param(PythonBaseNode): return '<%s: %s>' % (type(self).__name__, str(self._tfpdef()) + default) -class CompFor(PythonBaseNode): - type = 'comp_for' +class SyncCompFor(PythonBaseNode): + type = 'sync_comp_for' __slots__ = () def get_defined_names(self): @@ -1201,4 +1201,4 @@ class CompFor(PythonBaseNode): Returns the a list of `Name` that the comprehension defines. """ # allow async for - return _defined_names(self.children[self.children.index('for') + 1]) + return _defined_names(self.children[1])