MUSA Graderv0.1.0

API reference · grader/notebook.py · 425 lines

grader.notebook

Static analysis of a student notebook (design.md §23, structural grading).

Everything here works without executing anything, so it still produces evidence when a notebook fails to run.

Summary

NameKindDescription
NotebookAnalysisclassStatic facts about a notebook.
empty_analysis()functionPlaceholder used when no notebook was submitted at all.
read_notebook()function
analyze_notebook()function
extract_markdown_responses()functionFind the most substantial free-text markdown answer in the notebook.
render_cells()functionFlatten a notebook into a read-only structure for the UI (design.md §13).

Constants

NameValueNotes
ABSOLUTE_PATH_REre.compile('(?P<quote>[\'"])(?P<path>(?:[A-Za-z]:[\\\\/]|/(?:Users|home|mnt|Volumes|var|tmp)/|~[\\\\/])[^\'"]{2,200})(?P=quote)')/Users/..., C:\Users\..., ~/Desktop/... inside a string literal.
DATA_SUFFIXES('.csv', '.tsv', '.json', '.geojson', '.xlsx', '.xls', '.parquet', '.shp', '.gpkg', '.tif', '.txt', '.zip', '.gz')Any string literal that looks like a data file the notebook wants to open.
READ_FUNCS{'read_csv', 'read_excel', 'read_json', 'read_parquet', 'read_file', 'read_table', 'read_html', 'read_feather', 'read_stata'}
PLOT_HINTS('plt.', 'sns.', '.plot(', '.plot.', 'plotly', 'altair', 'alt.Chart', 'figure(', 'subplots(', 'hvplot')
IPYTHON_LINE_PREFIXES('%', '!', '?')IPython syntax that is not Python.
IMPORT_REre.compile('^[ \\t]*(?:from[ \\t]+([\\w.]+)[ \\t]+import\\b|import[ \\t]+([^\\n#]+))', re.M)
READ_CALL_REre.compile('\\b(read_(?:csv|excel|json|parquet|file|table|html|feather|stata))[ \\t]*\\([ \\t]*(?:[rRbBuUfF]*([\'\\"])([^\'\\"\\n]{1,300})\…
STRING_LITERAL_REre.compile('([\'\\"])([^\'\\"\\n]{1,300})\\1')
INSTRUCTION_REre.compile('\\b(in (?:a|one) (?:short |brief )?(?:paragraph|sentence)|describe|explain|discuss|interpret the|comment on|write (?:a|your)|an…Phrasing that belongs to the assignment prompt rather than a student answer.

Classes

class NotebookAnalysis #[source]

dataclass

Static facts about a notebook.

Fields

NameTypeDefaultNotes
pathstrrequired
validboolTrue
parse_errorstr | NoneNone
n_cellsint0
n_code_cellsint0
n_markdown_cellsint0
code_sourcestr''
code_cellslist[str]field(default_factory=list)
markdown_cellslist[str]field(default_factory=list)
importsset[str]field(default_factory=set)
functionslist[dict[str, Any]]field(default_factory=list)
absolute_pathslist[str]field(default_factory=list)
read_callslist[str]field(default_factory=list)
referenced_fileslist[str]field(default_factory=list)
data_path_literalslist[str]field(default_factory=list)Every data-file-looking string literal, wherever it appears — students often assign the path to a variable before reading it.
plot_callsint0
has_syntax_errorboolFalse
unparsed_cellslist[int]field(default_factory=list)Cells that could not be parsed; the rest of the notebook is still analysed.
stored_outputsdict[str, int]field(default_factory=dict)
stored_errorslist[dict[str, Any]]field(default_factory=list)

Methods

function_names() -> list[str] #[source]

No description.

to_dict() -> dict[str, Any] #[source]

No description.

Functions

empty_analysis(path: str = '') -> NotebookAnalysis #[source]

Placeholder used when no notebook was submitted at all.

read_notebook(path: str | Path) -> nbformat.NotebookNode #[source]

No description.

analyze_notebook(path: str | Path) -> NotebookAnalysis #[source]

No description.

extract_markdown_responses(analysis: NotebookAnalysis, heading_hints: list[str] | None = None, min_words: int = 30) -> dict[str, Any] #[source]

Find the most substantial free-text markdown answer in the notebook.

render_cells(path: str | Path, max_output_chars: int = 4000) -> list[dict[str, Any]] #[source]

Flatten a notebook into a read-only structure for the UI (design.md §13).