plom.create module
Plom tools related to producing papers, and setting up servers.
- class plom.create.PlomClasslistValidator[source]
The Plom Classlist Validator has methods to help ensure compatible classlists.
- checkHeaders(rowFromDict: dict[str, Any]) dict[str, Any][source]
Check existence of id and name columns in the classlist.
Checks the column titles (as given by the supplied row from the classlist). Tests for an id column, name-column, and the papernumber column. Names must be a single column. To avoid issues with upper and lower case, everything needs to be tested by casefolding.
- Parameters:
rowFromDict – a row from the classlist encoded as a dictionary. The keys give the column titles.
- Returns:
If errors then return
{'success': False, 'errors': error-list}, else return{'success': True, 'id': id_key, 'fullname': fullname_key, 'papernumber': papernumber_key}. If there is no"paper_number"column, then thepaper_number_keywill be None.- Return type:
dict
- check_classlist_against_spec(spec, classlist_length: int) list[str][source]
Validate the classlist-length against spec parameters.
- Parameters:
spec (None/dict/SpecVerifier) – an optional test specification, if given then run additional classlist-related tests.
classlist_length – the number of students in the classlist.
- Returns:
If ‘numberToProduce’ is positive but less than classlist_length then returns [warning_message], else returns empty list.
- check_is_canvas_csv(csv_file_name: Path | str) bool[source]
Detect if a csv file is likely a Canvas-exported classlist.
- Parameters:
csv_file_name – csv file to be checked.
- Returns:
True if we think the input was from Canvas, based on presence of certain header names. Otherwise False.
- check_is_non_canvas_csv(csv_file_name: Path | str) bool[source]
Read the csv file and check if id and name columns exist.
Check if id is present or any of possible_sid_fields.
Check if name is preset or any of possible_fullname_fields.
- Parameters:
csv_file_name – the csv file.
- Returns:
bool
- check_papernumber_column(papernum_key, classList) tuple[bool, list][source]
Check the papernumber column of the classlist.
Entries must either be blank, or integers >= -1. Note that:
no integer >=0 can be used twice, and
blank or -1 are sentinel values used to indicate ‘do not prename’
- static is_paper_number_sentinel(x: int | float | str | None) bool[source]
True if the input is None, blank, -1 or ‘-1’.
Note: zero is not sentinel.
- readClassList(filename: Path | str) list[dict[str, Any]][source]
Read classlist from filename and return as list of dicts.
- Parameters:
filename – csv-file to be loaded.
- Returns:
List of dictionaries (keys are column titles).
- validate_csv(filename: Path | str, *, spec=None) tuple[bool, list[dict[str, Any]]][source]
Validate the classlist csv and return summaries of any errors and warnings.
- Parameters:
filename – a csv file from which to try to load the classlist.
- Keyword Arguments:
spec (None/dict/SpecVerifier) – an optional test specification, if given then run additional classlist-related tests.
- Returns:
(valid, warnings_and_errors)where “valid” is either True or False and “warnings_and_errors” is a list of dicts. Each dict encodes a single warning or an error: see code for precise format. It is possible for “valid” to be True and still have non-empty “warnings_and_errors” for example when there are only warnings.
- plom.create.clear_manager_login(server=None, password=None)[source]
Force clear the “manager” authorisation, e.g., after a crash.
- Parameters:
server (str) – in the form “example.com” or “example.com:41984”.
password (str) – if not specified, prompt on the command line.
- plom.create.download_rubrics(*, msgr)[source]
Download a list of rubrics from a server.
- Keyword Arguments:
msgr (plom.Messenger/tuple) – either a connected Messenger or a tuple appropriate for credientials.
- Returns:
list of dicts, possibly an empty list if server has no rubrics.
- Return type:
list
- plom.create.download_rubrics_to_file(filename, *, msgr, verbose: bool = True) None[source]
Download the rubrics from a server and save them to a file.
- Parameters:
filename (pathlib.Path) – A filename to save to. The extension is used to determine what format, supporting: .json, .toml, and .csv. If no extension is included, default to .toml.
- Keyword Arguments:
msgr (plom.Messenger/tuple) – either a connected Messenger or a tuple appropriate for credientials.
verbose (bool) – display diagnostic output on stdout.
- Returns:
but saves a file as a side effect.
- Return type:
None
- plom.create.download_version_map(*, msgr) Dict[int, Dict[int, int]][source]
Get the question-version map from a server.
- Keyword Arguments:
msgr (plom.Messenger/tuple) – either a connected Messenger or a tuple appropriate for credientials.
- Returns:
keys are the paper numbers (int) and each value is a row of the version map: another dict with questions as question number (int) and value version (int).
- Raises:
PlomServerNotReady –
- plom.create.make_PDF(spec, papernum: int, question_versions: dict[int, int], extra: dict[str, Any] | None = None, xcoord: float | None = None, ycoord: float | None = None, no_qr: bool = False, fakepdf: bool = False, *, where=None, source_versions_path=None, font_subsetting: bool | None = None) Path | None[source]
Make a PDF of particular versions, with QR codes, and optionally name stamped.
Take pages from each source (using questions_versions/page_versions) and add QR codes and “DNW” staple-corner indicators. Optionally stamp the student name/id from extra onto the cover page. Save the new PDF file into the paperdir (typically “papersToPrint”).
- Parameters:
spec (dict | SpecVerifier) – A validated specification
papernum – the paper number.
question_versions – the version of each question for this paper. Note this is an input and must be predetermined before calling.
extra – Dictionary with student id and name or None to default not printing any prename.
xcoord – horizontal positioning of the prename box, or a default if None or omitted.
ycoord – vertical positioning of the prename box, or a default if None or omitted.
no_qr (bool) – determine whether or not to paste in qr-codes. Somewhat deprecated, definitely use it as kwarg if you’re writing new code.
fakepdf (bool) – when true, the build empty “pdf” files by just touching fhe files. This is could be used in testing or to save time when we have no use for the actual files. Why? Maybe later confirmation steps check these files exist or something like that… Somewhat deprecated, definitely use it as kwarg if you’re writing new code.
- Keyword Arguments:
where (pathlib.Path/None) – where to save the files, with some default if omitted.
source_versions_path (pathlib.Path/str/None) – location of the source versions directory.
font_subsetting – if None/omitted, do a generally-sensible default of using subsetting only when we added non-ascii characters. True forces subsetting and False disables is. We embed fonts for names and other overlay. But if there are non-Latin characters (e.g., CJK) in names, then the embedded font is quite large (several megabytes). Note: in theory, subsetting could muck around with fonts from the source (i.e., if they were NOT previously subsetted). So we only do the subsetting if we’re added non-ascii chars in any of the shortname, student name or question labels. Non-ascii is a stronger requirement than needed,
- Returns:
the file that was just written, or None in the slightly strange, perhaps deprecated
fakepdfcase.- Return type:
pathlib.Path
- Raises:
ValueError – Raise error if the student name and number is not encodable
- plom.create.make_hw_scribbles(server, password, basedir=PosixPath('.'), how_many=10)[source]
Fake homework submissions by scribbling on the pages of blank tests.
- Parameters:
server (str) – the name and port of the server.
password (str) – the “manager” password.
basedir (str/pathlib.Path) – the blank tests (for scribbling) will be taken from basedir/papersToPrint. The pdf files with scribbles will be created in basedir/submittedHWByQ.
how_many (int) – how many hws to create
Read in the existing papers.
Create the fake data filled pdfs
Generates second batch for first half of papers.
Generates some “semiloose” bundles; those that have all questions or more than one question in a single bundle.
- plom.create.make_scribbles(basedir=PosixPath('.'), *, msgr)[source]
Fake exam writing by scribbling on the pages of the blank exams.
After Plom exam PDF files have been generated, this can be used to scribble on them to simulate random student work. Note this tool does not upload those files, it just makes some PDF files for you to play with or for testing purposes.
- Parameters:
basedir (str/pathlib.Path) – the blank tests (for scribbling) will be taken from basedir/papersToPrint. The pdf files with scribbles will be created in basedir. Defaults to current directory.
- Keyword Arguments:
msgr (plom.Messenger/tuple) – either a connected Messenger or a tuple appropriate for credientials.
- Returns:
None
Read in the existing papers.
Create the fake data filled pdfs
Do some things to make the data unpleasant:
delete the last page of the first test.
Randomly add some extra pages
- plom.create.process_classlist_file(student_csv_file_name, spec, *, ignore_warnings=False)[source]
Get student names/IDs from a csv file.
Student numbers come from an id column. Student names must be in a single ‘name’ column. There is some flexibility in those titles, see
plom.create.possible_sid_fields()plom.create.possible_fullname_fields()
Alternatively, give a .csv exported from Canvas (experimental!)
- Parameters:
student_csv_file_name (pathlib.Path/str) – class info csv file.
spec (dict) – validated test spec.
- Keyword Arguments:
ignore_warnings (bool) – if true, proceed with classlist processing even if there are warnings. Default False.
- Returns:
if successful then “(True, clist)” where clist is a list of dicts each with “id” and “name”. On failure “(False, warn_err)” where “warn_err” is a list of dicts of warnings and errors. Each dict contains “warn_or_err” which is ‘warning’ or ‘error’, “werr_line” being the line number at which the error occurs, and ‘werr_text’ being a string describing the warning/error.
- Return type:
tuple
- plom.create.save_version_map(filename=None, *, msgr) Path[source]
Get the question-version map and save to a file.
- Parameters:
filename (pathlib.Path/str) – a file name and optionally path in which to save the version map. The extension is used to determine what format, supporting:
.jsonand.csv. If no extension is included, default to .csv. If filename omitted, default toquestion_version_map.csv.- Keyword Arguments:
msgr (plom.Messenger/tuple) – either a connected Messenger or a tuple appropriate for credientials.
- Returns:
the name of the file saved.
- Return type:
pathlib.Path
- Raises:
PlomServerNotReady –
Note if you specify
.json, the paper numbers and questions numbers will be converted to strings due to JSON limitations.
- plom.create.status(*, msgr) None[source]
Status information about a server.
- Keyword Arguments:
msgr (plom.Messenger/tuple) – either a connected Messenger or a tuple appropriate for credientials.
- plom.create.upload_classlist(classlist, *, msgr, force=False)[source]
Uploads a classlist file to the server.
- Arg:
- classdict (list): list of dict, each has at least keys “id” and
“name”, optionally other fields too.
- Keyword Arg:
- msgr (plom.Messenger/tuple): either a connected Messenger or a
tuple appropriate for credientials.
- force (bool): Force uploading if a classlist already exists,
default False.
- Returns:
None
- plom.create.upload_demo_classlist(spec, *, msgr, force=False)[source]
Uploads the demo classlist file to the server.
- Parameters:
spec – the server assessment specification.
- Keyword Arguments:
msgr (plom.Messenger/tuple) – either a connected Messenger or a tuple appropriate for credientials.
force (bool) – Force uploading if a classlist already exists, default False.
- Returns:
None
- plom.create.upload_demo_rubrics(*, msgr, numquestions: int = 3) int[source]
Load some demo rubrics and upload to server.
- Keyword Arguments:
msgr (plom.Messenger/tuple) – either a connected Messenger or a tuple appropriate for credientials.
numquestions (int) – how many questions should we build for. TODO: get number of questions from the server spec if omitted.
- Returns:
How many rubrics were created.
The demo data is a bit sparse: we fill in missing pieces and multiply over questions.
- plom.create.upload_rubrics_from_file(filename, *, msgr, verbose: bool = True) None[source]
Load rubrics from a file and upload them to a server.
- Parameters:
filename (pathlib.Path) – A filename to load from. Types .json, .toml, and .csv are supported. If no suffix is included we’ll try to append .toml.
- Keyword Arguments:
msgr (plom.Messenger/tuple) – either a connected Messenger or a tuple appropriate for credientials.
verbose (bool) – display diagnostic output on stdout.
- Returns:
None
- plom.create.version_map_from_file(f: Path | str, *, required_papers: list[int] | None = None) dict[int, dict[int, int]][source]
Extract the version map from a csv or json file.
- Parameters:
f – If
.csvfile, must have a test_number column and some q{n}.version columns. The number of such columns is autodetected. If.jsonfile, its a dict of dicts. Either case could, for example, be the output ofsave_question_version_map().- Keyword Arguments:
required_papers – A list of paper_numbers that the qv map must have.
- Returns:
keys are the paper numbers (int) and each value is a row of the version map: another dict with questions as question number (int) and value version (int).
- Raises:
ValueError – values could not be converted to integers, or other errors in the version map.
KeyError – wrong column header names.
- plom.create.version_map_to_csv(qvmap: dict[int, dict[int, int]], filename: Path, *, _legacy: bool = True) None[source]
Output a csv of the question-version map.
- Parameters:
qvmap – the question-version map, documented elsewhere.
filename – where to save.
- Keyword Arguments:
_legacy – if True, we call the column “test_number” else “paper_number”. Currently the default is True but this is expected to change.
- Raises:
ValueError – some rows have differing numbers of questions.