Esempio n. 1
0
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)
Esempio n. 2
0
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)
Esempio n. 3
0
def processScans(server, password, pdf_fname, skip_gamma):
    """Process PDF file into images and read QRcodes

    Convert file into a bundle-name
    Check with server if bundle/md5 already on server
    - abort if name xor md5sum known.
    - continue if neither known or both known
    Make required directories for processing bundle,
    convert PDF to images and read QR codes from those.
    """
    from plom.scan import scansToImages
    from plom.scan import sendPagesToServer
    from plom.scan import readQRCodes
    from plom.scan.sendPagesToServer import bundle_name_and_md5

    pdf_fname = Path(pdf_fname)
    if not pdf_fname.is_file():
        print("Cannot find file {} - skipping".format(pdf_fname))
        return
    # TODO: replace above with letting exception rise from next:
    bundle_name, md5 = bundle_name_and_md5(pdf_fname)
    # TODO: doesBundleExist(bundle_name, md5)

    print("Checking if bundle {} already exists on server".format(bundle_name))
    bundle_exists = sendPagesToServer.doesBundleExist(pdf_fname, server,
                                                      password)
    # return [False, name], [True, name], [True,md5sum] or [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"
            )
            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(bundle_name))
        else:
            raise RuntimeError("Should not be here: unexpected code path!")

    bundledir = Path("bundles") / bundle_name
    make_required_directories(bundledir)

    with open(bundledir / "source.toml", "w+") as f:
        toml.dump({"file": str(pdf_fname), "md5": md5}, f)

    print("Processing PDF {} to images".format(pdf_fname))
    scansToImages.processScans(pdf_fname, bundledir, skip_gamma)
    print("Read QR codes")
    readQRCodes.processBitmaps(bundledir, server, password)
    # TODO: can collisions warning be written here too?
    if bundle_has_nonuploaded_unknowns(bundledir):
        print_unknowns_warning(bundledir)
        print(
            'You can upload these by passing "--unknowns" to the upload command'
        )