Blob Blame History Raw
From 69e8e2ab42353479129f14afc542322d3b02de84 Mon Sep 17 00:00:00 2001
From: Dmitry S <dsagal+git@gmail.com>
Date: Thu, 5 Jul 2018 15:03:08 -0400
Subject: [PATCH] Fixes to make asttokens work with Python3.7 and astroid 2.0.

Fixes detection of non-coding tokens to work with py37.
Skips testing of deep-recursion on astroid 2.0, which no longer supports it.
Adds Python3.7 testing to tox.ini.
---
 asttokens/asttokens.py    |  8 ++++----
 asttokens/util.py         | 14 ++++++++++++++
 tests/test_mark_tokens.py | 20 ++++++++++++++------
 tox.ini                   |  5 +++--
 4 files changed, 35 insertions(+), 12 deletions(-)

diff --git a/asttokens/asttokens.py b/asttokens/asttokens.py
index c0126a6b78..668620d085 100644
--- a/asttokens/asttokens.py
+++ b/asttokens/asttokens.py
@@ -20,7 +20,7 @@ import io
 import six
 from six.moves import xrange      # pylint: disable=redefined-builtin
 from .line_numbers import LineNumbers
-from .util import Token, match_token
+from .util import Token, match_token, is_non_coding_token
 from .mark_tokens import MarkTokens
 
 class ASTTokens(object):
@@ -135,7 +135,7 @@ class ASTTokens(object):
     """
     i = tok.index + 1
     if not include_extra:
-      while self._tokens[i].type >= token.N_TOKENS:
+      while is_non_coding_token(self._tokens[i].type):
         i += 1
     return self._tokens[i]
 
@@ -146,7 +146,7 @@ class ASTTokens(object):
     """
     i = tok.index - 1
     if not include_extra:
-      while self._tokens[i].type >= token.N_TOKENS:
+      while is_non_coding_token(self._tokens[i].type):
         i -= 1
     return self._tokens[i]
 
@@ -168,7 +168,7 @@ class ASTTokens(object):
     include_extra is True, includes non-coding tokens such as tokenize.NL and .COMMENT.
     """
     for i in xrange(first_token.index, last_token.index + 1):
-      if include_extra or self._tokens[i].type < token.N_TOKENS:
+      if include_extra or not is_non_coding_token(self._tokens[i].type):
         yield self._tokens[i]
 
   def get_tokens(self, node, include_extra=False):
diff --git a/asttokens/util.py b/asttokens/util.py
index 4dd2f27983..3be33abb57 100644
--- a/asttokens/util.py
+++ b/asttokens/util.py
@@ -57,6 +57,20 @@ def expect_token(token, tok_type, tok_str=None):
       token_repr(tok_type, tok_str), str(token),
       token.start[0], token.start[1] + 1))
 
+# These were previously defined in tokenize.py and distinguishable by being greater than
+# token.N_TOKEN. As of python3.7, they are in token.py, and we check for them explicitly.
+if hasattr(token, 'COMMENT'):
+  def is_non_coding_token(token_type):
+    """
+    These are considered non-coding tokens, as they don't affect the syntax tree.
+    """
+    return token_type in (token.NL, token.COMMENT, token.ENCODING)
+else:
+  def is_non_coding_token(token_type):
+    """
+    These are considered non-coding tokens, as they don't affect the syntax tree.
+    """
+    return token_type >= token.N_TOKENS
 
 def iter_children(node):
   """
diff --git a/tests/test_mark_tokens.py b/tests/test_mark_tokens.py
index a15934df9c..61c56bab1b 100644
--- a/tests/test_mark_tokens.py
+++ b/tests/test_mark_tokens.py
@@ -3,6 +3,7 @@ from __future__ import unicode_literals, print_function
 import astroid
 import six
 import sys
+import token
 import textwrap
 import unittest
 from . import tools
@@ -155,13 +156,19 @@ b +     # line3
     # to_source() on it because it chokes on recursion depth. So we test individual nodes.
     source = tools.read_fixture('astroid/joined_strings.py')
 
-    astroid.MANAGER.optimize_ast = True
-    try:
-      m = self.create_mark_checker(source)
-    finally:
-      astroid.MANAGER.optimize_ast = False
-
     if self.is_astroid_test:
+      if getattr(astroid, '__version__', '1') >= '2':
+        # Astroid 2 no longer supports this; see
+        # https://github.com/PyCQA/astroid/issues/557#issuecomment-396004274
+        self.skipTest('astroid-2.0 does not support this')
+
+      # Astroid < 2 does support this with optimize_ast set to True
+      astroid.MANAGER.optimize_ast = True
+      try:
+        m = self.create_mark_checker(source)
+      finally:
+        astroid.MANAGER.optimize_ast = False
+
       self.assertEqual(len(m.all_nodes), 4)     # This is the result of astroid's optimization
       self.assertEqual(m.view_node_types_at(1, 0), {'Module', 'Assign', 'AssignName'})
       const = next(n for n in m.all_nodes if isinstance(n, astroid.nodes.Const))
@@ -171,6 +178,7 @@ b +     # line3
       # astroid could avoid the need for the optimization by using an explicit stack like we do.
       #self.assertEqual(m.atok.get_text_range(const), (5, len(source) - 1))
     else:
+      m = self.create_mark_checker(source)
       self.assertEqual(len(m.all_nodes), 2104)
       self.assertEqual(m.view_node(m.all_nodes[-1]),
                        "Str:'F1akOFFiRIgPHTZksKBAgMCLGTdGNIAAQgKfDAcgZbj0odOnUA8GBAA7'")