from __future__ import annotations import json from quantum_learning import legacy_archive_dir, project_root def _notebook_stats(relative_path: str) -> dict[str, int]: path = project_root() / "notebooks" / relative_path data = json.loads(path.read_text()) markdown = "\n".join( "".join(cell["source"]) for cell in data["cells"] if cell["cell_type"] == "markdown" ) code = ["".join(cell["source"]) for cell in data["cells"] if cell["cell_type"] == "code"] return { "word_count": len(markdown.split()), "quiz_blocks": sum("quiz_block(" in cell for cell in code), "editable_labs": sum("editable_circuit_lab(" in cell for cell in code), "reflections": sum("reflection_box(" in cell for cell in code), "rubrics": sum("rubric_scorecard(" in cell for cell in code), "feedback_loops": sum("feedback_iteration_panel(" in cell for cell in code), "checklists": sum("evidence_checklist(" in cell for cell in code), } def test_legacy_single_notebook_sequence_is_hidden_from_main_view(): archive = legacy_archive_dir() assert archive.exists() notebook_names = [ "00_circuit_literacy.ipynb", "01_statevectors.ipynb", "02_measurement_and_counts.ipynb", "03_transpilation_and_backend_reality.ipynb", "04_noise_and_robustness.ipynb", "05_design_patterns_and_subcircuits.ipynb", "06_reversible_logic_and_oracles.ipynb", "07_synthesis_and_parametric_design.ipynb", "08_hardware_aware_design_studio.ipynb", "09_verification_and_noise_debugging.ipynb", "10_capstone_circuit_design_review.ipynb", ] for notebook_name in notebook_names: assert (archive / notebook_name).exists() assert not (project_root() / "notebooks" / notebook_name).exists() def test_orientation_notebooks_are_substantial(): start_stats = _notebook_stats("START_HERE.ipynb") blueprint_stats = _notebook_stats("COURSE_BLUEPRINT.ipynb") assert start_stats["word_count"] >= 1500 assert start_stats["quiz_blocks"] >= 2 assert start_stats["reflections"] >= 1 assert blueprint_stats["word_count"] >= 1000 assert blueprint_stats["quiz_blocks"] >= 2 assert blueprint_stats["reflections"] >= 1 def test_foundations_bundle_modules_are_rich_and_interactive(): blueprint_stats = _notebook_stats("COURSE_BLUEPRINT.ipynb") assert blueprint_stats["word_count"] >= 1000 assert blueprint_stats["quiz_blocks"] >= 2 assert blueprint_stats["reflections"] >= 1 module_roots = [ "foundations/module_01_principles_and_circuit_literacy", "foundations/module_02_qubit_and_statevector_intuition", "foundations/module_03_gates_and_measurement", ] for module_root in module_roots: lecture_stats = _notebook_stats(f"{module_root}/lecture.ipynb") lab_stats = _notebook_stats(f"{module_root}/lab.ipynb") problems_stats = _notebook_stats(f"{module_root}/problems.ipynb") studio_stats = _notebook_stats(f"{module_root}/studio.ipynb") assert lecture_stats["word_count"] >= 1000 assert lecture_stats["quiz_blocks"] >= 2 assert lecture_stats["editable_labs"] >= 1 assert lecture_stats["reflections"] >= 2 assert lab_stats["word_count"] >= 300 assert lab_stats["quiz_blocks"] >= 2 assert lab_stats["editable_labs"] >= 3 assert lab_stats["reflections"] >= 2 assert problems_stats["word_count"] >= 250 assert problems_stats["quiz_blocks"] >= 4 assert problems_stats["reflections"] >= 2 assert studio_stats["word_count"] >= 200 assert studio_stats["quiz_blocks"] >= 1 assert studio_stats["editable_labs"] >= 3 assert studio_stats["reflections"] >= 4 assert ( lecture_stats["word_count"] + lab_stats["word_count"] + problems_stats["word_count"] + studio_stats["word_count"] >= 2200 ) def test_qiskit_engineering_bundle_modules_are_rich_and_interactive(): module_roots = [ "qiskit_engineering/module_01_circuit_construction_and_analysis", "qiskit_engineering/module_02_transpilation_and_visualization", "qiskit_engineering/module_03_simulation_and_noise_models", ] for module_root in module_roots: lecture_stats = _notebook_stats(f"{module_root}/lecture.ipynb") lab_stats = _notebook_stats(f"{module_root}/lab.ipynb") problems_stats = _notebook_stats(f"{module_root}/problems.ipynb") studio_stats = _notebook_stats(f"{module_root}/studio.ipynb") assert lecture_stats["word_count"] >= 1000 assert lecture_stats["quiz_blocks"] >= 2 assert lecture_stats["editable_labs"] >= 1 assert lecture_stats["reflections"] >= 2 assert lab_stats["word_count"] >= 300 assert lab_stats["quiz_blocks"] >= 2 assert lab_stats["editable_labs"] >= 3 assert lab_stats["reflections"] >= 2 assert problems_stats["word_count"] >= 250 assert problems_stats["quiz_blocks"] >= 4 assert problems_stats["reflections"] >= 2 assert studio_stats["word_count"] >= 200 assert studio_stats["quiz_blocks"] >= 1 assert studio_stats["editable_labs"] >= 3 assert studio_stats["reflections"] >= 4 assert ( lecture_stats["word_count"] + lab_stats["word_count"] + problems_stats["word_count"] + studio_stats["word_count"] >= 2200 ) def test_algorithmic_design_bundle_modules_are_rich_and_interactive(): module_roots = [ "algorithms/module_01_deutsch_family", "algorithms/module_02_bernstein_vazirani", "algorithms/module_03_qft", "algorithms/module_04_grover", ] for module_root in module_roots: lecture_stats = _notebook_stats(f"{module_root}/lecture.ipynb") lab_stats = _notebook_stats(f"{module_root}/lab.ipynb") problems_stats = _notebook_stats(f"{module_root}/problems.ipynb") studio_stats = _notebook_stats(f"{module_root}/studio.ipynb") assert lecture_stats["word_count"] >= 1000 assert lecture_stats["quiz_blocks"] >= 2 assert lecture_stats["editable_labs"] >= 1 assert lecture_stats["reflections"] >= 2 assert lab_stats["word_count"] >= 300 assert lab_stats["quiz_blocks"] >= 2 assert lab_stats["editable_labs"] >= 3 assert lab_stats["reflections"] >= 2 assert problems_stats["word_count"] >= 250 assert problems_stats["quiz_blocks"] >= 4 assert problems_stats["reflections"] >= 2 assert studio_stats["word_count"] >= 200 assert studio_stats["quiz_blocks"] >= 1 assert studio_stats["editable_labs"] >= 3 assert studio_stats["reflections"] >= 4 assert ( lecture_stats["word_count"] + lab_stats["word_count"] + problems_stats["word_count"] + studio_stats["word_count"] >= 2200 ) def test_professional_design_bundle_modules_are_rich_and_interactive(): module_roots = [ "professional/module_01_qiskit_patterns", "professional/module_02_hardware_aware_redesign", "professional/module_03_noise_aware_verification", "professional/module_04_capstone_design_review", ] for module_root in module_roots: lecture_stats = _notebook_stats(f"{module_root}/lecture.ipynb") lab_stats = _notebook_stats(f"{module_root}/lab.ipynb") problems_stats = _notebook_stats(f"{module_root}/problems.ipynb") studio_stats = _notebook_stats(f"{module_root}/studio.ipynb") assert lecture_stats["word_count"] >= 1000 assert lecture_stats["quiz_blocks"] >= 2 assert lecture_stats["editable_labs"] >= 1 assert lecture_stats["reflections"] >= 2 assert lecture_stats["rubrics"] >= 1 assert lecture_stats["feedback_loops"] >= 1 assert lab_stats["word_count"] >= 300 assert lab_stats["quiz_blocks"] >= 2 assert lab_stats["editable_labs"] >= 3 assert lab_stats["reflections"] >= 2 assert lab_stats["rubrics"] >= 1 assert lab_stats["feedback_loops"] >= 1 assert problems_stats["word_count"] >= 250 assert problems_stats["quiz_blocks"] >= 4 assert problems_stats["reflections"] >= 2 assert problems_stats["rubrics"] >= 1 assert problems_stats["feedback_loops"] >= 1 assert studio_stats["word_count"] >= 200 assert studio_stats["quiz_blocks"] >= 1 assert studio_stats["editable_labs"] >= 3 assert studio_stats["reflections"] >= 4 assert studio_stats["rubrics"] >= 1 assert studio_stats["feedback_loops"] >= 1 assert studio_stats["checklists"] >= 1 assert ( lecture_stats["word_count"] + lab_stats["word_count"] + problems_stats["word_count"] + studio_stats["word_count"] >= 2200 )