示例#1
0
def test_match_unparse():
    if sys.version_info < (3, 10):
        pytest.skip('Match statement not in python < 3.10')

    source = '''
match a:
    case (0 as a) as b: pass

match a:
    case _:pass
    
match a:
    case 0|(0|0): pass
    case (0|0)|0: pass    
    case 0|0|0: pass

match (lambda: a)():
    case [action, obj]:pass

match a:= h:
    case [action, obj]:pass
    case {**rest}: pass   
    '''

    expected_ast = ast.parse(source)
    actual_ast = unparse(expected_ast)
    compare_ast(expected_ast, ast.parse(actual_ast))
def test_remove():
    if sys.version_info < (3, 6):
        pytest.skip('annotations unavailable in python < 3.6')

    source = '''
class Dummy(NermedTupel):
    myfield: int
    mysecondfile: str

class Dummy(typing.NermedTupel):
    myfield: int
    mysecondfile: str
'''
    expected = '''
class Dummy(NermedTupel):
    myfield: 0
    mysecondfile: 0

class Dummy(typing.NermedTupel):
    myfield: 0
    mysecondfile: 0
'''
    expected_ast = ast.parse(expected)
    actual_ast = remove_annotations(source)
    compare_ast(expected_ast, actual_ast)
示例#3
0
 def is_correct_ast(self, code):
     try:
         c = ast.parse(code, 'FString candidate', mode='eval')
         compare_ast(self.node, c.body)
         return True
     except Exception as e:
         return False
示例#4
0
def test_pep():
    if sys.version_info < (3, 8):
        pytest.skip('No Assignment expressions in python < 3.8')

    source = '''
def name(p1, p2, /, p_or_kw, *, kw): pass
def name(p1, p2=None, /, p_or_kw=None, *, kw): pass
def name(p1, p2=None, /, *, kw): pass
def name(p1, p2=None, /): pass
def name(p1, p2, /, p_or_kw): pass
def name(p1, p2, /): pass
def name(p_or_kw, *, kw): pass
def name(*, kw): pass

def standard_arg(arg):
    print(arg)
def pos_only_arg(arg, /):
    print(arg)
def kwd_only_arg(*, arg):
    print(arg)
def combined_example(pos_only, /, standard, *, kwd_only):
    print(pos_only, standard, kwd_only)
'''

    expected_ast = ast.parse(source)
    actual_ast = unparse(expected_ast)
    compare_ast(expected_ast, ast.parse(actual_ast))
示例#5
0
def test_hoist_from_setcomp():
    if sys.version_info < (2, 7):
        pytest.skip('No SetComp in python < 2.7')

    source = '''
class a:
    def a():
        for i in {a for a in 'Hello' + 'Hello' + 'World'}:
            pass
        return 'World'    
    def c():
        return 'World'
'''

    expected = '''
A = 'World'
class a:
    def a():
        B = 'Hello'
        for i in {a for a in B + B + A}:
            pass  
        return A
    def c():
        return A
'''

    expected_ast = ast.parse(expected)
    actual_ast = hoist(source)
    compare_ast(expected_ast, actual_ast)
def test_remove_literal_num():
    source = '213'
    expected = ''

    expected_ast = ast.parse(expected)
    actual_ast = remove_literals(source)
    compare_ast(expected_ast, actual_ast)
示例#7
0
def unparse(module):
    """
    Turn a module AST into python code

    This returns an exact representation of the given module,
    such that it can be parsed back into the same AST.

    :param module: The module to turn into python code
    :type: module: :class:`ast.Module`
    :rtype: str

    """

    assert isinstance(module, ast.Module)

    printer = ModulePrinter()
    printer(module)

    try:
        minified_module = ast.parse(printer.code,
                                    'python_minifier.unparse output')
    except SyntaxError as syntax_error:
        raise UnstableMinification(syntax_error, '', printer.code)

    try:
        compare_ast(module, minified_module)
    except CompareError as compare_error:
        raise UnstableMinification(compare_error, '', printer.code)

    return printer.code
示例#8
0
def test_remove_pass_empty_module():
    source = 'pass'
    expected = ''

    expected_ast = ast.parse(expected)
    actual_ast = remove_literals(source)
    compare_ast(expected_ast, actual_ast)
def test_complex():
    source = '''
"module docstring"
a = 'hello'

def t():
    "function docstring"
    a = 2
    0
    2
    'sadfsaf'
    def g():
        "just a docstring"

'''
    expected = '''
a = 'hello'
def t():
    a=2
    def g():
        0
'''

    expected_ast = ast.parse(expected)
    actual_ast = remove_literals(source)
    compare_ast(expected_ast, actual_ast)
示例#10
0
def test_remove_if_line():
    source = '''if True: pass'''
    expected = '''if True: 0'''

    expected_ast = ast.parse(expected)
    actual_ast = remove_literals(source)
    compare_ast(expected_ast, actual_ast)
示例#11
0
def test_hoist_multiple_small():
    source = '''
A = '.'
B = '.'
C = '.'
D = '.'
E = '.'
F = '.'
G = '.'
'''

    expected = '''
H = '.'
A = H
B = H
C = H
D = H
E = H
F = H
G = H
'''

    expected_ast = ast.parse(expected)
    actual_ast = hoist(source)
    compare_ast(expected_ast, actual_ast)
def test_remove_literal_str():
    source = '"hello"'
    expected = ''

    expected_ast = ast.parse(expected)
    actual_ast = remove_literals(source)
    compare_ast(expected_ast, actual_ast)
示例#13
0
def test_hoist_from_listcomp():
    source = '''
class a:
    def a():
        for i in [a for a in 'Hello']:
            pass
        for i in [a for a in 'World']:
            pass            
        return 'World'
    def c():
        return 'Hello'
'''

    expected = '''
A = 'Hello'
class a:
    def a():
        B = 'World'
        for i in [a for a in A]:
            pass
        for i in [a for a in B]:
            pass            
        return B
    def c():
        return A
'''

    expected_ast = ast.parse(expected)
    actual_ast = hoist(source)
    compare_ast(expected_ast, actual_ast)
示例#14
0
def test_hoist_from_generator():
    source = '''
class a:
    def a():
        for i in (a for a in 'Hello'):
            pass
        for i in (a for a in 'World'):
            pass            
        return 'World'
    def c():
        return 'Hello'
'''

    expected = '''
A = 'Hello'
class a:
    def a():
        B = 'World'
        for i in (a for a in A):
            pass
        for i in (a for a in B):
            pass            
        return B
    def c():
        return A
'''

    expected_ast = ast.parse(expected)
    actual_ast = hoist(source)
    compare_ast(expected_ast, actual_ast)
def test_import():
    source = '''import builtins
import collections'''
    expected = 'import builtins, collections'

    expected_ast = ast.parse(expected)
    actual_ast = combine_imports(ast.parse(source))
    compare_ast(expected_ast, actual_ast)
示例#16
0
def test_remove_from_class_empty():
    source = '''class A:
    pass
'''
    expected = 'class A:0'

    expected_ast = ast.parse(expected)
    actual_ast = remove_literals(source)
    compare_ast(expected_ast, actual_ast)
def test_pep():
    if sys.version_info < (3, 9):
        pytest.skip('Decorator expression not allowed in python <3.9')

    source = """
buttons = [QPushButton(f'Button {i}') for i in range(10)]

# Do stuff with the list of buttons...

@buttons[0].clicked.connect
def spam():
    ...

@buttons[1].clicked.connect
def eggs():
    ...

# Do stuff with the list of buttons...
@(f, g)
def a(): pass

@(f, g)
class A:pass

@lambda func: (lambda *p: func(*p).u())
def g(n): pass

@s := lambda func: (lambda *p: func(*p).u())
def g(name): pass

@s
def r(n, t):
    pass

@lambda f: lambda *p: f or f(*p).u()
def g(name): pass

@lambda f: lambda *p: \
        [_ for _ in [ \
            f(*p),
            ] if _][0]
def c(): pass

@lambda f: lambda *p: \
            list(filter(lambda _: _,[
                (a := t()) and False,
                f(*p),
                (b := t()) and False,
            ]))[0]
def c(): pass

"""

    expected_ast = ast.parse(source)
    actual_ast = unparse(expected_ast)
    compare_ast(expected_ast, ast.parse(actual_ast))
def test_AnnAssign_novalue():
    if sys.version_info < (3, 6):
        pytest.skip('Variable annotation unsupported in python < 3.6')

    source = '''a :str
'''
    expected = '''a:0'''

    expected_ast = ast.parse(expected)
    actual_ast = remove_annotations(source)
    compare_ast(expected_ast, actual_ast)
示例#19
0
def test_remove_pass_module():
    source = '''import collections
pass
a = 1
pass'''
    expected = '''import collections
a=1'''

    expected_ast = ast.parse(expected)
    actual_ast = remove_literals(source)
    compare_ast(expected_ast, actual_ast)
示例#20
0
def test_nohoist_single_usage():
    source = '''
a = 'Hello'
'''

    expected = '''
a = 'Hello'
'''

    expected_ast = ast.parse(expected)
    actual_ast = hoist(source)
    compare_ast(expected_ast, actual_ast)
def test_import_from():
    source = '''from builtins import dir
from builtins import help
import collections
from collections import abc'''
    expected = '''from builtins import dir, help 
import collections
from collections import abc'''

    expected_ast = ast.parse(expected)
    actual_ast = combine_imports(ast.parse(source))
    compare_ast(expected_ast, actual_ast)
def test_AsyncFunctionDef():
    if sys.version_info < (3, 6):
        pytest.skip('Async function unsupported in python < 3.5')

    source = '''async def test(a: str, b: int=1, *c: hello, **aws: crap) -> None:
    pass'''
    expected = '''async def test(a, b=1, *c, **aws):
    pass'''

    expected_ast = ast.parse(expected)
    actual_ast = remove_annotations(source)
    compare_ast(expected_ast, actual_ast)
示例#23
0
def test_await_fstring():
    if sys.version_info < (3, 7):
        pytest.skip(
            'Await in f-string expressions not allowed in python < 3.7')

    source = '''
async def a(): return 'hello'
async def b(): return f'{await b()}'
'''

    expected_ast = ast.parse(source)
    actual_ast = unparse(expected_ast)
    compare_ast(expected_ast, ast.parse(actual_ast))
示例#24
0
def test_remove_suite():
    source = '''if True: 
    pass
    a=1 
    pass 
    return None'''
    expected = '''if True:
    a=1 
    return None'''

    expected_ast = ast.parse(expected)
    actual_ast = remove_literals(source)
    compare_ast(expected_ast, actual_ast)
def test_import_as():
    source = '''import builtins
import collections as c
import functools as f
import datetime

pass'''
    expected = '''import builtins, collections as c, functools as f, datetime
pass'''

    expected_ast = ast.parse(expected)
    actual_ast = combine_imports(ast.parse(source))
    compare_ast(expected_ast, actual_ast)
def test_fstring_empty_str():
    if sys.version_info < (3, 6):
        pytest.skip('f-string expressions not allowed in python < 3.6')

    source = r'''
f"""\
{fg_br}"""
'''

    print(source)
    expected_ast = ast.parse(source)
    actual_ast = unparse(expected_ast)
    compare_ast(expected_ast, ast.parse(actual_ast))
示例#27
0
def test_no_hoist_multiple_small():
    source = '''
A = ''
B = ''
'''

    expected = '''
A = ''
B = ''
'''

    expected_ast = ast.parse(expected)
    actual_ast = hoist(source)
    compare_ast(expected_ast, actual_ast)
def test_import_in_function():
    source = '''def test():
    import collection as c
    import builtins
    
    return None
'''
    expected = '''def test():
    import collection as c, builtins
    return None
'''

    expected_ast = ast.parse(expected)
    actual_ast = combine_imports(ast.parse(source))
    compare_ast(expected_ast, actual_ast)
示例#29
0
def test_hoist_multiple_usage():
    source = '''
A = 'Hello'
B = 'Hello'
'''

    expected = '''
C = 'Hello'
A = C
B = C
'''

    expected_ast = ast.parse(expected)
    actual_ast = hoist(source)
    compare_ast(expected_ast, actual_ast)
def test_dict_expanson():
    if sys.version_info < (3, 5):
        pytest.skip('dict expansion not allowed in python < 3.5')

    source = [
        r'{**a>>9}', r'{**(a or b)}', r'{**(a and b)}', r'{**a+b}',
        r'{**(lambda a:a)}', r'{**(a<b)}', r'{**(yield a())}',
        r'{**(a if a else a)}'
    ]

    for expression in source:
        expected_ast = ast.parse(expression)
        minified = unparse(expected_ast)
        compare_ast(expected_ast, ast.parse(minified))
        assert expression == minified