def processHWScans( server, password, pdf_fname, student_id, questions, gamma=False, extractbmp=False, ): """Process the given HW PDF into images, upload then archive the pdf. TODO: relax filename! Currently .YY. must be present but is ignored. pdf_fname should be for form 'submittedHWByQ/blah.XXXX.YY.pdf' where XXXX should be student_id and YY should be question_number. Do basic sanity checks to confirm. Ask server to map student_id to a test-number; these should have been pre-populated on test-generation and if id not known there is an error. Turn pdf_fname in to a bundle_name and check with server if that bundle_name / md5sum known. - abort if name xor md5sum known, - continue otherwise (when both name / md5sum known we assume this is resuming after a crash). Process PDF into images. Ask server to create the bundle - it will return an error or [True, skip_list]. The skip_list is a list of bundle-orders (ie page number within the PDF) that have already been uploaded. In typical use this will be empty. Then upload pages to the server if not in skip list (this will trigger a server-side update when finished). Finally archive the bundle. args: ... questions (list): list of integers of which questions this bundle covers. """ from plom.scan import scansToImages from plom.scan import sendPagesToServer if not isinstance(questions, list): raise ValueError("You must pass a list of ints for `questions`") for q in questions: if not isinstance(q, int): raise ValueError("You must pass a list of ints for `questions`") pdf_fname = Path(pdf_fname) if not pdf_fname.is_file(): print("Cannot find file {} - skipping".format(pdf_fname)) return assert os.path.split(pdf_fname)[0] in [ "submittedHWByQ", "./submittedHWByQ", ], 'At least for now, you must put your file into a directory named "submittedHWByQ"' IDQ = IDQorIDorBad(pdf_fname.name) if len(IDQ) != 3: # should return [IDQ, sid, q] raise ValueError( "File name has wrong format - should be 'blah.sid.q.pdf'.") _, sid, q = IDQ if sid != student_id: raise ValueError( "Student ID supplied {} does not match that in filename {}. Stopping." .format(student_id, sid)) # either we're dealing with multiquestions or we have exactly one question if not (q == "_" or [int(q)] == questions): raise ValueError( "Question supplied {} does not match that in filename {}. Stopping." .format(questions, q)) if len(questions) == 1: qlabel = "question" else: qlabel = "questions" print("Process and upload file {} as answer to {} {} for sid {}".format( pdf_fname.name, qlabel, questions, student_id)) test_number = sendPagesToServer.checkTestHasThatSID( student_id, server, password) if test_number is None: raise ValueError("No test has student ID = {}.".format(student_id)) else: print("Student ID {} is test_number {}".format(student_id, test_number)) bundle_exists = sendPagesToServer.doesBundleExist(pdf_fname, server, password) # should be [False] [True, name] [True,md5sum], [True, both] if bundle_exists[0]: if bundle_exists[1] == "name": raise ValueError( "The bundle name {} has been used previously for a different bundle." .format(pdf_fname)) elif bundle_exists[1] == "md5sum": raise ValueError( "A bundle with matching md5sum is already in system with a different name." ) elif bundle_exists[1] == "both": print( "Warning - bundle {} has been declared previously - you are likely trying again as a result of a crash. Continuing" .format(pdf_fname)) else: raise RuntimeError("Should not be here: unexpected code path!") bundle_name, md5 = bundle_name_and_md5(pdf_fname) bundledir = Path("bundles") / "submittedHWByQ" / bundle_name make_required_directories(bundledir) print("Processing PDF {} to images".format(pdf_fname)) scansToImages.processScans(pdf_fname, bundledir, not gamma, not extractbmp) print("Creating bundle for {} on server".format(pdf_fname)) rval = sendPagesToServer.createNewBundle(bundle_name, md5, server, password) # should be [True, skip_list] or [False, reason] if rval[0]: skip_list = rval[1] if len(skip_list) > 0: print("Some images from that bundle were uploaded previously:") print("Pages {}".format(skip_list)) print("Skipping those images.") else: print("There was a problem with this bundle.") if rval[1] == "name": print( "A different bundle with the same name was uploaded previously." ) else: print( "A bundle with matching md5sum but different name was uploaded previously." ) raise RuntimeError("Stopping, see above") # send the images to the server sendPagesToServer.uploadHWPages(bundle_name, skip_list, student_id, questions, server, password) # now archive the PDF scansToImages.archiveHWBundle(pdf_fname)
def processLooseScans(server, password, pdf_fname, student_id, gamma=False, extractbmp=False): """Process the given Loose-pages PDF into images, upload then archive the pdf. pdf_fname should be for form 'submittedLoose/blah.XXXX.pdf' where XXXX should be student_id. Do basic sanity check to confirm. Ask server to map student_id to a test-number; these should have been pre-populated on test-generation and if id not known there is an error. Turn pdf_fname in to a bundle_name and check with server if that bundle_name / md5sum known. - abort if name xor md5sum known, - continue otherwise (when both name / md5sum known we assume this is resuming after a crash). Process PDF into images. Ask server to create the bundle - it will return an error or [True, skip_list]. The skip_list is a list of bundle-orders (ie page number within the PDF) that have already been uploaded. In typical use this will be empty. Then upload pages to the server if not in skip list (this will trigger a server-side update when finished). Finally archive the bundle. """ from plom.scan import scansToImages from plom.scan import sendPagesToServer pdf_fname = Path(pdf_fname) if not pdf_fname.is_file(): print("Cannot find file {} - skipping".format(pdf_fname)) return assert os.path.split(pdf_fname)[0] in [ "submittedLoose", "./submittedLoose", ], 'At least for now, you must your file into a directory named "submittedLoose"' IDQ = IDQorIDorBad(pdf_fname.name) if len(IDQ) != 2: # should return [JID, sid] print( "File name has wrong format. Should be 'blah.sid.pdf'. Stopping.") return sid = IDQ[1] if sid != student_id: print( "Student ID supplied {} does not match that in filename {}. Stopping." .format(student_id, sid)) return print("Process and upload file {} as loose pages for sid {}".format( pdf_fname.name, student_id)) bundle_exists = sendPagesToServer.doesBundleExist(pdf_fname, server, password) # should be [False] [True, name] [True,md5sum], [True, both] if bundle_exists[0]: if bundle_exists[1] == "name": print( "The bundle name {} has been used previously for a different bundle. Stopping" .format(pdf_fname)) return elif bundle_exists[1] == "md5sum": print( "A bundle with matching md5sum is already in system with a different name. Stopping" .format(pdf_fname)) return elif bundle_exists[1] == "both": print( "Warning - bundle {} has been declared previously - you are likely trying again as a result of a crash. Continuing" .format(pdf_fname)) else: raise RuntimeError("Should not be here: unexpected code path!") bundle_name, md5 = bundle_name_and_md5(pdf_fname) bundledir = Path("bundles") / "submittedLoose" / bundle_name make_required_directories(bundledir) print("Processing PDF {} to images".format(pdf_fname)) scansToImages.processScans(pdf_fname, bundledir, not gamma, not extractbmp) print("Creating bundle for {} on server".format(pdf_fname)) rval = sendPagesToServer.createNewBundle(bundle_name, md5, server, password) # should be [True, skip_list] or [False, reason] if rval[0]: skip_list = rval[1] if len(skip_list) > 0: print("Some images from that bundle were uploaded previously:") print("Pages {}".format(skip_list)) print("Skipping those images.") else: print("There was a problem with this bundle.") if rval[1] == "name": print( "A different bundle with the same name was uploaded previously." ) else: print( "A bundle with matching md5sum but different name was uploaded previously." ) print("Stopping.") return # send the images to the server sendPagesToServer.uploadLPages(bundle_name, skip_list, student_id, server, password) # now archive the PDF scansToImages.archiveLBundle(pdf_fname)
def uploadImages(server, password, bundle_name, unknowns_flag=False, collisions_flag=False): """Upload processed images from bundle. Try to create a bundle on server. - abort if name xor md5sum of bundle known. - continue otherwise (server will give skip-list) Skip images whose page within the bundle is in the skip-list since those are already uploaded. Once uploaded archive the bundle pdf. As part of the upload 'unknown' pages and 'collisions' may be detected. These will not be uploaded unless the appropriate flags are set. """ from warnings import warn from plom.scan import sendPagesToServer, scansToImages if bundle_name.lower().endswith(".pdf"): warn('Careful, the bundle name should not include ".pdf"') bundledir = Path("bundles") / bundle_name info = toml.load(bundledir / "source.toml") md5 = info["md5"] # TODO: check first to avoid misleading msg? print('Creating bundle "{}" on server'.format(bundle_name)) rval = sendPagesToServer.createNewBundle(bundle_name, md5, server, password) # should be [True, skip_list] or [False, reason] if rval[0]: skip_list = rval[1] if len(skip_list) > 0: print("Some images from that bundle were uploaded previously:") print("Pages {}".format(skip_list)) print("Skipping those images.") else: print("There was a problem with this bundle.") if rval[1] == "name": print( "A different bundle with the same name was uploaded previously." ) else: print( "A bundle with matching md5sum but different name was uploaded previously." ) print("Stopping.") return print("Upload images to server") [TPN, updates] = sendPagesToServer.uploadTPages(bundledir, skip_list, server, password) print("Tests were uploaded to the following studentIDs: {}".format( ", ".join(TPN.keys()))) print("Server reports {} papers updated.".format(updates)) pdf_fname = Path(info["file"]) if pdf_fname.exists(): print('Original PDF "{}" still in place: archiving to "{}"...'.format( pdf_fname, str(archivedir))) scansToImages.archiveTBundle(pdf_fname) elif (archivedir / pdf_fname).exists(): print('Original PDF "{}" is already archived in "{}".'.format( pdf_fname, str(archivedir))) else: raise RuntimeError( "Did you move the archived PDF? Please don't do that!") # Note: no need to "finalize" a bundle, its ok to send unknown/collisions # after the above call to sendPagesToServer. if unknowns_flag: if bundle_has_nonuploaded_unknowns(bundledir): print_unknowns_warning(bundledir) print("Unknowns upload flag present: uploading...") upload_unknowns(bundledir, server, password) else: print( "Unknowns upload flag present: but no unknowns - so no actions required." ) else: if bundle_has_nonuploaded_unknowns(bundledir): print_unknowns_warning(bundledir) print( 'If you want to upload these unknowns, rerun with "--unknowns".' ) if collisions_flag: if bundle_has_nonuploaded_collisions(bundledir): print_collision_warning(bundledir) print("Collisions upload flag present.") # TODO:add a --yes flag? yn = input( "Are you sure you want to upload these colliding pages? [y/N] " ) if yn.lower() == "y": print("Proceeding.") upload_collisions(bundledir, server, password) else: print( "Collisions upload flag present: but no collisions - so no actions required." ) else: if bundle_has_nonuploaded_collisions(bundledir): print_collision_warning(bundledir) print( 'If you want to upload these collisions, rerun with "--collisions".' )