Source code for pykubegrader.build.markdown_questions
import argparse
import os
import nbformat as nbf
[docs]
class MarkdownToNotebook:
def __init__(self, markdown_file: str):
"""
Initializes the MarkdownToNotebook converter with the Markdown file path.
Args:
markdown_file (str): Path to the Markdown file to convert.
"""
self.markdown_file = markdown_file
[docs]
def convert_and_save(self):
"""
Converts the Markdown file into a Jupyter Notebook and saves it with the same name.
"""
if not os.path.exists(self.markdown_file):
print(f"Error: File '{self.markdown_file}' does not exist.")
return
notebook_name = os.path.splitext(self.markdown_file)[0] + ".ipynb"
with open(self.markdown_file, "r") as f:
content = f.read()
# Split content into lines
lines = content.splitlines()
nb = nbf.v4.new_notebook()
cells = []
current_cell = ""
current_type = None
for line in lines:
if line.startswith("# %%"):
if current_cell: # Save the previous cell
if current_type == "markdown":
cells.append(nbf.v4.new_markdown_cell(current_cell.strip()))
elif current_type == "code":
cells.append(nbf.v4.new_code_cell(current_cell.strip()))
elif current_type == "raw":
cells.append(nbf.v4.new_raw_cell(current_cell.strip()))
# Start a new cell
current_cell = ""
if "[markdown]" in line:
current_type = "markdown"
elif (
"# BEGIN" in line
or "# END" in line
or "# ASSIGNMENT CONFIG" in line
):
current_type = "raw"
else:
current_type = "code"
else:
# Append lines to the current cell
if current_type == "markdown" and line.startswith("# "):
current_cell += line[2:] + "\n"
else:
current_cell += line + "\n"
# Save the last cell
if current_cell:
if current_type == "markdown":
cells.append(nbf.v4.new_markdown_cell(current_cell.strip()))
elif current_type == "code":
cells.append(nbf.v4.new_code_cell(current_cell.strip()))
elif current_type == "raw":
cell = nbf.v4.new_raw_cell(current_cell.strip())
cell["metadata"]["languageId"] = "raw"
cell["metadata"]["cell_type"] = "raw"
cells.append(cell)
nb["cells"] = cells
# Write the notebook
with open(notebook_name, "w") as f:
nbf.write(nb, f)
self.modify_notebook(notebook_name)
print(f"Notebook saved as: {notebook_name}")
[docs]
@staticmethod
def modify_notebook(notebook_path: str):
"""
Modifies an existing Jupyter Notebook by converting cells containing specific markers
("# BEGIN T", "# END", "# ASSIGNMENT CONFIG") into raw cells.
Args:
notebook_path (str): Path to the existing Jupyter Notebook to modify.
"""
if not os.path.exists(notebook_path):
print(f"Error: Notebook '{notebook_path}' does not exist.")
return
with open(notebook_path, "r") as f:
nb = nbf.read(f, as_version=4)
for cell in nb["cells"]:
if cell["cell_type"] == "code" and cell["source"].startswith(
(
"# BEGIN TESTS",
"# END TESTS",
"# END SOLUTION",
"# BEGIN QUESTION",
"# ASSIGNMENT CONFIG",
"# END TF",
"# BEGIN TF",
)
):
cell["cell_type"] = "raw"
if "metadata" not in cell:
cell["metadata"] = {}
cell["metadata"] = {"vscode": {"languageId": "raw"}}
with open(notebook_path, "w") as f:
nbf.write(nb, f)
[docs]
def main():
parser = argparse.ArgumentParser(
description="Convert a Markdown file with Jupyter-style cells into a Jupyter Notebook."
)
parser.add_argument(
"markdown_file", type=str, help="Path to the Markdown file to convert."
)
args = parser.parse_args()
converter = MarkdownToNotebook(markdown_file=args.markdown_file)
converter.convert_and_save()
if __name__ == "__main__":
main()