contrib/check-py3-compat.py
changeset 48963 968b29a5a7fc
parent 45849 c102b704edb5
child 48966 6000f5b25c9b
equal deleted inserted replaced
48962:79009cca491e 48963:968b29a5a7fc
    13 import importlib
    13 import importlib
    14 import os
    14 import os
    15 import sys
    15 import sys
    16 import traceback
    16 import traceback
    17 import warnings
    17 import warnings
    18 
       
    19 
       
    20 def check_compat_py2(f):
       
    21     """Check Python 3 compatibility for a file with Python 2"""
       
    22     with open(f, 'rb') as fh:
       
    23         content = fh.read()
       
    24     root = ast.parse(content)
       
    25 
       
    26     # Ignore empty files.
       
    27     if not root.body:
       
    28         return
       
    29 
       
    30     futures = set()
       
    31     haveprint = False
       
    32     for node in ast.walk(root):
       
    33         if isinstance(node, ast.ImportFrom):
       
    34             if node.module == '__future__':
       
    35                 futures |= {n.name for n in node.names}
       
    36         elif isinstance(node, ast.Print):
       
    37             haveprint = True
       
    38 
       
    39     if 'absolute_import' not in futures:
       
    40         print('%s not using absolute_import' % f)
       
    41     if haveprint and 'print_function' not in futures:
       
    42         print('%s requires print_function' % f)
       
    43 
    18 
    44 
    19 
    45 def check_compat_py3(f):
    20 def check_compat_py3(f):
    46     """Check Python 3 compatibility of a file with Python 3."""
    21     """Check Python 3 compatibility of a file with Python 3."""
    47     with open(f, 'rb') as fh:
    22     with open(f, 'rb') as fh:
    92                     % (f, type(e).__name__, e, frame.lineno)
    67                     % (f, type(e).__name__, e, frame.lineno)
    93                 )
    68                 )
    94 
    69 
    95 
    70 
    96 if __name__ == '__main__':
    71 if __name__ == '__main__':
    97     if sys.version_info[0] == 2:
    72     # check_compat_py3 will import every filename we specify as long as it
    98         fn = check_compat_py2
    73     # starts with one of a few prefixes. It does this by converting
    99     else:
    74     # specified filenames like 'mercurial/foo.py' to 'mercurial.foo' and
   100         # check_compat_py3 will import every filename we specify as long as it
    75     # importing that. When running standalone (not as part of a test), this
   101         # starts with one of a few prefixes. It does this by converting
    76     # means we actually import the installed versions, not the files we just
   102         # specified filenames like 'mercurial/foo.py' to 'mercurial.foo' and
    77     # specified. When running as test-check-py3-compat.t, we technically
   103         # importing that. When running standalone (not as part of a test), this
    78     # would import the correct paths, but it's cleaner to have both cases
   104         # means we actually import the installed versions, not the files we just
    79     # use the same import logic.
   105         # specified. When running as test-check-py3-compat.t, we technically
    80     sys.path.insert(0, '.')
   106         # would import the correct paths, but it's cleaner to have both cases
       
   107         # use the same import logic.
       
   108         sys.path.insert(0, '.')
       
   109         fn = check_compat_py3
       
   110 
    81 
   111     for f in sys.argv[1:]:
    82     for f in sys.argv[1:]:
   112         with warnings.catch_warnings(record=True) as warns:
    83         with warnings.catch_warnings(record=True) as warns:
   113             fn(f)
    84             check_compat_py3(f)
   114 
    85 
   115         for w in warns:
    86         for w in warns:
   116             print(
    87             print(
   117                 warnings.formatwarning(
    88                 warnings.formatwarning(
   118                     w.message, w.category, w.filename, w.lineno
    89                     w.message, w.category, w.filename, w.lineno