You've already forked python-uncompyle6
mirror of
https://github.com/rocky/python-uncompyle6.git
synced 2025-08-04 01:09:52 +08:00
Fix "with as" indenting and decorated "async def"
Misc other improvements: make check-short now is short
This commit is contained in:
@@ -23,7 +23,7 @@ COVER_DIR=../tmp/grammar-cover
|
|||||||
# Run short tests
|
# Run short tests
|
||||||
check-short:
|
check-short:
|
||||||
@$(PYTHON) -V && PYTHON_VERSION=`$(PYTHON) -V 2>&1 | cut -d ' ' -f 2 | cut -d'.' -f1,2`; \
|
@$(PYTHON) -V && PYTHON_VERSION=`$(PYTHON) -V 2>&1 | cut -d ' ' -f 2 | cut -d'.' -f1,2`; \
|
||||||
$(MAKE) check-bytecode-short
|
$(MAKE) check-bytecode-$${PYTHON_VERSION}
|
||||||
|
|
||||||
# Run all tests
|
# Run all tests
|
||||||
check:
|
check:
|
||||||
|
BIN
test/bytecode_3.7/04_async.pyc
Normal file
BIN
test/bytecode_3.7/04_async.pyc
Normal file
Binary file not shown.
12
test/simple_source/bug37/04_async.py
Normal file
12
test/simple_source/bug37/04_async.py
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# from 3.7 test_contextlib_async.py
|
||||||
|
# Bugs were not adding "async" when a function is a decorator,
|
||||||
|
# and a misaligment when using "async with as".
|
||||||
|
@_async_test
|
||||||
|
async def test_enter(self):
|
||||||
|
self.assertIs(await manager.__aenter__(), manager)
|
||||||
|
|
||||||
|
async with manager as context:
|
||||||
|
async with woohoo() as x:
|
||||||
|
x = 1
|
||||||
|
y = 2
|
||||||
|
assert manager is context
|
@@ -165,6 +165,7 @@ case $PYVERSION in
|
|||||||
SKIP_TESTS=(
|
SKIP_TESTS=(
|
||||||
[test_atexit.py]=1 #
|
[test_atexit.py]=1 #
|
||||||
[test_decorators.py]=1 # Control flow wrt "if elif"
|
[test_decorators.py]=1 # Control flow wrt "if elif"
|
||||||
|
[test_dis.py]=1 # We change line numbers - duh!
|
||||||
)
|
)
|
||||||
if (( batch )) ; then
|
if (( batch )) ; then
|
||||||
# Fails in crontab environment?
|
# Fails in crontab environment?
|
||||||
@@ -178,16 +179,43 @@ case $PYVERSION in
|
|||||||
SKIP_TESTS=(
|
SKIP_TESTS=(
|
||||||
[test_contains.py]=1 # Code "while False: yield None" is optimized away in compilation
|
[test_contains.py]=1 # Code "while False: yield None" is optimized away in compilation
|
||||||
[test_decorators.py]=1 # Control flow wrt "if elif"
|
[test_decorators.py]=1 # Control flow wrt "if elif"
|
||||||
|
[test_dis.py]=1 # We change line numbers - duh!
|
||||||
[test_pow.py]=1 # Control flow wrt "continue"
|
[test_pow.py]=1 # Control flow wrt "continue"
|
||||||
[test_quopri.py]=1 # Only fails on POWER
|
[test_quopri.py]=1 # Only fails on POWER
|
||||||
)
|
)
|
||||||
;;
|
;;
|
||||||
3.7)
|
3.7)
|
||||||
SKIP_TESTS=(
|
SKIP_TESTS=(
|
||||||
[test_argparse.py]=1 #
|
|
||||||
[test_ast.py]=1 #
|
[test_ast.py]=1 #
|
||||||
|
[test_atexit.py]=1 #
|
||||||
|
[test_bdb.py]=1 #
|
||||||
|
[test_buffer.py]=1 #
|
||||||
|
[test_builtin.py]=1 #
|
||||||
|
[test_c_locale_coercion.py]=1 # Parse error
|
||||||
|
[test_cmdline.py]=1 # Interactive?
|
||||||
|
[test_codecs-3.7.py]=1
|
||||||
|
[test_collections.py]=1 # Investigate syntax error: self.assertEqual(p, Point(**))
|
||||||
|
[test_compare.py]=1
|
||||||
|
[test_compile.py]=1
|
||||||
|
[test_complex.py]=1 # Investigate: NameError: global name 'infj' is not defined
|
||||||
|
[test_contains.py]=1 # Code "while False: yield None" is optimized away in compilation
|
||||||
|
[test_contextlib_async.py]=1 # Investigate
|
||||||
|
[test_context.py]=1
|
||||||
|
[test_coroutines.py]=1 # Parse error
|
||||||
|
[test_curses.py]=1 # Parse error
|
||||||
|
[test_cmath.py]=1 # Syntax error - investigate
|
||||||
|
[test_decorators.py]=1 # Control flow wrt "if elif"
|
||||||
|
[test_dis.py]=1 # We change line numbers - duh!
|
||||||
|
# ...
|
||||||
|
)
|
||||||
|
3.8)
|
||||||
|
SKIP_TESTS=(
|
||||||
[test_contains.py]=1 # Code "while False: yield None" is optimized away in compilation
|
[test_contains.py]=1 # Code "while False: yield None" is optimized away in compilation
|
||||||
[test_decorators.py]=1 # Control flow wrt "if elif"
|
[test_decorators.py]=1 # Control flow wrt "if elif"
|
||||||
|
[test_dis.py]=1 # We change line numbers - duh!
|
||||||
|
[test_pow.py]=1 # Control flow wrt "continue"
|
||||||
|
[test_quopri.py]=1 # Only fails on POWER
|
||||||
|
# ...
|
||||||
)
|
)
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
|
@@ -316,10 +316,18 @@ TABLE_DIRECT = {
|
|||||||
'compare_chained1': ( '%[3]{pattr.replace("-", " ")} %p %p', (0, 19), (-2, 19)),
|
'compare_chained1': ( '%[3]{pattr.replace("-", " ")} %p %p', (0, 19), (-2, 19)),
|
||||||
'compare_chained2': ( '%[1]{pattr.replace("-", " ")} %p', (0, 19)),
|
'compare_chained2': ( '%[1]{pattr.replace("-", " ")} %p', (0, 19)),
|
||||||
# 'classdef': (), # handled by n_classdef()
|
# 'classdef': (), # handled by n_classdef()
|
||||||
|
|
||||||
|
# A custom rule in n_function def distinguishes whether to call this or
|
||||||
|
# function_def_async
|
||||||
'function_def': ( '\n\n%|def %c\n', -2), # -2 to handle closures
|
'function_def': ( '\n\n%|def %c\n', -2), # -2 to handle closures
|
||||||
|
|
||||||
'function_def_deco': ( '\n\n%c', 0),
|
'function_def_deco': ( '\n\n%c', 0),
|
||||||
'mkfuncdeco': ( '%|@%c\n%c', 0, 1),
|
'mkfuncdeco': ( '%|@%c\n%c', 0, 1),
|
||||||
|
|
||||||
|
# A custom rule in n_function def distinguishes whether to call this or
|
||||||
|
# function_def_async
|
||||||
'mkfuncdeco0': ( '%|def %c\n', 0),
|
'mkfuncdeco0': ( '%|def %c\n', 0),
|
||||||
|
|
||||||
'classdefdeco': ( '\n\n%c', 0),
|
'classdefdeco': ( '\n\n%c', 0),
|
||||||
'classdefdeco1': ( '%|@%c\n%c', 0, 1),
|
'classdefdeco1': ( '%|@%c\n%c', 0, 1),
|
||||||
'kwarg': ( '%[0]{pattr}=%c', 1), # Change when Python 2 does LOAD_STR
|
'kwarg': ( '%[0]{pattr}=%c', 1), # Change when Python 2 does LOAD_STR
|
||||||
|
@@ -49,7 +49,7 @@ def customize_for_version3(self, version):
|
|||||||
"raise_stmt2": ("%|raise %c from %c\n", 0, 1),
|
"raise_stmt2": ("%|raise %c from %c\n", 0, 1),
|
||||||
"store_locals": ("%|# inspect.currentframe().f_locals = __locals__\n",),
|
"store_locals": ("%|# inspect.currentframe().f_locals = __locals__\n",),
|
||||||
"withstmt": ("%|with %c:\n%+%c%-", 0, 3),
|
"withstmt": ("%|with %c:\n%+%c%-", 0, 3),
|
||||||
"withasstmt": ("%|with %c as (%c):\n%+%c%-", 0, 2, 3),
|
"withasstmt": ("%|with %c as %c:\n%+%c%-", 0, 2, 3),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@@ -17,44 +17,47 @@
|
|||||||
|
|
||||||
from xdis.code import iscode
|
from xdis.code import iscode
|
||||||
from xdis.util import COMPILER_FLAG_BIT
|
from xdis.util import COMPILER_FLAG_BIT
|
||||||
from uncompyle6.semantics.consts import (
|
from uncompyle6.semantics.consts import INDENT_PER_LEVEL, TABLE_DIRECT
|
||||||
INDENT_PER_LEVEL, TABLE_DIRECT)
|
from uncompyle6.semantics.helper import flatten_list, gen_function_parens_adjust
|
||||||
from uncompyle6.semantics.helper import (
|
|
||||||
flatten_list, gen_function_parens_adjust)
|
|
||||||
|
|
||||||
#######################
|
#######################
|
||||||
# Python 3.5+ Changes #
|
# Python 3.5+ Changes #
|
||||||
#######################
|
#######################
|
||||||
def customize_for_version35(self, version):
|
def customize_for_version35(self, version):
|
||||||
TABLE_DIRECT.update({
|
TABLE_DIRECT.update(
|
||||||
'await_expr': ( 'await %c', 0),
|
{
|
||||||
'await_stmt': ( '%|%c\n', 0),
|
"await_expr": ("await %c", 0),
|
||||||
'async_for_stmt': (
|
"await_stmt": ("%|%c\n", 0),
|
||||||
'%|async for %c in %c:\n%+%|%c%-\n\n', 9, 1, 25 ),
|
"async_for_stmt": ("%|async for %c in %c:\n%+%|%c%-\n\n", 9, 1, 25),
|
||||||
'async_forelse_stmt': (
|
"async_forelse_stmt": (
|
||||||
'%|async for %c in %c:\n%+%c%-%|else:\n%+%c%-\n\n',
|
"%|async for %c in %c:\n%+%c%-%|else:\n%+%c%-\n\n",
|
||||||
9, 1, 25, (27, 'else_suite') ),
|
9,
|
||||||
'async_with_stmt': (
|
1,
|
||||||
'%|async with %c:\n%+%|%c%-',
|
25,
|
||||||
(0, 'expr'), 7 ),
|
(27, "else_suite"),
|
||||||
'async_with_as_stmt': (
|
),
|
||||||
'%|async with %c as %c:\n%+%|%c%-',
|
"async_with_stmt": ("%|async with %c:\n%+%c%-", (0, "expr"), 7),
|
||||||
(0, 'expr'), (6, 'store'), 7),
|
"async_with_as_stmt": (
|
||||||
'unmap_dict': ( '{**%C}', (0, -1, ', **') ),
|
"%|async with %c as %c:\n%+%c%-",
|
||||||
# 'unmapexpr': ( '{**%c}', 0), # done by n_unmapexpr
|
(0, "expr"),
|
||||||
|
(6, "store"),
|
||||||
})
|
7,
|
||||||
|
),
|
||||||
|
"unmap_dict": ("{**%C}", (0, -1, ", **")),
|
||||||
|
# "unmapexpr": ( "{**%c}", 0), # done by n_unmapexpr
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
def async_call(node):
|
def async_call(node):
|
||||||
self.f.write('async ')
|
self.f.write("async ")
|
||||||
node.kind == 'call'
|
node.kind == "call"
|
||||||
p = self.prec
|
p = self.prec
|
||||||
self.prec = 80
|
self.prec = 80
|
||||||
self.template_engine(('%c(%P)', 0, (1, -4, ', ',
|
self.template_engine(("%c(%P)", 0, (1, -4, ", ", 100)), node)
|
||||||
100)), node)
|
|
||||||
self.prec = p
|
self.prec = p
|
||||||
node.kind == 'async_call'
|
node.kind == "async_call"
|
||||||
self.prune()
|
self.prune()
|
||||||
|
|
||||||
self.n_async_call = async_call
|
self.n_async_call = async_call
|
||||||
|
|
||||||
def n_build_list_unpack(node):
|
def n_build_list_unpack(node):
|
||||||
@@ -90,7 +93,9 @@ def customize_for_version35(self, version):
|
|||||||
if value.startswith("("):
|
if value.startswith("("):
|
||||||
assert value.endswith(")")
|
assert value.endswith(")")
|
||||||
use_star = False
|
use_star = False
|
||||||
value = value[1:-1].rstrip(" ") # Remove starting '(' and trailing ')' and additional spaces
|
value = value[1:-1].rstrip(
|
||||||
|
" "
|
||||||
|
) # Remove starting "(" and trailing ")" and additional spaces
|
||||||
if value == "":
|
if value == "":
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
@@ -114,6 +119,7 @@ def customize_for_version35(self, version):
|
|||||||
self.prec = p
|
self.prec = p
|
||||||
self.prune()
|
self.prune()
|
||||||
return
|
return
|
||||||
|
|
||||||
self.n_build_list_unpack = n_build_list_unpack
|
self.n_build_list_unpack = n_build_list_unpack
|
||||||
|
|
||||||
def n_call(node):
|
def n_call(node):
|
||||||
@@ -123,7 +129,7 @@ def customize_for_version35(self, version):
|
|||||||
for i in mapping[1:]:
|
for i in mapping[1:]:
|
||||||
key = key[i]
|
key = key[i]
|
||||||
pass
|
pass
|
||||||
if key.kind.startswith('CALL_FUNCTION_VAR_KW'):
|
if key.kind.startswith("CALL_FUNCTION_VAR_KW"):
|
||||||
# Python 3.5 changes the stack position of
|
# Python 3.5 changes the stack position of
|
||||||
# *args: kwargs come after *args whereas
|
# *args: kwargs come after *args whereas
|
||||||
# in earlier Pythons, *args is at the end
|
# in earlier Pythons, *args is at the end
|
||||||
@@ -137,12 +143,12 @@ def customize_for_version35(self, version):
|
|||||||
kwarg_pos = entry[2][1]
|
kwarg_pos = entry[2][1]
|
||||||
args_pos = kwarg_pos - 1
|
args_pos = kwarg_pos - 1
|
||||||
# Put last node[args_pos] after subsequent kwargs
|
# Put last node[args_pos] after subsequent kwargs
|
||||||
while node[kwarg_pos] == 'kwarg' and kwarg_pos < len(node):
|
while node[kwarg_pos] == "kwarg" and kwarg_pos < len(node):
|
||||||
# swap node[args_pos] with node[kwargs_pos]
|
# swap node[args_pos] with node[kwargs_pos]
|
||||||
node[kwarg_pos], node[args_pos] = node[args_pos], node[kwarg_pos]
|
node[kwarg_pos], node[args_pos] = node[args_pos], node[kwarg_pos]
|
||||||
args_pos = kwarg_pos
|
args_pos = kwarg_pos
|
||||||
kwarg_pos += 1
|
kwarg_pos += 1
|
||||||
elif key.kind.startswith('CALL_FUNCTION_VAR'):
|
elif key.kind.startswith("CALL_FUNCTION_VAR"):
|
||||||
# CALL_FUNCTION_VAR's top element of the stack contains
|
# CALL_FUNCTION_VAR's top element of the stack contains
|
||||||
# the variable argument list, then comes
|
# the variable argument list, then comes
|
||||||
# annotation args, then keyword args.
|
# annotation args, then keyword args.
|
||||||
@@ -153,65 +159,79 @@ def customize_for_version35(self, version):
|
|||||||
kwargs = (argc >> 8) & 0xFF
|
kwargs = (argc >> 8) & 0xFF
|
||||||
# FIXME: handle annotation args
|
# FIXME: handle annotation args
|
||||||
if nargs > 0:
|
if nargs > 0:
|
||||||
template = ('%c(%C, ', 0, (1, nargs+1, ', '))
|
template = ("%c(%C, ", 0, (1, nargs + 1, ", "))
|
||||||
else:
|
else:
|
||||||
template = ('%c(', 0)
|
template = ("%c(", 0)
|
||||||
self.template_engine(template, node)
|
self.template_engine(template, node)
|
||||||
|
|
||||||
args_node = node[-2]
|
args_node = node[-2]
|
||||||
if args_node in ('pos_arg', 'expr'):
|
if args_node in ("pos_arg", "expr"):
|
||||||
args_node = args_node[0]
|
args_node = args_node[0]
|
||||||
if args_node == 'build_list_unpack':
|
if args_node == "build_list_unpack":
|
||||||
template = ('*%P)', (0, len(args_node)-1, ', *', 100))
|
template = ("*%P)", (0, len(args_node) - 1, ", *", 100))
|
||||||
self.template_engine(template, args_node)
|
self.template_engine(template, args_node)
|
||||||
else:
|
else:
|
||||||
if len(node) - nargs > 3:
|
if len(node) - nargs > 3:
|
||||||
template = ('*%c, %C)', nargs+1, (nargs+kwargs+1, -1, ', '))
|
template = ("*%c, %C)", nargs + 1, (nargs + kwargs + 1, -1, ", "))
|
||||||
else:
|
else:
|
||||||
template = ('*%c)', nargs+1)
|
template = ("*%c)", nargs + 1)
|
||||||
self.template_engine(template, node)
|
self.template_engine(template, node)
|
||||||
self.prune()
|
self.prune()
|
||||||
else:
|
else:
|
||||||
gen_function_parens_adjust(key, node)
|
gen_function_parens_adjust(key, node)
|
||||||
|
|
||||||
self.default(node)
|
self.default(node)
|
||||||
|
|
||||||
self.n_call = n_call
|
self.n_call = n_call
|
||||||
|
|
||||||
def n_function_def(node):
|
def is_async_fn(node):
|
||||||
n0 = node[0]
|
code_node = node[0][0]
|
||||||
is_code = False
|
for n in node[0]:
|
||||||
for i in list(range(len(n0)-2, -1, -1)):
|
if hasattr(n, "attr") and iscode(n.attr):
|
||||||
code_node = n0[i]
|
code_node = n
|
||||||
if hasattr(code_node, 'attr') and iscode(code_node.attr):
|
|
||||||
is_code = True
|
|
||||||
break
|
break
|
||||||
|
pass
|
||||||
|
pass
|
||||||
|
|
||||||
if is_code and (
|
is_code = hasattr(code_node, "attr") and iscode(code_node.attr)
|
||||||
|
return is_code and (
|
||||||
code_node.attr.co_flags
|
code_node.attr.co_flags
|
||||||
& (
|
& (
|
||||||
COMPILER_FLAG_BIT["COROUTINE"]
|
COMPILER_FLAG_BIT["COROUTINE"]
|
||||||
| COMPILER_FLAG_BIT["ITERABLE_COROUTINE"]
|
| COMPILER_FLAG_BIT["ITERABLE_COROUTINE"]
|
||||||
| COMPILER_FLAG_BIT["ASYNC_GENERATOR"]
|
| COMPILER_FLAG_BIT["ASYNC_GENERATOR"]
|
||||||
)
|
)
|
||||||
):
|
)
|
||||||
self.template_engine(('\n\n%|async def %c\n',
|
|
||||||
-2), node)
|
def n_function_def(node):
|
||||||
|
if is_async_fn(node):
|
||||||
|
self.template_engine(("\n\n%|async def %c\n", -2), node)
|
||||||
else:
|
else:
|
||||||
self.template_engine(('\n\n%|def %c\n', -2),
|
self.default(node)
|
||||||
node)
|
|
||||||
self.prune()
|
self.prune()
|
||||||
|
|
||||||
self.n_function_def = n_function_def
|
self.n_function_def = n_function_def
|
||||||
|
|
||||||
|
def n_mkfuncdeco0(node):
|
||||||
|
if is_async_fn(node):
|
||||||
|
self.template_engine(("%|async def %c\n", 0), node)
|
||||||
|
else:
|
||||||
|
self.default(node)
|
||||||
|
self.prune()
|
||||||
|
|
||||||
|
self.n_mkfuncdeco0 = n_mkfuncdeco0
|
||||||
|
|
||||||
def unmapexpr(node):
|
def unmapexpr(node):
|
||||||
last_n = node[0][-1]
|
last_n = node[0][-1]
|
||||||
for n in node[0]:
|
for n in node[0]:
|
||||||
self.preorder(n)
|
self.preorder(n)
|
||||||
if n != last_n:
|
if n != last_n:
|
||||||
self.f.write(', **')
|
self.f.write(", **")
|
||||||
pass
|
pass
|
||||||
pass
|
pass
|
||||||
self.prune()
|
self.prune()
|
||||||
pass
|
pass
|
||||||
|
|
||||||
self.n_unmapexpr = unmapexpr
|
self.n_unmapexpr = unmapexpr
|
||||||
|
|
||||||
# FIXME: start here
|
# FIXME: start here
|
||||||
@@ -228,67 +248,75 @@ def customize_for_version35(self, version):
|
|||||||
# then the first * has already been printed.
|
# then the first * has already been printed.
|
||||||
# Until I have a better way to check for CALL_FUNCTION_VAR,
|
# Until I have a better way to check for CALL_FUNCTION_VAR,
|
||||||
# will assume that if the text ends in *.
|
# will assume that if the text ends in *.
|
||||||
last_was_star = self.f.getvalue().endswith('*')
|
last_was_star = self.f.getvalue().endswith("*")
|
||||||
|
|
||||||
if lastnodetype.startswith('BUILD_LIST'):
|
if lastnodetype.startswith("BUILD_LIST"):
|
||||||
self.write('['); endchar = ']'
|
self.write("[")
|
||||||
elif lastnodetype.startswith('BUILD_TUPLE'):
|
endchar = "]"
|
||||||
|
elif lastnodetype.startswith("BUILD_TUPLE"):
|
||||||
# Tuples can appear places that can NOT
|
# Tuples can appear places that can NOT
|
||||||
# have parenthesis around them, like array
|
# have parenthesis around them, like array
|
||||||
# subscripts. We check for that by seeing
|
# subscripts. We check for that by seeing
|
||||||
# if a tuple item is some sort of slice.
|
# if a tuple item is some sort of slice.
|
||||||
no_parens = False
|
no_parens = False
|
||||||
for n in node:
|
for n in node:
|
||||||
if n == 'expr' and n[0].kind.startswith('build_slice'):
|
if n == "expr" and n[0].kind.startswith("build_slice"):
|
||||||
no_parens = True
|
no_parens = True
|
||||||
break
|
break
|
||||||
pass
|
pass
|
||||||
if no_parens:
|
if no_parens:
|
||||||
endchar = ''
|
endchar = ""
|
||||||
else:
|
else:
|
||||||
self.write('('); endchar = ')'
|
self.write("(")
|
||||||
|
endchar = ")"
|
||||||
pass
|
pass
|
||||||
|
|
||||||
elif lastnodetype.startswith('BUILD_SET'):
|
elif lastnodetype.startswith("BUILD_SET"):
|
||||||
self.write('{'); endchar = '}'
|
self.write("{")
|
||||||
elif lastnodetype.startswith('BUILD_MAP_UNPACK'):
|
endchar = "}"
|
||||||
self.write('{*'); endchar = '}'
|
elif lastnodetype.startswith("BUILD_MAP_UNPACK"):
|
||||||
elif lastnodetype.startswith('ROT_TWO'):
|
self.write("{*")
|
||||||
self.write('('); endchar = ')'
|
endchar = "}"
|
||||||
|
elif lastnodetype.startswith("ROT_TWO"):
|
||||||
|
self.write("(")
|
||||||
|
endchar = ")"
|
||||||
else:
|
else:
|
||||||
raise TypeError('Internal Error: n_build_list expects list, tuple, set, or unpack')
|
raise TypeError(
|
||||||
|
"Internal Error: n_build_list expects list, tuple, set, or unpack"
|
||||||
|
)
|
||||||
|
|
||||||
flat_elems = flatten_list(node)
|
flat_elems = flatten_list(node)
|
||||||
|
|
||||||
self.indent_more(INDENT_PER_LEVEL)
|
self.indent_more(INDENT_PER_LEVEL)
|
||||||
sep = ''
|
sep = ""
|
||||||
for elem in flat_elems:
|
for elem in flat_elems:
|
||||||
if elem in ('ROT_THREE', 'EXTENDED_ARG'):
|
if elem in ("ROT_THREE", "EXTENDED_ARG"):
|
||||||
continue
|
continue
|
||||||
assert elem == 'expr'
|
assert elem == "expr"
|
||||||
line_number = self.line_number
|
line_number = self.line_number
|
||||||
value = self.traverse(elem)
|
value = self.traverse(elem)
|
||||||
if elem[0] == 'tuple':
|
if elem[0] == "tuple":
|
||||||
assert value[0] == '('
|
assert value[0] == "("
|
||||||
assert value[-1] == ')'
|
assert value[-1] == ")"
|
||||||
value = value[1:-1]
|
value = value[1:-1]
|
||||||
if value[-1] == ',':
|
if value[-1] == ",":
|
||||||
# singleton tuple
|
# singleton tuple
|
||||||
value = value[:-1]
|
value = value[:-1]
|
||||||
else:
|
else:
|
||||||
value = '*' + value
|
value = "*" + value
|
||||||
if line_number != self.line_number:
|
if line_number != self.line_number:
|
||||||
sep += '\n' + self.indent + INDENT_PER_LEVEL[:-1]
|
sep += "\n" + self.indent + INDENT_PER_LEVEL[:-1]
|
||||||
else:
|
else:
|
||||||
if sep != '': sep += ' '
|
if sep != "":
|
||||||
|
sep += " "
|
||||||
if not last_was_star:
|
if not last_was_star:
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
last_was_star = False
|
last_was_star = False
|
||||||
self.write(sep, value)
|
self.write(sep, value)
|
||||||
sep = ','
|
sep = ","
|
||||||
if lastnode.attr == 1 and lastnodetype.startswith('BUILD_TUPLE'):
|
if lastnode.attr == 1 and lastnodetype.startswith("BUILD_TUPLE"):
|
||||||
self.write(',')
|
self.write(",")
|
||||||
self.write(endchar)
|
self.write(endchar)
|
||||||
self.indent_less(INDENT_PER_LEVEL)
|
self.indent_less(INDENT_PER_LEVEL)
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user