1# (C) Copyright 2020 by Rocky Bernstein 2# 3# This program is free software; you can redistribute it and/or 4# modify it under the terms of the GNU General Public License 5# as published by the Free Software Foundation; either version 2 6# of the License, or (at your option) any later version. 7# 8# This program is distributed in the hope that it will be useful, 9# but WITHOUT ANY WARRANTY; without even the implied warranty of 10# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11# GNU General Public License for more details. 12# 13# You should have received a copy of the GNU General Public License 14# along with this program; if not, write to the Free Software 15# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 16 17from xdis.version_info import PYTHON_VERSION 18from xdis.codetype.code30 import Code3, Code3FieldTypes 19import types 20from copy import deepcopy 21 22# Note: order is the positional order. It is important to match this 23# with the 3.8 order. 24Code38FieldNames = """ 25 co_argcount 26 co_posonlyargcount 27 co_kwonlyargcount 28 co_nlocals 29 co_stacksize 30 co_flags 31 co_code 32 co_consts 33 co_names 34 co_varnames 35 co_filename 36 co_name 37 co_firstlineno 38 co_lnotab 39 co_freevars 40 co_cellvars 41""" 42 43Code38FieldTypes = deepcopy(Code3FieldTypes) 44Code38FieldTypes.update({ 45 "co_posonlyargcount": int, 46}) 47 48 49 50class Code38(Code3): 51 """Class for a Python 3.8+ code object used when a Python interpreter less than 3.8 is 52 working on Python3 bytecode. It also functions as an object that can be used 53 to build or write a Python3 code object, since we allow mutable structures. 54 55 When done mutating, call method to_native(). 56 57 For convenience in generating code objects, fields like 58 `co_consts`, co_names which are (immutable) tuples in the end-result can be stored 59 instead as (mutable) lists. Likewise the line number table `co_lnotab` 60 can be stored as a simple list of offset, line_number tuples. 61 """ 62 63 def __init__( 64 self, 65 co_argcount, 66 co_posonlyargcount, 67 co_kwonlyargcount, 68 co_nlocals, 69 co_stacksize, 70 co_flags, 71 co_code, 72 co_consts, 73 co_names, 74 co_varnames, 75 co_filename, 76 co_name, 77 co_firstlineno, 78 co_lnotab, 79 co_freevars, 80 co_cellvars, 81 ): 82 super(Code38, self).__init__( 83 co_argcount, 84 co_kwonlyargcount, 85 co_nlocals, 86 co_stacksize, 87 co_flags, 88 co_code, 89 co_consts, 90 co_names, 91 co_varnames, 92 co_filename, 93 co_name, 94 co_firstlineno, 95 co_lnotab, 96 co_freevars, 97 co_cellvars, 98 ) 99 self.co_posonlyargcount = co_posonlyargcount 100 self.fieldtypes = Code38FieldTypes 101 if type(self) == Code38: 102 self.check() 103 104 def to_native(self): 105 if not (PYTHON_VERSION >= 3.8): 106 raise TypeError( 107 "Python Interpreter needs to be in 3.8 or greater; is %s" 108 % PYTHON_VERSION 109 ) 110 111 code = deepcopy(self) 112 code.freeze() 113 try: 114 code.check() 115 except AssertionError as e: 116 raise TypeError(e) 117 118 return types.CodeType( 119 code.co_argcount, 120 code.co_posonlyargcount, 121 code.co_kwonlyargcount, 122 code.co_nlocals, 123 code.co_stacksize, 124 code.co_flags, 125 code.co_code, 126 code.co_consts, 127 code.co_names, 128 code.co_varnames, 129 code.co_filename, 130 code.co_name, 131 code.co_firstlineno, 132 code.co_lnotab, 133 code.co_freevars, 134 code.co_cellvars, 135 ) 136