Remove type hints in Python source programmatically

后端 未结 3 739
孤城傲影
孤城傲影 2020-12-29 07:21

I have some source code written for Python 3.5 that I want to make executable under Python 3.4. The only feature from 3.5 that I use which is not available in 3.4 are type h

3条回答
  •  伪装坚强ぢ
    2020-12-29 08:19

    You can subclass lib2to3.refactor.RefactoringTool to refactor the code using a fixer that is a subclass of lib2to3.fixer_base.BaseFix with a pattern that looks for either a typed argument, a function declaration with an annotated returning value, or a simple statement that imports or imports from typing, and a transform method that removes the indices of the annotations from the child nodes or replaces the statement node with an empty node:

    from lib2to3 import fixer_base, refactor, fixer_util
    
    class FixParameterAnnotations(fixer_base.BaseFix):
        PATTERN = r'''
            name=tname
            |
            func=funcdef< any+ '->' any+ >
            |
            simple_stmt<
                (
                    import_name< 'import' 'typing' >
                    |
                    import_from< 'from' 'typing' 'import' any+ >
                ) '\n'
            >
        '''
    
        def transform(self, node, results):
            if 'name' in results:
                del node.children[1:] # delete annotation to typed argument
            elif 'func' in results:
                del node.children[-4:-2] # delete annotation to function declaration
            else:
                return fixer_util.BlankLine() # delete statement that imports typing
            return node
    
    class Refactor(refactor.RefactoringTool):
        def __init__(self, fixers):
            self._fixers= [cls(None, None) for cls in fixers]
            super().__init__(None, {'print_function': True})
    
        def get_fixers(self):
            return self._fixers, []
    

    so that:

    source = """
    import typing
    from typing import Dict, T, Callable
    from typing import List
    
    def foo(bar: Dict[T, List[T]],
            baz: Callable[[T], int] = lambda x: (x+3)/7,
            **kwargs) -> List[T]:
        print(line, end="")    # comments and white spaces are preserved
    """
    print(Refactor([FixParameterAnnotations]).refactor_string(source, ''))
    

    outputs:

    def foo(bar,
            baz = lambda x: (x+3)/7,
            **kwargs):
        print(line, end="")    # comments and white spaces are preserved
    

    Demo: https://repl.it/@blhsing/BurlywoodFeistyTrials

    As a bonus, lib2to3 also preserves all comments and white spaces after the transformation. You can find the definition of the Python grammar in Grammar.txt of the lib2to3 module.

提交回复
热议问题