def get_number_of_questions(server=None, pwd=None): """Contact server for number of questions.""" if server and ":" in server: s, p = server.split(":") msgr = ScanMessenger(s, port=p) else: msgr = ScanMessenger(server) msgr.start() if not pwd: pwd = getpass.getpass("Please enter the 'scanner' password:"******"scanner", pwd) except PlomExistingLoginException: print( "You appear to be already logged in!\n\n" " * Perhaps a previous session crashed?\n" " * Do you have another scanner-script running,\n" " e.g., on another computer?\n\n" 'In order to force-logout the existing authorisation run "plom-scan clear"' ) exit(-1) spec = msgr.get_spec() msgr.closeUser() msgr.stop() return spec["numberOfQuestions"]
def replaceMissingHWQ(server, pwd, student_id, question): if server and ":" in server: s, p = server.split(":") msgr = ScanMessenger(s, port=p) else: msgr = ScanMessenger(server) msgr.start() if not pwd: pwd = getpass.getpass("Please enter the 'scanner' password:"******"scanner", pwd) except PlomExistingLoginException as e: print( "You appear to be already logged in!\n\n" " * Perhaps a previous session crashed?\n" " * Do you have another scanner-script running,\n" " e.g., on another computer?\n\n" 'In order to force-logout the existing authorisation run "plom-scan clear"' ) exit(10) rval = msgr.replaceMissingHWQuestion( student_id=student_id, test=None, question=question) # can replace by SID or by test-number msgr.triggerUpdateAfterHWUpload() msgr.closeUser() msgr.stop() return rval
def get_and_start_scan_msgr(server=None, password=None): """Get a scanner messenger. Args: server (str): "server:port" or localhost default if omitted. password (str): prompts on the command line if omitted. Returns: ScanMessenger: authenicated connection to the server. When you are done with this you should call `.closeUser()` and then `.stop()`. Raises: PlomExistingLoginException: scanner is logged in somewhere else. TODO: xref the force logout function once it exists. TODO: for now use command line tool `plom-scan clear`. """ if server and ":" in server: s, p = server.split(":") msgr = ScanMessenger(s, port=p) else: msgr = ScanMessenger(server) msgr.start() if password is None: password = getpass.getpass("Please enter the 'scanner' password: "******"scanner", password) return msgr
def checkMissingHWQ(server=None, pwd=None): if server and ":" in server: s, p = server.split(":") msgr = ScanMessenger(s, port=p) else: msgr = ScanMessenger(server) msgr.start() if not pwd: pwd = getpass.getpass("Please enter the 'scanner' password:"******"scanner", pwd) except PlomExistingLoginException as e: print( "You appear to be already logged in!\n\n" " * Perhaps a previous session crashed?\n" " * Do you have another scanner-script running,\n" " e.g., on another computer?\n\n" 'In order to force-logout the existing authorisation run "plom-scan clear"' ) exit(10) missingHWQ = msgr.getMissingHW() msgr.closeUser() msgr.stop() return missingHWQ
def uploadTPages(bundleDir, skip_list, server=None, password=None): """Upload the test pages to the server. Skips pages-image with orders in the skip-list (ie the page number within the bundle.pdf) Bundle must already be created. We will upload the files and then send a 'please trigger an update' message to the server. """ if server and ":" in server: s, p = server.split(":") msgr = ScanMessenger(s, port=p) else: msgr = ScanMessenger(server) msgr.start() # get the password if not specified if password is None: try: pwd = getpass.getpass("Please enter the 'scanner' password:"******"ERROR", error) else: pwd = password # get started try: msgr.requestAndSaveToken("scanner", pwd) except PlomExistingLoginException: print( "You appear to be already logged in!\n\n" " * Perhaps a previous session crashed?\n" " * Do you have another scanner-script running,\n" " e.g., on another computer?\n\n" 'In order to force-logout the existing authorisation run "plom-scan clear" or "plom-hwscan clear"' ) exit(10) spec = msgr.get_spec() numberOfPages = spec["numberOfPages"] if not bundleDir.is_dir(): raise ValueError("should've been a directory!") files = [] # Look for pages in decodedPages for ext in PlomImageExts: files.extend( sorted((bundleDir / "decodedPages").glob("t*.{}".format(ext)))) TUP = sendTestFiles(msgr, bundleDir.name, files, skip_list) # we do not automatically replace any missing test-pages, since that is a serious issue for tests, and should be done only by manager. updates = msgr.triggerUpdateAfterTUpload() # close down messenger msgr.closeUser() msgr.stop() return [TUP, updates]
def checkTestHasThatSID(student_id, server=None, password=None): """Get test-number corresponding to given student id For HW tests should be pre-IDd, so this function is used to map a student-id to the underlying test. This means that and uploaded HW page can be matched to the test in the database. Returns the test-number if the SID is matched to a test in the database else returns None. """ if server and ":" in server: s, p = server.split(":") msgr = ScanMessenger(s, port=p) else: msgr = ScanMessenger(server) msgr.start() # get the password if not specified if password is None: try: pwd = getpass.getpass("Please enter the 'scanner' password:"******"ERROR", error) else: pwd = password # get started try: msgr.requestAndSaveToken("scanner", pwd) except PlomExistingLoginException: print( "You appear to be already logged in!\n\n" " * Perhaps a previous session crashed?\n" " * Do you have another scanner-script running,\n" " e.g., on another computer?\n\n" 'In order to force-logout the existing authorisation run "plom-scan clear"' ) exit(10) # get test_number from SID. # response is [true, test_number] or [false, reason] test_success = msgr.sidToTest(student_id) msgr.closeUser() msgr.stop() if test_success[0]: # found it return test_success[1] # return the number else: # couldn't find it return None
def verifiedComplete(server=None, password=None): if server and ":" in server: s, p = server.split(":") msgr = ScanMessenger(s, port=p) else: msgr = ScanMessenger(server) msgr.start() # get the password if not specified if password is None: try: pwd = getpass.getpass("Please enter the 'scanner' password:"******"ERROR", error) else: pwd = password # get started try: msgr.requestAndSaveToken("scanner", pwd) except PlomExistingLoginException: print( "You appear to be already logged in!\n\n" " * Perhaps a previous session crashed?\n" " * Do you have another scanner-script running,\n" " e.g., on another computer?\n\n" 'In order to force-logout the existing authorisation run "plom-hwscan clear"' ) exit(10) # grab number of questions - so we can work out what is missing spec = msgr.get_spec() numberOfQuestions = spec["numberOfQuestions"] msgr.closeUser() msgr.stop() hwByQ = defaultdict(list) for fn in glob.glob("submittedHWByQ/*.pdf"): IDQ = IDQorIDorBad(fn) if len(IDQ) == 3: sid, q = IDQ[1:] hwByQ[sid].append([fn, q]) # return fileNames belonging to complete homeworks validFiles = [] for sid in hwByQ: if len(hwByQ[sid]) == numberOfQuestions: validFiles += [x[0] for x in hwByQ[sid]] return validFiles
def createNewBundle(bundle_name, md5, server=None, password=None): """Create a new bundle with a given name. Args: bundle_name (str): a bundle name, typically extracted from the name of a PDF file. md5 (str): the md5sum of the file from which this bundle is extracted. In future, could be extended to a list/dict for more than one file. server: information to contact a server. password: information to contact a server. Returns: list: either the pair `[True, bundle_name]` or `[False]`. """ if server and ":" in server: s, p = server.split(":") msgr = ScanMessenger(s, port=p) else: msgr = ScanMessenger(server) msgr.start() if password is None: pwd = getpass.getpass("Please enter the 'scanner' password: "******"scanner", pwd) except PlomExistingLoginException: print( "You appear to be already logged in!\n\n" " * Perhaps a previous session crashed?\n" " * Do you have another scanner-script running,\n" " e.g., on another computer?\n\n" 'In order to force-logout the existing authorisation run "plom-scan clear"' ) exit(10) try: bundle_success = msgr.createNewBundle(bundle_name, md5) finally: msgr.closeUser() msgr.stop() return bundle_success
def whoSubmittedWhatOnServer(server, password): if server and ":" in server: s, p = server.split(":") msgr = ScanMessenger(s, port=p) else: msgr = ScanMessenger(server) msgr.start() # get the password if not specified if password is None: try: pwd = getpass.getpass("Please enter the 'scanner' password:"******"ERROR", error) else: pwd = password # get started try: msgr.requestAndSaveToken("scanner", pwd) except PlomExistingLoginException: print( "You appear to be already logged in!\n\n" " * Perhaps a previous session crashed?\n" " * Do you have another scanner-script running,\n" " e.g., on another computer?\n\n" 'In order to force-logout the existing authorisation run "plom-hwscan clear"' ) exit(10) missingHWQ = msgr.getMissingHW() # passes back dict completeHW = msgr.getCompleteHW() # passes back list [test_number, sid] msgr.closeUser() msgr.stop() print(">> Checking incomplete submissions on server <<") print( "The following students have complete submissions (each question present)" ) print(", ".join(sorted([x[1] for x in completeHW]))) print( "The following students have incomplete submissions (missing questions indicated)" ) for t in missingHWQ: print("{} missing {}".format(missingHWQ[t][1], missingHWQ[t][2:]))
def doesBundleExist(bundle_file, server=None, password=None): """Check if bundle exists and is so does its md5sum match a given file. Args: bundle_file (str, Path): needs to be the actual file not the bundle name because we need to compute the md5sum. Returns: list: the pair `[True, bundle_name]` where `bundle_name` is a `str` or `[False, reason]` where `reason` is a `str`. """ if server and ":" in server: s, p = server.split(":") msgr = ScanMessenger(s, port=p) else: msgr = ScanMessenger(server) msgr.start() # get the password if not specified if password is None: pwd = getpass.getpass("Please enter the 'scanner' password:"******"scanner", pwd) except PlomExistingLoginException: print( "You appear to be already logged in!\n\n" " * Perhaps a previous session crashed?\n" " * Do you have another scanner-script running,\n" " e.g., on another computer?\n\n" 'In order to force-logout the existing authorisation run "plom-scan clear"' ) exit(10) bundle_name, md5 = bundle_name_and_md5(bundle_file) bundle_success = msgr.doesBundleExist(bundle_name, md5) msgr.closeUser() msgr.stop() return bundle_success
def processBitmaps(bundle, server=None, password=None): examsScannedNow = defaultdict(list) if server and ":" in server: s, p = server.split(":") scanMessenger = ScanMessenger(s, port=p) else: scanMessenger = ScanMessenger(server) scanMessenger.start() # get the password if not specified if password is None: try: pwd = getpass.getpass("Please enter the 'scanner' password:"******"ERROR", error) exit(1) else: pwd = password # get started try: scanMessenger.requestAndSaveToken("scanner", pwd) except PlomExistingLoginException: print( "You appear to be already logged in!\n\n" " * Perhaps a previous session crashed?\n" " * Do you have another scanner-script running,\n" " e.g., on another computer?\n\n" 'In order to force-logout the existing authorisation run "plom-scan clear"' ) exit(10) spec = scanMessenger.get_spec() scanMessenger.closeUser() scanMessenger.stop() decodeQRs(bundle / "pageImages") checkQRsValid(bundle, spec, examsScannedNow) validateQRsAgainstSpec(spec, examsScannedNow) moveScansIntoPlace(examsScannedNow)
def upload_collisions(bundleDir, server=None, password=None): if server and ":" in server: s, p = server.split(":") scanMessenger = ScanMessenger(s, port=p) else: scanMessenger = ScanMessenger(server) scanMessenger.start() if password is None: pwd = getpass.getpass("Please enter the 'scanner' password: "******"scanner", pwd) except PlomExistingLoginException: print( "You appear to be already logged in!\n\n" " * Perhaps a previous session crashed?\n" " * Do you have another scanner-script running,\n" " e.g., on another computer?\n\n" 'In order to force-logout the existing authorisation run "plom-scan clear"' ) exit(10) try: if not bundleDir.is_dir(): raise ValueError("should've been a directory!") files = [] for ext in PlomImageExts: files.extend( (bundleDir / "uploads/collidingPages").glob("*.{}".format(ext)) ) sendCollidingFiles(scanMessenger, bundleDir.name, files) finally: scanMessenger.closeUser() scanMessenger.stop()
def checkStatus(server=None, pwd=None): if server and ":" in server: s, p = server.split(":") msgr = ScanMessenger(s, port=p) else: msgr = ScanMessenger(server) msgr.start() if not pwd: pwd = getpass.getpass("Please enter the 'scanner' password:"******"scanner", pwd) except PlomExistingLoginException as e: print( "You appear to be already logged in!\n\n" " * Perhaps a previous session crashed?\n" " * Do you have another scanner-script running,\n" " e.g., on another computer?\n\n" 'In order to force-logout the existing authorisation run "plom-scan clear"' ) exit(10) spec = msgr.get_spec() ST = msgr.getScannedTests( ) # returns pairs of [page,version] - only display pages UT = msgr.getUnusedTests() IT = msgr.getIncompleteTests() msgr.closeUser() msgr.stop() print("Test papers unused: [{}]".format(format_int_list_with_runs(UT))) print("Scanned tests in the system:") for t in ST: scannedTPages = [] scannedHWPages = [] for x in ST[t]: if x[0][0] == "t": # is a test page = "t.p" p = int(x[0].split(".")[1]) scannedTPages.append(p) elif x[0][0] == "h": # is a hw page = "h.q.o" q = int(x[0].split(".")[1]) if q not in scannedHWPages: scannedHWPages.append(q) print("\t{}: testPages [{}] hwPages [{}]".format( t, format_int_list_with_runs(scannedTPages), format_int_list_with_runs(scannedHWPages), )) print("Number of scanned tests in the system: {}".format(len(ST))) print("Incomplete scans - listed with their missing pages: ") for t in IT: missingPagesT = [] missingPagesH = [] for x in IT[t]: # each entry is [page, version, scanned?] if x[0][0] == "t": # is a test page p = int(x[0].split(".")[1]) if x[2] is False: missingPagesT.append(p) elif x[0][0] == "h": # is a w page q = int(x[0].split(".")[1]) if x[2] is False: missingPagesH.append(q) print("\t{}: t[{}] h[{}]".format( t, format_int_list_with_runs(missingPagesT), format_int_list_with_runs(missingPagesH), ))
def uploadLPages(bundle_name, skip_list, student_id, server=None, password=None): """Upload the hw pages to the server. lpages uploaded to given student_id. Skips pages-image with orders in the skip-list (i.e., the page number within the bundle.pdf) Bundle must already be created. We will upload the files and then send a 'please trigger an update' message to the server. """ if server and ":" in server: s, p = server.split(":") msgr = ScanMessenger(s, port=p) else: msgr = ScanMessenger(server) msgr.start() # get the password if not specified if password is None: try: pwd = getpass.getpass("Please enter the 'scanner' password:"******"ERROR", error) else: pwd = password # get started try: msgr.requestAndSaveToken("scanner", pwd) except PlomExistingLoginException: print( "You appear to be already logged in!\n\n" " * Perhaps a previous session crashed?\n" " * Do you have another scanner-script running,\n" " e.g., on another computer?\n\n" 'In order to force-logout the existing authorisation run "plom-hwscan clear"' ) exit(10) file_list = [] # files are sitting in "bundles/submittedLoose/<bundle_name>" os.chdir(os.path.join("bundles", "submittedLoose", bundle_name)) # Look for pages in pageImages for ext in PlomImageExts: file_list.extend( sorted(glob(os.path.join("pageImages", "*.{}".format(ext))))) LUP = sendLFiles(msgr, file_list, skip_list, student_id, bundle_name) updates = msgr.triggerUpdateAfterLUpload() # go back to original dir os.chdir("..") os.chdir("..") os.chdir("..") # close down messenger msgr.closeUser() msgr.stop() return [LUP, updates]