Commit 916f1285 authored by Tandri Gauksson's avatar Tandri Gauksson

A new print script, since the old print.sh was outdated and not working

parent 3a3a44fa
#!/usr/bin/python3
"""
Usage: ./print.py /path/to/results
This script will print all <ip>.pdf files in /path/to/results in alphabetical
order* w.r.t the students' last names (as opposed to ip addresses).
A new directory /path/to/results/pdf_alphabetic of alphabetized (symlink)
pdfs is created, and can be safely deleted afterwards.
*Approximate alphabetical order, see create_symlinks.__doc__.
By default, the pdfs are printed double-sided, two pages per side,
and each student's solution is stapled. This can be configured in
the LPR_OPTIONS variable.
The default printer is p-hg-j-54. This can be configured in the PRINTER
variable.
Tip: Use "lpstat -p" to see the list of available printers.
The path/to/results should point to a directory containing the pdfs of
the student's solution, created by latex_creator.py, as well as the
candidates.csv for the <ip> -> <last name> mapping.
The pdfs should be named <ip>.pdf and other files, such as <ip>-nup.pdf,
out.pdf, out_rotated.pdf are ignored.
To do:
* Add --printer to command line arguments.
* Automatically split the job into batches, including a small test batch.
* Await user input before starting next batch. "Print next batch? (Y/n)".
* Allow a list of printers ["p-hg-j-42","p-hg-j-54",...] to print in
parallel. Make sure each printer gets consecutive batches, so that
the piles of paper can be easily joined while retaining the order.
"""
# Remove "-o StapleLocation=UpperRight" to skip stapling.
LPR_OPTIONS = "-o sides=two-sided-short-edge -o landscape -o fit-to-page -o media=A4 -o number-up=2 -o number-up-layout=lr -o StapleLocation=UpperRight"
# ~ PRINTER = "p-hg-j-54"
PRINTER = "p-hg-e-62-2"
import sys
import os
import subprocess
import csv
from string import ascii_letters
def format_status(string):
start = '\033[92m' #green
end = '\033[0m'
return start + string + end
def is_ip_pdf( fname ):
'''
Any <ip>.pdf will satisfy this condition, while out.pdf,
out_rotated.pdf, <ip>-nup.pdf, and non-pdf files are ignored.
Not actually checking if valid ip address.
'''
fname_split = fname.split('.')
return len(fname_split)>1 and fname_split[-1] == "pdf" \
and all([x.isdigit() for x in fname_split[:-1]])
def rm_non_ascii( name ):
# To do: instead of removing, replace non-ascii letters by their ascii alternatives.
allowed_letters = set(ascii_letters)
return "".join([letter for letter in name if letter in allowed_letters])
def create_symlinks( pdf_dir ):
'''
pdf_dir needs to contain candidates.csv
Creates a subdirectory of pdf_dir called pdf_alphabetic.
The new directory contains symbolic links to all <ip>.pdf files in pdf_dir,
with names <lastname>.<ip>.pdf, so that they are in alphabetic order.
The following caveats can cause interruptions of the alphabetic ordering:
Caveat 1: The <lastname> is provided by the student and sometimes the
student will instead give their first name.
Caveat 2: Any non-ascii characters of <lastname> are removed.
'''
pdf_dir = os.path.abspath( pdf_dir )
file_list = os.listdir( pdf_dir )
symlink_dir = os.path.abspath( pdf_dir+"/pdf_alphabetic" )
if not os.path.isdir( symlink_dir ):
print(format_status("Alphabetizing into directory:\n\t") + symlink_dir)
os.mkdir( symlink_dir ) # directory for for symlinks
else:
print(format_status("Overwriting existing alphabetized directory:\n\t") + symlink_dir)
for fname in file_list:
if is_ip_pdf( fname ):
pdf_ip = fname[:-4]
with open( pdf_dir+"/candidates.csv" ) as csvfile:
# Searching for the student's name.
candidates = csv.reader( csvfile, delimiter=';' )
for student in candidates:
# student = [ <ip>, <login>, <fullname> ]
if student[0] == pdf_ip:
student_name = student[2].split()[0].lower()
student_name = rm_non_ascii( student_name )
if not student_name:
# if name contains no ascii characters (!!!)
# use login instead.
student_name = student[1]
new_fname = student_name + '.' + fname
symlink_path = symlink_dir + '/' + new_fname
# print(fname + ' -> ' + new_fname)
if os.path.exists(symlink_path):
os.remove(symlink_path)
os.symlink(pdf_dir+'/'+fname,symlink_path)
return symlink_dir
def print_all( symlink_dir ):
lpr_command = "lpr -P {} {}".format(PRINTER,LPR_OPTIONS)
# Create a list of arguments instead of string.
lpr_command = lpr_command.split()
# The path needs to be treated separately, in case any folder has
# a space in its name.
pdf_files = [f for f in os.listdir(symlink_dir) if f[-4:]==".pdf"]
print(format_status("Printing %d documents using:\n\t"%len(pdf_files))+" ".join(lpr_command) + " <filename>")
for fname in pdf_files:
# To glob (*.pdf), we need shell=True in subprocess.run().
# To avoid this, just print all .pdf in separate commands.
if fname[-4:] == ".pdf":
print(".",end="")
subprocess.run(lpr_command+[symlink_dir+'/'+fname],check=True,shell=False)
print(format_status("\nPrint job started! Go check printer: ") + PRINTER)
if __name__ == "__main__":
if len(sys.argv) > 1 and os.path.isdir(sys.argv[1]):
path_to_results = sys.argv[1]
path_to_symlinks = create_symlinks( path_to_results )
print_all( path_to_symlinks )
else:
print("Please provide a valid /path/to/results.")
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment