Merge branch 'master' into python-2.4

This commit is contained in:
rocky
2020-05-18 23:25:53 -04:00
34 changed files with 836 additions and 426 deletions

12
.github/FUNDING.yml vendored Normal file
View File

@@ -0,0 +1,12 @@
# These are supported funding model platforms
github: [rocky]
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']

1
.gitignore vendored
View File

@@ -10,6 +10,7 @@
/.pytest_cache
/.python-version
/.tox
.mypy_cache
/.venv*
/README
/__pkginfo__.pyc

View File

@@ -21,6 +21,17 @@
# less elegant than having it here with reduced code, albeit there
# still is some room for improvement.
# Python-version | package | last-version |
# -----------------------------------------
# 2.5 | pip | 1.1 |
# 2.6 | pip | 1.5.6 |
# 2.7 | pip | 19.2.3 |
# 2.7 | pip | 1.2.1 |
# 3.1 | pip | 1.5.6 |
# 3.2 | pip | 7.1.2 |
# 3.3 | pip | 10.0.1 |
# 3.4 | pip | 19.1.1 |
# Things that change more often go here.
copyright = """
Copyright (C) 2015-2020 Rocky Bernstein <rb@dustyfeet.com>.
@@ -58,7 +69,7 @@ entry_points = {
]}
ftp_url = None
install_requires = ["spark-parser >= 1.8.9, < 1.9.0",
"xdis >= 4.5.1, < 4.6.0"]
"xdis >= 4.6.0, < 4.7.0"]
license = "GPL3"
mailing_list = "python-debugger@googlegroups.com"

View File

@@ -5,4 +5,4 @@ if [[ $0 == ${BASH_SOURCE[0]} ]] ; then
echo "This script should be *sourced* rather than run directly through bash"
exit 1
fi
export PYVERSIONS='3.5.9 3.6.10 2.6.9 3.3.7 2.7.18 3.2.6 3.1.5 3.4.10 3.7.7 3.8.2'
export PYVERSIONS='3.5.9 3.6.10 2.6.9 3.3.7 2.7.18 3.2.6 3.1.5 3.4.10 3.7.7 3.8.3'

View File

@@ -12,8 +12,7 @@ import functools
from uncompyle6 import PYTHON_VERSION, PYTHON3, IS_PYPY, code_deparse
# TODO : I think we can get xdis to support the dis api (python 3 version) by doing something like this there
from xdis.bytecode import Bytecode
from xdis.main import get_opcode
from xdis import Bytecode, get_opcode
opc = get_opcode(PYTHON_VERSION, IS_PYPY)
Bytecode = functools.partial(Bytecode, opc=opc)

View File

@@ -15,29 +15,40 @@ if not ((2, 4) <= SYS_VERSION <= (2, 7)):
print(mess)
raise Exception(mess)
from __pkginfo__ import \
author, author_email, install_requires, \
license, long_description, classifiers, \
entry_points, modname, py_modules, \
short_desc, VERSION, web, \
zip_safe
from __pkginfo__ import (
author,
author_email,
install_requires,
license,
long_description,
classifiers,
entry_points,
modname,
py_modules,
short_desc,
VERSION,
web,
zip_safe,
)
from setuptools import setup, find_packages
setup(
author = author,
author_email = author_email,
classifiers = classifiers,
description = short_desc,
entry_points = entry_points,
install_requires = install_requires,
license = license,
long_description = long_description,
long_description_content_type = "text/x-rst",
name = modname,
packages = find_packages(),
py_modules = py_modules,
test_suite = 'nose.collector',
url = web,
tests_require = ['nose>=1.0'],
version = VERSION,
zip_safe = zip_safe)
author=author,
author_email=author_email,
classifiers=classifiers,
description=short_desc,
entry_points=entry_points,
install_requires=install_requires,
license=license,
long_description=long_description,
long_description_content_type="text/x-rst",
name=modname,
packages=find_packages(),
py_modules=py_modules,
test_suite="nose.collector",
url=web,
tests_require=["nose>=1.0"],
version=VERSION,
zip_safe=zip_safe,
)

5
test/.gitignore vendored
View File

@@ -1,3 +1,8 @@
/.coverage
/.python-version
/nohup.out
/pycdc
/test_pycdc_tests.sh
/test_uncompyle2.py
/test_unpy33.py
/test_unpy37.py

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1,23 +0,0 @@
# 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
# From 3.7.6 test_coroutines.py
# Bug was different form of code for "async with" below
class CoroutineTest():
def test_with_8(self):
CNT = 0
async def foo():
nonlocal CNT
async with CM():
CNT += 1
return

View File

@@ -0,0 +1,70 @@
# 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".
"""This program is self-checking!"""
import asyncio
from contextlib import asynccontextmanager, AbstractAsyncContextManager
import functools
def _async_test(func):
"""Decorator to turn an async function into a test case."""
@functools.wraps(func)
def wrapper(*args, **kwargs):
coro = func(*args, **kwargs)
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
try:
return loop.run_until_complete(coro)
finally:
loop.close()
asyncio.set_event_loop(None)
return wrapper
state = []
@asynccontextmanager
async def woohoo():
state.append(1)
yield 42
state.append(999)
@_async_test
async def test_enter():
class DefaultEnter(AbstractAsyncContextManager):
async def __aexit__(*args):
return
# await super().__aexit__(*args)
manager = DefaultEnter()
got_manager = await manager.__aenter__()
# print(got_manager, manager)
assert got_manager is manager
async with manager as context:
async with woohoo() as x:
x = 1
y = 2
assert manager is context
# From 3.7.6 test_coroutines.py
# Bug was different form of code for "async with" below
class CoroutineTest:
def test_with_8(self):
CNT = 0
async def foo():
nonlocal CNT
async with CM():
CNT += 1
return
test_enter()

View File

@@ -1 +1,3 @@
/.python-version
/runun33.sh
/runun7.sh

View File

@@ -1,4 +1,12 @@
SKIP_TESTS=(
# ifelsestmt is borked in:
# if filename == 'srcfile':
# return srcfile
# if filename == 'destfile':
# return destfile
# assert 0 # shouldn't reach here.
[test_shutil.py]=1
[test___all__.py]=1 # it fails on its own
[test___all__.py]=1 # it fails on its own
@@ -59,6 +67,7 @@ SKIP_TESTS=(
[test_scriptpackages.py]=1 # it fails on its own
[test_select.py]=1 # test takes too long to run: 11 seconds
[test_socket.py]=1 # test takes too long to run: 12 seconds
[test_startfile.py]=1 # it fails on its own
[test_structmembers.py]=1 # it fails on its own

View File

@@ -32,8 +32,8 @@ want to run on earlier Python versions.
import sys
from collections import deque
from xdis import iscode
from xdis.load import check_object_path, load_module
from xdis import iscode, load_module
from xdis.load import check_object_path
from uncompyle6.scanner import get_scanner

View File

@@ -1,4 +1,4 @@
# Copyright (c) 2015-2016, 2818 by Rocky Bernstein
# Copyright (c) 2015-2016, 2818, 2020 by Rocky Bernstein
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -15,14 +15,27 @@
from collections import deque
from xdis import iscode
from xdis.load import load_file, load_module
from xdis.main import get_opcode
from xdis.bytecode import Bytecode, findlinestarts, offset2line
from xdis import (
Bytecode,
iscode,
findlinestarts,
get_opcode,
offset2line,
load_file,
load_module,
)
def line_number_mapping(pyc_filename, src_filename):
(version, timestamp, magic_int, code1, is_pypy,
source_size, sip_hash) = load_module(pyc_filename)
(
version,
timestamp,
magic_int,
code1,
is_pypy,
source_size,
sip_hash,
) = load_module(pyc_filename)
try:
code2 = load_file(src_filename)
except SyntaxError, e:
@@ -44,7 +57,10 @@ def number_loop(queue, mappings, opc):
assert code1.co_name == code2.co_name
linestarts_orig = findlinestarts(code1)
linestarts_uncompiled = list(findlinestarts(code2))
mappings += [[line, offset2line(offset, linestarts_uncompiled)] for offset, line in linestarts_orig]
mappings += [
[line, offset2line(offset, linestarts_uncompiled)]
for offset, line in linestarts_orig
]
bytecode1 = Bytecode(code1, opc)
bytecode2 = Bytecode(code2, opc)
instr2s = bytecode2.get_instructions(code2)

View File

@@ -21,8 +21,7 @@ Common uncompyle6 parser routines.
import sys
from xdis import iscode
from xdis.magics import py_str2float
from xdis import iscode, py_str2float
from spark_parser import GenericASTBuilder, DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG
from uncompyle6.show import maybe_show_asm

View File

@@ -7,7 +7,7 @@ from uncompyle6.parsers.parse11 import Python11Parser
class Python10Parser(Python11Parser):
def __init__(self, debug_parser=PARSER_DEFAULT_DEBUG):
super(Python11Parser, self).__init__(debug_parser)
super(Python10Parser, self).__init__(debug_parser)
self.customized = {}

View File

@@ -1,4 +1,4 @@
# Copyright (c) 2019 Rocky Bernstein
# Copyright (c) 2019-2020 Rocky Bernstein
from spark_parser import DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG
from uncompyle6.parser import PythonParserSingle
@@ -7,7 +7,7 @@ from uncompyle6.parsers.parse12 import Python12Parser
class Python11Parser(Python12Parser):
def __init__(self, debug_parser=PARSER_DEFAULT_DEBUG):
super(Python12Parser, self).__init__(debug_parser)
super(Python11Parser, self).__init__(debug_parser)
self.customized = {}

View File

@@ -8,7 +8,7 @@ from uncompyle6.parsers.parse22 import Python22Parser
class Python21Parser(Python22Parser):
def __init__(self, debug_parser=PARSER_DEFAULT_DEBUG):
super(Python22Parser, self).__init__(debug_parser)
super(Python21Parser, self).__init__(debug_parser)
self.customized = {}
def p_forstmt21(self, args):

View File

@@ -1,4 +1,4 @@
# Copyright (c) 2016-2017 Rocky Bernstein
# Copyright (c) 2016-2017, 2020 Rocky Bernstein
# Copyright (c) 2000-2002 by hartmut Goebel <hartmut@goebel.noris.de>
from spark_parser import DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG
@@ -8,7 +8,7 @@ from uncompyle6.parsers.parse23 import Python23Parser
class Python22Parser(Python23Parser):
def __init__(self, debug_parser=PARSER_DEFAULT_DEBUG):
super(Python23Parser, self).__init__(debug_parser)
super(Python22Parser, self).__init__(debug_parser)
self.customized = {}
def p_misc22(self, args):

View File

@@ -1,4 +1,4 @@
# Copyright (c) 2016-2018 Rocky Bernstein
# Copyright (c) 2016-2018, 2020 Rocky Bernstein
# Copyright (c) 2000-2002 by hartmut Goebel <hartmut@goebel.noris.de>
# Copyright (c) 1999 John Aycock
@@ -9,7 +9,7 @@ from uncompyle6.parsers.parse24 import Python24Parser
class Python23Parser(Python24Parser):
def __init__(self, debug_parser=PARSER_DEFAULT_DEBUG):
super(Python24Parser, self).__init__(debug_parser)
super(Python23Parser, self).__init__(debug_parser)
self.customized = {}
def p_misc23(self, args):

View File

@@ -929,8 +929,10 @@ class Python37Parser(Python37BaseParser):
jitop_come_from_expr ::= JUMP_IF_TRUE_OR_POP come_froms expr
jifop_come_from ::= JUMP_IF_FALSE_OR_POP come_froms
expr_jitop ::= expr JUMP_IF_TRUE_OR_POP
or ::= and jitop_come_from_expr COME_FROM
or ::= expr JUMP_IF_TRUE_OR_POP expr COME_FROM
or ::= expr_jitop expr COME_FROM
or ::= expr_jit expr COME_FROM
or ::= expr_pjit expr POP_JUMP_IF_FALSE COME_FROM
@@ -953,8 +955,8 @@ class Python37Parser(Python37BaseParser):
and ::= expr JUMP_IF_FALSE_OR_POP expr come_from_opt
and ::= expr jifop_come_from expr
pjit_come_from ::= POP_JUMP_IF_TRUE COME_FROM
or ::= expr pjit_come_from expr
expr_pjit_come_from ::= expr POP_JUMP_IF_TRUE COME_FROM
or ::= expr_pjit_come_from expr
## Note that "jmp_false" is what we check on in the "and" reduce rule.
and ::= expr jmp_false expr COME_FROM

View File

@@ -1,4 +1,4 @@
# Copyright (c) 2017-2019 Rocky Bernstein
# Copyright (c) 2017-2020 Rocky Bernstein
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -38,14 +38,17 @@ class Python38Parser(Python37Parser):
stmt ::= forelselaststmtl38
stmt ::= tryfinally38stmt
stmt ::= tryfinally38rstmt
stmt ::= tryfinally38rstmt2
stmt ::= tryfinally38rstmt3
stmt ::= tryfinally38astmt
stmt ::= try_elsestmtl38
stmt ::= try_except_ret38
stmt ::= try_except38
stmt ::= whilestmt38
stmt ::= whileTruestmt38
stmt ::= call
stmt ::= call_stmt
call_stmt ::= call
break ::= POP_BLOCK BREAK_LOOP
break ::= POP_BLOCK POP_TOP BREAK_LOOP
break ::= POP_TOP BREAK_LOOP
@@ -53,15 +56,12 @@ class Python38Parser(Python37Parser):
# FIXME: this should be restricted to being inside a try block
stmt ::= except_ret38
stmt ::= except_ret38a
# FIXME: this should be added only when seeing GET_AITER or YIELD_FROM
async_for_stmt38 ::= expr
GET_AITER
SETUP_FINALLY
GET_ANEXT
LOAD_CONST
YIELD_FROM
POP_BLOCK
async_for ::= GET_AITER _come_froms
SETUP_FINALLY GET_ANEXT LOAD_CONST YIELD_FROM POP_BLOCK
async_for_stmt38 ::= expr async_for
store for_block
COME_FROM_FINALLY
END_ASYNC_FOR
@@ -80,7 +80,20 @@ class Python38Parser(Python37Parser):
END_ASYNC_FOR
else_suite
return ::= ret_expr ROT_TWO POP_TOP RETURN_VALUE
# Seems to be used to discard values before a return in a "for" loop
discard_top ::= ROT_TWO POP_TOP
discard_tops ::= discard_top+
return ::= ret_expr
discard_tops RETURN_VALUE
return ::= popb_return
return ::= pop_return
return ::= pop_ex_return
except_stmt ::= pop_ex_return
pop_return ::= POP_TOP ret_expr RETURN_VALUE
popb_return ::= ret_expr POP_BLOCK RETURN_VALUE
pop_ex_return ::= ret_expr ROT_FOUR POP_EXCEPT RETURN_VALUE
# 3.8 can push a looping JUMP_BACK into into a JUMP_ from a statement that jumps to it
lastl_stmt ::= ifpoplaststmtl
@@ -127,8 +140,14 @@ class Python38Parser(Python37Parser):
except_handler38
try_except38 ::= SETUP_FINALLY POP_BLOCK POP_TOP suite_stmts_opt
except_handler38a
try_except_ret38 ::= SETUP_FINALLY expr POP_BLOCK
RETURN_VALUE except_ret38a
# suite_stmts has a return
try_except38 ::= SETUP_FINALLY POP_BLOCK suite_stmts
except_handler38b
try_except_ret38 ::= SETUP_FINALLY returns except_ret38a
try_except_ret38a ::= SETUP_FINALLY returns except_handler38c
END_FINALLY come_from_opt
# Note: there is a suite_stmts_opt which seems
# to be bookkeeping which is not expressed in source code
@@ -148,19 +167,42 @@ class Python38Parser(Python37Parser):
tryfinallystmt ::= SETUP_FINALLY suite_stmts_opt POP_BLOCK
BEGIN_FINALLY COME_FROM_FINALLY suite_stmts_opt
END_FINALLY
tryfinally38rstmt ::= SETUP_FINALLY POP_BLOCK CALL_FINALLY
lc_setup_finally ::= LOAD_CONST SETUP_FINALLY
call_finally_pt ::= CALL_FINALLY POP_TOP
cf_cf_finally ::= come_from_opt COME_FROM_FINALLY
pop_finally_pt ::= POP_FINALLY POP_TOP
ss_end_finally ::= suite_stmts END_FINALLY
sf_pb_call_returns ::= SETUP_FINALLY POP_BLOCK CALL_FINALLY returns
# FIXME: DRY rules below
tryfinally38rstmt ::= sf_pb_call_returns
cf_cf_finally
ss_end_finally
tryfinally38rstmt ::= sf_pb_call_returns
cf_cf_finally END_FINALLY
suite_stmts
tryfinally38rstmt ::= sf_pb_call_returns
cf_cf_finally POP_FINALLY
ss_end_finally
tryfinally38rstmt ::= sf_bp_call_returns
COME_FROM_FINALLY POP_FINALLY
ss_end_finally
tryfinally38rstmt2 ::= lc_setup_finally POP_BLOCK call_finally_pt
returns
COME_FROM_FINALLY END_FINALLY suite_stmts
tryfinally38rstmt ::= SETUP_FINALLY POP_BLOCK CALL_FINALLY
returns
COME_FROM_FINALLY POP_FINALLY returns
END_FINALLY
tryfinally38stmt ::= SETUP_FINALLY suite_stmts_opt POP_BLOCK
BEGIN_FINALLY COME_FROM_FINALLY
POP_FINALLY suite_stmts_opt END_FINALLY
cf_cf_finally pop_finally_pt
ss_end_finally POP_TOP
tryfinally38rstmt3 ::= SETUP_FINALLY expr POP_BLOCK CALL_FINALLY RETURN_VALUE
COME_FROM COME_FROM_FINALLY
ss_end_finally
tryfinally38stmt ::= SETUP_FINALLY suite_stmts_opt POP_BLOCK
BEGIN_FINALLY COME_FROM_FINALLY
POP_FINALLY suite_stmts_opt END_FINALLY
tryfinally38astmt ::= LOAD_CONST SETUP_FINALLY suite_stmts_opt POP_BLOCK
BEGIN_FINALLY COME_FROM_FINALLY
POP_FINALLY POP_TOP suite_stmts_opt END_FINALLY POP_TOP

View File

@@ -1,4 +1,4 @@
# Copyright (c) 2019 by Rocky Bernstein
# Copyright (c) 2019-2020 by Rocky Bernstein
"""
Python PyPy 3.3 decompiler scanner.
@@ -10,6 +10,7 @@ import uncompyle6.scanners.scanner33 as scan
# bytecode verification, verify(), uses JUMP_OPs from here
from xdis.opcodes import opcode_33pypy as opc
JUMP_OPs = map(lambda op: opc.opname[op], opc.hasjrel + opc.hasjabs)
# We base this off of 3.3

File diff suppressed because it is too large Load Diff

View File

@@ -896,6 +896,7 @@ class Scanner3(Scanner):
start, self.next_stmt[offset], self.opc.POP_JUMP_IF_FALSE, target
)
# FIXME: Remoeve this whole "if" block
# If we still have any offsets in set, start working on it
if match:
is_jump_forward = self.is_jump_forward(pre_rtarget)
@@ -964,7 +965,7 @@ class Scanner3(Scanner):
)
):
pass
else:
elif self.version <= 3.2:
fix = None
jump_ifs = self.inst_matches(
start,

View File

@@ -339,7 +339,11 @@ TABLE_DIRECT = {
"raise_stmt1": ("%|raise %c\n", 0),
"raise_stmt3": ("%|raise %c, %c, %c\n", 0, 1, 2),
# "yield": ( "yield %c", 0),
# "return": ( "%|return %c\n", 0),
# Note: we have a custom rule, which calls when we don't
# have "return None"
"return": ( "%|return %c\n", 0),
"return_if_stmt": ("return %c\n", 0),
"ifstmt": (
"%|if %c:\n%+%c%-",

View File

@@ -29,9 +29,9 @@ def customize_for_version38(self, version):
# del TABLE_DIRECT[lhs]
TABLE_DIRECT.update({
'async_for_stmt38': (
'%|async for %c in %c:\n%+%c%-%-\n\n',
(7, 'store'), (0, 'expr'), (8, 'for_block') ),
"async_for_stmt38": (
"%|async for %c in %c:\n%+%c%-%-\n\n",
(2, "store"), (0, "expr"), (3, "for_block") ),
'async_forelse_stmt38': (
'%|async for %c in %c:\n%+%c%-%|else:\n%+%c%-\n\n',
@@ -46,6 +46,10 @@ def customize_for_version38(self, version):
(0, 'expr'), (6, 'store'),
(7, 'suite_stmts') ),
"call_stmt": (
"%|%c\n", 0
),
'except_handler38': (
'%c', (2, 'except_stmts') ),
@@ -101,12 +105,26 @@ def customize_for_version38(self, version):
'try_except38': (
'%|try:\n%+%c\n%-%|except:\n%|%-%c\n\n',
(-2, 'suite_stmts_opt'), (-1, 'except_handler38a') ),
'try_except_ret38': (
'%|try:\n%+%|return %c%-\n%|except:\n%+%|%c%-\n\n',
(1, 'expr'), (-1, 'except_ret38a') ),
"try_except_ret38": (
"%|try:\n%+%c%-\n%|except:\n%+%|%c%-\n\n",
(1, "returns"),
(2, "except_ret38a"),
),
'tryfinally38rstmt': (
'%|try:\n%+%c%-%|finally:\n%+%c%-\n\n',
(3, 'returns'), 6 ),
(0, "sf_pb_call_returns"),
(-1, ("ss_end_finally", "suite_stmts")),
),
"tryfinally38rstmt2": (
"%|try:\n%+%c%-%|finally:\n%+%c%-\n\n",
(4, "returns"),
-2, "ss_end_finally"
),
"tryfinally38rstmt3": (
"%|try:\n%+%|return %c%-\n%|finally:\n%+%c%-\n\n",
(1, "expr"),
(-1, "ss_end_finally")
),
'tryfinally38stmt': (
'%|try:\n%+%c%-%|finally:\n%+%c%-\n\n',
(1, "suite_stmts_opt"),

View File

@@ -65,8 +65,7 @@ The node position 0 will be associated with "import".
import re
from xdis import iscode
from xdis.magics import sysinfo2float
from xdis import iscode, sysinfo2float
from uncompyle6.semantics import pysource
from uncompyle6 import parser
from uncompyle6.scanner import Token, Code, get_scanner

View File

@@ -16,8 +16,7 @@
All the crazy things we have to do to handle Python functions in 3.0-3.5 or so.
The saga of changes before and after is in other files.
"""
from xdis import iscode, code_has_star_arg, code_has_star_star_arg
from xdis.util import CO_GENERATOR
from xdis import iscode, code_has_star_arg, code_has_star_star_arg, CO_GENERATOR
from uncompyle6.scanner import Code
from uncompyle6.parsers.treenode import SyntaxTree
from uncompyle6.semantics.parser_error import ParserError
@@ -33,6 +32,7 @@ from uncompyle6.show import maybe_show_tree_param_default
# FIXME: DRY the below code...
def make_function3_annotate(
self, node, is_lambda, nested=1, code_node=None, annotate_last=-1
):
@@ -265,8 +265,8 @@ def make_function3_annotate(
self.write("\n" + indent)
line_number = self.line_number
self.write(" -> ")
if 'return' in annotate_dict:
self.write(annotate_dict['return'])
if "return" in annotate_dict:
self.write(annotate_dict["return"])
else:
# value, string = annotate_args['return']
# if string:
@@ -423,9 +423,7 @@ def make_function3(self, node, is_lambda, nested=1, code_node=None):
lc_index = -3
pass
if (len(node) > 2
and (have_kwargs or node[lc_index].kind != "load_closure")
):
if len(node) > 2 and (have_kwargs or node[lc_index].kind != "load_closure"):
# Find the index in "node" where the first default
# parameter value is located. Note this is in contrast to
@@ -483,7 +481,7 @@ def make_function3(self, node, is_lambda, nested=1, code_node=None):
if is_lambda:
kwargs = []
for i in range(kwonlyargcount):
paramnames.append(scanner_code.co_varnames[argc+i])
paramnames.append(scanner_code.co_varnames[argc + i])
pass
else:
kwargs = list(scanner_code.co_varnames[argc : argc + kwonlyargcount])
@@ -686,5 +684,5 @@ def make_function3(self, node, is_lambda, nested=1, code_node=None):
if need_bogus_yield:
self.template_engine(("%|if False:\n%+%|yield None%-",), node)
scanner_code._tokens = None # save memory
scanner_code._tokens = None # save memory
scanner_code._customize = None # save memory

View File

@@ -16,8 +16,13 @@
All the crazy things we have to do to handle Python functions in 3.6 and above.
The saga of changes before 3.6 is in other files.
"""
from xdis import iscode, code_has_star_arg, code_has_star_star_arg
from xdis.util import CO_GENERATOR, CO_ASYNC_GENERATOR
from xdis import (
iscode,
code_has_star_arg,
code_has_star_star_arg,
CO_GENERATOR,
CO_ASYNC_GENERATOR,
)
from uncompyle6.scanner import Code
from uncompyle6.parsers.treenode import SyntaxTree
from uncompyle6.semantics.parser_error import ParserError
@@ -103,9 +108,7 @@ def make_function36(self, node, is_lambda, nested=1, code_node=None):
if annotate_node == "dict" and annotate_name_node.kind.startswith(
"BUILD_CONST_KEY_MAP"
):
types = [
self.traverse(n, indent="") for n in annotate_node[:-2]
]
types = [self.traverse(n, indent="") for n in annotate_node[:-2]]
names = annotate_node[-2].attr
l = len(types)
assert l == len(names)
@@ -328,9 +331,7 @@ def make_function36(self, node, is_lambda, nested=1, code_node=None):
self.write(" -> %s" % annotate_dict["return"])
self.println(":")
if (
node[-2] == "docstring" and not is_lambda
):
if node[-2] == "docstring" and not is_lambda:
# docstring exists, dump it
self.println(self.traverse(node[-2]))
@@ -369,5 +370,5 @@ def make_function36(self, node, is_lambda, nested=1, code_node=None):
if need_bogus_yield:
self.template_engine(("%|if False:\n%+%|yield None%-",), node)
scanner_code._tokens = None # save memory
scanner_code._tokens = None # save memory
scanner_code._customize = None # save memory

View File

@@ -510,14 +510,14 @@ class SourceWalker(GenericASTTraversal, object):
self.preorder(node[0])
self.prune()
else:
self.write(self.indent, "return")
# One reason we worry over whether we use "return None" or "return"
# is that inside a generator, "return None" is illegal.
# Thank you, Python!
if self.return_none or not self.is_return_none(node):
self.write(" ")
self.preorder(node[0])
self.println()
self.default(node)
else:
self.template_engine(("%|return\n",), node)
self.prune() # stop recursing
def n_return_if_stmt(self, node):
@@ -2053,10 +2053,17 @@ class SourceWalker(GenericASTTraversal, object):
elif typ == "c":
index = entry[arg]
if isinstance(index, tuple):
assert node[index[0]] == index[1], (
"at %s[%d], expected '%s' node; got '%s'"
% (node.kind, arg, index[1], node[index[0]].kind)
)
if isinstance(index[1], str):
assert node[index[0]] == index[1], (
"at %s[%d], expected '%s' node; got '%s'"
% (node.kind, arg, index[1], node[index[0]].kind)
)
else:
assert node[index[0]] in index[1], (
"at %s[%d], expected to be in '%s' node; got '%s'"
% (node.kind, arg, index[1], node[index[0]].kind)
)
index = index[0]
assert isinstance(
index, int
@@ -2065,6 +2072,16 @@ class SourceWalker(GenericASTTraversal, object):
arg,
type(index),
)
try:
node[index]
except IndexError:
raise RuntimeError(
"""
Expanding '%' in template '%s[%s]':
%s is invalid; has only %d entries
""" % (node,kind, enty, arg, index, len(node))
)
self.preorder(node[index])
arg += 1

View File

@@ -10,6 +10,6 @@
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# This file is suitable for sourcing inside bash as
# This file is suitable for sourcing inside POSIX shell as
# well as importing into Python
VERSION="3.6.7" # noqa