|
| 1 | +""" |
| 2 | +This code translate .py files to .ipynb |
| 3 | +""" |
| 4 | +# Standard imports for file handling and JSON files |
| 5 | +import argparse |
| 6 | +import os |
| 7 | +import json |
| 8 | +import sys |
| 9 | + |
| 10 | +# Reserved Python keywords |
| 11 | +RESERVED = ['for', 'with', 'class', 'while'] |
| 12 | +HERE = os.path.abspath(os.path.dirname(__file__)) |
| 13 | + |
| 14 | +def main(): |
| 15 | + |
| 16 | + # Get source and target filenames |
| 17 | + parser = argparse.ArgumentParser(description='Parse a file.') |
| 18 | + parser.add_argument('source_filename', help='File to parse') |
| 19 | + parser.add_argument('-t', '--target_filename', help='Target filename') |
| 20 | + parser.add_argument('-o', '--overwrite', action='store_true', |
| 21 | + help='Flag to overwrite existing target file') |
| 22 | + args = parser.parse_args() |
| 23 | + source_filename = args.source_filename |
| 24 | + target_filename = args.target_filename |
| 25 | + overwrite = args.overwrite |
| 26 | + |
| 27 | + # Check if source file exists and read |
| 28 | + try: |
| 29 | + with open(source_filename, 'r') as file: |
| 30 | + data = [l.rstrip('\n') for l in file] |
| 31 | + except FileNotFoundError: |
| 32 | + print("Source file not found. Specify a valid source file.") |
| 33 | + sys.exit(1) |
| 34 | + |
| 35 | + # Check if target file is specified and exists. If not specified, create |
| 36 | + if target_filename is None: |
| 37 | + target_filename = os.path.splitext(source_filename)[0] + ".ipynb" |
| 38 | + print("Target file not specified. Creating a default notebook with name {}.".format( |
| 39 | + target_filename)) |
| 40 | + if not overwrite and os.path.isfile(target_filename): |
| 41 | + print("File {} exists. Add -o flag to overwrite or specify a different name.".format(target_filename)) |
| 42 | + sys.exit(1) |
| 43 | + |
| 44 | + # Read JSON files for .ipynb template |
| 45 | + with open(HERE + '/templates/cell_code.json') as file: |
| 46 | + code = json.load(file) |
| 47 | + with open(HERE + '/templates/cell_markdown.json') as file: |
| 48 | + markdown = json.load(file) |
| 49 | + with open(HERE + '/templates/metadata.json') as file: |
| 50 | + misc = json.load(file) |
| 51 | + |
| 52 | + # Initialise variables |
| 53 | + final = {} |
| 54 | + cells = [] |
| 55 | + arr = [] |
| 56 | + num_lines = len(data) |
| 57 | + |
| 58 | + # Initialise variables for checks |
| 59 | + is_block_comment = False |
| 60 | + end_paragraph = True |
| 61 | + is_running_comment = False |
| 62 | + is_running_code = False |
| 63 | + next_is_code = False |
| 64 | + next_is_nothing = False |
| 65 | + next_is_comment = False |
| 66 | + is_running_function = False |
| 67 | + next_is_function = False |
| 68 | + |
| 69 | + # Read source code line by line |
| 70 | + for i, line in enumerate(data): |
| 71 | + |
| 72 | + buffer = "" |
| 73 | + |
| 74 | + # Check next line |
| 75 | + try: |
| 76 | + next_is_code = data[i+1][0] != "#" |
| 77 | + except: |
| 78 | + pass |
| 79 | + try: |
| 80 | + next_is_comment = data[i+1][0] == "#" |
| 81 | + except: |
| 82 | + pass |
| 83 | + try: |
| 84 | + next_is_nothing = data[i+1] == "" |
| 85 | + except: |
| 86 | + pass |
| 87 | + try: |
| 88 | + next_is_function = data[i+1][:4] == " " or ( |
| 89 | + data[i+1] == "" and data[i+2][:4] == " ") |
| 90 | + # print(line) |
| 91 | + # print(data[i+1][:4] == "") |
| 92 | + except: |
| 93 | + pass |
| 94 | + end_of_code = i == num_lines-1 |
| 95 | + |
| 96 | + # Skip if line is empty |
| 97 | + if line == "": |
| 98 | + continue |
| 99 | + |
| 100 | + # Sub-paragraph is a comment but not a running code |
| 101 | + if (is_running_comment or (line[0] == "#" and (line[:8] != "# pylint" or line[:7] != "#pylint")) or line[:3] == "'''" or line[-3:] == "'''" or line[:3] == "\"\"\"" or line[-3:] == "\"\"\"") and not is_running_code: |
| 102 | + |
| 103 | + if line[:3] == "'''" or line[-3:] == "'''" or line[:3] == "\"\"\"" or line[-3:] == "\"\"\"": |
| 104 | + is_block_comment = not is_block_comment |
| 105 | + |
| 106 | + if is_block_comment: |
| 107 | + buffer = line.replace("'''", "").replace("\"\"\"", "") |
| 108 | + else: |
| 109 | + buffer = line[2:] |
| 110 | + |
| 111 | + # Wrap this sub-paragraph as a cell |
| 112 | + # if next line is code or next line is space or end of code |
| 113 | + if end_of_code or (next_is_code and not is_block_comment) or (next_is_nothing and not is_block_comment): |
| 114 | + arr.append(f"{buffer}") |
| 115 | + markdown["source"] = arr |
| 116 | + cells.append(dict(markdown)) |
| 117 | + arr = [] |
| 118 | + is_running_comment = False |
| 119 | + else: |
| 120 | + buffer = buffer + "<br>" |
| 121 | + arr.append(f"{buffer}") |
| 122 | + is_running_comment = True |
| 123 | + continue |
| 124 | + else: # Sub-paragraph is a comment but not a running code |
| 125 | + buffer = line |
| 126 | + |
| 127 | + # Close this if next line is end of code or next is nothing |
| 128 | + # Don't close if next is still part of a |
| 129 | + # or not next_is_function) or (not next_is_function and next_is_nothing): |
| 130 | + if (end_of_code or next_is_nothing) and not (next_is_nothing and next_is_function): |
| 131 | + arr.append(f"{buffer}") |
| 132 | + code["source"] = arr |
| 133 | + cells.append(dict(code)) |
| 134 | + arr = [] |
| 135 | + is_running_code = False |
| 136 | + else: |
| 137 | + buffer = buffer + "\n" |
| 138 | + |
| 139 | + # Put another newline character if in a function |
| 140 | + try: |
| 141 | + if data[i+1] == "" and (data[i+2][:5] == " #" or data[i+2][:9] == " #"): |
| 142 | + buffer = buffer + "\n" |
| 143 | + except: |
| 144 | + pass |
| 145 | + |
| 146 | + arr.append(f"{buffer}") |
| 147 | + is_running_code = True |
| 148 | + continue |
| 149 | + |
| 150 | + # Finalise the contents of notebook |
| 151 | + final["cells"] = cells |
| 152 | + final.update(misc) |
| 153 | + |
| 154 | + # Write JSON to target file |
| 155 | + with open(target_filename, 'w') as outfile: |
| 156 | + json.dump(final, outfile) |
| 157 | + print("Notebook {} written.".format(target_filename)) |
| 158 | + |
| 159 | + |
| 160 | +if __name__ == "__main__": |
| 161 | + print("Convert a Python script to Jupyter notebook") |
| 162 | + main() |
0 commit comments