You've already forked python-uncompyle6
mirror of
https://github.com/rocky/python-uncompyle6.git
synced 2025-08-04 01:09:52 +08:00
Merge branch 'master' into python-2.4
This commit is contained in:
33
NEWS.md
33
NEWS.md
@@ -1,21 +1,36 @@
|
|||||||
|
3.3.4 2019-05-19 Fleetwood at 65
|
||||||
|
================================
|
||||||
|
|
||||||
|
Most of the work in this is release is thanks to x0ret.
|
||||||
|
|
||||||
|
- Major work was done by x0ret to correct function signatures and include annotation types
|
||||||
|
- Handle Python 3.6 STORE_ANNOTATION [#58](https://github.com/rocky/python-uncompyle6/issues/58)
|
||||||
|
- Friendlier assembly output
|
||||||
|
- `LOAD_CONST` replaced by `LOAD_STR` where appropriate to simplify parsing and improve clarity
|
||||||
|
- remove unneeded parenthesis in a generator expression when it is the single argument to the function [#247](https://github.com/rocky/python-uncompyle6/issues/246)
|
||||||
|
- Bug in noting an async function [#246](https://github.com/rocky/python-uncompyle6/issues/246)
|
||||||
|
- Handle unicode docstrings and fix docstring bugs [#241](https://github.com/rocky/python-uncompyle6/issues/241)
|
||||||
|
- Add short option -T as an alternate for --tree+
|
||||||
|
- Some grammar cleanup
|
||||||
|
|
||||||
3.3.3 2019-05-19 Henry and Lewis
|
3.3.3 2019-05-19 Henry and Lewis
|
||||||
================================
|
================================
|
||||||
|
|
||||||
As before, decomplation bugs fixed. The focus has primarily been on
|
As before, decomplation bugs fixed. The focus has primarily been on
|
||||||
Python 3.7. But with this release, releases will be put on hold,as a
|
Python 3.7. But with this release, releases will be put on hold,as a
|
||||||
better control-flow detection is worked on . Tis has been needed for a
|
better control-flow detection is worked on . This has been needed for a
|
||||||
while, and is long overdue. It will probably also take a while to get
|
while, and is long overdue. It will probably also take a while to get
|
||||||
done as good as what we have now.
|
done as good as what we have now.
|
||||||
|
|
||||||
However this work will be done in a new project
|
However this work will be done in a new project
|
||||||
[decompyle3](https://github.com/rocky/python-decompile3). In contrast
|
[decompyle3](https://github.com/rocky/python-decompile3). In contrast
|
||||||
to _uncompyle6_ the code wil be written assuming a modern Python 3,
|
to _uncompyle6_ the code will be written assuming a modern Python 3,
|
||||||
e.g. 3.7. It is originally intended to decompile Python version 3.7
|
e.g. 3.7. It is originally intended to decompile Python version 3.7
|
||||||
and greater.
|
and greater.
|
||||||
|
|
||||||
* A number of Python 3.7+ chained comparisons were fixed
|
* A number of Python 3.7+ chained comparisons were fixed
|
||||||
* Revise Python 3.6ish format string handling
|
* Revise Python 3.6ish format string handling
|
||||||
* Go over operator precedence, e.g. for AST IfExp
|
* Go over operator precedence, e.g. for AST `IfExp`
|
||||||
|
|
||||||
Reported Bug Fixes
|
Reported Bug Fixes
|
||||||
------------------
|
------------------
|
||||||
@@ -47,7 +62,7 @@ Lots of decomplation bugs, especially in the 3.x series fixed. Don't worry thoug
|
|||||||
|
|
||||||
* Add annotation return values in 3.6+
|
* Add annotation return values in 3.6+
|
||||||
* Fix 3.6+ lambda parameter handling decompilation
|
* Fix 3.6+ lambda parameter handling decompilation
|
||||||
* Fix 3.7+ chained comparision decompilation
|
* Fix 3.7+ chained comparison decompilation
|
||||||
* split out semantic-action customization into more separate files
|
* split out semantic-action customization into more separate files
|
||||||
* Add 3.8 try/else
|
* Add 3.8 try/else
|
||||||
* Fix 2.7 generator decompilation
|
* Fix 2.7 generator decompilation
|
||||||
@@ -79,14 +94,14 @@ Bug Fixes
|
|||||||
Pull Requests
|
Pull Requests
|
||||||
----------------
|
----------------
|
||||||
|
|
||||||
* [#202: Better "assert" statement detemination in Python 2.7](https://github.com/rocky/python-uncompyle6/pull/211)
|
* [#202: Better "assert" statement determination in Python 2.7](https://github.com/rocky/python-uncompyle6/pull/211)
|
||||||
* [#204: Python 3.7 testing](https://github.com/rocky/python-uncompyle6/pull/204)
|
* [#204: Python 3.7 testing](https://github.com/rocky/python-uncompyle6/pull/204)
|
||||||
* [#205: Run more f-string tests on Python 3.7](https://github.com/rocky/python-uncompyle6/pull/205)
|
* [#205: Run more f-string tests on Python 3.7](https://github.com/rocky/python-uncompyle6/pull/205)
|
||||||
* [#211: support utf-8 chars in Python 3 sourcecode](https://github.com/rocky/python-uncompyle6/pull/202)
|
* [#211: support utf-8 chars in Python 3 sourcecode](https://github.com/rocky/python-uncompyle6/pull/202)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
3.2.5 2018-12-30 Clearout sale
|
3.2.5 2018-12-30 Clear-out sale
|
||||||
======================================
|
======================================
|
||||||
|
|
||||||
- 3.7.2 Remove deprecation warning on regexp string that isn't raw
|
- 3.7.2 Remove deprecation warning on regexp string that isn't raw
|
||||||
@@ -151,14 +166,14 @@ Jesus on Friday's New York Times puzzle: "I'm stuck on 2A"
|
|||||||
- reduce 3.5, 3.6 control-flow bugs
|
- reduce 3.5, 3.6 control-flow bugs
|
||||||
- reduce ambiguity in rules that lead to long (exponential?) parses
|
- reduce ambiguity in rules that lead to long (exponential?) parses
|
||||||
- limit/isolate some 2.6/2.7,3.x grammar rules
|
- limit/isolate some 2.6/2.7,3.x grammar rules
|
||||||
- more runtime testing of decompiled code
|
- more run-time testing of decompiled code
|
||||||
- more removal of parenthesis around calls via setting precidence
|
- more removal of parenthesis around calls via setting precedence
|
||||||
|
|
||||||
3.1.0 2018-03-21 Equinox
|
3.1.0 2018-03-21 Equinox
|
||||||
==============================
|
==============================
|
||||||
|
|
||||||
- Add code_deparse_with_offset() fragment function.
|
- Add code_deparse_with_offset() fragment function.
|
||||||
- Correct paramenter call fragment deparse_code()
|
- Correct parameter call fragment deparse_code()
|
||||||
- Lots of 3.6, 3.x, and 2.7 bug fixes
|
- Lots of 3.6, 3.x, and 2.7 bug fixes
|
||||||
About 5% of 3.6 fail parsing now. But
|
About 5% of 3.6 fail parsing now. But
|
||||||
semantics still needs much to be desired.
|
semantics still needs much to be desired.
|
||||||
|
@@ -58,7 +58,7 @@ entry_points = {
|
|||||||
]}
|
]}
|
||||||
ftp_url = None
|
ftp_url = None
|
||||||
install_requires = ['spark-parser >= 1.8.7, < 1.9.0',
|
install_requires = ['spark-parser >= 1.8.7, < 1.9.0',
|
||||||
'xdis >= 4.0.1, < 4.1.0']
|
'xdis >= 4.0.2, < 4.1.0']
|
||||||
|
|
||||||
license = 'GPL3'
|
license = 'GPL3'
|
||||||
mailing_list = 'python-debugger@googlegroups.com'
|
mailing_list = 'python-debugger@googlegroups.com'
|
||||||
|
@@ -88,7 +88,7 @@ def test_grammar():
|
|||||||
COME_FROM_EXCEPT_CLAUSE
|
COME_FROM_EXCEPT_CLAUSE
|
||||||
COME_FROM_LOOP COME_FROM_WITH
|
COME_FROM_LOOP COME_FROM_WITH
|
||||||
COME_FROM_FINALLY ELSE
|
COME_FROM_FINALLY ELSE
|
||||||
LOAD_GENEXPR LOAD_ASSERT LOAD_SETCOMP LOAD_DICTCOMP
|
LOAD_GENEXPR LOAD_ASSERT LOAD_SETCOMP LOAD_DICTCOMP LOAD_STR
|
||||||
LAMBDA_MARKER
|
LAMBDA_MARKER
|
||||||
RETURN_END_IF RETURN_END_IF_LAMBDA RETURN_VALUE_LAMBDA RETURN_LAST
|
RETURN_END_IF RETURN_END_IF_LAMBDA RETURN_VALUE_LAMBDA RETURN_LAST
|
||||||
""".split())
|
""".split())
|
||||||
|
@@ -1,3 +1,4 @@
|
|||||||
|
from uncompyle6 import PYTHON_VERSION
|
||||||
from uncompyle6.scanners.tok import Token
|
from uncompyle6.scanners.tok import Token
|
||||||
|
|
||||||
def test_token():
|
def test_token():
|
||||||
@@ -16,7 +17,7 @@ def test_token():
|
|||||||
# Make sure formatting of: LOAD_CONST False. We assume False is the 0th index
|
# Make sure formatting of: LOAD_CONST False. We assume False is the 0th index
|
||||||
# of co_consts.
|
# of co_consts.
|
||||||
t = Token('LOAD_CONST', offset=1, attr=False, pattr=False, has_arg=True)
|
t = Token('LOAD_CONST', offset=1, attr=False, pattr=False, has_arg=True)
|
||||||
expect = ' 1 LOAD_CONST 0 False'
|
expect = ' 1 LOAD_CONST False'
|
||||||
assert t.format() == expect
|
assert t.format() == expect
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
2
pytest/testdata/if-2.7.right
vendored
2
pytest/testdata/if-2.7.right
vendored
@@ -8,5 +8,5 @@
|
|||||||
9 STORE_NAME 2 'b'
|
9 STORE_NAME 2 'b'
|
||||||
12 JUMP_FORWARD 0 'to 15'
|
12 JUMP_FORWARD 0 'to 15'
|
||||||
15_0 COME_FROM 12 '12'
|
15_0 COME_FROM 12 '12'
|
||||||
15 LOAD_CONST 0 None
|
15 LOAD_CONST None
|
||||||
18 RETURN_VALUE
|
18 RETURN_VALUE
|
||||||
|
6
pytest/testdata/ifelse-2.7.right
vendored
6
pytest/testdata/ifelse-2.7.right
vendored
@@ -4,12 +4,12 @@
|
|||||||
3 0 LOAD_NAME 0 'True'
|
3 0 LOAD_NAME 0 'True'
|
||||||
3 POP_JUMP_IF_FALSE 15 'to 15'
|
3 POP_JUMP_IF_FALSE 15 'to 15'
|
||||||
|
|
||||||
4 6 LOAD_CONST 0 1
|
4 6 LOAD_CONST 1
|
||||||
9 STORE_NAME 1 'b'
|
9 STORE_NAME 1 'b'
|
||||||
12 JUMP_FORWARD 6 'to 21'
|
12 JUMP_FORWARD 6 'to 21'
|
||||||
|
|
||||||
6 15 LOAD_CONST 1 2
|
6 15 LOAD_CONST 2
|
||||||
18 STORE_NAME 2 'd'
|
18 STORE_NAME 2 'd'
|
||||||
21_0 COME_FROM 12 '12'
|
21_0 COME_FROM 12 '12'
|
||||||
21 LOAD_CONST 2 None
|
21 LOAD_CONST None
|
||||||
24 RETURN_VALUE
|
24 RETURN_VALUE
|
||||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
test/bytecode_3.6/05_ann_mopdule2.pyc
Normal file
BIN
test/bytecode_3.6/05_ann_mopdule2.pyc
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -47,11 +47,50 @@ def div(a: dict(type=float, help='the dividend'),
|
|||||||
"""Divide a by b"""
|
"""Divide a by b"""
|
||||||
return a / b
|
return a / b
|
||||||
|
|
||||||
# FIXME:
|
class TestSignatureObject1():
|
||||||
# class TestSignatureObject():
|
def test_signature_on_wkwonly(self):
|
||||||
# def test_signature_on_wkwonly(self):
|
def test(*, a:float, b:str, c:str = 'test', **kwargs: int) -> int:
|
||||||
# def test(*, a:float, b:str) -> int:
|
pass
|
||||||
# pass
|
|
||||||
|
class TestSignatureObject2():
|
||||||
|
def test_signature_on_wkwonly(self):
|
||||||
|
def test(*, c='test', a:float, b:str="S", **kwargs: int) -> int:
|
||||||
|
pass
|
||||||
|
|
||||||
|
class TestSignatureObject3():
|
||||||
|
def test_signature_on_wkwonly(self):
|
||||||
|
def test(*, c='test', a:float, kwargs:str="S", **b: int) -> int:
|
||||||
|
pass
|
||||||
|
|
||||||
|
class TestSignatureObject4():
|
||||||
|
def test_signature_on_wkwonly(self):
|
||||||
|
def test(x=55, *args, c:str='test', a:float, kwargs:str="S", **b: int) -> int:
|
||||||
|
pass
|
||||||
|
|
||||||
|
class TestSignatureObject5():
|
||||||
|
def test_signature_on_wkwonly(self):
|
||||||
|
def test(x=55, *args: int, c='test', a:float, kwargs:str="S", **b: int) -> int:
|
||||||
|
pass
|
||||||
|
|
||||||
|
class TestSignatureObject5():
|
||||||
|
def test_signature_on_wkwonly(self):
|
||||||
|
def test(x:int=55, *args: (int, str), c='test', a:float, kwargs:str="S", **b: int) -> int:
|
||||||
|
pass
|
||||||
|
|
||||||
|
class TestSignatureObject7():
|
||||||
|
def test_signature_on_wkwonly(self):
|
||||||
|
def test(c='test', kwargs:str="S", **b: int) -> int:
|
||||||
|
pass
|
||||||
|
|
||||||
|
class TestSignatureObject8():
|
||||||
|
def test_signature_on_wkwonly(self):
|
||||||
|
def test(**b: int) -> int:
|
||||||
|
pass
|
||||||
|
|
||||||
|
class TestSignatureObject9():
|
||||||
|
def test_signature_on_wkwonly(self):
|
||||||
|
def test(a, **b: int) -> int:
|
||||||
|
pass
|
||||||
|
|
||||||
class SupportsInt():
|
class SupportsInt():
|
||||||
|
|
||||||
|
37
test/simple_source/bug36/05_ann_mopdule2.py
Normal file
37
test/simple_source/bug36/05_ann_mopdule2.py
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
# This is from Python 3.6's test directory.
|
||||||
|
"""
|
||||||
|
Some correct syntax for variable annotation here.
|
||||||
|
More examples are in test_grammar and test_parser.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from typing import no_type_check, ClassVar
|
||||||
|
|
||||||
|
i: int = 1
|
||||||
|
j: int
|
||||||
|
x: float = i/10
|
||||||
|
|
||||||
|
def f():
|
||||||
|
class C: ...
|
||||||
|
return C()
|
||||||
|
|
||||||
|
f().new_attr: object = object()
|
||||||
|
|
||||||
|
class C:
|
||||||
|
def __init__(self, x: int) -> None:
|
||||||
|
self.x = x
|
||||||
|
|
||||||
|
c = C(5)
|
||||||
|
c.new_attr: int = 10
|
||||||
|
|
||||||
|
__annotations__ = {}
|
||||||
|
|
||||||
|
|
||||||
|
@no_type_check
|
||||||
|
class NTC:
|
||||||
|
def meth(self, param: complex) -> None:
|
||||||
|
...
|
||||||
|
|
||||||
|
class CV:
|
||||||
|
var: ClassVar['CV']
|
||||||
|
|
||||||
|
CV.var = CV()
|
@@ -114,10 +114,9 @@ class Python3Parser(PythonParser):
|
|||||||
continues ::= continue
|
continues ::= continue
|
||||||
|
|
||||||
|
|
||||||
kwarg ::= LOAD_CONST expr
|
kwarg ::= LOAD_STR expr
|
||||||
kwargs ::= kwarg+
|
kwargs ::= kwarg+
|
||||||
|
|
||||||
|
|
||||||
classdef ::= build_class store
|
classdef ::= build_class store
|
||||||
|
|
||||||
# FIXME: we need to add these because don't detect this properly
|
# FIXME: we need to add these because don't detect this properly
|
||||||
@@ -396,11 +395,12 @@ class Python3Parser(PythonParser):
|
|||||||
def p_generator_exp3(self, args):
|
def p_generator_exp3(self, args):
|
||||||
'''
|
'''
|
||||||
load_genexpr ::= LOAD_GENEXPR
|
load_genexpr ::= LOAD_GENEXPR
|
||||||
load_genexpr ::= BUILD_TUPLE_1 LOAD_GENEXPR LOAD_CONST
|
load_genexpr ::= BUILD_TUPLE_1 LOAD_GENEXPR LOAD_STR
|
||||||
'''
|
'''
|
||||||
|
|
||||||
def p_expr3(self, args):
|
def p_expr3(self, args):
|
||||||
"""
|
"""
|
||||||
|
expr ::= LOAD_STR
|
||||||
expr ::= conditionalnot
|
expr ::= conditionalnot
|
||||||
conditionalnot ::= expr jmp_true expr jump_forward_else expr COME_FROM
|
conditionalnot ::= expr jmp_true expr jump_forward_else expr COME_FROM
|
||||||
|
|
||||||
@@ -443,7 +443,7 @@ class Python3Parser(PythonParser):
|
|||||||
break
|
break
|
||||||
pass
|
pass
|
||||||
assert i < len(tokens), "build_class needs to find MAKE_FUNCTION or MAKE_CLOSURE"
|
assert i < len(tokens), "build_class needs to find MAKE_FUNCTION or MAKE_CLOSURE"
|
||||||
assert tokens[i+1].kind == 'LOAD_CONST', \
|
assert tokens[i+1].kind == 'LOAD_STR', \
|
||||||
"build_class expecting CONST after MAKE_FUNCTION/MAKE_CLOSURE"
|
"build_class expecting CONST after MAKE_FUNCTION/MAKE_CLOSURE"
|
||||||
call_fn_tok = None
|
call_fn_tok = None
|
||||||
for i in range(i, len(tokens)):
|
for i in range(i, len(tokens)):
|
||||||
@@ -517,13 +517,13 @@ class Python3Parser(PythonParser):
|
|||||||
self.add_unique_rule(rule, token.kind, uniq_param, customize)
|
self.add_unique_rule(rule, token.kind, uniq_param, customize)
|
||||||
|
|
||||||
def add_make_function_rule(self, rule, opname, attr, customize):
|
def add_make_function_rule(self, rule, opname, attr, customize):
|
||||||
"""Python 3.3 added a an addtional LOAD_CONST before MAKE_FUNCTION and
|
"""Python 3.3 added a an addtional LOAD_STR before MAKE_FUNCTION and
|
||||||
this has an effect on many rules.
|
this has an effect on many rules.
|
||||||
"""
|
"""
|
||||||
if self.version >= 3.3:
|
if self.version >= 3.3:
|
||||||
new_rule = rule % (('LOAD_CONST ') * 1)
|
new_rule = rule % (('LOAD_STR ') * 1)
|
||||||
else:
|
else:
|
||||||
new_rule = rule % (('LOAD_CONST ') * 0)
|
new_rule = rule % (('LOAD_STR ') * 0)
|
||||||
self.add_unique_rule(new_rule, opname, attr, customize)
|
self.add_unique_rule(new_rule, opname, attr, customize)
|
||||||
|
|
||||||
def customize_grammar_rules(self, tokens, customize):
|
def customize_grammar_rules(self, tokens, customize):
|
||||||
@@ -732,7 +732,7 @@ class Python3Parser(PythonParser):
|
|||||||
|
|
||||||
if opname == 'CALL_FUNCTION' and token.attr == 1:
|
if opname == 'CALL_FUNCTION' and token.attr == 1:
|
||||||
rule = """
|
rule = """
|
||||||
dict_comp ::= LOAD_DICTCOMP LOAD_CONST MAKE_FUNCTION_0 expr
|
dict_comp ::= LOAD_DICTCOMP LOAD_STR MAKE_FUNCTION_0 expr
|
||||||
GET_ITER CALL_FUNCTION_1
|
GET_ITER CALL_FUNCTION_1
|
||||||
classdefdeco1 ::= expr classdefdeco2 CALL_FUNCTION_1
|
classdefdeco1 ::= expr classdefdeco2 CALL_FUNCTION_1
|
||||||
"""
|
"""
|
||||||
@@ -851,7 +851,7 @@ class Python3Parser(PythonParser):
|
|||||||
# Note that 3.6+ doesn't do this, but we'll remove
|
# Note that 3.6+ doesn't do this, but we'll remove
|
||||||
# this rule in parse36.py
|
# this rule in parse36.py
|
||||||
rule = """
|
rule = """
|
||||||
dict_comp ::= load_closure LOAD_DICTCOMP LOAD_CONST
|
dict_comp ::= load_closure LOAD_DICTCOMP LOAD_STR
|
||||||
MAKE_CLOSURE_0 expr
|
MAKE_CLOSURE_0 expr
|
||||||
GET_ITER CALL_FUNCTION_1
|
GET_ITER CALL_FUNCTION_1
|
||||||
"""
|
"""
|
||||||
@@ -904,10 +904,10 @@ class Python3Parser(PythonParser):
|
|||||||
rule = ('mkfunc ::= %s%sload_closure LOAD_CONST %s'
|
rule = ('mkfunc ::= %s%sload_closure LOAD_CONST %s'
|
||||||
% (kwargs_str, 'expr ' * args_pos, opname))
|
% (kwargs_str, 'expr ' * args_pos, opname))
|
||||||
elif self.version == 3.3:
|
elif self.version == 3.3:
|
||||||
rule = ('mkfunc ::= %s%sload_closure LOAD_CONST LOAD_CONST %s'
|
rule = ('mkfunc ::= %s%sload_closure LOAD_CONST LOAD_STR %s'
|
||||||
% (kwargs_str, 'expr ' * args_pos, opname))
|
% (kwargs_str, 'expr ' * args_pos, opname))
|
||||||
elif self.version >= 3.4:
|
elif self.version >= 3.4:
|
||||||
rule = ('mkfunc ::= %s%s load_closure LOAD_CONST LOAD_CONST %s'
|
rule = ('mkfunc ::= %s%s load_closure LOAD_CONST LOAD_STR %s'
|
||||||
% ('expr ' * args_pos, kwargs_str, opname))
|
% ('expr ' * args_pos, kwargs_str, opname))
|
||||||
|
|
||||||
self.add_unique_rule(rule, opname, token.attr, customize)
|
self.add_unique_rule(rule, opname, token.attr, customize)
|
||||||
@@ -935,17 +935,17 @@ class Python3Parser(PythonParser):
|
|||||||
rule = ('mklambda ::= %s%s%s%s' %
|
rule = ('mklambda ::= %s%s%s%s' %
|
||||||
('expr ' * stack_count,
|
('expr ' * stack_count,
|
||||||
'load_closure ' * closure,
|
'load_closure ' * closure,
|
||||||
'BUILD_TUPLE_1 LOAD_LAMBDA LOAD_CONST ',
|
'BUILD_TUPLE_1 LOAD_LAMBDA LOAD_STR ',
|
||||||
opname))
|
opname))
|
||||||
else:
|
else:
|
||||||
rule = ('mklambda ::= %s%s%s' %
|
rule = ('mklambda ::= %s%s%s' %
|
||||||
('load_closure ' * closure,
|
('load_closure ' * closure,
|
||||||
'LOAD_LAMBDA LOAD_CONST ',
|
'LOAD_LAMBDA LOAD_STR ',
|
||||||
opname))
|
opname))
|
||||||
self.add_unique_rule(rule, opname, token.attr, customize)
|
self.add_unique_rule(rule, opname, token.attr, customize)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
rule = ('mklambda ::= %sLOAD_LAMBDA LOAD_CONST %s' %
|
rule = ('mklambda ::= %sLOAD_LAMBDA LOAD_STR %s' %
|
||||||
(('expr ' * stack_count), opname))
|
(('expr ' * stack_count), opname))
|
||||||
self.add_unique_rule(rule, opname, token.attr, customize)
|
self.add_unique_rule(rule, opname, token.attr, customize)
|
||||||
|
|
||||||
@@ -953,7 +953,7 @@ class Python3Parser(PythonParser):
|
|||||||
rule = ('mkfunc ::= %s%s%s%s' %
|
rule = ('mkfunc ::= %s%s%s%s' %
|
||||||
('expr ' * stack_count,
|
('expr ' * stack_count,
|
||||||
'load_closure ' * closure,
|
'load_closure ' * closure,
|
||||||
'LOAD_CONST ' * 2,
|
'LOAD_CONST LOAD_STR ',
|
||||||
opname))
|
opname))
|
||||||
self.add_unique_rule(rule, opname, token.attr, customize)
|
self.add_unique_rule(rule, opname, token.attr, customize)
|
||||||
|
|
||||||
@@ -1035,17 +1035,17 @@ class Python3Parser(PythonParser):
|
|||||||
elif self.version == 3.3:
|
elif self.version == 3.3:
|
||||||
# positional args after keyword args
|
# positional args after keyword args
|
||||||
rule = ('mkfunc ::= %s %s%s%s' %
|
rule = ('mkfunc ::= %s %s%s%s' %
|
||||||
(kwargs, 'pos_arg ' * args_pos, 'LOAD_CONST '*2,
|
(kwargs, 'pos_arg ' * args_pos, 'LOAD_CONST LOAD_STR ',
|
||||||
opname))
|
opname))
|
||||||
elif self.version > 3.5:
|
elif self.version > 3.5:
|
||||||
# positional args before keyword args
|
# positional args before keyword args
|
||||||
rule = ('mkfunc ::= %s%s %s%s' %
|
rule = ('mkfunc ::= %s%s %s%s' %
|
||||||
('pos_arg ' * args_pos, kwargs, 'LOAD_CONST '*2,
|
('pos_arg ' * args_pos, kwargs, 'LOAD_CONST LOAD_STR ',
|
||||||
opname))
|
opname))
|
||||||
elif self.version > 3.3:
|
elif self.version > 3.3:
|
||||||
# positional args before keyword args
|
# positional args before keyword args
|
||||||
rule = ('mkfunc ::= %s%s %s%s' %
|
rule = ('mkfunc ::= %s%s %s%s' %
|
||||||
('pos_arg ' * args_pos, kwargs, 'LOAD_CONST '*2,
|
('pos_arg ' * args_pos, kwargs, 'LOAD_CONST LOAD_STR ',
|
||||||
opname))
|
opname))
|
||||||
else:
|
else:
|
||||||
rule = ('mkfunc ::= %s%sexpr %s' %
|
rule = ('mkfunc ::= %s%sexpr %s' %
|
||||||
@@ -1054,38 +1054,38 @@ class Python3Parser(PythonParser):
|
|||||||
|
|
||||||
if re.search('^MAKE_FUNCTION.*_A', opname):
|
if re.search('^MAKE_FUNCTION.*_A', opname):
|
||||||
if self.version >= 3.6:
|
if self.version >= 3.6:
|
||||||
rule = ('mkfunc_annotate ::= %s%sannotate_tuple LOAD_CONST LOAD_CONST %s' %
|
rule = ('mkfunc_annotate ::= %s%sannotate_tuple LOAD_CONST LOAD_STR %s' %
|
||||||
(('pos_arg ' * (args_pos)),
|
(('pos_arg ' * (args_pos)),
|
||||||
('call ' * (annotate_args-1)), opname))
|
('call ' * (annotate_args-1)), opname))
|
||||||
self.add_unique_rule(rule, opname, token.attr, customize)
|
self.add_unique_rule(rule, opname, token.attr, customize)
|
||||||
rule = ('mkfunc_annotate ::= %s%sannotate_tuple LOAD_CONST LOAD_CONST %s' %
|
rule = ('mkfunc_annotate ::= %s%sannotate_tuple LOAD_CONST LOAD_STR %s' %
|
||||||
(('pos_arg ' * (args_pos)),
|
(('pos_arg ' * (args_pos)),
|
||||||
('annotate_arg ' * (annotate_args-1)), opname))
|
('annotate_arg ' * (annotate_args-1)), opname))
|
||||||
if self.version >= 3.3:
|
if self.version >= 3.3:
|
||||||
# Normally we remove EXTENDED_ARG from the opcodes, but in the case of
|
# Normally we remove EXTENDED_ARG from the opcodes, but in the case of
|
||||||
# annotated functions can use the EXTENDED_ARG tuple to signal we have an annotated function.
|
# annotated functions can use the EXTENDED_ARG tuple to signal we have an annotated function.
|
||||||
# Yes this is a little hacky
|
# Yes this is a little hacky
|
||||||
if self.version < 3.5:
|
if self.version == 3.3:
|
||||||
# 3.3 and 3.4 put kwargs before pos_arg
|
# 3.3 puts kwargs before pos_arg
|
||||||
pos_kw_tuple = (('kwargs ' * args_kw), ('pos_arg ' * (args_pos)))
|
pos_kw_tuple = (('kwargs ' * args_kw), ('pos_arg ' * (args_pos)))
|
||||||
else:
|
else:
|
||||||
# 3.5 puts pos_arg before kwargs
|
# 3.4 and 3.5puts pos_arg before kwargs
|
||||||
pos_kw_tuple = (('pos_arg ' * (args_pos), ('kwargs ' * args_kw)))
|
pos_kw_tuple = (('pos_arg ' * (args_pos), ('kwargs ' * args_kw)))
|
||||||
rule = ('mkfunc_annotate ::= %s%s%sannotate_tuple LOAD_CONST LOAD_CONST EXTENDED_ARG %s' %
|
rule = ('mkfunc_annotate ::= %s%s%sannotate_tuple LOAD_CONST LOAD_STR EXTENDED_ARG %s' %
|
||||||
( pos_kw_tuple[0], pos_kw_tuple[1],
|
( pos_kw_tuple[0], pos_kw_tuple[1],
|
||||||
('call ' * (annotate_args-1)), opname))
|
('call ' * (annotate_args-1)), opname))
|
||||||
self.add_unique_rule(rule, opname, token.attr, customize)
|
self.add_unique_rule(rule, opname, token.attr, customize)
|
||||||
rule = ('mkfunc_annotate ::= %s%s%sannotate_tuple LOAD_CONST LOAD_CONST EXTENDED_ARG %s' %
|
rule = ('mkfunc_annotate ::= %s%s%sannotate_tuple LOAD_CONST LOAD_STR EXTENDED_ARG %s' %
|
||||||
( pos_kw_tuple[0], pos_kw_tuple[1],
|
( pos_kw_tuple[0], pos_kw_tuple[1],
|
||||||
('annotate_arg ' * (annotate_args-1)), opname))
|
('annotate_arg ' * (annotate_args-1)), opname))
|
||||||
else:
|
else:
|
||||||
# See above comment about use of EXTENDED_ARG
|
# See above comment about use of EXTENDED_ARG
|
||||||
rule = ('mkfunc_annotate ::= %s%s%sannotate_tuple LOAD_CONST EXTENDED_ARG %s' %
|
rule = ('mkfunc_annotate ::= %s%s%sannotate_tuple LOAD_CONST EXTENDED_ARG %s' %
|
||||||
(('pos_arg ' * (args_pos)), ('kwargs ' * args_kw),
|
(('kwargs ' * args_kw), ('pos_arg ' * (args_pos)),
|
||||||
('annotate_arg ' * (annotate_args-1)), opname))
|
('annotate_arg ' * (annotate_args-1)), opname))
|
||||||
self.add_unique_rule(rule, opname, token.attr, customize)
|
self.add_unique_rule(rule, opname, token.attr, customize)
|
||||||
rule = ('mkfunc_annotate ::= %s%s%sannotate_tuple LOAD_CONST EXTENDED_ARG %s' %
|
rule = ('mkfunc_annotate ::= %s%s%sannotate_tuple LOAD_CONST EXTENDED_ARG %s' %
|
||||||
(('pos_arg ' * (args_pos)), ('kwargs ' * args_kw),
|
(('kwargs ' * args_kw), ('pos_arg ' * (args_pos)),
|
||||||
('call ' * (annotate_args-1)), opname))
|
('call ' * (annotate_args-1)), opname))
|
||||||
self.addRule(rule, nop_func)
|
self.addRule(rule, nop_func)
|
||||||
elif opname == 'RETURN_VALUE_LAMBDA':
|
elif opname == 'RETURN_VALUE_LAMBDA':
|
||||||
@@ -1151,6 +1151,7 @@ class Python3Parser(PythonParser):
|
|||||||
self.check_reduce['while1elsestmt'] = 'noAST'
|
self.check_reduce['while1elsestmt'] = 'noAST'
|
||||||
self.check_reduce['ifelsestmt'] = 'AST'
|
self.check_reduce['ifelsestmt'] = 'AST'
|
||||||
self.check_reduce['annotate_tuple'] = 'noAST'
|
self.check_reduce['annotate_tuple'] = 'noAST'
|
||||||
|
if not PYTHON3:
|
||||||
self.check_reduce['kwarg'] = 'noAST'
|
self.check_reduce['kwarg'] = 'noAST'
|
||||||
if self.version < 3.6:
|
if self.version < 3.6:
|
||||||
# 3.6+ can remove a JUMP_FORWARD which messes up our testing here
|
# 3.6+ can remove a JUMP_FORWARD which messes up our testing here
|
||||||
@@ -1168,9 +1169,6 @@ class Python3Parser(PythonParser):
|
|||||||
return not isinstance(tokens[first].attr, tuple)
|
return not isinstance(tokens[first].attr, tuple)
|
||||||
elif lhs == 'kwarg':
|
elif lhs == 'kwarg':
|
||||||
arg = tokens[first].attr
|
arg = tokens[first].attr
|
||||||
if PYTHON3:
|
|
||||||
return not isinstance(arg, str)
|
|
||||||
else:
|
|
||||||
return not (isinstance(arg, str) or isinstance(arg, unicode))
|
return not (isinstance(arg, str) or isinstance(arg, unicode))
|
||||||
elif lhs == 'while1elsestmt':
|
elif lhs == 'while1elsestmt':
|
||||||
|
|
||||||
|
@@ -29,8 +29,7 @@ class Python36Parser(Python35Parser):
|
|||||||
|
|
||||||
|
|
||||||
def p_36misc(self, args):
|
def p_36misc(self, args):
|
||||||
"""
|
"""sstmt ::= sstmt RETURN_LAST
|
||||||
sstmt ::= sstmt RETURN_LAST
|
|
||||||
|
|
||||||
# 3.6 redoes how return_closure works. FIXME: Isolate to LOAD_CLOSURE
|
# 3.6 redoes how return_closure works. FIXME: Isolate to LOAD_CLOSURE
|
||||||
return_closure ::= LOAD_CLOSURE DUP_TOP STORE_NAME RETURN_VALUE RETURN_LAST
|
return_closure ::= LOAD_CLOSURE DUP_TOP STORE_NAME RETURN_VALUE RETURN_LAST
|
||||||
@@ -142,6 +141,7 @@ class Python36Parser(Python35Parser):
|
|||||||
COME_FROM_FINALLY
|
COME_FROM_FINALLY
|
||||||
|
|
||||||
compare_chained2 ::= expr COMPARE_OP come_froms JUMP_FORWARD
|
compare_chained2 ::= expr COMPARE_OP come_froms JUMP_FORWARD
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def customize_grammar_rules(self, tokens, customize):
|
def customize_grammar_rules(self, tokens, customize):
|
||||||
@@ -201,14 +201,14 @@ class Python36Parser(Python35Parser):
|
|||||||
if 'LOAD_DICTCOMP' in self.seen_ops:
|
if 'LOAD_DICTCOMP' in self.seen_ops:
|
||||||
# Is there something general going on here?
|
# Is there something general going on here?
|
||||||
rule = """
|
rule = """
|
||||||
dict_comp ::= load_closure LOAD_DICTCOMP LOAD_CONST
|
dict_comp ::= load_closure LOAD_DICTCOMP LOAD_STR
|
||||||
MAKE_FUNCTION_8 expr
|
MAKE_FUNCTION_8 expr
|
||||||
GET_ITER CALL_FUNCTION_1
|
GET_ITER CALL_FUNCTION_1
|
||||||
"""
|
"""
|
||||||
self.addRule(rule, nop_func)
|
self.addRule(rule, nop_func)
|
||||||
elif 'LOAD_SETCOMP' in self.seen_ops:
|
elif 'LOAD_SETCOMP' in self.seen_ops:
|
||||||
rule = """
|
rule = """
|
||||||
set_comp ::= load_closure LOAD_SETCOMP LOAD_CONST
|
set_comp ::= load_closure LOAD_SETCOMP LOAD_STR
|
||||||
MAKE_FUNCTION_8 expr
|
MAKE_FUNCTION_8 expr
|
||||||
GET_ITER CALL_FUNCTION_1
|
GET_ITER CALL_FUNCTION_1
|
||||||
"""
|
"""
|
||||||
@@ -263,6 +263,23 @@ class Python36Parser(Python35Parser):
|
|||||||
self.addRule(rule, nop_func)
|
self.addRule(rule, nop_func)
|
||||||
rule = ('starred ::= %s %s' % ('expr ' * v, opname))
|
rule = ('starred ::= %s %s' % ('expr ' * v, opname))
|
||||||
self.addRule(rule, nop_func)
|
self.addRule(rule, nop_func)
|
||||||
|
elif opname == 'SETUP_ANNOTATIONS':
|
||||||
|
# 3.6 Variable Annotations PEP 526
|
||||||
|
# This seems to come before STORE_ANNOTATION, and doesn't
|
||||||
|
# correspond to direct Python source code.
|
||||||
|
rule = """
|
||||||
|
stmt ::= SETUP_ANNOTATIONS
|
||||||
|
stmt ::= ann_assign_init_value
|
||||||
|
stmt ::= ann_assign_no_init
|
||||||
|
|
||||||
|
ann_assign_init_value ::= expr store store_annotation
|
||||||
|
ann_assign_no_init ::= store_annotation
|
||||||
|
store_annotation ::= LOAD_NAME STORE_ANNOTATION
|
||||||
|
store_annotation ::= subscript STORE_ANNOTATION
|
||||||
|
"""
|
||||||
|
self.addRule(rule, nop_func)
|
||||||
|
# Check to combine assignment + annotation into one statement
|
||||||
|
self.check_reduce['assign'] = 'token'
|
||||||
elif opname == 'SETUP_WITH':
|
elif opname == 'SETUP_WITH':
|
||||||
rules_str = """
|
rules_str = """
|
||||||
withstmt ::= expr SETUP_WITH POP_TOP suite_stmts_opt COME_FROM_WITH
|
withstmt ::= expr SETUP_WITH POP_TOP suite_stmts_opt COME_FROM_WITH
|
||||||
@@ -288,6 +305,7 @@ class Python36Parser(Python35Parser):
|
|||||||
self.addRule(rules_str, nop_func)
|
self.addRule(rules_str, nop_func)
|
||||||
pass
|
pass
|
||||||
pass
|
pass
|
||||||
|
return
|
||||||
|
|
||||||
def custom_classfunc_rule(self, opname, token, customize, next_token):
|
def custom_classfunc_rule(self, opname, token, customize, next_token):
|
||||||
|
|
||||||
@@ -387,6 +405,15 @@ class Python36Parser(Python35Parser):
|
|||||||
tokens, first, last)
|
tokens, first, last)
|
||||||
if invalid:
|
if invalid:
|
||||||
return invalid
|
return invalid
|
||||||
|
if rule[0] == 'assign':
|
||||||
|
# Try to combine assignment + annotation into one statement
|
||||||
|
if (len(tokens) >= last + 1 and
|
||||||
|
tokens[last] == 'LOAD_NAME' and
|
||||||
|
tokens[last+1] == 'STORE_ANNOTATION' and
|
||||||
|
tokens[last-1].pattr == tokens[last+1].pattr):
|
||||||
|
# Will handle as ann_assign_init_value
|
||||||
|
return True
|
||||||
|
pass
|
||||||
if rule[0] == 'call_kw':
|
if rule[0] == 'call_kw':
|
||||||
# Make sure we don't derive call_kw
|
# Make sure we don't derive call_kw
|
||||||
nt = ast[0]
|
nt = ast[0]
|
||||||
|
@@ -318,6 +318,8 @@ class Scanner3(Scanner):
|
|||||||
# pattr = 'code_object @ 0x%x %s->%s' %\
|
# pattr = 'code_object @ 0x%x %s->%s' %\
|
||||||
# (id(const), const.co_filename, const.co_name)
|
# (id(const), const.co_filename, const.co_name)
|
||||||
pattr = '<code_object ' + const.co_name + '>'
|
pattr = '<code_object ' + const.co_name + '>'
|
||||||
|
elif isinstance(const, str):
|
||||||
|
opname = 'LOAD_STR'
|
||||||
else:
|
else:
|
||||||
if isinstance(inst.arg, int) and inst.arg < len(co.co_consts):
|
if isinstance(inst.arg, int) and inst.arg < len(co.co_consts):
|
||||||
argval, _ = _get_const_info(inst.arg, co.co_consts)
|
argval, _ = _get_const_info(inst.arg, co.co_consts)
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
# Copyright (c) 2016-2018 by Rocky Bernstein
|
# Copyright (c) 2016-2019 by Rocky Bernstein
|
||||||
# Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com>
|
# Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com>
|
||||||
# Copyright (c) 1999 John Aycock
|
# Copyright (c) 1999 John Aycock
|
||||||
#
|
#
|
||||||
@@ -58,7 +58,10 @@ class Token: # Python 2.4 can't have empty ()
|
|||||||
""" '==' on kind and "pattr" attributes.
|
""" '==' on kind and "pattr" attributes.
|
||||||
It is okay if offsets and linestarts are different"""
|
It is okay if offsets and linestarts are different"""
|
||||||
if isinstance(o, Token):
|
if isinstance(o, Token):
|
||||||
return (self.kind == o.kind) and (self.pattr == o.pattr)
|
return (
|
||||||
|
(self.kind == o.kind)
|
||||||
|
and ((self.pattr == o.pattr) or self.attr == o.attr)
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
# ?? do we need this?
|
# ?? do we need this?
|
||||||
return self.kind == o
|
return self.kind == o
|
||||||
@@ -85,13 +88,15 @@ class Token: # Python 2.4 can't have empty ()
|
|||||||
else:
|
else:
|
||||||
prefix = ' ' * (6 + len(line_prefix))
|
prefix = ' ' * (6 + len(line_prefix))
|
||||||
offset_opname = '%6s %-17s' % (self.offset, self.kind)
|
offset_opname = '%6s %-17s' % (self.offset, self.kind)
|
||||||
|
|
||||||
if not self.has_arg:
|
if not self.has_arg:
|
||||||
return "%s%s" % (prefix, offset_opname)
|
return "%s%s" % (prefix, offset_opname)
|
||||||
|
|
||||||
if isinstance(self.attr, int):
|
if isinstance(self.attr, int):
|
||||||
argstr = "%6d " % self.attr
|
argstr = "%6d " % self.attr
|
||||||
else:
|
else:
|
||||||
argstr = ' '*7
|
argstr = ' '*7
|
||||||
|
name = self.kind
|
||||||
|
|
||||||
if self.has_arg:
|
if self.has_arg:
|
||||||
pattr = self.pattr
|
pattr = self.pattr
|
||||||
if self.opc:
|
if self.opc:
|
||||||
@@ -104,13 +109,25 @@ class Token: # Python 2.4 can't have empty ()
|
|||||||
pattr = "to " + str(self.pattr)
|
pattr = "to " + str(self.pattr)
|
||||||
pass
|
pass
|
||||||
elif self.op in self.opc.CONST_OPS:
|
elif self.op in self.opc.CONST_OPS:
|
||||||
# Compare with pysource n_LOAD_CONST
|
if name == 'LOAD_STR':
|
||||||
attr = self.attr
|
pattr = self.attr
|
||||||
if attr is None:
|
elif name == 'LOAD_CODE':
|
||||||
pattr = None
|
return "%s%s%s %s" % (prefix, offset_opname, argstr, pattr)
|
||||||
|
else:
|
||||||
|
return "%s%s %r" % (prefix, offset_opname, pattr)
|
||||||
|
|
||||||
elif self.op in self.opc.hascompare:
|
elif self.op in self.opc.hascompare:
|
||||||
if isinstance(self.attr, int):
|
if isinstance(self.attr, int):
|
||||||
pattr = self.opc.cmp_op[self.attr]
|
pattr = self.opc.cmp_op[self.attr]
|
||||||
|
return "%s%s%s %s" % (prefix, offset_opname, argstr, pattr)
|
||||||
|
elif self.op in self.opc.hasvargs:
|
||||||
|
return "%s%s%s" % (prefix, offset_opname, argstr)
|
||||||
|
elif self.op in self.opc.NAME_OPS:
|
||||||
|
if self.opc.version >= 3.0:
|
||||||
|
return "%s%s%s %s" % (prefix, offset_opname, argstr, self.attr)
|
||||||
|
elif name == 'EXTENDED_ARG':
|
||||||
|
return "%s%s%s 0x%x << %s = %s" % (prefix, offset_opname, argstr, self.attr,
|
||||||
|
self.opc.EXTENDED_ARG_SHIFT, pattr)
|
||||||
# And so on. See xdis/bytecode.py get_instructions_bytes
|
# And so on. See xdis/bytecode.py get_instructions_bytes
|
||||||
pass
|
pass
|
||||||
elif re.search(r'_\d+$', self.kind):
|
elif re.search(r'_\d+$', self.kind):
|
||||||
|
@@ -128,10 +128,10 @@ PASS = SyntaxTree('stmts',
|
|||||||
[ SyntaxTree('stmt',
|
[ SyntaxTree('stmt',
|
||||||
[ SyntaxTree('pass', [])])])])
|
[ SyntaxTree('pass', [])])])])
|
||||||
|
|
||||||
ASSIGN_DOC_STRING = lambda doc_string: \
|
ASSIGN_DOC_STRING = lambda doc_string, doc_load: \
|
||||||
SyntaxTree('stmt',
|
SyntaxTree('stmt',
|
||||||
[ SyntaxTree('assign',
|
[ SyntaxTree('assign',
|
||||||
[ SyntaxTree('expr', [ Token('LOAD_CONST', pattr=doc_string) ]),
|
[ SyntaxTree('expr', [ Token(doc_load, pattr=doc_string, attr=doc_string) ]),
|
||||||
SyntaxTree('store', [ Token('STORE_NAME', pattr='__doc__')])
|
SyntaxTree('store', [ Token('STORE_NAME', pattr='__doc__')])
|
||||||
])])
|
])])
|
||||||
|
|
||||||
@@ -221,6 +221,7 @@ TABLE_DIRECT = {
|
|||||||
'IMPORT_FROM': ( '%{pattr}', ),
|
'IMPORT_FROM': ( '%{pattr}', ),
|
||||||
'attribute': ( '%c.%[1]{pattr}',
|
'attribute': ( '%c.%[1]{pattr}',
|
||||||
(0, 'expr')),
|
(0, 'expr')),
|
||||||
|
'LOAD_STR': ( '%{pattr}', ),
|
||||||
'LOAD_FAST': ( '%{pattr}', ),
|
'LOAD_FAST': ( '%{pattr}', ),
|
||||||
'LOAD_NAME': ( '%{pattr}', ),
|
'LOAD_NAME': ( '%{pattr}', ),
|
||||||
'LOAD_CLASSNAME': ( '%{pattr}', ),
|
'LOAD_CLASSNAME': ( '%{pattr}', ),
|
||||||
@@ -317,7 +318,7 @@ TABLE_DIRECT = {
|
|||||||
'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),
|
'kwarg': ( '%[0]{pattr}=%c', 1), # Change when Python 2 does LOAD_STR
|
||||||
'kwargs': ( '%D', (0, maxint, ', ') ),
|
'kwargs': ( '%D', (0, maxint, ', ') ),
|
||||||
'kwargs1': ( '%D', (0, maxint, ', ') ),
|
'kwargs1': ( '%D', (0, maxint, ', ') ),
|
||||||
|
|
||||||
|
@@ -41,6 +41,7 @@ def customize_for_version3(self, version):
|
|||||||
|
|
||||||
'importmultiple' : ( '%|import %c%c\n', 2, 3 ),
|
'importmultiple' : ( '%|import %c%c\n', 2, 3 ),
|
||||||
'import_cont' : ( ', %c', 2 ),
|
'import_cont' : ( ', %c', 2 ),
|
||||||
|
'kwarg' : ( '%[0]{attr}=%c', 1),
|
||||||
'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),
|
||||||
@@ -62,11 +63,11 @@ def customize_for_version3(self, version):
|
|||||||
subclass_info = None
|
subclass_info = None
|
||||||
if node == 'classdefdeco2':
|
if node == 'classdefdeco2':
|
||||||
if self.version >= 3.6:
|
if self.version >= 3.6:
|
||||||
class_name = node[1][1].pattr
|
class_name = node[1][1].attr
|
||||||
elif self.version <= 3.3:
|
elif self.version <= 3.3:
|
||||||
class_name = node[2][0].pattr
|
class_name = node[2][0].attr
|
||||||
else:
|
else:
|
||||||
class_name = node[1][2].pattr
|
class_name = node[1][2].attr
|
||||||
build_class = node
|
build_class = node
|
||||||
else:
|
else:
|
||||||
build_class = node[0]
|
build_class = node[0]
|
||||||
@@ -87,7 +88,7 @@ def customize_for_version3(self, version):
|
|||||||
code_node = build_class[1][0]
|
code_node = build_class[1][0]
|
||||||
class_name = code_node.attr.co_name
|
class_name = code_node.attr.co_name
|
||||||
else:
|
else:
|
||||||
class_name = node[1][0].pattr
|
class_name = node[1][0].attr
|
||||||
build_class = node[0]
|
build_class = node[0]
|
||||||
|
|
||||||
assert 'mkfunc' == build_class[1]
|
assert 'mkfunc' == build_class[1]
|
||||||
|
@@ -60,6 +60,15 @@ def customize_for_version36(self, version):
|
|||||||
'call_ex' : (
|
'call_ex' : (
|
||||||
'%c(%p)',
|
'%c(%p)',
|
||||||
(0, 'expr'), (1, 100)),
|
(0, 'expr'), (1, 100)),
|
||||||
|
'store_annotation': (
|
||||||
|
'%[1]{pattr}: %c',
|
||||||
|
0
|
||||||
|
),
|
||||||
|
'ann_assign_init_value': (
|
||||||
|
'%|%c = %p\n',
|
||||||
|
(-1, 'store_annotation'), (0, 'expr', 200)),
|
||||||
|
'ann_assign_no_init': (
|
||||||
|
'%|%c\n', (0, 'store_annotation')),
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -77,7 +86,7 @@ def customize_for_version36(self, version):
|
|||||||
self.call36_tuple(n)
|
self.call36_tuple(n)
|
||||||
first = 1
|
first = 1
|
||||||
sep = ', *'
|
sep = ', *'
|
||||||
elif n == 'LOAD_CONST':
|
elif n == 'LOAD_STR':
|
||||||
value = self.format_pos_args(n)
|
value = self.format_pos_args(n)
|
||||||
self.f.write(value)
|
self.f.write(value)
|
||||||
first = 1
|
first = 1
|
||||||
@@ -401,7 +410,7 @@ def customize_for_version36(self, version):
|
|||||||
self.n_except_suite_finalize = n_except_suite_finalize
|
self.n_except_suite_finalize = n_except_suite_finalize
|
||||||
|
|
||||||
def n_formatted_value(node):
|
def n_formatted_value(node):
|
||||||
if node[0] == 'LOAD_CONST':
|
if node[0] in ('LOAD_STR', 'LOAD_CONST'):
|
||||||
value = node[0].attr
|
value = node[0].attr
|
||||||
if isinstance(value, tuple):
|
if isinstance(value, tuple):
|
||||||
self.write(node[0].attr)
|
self.write(node[0].attr)
|
||||||
@@ -415,7 +424,7 @@ def customize_for_version36(self, version):
|
|||||||
def n_formatted_value_attr(node):
|
def n_formatted_value_attr(node):
|
||||||
f_conversion(node)
|
f_conversion(node)
|
||||||
fmt_node = node.data[3]
|
fmt_node = node.data[3]
|
||||||
if fmt_node == 'expr' and fmt_node[0] == 'LOAD_CONST':
|
if fmt_node == 'expr' and fmt_node[0] == 'LOAD_STR':
|
||||||
node.string = escape_format(fmt_node[0].attr)
|
node.string = escape_format(fmt_node[0].attr)
|
||||||
else:
|
else:
|
||||||
node.string = fmt_node
|
node.string = fmt_node
|
||||||
@@ -424,7 +433,7 @@ def customize_for_version36(self, version):
|
|||||||
|
|
||||||
def f_conversion(node):
|
def f_conversion(node):
|
||||||
fmt_node = node.data[1]
|
fmt_node = node.data[1]
|
||||||
if fmt_node == 'expr' and fmt_node[0] == 'LOAD_CONST':
|
if fmt_node == 'expr' and fmt_node[0] == 'LOAD_STR':
|
||||||
data = fmt_node[0].attr
|
data = fmt_node[0].attr
|
||||||
else:
|
else:
|
||||||
data = fmt_node.attr
|
data = fmt_node.attr
|
||||||
@@ -482,11 +491,11 @@ def customize_for_version36(self, version):
|
|||||||
else:
|
else:
|
||||||
# {{ and }} in Python source-code format strings mean
|
# {{ and }} in Python source-code format strings mean
|
||||||
# { and } respectively. But only when *not* part of a
|
# { and } respectively. But only when *not* part of a
|
||||||
# formatted value. However in the LOAD_CONST
|
# formatted value. However in the LOAD_STR
|
||||||
# bytecode, the escaping of the braces has been
|
# bytecode, the escaping of the braces has been
|
||||||
# removed. So we need to put back the braces escaping in
|
# removed. So we need to put back the braces escaping in
|
||||||
# reconstructing the source.
|
# reconstructing the source.
|
||||||
assert expr[0] == 'LOAD_CONST'
|
assert expr[0] == 'LOAD_STR'
|
||||||
value = value.replace("{", "{{").replace("}", "}}")
|
value = value.replace("{", "{{").replace("}", "}}")
|
||||||
|
|
||||||
# Remove leading quotes
|
# Remove leading quotes
|
||||||
|
@@ -424,6 +424,7 @@ class FragmentsWalker(pysource.SourceWalker, object):
|
|||||||
pass
|
pass
|
||||||
self.set_pos_info(node, start, len(self.f.getvalue()))
|
self.set_pos_info(node, start, len(self.f.getvalue()))
|
||||||
self.prune()
|
self.prune()
|
||||||
|
n_LOAD_STR = n_LOAD_CONST
|
||||||
|
|
||||||
def n_exec_stmt(self, node):
|
def n_exec_stmt(self, node):
|
||||||
"""
|
"""
|
||||||
|
@@ -85,6 +85,12 @@ def make_function3_annotate(self, node, is_lambda, nested=1,
|
|||||||
annotate_argc = 0
|
annotate_argc = 0
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
annotate_dict = {}
|
||||||
|
|
||||||
|
for name in annotate_args.keys():
|
||||||
|
n = self.traverse(annotate_args[name], indent='')
|
||||||
|
annotate_dict[name] = n
|
||||||
|
|
||||||
if 3.0 <= self.version <= 3.2:
|
if 3.0 <= self.version <= 3.2:
|
||||||
lambda_index = -2
|
lambda_index = -2
|
||||||
elif 3.03 <= self.version:
|
elif 3.03 <= self.version:
|
||||||
@@ -103,7 +109,11 @@ def make_function3_annotate(self, node, is_lambda, nested=1,
|
|||||||
|
|
||||||
# add defaults values to parameter names
|
# add defaults values to parameter names
|
||||||
argc = code.co_argcount
|
argc = code.co_argcount
|
||||||
|
kwonlyargcount = code.co_kwonlyargcount
|
||||||
|
|
||||||
paramnames = list(code.co_varnames[:argc])
|
paramnames = list(code.co_varnames[:argc])
|
||||||
|
if kwonlyargcount > 0:
|
||||||
|
kwargs = list(code.co_varnames[argc:argc+kwonlyargcount])
|
||||||
|
|
||||||
try:
|
try:
|
||||||
ast = self.build_ast(code._tokens,
|
ast = self.build_ast(code._tokens,
|
||||||
@@ -137,14 +147,8 @@ def make_function3_annotate(self, node, is_lambda, nested=1,
|
|||||||
for param in paramnames[:i]:
|
for param in paramnames[:i]:
|
||||||
self.write(suffix, param)
|
self.write(suffix, param)
|
||||||
suffix = ', '
|
suffix = ', '
|
||||||
if param in annotate_tuple[0].attr:
|
if param in annotate_dict:
|
||||||
# p = [x for x in annotate_tuple[0].attr].index(param)
|
self.write(': %s' % annotate_dict[param])
|
||||||
l = []
|
|
||||||
for x in annotate_tuple[0].attr:
|
|
||||||
l.append(x)
|
|
||||||
p = l.index(param)
|
|
||||||
self.write(': ')
|
|
||||||
self.preorder(node[p])
|
|
||||||
if (line_number != self.line_number):
|
if (line_number != self.line_number):
|
||||||
suffix = ",\n" + indent
|
suffix = ",\n" + indent
|
||||||
line_number = self.line_number
|
line_number = self.line_number
|
||||||
@@ -184,17 +188,16 @@ def make_function3_annotate(self, node, is_lambda, nested=1,
|
|||||||
|
|
||||||
|
|
||||||
if code_has_star_arg(code):
|
if code_has_star_arg(code):
|
||||||
star_arg = code.co_varnames[argc + kw_pairs]
|
star_arg = code.co_varnames[argc + kwonlyargcount]
|
||||||
|
if annotate_dict and star_arg in annotate_dict:
|
||||||
|
self.write(suffix, '*%s: %s' % (star_arg, annotate_dict[star_arg]))
|
||||||
|
else:
|
||||||
self.write(suffix, '*%s' % star_arg)
|
self.write(suffix, '*%s' % star_arg)
|
||||||
if star_arg in annotate_tuple[0].attr:
|
|
||||||
p = annotate_tuple[0].attr.index(star_arg) + pos_args + kw_args
|
|
||||||
self.write(': ')
|
|
||||||
self.preorder(node[p])
|
|
||||||
argc += 1
|
argc += 1
|
||||||
|
|
||||||
# self.println(indent, '#flags:\t', int(code.co_flags))
|
# self.println(indent, '#flags:\t', int(code.co_flags))
|
||||||
ends_in_comma = False
|
ends_in_comma = False
|
||||||
if kw_args + annotate_argc > 0:
|
if kwonlyargcount > 0:
|
||||||
if no_paramnames:
|
if no_paramnames:
|
||||||
if not code_has_star_arg(code):
|
if not code_has_star_arg(code):
|
||||||
if argc > 0:
|
if argc > 0:
|
||||||
@@ -205,46 +208,51 @@ def make_function3_annotate(self, node, is_lambda, nested=1,
|
|||||||
else:
|
else:
|
||||||
self.write(", ")
|
self.write(", ")
|
||||||
ends_in_comma = True
|
ends_in_comma = True
|
||||||
|
|
||||||
kwargs = node[1]
|
|
||||||
last = len(kwargs)-1
|
|
||||||
i = 0
|
|
||||||
for n in node[1]:
|
|
||||||
if n == 'kwarg':
|
|
||||||
if argc > 0 and not ends_in_comma:
|
|
||||||
self.write(', ')
|
|
||||||
if (line_number != self.line_number):
|
|
||||||
self.write("\n" + indent)
|
|
||||||
line_number = self.line_number
|
|
||||||
kn = n[0].pattr
|
|
||||||
if kn in annotate_tuple[0].attr:
|
|
||||||
p = annotate_tuple[0].attr.index(star_arg) + pos_args + kw_args
|
|
||||||
self.write('%s: ' % kn)
|
|
||||||
self.preorder(node[p])
|
|
||||||
self.write('=')
|
|
||||||
else:
|
else:
|
||||||
self.write('%s=' % kn)
|
if argc > 0:
|
||||||
self.preorder(n[1])
|
|
||||||
if i < last:
|
|
||||||
self.write(', ')
|
self.write(', ')
|
||||||
ends_in_comma = True
|
ends_in_comma = True
|
||||||
|
|
||||||
|
kw_args = [None] * kwonlyargcount
|
||||||
|
|
||||||
|
for n in node:
|
||||||
|
if n == 'kwargs':
|
||||||
|
n = n[0]
|
||||||
|
if n == 'kwarg':
|
||||||
|
name = eval(n[0].pattr)
|
||||||
|
idx = kwargs.index(name)
|
||||||
|
default = self.traverse(n[1], indent='')
|
||||||
|
if annotate_dict and name in annotate_dict:
|
||||||
|
kw_args[idx] = '%s: %s=%s' % (name, annotate_dict[name], default)
|
||||||
else:
|
else:
|
||||||
ends_in_comma = False
|
kw_args[idx] = '%s=%s' % (name, default)
|
||||||
i += 1
|
|
||||||
pass
|
|
||||||
pass
|
pass
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
# handling other args
|
||||||
|
ann_other_kw = [c == None for c in kw_args]
|
||||||
|
for i, flag in enumerate(ann_other_kw):
|
||||||
|
if flag:
|
||||||
|
n = kwargs[i]
|
||||||
|
if n in annotate_dict:
|
||||||
|
kw_args[i] = "%s: %s" %(n, annotate_dict[n])
|
||||||
|
else:
|
||||||
|
kw_args[i] = "%s" % n
|
||||||
|
|
||||||
|
self.write(', '.join(kw_args), ', ')
|
||||||
|
|
||||||
|
else:
|
||||||
|
if argc == 0:
|
||||||
|
ends_in_comma = True
|
||||||
|
|
||||||
if code_has_star_star_arg(code):
|
if code_has_star_star_arg(code):
|
||||||
if argc > 0 and not ends_in_comma:
|
if not ends_in_comma:
|
||||||
self.write(', ')
|
self.write(', ')
|
||||||
star_star_arg = code.co_varnames[argc + kw_pairs]
|
star_star_arg = code.co_varnames[argc + kwonlyargcount]
|
||||||
|
if annotate_dict and star_star_arg in annotate_dict:
|
||||||
|
self.write('**%s: %s' % (star_star_arg, annotate_dict[star_star_arg]))
|
||||||
|
else:
|
||||||
self.write('**%s' % star_star_arg)
|
self.write('**%s' % star_star_arg)
|
||||||
if star_star_arg in annotate_tuple[0].attr:
|
|
||||||
p = annotate_tuple[0].attr.index(star_star_arg) + pos_args + kw_args
|
|
||||||
self.write(': ')
|
|
||||||
self.preorder(node[p])
|
|
||||||
|
|
||||||
if is_lambda:
|
if is_lambda:
|
||||||
self.write(": ")
|
self.write(": ")
|
||||||
@@ -669,7 +677,11 @@ def make_function3(self, node, is_lambda, nested=1, code_node=None):
|
|||||||
|
|
||||||
# add defaults values to parameter names
|
# add defaults values to parameter names
|
||||||
argc = code.co_argcount
|
argc = code.co_argcount
|
||||||
|
kwonlyargcount = code.co_kwonlyargcount
|
||||||
|
|
||||||
paramnames = list(scanner_code.co_varnames[:argc])
|
paramnames = list(scanner_code.co_varnames[:argc])
|
||||||
|
if kwonlyargcount > 0:
|
||||||
|
kwargs = list(scanner_code.co_varnames[argc:argc+kwonlyargcount])
|
||||||
|
|
||||||
# defaults are for last n parameters, thus reverse
|
# defaults are for last n parameters, thus reverse
|
||||||
paramnames.reverse();
|
paramnames.reverse();
|
||||||
@@ -692,6 +704,9 @@ def make_function3(self, node, is_lambda, nested=1, code_node=None):
|
|||||||
else:
|
else:
|
||||||
kw_pairs = 0
|
kw_pairs = 0
|
||||||
|
|
||||||
|
i = len(paramnames) - len(defparams)
|
||||||
|
no_paramnames = len(paramnames[:i]) == 0
|
||||||
|
|
||||||
# build parameters
|
# build parameters
|
||||||
params = []
|
params = []
|
||||||
if defparams:
|
if defparams:
|
||||||
@@ -715,9 +730,9 @@ def make_function3(self, node, is_lambda, nested=1, code_node=None):
|
|||||||
|
|
||||||
if code_has_star_arg(code):
|
if code_has_star_arg(code):
|
||||||
if self.version > 3.0:
|
if self.version > 3.0:
|
||||||
star_arg = code.co_varnames[argc + kw_pairs]
|
star_arg = code.co_varnames[argc + kwonlyargcount]
|
||||||
if star_arg in annotate_dict:
|
if annotate_dict and star_arg in annotate_dict:
|
||||||
params.append('*%s: %s' %(star_arg, annotate_dict[star_arg]))
|
params.append('*%s: %s' % (star_arg, annotate_dict[star_arg]))
|
||||||
else:
|
else:
|
||||||
params.append('*%s' % star_arg)
|
params.append('*%s' % star_arg)
|
||||||
else:
|
else:
|
||||||
@@ -744,11 +759,16 @@ def make_function3(self, node, is_lambda, nested=1, code_node=None):
|
|||||||
ast[-1] = ast_expr
|
ast[-1] = ast_expr
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
|
# FIXME: add annotations here
|
||||||
self.write("(", ", ".join(params))
|
self.write("(", ", ".join(params))
|
||||||
# self.println(indent, '#flags:\t', int(code.co_flags))
|
# self.println(indent, '#flags:\t', int(code.co_flags))
|
||||||
|
|
||||||
|
# FIXME: Could we remove ends_in_comma and its tests if we just
|
||||||
|
# created a parameter list and at the very end did a join on that?
|
||||||
|
# Unless careful, We might lose line breaks though.
|
||||||
ends_in_comma = False
|
ends_in_comma = False
|
||||||
if kw_args > 0:
|
if kwonlyargcount > 0:
|
||||||
|
if no_paramnames:
|
||||||
if not (4 & code.co_flags):
|
if not (4 & code.co_flags):
|
||||||
if argc > 0:
|
if argc > 0:
|
||||||
self.write(", *, ")
|
self.write(", *, ")
|
||||||
@@ -758,6 +778,10 @@ def make_function3(self, node, is_lambda, nested=1, code_node=None):
|
|||||||
else:
|
else:
|
||||||
self.write(", ")
|
self.write(", ")
|
||||||
ends_in_comma = True
|
ends_in_comma = True
|
||||||
|
else:
|
||||||
|
if argc > 0:
|
||||||
|
self.write(', ')
|
||||||
|
ends_in_comma = True
|
||||||
|
|
||||||
# FIXME: this is not correct for 3.5. or 3.6 (which works different)
|
# FIXME: this is not correct for 3.5. or 3.6 (which works different)
|
||||||
# and 3.7?
|
# and 3.7?
|
||||||
@@ -767,7 +791,7 @@ def make_function3(self, node, is_lambda, nested=1, code_node=None):
|
|||||||
i = 0
|
i = 0
|
||||||
for n in node[0]:
|
for n in node[0]:
|
||||||
if n == 'kwarg':
|
if n == 'kwarg':
|
||||||
self.write('%s=' % n[0].pattr)
|
self.write('%s=' % n[0].attr)
|
||||||
self.preorder(n[1])
|
self.preorder(n[1])
|
||||||
if i < last:
|
if i < last:
|
||||||
self.write(', ')
|
self.write(', ')
|
||||||
@@ -796,7 +820,7 @@ def make_function3(self, node, is_lambda, nested=1, code_node=None):
|
|||||||
# argcount = co.co_argcount
|
# argcount = co.co_argcount
|
||||||
# kwonlyargcount = co.co_kwonlyargcount
|
# kwonlyargcount = co.co_kwonlyargcount
|
||||||
|
|
||||||
free_tup = annotate_dict = kw_dict = default_tup = None
|
free_tup = ann_dict = kw_dict = default_tup = None
|
||||||
fn_bits = node[-1].attr
|
fn_bits = node[-1].attr
|
||||||
index = -4 # Skip over:
|
index = -4 # Skip over:
|
||||||
# MAKE_FUNCTION,
|
# MAKE_FUNCTION,
|
||||||
@@ -806,7 +830,7 @@ def make_function3(self, node, is_lambda, nested=1, code_node=None):
|
|||||||
free_tup = node[index]
|
free_tup = node[index]
|
||||||
index -= 1
|
index -= 1
|
||||||
if fn_bits[-2]:
|
if fn_bits[-2]:
|
||||||
annotate_dict = node[index]
|
ann_dict = node[index]
|
||||||
index -= 1
|
index -= 1
|
||||||
if fn_bits[-3]:
|
if fn_bits[-3]:
|
||||||
kw_dict = node[index]
|
kw_dict = node[index]
|
||||||
@@ -818,6 +842,8 @@ def make_function3(self, node, is_lambda, nested=1, code_node=None):
|
|||||||
kw_dict = kw_dict[0]
|
kw_dict = kw_dict[0]
|
||||||
|
|
||||||
# FIXME: handle free_tup, annotate_dict, and default_tup
|
# FIXME: handle free_tup, annotate_dict, and default_tup
|
||||||
|
kw_args = [None] * kwonlyargcount
|
||||||
|
|
||||||
if kw_dict:
|
if kw_dict:
|
||||||
assert kw_dict == 'dict'
|
assert kw_dict == 'dict'
|
||||||
defaults = [self.traverse(n, indent='') for n in kw_dict[:-2]]
|
defaults = [self.traverse(n, indent='') for n in kw_dict[:-2]]
|
||||||
@@ -826,20 +852,40 @@ def make_function3(self, node, is_lambda, nested=1, code_node=None):
|
|||||||
sep = ''
|
sep = ''
|
||||||
# FIXME: possibly handle line breaks
|
# FIXME: possibly handle line breaks
|
||||||
for i, n in enumerate(names):
|
for i, n in enumerate(names):
|
||||||
self.write(sep)
|
idx = kwargs.index(n)
|
||||||
self.write("%s=%s" % (n, defaults[i]))
|
if annotate_dict and n in annotate_dict:
|
||||||
sep = ', '
|
t = "%s: %s=%s" % (n, annotate_dict[n], defaults[i])
|
||||||
ends_in_comma = False
|
else:
|
||||||
pass
|
t = "%s=%s" % (n, defaults[i])
|
||||||
|
kw_args[idx] = t
|
||||||
pass
|
pass
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
# handle others
|
||||||
|
if ann_dict:
|
||||||
|
ann_other_kw = [c == None for c in kw_args]
|
||||||
|
|
||||||
|
for i, flag in enumerate(ann_other_kw):
|
||||||
|
if flag:
|
||||||
|
n = kwargs[i]
|
||||||
|
if n in annotate_dict:
|
||||||
|
kw_args[i] = "%s: %s" %(n, annotate_dict[n])
|
||||||
|
else:
|
||||||
|
kw_args[i] = "%s" % n
|
||||||
|
self.write(', '.join(kw_args))
|
||||||
|
ends_in_comma = False
|
||||||
|
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
if argc == 0:
|
||||||
|
ends_in_comma = True
|
||||||
|
|
||||||
if code_has_star_star_arg(code):
|
if code_has_star_star_arg(code):
|
||||||
if argc > 0 and not ends_in_comma:
|
if not ends_in_comma:
|
||||||
self.write(', ')
|
self.write(', ')
|
||||||
star_star_arg = code.co_varnames[argc + kw_pairs]
|
star_star_arg = code.co_varnames[argc + kwonlyargcount]
|
||||||
if annotate_dict and star_star_arg and star_star_arg in annotate_dict:
|
if annotate_dict and star_star_arg in annotate_dict:
|
||||||
self.write('**%s: %s' %(star_star_arg, annotate_dict[star_star_arg]))
|
self.write('**%s: %s' % (star_star_arg, annotate_dict[star_star_arg]))
|
||||||
else:
|
else:
|
||||||
self.write('**%s' % star_star_arg)
|
self.write('**%s' % star_star_arg)
|
||||||
|
|
||||||
|
@@ -1436,7 +1436,7 @@ class SourceWalker(GenericASTTraversal, object):
|
|||||||
n = len(node) - 1
|
n = len(node) - 1
|
||||||
if node.kind != 'expr':
|
if node.kind != 'expr':
|
||||||
if node == 'kwarg':
|
if node == 'kwarg':
|
||||||
self.template_engine(('(%[0]{pattr}=%c)', 1), node)
|
self.template_engine(('(%[0]{attr}=%c)', 1), node)
|
||||||
return
|
return
|
||||||
|
|
||||||
kwargs = None
|
kwargs = None
|
||||||
@@ -2107,6 +2107,7 @@ class SourceWalker(GenericASTTraversal, object):
|
|||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
have_qualname = False
|
have_qualname = False
|
||||||
if self.version < 3.0:
|
if self.version < 3.0:
|
||||||
# Should we ditch this in favor of the "else" case?
|
# Should we ditch this in favor of the "else" case?
|
||||||
@@ -2122,7 +2123,7 @@ class SourceWalker(GenericASTTraversal, object):
|
|||||||
# which are not simple classes like the < 3 case.
|
# which are not simple classes like the < 3 case.
|
||||||
try:
|
try:
|
||||||
if (first_stmt[0] == 'assign' and
|
if (first_stmt[0] == 'assign' and
|
||||||
first_stmt[0][0][0] == 'LOAD_CONST' and
|
first_stmt[0][0][0] == 'LOAD_STR' and
|
||||||
first_stmt[0][1] == 'store' and
|
first_stmt[0][1] == 'store' and
|
||||||
first_stmt[0][1][0] == Token('STORE_NAME', pattr='__qualname__')):
|
first_stmt[0][1][0] == Token('STORE_NAME', pattr='__qualname__')):
|
||||||
have_qualname = True
|
have_qualname = True
|
||||||
@@ -2333,13 +2334,28 @@ def code_deparse(co, out=sys.stdout, version=None, debug_opts=DEFAULT_DEBUG_OPTS
|
|||||||
|
|
||||||
assert not nonlocals
|
assert not nonlocals
|
||||||
|
|
||||||
|
if version >= 3.0:
|
||||||
|
load_op = 'LOAD_STR'
|
||||||
|
else:
|
||||||
|
load_op = 'LOAD_CONST'
|
||||||
|
|
||||||
# convert leading '__doc__ = "..." into doc string
|
# convert leading '__doc__ = "..." into doc string
|
||||||
try:
|
try:
|
||||||
if deparsed.ast[0][0] == ASSIGN_DOC_STRING(co.co_consts[0]):
|
stmts = deparsed.ast
|
||||||
|
first_stmt = stmts[0][0]
|
||||||
|
if version >= 3.6:
|
||||||
|
if first_stmt[0] == 'SETUP_ANNOTATIONS':
|
||||||
|
del stmts[0]
|
||||||
|
assert stmts[0] == 'sstmt'
|
||||||
|
# Nuke sstmt
|
||||||
|
first_stmt = stmts[0][0]
|
||||||
|
pass
|
||||||
|
pass
|
||||||
|
if first_stmt == ASSIGN_DOC_STRING(co.co_consts[0], load_op):
|
||||||
print_docstring(deparsed, '', co.co_consts[0])
|
print_docstring(deparsed, '', co.co_consts[0])
|
||||||
del deparsed.ast[0]
|
del stmts[0]
|
||||||
if deparsed.ast[-1] == RETURN_NONE:
|
if stmts[-1] == RETURN_NONE:
|
||||||
deparsed.ast.pop() # remove last node
|
stmts.pop() # remove last node
|
||||||
# todo: if empty, add 'pass'
|
# todo: if empty, add 'pass'
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
@@ -12,4 +12,4 @@
|
|||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# 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 bash as
|
||||||
# well as importing into Python
|
# well as importing into Python
|
||||||
VERSION='3.3.3' # noqa
|
VERSION='3.3.4' # noqa
|
||||||
|
Reference in New Issue
Block a user