Source code for pykubegrader.build.collate
import argparse
import json
import os
from nbformat.v4 import new_markdown_cell, new_notebook
[docs]
class QuestionCollator:
def __init__(self, root_folder: str, output_path: str):
"""
Initializes the QuestionCollator with the root folder and output path.
Args:
root_folder (str): Path to the root folder containing the solution files.
output_path (str): Path to save the collated notebook.
"""
self.root_folder = root_folder
self.output_path = output_path
[docs]
def find_solution_folders(self):
"""
Finds all immediate subdirectories inside '_solution*' folders that contain notebooks.
Returns:
list: List of folder paths containing notebooks.
"""
solution_folders = []
# Look for _solution* folders inside the root_folder
for dir_name in os.listdir(self.root_folder):
solution_folder_path = os.path.join(self.root_folder, dir_name)
if os.path.isdir(solution_folder_path) and dir_name.startswith("_solution"):
print(f"Found solution folder: {solution_folder_path}") # Debug output
# Now, look for immediate subdirectories inside this _solution* folder
for sub_dir in os.listdir(solution_folder_path):
sub_dir_path = os.path.join(solution_folder_path, sub_dir)
if os.path.isdir(sub_dir_path):
# Check if this subdirectory contains at least one .ipynb file
if any(f.endswith(".ipynb") for f in os.listdir(sub_dir_path)):
solution_folders.append(sub_dir_path)
print(f"Final list of solution subfolders: {solution_folders}") # Debug output
return solution_folders
[docs]
def create_collated_notebook(self, questions):
"""
Creates a new notebook with questions organized by type.
Args:
questions (dict): Dictionary of categorized questions.
Returns:
Notebook: The collated notebook.
"""
nb = new_notebook()
# Add Multiple Choice Questions
nb.cells.append(new_markdown_cell("# Multiple Choice Questions"))
for q in questions["multiple_choice"]:
nb.cells.append(new_markdown_cell(q["source"]))
# Add Select Many Questions
nb.cells.append(new_markdown_cell("# Select Many Questions"))
for q in questions["select_many"]:
nb.cells.append(new_markdown_cell(q["source"]))
# Add True/False Questions
nb.cells.append(new_markdown_cell("# True/False Questions"))
for q in questions["true_false"]:
nb.cells.append(new_markdown_cell(q["source"]))
# Add Other Questions
nb.cells.append(new_markdown_cell("# Other Questions"))
for q in questions["other"]:
nb.cells.append(new_markdown_cell(q["source"]))
return nb
[docs]
def save_notebook(self, nb):
"""
Saves the collated notebook to the specified output path.
Args:
nb (Notebook): The notebook to save.
"""
import nbformat
with open(self.output_path, "w") as f:
nbformat.write(nb, f)
[docs]
def collate_questions(self):
"""
Collates questions from all solution folders and saves them to a new notebook.
"""
solution_folders = self.find_solution_folders()
all_questions = {
"multiple_choice": [],
"select_many": [],
"true_false": [],
"other": [],
}
for folder in solution_folders:
questions = self.extract_questions(folder)
all_questions["multiple_choice"].extend(questions["multiple_choice"])
all_questions["select_many"].extend(questions["select_many"])
all_questions["true_false"].extend(questions["true_false"])
all_questions["other"].extend(questions["other"])
collated_nb = self.create_collated_notebook(all_questions)
self.save_notebook(collated_nb)
print(f"Collated notebook saved to {self.output_path}")
[docs]
def main():
parser = argparse.ArgumentParser(
description="Collate questions from solution folders into a single notebook."
)
parser.add_argument(
"root_folder",
type=str,
help="Path to the root folder containing solution folders",
)
parser.add_argument(
"output_path", type=str, help="Path to save the collated notebook"
)
args = parser.parse_args()
collator = QuestionCollator(
root_folder=args.root_folder, output_path=args.output_path
)
collator.collate_questions()
if __name__ == "__main__":
import sys
sys.exit(main())