diff options
Diffstat (limited to 'scripts/buildcommands.py')
-rw-r--r-- | scripts/buildcommands.py | 340 |
1 files changed, 224 insertions, 116 deletions
diff --git a/scripts/buildcommands.py b/scripts/buildcommands.py index b3587384..fa4303ed 100644 --- a/scripts/buildcommands.py +++ b/scripts/buildcommands.py @@ -6,7 +6,8 @@ # This file may be distributed under the terms of the GNU GPLv3 license. import sys, os, subprocess, optparse, logging, shlex, socket, time, traceback import json, zlib -sys.path.append('./klippy') + +sys.path.append("./klippy") import msgproto FILEHEADER = """ @@ -19,10 +20,12 @@ FILEHEADER = """ #include "initial_pins.h" """ + def error(msg): sys.stderr.write(msg + "\n") sys.exit(-1) + Handlers = [] @@ -30,23 +33,26 @@ Handlers = [] # C call list generation ###################################################################### + # Create dynamic C functions that call a list of other C functions class HandleCallList: def __init__(self): - self.call_lists = {'ctr_run_initfuncs': []} - self.ctr_dispatch = { '_DECL_CALLLIST': self.decl_calllist } + self.call_lists = {"ctr_run_initfuncs": []} + self.ctr_dispatch = {"_DECL_CALLLIST": self.decl_calllist} + def decl_calllist(self, req): funcname, callname = req.split()[1:] self.call_lists.setdefault(funcname, []).append(callname) + def update_data_dictionary(self, data): pass + def generate_code(self, options): code = [] for funcname, funcs in self.call_lists.items(): - func_code = [' extern void %s(void);\n %s();' % (f, f) - for f in funcs] - if funcname == 'ctr_run_taskfuncs': - add_poll = ' irq_poll();\n' + func_code = [" extern void %s(void);\n %s();" % (f, f) for f in funcs] + if funcname == "ctr_run_taskfuncs": + add_poll = " irq_poll();\n" func_code = [add_poll + fc for fc in func_code] func_code.append(add_poll) fmt = """ @@ -59,6 +65,7 @@ void code.append(fmt % (funcname, "\n".join(func_code).strip())) return "".join(code) + Handlers.append(HandleCallList()) @@ -68,41 +75,49 @@ Handlers.append(HandleCallList()) STATIC_STRING_MIN = 2 + # Generate a dynamic string to integer mapping class HandleEnumerations: def __init__(self): self.static_strings = [] self.enumerations = {} self.ctr_dispatch = { - '_DECL_STATIC_STR': self.decl_static_str, - 'DECL_ENUMERATION': self.decl_enumeration, - 'DECL_ENUMERATION_RANGE': self.decl_enumeration_range + "_DECL_STATIC_STR": self.decl_static_str, + "DECL_ENUMERATION": self.decl_enumeration, + "DECL_ENUMERATION_RANGE": self.decl_enumeration_range, } + def add_enumeration(self, enum, name, value): enums = self.enumerations.setdefault(enum, {}) if name in enums and enums[name] != value: - error("Conflicting definition for enumeration '%s %s'" % ( - enum, name)) + error("Conflicting definition for enumeration '%s %s'" % (enum, name)) enums[name] = value + def decl_enumeration(self, req): enum, name, value = req.split()[1:] self.add_enumeration(enum, name, int(value, 0)) + def decl_enumeration_range(self, req): enum, name, value, count = req.split()[1:] self.add_enumeration(enum, name, (int(value, 0), int(count, 0))) + def decl_static_str(self, req): msg = req.split(None, 1)[1] if msg not in self.static_strings: self.static_strings.append(msg) + def update_data_dictionary(self, data): for i, s in enumerate(self.static_strings): self.add_enumeration("static_string_id", s, i + STATIC_STRING_MIN) - data['enumerations'] = self.enumerations + data["enumerations"] = self.enumerations + def generate_code(self, options): code = [] for i, s in enumerate(self.static_strings): - code.append(' if (__builtin_strcmp(str, "%s") == 0)\n' - ' return %d;\n' % (s, i + STATIC_STRING_MIN)) + code.append( + ' if (__builtin_strcmp(str, "%s") == 0)\n' + " return %d;\n" % (s, i + STATIC_STRING_MIN) + ) fmt = """ uint8_t __always_inline ctr_lookup_static_string(const char *str) @@ -113,6 +128,7 @@ ctr_lookup_static_string(const char *str) """ return fmt % ("".join(code).strip(),) + HandlerEnumerations = HandleEnumerations() Handlers.append(HandlerEnumerations) @@ -121,32 +137,39 @@ Handlers.append(HandlerEnumerations) # Constants ###################################################################### + # Allow adding build time constants to the data dictionary class HandleConstants: def __init__(self): self.constants = {} self.ctr_dispatch = { - 'DECL_CONSTANT': self.decl_constant, - 'DECL_CONSTANT_STR': self.decl_constant_str, + "DECL_CONSTANT": self.decl_constant, + "DECL_CONSTANT_STR": self.decl_constant_str, } + def set_value(self, name, value): if name in self.constants and self.constants[name] != value: error("Conflicting definition for constant '%s'" % name) self.constants[name] = value + def decl_constant(self, req): name, value = req.split()[1:] self.set_value(name, int(value, 0)) + def decl_constant_str(self, req): name, value = req.split(None, 2)[1:] value = value.strip() if value.startswith('"') and value.endswith('"'): value = value[1:-1] self.set_value(name, value) + def update_data_dictionary(self, data): - data['config'] = self.constants + data["config"] = self.constants + def generate_code(self, options): return "" + HandlerConstants = HandleConstants() Handlers.append(HandlerConstants) @@ -155,37 +178,42 @@ Handlers.append(HandlerConstants) # Initial pins ###################################################################### + class HandleInitialPins: def __init__(self): self.initial_pins = [] - self.ctr_dispatch = { 'DECL_INITIAL_PINS': self.decl_initial_pins } + self.ctr_dispatch = {"DECL_INITIAL_PINS": self.decl_initial_pins} + def decl_initial_pins(self, req): pins = req.split(None, 1)[1].strip() if pins.startswith('"') and pins.endswith('"'): pins = pins[1:-1] if pins: - self.initial_pins = [p.strip() for p in pins.split(',')] + self.initial_pins = [p.strip() for p in pins.split(",")] HandlerConstants.decl_constant_str( - "_DECL_CONSTANT_STR INITIAL_PINS " - + ','.join(self.initial_pins)) + "_DECL_CONSTANT_STR INITIAL_PINS " + ",".join(self.initial_pins) + ) + def update_data_dictionary(self, data): pass + def map_pins(self): if not self.initial_pins: return [] mp = msgproto.MessageParser() mp.fill_enumerations(HandlerEnumerations.enumerations) - pinmap = mp.get_enumerations().get('pin', {}) + pinmap = mp.get_enumerations().get("pin", {}) out = [] for p in self.initial_pins: flag = "IP_OUT_HIGH" - if p.startswith('!'): + if p.startswith("!"): flag = "0" p = p[1:].strip() if p not in pinmap: error("Unknown initial pin '%s'" % (p,)) out.append("\n {%d, %s}, // %s" % (pinmap[p], flag, p)) return out + def generate_code(self, options): out = self.map_pins() fmt = """ @@ -193,7 +221,8 @@ const struct initial_pin_s initial_pins[] PROGMEM = {%s }; const int initial_pins_size PROGMEM = ARRAY_SIZE(initial_pins); """ - return fmt % (''.join(out),) + return fmt % ("".join(out),) + Handlers.append(HandleInitialPins()) @@ -202,20 +231,26 @@ Handlers.append(HandleInitialPins()) # ARM IRQ vector table generation ###################################################################### + # Create ARM IRQ vector table from interrupt handler declarations class Handle_arm_irq: def __init__(self): self.irqs = {} - self.ctr_dispatch = { 'DECL_ARMCM_IRQ': self.decl_armcm_irq } + self.ctr_dispatch = {"DECL_ARMCM_IRQ": self.decl_armcm_irq} + def decl_armcm_irq(self, req): func, num = req.split()[1:] num = int(num, 0) if num in self.irqs and self.irqs[num] != func: - error("Conflicting IRQ definition %d (old %s new %s)" - % (num, self.irqs[num], func)) + error( + "Conflicting IRQ definition %d (old %s new %s)" + % (num, self.irqs[num], func) + ) self.irqs[num] = func + def update_data_dictionary(self, data): pass + def generate_code(self, options): armcm_offset = 16 if 1 - armcm_offset not in self.irqs: @@ -237,7 +272,8 @@ extern uint32_t _stack_end; const void *VectorTable[] __visible __section(".vector_table") = { %s}; """ - return fmt % (''.join(defs), ''.join(table)) + return fmt % ("".join(defs), "".join(table)) + Handlers.append(Handle_arm_irq()) @@ -246,6 +282,7 @@ Handlers.append(Handle_arm_irq()) # Wire protocol commands and responses ###################################################################### + # Dynamic command and response registration class HandleCommandGeneration: def __init__(self): @@ -253,13 +290,14 @@ class HandleCommandGeneration: self.encoders = [] self.msg_to_encid = dict(msgproto.DefaultMessages) self.encid_to_msgid = {} - self.messages_by_name = { m.split()[0]: m for m in self.msg_to_encid } + self.messages_by_name = {m.split()[0]: m for m in self.msg_to_encid} self.all_param_types = {} self.ctr_dispatch = { - 'DECL_COMMAND_FLAGS': self.decl_command, - '_DECL_ENCODER': self.decl_encoder, - '_DECL_OUTPUT': self.decl_output + "DECL_COMMAND_FLAGS": self.decl_command, + "_DECL_ENCODER": self.decl_encoder, + "_DECL_OUTPUT": self.decl_output, } + def decl_command(self, req): funcname, flags, msgname = req.split()[1:4] if msgname in self.commands: @@ -270,6 +308,7 @@ class HandleCommandGeneration: if m is not None and m != msg: error("Conflicting definition for command '%s'" % msgname) self.messages_by_name[msgname] = msg + def decl_encoder(self, req): msg = req.split(None, 1)[1] msgname = msg.split()[0] @@ -278,15 +317,18 @@ class HandleCommandGeneration: error("Conflicting definition for message '%s'" % msgname) self.messages_by_name[msgname] = msg self.encoders.append((msgname, msg)) + def decl_output(self, req): msg = req.split(None, 1)[1] self.encoders.append((None, msg)) + def convert_encoded_msgid(self, encoded_msgid): if encoded_msgid >= 0x80: - data = [(encoded_msgid >> 7) | 0x80, encoded_msgid & 0x7f] + data = [(encoded_msgid >> 7) | 0x80, encoded_msgid & 0x7F] else: data = [encoded_msgid] return msgproto.PT_int32().parse(data, 0)[0] + def create_message_ids(self): # Create unique ids for each message type encoded_msgid = max(self.msg_to_encid.values()) @@ -296,31 +338,44 @@ class HandleCommandGeneration: if msg not in self.msg_to_encid: encoded_msgid += 1 self.msg_to_encid[msg] = encoded_msgid - if encoded_msgid >= 1<<14: + if encoded_msgid >= 1 << 14: # The mcu currently assumes all message ids encode to 1 or 2 bytes error("Too many message ids") self.encid_to_msgid = { encoded_msgid: self.convert_encoded_msgid(encoded_msgid) for encoded_msgid in self.msg_to_encid.values() } + def update_data_dictionary(self, data): # Convert ids to standard form (use both positive and negative numbers) - msg_to_msgid = {msg: self.encid_to_msgid[encoded_msgid] - for msg, encoded_msgid in self.msg_to_encid.items()} - command_ids = [msg_to_msgid[msg] - for msgname, msg in self.messages_by_name.items() - if msgname in self.commands] - response_ids = [msg_to_msgid[msg] - for msgname, msg in self.messages_by_name.items() - if msgname not in self.commands] - data['commands'] = { msg: msgid for msg, msgid in msg_to_msgid.items() - if msgid in command_ids } - data['responses'] = { msg: msgid for msg, msgid in msg_to_msgid.items() - if msgid in response_ids } - output = {msg: msgid for msg, msgid in msg_to_msgid.items() - if msgid not in command_ids and msgid not in response_ids} + msg_to_msgid = { + msg: self.encid_to_msgid[encoded_msgid] + for msg, encoded_msgid in self.msg_to_encid.items() + } + command_ids = [ + msg_to_msgid[msg] + for msgname, msg in self.messages_by_name.items() + if msgname in self.commands + ] + response_ids = [ + msg_to_msgid[msg] + for msgname, msg in self.messages_by_name.items() + if msgname not in self.commands + ] + data["commands"] = { + msg: msgid for msg, msgid in msg_to_msgid.items() if msgid in command_ids + } + data["responses"] = { + msg: msgid for msg, msgid in msg_to_msgid.items() if msgid in response_ids + } + output = { + msg: msgid + for msg, msgid in msg_to_msgid.items() + if msgid not in command_ids and msgid not in response_ids + } if output: - data['output'] = output + data["output"] = output + def build_parser(self, encoded_msgid, msgformat, msgtype): if msgtype == "output": param_types = msgproto.lookup_output_params(msgformat) @@ -328,34 +383,46 @@ class HandleCommandGeneration: else: param_types = [t for name, t in msgproto.lookup_params(msgformat)] comment = msgformat - params = '0' + params = "0" types = tuple([t.__class__.__name__ for t in param_types]) if types: paramid = self.all_param_types.get(types) if paramid is None: paramid = len(self.all_param_types) self.all_param_types[types] = paramid - params = 'command_parameters%d' % (paramid,) + params = "command_parameters%d" % (paramid,) out = """ // %s .encoded_msgid=%d, // msgid=%d .num_params=%d, .param_types = %s, -""" % (comment, encoded_msgid, self.encid_to_msgid[encoded_msgid], - len(types), params) - if msgtype == 'response': - num_args = (len(types) + types.count('PT_progmem_buffer') - + types.count('PT_buffer')) +""" % ( + comment, + encoded_msgid, + self.encid_to_msgid[encoded_msgid], + len(types), + params, + ) + if msgtype == "response": + num_args = ( + len(types) + types.count("PT_progmem_buffer") + types.count("PT_buffer") + ) out += " .num_args=%d," % (num_args,) else: msgid_size = 1 if encoded_msgid >= 0x80: msgid_size = 2 - max_size = min(msgproto.MESSAGE_MAX, - (msgproto.MESSAGE_MIN + msgid_size - + sum([t.max_length for t in param_types]))) + max_size = min( + msgproto.MESSAGE_MAX, + ( + msgproto.MESSAGE_MIN + + msgid_size + + sum([t.max_length for t in param_types]) + ), + ) out += " .max_size=%d," % (max_size,) return out + def generate_responses_code(self): encoder_defs = [] output_code = [] @@ -366,19 +433,20 @@ class HandleCommandGeneration: if encoded_msgid in did_output: continue did_output[encoded_msgid] = True - code = (' if (__builtin_strcmp(str, "%s") == 0)\n' - ' return &command_encoder_%s;\n' - % (msg, encoded_msgid)) + code = ( + ' if (__builtin_strcmp(str, "%s") == 0)\n' + " return &command_encoder_%s;\n" % (msg, encoded_msgid) + ) if msgname is None: - parsercode = self.build_parser(encoded_msgid, msg, 'output') + parsercode = self.build_parser(encoded_msgid, msg, "output") output_code.append(code) else: - parsercode = self.build_parser(encoded_msgid, msg, 'command') + parsercode = self.build_parser(encoded_msgid, msg, "command") encoder_code.append(code) encoder_defs.append( "const struct command_encoder command_encoder_%s PROGMEM = {" - " %s\n};\n" % ( - encoded_msgid, parsercode)) + " %s\n};\n" % (encoded_msgid, parsercode) + ) fmt = """ %s @@ -396,9 +464,12 @@ ctr_lookup_output(const char *str) return NULL; } """ - return fmt % ("".join(encoder_defs).strip(), - "".join(encoder_code).strip(), - "".join(output_code).strip()) + return fmt % ( + "".join(encoder_defs).strip(), + "".join(encoder_code).strip(), + "".join(output_code).strip(), + ) + def generate_commands_code(self): cmd_by_encid = { self.msg_to_encid[self.messages_by_name.get(msgname, msgname)]: cmd @@ -407,19 +478,21 @@ ctr_lookup_output(const char *str) max_cmd_encid = max(cmd_by_encid.keys()) index = [] externs = {} - for encoded_msgid in range(max_cmd_encid+1): + for encoded_msgid in range(max_cmd_encid + 1): if encoded_msgid not in cmd_by_encid: index.append(" {\n},") continue funcname, flags, msgname = cmd_by_encid[encoded_msgid] msg = self.messages_by_name[msgname] externs[funcname] = 1 - parsercode = self.build_parser(encoded_msgid, msg, 'response') - index.append(" {%s\n .flags=%s,\n .func=%s\n}," % ( - parsercode, flags, funcname)) + parsercode = self.build_parser(encoded_msgid, msg, "response") + index.append( + " {%s\n .flags=%s,\n .func=%s\n}," % (parsercode, flags, funcname) + ) index = "".join(index).strip() - externs = "\n".join(["extern void "+funcname+"(uint32_t*);" - for funcname in sorted(externs)]) + externs = "\n".join( + ["extern void " + funcname + "(uint32_t*);" for funcname in sorted(externs)] + ) fmt = """ %s @@ -430,17 +503,22 @@ const struct command_parser command_index[] PROGMEM = { const uint16_t command_index_size PROGMEM = ARRAY_SIZE(command_index); """ return fmt % (externs, index) + def generate_param_code(self): - sorted_param_types = sorted( - [(i, a) for a, i in self.all_param_types.items()]) - params = [''] + sorted_param_types = sorted([(i, a) for a, i in self.all_param_types.items()]) + params = [""] for paramid, argtypes in sorted_param_types: params.append( - 'static const uint8_t command_parameters%d[] PROGMEM = {\n' - ' %s };' % ( - paramid, ', '.join(argtypes),)) - params.append('') + "static const uint8_t command_parameters%d[] PROGMEM = {\n" + " %s };" + % ( + paramid, + ", ".join(argtypes), + ) + ) + params.append("") return "\n".join(params) + def generate_code(self, options): self.create_message_ids() parsercode = self.generate_responses_code() @@ -448,6 +526,7 @@ const uint16_t command_index_size PROGMEM = ARRAY_SIZE(command_index); paramcode = self.generate_param_code() return paramcode + parsercode + cmdcode + Handlers.append(HandleCommandGeneration()) @@ -455,6 +534,7 @@ Handlers.append(HandleCommandGeneration()) # Version generation ###################################################################### + # Run program and return the specified output def check_output(prog): logging.debug("Running %s" % (repr(prog),)) @@ -469,26 +549,28 @@ def check_output(prog): if retcode: return "" try: - return str(output.decode('utf8')) + return str(output.decode("utf8")) except UnicodeError: logging.debug("Exception on decode: %s" % (traceback.format_exc(),)) return "" + # Obtain version info from "git" program def git_version(): - if not os.path.exists('.git'): + if not os.path.exists(".git"): logging.debug("No '.git' file/directory found") return "" ver = check_output("git describe --always --tags --long --dirty").strip() logging.debug("Got git version: %s" % (repr(ver),)) return ver + def build_version(extra, cleanbuild): version = git_version() if not version: cleanbuild = False version = "?" - elif 'dirty' in version: + elif "dirty" in version: cleanbuild = False if not cleanbuild: btime = time.strftime("%Y%m%d_%H%M%S") @@ -496,29 +578,31 @@ def build_version(extra, cleanbuild): version = "%s-%s-%s" % (version, btime, hostname) return version + extra + # Run "tool --version" for each specified tool and extract versions def tool_versions(tools): - tools = [t.strip() for t in tools.split(';')] - versions = ['', ''] + tools = [t.strip() for t in tools.split(";")] + versions = ["", ""] success = 0 for tool in tools: # Extract first line from "tool --version" output - verstr = check_output("%s --version" % (tool,)).split('\n')[0] + verstr = check_output("%s --version" % (tool,)).split("\n")[0] # Check if this tool looks like a binutils program isbinutils = 0 - if verstr.startswith('GNU '): + if verstr.startswith("GNU "): isbinutils = 1 verstr = verstr[4:] # Extract version information and exclude program name - if ' ' not in verstr: + if " " not in verstr: continue - prog, ver = verstr.split(' ', 1) + prog, ver = verstr.split(" ", 1) if not prog or not ver: continue # Check for any version conflicts if versions[isbinutils] and versions[isbinutils] != ver: - logging.debug("Mixed version %s vs %s" % ( - repr(versions[isbinutils]), repr(ver))) + logging.debug( + "Mixed version %s vs %s" % (repr(versions[isbinutils]), repr(ver)) + ) versions[isbinutils] = "mixed" continue versions[isbinutils] = ver @@ -526,22 +610,28 @@ def tool_versions(tools): cleanbuild = versions[0] and versions[1] and success == len(tools) return cleanbuild, "gcc: %s binutils: %s" % (versions[0], versions[1]) + # Add version information to the data dictionary class HandleVersions: def __init__(self): self.ctr_dispatch = {} self.toolstr = self.version = "" + def update_data_dictionary(self, data): - data['version'] = self.version - data['build_versions'] = self.toolstr - data['app'] = 'Klipper' - data['license'] = 'GNU GPLv3' + data["version"] = self.version + data["build_versions"] = self.toolstr + data["app"] = "Klipper" + data["license"] = "GNU GPLv3" + def generate_code(self, options): cleanbuild, self.toolstr = tool_versions(options.tools) self.version = build_version(options.extra, cleanbuild) sys.stdout.write("Version: %s\n" % (self.version,)) return "\n// version: %s\n// build_versions: %s\n" % ( - self.version, self.toolstr) + self.version, + self.toolstr, + ) + Handlers.append(HandleVersions()) @@ -550,22 +640,25 @@ Handlers.append(HandleVersions()) # Identify data dictionary generation ###################################################################### + # Automatically generate the wire protocol data dictionary class HandleIdentify: def __init__(self): self.ctr_dispatch = {} + def update_data_dictionary(self, data): pass + def generate_code(self, options): # Generate data dictionary data = {} for h in Handlers: h.update_data_dictionary(data) - datadict = json.dumps(data, separators=(',', ':'), sort_keys=True) + datadict = json.dumps(data, separators=(",", ":"), sort_keys=True) # Write data dictionary if options.write_dictionary: - f = open(options.write_dictionary, 'w') + f = open(options.write_dictionary, "w") f.write(datadict) f.close() @@ -574,7 +667,7 @@ class HandleIdentify: out = [] for i in range(len(zdatadict)): if i % 8 == 0: - out.append('\n ') + out.append("\n ") out.append(" 0x%02x," % (zdatadict[i],)) fmt = """ const uint8_t command_identify_data[] PROGMEM = {%s @@ -584,7 +677,8 @@ const uint8_t command_identify_data[] PROGMEM = {%s const uint32_t command_identify_size PROGMEM = ARRAY_SIZE(command_identify_data); """ - return fmt % (''.join(out), len(zdatadict), len(datadict)) + return fmt % ("".join(out), len(zdatadict), len(datadict)) + Handlers.append(HandleIdentify()) @@ -593,17 +687,30 @@ Handlers.append(HandleIdentify()) # Main code ###################################################################### + def main(): usage = "%prog [options] <cmd section file> <output.c>" opts = optparse.OptionParser(usage) - opts.add_option("-e", "--extra", dest="extra", default="", - help="extra version string to append to version") - opts.add_option("-d", dest="write_dictionary", - help="file to write mcu protocol dictionary") - opts.add_option("-t", "--tools", dest="tools", default="", - help="list of build programs to extract version from") - opts.add_option("-v", action="store_true", dest="verbose", - help="enable debug messages") + opts.add_option( + "-e", + "--extra", + dest="extra", + default="", + help="extra version string to append to version", + ) + opts.add_option( + "-d", dest="write_dictionary", help="file to write mcu protocol dictionary" + ) + opts.add_option( + "-t", + "--tools", + dest="tools", + default="", + help="list of build programs to extract version from", + ) + opts.add_option( + "-v", action="store_true", dest="verbose", help="enable debug messages" + ) options, args = opts.parse_args() if len(args) != 2: @@ -613,11 +720,11 @@ def main(): logging.basicConfig(level=logging.DEBUG) # Parse request file - ctr_dispatch = { k: v for h in Handlers for k, v in h.ctr_dispatch.items() } - f = open(incmdfile, 'r') + ctr_dispatch = {k: v for h in Handlers for k, v in h.ctr_dispatch.items()} + f = open(incmdfile, "r") data = f.read() f.close() - for req in data.split('\n'): + for req in data.split("\n"): req = req.lstrip() if not req: continue @@ -628,9 +735,10 @@ def main(): # Write output code = "".join([FILEHEADER] + [h.generate_code(options) for h in Handlers]) - f = open(outcfile, 'w') + f = open(outcfile, "w") f.write(code) f.close() -if __name__ == '__main__': + +if __name__ == "__main__": main() |