\n"""
@@ -539,7 +544,6 @@ def process_multiple_choice(part_name, parsed_question, data_dict):
## Note: `|@`` gets converted into `{{` and `@|`` gets converted to `}}` by `replace_tags()`
for a in data_dict["params"][f"{part_name}"].keys():
-
if "ans" in a:
if data_dict["params"][f"{part_name}"][f"{a}"]["feedback"]:
feedback = f"|@ params.{part_name}.{a}.feedback @|"
@@ -550,7 +554,7 @@ def process_multiple_choice(part_name, parsed_question, data_dict):
value = f"|@ params.{part_name}.{a}.value @|"
## Hack to remove feedback for Dropdown questions
- if parsed_question["header"][part_name]['type'] == 'dropdown':
+ if parsed_question["header"][part_name]["type"] == "dropdown":
html += f"\t {value} {units} \n"
else:
html += f"\t {value} {units} \n"
@@ -571,7 +575,9 @@ def process_dropdown(part_name, parsed_question, data_dict):
Returns:
html: A string of HTML that is part of the final PL question.html file.
"""
- html = process_multiple_choice(part_name, parsed_question, data_dict).replace("-multiple-choice", "-dropdown")
+ html = process_multiple_choice(part_name, parsed_question, data_dict).replace(
+ "-multiple-choice", "-dropdown"
+ )
return html
@@ -590,7 +596,10 @@ def process_number_input(part_name, parsed_question, data_dict):
html = f"""\n\t{parsed_question['body_parts_split'][part_name]['content']}\t\n\n\n"""
pl_customizations = " ".join(
- [f'{k} = "{v}"' for k, v in parsed_question["header"][part_name]["pl-customizations"].items()]
+ [
+ f'{k} = "{v}"'
+ for k, v in parsed_question["header"][part_name]["pl-customizations"].items()
+ ]
) # PL-customizations
html += f"""\n"""
@@ -609,7 +618,9 @@ def process_checkbox(part_name, parsed_question, data_dict):
html: A string of HTML that is part of the final PL question.html file.
"""
# start with the MCQ version and then...change things for checkbox questions
- html = process_multiple_choice(part_name, parsed_question, data_dict).replace("-multiple-choice", "-checkbox")
+ html = process_multiple_choice(part_name, parsed_question, data_dict).replace(
+ "-multiple-choice", "-checkbox"
+ )
return html
@@ -628,7 +639,10 @@ def process_symbolic_input(part_name, parsed_question, data_dict):
html = f"""\n\t{parsed_question['body_parts_split'][part_name]['content']}\t\n\n\n"""
pl_customizations = " ".join(
- [f'{k} = "{v}"' for k, v in parsed_question["header"][part_name]["pl-customizations"].items()]
+ [
+ f'{k} = "{v}"'
+ for k, v in parsed_question["header"][part_name]["pl-customizations"].items()
+ ]
) # PL-customizations
html += f"""\n"""
@@ -646,7 +660,10 @@ def process_longtext(part_name, parsed_question, data_dict):
html: A string of HTML that is part of the final PL question.html file.
"""
pl_customizations = " ".join(
- [f'{k} = "{v}"' for k, v in parsed_question["header"][part_name]["pl-customizations"].items()]
+ [
+ f'{k} = "{v}"'
+ for k, v in parsed_question["header"][part_name]["pl-customizations"].items()
+ ]
) # PL-customizations
html = f"""\n{parsed_question['body_parts_split'][part_name]['content']}\n\n\n"""
@@ -667,7 +684,10 @@ def process_file_upload(part_name, parsed_question, data_dict):
html: A string of HTML that is part of the final PL question.html file.
"""
pl_customizations = " ".join(
- [f'{k} = "{v}"' for k, v in parsed_question["header"][part_name]["pl-customizations"].items()]
+ [
+ f'{k} = "{v}"'
+ for k, v in parsed_question["header"][part_name]["pl-customizations"].items()
+ ]
) # PL-customizations
html = f"""\n{parsed_question['body_parts_split'][part_name]['content']}\n\n\n"""
@@ -697,7 +717,10 @@ def process_file_editor(part_name, parsed_question, data_dict):
html: A string of HTML that is part of the final PL question.html file.
"""
pl_customizations = " ".join(
- [f'{k} = "{v}"' for k, v in parsed_question["header"][part_name]["pl-customizations"].items()]
+ [
+ f'{k} = "{v}"'
+ for k, v in parsed_question["header"][part_name]["pl-customizations"].items()
+ ]
) # PL-customizations
html = f"""\n{parsed_question['body_parts_split'][part_name]['content']}\n\n\n"""
@@ -706,6 +729,7 @@ def process_file_editor(part_name, parsed_question, data_dict):
return replace_tags(html)
+
def process_string_input(part_name, parsed_question, data_dict):
"""Processes markdown format of string-input questions and returns PL HTML
Args:
@@ -717,7 +741,10 @@ def process_string_input(part_name, parsed_question, data_dict):
html: A string of HTML that is part of the final PL question.html file.
"""
pl_customizations = " ".join(
- [f'{k} = "{v}"' for k, v in parsed_question["header"][part_name]["pl-customizations"].items()]
+ [
+ f'{k} = "{v}"'
+ for k, v in parsed_question["header"][part_name]["pl-customizations"].items()
+ ]
) # PL-customizations
html = f"""\n{parsed_question['body_parts_split'][part_name]['content']}\n\n\n"""
@@ -726,6 +753,7 @@ def process_string_input(part_name, parsed_question, data_dict):
return replace_tags(html)
+
def replace_tags(string):
"""Takes in a string with tags: |@ and @| and returns {{ and }} respectively. This is because Python strings can't have double curly braces.
@@ -735,7 +763,9 @@ def replace_tags(string):
Returns:
string (str): returns string with tags replaced with curly braces.
"""
- return string.replace("|@|@", "{{{").replace("@|@|", "}}}").replace("|@", "{{").replace("@|", "}}")
+ return (
+ string.replace("|@|@", "{{{").replace("@|@|", "}}}").replace("|@", "{{").replace("@|", "}}")
+ )
def remove_correct_answers(data2_dict):
@@ -778,7 +808,7 @@ def process_attribution(attribution):
"""
with importlib.resources.open_text("problem_bank_scripts", "attributions.json") as file:
- possible_attributions = json.load(file)
+ possible_attributions = json.load(file)
try:
attribution_text = possible_attributions[attribution]
@@ -793,7 +823,6 @@ def process_attribution(attribution):
def process_question_md(source_filepath, output_path=None, instructor=False):
-
try:
pathlib.Path(source_filepath)
except:
@@ -809,7 +838,9 @@ def process_question_md(source_filepath, output_path=None, instructor=False):
if "source" in source_filepath:
output_path = pathlib.Path(source_filepath.replace("source", path_replace))
else:
- raise NotImplementedError("Check the source filepath; it does not have 'source' in it!! ")
+ raise NotImplementedError(
+ "Check the source filepath; it does not have 'source' in it!! "
+ )
else:
## TODO: Make this a bit more robust, perhaps by switching encodings!?
output_path = pathlib.Path(output_path)
@@ -863,21 +894,21 @@ def str_presenter(dumper, data2):
repl_keys = {k.replace("_", "."): k for k in list(data2_sanitized_flattened.keys())}
text = dict_to_md(
- body_parts,
- remove_keys=[
- "Rubric",
- "Solution",
- "Comments",
- "pl-submission-panel", #FIXME: This will not remove level 3 headings because it's all a string!
- "pl-answer-panel", #FIXME: This will not remove level 3 headings because it's all a string!
- ],
- )
+ body_parts,
+ remove_keys=[
+ "Rubric",
+ "Solution",
+ "Comments",
+ "pl-submission-panel", # FIXME: This will not remove level 3 headings because it's all a string!
+ "pl-answer-panel", # FIXME: This will not remove level 3 headings because it's all a string!
+ ],
+ )
for k, v in repl_keys.items():
text = text.replace(k, v)
# Update the YAML header to add substitutions
- header.update({"myst": {"substitutions": data2_sanitized_flattened} })
+ header.update({"myst": {"substitutions": data2_sanitized_flattened}})
# Update the YAML header to add substitutions, unsort it, and process for file
header_yml = yaml.dump(header, sort_keys=False, allow_unicode=True)
@@ -953,18 +984,24 @@ def str_presenter(dumper, data2):
# Move image assets
files_to_copy = header.get("assets")
if files_to_copy:
- [copy2(pathlib.Path(source_filepath).parent / fl, output_path.parent) for fl in files_to_copy]
+ [
+ copy2(pathlib.Path(source_filepath).parent / fl, output_path.parent)
+ for fl in files_to_copy
+ ]
# Move autograde py test files
files_to_copy = header.get("autogradeTestFiles")
if files_to_copy:
pl_path = output_path.parent / "tests"
pl_path.mkdir(parents=True, exist_ok=True)
- [copy2(pathlib.Path(source_filepath).parent / "tests" / fl, pl_path / fl) for fl in files_to_copy if (instructor or fl=="starter_code.py")]
+ [
+ copy2(pathlib.Path(source_filepath).parent / "tests" / fl, pl_path / fl)
+ for fl in files_to_copy
+ if (instructor or fl == "starter_code.py")
+ ]
def process_question_pl(source_filepath, output_path=None):
-
try:
pathlib.Path(source_filepath)
except:
@@ -977,7 +1014,9 @@ def process_question_pl(source_filepath, output_path=None):
if "source" in source_filepath:
output_path = pathlib.Path(source_filepath.replace("source", path_replace)).parent
else:
- raise NotImplementedError("Check the source filepath; it does not have 'source' in it!! ")
+ raise NotImplementedError(
+ "Check the source filepath; it does not have 'source' in it!! "
+ )
else:
## TODO: It's annoying that here output_path.parent is used, but for md problems, it's just output_path
output_path = pathlib.Path(output_path).parent
@@ -1007,18 +1046,20 @@ def process_question_pl(source_filepath, output_path=None):
# Question Preamble
preamble = parsed_q["body_parts"].get("preamble", None)
- #TODO: Remove Debugging print statement
- #print(f"premable: {preamble}")
-
+ # TODO: Remove Debugging print statement
+ # print(f"premable: {preamble}")
+
if preamble:
- question_html = f"\n\n{ preamble }\n\n\n\n"
+ question_html = (
+ f"\n\n{ preamble }\n\n\n\n"
+ )
else:
question_html = f""
# Useful info panel
useful_info = parsed_q["body_parts"].get("Useful_info", None)
- #TODO: When PrairieLearn updates to BootStrap5, update this box as described here: https://github.com/open-resources/problem_bank_scripts/issues/30#issuecomment-1177101211
+ # TODO: When PrairieLearn updates to BootStrap5, update this box as described here: https://github.com/open-resources/problem_bank_scripts/issues/30#issuecomment-1177101211
if useful_info:
question_html += f"""