From 44d7cbcf6f883afc14e4b6982b622a48d7b04626 Mon Sep 17 00:00:00 2001 From: rocky Date: Fri, 7 Jun 2019 05:54:26 -0400 Subject: [PATCH 01/32] LOAD_CONST->LOAD_STR for Python 3.x --- pytest/test_grammar.py | 2 +- uncompyle6/parsers/parse3.py | 52 ++++++++++++++--------------- uncompyle6/parsers/parse36.py | 4 +-- uncompyle6/scanners/scanner3.py | 2 ++ uncompyle6/semantics/consts.py | 9 ++--- uncompyle6/semantics/customize3.py | 6 ++-- uncompyle6/semantics/customize36.py | 12 +++---- uncompyle6/semantics/fragments.py | 1 + 8 files changed, 45 insertions(+), 43 deletions(-) diff --git a/pytest/test_grammar.py b/pytest/test_grammar.py index 73cda0ce..fd2771c9 100644 --- a/pytest/test_grammar.py +++ b/pytest/test_grammar.py @@ -88,7 +88,7 @@ def test_grammar(): COME_FROM_EXCEPT_CLAUSE COME_FROM_LOOP COME_FROM_WITH COME_FROM_FINALLY ELSE - LOAD_GENEXPR LOAD_ASSERT LOAD_SETCOMP LOAD_DICTCOMP + LOAD_GENEXPR LOAD_ASSERT LOAD_SETCOMP LOAD_DICTCOMP LOAD_STR LAMBDA_MARKER RETURN_END_IF RETURN_END_IF_LAMBDA RETURN_VALUE_LAMBDA RETURN_LAST """.split()) diff --git a/uncompyle6/parsers/parse3.py b/uncompyle6/parsers/parse3.py index 24eac0ab..757c19c5 100644 --- a/uncompyle6/parsers/parse3.py +++ b/uncompyle6/parsers/parse3.py @@ -112,10 +112,9 @@ class Python3Parser(PythonParser): continues ::= continue - kwarg ::= LOAD_CONST expr + kwarg ::= LOAD_STR expr kwargs ::= kwarg+ - classdef ::= build_class store # FIXME: we need to add these because don't detect this properly @@ -394,11 +393,12 @@ class Python3Parser(PythonParser): def p_generator_exp3(self, args): ''' 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): """ + expr ::= LOAD_STR expr ::= conditionalnot conditionalnot ::= expr jmp_true expr jump_forward_else expr COME_FROM @@ -441,7 +441,7 @@ class Python3Parser(PythonParser): break pass 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" call_fn_tok = None for i in range(i, len(tokens)): @@ -515,13 +515,13 @@ class Python3Parser(PythonParser): self.add_unique_rule(rule, token.kind, uniq_param, 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. """ if self.version >= 3.3: - new_rule = rule % (('LOAD_CONST ') * 1) + new_rule = rule % (('LOAD_STR ') * 1) else: - new_rule = rule % (('LOAD_CONST ') * 0) + new_rule = rule % (('LOAD_STR ') * 0) self.add_unique_rule(new_rule, opname, attr, customize) def customize_grammar_rules(self, tokens, customize): @@ -730,7 +730,7 @@ class Python3Parser(PythonParser): if opname == 'CALL_FUNCTION' and token.attr == 1: 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 classdefdeco1 ::= expr classdefdeco2 CALL_FUNCTION_1 """ @@ -849,7 +849,7 @@ class Python3Parser(PythonParser): # Note that 3.6+ doesn't do this, but we'll remove # this rule in parse36.py rule = """ - dict_comp ::= load_closure LOAD_DICTCOMP LOAD_CONST + dict_comp ::= load_closure LOAD_DICTCOMP LOAD_STR MAKE_CLOSURE_0 expr GET_ITER CALL_FUNCTION_1 """ @@ -902,10 +902,10 @@ class Python3Parser(PythonParser): rule = ('mkfunc ::= %s%sload_closure LOAD_CONST %s' % (kwargs_str, 'expr ' * args_pos, opname)) 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)) 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)) self.add_unique_rule(rule, opname, token.attr, customize) @@ -933,17 +933,17 @@ class Python3Parser(PythonParser): rule = ('mklambda ::= %s%s%s%s' % ('expr ' * stack_count, 'load_closure ' * closure, - 'BUILD_TUPLE_1 LOAD_LAMBDA LOAD_CONST ', + 'BUILD_TUPLE_1 LOAD_LAMBDA LOAD_STR ', opname)) else: rule = ('mklambda ::= %s%s%s' % ('load_closure ' * closure, - 'LOAD_LAMBDA LOAD_CONST ', + 'LOAD_LAMBDA LOAD_STR ', opname)) self.add_unique_rule(rule, opname, token.attr, customize) else: - rule = ('mklambda ::= %sLOAD_LAMBDA LOAD_CONST %s' % + rule = ('mklambda ::= %sLOAD_LAMBDA LOAD_STR %s' % (('expr ' * stack_count), opname)) self.add_unique_rule(rule, opname, token.attr, customize) @@ -951,7 +951,7 @@ class Python3Parser(PythonParser): rule = ('mkfunc ::= %s%s%s%s' % ('expr ' * stack_count, 'load_closure ' * closure, - 'LOAD_CONST ' * 2, + 'LOAD_CONST LOAD_STR ', opname)) self.add_unique_rule(rule, opname, token.attr, customize) @@ -1033,17 +1033,17 @@ class Python3Parser(PythonParser): elif self.version == 3.3: # positional args after keyword args rule = ('mkfunc ::= %s %s%s%s' % - (kwargs, 'pos_arg ' * args_pos, 'LOAD_CONST '*2, + (kwargs, 'pos_arg ' * args_pos, 'LOAD_CONST LOAD_STR ', opname)) elif self.version > 3.5: # positional args before keyword args rule = ('mkfunc ::= %s%s %s%s' % - ('pos_arg ' * args_pos, kwargs, 'LOAD_CONST '*2, + ('pos_arg ' * args_pos, kwargs, 'LOAD_CONST LOAD_STR ', opname)) elif self.version > 3.3: # positional args before keyword args rule = ('mkfunc ::= %s%s %s%s' % - ('pos_arg ' * args_pos, kwargs, 'LOAD_CONST '*2, + ('pos_arg ' * args_pos, kwargs, 'LOAD_CONST LOAD_STR ', opname)) else: rule = ('mkfunc ::= %s%sexpr %s' % @@ -1052,22 +1052,22 @@ class Python3Parser(PythonParser): if opname.startswith('MAKE_FUNCTION_A'): 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)), ('call ' * (annotate_args-1)), opname)) 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)), ('annotate_arg ' * (annotate_args-1)), opname)) if self.version >= 3.3: # 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. # Yes this is a little hacky - rule = ('mkfunc_annotate ::= %s%sannotate_tuple LOAD_CONST LOAD_CONST EXTENDED_ARG %s' % + rule = ('mkfunc_annotate ::= %s%sannotate_tuple LOAD_CONST LOAD_STR EXTENDED_ARG %s' % (('pos_arg ' * (args_pos)), ('call ' * (annotate_args-1)), opname)) self.add_unique_rule(rule, opname, token.attr, customize) - rule = ('mkfunc_annotate ::= %s%sannotate_tuple LOAD_CONST LOAD_CONST EXTENDED_ARG %s' % + rule = ('mkfunc_annotate ::= %s%sannotate_tuple LOAD_CONST LOAD_STR EXTENDED_ARG %s' % (('pos_arg ' * (args_pos)), ('annotate_arg ' * (annotate_args-1)), opname)) else: @@ -1143,7 +1143,8 @@ class Python3Parser(PythonParser): self.check_reduce['while1elsestmt'] = 'noAST' self.check_reduce['ifelsestmt'] = 'AST' self.check_reduce['annotate_tuple'] = 'noAST' - self.check_reduce['kwarg'] = 'noAST' + if not PYTHON3: + self.check_reduce['kwarg'] = 'noAST' if self.version < 3.6: # 3.6+ can remove a JUMP_FORWARD which messes up our testing here self.check_reduce['try_except'] = 'AST' @@ -1160,10 +1161,7 @@ class Python3Parser(PythonParser): return not isinstance(tokens[first].attr, tuple) elif lhs == 'kwarg': 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': n = len(tokens) diff --git a/uncompyle6/parsers/parse36.py b/uncompyle6/parsers/parse36.py index f87da84b..abb80cf4 100644 --- a/uncompyle6/parsers/parse36.py +++ b/uncompyle6/parsers/parse36.py @@ -202,14 +202,14 @@ class Python36Parser(Python35Parser): if 'LOAD_DICTCOMP' in self.seen_ops: # Is there something general going on here? rule = """ - dict_comp ::= load_closure LOAD_DICTCOMP LOAD_CONST + dict_comp ::= load_closure LOAD_DICTCOMP LOAD_STR MAKE_FUNCTION_8 expr GET_ITER CALL_FUNCTION_1 """ self.addRule(rule, nop_func) elif 'LOAD_SETCOMP' in self.seen_ops: rule = """ - set_comp ::= load_closure LOAD_SETCOMP LOAD_CONST + set_comp ::= load_closure LOAD_SETCOMP LOAD_STR MAKE_FUNCTION_8 expr GET_ITER CALL_FUNCTION_1 """ diff --git a/uncompyle6/scanners/scanner3.py b/uncompyle6/scanners/scanner3.py index 9eeabc7c..491ac49d 100644 --- a/uncompyle6/scanners/scanner3.py +++ b/uncompyle6/scanners/scanner3.py @@ -310,6 +310,8 @@ class Scanner3(Scanner): # pattr = 'code_object @ 0x%x %s->%s' %\ # (id(const), const.co_filename, const.co_name) pattr = '' + elif isinstance(const, str): + opname = 'LOAD_STR' else: if isinstance(inst.arg, int) and inst.arg < len(co.co_consts): argval, _ = _get_const_info(inst.arg, co.co_consts) diff --git a/uncompyle6/semantics/consts.py b/uncompyle6/semantics/consts.py index 10707eea..3585920f 100644 --- a/uncompyle6/semantics/consts.py +++ b/uncompyle6/semantics/consts.py @@ -131,7 +131,7 @@ PASS = SyntaxTree('stmts', ASSIGN_DOC_STRING = lambda doc_string: \ SyntaxTree('stmt', [ SyntaxTree('assign', - [ SyntaxTree('expr', [ Token('LOAD_CONST', pattr=doc_string) ]), + [ SyntaxTree('expr', [ Token('LOAD_STR', pattr=doc_string) ]), SyntaxTree('store', [ Token('STORE_NAME', pattr='__doc__')]) ])]) @@ -221,8 +221,9 @@ TABLE_DIRECT = { 'IMPORT_FROM': ( '%{pattr}', ), 'attribute': ( '%c.%[1]{pattr}', (0, 'expr')), - 'LOAD_FAST': ( '%{pattr}', ), - 'LOAD_NAME': ( '%{pattr}', ), + 'LOAD_STR': ( '%{pattr}', ), + 'LOAD_FAST': ( '%{pattr}', ), + 'LOAD_NAME': ( '%{pattr}', ), 'LOAD_CLASSNAME': ( '%{pattr}', ), 'LOAD_GLOBAL': ( '%{pattr}', ), 'LOAD_DEREF': ( '%{pattr}', ), @@ -317,7 +318,7 @@ TABLE_DIRECT = { 'mkfuncdeco0': ( '%|def %c\n', 0), 'classdefdeco': ( '\n\n%c', 0), 'classdefdeco1': ( '%|@%c\n%c', 0, 1), - 'kwarg': ( '%[0]{pattr}=%c', 1), + 'kwarg': ( '%[0]{attr}=%c', 1), 'kwargs': ( '%D', (0, maxint, ', ') ), 'kwargs1': ( '%D', (0, maxint, ', ') ), diff --git a/uncompyle6/semantics/customize3.py b/uncompyle6/semantics/customize3.py index 83a69bb9..7eabfd58 100644 --- a/uncompyle6/semantics/customize3.py +++ b/uncompyle6/semantics/customize3.py @@ -62,11 +62,11 @@ def customize_for_version3(self, version): subclass_info = None if node == 'classdefdeco2': if self.version >= 3.6: - class_name = node[1][1].pattr + class_name = node[1][1].attr elif self.version <= 3.3: - class_name = node[2][0].pattr + class_name = node[2][0].attr else: - class_name = node[1][2].pattr + class_name = node[1][2].attr build_class = node else: build_class = node[0] diff --git a/uncompyle6/semantics/customize36.py b/uncompyle6/semantics/customize36.py index 2245e648..97191f90 100644 --- a/uncompyle6/semantics/customize36.py +++ b/uncompyle6/semantics/customize36.py @@ -77,7 +77,7 @@ def customize_for_version36(self, version): self.call36_tuple(n) first = 1 sep = ', *' - elif n == 'LOAD_CONST': + elif n == 'LOAD_STR': value = self.format_pos_args(n) self.f.write(value) first = 1 @@ -401,7 +401,7 @@ def customize_for_version36(self, version): self.n_except_suite_finalize = n_except_suite_finalize def n_formatted_value(node): - if node[0] == 'LOAD_CONST': + if node[0] in ('LOAD_STR', 'LOAD_CONST'): value = node[0].attr if isinstance(value, tuple): self.write(node[0].attr) @@ -415,7 +415,7 @@ def customize_for_version36(self, version): def n_formatted_value_attr(node): f_conversion(node) 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) else: node.string = fmt_node @@ -424,7 +424,7 @@ def customize_for_version36(self, version): def f_conversion(node): 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 else: data = fmt_node.attr @@ -482,11 +482,11 @@ def customize_for_version36(self, version): else: # {{ and }} in Python source-code format strings mean # { 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 # removed. So we need to put back the braces escaping in # reconstructing the source. - assert expr[0] == 'LOAD_CONST' + assert expr[0] == 'LOAD_STR' value = value.replace("{", "{{").replace("}", "}}") # Remove leading quotes diff --git a/uncompyle6/semantics/fragments.py b/uncompyle6/semantics/fragments.py index 968a69cc..e385d347 100644 --- a/uncompyle6/semantics/fragments.py +++ b/uncompyle6/semantics/fragments.py @@ -421,6 +421,7 @@ class FragmentsWalker(pysource.SourceWalker, object): pass self.set_pos_info(node, start, len(self.f.getvalue())) self.prune() + n_LOAD_STR = n_LOAD_CONST def n_exec_stmt(self, node): """ From 59b012df6fda8702555a1dea36c3029712f8f2f7 Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 8 Jun 2019 11:01:58 -0400 Subject: [PATCH 02/32] localize LOAD_STR change to Python 3 --- uncompyle6/semantics/consts.py | 2 +- uncompyle6/semantics/customize3.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/uncompyle6/semantics/consts.py b/uncompyle6/semantics/consts.py index 3585920f..ee998f94 100644 --- a/uncompyle6/semantics/consts.py +++ b/uncompyle6/semantics/consts.py @@ -318,7 +318,7 @@ TABLE_DIRECT = { 'mkfuncdeco0': ( '%|def %c\n', 0), 'classdefdeco': ( '\n\n%c', 0), 'classdefdeco1': ( '%|@%c\n%c', 0, 1), - 'kwarg': ( '%[0]{attr}=%c', 1), + 'kwarg': ( '%[0]{pattr}=%c', 1), # Change when Python 2 does LOAD_STR 'kwargs': ( '%D', (0, maxint, ', ') ), 'kwargs1': ( '%D', (0, maxint, ', ') ), diff --git a/uncompyle6/semantics/customize3.py b/uncompyle6/semantics/customize3.py index 7eabfd58..ba8184bc 100644 --- a/uncompyle6/semantics/customize3.py +++ b/uncompyle6/semantics/customize3.py @@ -41,6 +41,7 @@ def customize_for_version3(self, version): 'importmultiple' : ( '%|import %c%c\n', 2, 3 ), 'import_cont' : ( ', %c', 2 ), + 'kwarg' : ( '%[0]{attr}=%c', 1), 'raise_stmt2' : ( '%|raise %c from %c\n', 0, 1), 'store_locals' : ( '%|# inspect.currentframe().f_locals = __locals__\n', ), 'withstmt' : ( '%|with %c:\n%+%c%-', 0, 3), From 9d47b9993267445e7c1dbda82b960e2187baafed Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 8 Jun 2019 11:40:48 -0400 Subject: [PATCH 03/32] Another LOAD_STR/CONST isolation in < 3.0 --- uncompyle6/semantics/consts.py | 4 ++-- uncompyle6/semantics/pysource.py | 7 ++++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/uncompyle6/semantics/consts.py b/uncompyle6/semantics/consts.py index ee998f94..95e9cc56 100644 --- a/uncompyle6/semantics/consts.py +++ b/uncompyle6/semantics/consts.py @@ -128,10 +128,10 @@ PASS = SyntaxTree('stmts', [ SyntaxTree('stmt', [ SyntaxTree('pass', [])])])]) -ASSIGN_DOC_STRING = lambda doc_string: \ +ASSIGN_DOC_STRING = lambda doc_string, doc_load: \ SyntaxTree('stmt', [ SyntaxTree('assign', - [ SyntaxTree('expr', [ Token('LOAD_STR', pattr=doc_string) ]), + [ SyntaxTree('expr', [ Token(doc_load, pattr=doc_string) ]), SyntaxTree('store', [ Token('STORE_NAME', pattr='__doc__')]) ])]) diff --git a/uncompyle6/semantics/pysource.py b/uncompyle6/semantics/pysource.py index 95a76cd1..cfa5453b 100644 --- a/uncompyle6/semantics/pysource.py +++ b/uncompyle6/semantics/pysource.py @@ -2331,9 +2331,14 @@ def code_deparse(co, out=sys.stdout, version=None, debug_opts=DEFAULT_DEBUG_OPTS assert not nonlocals + if version >= 3.0: + load_op = 'LOAD_STR' + else: + load_op = 'LOAD_CONST' + # convert leading '__doc__ = "..." into doc string try: - if deparsed.ast[0][0] == ASSIGN_DOC_STRING(co.co_consts[0]): + if deparsed.ast[0][0] == ASSIGN_DOC_STRING(co.co_consts[0], load_op): print_docstring(deparsed, '', co.co_consts[0]) del deparsed.ast[0] if deparsed.ast[-1] == RETURN_NONE: From c8fc6a704c12679b9f286c38a69c5e635a980d96 Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 9 Jun 2019 02:18:21 -0400 Subject: [PATCH 04/32] LOAD_CONST->LOAD_STR bugs and 3.4 kwargsonly --- test/bytecode_3.3_run/04_def_annotate.pyc | Bin 5605 -> 5605 bytes test/bytecode_3.4/04_def_annotate.pyc | Bin 1857 -> 0 bytes test/bytecode_3.4_run/04_def_annotate.pyc | Bin 3628 -> 0 bytes uncompyle6/parsers/parse3.py | 14 ++++---------- uncompyle6/semantics/customize3.py | 2 +- uncompyle6/semantics/make_function.py | 2 +- uncompyle6/semantics/pysource.py | 2 +- 7 files changed, 7 insertions(+), 13 deletions(-) delete mode 100644 test/bytecode_3.4/04_def_annotate.pyc delete mode 100644 test/bytecode_3.4_run/04_def_annotate.pyc diff --git a/test/bytecode_3.3_run/04_def_annotate.pyc b/test/bytecode_3.3_run/04_def_annotate.pyc index a04626597e395418acb9e551bc1ec173265ecd8b..7014aa44b53048722a2ea0e43c5cce970538c964 100644 GIT binary patch delta 15 XcmaE={ZyN69uF_q#%UYb?u!BdFun!a delta 15 WcmaE={ZyN69uF^9w8=)c`=S6W&;=p@ diff --git a/test/bytecode_3.4/04_def_annotate.pyc b/test/bytecode_3.4/04_def_annotate.pyc deleted file mode 100644 index 376e257550c059e9029de488497dc7fe805f93ae..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1857 zcmb7EPj4GV6o2DguN}upX+oPnrtLzjiWMR)0!~y_)F7cAa6#??`7&DXjGZm(9Wyga z8mpX=574i{2jVhUP8{F^aN@mL$90+_#AxTu?7VsJ{ocR%tGm(p{>h&|d>a7#4lARB z`$L@OHzWc;;>SSX*8mZ~>k!TXhPV$wG*`X|L<>Y4#2SbWyl%jG1j7KtI*2Za4G^1N z9M2hvOBBE6HNOYqI-Eh{(#h79lWjT??}NAj;^qa6CVV4yK>Om3F+2G)p#rs=)|>UnJGcLNNTOLajjCG6nQCKD=UOW(1T5t>mBwy@{JTu9xDe z$r<$a1}<;m@KNdF`65a#w5K!l@K_eJdDkAxSmZzFLY88F|KiUm9e+HnjEzUcrXVbk zmhr=6ev9sDX%KL%#Kcx)lP+a7xx*?g!*P0E#WWr+f}@8p;`Bq5}L+ zf3ZA`-61K$18n})J1`&6C2lSp;i}{(Kc1+vI6Zh&s4OkaV}AwPt~oALYF%Kgb^&!_ z!-Yl`W4({s->M+D_pf@X%`Xsr`o9qMG45^7%XBI^cOA~L<0|ZV?z)`+RHa4D(G>9& zJiZL5sq`KaDtB+b%l!YP3ZNo9qzj)QS*-vW`1f>~J$z&Vu$_kZK!=!)rduCWvzgM? zJjKW?-jLOHq`j|)D=B39Hu6>g`=_AAImVcCs>M27jrsP9je`ZhpF}z)`45SFgv4#8 zBg|2n*{QV0O6Xg}xkuzpN4yEjU1U%OeQk9c0n>Dntk+^a5~IHJPmv2no>|{H!**5X zma;r-Qx=c#?eqa1uJP}*vMN)B*Yqx&>-nwjqD{`xV!^Lu`v|CipszIxL~ z^c!Uw*0hWs{%R3vqCoz&qCkj!?mwp$3i|?^h@;%UH#58y~d1OA5YCDJ!Y-%JBFN&zByi+NyJGC}C7 zL=}ggTNDmj(MkFqDbS|gCVhwWUD~%*i~lxNksx<@f2nos%k&sB;d9dWI3M;ib1W-~ znw+S4k@6!+?lV85c_^ee8PYP#VXP3fBGjK#D(r+A4_Z_eAn>$U`wPVe*RyTkAf!pYEqSyJ? zs^;0?R8<~xcvzLX>^B^o|Bhh*r@AGzW0Wy>ff-W_$1y+rfAuYLdZqe!zUo<~4Yr+; zoLJmfn48J%U{~x+jP1_R*x`J7Z%CI$SV}9&hB5b)BtaQdX-wiSk>#Ky+A3B?mGzOl zxxp!!Dq)3(H!#3BHX{ilCl5E?;V$YvU|g)e`-sw;V-S-nWdO~5rUqf6ioEZjdef0ypnaS z41)ZQ(QLRF{Xwr+Vh8GjxNoCTsRRb)G^1B4g{ogl6{2oUVBQ=r)rzQ&jh&zt6{D?E zR7AlmHMXO$7}bl5Kr;%qa+(AD%XkG1-@8b%PD(mS+IcE=ccDCL9qq>8RO#|@ zo_&B@@M<@RovmPdx0#Q&f}*azsOq4mo0I7(tefKHokkcHH<-*OwlLRtVsCo&A_WvA~VJPY^>=Eld?8oRr76NOL2rvg434xX>D zP`MFF5E7^=cEVu0(j9>w-$!_S{|+Bw(@8Z)GD@ae^i|I_XFxRt9?oKjZ5%WnFFU4p zGMba?7J8D=mf^MMWGrbc=wSyyoRr1=!Kbllk;8OfMHZC`_~Qpr5`0s`Xlk>wWw| z7zQT7>I-A)#&AN%HVS#{R<`S<2xj+StK0UD*Q5ko1`}YWQ?N&zf_>T^R>SH-|A;%D8}GTKZm1cnpvJ8e>Tl(wR#yN3 diff --git a/uncompyle6/parsers/parse3.py b/uncompyle6/parsers/parse3.py index a77f1474..852c4aae 100644 --- a/uncompyle6/parsers/parse3.py +++ b/uncompyle6/parsers/parse3.py @@ -1064,19 +1064,13 @@ class Python3Parser(PythonParser): # 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. # Yes this is a little hacky - if self.version < 3.5: - # 3.3 and 3.4 put kwargs before pos_arg + if self.version == 3.3: + # 3.3 puts kwargs before pos_arg pos_kw_tuple = (('kwargs ' * args_kw), ('pos_arg ' * (args_pos))) 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))) - if self.version < 3.5: - # 3.3 and 3.4 put kwargs before pos_arg - pos_kw_tuple = (('kwargs ' * args_kw), ('pos_arg ' * (args_pos))) - else: - # 3.5 puts pos_arg before kwargs - pos_kw_tuple = (('pos_arg ' * (args_pos), ('kwargs ' * args_kw))) - rule = ('mkfunc_annotate ::= %s%s%s%sannotate_tuple LOAD_CONST LOAD_STR 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], ('call ' * (annotate_args-1)), opname)) self.add_unique_rule(rule, opname, token.attr, customize) diff --git a/uncompyle6/semantics/customize3.py b/uncompyle6/semantics/customize3.py index ba8184bc..1a02056c 100644 --- a/uncompyle6/semantics/customize3.py +++ b/uncompyle6/semantics/customize3.py @@ -88,7 +88,7 @@ def customize_for_version3(self, version): code_node = build_class[1][0] class_name = code_node.attr.co_name else: - class_name = node[1][0].pattr + class_name = node[1][0].attr build_class = node[0] assert 'mkfunc' == build_class[1] diff --git a/uncompyle6/semantics/make_function.py b/uncompyle6/semantics/make_function.py index 0b4afdb1..7727b805 100644 --- a/uncompyle6/semantics/make_function.py +++ b/uncompyle6/semantics/make_function.py @@ -216,7 +216,7 @@ def make_function3_annotate(self, node, is_lambda, nested=1, if (line_number != self.line_number): self.write("\n" + indent) line_number = self.line_number - kn = n[0].pattr + kn = n[0].attr if kn in annotate_tuple[0].attr: p = annotate_tuple[0].attr.index(star_arg) + pos_args + kw_args self.write('%s: ' % kn) diff --git a/uncompyle6/semantics/pysource.py b/uncompyle6/semantics/pysource.py index cfa5453b..8b4b67f5 100644 --- a/uncompyle6/semantics/pysource.py +++ b/uncompyle6/semantics/pysource.py @@ -1436,7 +1436,7 @@ class SourceWalker(GenericASTTraversal, object): n = len(node) - 1 if node.kind != 'expr': if node == 'kwarg': - self.template_engine(('(%[0]{pattr}=%c)', 1), node) + self.template_engine(('(%[0]{attr}=%c)', 1), node) return kwargs = None From fd5f4fa5b8c3f65bb6c38e5a2d5987b11510f8ef Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 9 Jun 2019 09:53:21 -0400 Subject: [PATCH 05/32] Nicer LOAD_STR assembly output --- uncompyle6/scanners/tok.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/uncompyle6/scanners/tok.py b/uncompyle6/scanners/tok.py index 4a4ee2f5..e6f006e4 100644 --- a/uncompyle6/scanners/tok.py +++ b/uncompyle6/scanners/tok.py @@ -98,9 +98,9 @@ class Token(): pattr = "to " + str(self.pattr) pass elif self.op in self.opc.CONST_OPS: - # Compare with pysource n_LOAD_CONST - attr = self.attr - if attr is None: + if self.kind == 'LOAD_STR': + pattr = self.attr + elif self.attr is None: pattr = None elif self.op in self.opc.hascompare: if isinstance(self.attr, int): From 2f99da81991e8822884feff828bf4cdcafd5279f Mon Sep 17 00:00:00 2001 From: x0ret Date: Sun, 9 Jun 2019 19:06:57 +0430 Subject: [PATCH 06/32] Fix leading * arg in function signature in 3.6 --- uncompyle6/semantics/make_function.py | 157 +++++++++++++------------- 1 file changed, 80 insertions(+), 77 deletions(-) diff --git a/uncompyle6/semantics/make_function.py b/uncompyle6/semantics/make_function.py index 7727b805..9767dd7a 100644 --- a/uncompyle6/semantics/make_function.py +++ b/uncompyle6/semantics/make_function.py @@ -135,6 +135,10 @@ def make_function3_annotate(self, node, is_lambda, nested=1, indent = ' ' * l line_number = self.line_number + if code_has_star_arg(code): + self.write('*%s' % code.co_varnames[argc + kw_pairs]) + argc += 1 + i = len(paramnames) - len(defparams) suffix = '' @@ -144,7 +148,7 @@ def make_function3_annotate(self, node, is_lambda, nested=1, self.write(suffix, param) suffix = ', ' if param in annotate_tuple[0].attr: - p = annotate_tuple[0].attr.index(param) + pos_args + p = annotate_tuple[0].attr.index(param) self.write(': ') self.preorder(node[p]) if (line_number != self.line_number): @@ -183,17 +187,7 @@ def make_function3_annotate(self, node, is_lambda, nested=1, suffix = ', ' - if code_has_star_arg(code): - star_arg = code.co_varnames[argc + kw_pairs] - 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 - # self.println(indent, '#flags:\t', int(code.co_flags)) - ends_in_comma = False if kw_args + annotate_argc > 0: if no_paramnames: if not code_has_star_arg(code): @@ -204,47 +198,49 @@ def make_function3_annotate(self, node, is_lambda, nested=1, pass else: self.write(", ") - 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].attr - 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: - self.write('%s=' % kn) - self.preorder(n[1]) - if i < last: - self.write(', ') - ends_in_comma = True - else: - ends_in_comma = False - i += 1 + kwargs = node[0] + last = len(kwargs)-1 + i = 0 + for n in node[0]: + if n == 'kwarg': + if (line_number != self.line_number): + self.write("\n" + indent) + line_number = self.line_number + self.write('%s=' % n[0].pattr) + self.preorder(n[1]) + if i < last: + self.write(', ') + i += 1 + pass + pass + annotate_args = [] + for n in node: + if n == 'annotate_arg': + annotate_args.append(n[0]) + elif n == 'annotate_tuple': + t = n[0].attr + if t[-1] == 'return': + t = t[0:-1] + annotate_args = annotate_args[:-1] + pass + last = len(annotate_args) - 1 + for i in range(len(annotate_args)): + self.write("%s: " % (t[i])) + self.preorder(annotate_args[i]) + if i < last: + self.write(', ') + pass + pass + break pass pass - pass if code_has_star_star_arg(code): - if argc > 0 and not ends_in_comma: + if argc > 0: self.write(', ') - star_star_arg = code.co_varnames[argc + kw_pairs] - 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]) + self.write('**%s' % code.co_varnames[argc + kw_pairs]) if is_lambda: self.write(": ") @@ -480,7 +476,7 @@ def make_function3(self, node, is_lambda, nested=1, code_node=None): # Thank you, Python. - def build_param(ast, name, default, annotation=None): + def build_param(ast, name, default): """build parameters: - handle defaults - handle format tuple parameters @@ -490,10 +486,7 @@ def make_function3(self, node, is_lambda, nested=1, code_node=None): else: value = self.traverse(default, indent='') maybe_show_tree_param_default(self.showast, name, value) - if annotation: - result = '%s: %s=%s' % (name, annotation, value) - else: - result = '%s=%s' % (name, value) + result = '%s=%s' % (name, value) # The below can probably be removed. This is probably # a holdover from days when LOAD_CONST erroneously @@ -688,30 +681,17 @@ def make_function3(self, node, is_lambda, nested=1, code_node=None): params = [] if defparams: for i, defparam in enumerate(defparams): - params.append(build_param(ast, paramnames[i], defparam, - annotate_dict.get(paramnames[i]))) + params.append(build_param(ast, paramnames[i], defparam)) - for param in paramnames[i+1:]: - if param in annotate_dict: - params.append("%s: %s" % (param, annotate_dict[param])) - else: - params.append(param) + params += paramnames[i+1:] else: - for param in paramnames: - if param in annotate_dict: - params.append("%s: %s" % (param, annotate_dict[param])) - else: - params.append(param) + params = paramnames params.reverse() # back to correct order if code_has_star_arg(code): if self.version > 3.0: - star_arg = code.co_varnames[argc + kw_pairs] - if star_arg in annotate_dict: - params.append('*%s: %s' %(star_arg, annotate_dict[star_arg])) - else: - params.append('*%s' % star_arg) + params.append('*%s' % code.co_varnames[argc + kw_pairs]) else: params.append('*%s' % code.co_varnames[argc]) argc += 1 @@ -736,11 +716,14 @@ def make_function3(self, node, is_lambda, nested=1, code_node=None): ast[-1] = ast_expr pass else: + # FIXME: add annotations here self.write("(", ", ".join(params)) # self.println(indent, '#flags:\t', int(code.co_flags)) + kwonlyargcount = 0 + ends_in_comma = False - if kw_args > 0: + if kw_args + annotate_argc > 0: if not (4 & code.co_flags): if argc > 0: self.write(", *, ") @@ -784,11 +767,11 @@ def make_function3(self, node, is_lambda, nested=1, code_node=None): break elif self.version >= 3.6: # argc = node[-1].attr - # co = node[-3].attr + co = node[-3].attr # argcount = co.co_argcount - # kwonlyargcount = co.co_kwonlyargcount + kwcount = 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 index = -4 # Skip over: # MAKE_FUNCTION, @@ -798,7 +781,7 @@ def make_function3(self, node, is_lambda, nested=1, code_node=None): free_tup = node[index] index -= 1 if fn_bits[-2]: - annotate_dict = node[index] + ann_dict = node[index] index -= 1 if fn_bits[-3]: kw_dict = node[index] @@ -819,19 +802,39 @@ def make_function3(self, node, is_lambda, nested=1, code_node=None): # FIXME: possibly handle line breaks for i, n in enumerate(names): self.write(sep) - self.write("%s=%s" % (n, defaults[i])) + if annotate_dict and n in annotate_dict: + self.write("%s: %s=%s" % (n, annotate_dict[n], defaults[i])) + else: + self.write("%s=%s" % (n, defaults[i])) sep = ', ' ends_in_comma = False + kwcount -= 1 pass pass + if ann_dict: + annotate_args = ann_dict[0][-2].attr + if annotate_args[-1] == 'return': + annotate_args = annotate_args[:-1] + + sep = '' + if not ends_in_comma: + sep = ', ' + for n in annotate_args: + if kwcount == 0: + break + self.write(sep) + self.write('%s: %s' %(n, annotate_dict[n])) + sep = ', ' + ends_in_comma = False + kwcount -= 1 pass if code_has_star_star_arg(code): - if argc > 0 and not ends_in_comma: + if not ends_in_comma: self.write(', ') - star_star_arg = code.co_varnames[argc + kw_pairs] - if annotate_dict and star_star_arg and star_star_arg in annotate_dict: - self.write('**%s: %s' %(star_star_arg, annotate_dict[star_star_arg])) + 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) From 354796fffdb534f0ae02a7bebd81bd836d91f20f Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 9 Jun 2019 11:10:14 -0400 Subject: [PATCH 07/32] One more LOAD_CONST->LOAD_STR artifact --- uncompyle6/semantics/pysource.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uncompyle6/semantics/pysource.py b/uncompyle6/semantics/pysource.py index 8b4b67f5..8ce6dee0 100644 --- a/uncompyle6/semantics/pysource.py +++ b/uncompyle6/semantics/pysource.py @@ -2122,7 +2122,7 @@ class SourceWalker(GenericASTTraversal, object): # which are not simple classes like the < 3 case. try: 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][0] == Token('STORE_NAME', pattr='__qualname__')): have_qualname = True From 9811c5bc4290eec268ab99408e8959a3ebe9fb03 Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 9 Jun 2019 12:21:45 -0400 Subject: [PATCH 08/32] Nicer assembly output --- uncompyle6/scanners/tok.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/uncompyle6/scanners/tok.py b/uncompyle6/scanners/tok.py index e6f006e4..a55f3d05 100644 --- a/uncompyle6/scanners/tok.py +++ b/uncompyle6/scanners/tok.py @@ -83,12 +83,15 @@ class Token(): prefix = ('\n%s%4d ' % (line_prefix, self.linestart) if self.linestart else (' ' * (6 + len(line_prefix)))) offset_opname = '%6s %-17s' % (self.offset, self.kind) + if not self.has_arg: return "%s%s" % (prefix, offset_opname) argstr = "%6d " % self.attr if isinstance(self.attr, int) else (' '*7) if self.has_arg: pattr = self.pattr if self.opc: + name = self.kind + opname_base = name[:name.find('_')] if self.op in self.opc.JREL_OPS: if not self.pattr.startswith('to '): pattr = "to " + self.pattr @@ -98,13 +101,16 @@ class Token(): pattr = "to " + str(self.pattr) pass elif self.op in self.opc.CONST_OPS: - if self.kind == 'LOAD_STR': + if name == 'LOAD_STR': pattr = self.attr elif self.attr is None: pattr = None elif self.op in self.opc.hascompare: if isinstance(self.attr, int): pattr = self.opc.cmp_op[self.attr] + pass + elif opname_base in ('CALL', 'BUILD', 'RAISE'): + return "%s%s%s" % (prefix, offset_opname, argstr) # And so on. See xdis/bytecode.py get_instructions_bytes pass elif re.search(r'_\d+$', self.kind): From 4022e80d6d398c9f5c5ab6e0e08549b3a8e3ad9d Mon Sep 17 00:00:00 2001 From: x0ret Date: Sun, 9 Jun 2019 23:46:33 +0430 Subject: [PATCH 09/32] Fix py3 function signatures + annotations + ordering --- uncompyle6/semantics/make_function.py | 183 +++++++++++++++----------- 1 file changed, 104 insertions(+), 79 deletions(-) diff --git a/uncompyle6/semantics/make_function.py b/uncompyle6/semantics/make_function.py index 9767dd7a..600990e6 100644 --- a/uncompyle6/semantics/make_function.py +++ b/uncompyle6/semantics/make_function.py @@ -91,6 +91,12 @@ def make_function3_annotate(self, node, is_lambda, nested=1, annotate_argc = 0 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: lambda_index = -2 elif 3.03 <= self.version: @@ -109,7 +115,11 @@ def make_function3_annotate(self, node, is_lambda, nested=1, # add defaults values to parameter names argc = code.co_argcount + kwonlyargcount = code.co_kwonlyargcount + paramnames = list(code.co_varnames[:argc]) + if kwonlyargcount > 0: + kwargs = list(code.co_varnames[argc:argc+kwonlyargcount]) try: ast = self.build_ast(code._tokens, @@ -135,10 +145,6 @@ def make_function3_annotate(self, node, is_lambda, nested=1, indent = ' ' * l line_number = self.line_number - if code_has_star_arg(code): - self.write('*%s' % code.co_varnames[argc + kw_pairs]) - argc += 1 - i = len(paramnames) - len(defparams) suffix = '' @@ -147,10 +153,8 @@ def make_function3_annotate(self, node, is_lambda, nested=1, for param in paramnames[:i]: self.write(suffix, param) suffix = ', ' - if param in annotate_tuple[0].attr: - p = annotate_tuple[0].attr.index(param) - self.write(': ') - self.preorder(node[p]) + if param in annotate_dict: + self.write(': %s' % annotate_dict[param]) if (line_number != self.line_number): suffix = ",\n" + indent line_number = self.line_number @@ -187,8 +191,16 @@ def make_function3_annotate(self, node, is_lambda, nested=1, suffix = ', ' + if code_has_star_arg(code): + 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) + argc += 1 + # self.println(indent, '#flags:\t', int(code.co_flags)) - if kw_args + annotate_argc > 0: + if kwonlyargcount > 0: if no_paramnames: if not code_has_star_arg(code): if argc > 0: @@ -198,49 +210,45 @@ def make_function3_annotate(self, node, is_lambda, nested=1, pass else: self.write(", ") + else: + if argc > 0: + self.write(', ') - kwargs = node[0] - last = len(kwargs)-1 - i = 0 - for n in node[0]: - if n == 'kwarg': - if (line_number != self.line_number): - self.write("\n" + indent) - line_number = self.line_number - self.write('%s=' % n[0].pattr) - self.preorder(n[1]) - if i < last: - self.write(', ') - i += 1 - pass - pass - annotate_args = [] - for n in node: - if n == 'annotate_arg': - annotate_args.append(n[0]) - elif n == 'annotate_tuple': - t = n[0].attr - if t[-1] == 'return': - t = t[0:-1] - annotate_args = annotate_args[:-1] - pass - last = len(annotate_args) - 1 - for i in range(len(annotate_args)): - self.write("%s: " % (t[i])) - self.preorder(annotate_args[i]) - if i < last: - self.write(', ') - pass - pass - break + 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: + kw_args[idx] = '%s=%s' % (name, default) 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)) - if code_has_star_star_arg(code): - if argc > 0: - self.write(', ') - self.write('**%s' % code.co_varnames[argc + kw_pairs]) + if code_has_star_star_arg(code): + if argc > 0: + self.write(', ') + 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) if is_lambda: self.write(": ") @@ -476,7 +484,7 @@ def make_function3(self, node, is_lambda, nested=1, code_node=None): # Thank you, Python. - def build_param(ast, name, default): + def build_param(ast, name, default, annotation=None): """build parameters: - handle defaults - handle format tuple parameters @@ -486,7 +494,10 @@ def make_function3(self, node, is_lambda, nested=1, code_node=None): else: value = self.traverse(default, indent='') maybe_show_tree_param_default(self.showast, name, value) - result = '%s=%s' % (name, value) + if annotation: + result = '%s: %s=%s' % (name, annotation, value) + else: + result = '%s=%s' % (name, value) # The below can probably be removed. This is probably # a holdover from days when LOAD_CONST erroneously @@ -654,7 +665,11 @@ def make_function3(self, node, is_lambda, nested=1, code_node=None): # add defaults values to parameter names argc = code.co_argcount + kwonlyargcount = code.co_kwonlyargcount + 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 paramnames.reverse(); @@ -681,17 +696,30 @@ def make_function3(self, node, is_lambda, nested=1, code_node=None): params = [] if defparams: for i, defparam in enumerate(defparams): - params.append(build_param(ast, paramnames[i], defparam)) + params.append(build_param(ast, paramnames[i], defparam, + annotate_dict.get(paramnames[i]))) - params += paramnames[i+1:] + for param in paramnames[i+1:]: + if param in annotate_dict: + params.append("%s: %s" % (param, annotate_dict[param])) + else: + params.append(param) else: - params = paramnames + for param in paramnames: + if param in annotate_dict: + params.append("%s: %s" % (param, annotate_dict[param])) + else: + params.append(param) params.reverse() # back to correct order if code_has_star_arg(code): if self.version > 3.0: - params.append('*%s' % code.co_varnames[argc + kw_pairs]) + star_arg = code.co_varnames[argc + kwonlyargcount] + if annotate_dict and star_arg in annotate_dict: + params.append('*%s: %s' % (star_arg, annotate_dict[star_arg])) + else: + params.append('*%s' % star_arg) else: params.append('*%s' % code.co_varnames[argc]) argc += 1 @@ -720,10 +748,8 @@ def make_function3(self, node, is_lambda, nested=1, code_node=None): self.write("(", ", ".join(params)) # self.println(indent, '#flags:\t', int(code.co_flags)) - kwonlyargcount = 0 - ends_in_comma = False - if kw_args + annotate_argc > 0: + if kwonlyargcount > 0: if not (4 & code.co_flags): if argc > 0: self.write(", *, ") @@ -767,9 +793,9 @@ def make_function3(self, node, is_lambda, nested=1, code_node=None): break elif self.version >= 3.6: # argc = node[-1].attr - co = node[-3].attr + # co = node[-3].attr # argcount = co.co_argcount - kwcount = kwonlyargcount = co.co_kwonlyargcount + # kwonlyargcount = co.co_kwonlyargcount free_tup = ann_dict = kw_dict = default_tup = None fn_bits = node[-1].attr @@ -793,6 +819,8 @@ def make_function3(self, node, is_lambda, nested=1, code_node=None): kw_dict = kw_dict[0] # FIXME: handle free_tup, annotate_dict, and default_tup + kw_args = [None] * kwonlyargcount + if kw_dict: assert kw_dict == 'dict' defaults = [self.traverse(n, indent='') for n in kw_dict[:-2]] @@ -801,32 +829,29 @@ def make_function3(self, node, is_lambda, nested=1, code_node=None): sep = '' # FIXME: possibly handle line breaks for i, n in enumerate(names): - self.write(sep) + idx = kwargs.index(n) if annotate_dict and n in annotate_dict: - self.write("%s: %s=%s" % (n, annotate_dict[n], defaults[i])) + t = "%s: %s=%s" % (n, annotate_dict[n], defaults[i]) else: - self.write("%s=%s" % (n, defaults[i])) - sep = ', ' - ends_in_comma = False - kwcount -= 1 + t = "%s=%s" % (n, defaults[i]) + kw_args[idx] = t pass pass - if ann_dict: - annotate_args = ann_dict[0][-2].attr - if annotate_args[-1] == 'return': - annotate_args = annotate_args[:-1] - sep = '' - if not ends_in_comma: - sep = ', ' - for n in annotate_args: - if kwcount == 0: - break - self.write(sep) - self.write('%s: %s' %(n, annotate_dict[n])) - sep = ', ' - ends_in_comma = False - kwcount -= 1 + # 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 if code_has_star_star_arg(code): From 9ab086b207fc05e576a84a8ebd2035b7518e00c7 Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 9 Jun 2019 15:19:01 -0400 Subject: [PATCH 10/32] Add more x0ret tests --- test/bytecode_3.3_run/04_def_annotate.pyc | Bin 5605 -> 13585 bytes test/bytecode_3.5_run/04_def_annotate.pyc | Bin 3895 -> 8712 bytes test/bytecode_3.6_run/04_def_annotate.pyc | Bin 3625 -> 8251 bytes test/bytecode_3.7_run/04_def_annotate.pyc | Bin 2325 -> 8268 bytes test/simple_source/bug31/04_def_annotate.py | 49 ++++++++++++++++++-- 5 files changed, 44 insertions(+), 5 deletions(-) diff --git a/test/bytecode_3.3_run/04_def_annotate.pyc b/test/bytecode_3.3_run/04_def_annotate.pyc index 7014aa44b53048722a2ea0e43c5cce970538c964..62ab73c34a8685f7246b11dc4033ba6c4aa8dcb0 100644 GIT binary patch literal 13585 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 WvfY%Mo)&d6D_k*coD;5*6Mq2noQIeI diff --git a/test/bytecode_3.6_run/04_def_annotate.pyc b/test/bytecode_3.6_run/04_def_annotate.pyc index 8aac3046e9970f47f424a89135182b0b24ae76f4..1ec446159b2e31bdc68b001e78c124b561ed2f6e 100644 GIT binary patch literal 8251 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 DLu#Ct diff --git a/test/bytecode_3.7_run/04_def_annotate.pyc b/test/bytecode_3.7_run/04_def_annotate.pyc index 0636a4bb92c02a2925da86c5c00aca937a3eecfa..48fd26bc51f9d9735eaffbbff1ade2d62bc10010 100644 GIT binary patch literal 8268 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 Tzsjq8A(#%Q!}-#DrN;jOiImcv diff --git a/test/simple_source/bug31/04_def_annotate.py b/test/simple_source/bug31/04_def_annotate.py index a7ee2128..9ae36156 100644 --- a/test/simple_source/bug31/04_def_annotate.py +++ b/test/simple_source/bug31/04_def_annotate.py @@ -47,11 +47,50 @@ def div(a: dict(type=float, help='the dividend'), """Divide a by b""" return a / b -# FIXME: -# class TestSignatureObject(): -# def test_signature_on_wkwonly(self): -# def test(*, a:float, b:str) -> int: -# pass +class TestSignatureObject1(): + def test_signature_on_wkwonly(self): + def test(*, a:float, b:str, c:str = 'test', **kwargs: int) -> int: + 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(): From e82cabc278a69c575bd7c4cf8dcf481f311a7959 Mon Sep 17 00:00:00 2001 From: x0ret Date: Mon, 10 Jun 2019 00:29:34 +0430 Subject: [PATCH 11/32] Fix 2 issues in commas in function signatures --- uncompyle6/semantics/make_function.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/uncompyle6/semantics/make_function.py b/uncompyle6/semantics/make_function.py index 600990e6..910efffc 100644 --- a/uncompyle6/semantics/make_function.py +++ b/uncompyle6/semantics/make_function.py @@ -239,11 +239,13 @@ def make_function3_annotate(self, node, is_lambda, nested=1, kw_args[i] = "%s: %s" %(n, annotate_dict[n]) else: kw_args[i] = "%s" % n - self.write(', '.join(kw_args)) + + self.write(', '.join(kw_args), ', ') + + elif argc > 0: + self.write(', ') if code_has_star_star_arg(code): - if argc > 0: - self.write(', ') 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])) @@ -748,7 +750,7 @@ def make_function3(self, node, is_lambda, nested=1, code_node=None): self.write("(", ", ".join(params)) # self.println(indent, '#flags:\t', int(code.co_flags)) - ends_in_comma = False + ends_in_comma = True if kwonlyargcount > 0: if not (4 & code.co_flags): if argc > 0: @@ -853,6 +855,8 @@ def make_function3(self, node, is_lambda, nested=1, code_node=None): ends_in_comma = False pass + elif argc > 0: + self.write(', ') if code_has_star_star_arg(code): if not ends_in_comma: From 719d2d7232e8aa33f1252d7e76ac8f995aa83d5f Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 9 Jun 2019 16:26:08 -0400 Subject: [PATCH 12/32] Correct order of pos vs kwargs in 3.0-3.2 --- uncompyle6/parsers/parse3.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/uncompyle6/parsers/parse3.py b/uncompyle6/parsers/parse3.py index 852c4aae..c24606f9 100644 --- a/uncompyle6/parsers/parse3.py +++ b/uncompyle6/parsers/parse3.py @@ -1080,11 +1080,11 @@ class Python3Parser(PythonParser): else: # See above comment about use of EXTENDED_ARG 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)) self.add_unique_rule(rule, opname, token.attr, customize) 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)) self.addRule(rule, nop_func) elif opname == 'RETURN_VALUE_LAMBDA': From a54fba7993f241c6e570b575f71b1a7ee54106f9 Mon Sep 17 00:00:00 2001 From: x0ret Date: Mon, 10 Jun 2019 01:42:16 +0430 Subject: [PATCH 13/32] Fix issue in commas in function signatures --- uncompyle6/semantics/make_function.py | 29 ++++++++++++++++++--------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/uncompyle6/semantics/make_function.py b/uncompyle6/semantics/make_function.py index 910efffc..44b5721f 100644 --- a/uncompyle6/semantics/make_function.py +++ b/uncompyle6/semantics/make_function.py @@ -694,6 +694,9 @@ def make_function3(self, node, is_lambda, nested=1, code_node=None): else: kw_pairs = 0 + i = len(paramnames) - len(defparams) + no_paramnames = len(paramnames[:i]) == 0 + # build parameters params = [] if defparams: @@ -750,17 +753,22 @@ def make_function3(self, node, is_lambda, nested=1, code_node=None): self.write("(", ", ".join(params)) # self.println(indent, '#flags:\t', int(code.co_flags)) - ends_in_comma = True + ends_in_comma = False if kwonlyargcount > 0: - if not (4 & code.co_flags): - if argc > 0: - self.write(", *, ") + if no_paramnames: + if not (4 & code.co_flags): + if argc > 0: + self.write(", *, ") + else: + self.write("*, ") + pass else: - self.write("*, ") - pass + self.write(", ") + ends_in_comma = True else: - self.write(", ") - ends_in_comma = True + if argc > 0: + self.write(', ') + ends_in_comma = True # FIXME: this is not correct for 3.5. or 3.6 (which works different) # and 3.7? @@ -855,8 +863,9 @@ def make_function3(self, node, is_lambda, nested=1, code_node=None): ends_in_comma = False pass - elif argc > 0: - self.write(', ') + else: + if argc == 0: + ends_in_comma = True if code_has_star_star_arg(code): if not ends_in_comma: From eae3f0d77b3dab18b677041f14bcfaeddc23c996 Mon Sep 17 00:00:00 2001 From: x0ret Date: Mon, 10 Jun 2019 02:25:19 +0430 Subject: [PATCH 14/32] Fix issue in commas in function signatures --- uncompyle6/semantics/make_function.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/uncompyle6/semantics/make_function.py b/uncompyle6/semantics/make_function.py index 44b5721f..dc8e50f9 100644 --- a/uncompyle6/semantics/make_function.py +++ b/uncompyle6/semantics/make_function.py @@ -200,6 +200,7 @@ def make_function3_annotate(self, node, is_lambda, nested=1, argc += 1 # self.println(indent, '#flags:\t', int(code.co_flags)) + ends_in_comma = False if kwonlyargcount > 0: if no_paramnames: if not code_has_star_arg(code): @@ -210,9 +211,11 @@ def make_function3_annotate(self, node, is_lambda, nested=1, pass else: self.write(", ") + ends_in_comma = True else: if argc > 0: self.write(', ') + ends_in_comma = True kw_args = [None] * kwonlyargcount @@ -242,10 +245,13 @@ def make_function3_annotate(self, node, is_lambda, nested=1, self.write(', '.join(kw_args), ', ') - elif argc > 0: - self.write(', ') + else: + if argc == 0: + ends_in_comma = True if code_has_star_star_arg(code): + if not ends_in_comma: + self.write(', ') 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])) From 24ba5d7f40b861991a0c92fed54415c97f64eb2b Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 9 Jun 2019 18:20:05 -0400 Subject: [PATCH 15/32] One more LOAD_CONST->LOAD_STR remnant and... We're good to go! All function signatures seem to be working! YAY! Credit goes to x0ret --- test/bytecode_3.1/04_def_annotate.pyc | Bin 2449 -> 0 bytes test/bytecode_3.2_run/15_assert.pyc | Bin 809 -> 601 bytes test/bytecode_3.5/04_def_annotate.pyc | Bin 1857 -> 0 bytes test/bytecode_3.7/04_def_annotate.pyc | Bin 1776 -> 0 bytes uncompyle6/semantics/make_function.py | 2 +- 5 files changed, 1 insertion(+), 1 deletion(-) delete mode 100644 test/bytecode_3.1/04_def_annotate.pyc delete mode 100644 test/bytecode_3.5/04_def_annotate.pyc delete mode 100644 test/bytecode_3.7/04_def_annotate.pyc diff --git a/test/bytecode_3.1/04_def_annotate.pyc b/test/bytecode_3.1/04_def_annotate.pyc deleted file mode 100644 index 607ee87a70c191d75037be517495daed26d40912..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2449 zcmb_dO>Y}F5S?AgvMt+5sgKXl%#R+eJKK!q%J$>DH0oSFAHJl);v{&Di}pE)f(+bsXgpZkX!MWp$S zNbwuf`!>BJ8pfnrqz;$fBT{Wr8>Bk)KBjja8nV1eYKzo1sjes^EYuxRJ7RE`)E-?^ zyrQ{xOLHF@^%LKYZdc958EgE)N`$)70q<2KcI~>xWcg%5wU2ZaC ztj~O5CdsJRf;Qr2ByAo#ELYlx%H){CgC5^Y{@fuqp6Cs~5gomW>F7G5h!ZsE!AxJ; zu)*T2DvZC`AY0z1$MYmjc+8S3rn6F~&W0-2Pe)<$!}m|0{g^5}PUqh0C$p;nC&t#I zb1^p*iOou!esy}1IbCnR6vQU};|Dz)lpxwHa1bjli%wtq9{vm%jf+x?Fttht5MmU@ zW6fbr!WNIT$*sZw+v%#Zl?zyG^hH@1EplF3r^jl&c;SSdX#=Bmz^wwA4c~B+nIx+w zVXBQ!{CVaR&Q=ym?-Fm5=XD+s@MVq`4|=3cQgDxj8ppfw!y?J@<$5v9F$3`$%p}uS zvpToux||6u{kcw5@pqxLQ9_DF;cS)kros7Sgg=15JZ6(T`!0NqKzMDX9Y>$oacu?k z&XUp9GRGSVF4041#1_ymaszN{f`3_4B z#1<9_f;R*H98hE*nlr?sPn8ehhjt$E&N)-NhnU8t&Ae0s=PT(^WdsPUbGjVMne}X7 zJvcsRGgzIvVq$o&N~hMO7k^z?Q(mF`&3&5Z3}i`DlTCG+hOP{_UIZ>@X}Hr=eMIXO zrOmU_rRjPeKjdA{*yBOt@agEa&iz5-Yc~oX`DH;Fz>53{(H^sKLp06T72k7=b|e=V z5m$^M-*Yj8kK=u-=E4{r^!S8_u+BzS_<~763$U#hJ8EN^G6&KWOs}zt`#q_XcVUA9 zn2nf3S?;IWpEG6%hAm0qp4q0rcU3Tj2dQNMuDs;S@?)%!yDt5`vfk#l{Lr}@ moJ9IR7dY^EQJ;>VkZiZl&2hUEb)w_eL2EzSkG^dmZu|%F68sjkrhJjkrhJx&zNCbeykAc9i0V06cAzT0qaUX(cu6z-Q7Kk>8H4q(m-GGY-h5?9m5M2-(AU3@? zo--1cD1O6hz6s(zIETiSldWqf+jJt{2XPC;&LxZ{d@FWA>=7oUGJ+Q^I1gahM#esf z1J5`Bx#mwhgm;ki=H0X`l}&A4PU2A#I5u)DbCH&|(q)Dr@q<>H$2iRn5)1GOKL)$6 z8nAoLfMI|J3F{}!HD@|6E$K=%!@IhHSefA_ZGGUtdS&R5MXeDbNVu%}rxBwJd`O+pW z7mo8nx^Sw5bZet(JeCM_;@Yyzl%QQCwN~1=Rw+-5yp*n$70Sr5@YriYc3h}tvZP%N zFVNe#|Fel?ekU#CR8Oj@ENyI0QX8XdX;oMgTNQtW@nJ7B0!o8ca?pd`#7!O7EAiCi z40?MDm$z{EsC4ms5hWMevl)7LB8%C)Yfoe>@?UZxOEJHH`Dc`lKbcm>#v@`=5Ee+w z_+c`?P4~1k2sl>bTApenjYnrxAex-4)9S?vEx`1LZu_}3c92iX z6bo8D8@-U3U51|&k?~_v_8}4szhz*tr>}PTuigUc>tBxmiY>jTd=79L${Av!0{l;Z zu{@34B`LxKZ2t8-Fdxz-ZY~|+s^q6XovN}pJA72AEG^7qe+ApFIWAOcU0|$s0d-=- zg+>-*eSq5Esvx)juX?G?FA;tAzYz5??rqM?bSgP_9nP`iD(rdgx}5)9rA5ur6!8^2 zz6_|T^ga?QcW=JS{Qs2-pdvh?3!frctpFML_jH*(d}INzord^8hnSA0TOU-jnbOug z#mFq)kkxjiy|0IBDP;N%@>T%*r=Z0-#+Y-e#X4M#`Syy9!v(*eL^>wqqrUS`kqbqhS>HLsc2(w< zvOH{47LW1m^Z^~N@$a>=DpQ5m^e&^W{ix2}^{{hy* Bdo}<7 diff --git a/test/bytecode_3.7/04_def_annotate.pyc b/test/bytecode_3.7/04_def_annotate.pyc deleted file mode 100644 index fa138bd460e340d2a5a8349eab1a6589d57244c3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1776 zcmb7E&2Aev5GHq5(n^sN*G}x%PSS1C1l>cO1Z__Z0wXR^^MbH0vrzihTqIL!xt+nJp%3b^p9*167nZb z7Of4+9(3~y2u=hMl+$-14|sSUWdYye9Ui}eP}r1YaU<(id_PVtaxkFj*H5w7A_hqE?jrml%)WmBNq!< zD2`fNXsxty9Vw3MN($F0YGp*pJ@%QvcU+_rpcn(kAvO zw+XnGH?=j1RmnFHANsaHpxAIk2R-OMC>YgC(bVV)_<9S5D<~jFPx00wNE@I}`}RmA zy!xr)Lh>|lkv*A!*GHnBOdl=wjMB*$iKS&wo$c`ssy7HaJG`Hb>NrMZ9Fg-4WI0P4Nz|zdONN<5& zKwma|XAip1MnN*l3Dghe!8w7t2_YLJw|*#$J*Y-9hh!G7hOb3om%&E^7~Op|f}yj- zQVS*)<@ht0L^Fe{4#VlCvq<6rbc4p`W$>TwK~5UGiMJ32q0?_a0(BP;F|)wWlw`+m zj+LxWcAwR%$ZPZ5AAwqHm9@&P3ysw-#PS2;ji^h#1J*xGoUMPgi(yzG`tpAv8bG*X z#$-MgjJY0TP-YDjI&*!-er)o3wxg5Fcs%P^NqQRuX1RYprha~ja18Gr9=Hc$LAVG- z1dIXg_<^3$ti>bXtmUp9G?R(a*1UvZ%>RmuWrw0oAwy zR=Y3^pdErc_yec?nI%Nz|407|X{69ayeh1(nJjK(Ws&eKMnd=D@AR?Fy6gw7tSVIP iU-%dp7eAZP_&fxwW(~wz1iuzt4Ohb+?a_^Bt@RI4(taBN diff --git a/uncompyle6/semantics/make_function.py b/uncompyle6/semantics/make_function.py index dc8e50f9..4e1d9614 100644 --- a/uncompyle6/semantics/make_function.py +++ b/uncompyle6/semantics/make_function.py @@ -784,7 +784,7 @@ def make_function3(self, node, is_lambda, nested=1, code_node=None): i = 0 for n in node[0]: if n == 'kwarg': - self.write('%s=' % n[0].pattr) + self.write('%s=' % n[0].attr) self.preorder(n[1]) if i < last: self.write(', ') From b2d97f9847d31be8011c30138a6d98a6f6a55b68 Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 9 Jun 2019 18:29:46 -0400 Subject: [PATCH 16/32] Possble use of ','.join to remove "ends_in_comma"? --- uncompyle6/semantics/make_function.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/uncompyle6/semantics/make_function.py b/uncompyle6/semantics/make_function.py index 4e1d9614..c9f65d1b 100644 --- a/uncompyle6/semantics/make_function.py +++ b/uncompyle6/semantics/make_function.py @@ -759,6 +759,9 @@ def make_function3(self, node, is_lambda, nested=1, code_node=None): self.write("(", ", ".join(params)) # 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 if kwonlyargcount > 0: if no_paramnames: From 5981c7eae9870b2dea1e9f8534befa4ebcdca591 Mon Sep 17 00:00:00 2001 From: rocky Date: Tue, 11 Jun 2019 10:20:52 -0400 Subject: [PATCH 17/32] Fix LOAD_STR messing up docstring comparision --- uncompyle6/scanners/tok.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/uncompyle6/scanners/tok.py b/uncompyle6/scanners/tok.py index a55f3d05..5514c549 100644 --- a/uncompyle6/scanners/tok.py +++ b/uncompyle6/scanners/tok.py @@ -58,7 +58,10 @@ class Token(): """ '==' on kind and "pattr" attributes. It is okay if offsets and linestarts are different""" 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: # ?? do we need this? return self.kind == o From efe0914814594e4c39d34e35dfe946bf56792dce Mon Sep 17 00:00:00 2001 From: rocky Date: Tue, 11 Jun 2019 10:35:53 -0400 Subject: [PATCH 18/32] See above. --- uncompyle6/semantics/consts.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uncompyle6/semantics/consts.py b/uncompyle6/semantics/consts.py index 95e9cc56..23db96b5 100644 --- a/uncompyle6/semantics/consts.py +++ b/uncompyle6/semantics/consts.py @@ -131,7 +131,7 @@ PASS = SyntaxTree('stmts', ASSIGN_DOC_STRING = lambda doc_string, doc_load: \ SyntaxTree('stmt', [ SyntaxTree('assign', - [ SyntaxTree('expr', [ Token(doc_load, pattr=doc_string) ]), + [ SyntaxTree('expr', [ Token(doc_load, pattr=doc_string, attr=doc_string) ]), SyntaxTree('store', [ Token('STORE_NAME', pattr='__doc__')]) ])]) From 21fd506fbb61ff1e1a82eaa30c217e9fbf5d300f Mon Sep 17 00:00:00 2001 From: x0ret Date: Sun, 9 Jun 2019 00:49:50 +0430 Subject: [PATCH 19/32] Add 3.6 STORE_ANNOTATION --- uncompyle6/parsers/parse36.py | 5 +++++ uncompyle6/semantics/customize36.py | 7 +++++++ 2 files changed, 12 insertions(+) diff --git a/uncompyle6/parsers/parse36.py b/uncompyle6/parsers/parse36.py index abb80cf4..fed0b346 100644 --- a/uncompyle6/parsers/parse36.py +++ b/uncompyle6/parsers/parse36.py @@ -143,6 +143,11 @@ class Python36Parser(Python35Parser): COME_FROM_FINALLY compare_chained2 ::= expr COMPARE_OP come_froms JUMP_FORWARD + + stmt ::= SETUP_ANNOTATIONS + stmt ::= annotated_assign + annotated_assign ::= expr store store_annotation + store_annotation ::= LOAD_NAME STORE_ANNOTATION """ def customize_grammar_rules(self, tokens, customize): diff --git a/uncompyle6/semantics/customize36.py b/uncompyle6/semantics/customize36.py index 97191f90..86f426a9 100644 --- a/uncompyle6/semantics/customize36.py +++ b/uncompyle6/semantics/customize36.py @@ -60,6 +60,13 @@ def customize_for_version36(self, version): 'call_ex' : ( '%c(%p)', (0, 'expr'), (1, 100)), + 'store_annotation': ( + '%|%[1]{pattr}: %c', + 0 + ), + 'annotated_assign': ( + '%|%c = %p\n', + (-1, 'store_annotation'), (0, 200)) }) From 76dcaf9bf070347801dc1221b9f849ffa94d0c25 Mon Sep 17 00:00:00 2001 From: rocky Date: Tue, 11 Jun 2019 10:38:10 -0400 Subject: [PATCH 20/32] Tweaks to x0ret's anotation type handling - match AST names a little better: AnnAssign -> ann_assign... - localize Annotation type grammar change only when we have it - Add reduce rule to combine assignment and annotate declaration - Add annotation-type test from Python 3.6 - Docuemnt what's up with annotation types --- test/bytecode_3.6/05_ann_mopdule2.pyc | Bin 0 -> 1254 bytes uncompyle6/parsers/parse36.py | 33 +++++++++++++++++++++----- uncompyle6/semantics/customize36.py | 7 ++++-- uncompyle6/semantics/pysource.py | 19 +++++++++++---- 4 files changed, 47 insertions(+), 12 deletions(-) create mode 100644 test/bytecode_3.6/05_ann_mopdule2.pyc diff --git a/test/bytecode_3.6/05_ann_mopdule2.pyc b/test/bytecode_3.6/05_ann_mopdule2.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5e4604ee190ca91072c774eae89b83668017ef2c GIT binary patch literal 1254 zcmbVL&2AGh5VpO$$!7D@w19*Jh&>_YlA>1hR8^I7;6yHk9#%+}yLQ@z{R#F4(yFM3 zR6GSQz!UH;zH;g-aDf@8>5sT!X~y=9$DZ$-@piWxZTn^kff=?i>3@@8FbGk(Lq(HIIXl+ zX&sx>vKI4rQt9}!(3v>ORV>P~szseuWqhKv8b)s_tztD7#WYtY7O=_6xK^g-$66GH z&=4Y*hN;j->0xvQn8|?IZdvjAbgFoIqSB8x9Oc58L!qxI_^%>RDW1fE77t_uVjhA5 zB)}ISVGH(^oRb9s1m5^20FJnzeV9!Llp+ZQnwg|S@C4-=BG4`QBzT47QilJT8MPx_aB z;ya9idteMa)46SERnK&pVj4JbMsa-N%jfi*aOguIhmIjROanrFqwq3V<8;8;Np;gum8{{`GkD{PUu zesupL2On?K2>99RvXHs`c(7rcoXaZZJZZrH$jW1lwbEF7OEbOh<`1qcHkjmI)ZjtsSeDrgn{EV_yGU!?}AYVWUIq!PmY6@+LPM?k<199u~no2GwAF U7E+&fSm^gy&kt$Dd~YNC3lG5i#{d8T literal 0 HcmV?d00001 diff --git a/uncompyle6/parsers/parse36.py b/uncompyle6/parsers/parse36.py index fed0b346..02186375 100644 --- a/uncompyle6/parsers/parse36.py +++ b/uncompyle6/parsers/parse36.py @@ -30,8 +30,7 @@ class Python36Parser(Python35Parser): 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 return_closure ::= LOAD_CLOSURE DUP_TOP STORE_NAME RETURN_VALUE RETURN_LAST @@ -144,10 +143,6 @@ class Python36Parser(Python35Parser): compare_chained2 ::= expr COMPARE_OP come_froms JUMP_FORWARD - stmt ::= SETUP_ANNOTATIONS - stmt ::= annotated_assign - annotated_assign ::= expr store store_annotation - store_annotation ::= LOAD_NAME STORE_ANNOTATION """ def customize_grammar_rules(self, tokens, customize): @@ -269,6 +264,22 @@ class Python36Parser(Python35Parser): self.addRule(rule, nop_func) rule = ('starred ::= %s %s' % ('expr ' * v, opname)) 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 + """ + self.addRule(rule, nop_func) + # Check to combine assignment + annotation into one statement + self.check_reduce['assign'] = 'token' elif opname == 'SETUP_WITH': rules_str = """ withstmt ::= expr SETUP_WITH POP_TOP suite_stmts_opt COME_FROM_WITH @@ -294,6 +305,7 @@ class Python36Parser(Python35Parser): self.addRule(rules_str, nop_func) pass pass + return def custom_classfunc_rule(self, opname, token, customize, next_token): @@ -393,6 +405,15 @@ class Python36Parser(Python35Parser): tokens, first, last) if 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': # Make sure we don't derive call_kw nt = ast[0] diff --git a/uncompyle6/semantics/customize36.py b/uncompyle6/semantics/customize36.py index 86f426a9..383ed754 100644 --- a/uncompyle6/semantics/customize36.py +++ b/uncompyle6/semantics/customize36.py @@ -64,9 +64,12 @@ def customize_for_version36(self, version): '%|%[1]{pattr}: %c', 0 ), - 'annotated_assign': ( + 'ann_assign_init_value': ( '%|%c = %p\n', - (-1, 'store_annotation'), (0, 200)) + (-1, 'store_annotation'), (0, 'expr', 200)), + 'ann_assign_no_init': ( + '%|%c\n', + (0, 200)) }) diff --git a/uncompyle6/semantics/pysource.py b/uncompyle6/semantics/pysource.py index 8ce6dee0..1cb6980d 100644 --- a/uncompyle6/semantics/pysource.py +++ b/uncompyle6/semantics/pysource.py @@ -2107,6 +2107,7 @@ class SourceWalker(GenericASTTraversal, object): except: pass + have_qualname = False if self.version < 3.0: # Should we ditch this in favor of the "else" case? @@ -2338,11 +2339,21 @@ def code_deparse(co, out=sys.stdout, version=None, debug_opts=DEFAULT_DEBUG_OPTS # convert leading '__doc__ = "..." into doc string try: - if deparsed.ast[0][0] == ASSIGN_DOC_STRING(co.co_consts[0], load_op): + 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]) - del deparsed.ast[0] - if deparsed.ast[-1] == RETURN_NONE: - deparsed.ast.pop() # remove last node + del stmts[0] + if stmts[-1] == RETURN_NONE: + stmts.pop() # remove last node # todo: if empty, add 'pass' except: pass From 70b07049676b7caabbc195d7b42b4528953acf73 Mon Sep 17 00:00:00 2001 From: rocky Date: Tue, 11 Jun 2019 11:03:43 -0400 Subject: [PATCH 21/32] CI - remove 2.6 testing, add 3.7 testing --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 7fce7351..98fd0ec6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,9 +3,9 @@ language: python python: - '3.5' - '2.7' - - '2.6' - '3.4' - '3.6' + - '3.7' matrix: include: From c3257a9b7997b6e78278324100402e0a71291730 Mon Sep 17 00:00:00 2001 From: rocky Date: Tue, 11 Jun 2019 11:05:50 -0400 Subject: [PATCH 22/32] CI testing - remove Python 2.6 testing and add 3.7 --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 7fce7351..98fd0ec6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,9 +3,9 @@ language: python python: - '3.5' - '2.7' - - '2.6' - '3.4' - '3.6' + - '3.7' matrix: include: From 37e4754268de24c644a2dfe1ba1a19ba81cdd780 Mon Sep 17 00:00:00 2001 From: rocky Date: Tue, 11 Jun 2019 11:10:53 -0400 Subject: [PATCH 23/32] Fix Improper semantic action format --- uncompyle6/semantics/customize36.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/uncompyle6/semantics/customize36.py b/uncompyle6/semantics/customize36.py index 383ed754..cecec452 100644 --- a/uncompyle6/semantics/customize36.py +++ b/uncompyle6/semantics/customize36.py @@ -68,8 +68,7 @@ def customize_for_version36(self, version): '%|%c = %p\n', (-1, 'store_annotation'), (0, 'expr', 200)), 'ann_assign_no_init': ( - '%|%c\n', - (0, 200)) + '%|%c\n', (0, 'store_annotation')), }) From 164e9d4b5cc8f103f507bb566a7934e1ba1a3e56 Mon Sep 17 00:00:00 2001 From: rocky Date: Tue, 11 Jun 2019 11:16:45 -0400 Subject: [PATCH 24/32] CI testing take 2 --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 98fd0ec6..015efe5f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,6 @@ python: - '2.7' - '3.4' - '3.6' - - '3.7' matrix: include: From 43348d7d247c5b507c952ec60d2a706bfee67fcd Mon Sep 17 00:00:00 2001 From: rocky Date: Tue, 11 Jun 2019 11:13:33 -0400 Subject: [PATCH 25/32] CI testing take 3 This time, for sure! --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 98fd0ec6..015efe5f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,6 @@ python: - '2.7' - '3.4' - '3.6' - - '3.7' matrix: include: From 08f23567a6caa9991703321932cc6bd5c1f1cdf4 Mon Sep 17 00:00:00 2001 From: rocky Date: Tue, 11 Jun 2019 12:44:29 -0400 Subject: [PATCH 26/32] Nicer assembly display... Fewer extraneous quotes and remove pattrs that don't mean anything. Base more on OP poperties like varargs and NAME_OPS --- uncompyle6/scanners/tok.py | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/uncompyle6/scanners/tok.py b/uncompyle6/scanners/tok.py index 5514c549..83750d7d 100644 --- a/uncompyle6/scanners/tok.py +++ b/uncompyle6/scanners/tok.py @@ -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 # Copyright (c) 1999 John Aycock # @@ -90,11 +90,11 @@ class Token(): if not self.has_arg: return "%s%s" % (prefix, offset_opname) argstr = "%6d " % self.attr if isinstance(self.attr, int) else (' '*7) + name = self.kind + if self.has_arg: pattr = self.pattr if self.opc: - name = self.kind - opname_base = name[:name.find('_')] if self.op in self.opc.JREL_OPS: if not self.pattr.startswith('to '): pattr = "to " + self.pattr @@ -106,14 +106,22 @@ class Token(): elif self.op in self.opc.CONST_OPS: if name == 'LOAD_STR': pattr = self.attr - elif self.attr is None: - pattr = None + elif name == 'LOAD_CODE': + 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: if isinstance(self.attr, int): pattr = self.opc.cmp_op[self.attr] - pass - elif opname_base in ('CALL', 'BUILD', 'RAISE'): + 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: + 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 pass elif re.search(r'_\d+$', self.kind): From 002720988c60406c9de1a09f42b3cb0c100f3459 Mon Sep 17 00:00:00 2001 From: rocky Date: Tue, 11 Jun 2019 14:08:50 -0400 Subject: [PATCH 27/32] Formatting in < 3.0 is different for name ops --- pytest/test_token.py | 6 +++++- pytest/testdata/if-2.7.right | 2 +- pytest/testdata/ifelse-2.7.right | 6 +++--- uncompyle6/scanners/tok.py | 3 ++- 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/pytest/test_token.py b/pytest/test_token.py index 7c5cb8c0..89173b60 100644 --- a/pytest/test_token.py +++ b/pytest/test_token.py @@ -1,3 +1,4 @@ +from uncompyle6 import PYTHON_VERSION from uncompyle6.scanners.tok import Token def test_token(): @@ -16,7 +17,10 @@ def test_token(): # Make sure formatting of: LOAD_CONST False. We assume False is the 0th index # of co_consts. t = Token('LOAD_CONST', offset=1, attr=False, pattr=False, has_arg=True) - expect = ' 1 LOAD_CONST 0 False' + if PYTHON_VERSION >= 3.0: + expect = ' 1 LOAD_CONST False' + else: + expect = ' 1 LOAD_CONST 0 False' assert t.format() == expect if __name__ == '__main__': diff --git a/pytest/testdata/if-2.7.right b/pytest/testdata/if-2.7.right index 9e315271..bab182cc 100644 --- a/pytest/testdata/if-2.7.right +++ b/pytest/testdata/if-2.7.right @@ -8,5 +8,5 @@ 9 STORE_NAME 2 'b' 12 JUMP_FORWARD 0 'to 15' 15_0 COME_FROM 12 '12' - 15 LOAD_CONST 0 None + 15 LOAD_CONST None 18 RETURN_VALUE diff --git a/pytest/testdata/ifelse-2.7.right b/pytest/testdata/ifelse-2.7.right index 1bfb5aaf..d95c4a13 100644 --- a/pytest/testdata/ifelse-2.7.right +++ b/pytest/testdata/ifelse-2.7.right @@ -4,12 +4,12 @@ 3 0 LOAD_NAME 0 'True' 3 POP_JUMP_IF_FALSE 15 'to 15' - 4 6 LOAD_CONST 0 1 + 4 6 LOAD_CONST 1 9 STORE_NAME 1 'b' 12 JUMP_FORWARD 6 'to 21' - 6 15 LOAD_CONST 1 2 + 6 15 LOAD_CONST 2 18 STORE_NAME 2 'd' 21_0 COME_FROM 12 '12' - 21 LOAD_CONST 2 None + 21 LOAD_CONST None 24 RETURN_VALUE diff --git a/uncompyle6/scanners/tok.py b/uncompyle6/scanners/tok.py index 83750d7d..e558729e 100644 --- a/uncompyle6/scanners/tok.py +++ b/uncompyle6/scanners/tok.py @@ -118,7 +118,8 @@ class Token(): elif self.op in self.opc.hasvargs: return "%s%s%s" % (prefix, offset_opname, argstr) elif self.op in self.opc.NAME_OPS: - return "%s%s%s %s" % (prefix, offset_opname, argstr, self.attr) + 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) From cd9eca7bffa6ab2a1c1e927b80e6ac33e0bb3c5c Mon Sep 17 00:00:00 2001 From: rocky Date: Tue, 11 Jun 2019 14:14:45 -0400 Subject: [PATCH 28/32] Formatting change slighty --- pytest/test_token.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/pytest/test_token.py b/pytest/test_token.py index 89173b60..07252b64 100644 --- a/pytest/test_token.py +++ b/pytest/test_token.py @@ -17,10 +17,7 @@ def test_token(): # Make sure formatting of: LOAD_CONST False. We assume False is the 0th index # of co_consts. t = Token('LOAD_CONST', offset=1, attr=False, pattr=False, has_arg=True) - if PYTHON_VERSION >= 3.0: - expect = ' 1 LOAD_CONST False' - else: - expect = ' 1 LOAD_CONST 0 False' + expect = ' 1 LOAD_CONST False' assert t.format() == expect if __name__ == '__main__': From c871a4ecc5a76b3fae245c57d139f1c45dc475b5 Mon Sep 17 00:00:00 2001 From: x0ret Date: Wed, 12 Jun 2019 00:26:34 +0430 Subject: [PATCH 29/32] Fix subscript in store_annotation + indentation --- uncompyle6/parsers/parse36.py | 1 + uncompyle6/semantics/customize36.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/uncompyle6/parsers/parse36.py b/uncompyle6/parsers/parse36.py index 02186375..edacf7e7 100644 --- a/uncompyle6/parsers/parse36.py +++ b/uncompyle6/parsers/parse36.py @@ -276,6 +276,7 @@ class Python36Parser(Python35Parser): 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 diff --git a/uncompyle6/semantics/customize36.py b/uncompyle6/semantics/customize36.py index cecec452..f1a04a01 100644 --- a/uncompyle6/semantics/customize36.py +++ b/uncompyle6/semantics/customize36.py @@ -61,7 +61,7 @@ def customize_for_version36(self, version): '%c(%p)', (0, 'expr'), (1, 100)), 'store_annotation': ( - '%|%[1]{pattr}: %c', + '%[1]{pattr}: %c', 0 ), 'ann_assign_init_value': ( From aea1adeb857a7d7e54bb598c1288a4b6bdbdb97b Mon Sep 17 00:00:00 2001 From: rocky Date: Tue, 11 Jun 2019 16:04:29 -0400 Subject: [PATCH 30/32] Reinstate test --- test/bytecode_3.6/05_ann_mopdule2.pyc | Bin 1254 -> 1394 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/test/bytecode_3.6/05_ann_mopdule2.pyc b/test/bytecode_3.6/05_ann_mopdule2.pyc index 5e4604ee190ca91072c774eae89b83668017ef2c..4b33083236f456926bb523ac4998a36b1e663747 100644 GIT binary patch delta 233 zcmaFH`H4%}n3tDpDhETX5fcN$V+JI^0%SV?aq*Oi%C$1?3@JP*ye$kVyv8#44V8K*R?U%CnITP0Gb8SD+XkwGDI<^FhnthGNdx6Fi0}gv!pNrwK3gd zat`y;WG!L?swrXz5gZ_b8A#k>E=w#b;skLK1Q&=a4kVO-xEN#w7bBSOrzv!6vIR>T Z7noNh0hF1%oJE;YYVv6oDP~qaW&n5;B?tfj delta 108 zcmeyw^^8;5n3tE!X#4*dGbRRx#|%h-1;};);^MZ6%C&r{0?iDm0`Y<=Ji!c_yc_ql zF;CvhlEo6mM3BMT!B69)?)6CVo)BNr13vk(UWzP=K@ From 58c8fe5a6674ea70eb761789d9a6ddfe4f686354 Mon Sep 17 00:00:00 2001 From: rocky Date: Tue, 11 Jun 2019 16:09:04 -0400 Subject: [PATCH 31/32] Oops - forgot to add the test source --- test/simple_source/bug36/05_ann_mopdule2.py | 37 +++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 test/simple_source/bug36/05_ann_mopdule2.py diff --git a/test/simple_source/bug36/05_ann_mopdule2.py b/test/simple_source/bug36/05_ann_mopdule2.py new file mode 100644 index 00000000..9b36a43e --- /dev/null +++ b/test/simple_source/bug36/05_ann_mopdule2.py @@ -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() From 3c06b82931c5a8abae6ecd6b5995e88528255017 Mon Sep 17 00:00:00 2001 From: rocky Date: Wed, 12 Jun 2019 11:31:21 -0400 Subject: [PATCH 32/32] Get ready for release 3.3.4 --- NEWS.md | 33 ++++++++++++++++++++++++--------- __pkginfo__.py | 2 +- uncompyle6/version.py | 2 +- 3 files changed, 26 insertions(+), 11 deletions(-) diff --git a/NEWS.md b/NEWS.md index 6e71ece2..0e5aee6e 100644 --- a/NEWS.md +++ b/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 ================================ 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 -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 done as good as what we have now. However this work will be done in a new project [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 and greater. * A number of Python 3.7+ chained comparisons were fixed * 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 ------------------ @@ -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+ * 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 * Add 3.8 try/else * Fix 2.7 generator decompilation @@ -80,14 +95,14 @@ Bug Fixes 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) * [#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) -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 @@ -152,14 +167,14 @@ Jesus on Friday's New York Times puzzle: "I'm stuck on 2A" - reduce 3.5, 3.6 control-flow bugs - reduce ambiguity in rules that lead to long (exponential?) parses - limit/isolate some 2.6/2.7,3.x grammar rules -- more runtime testing of decompiled code -- more removal of parenthesis around calls via setting precidence +- more run-time testing of decompiled code +- more removal of parenthesis around calls via setting precedence 3.1.0 2018-03-21 Equinox ============================== - 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 About 5% of 3.6 fail parsing now. But semantics still needs much to be desired. diff --git a/__pkginfo__.py b/__pkginfo__.py index b4bde950..1a116073 100644 --- a/__pkginfo__.py +++ b/__pkginfo__.py @@ -58,7 +58,7 @@ entry_points = { ]} ftp_url = None 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' mailing_list = 'python-debugger@googlegroups.com' diff --git a/uncompyle6/version.py b/uncompyle6/version.py index 4271e0be..16c93474 100644 --- a/uncompyle6/version.py +++ b/uncompyle6/version.py @@ -12,4 +12,4 @@ # along with this program. If not, see . # This file is suitable for sourcing inside bash as # well as importing into Python -VERSION='3.3.3' # noqa +VERSION='3.3.4' # noqa