Download

yam2lms is just a python script. It can be obtained below:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Sat Aug 29 17:49:38 2020

@author: vmeunier
"""
#38add: scp -r Questions_THERMO_quiz14 meuniv@rcs.rpi.edu:~/public_html/Images/TSM_F20/.

import yaml
from textblob import TextBlob
from distutils.util import strtobool
from spellchecker import SpellChecker

with open("config.yaml") as conf:
    configuration = yaml.load(conf, Loader=yaml.FullLoader)

yamlfile=configuration['yamlfile']
spellcheck=configuration['spellcheck']
create_LMS=configuration['createLMS']
create_LMS_text=configuration['createLMS_text']
base=configuration['base']
dir=configuration['dir']
title1=configuration['title1']
title2=configuration['title2']
solutions=configuration['solutionKey']

print(yamlfile)

with open(yamlfile) as f:
    myset = yaml.load(f, Loader=yaml.FullLoader)

print(myset)

class Question:
    def __init__(self, Type, Text, Size, Choice, Valid):
        self.Type = Type
        self.Text = Text
        self.Size = 'Auto'
        self.Points = '0'
        self.Skip = 'False'
        self.TextString = Text
        self.Choice = []
        self.ChoiceString = []
        self.Valid = []
        self.ValidString = []

    def out(self):
        string="%s\t%s" % (self.Type,self.Text)
        for i in range(len(self.Choice)):
            string+='\t%s \t%s' %  (self.Choice[i], self.Valid[i])
        string+='\n'
        return string

    def outpng(self):
        string="%s\t%s" % (self.Type,self.TextString)
        for i in range(len(self.ChoiceString)):
            string+='\t%s \t%s' %  (self.ChoiceString[i], self.ValidString[i])
        string+='\n'
        return string

#here we want to translate input into the question class and populate it
MyQuestions=[]
l=len(myset)
print(l)
for q, question in enumerate(myset):
    ThisQuestion=Question('MC','','','','')
    if 'Type' in question.keys():
        ThisQuestion=Question(question['Type'],'','','','')
    ThisQuestion.Text=question['Text']
    if 'Size' in question.keys():
        ThisQuestion.Size=question['Size']
    else:
        ThisQuestion.Size='Auto'
    nanswers=len(question['Answers'])
    for i in range(nanswers):
        ThisQuestion.Choice.append(question['Answers'][i]['Choice'])
        if 'Validity' in question['Answers'][i].keys():
            ThisQuestion.Valid.append(question['Answers'][i]['Validity'])
        else:
            ThisQuestion.Valid.append('incorrect')
    if 'Skip' in question.keys():
        ThisQuestion.Skip=strtobool(question['Skip'])
    else:
        ThisQuestion.Skip=strtobool('no')

    if not ThisQuestion.Skip:
        MyQuestions.append(ThisQuestion)



#spell checking

def correctstring(string):
    splits=string.split()
    for i, word in enumerate(splits):
        if "$" not in word and "\\" not in word:
            #print(word)
            wordy=TextBlob(word)
            if wordy != wordy.correct():
                splits[i]="\\sout{\\textcolor{red}{" + word + "}} \\textcolor{blue}{" + str(wordy.correct())+"}"
    newstring=' '.join(splits)
    return newstring


def correctstring2(string):
    spell=SpellChecker()
    splits=string.split()
    misspelled=spell.unknown(splits)

    for i, word in enumerate(misspelled):
    # Get the one `most likely` answer
        splits[i]=spell.correction(word)

    newstring=' '.join(splits)
    return newstring


import os
os.environ["PATH"] += os.pathsep + '/Library/TeX/texbin/'
os.environ["PATH"] += os.pathsep +'/usr/local/bin/'
def latexsize(string,filename):
    size='auto'
    with open("temporary.tex","w") as myfile:
       myfile.write("\\documentclass[preview]{standalone}\n")
       myfile.write("\\usepackage[fleqn]{amsmath}\n")
       myfile.write("\\usepackage{physics}\n")
       myfile.write("\\usepackage[T1]{fontenc}")
       myfile.write("\\newcommand{\\dbar}{\\text{\\dj}}")
       myfile.write("\\DeclareUnicodeCharacter{2212}{-}")
       myfile.write("\\begin{document}\n")
       myfile.write("\\setlength{\\mathindent}{3pt}\n")
       #myfile.write("\\setlength{\\abovedisplayskip}{3pt}\n")
       myfile.write("\\newcommand{\\makenonemptybox}[2]{%\n")
       myfile.write("\\par\\nobreak\\vspace{\\ht\\strutbox}\\noindent\n")
    #FIXME: make this part of option
    #put back if you want a box around the box
    #   myfile.write("\\fbox{%\n")
       myfile.write("\\parbox[c][\\dimexpr#1-2\\fboxsep][c]{\\dimexpr\\linewidth-6\\fboxsep}{\n")
       myfile.write("\\hrule width \\hsize height 0pt\n")
       myfile.write("  #2\n")
    #put back if you want a box around the box
    #   myfile.write(" }%\n")
       myfile.write("}%\n")
       myfile.write("\\par\\vspace{\\ht\\strutbox}\n")
       myfile.write("}\n")
       myfile.write("\\makeatother\n")
       string=string.replace("$$","\\begin{equation*}",1)
       string=string.replace("$$","\\end{equation*}",1)
       size2=size.strip()

       if size2.lower()=="auto": #automatic height is size is negative
           #print(string)
           myfile.write("\\parbox[c]{\\textwidth}{\\begin{flushleft}\n%s\n\\end{flushleft}} \n" % string)
       else: #fixed height if size is provided (Auto is default)
           myfile.write("\\makenonemptybox{%s}{%s} \n" % (size, string))

       myfile.write("\\end{document}\n")
       myfile.close()

       x = os.system("pdflatex temporary.tex > latex.log 2>&1 && gs -sDEVICE=pnggray -sBATCH -sOutputFile=%s -dNOPAUSE -r1200 temporary.pdf > latex.log 2>&1" % filename)

       if x !=0:
           print ('Exit code not 0, check result!')
       else:
           #os.system('open %s' % filename)
           os.system('rm temporary.tex')


def latexquestionnaire(Questions,solutions,yamlfile):
    if solutions:
        answers='answers'
        filepdf=yamlfile.rsplit(".",1)[0]+"_solutions.pdf"
        filelatex=filepdf.rsplit(".",1)[0]+".tex"
    else:
        answers=''
        filepdf=yamlfile.rsplit(".",1)[0]+".pdf"
        filelatex=filepdf.rsplit(".",1)[0]+".tex"

    with open(filelatex,"w") as flatex:
        flatex.write("\\documentclass[%s]{exam}\n" % answers)
        flatex.write("\\usepackage{physics}\n")
        flatex.write("\\usepackage[T1]{fontenc}\n")
        flatex.write("\\usepackage[normalem]{ulem}\n")
        #below is special macro for Thermo!
        flatex.write("\\newcommand{\\dbar}{\\text{\\dj}}\n")
        flatex.write("\\usepackage[margin=.75in]{geometry}\n")
        flatex.write("\\usepackage{lastpage}\n")
        flatex.write("\\usepackage{color}\n")
        flatex.write("\\usepackage[T1]{fontenc}\n")
        flatex.write("\\DeclareUnicodeCharacter{2212}{-}")
        flatex.write("\\firstpageheader{% left\n")
        flatex.write("%s\\\\\n" % title1)
        flatex.write("%s\n" % title2)
        flatex.write("}{% center\n")
        flatex.write("}{% right\n")
        flatex.write("\ifprintanswers \\textbf{Answer Key}\n")
        flatex.write("      \\fi}\n")
        #flatex.write("\\runningheader{}{}{}\n")
        #flatex.write("\\firstpagefooter{}{\\thepage/\pageref{LastPage}}{}\n")
        #flatex.write("\\runningfooter{}{\\thepage/\pageref{LastPage}}{}\n")
        #flatex.write("\\frenchspacing\n")
        flatex.write("\\unframedsolutions\n")
        flatex.write("\\SolutionEmphasis{\\sffamily}\n")
        flatex.write("\\renewcommand{\\solutiontitle}{Answer:~}\n")
        flatex.write("\\makeatother\n")
        flatex.write("\\extraheadheight{.35in}\n")
        flatex.write("\\extrafootheight{.15in}\n")
        flatex.write("\\setlength{\\marginparwidth}{1.5in}\n")
        flatex.write("\\nopointsinmargin\n")
        flatex.write("\\pointformat{}\n")
        flatex.write("\\CorrectChoiceEmphasis{\\color{red}\\bfseries}\n")

        flatex.write("\\begin{document}\n")
        flatex.write("\\begin{questions}\n")
        for q, question in enumerate(Questions):
            flatex.write("\\question %s\n" % question.Text)
            flatex.write("\\begin{choices}\n")
            for i in range(len(question.Choice)):
                if(solutions and question.Valid[i].lower() == "correct"):
                    flatex.write("\\CorrectChoice %s\n" % question.Choice[i])
                else:
                    flatex.write("\\choice %s\n" % question.Choice[i])
            flatex.write("\\end{choices}\n")
            flatex.write("\n")
        flatex.write("\\end{questions}\n")
        flatex.write("\\end{document}\n")
        flatex.close()
    x = os.system("/Library/TeX/texbin/pdflatex %s > latex.log2 2>&1" % filelatex)
    #need to run twice to get total number of points correctly added
    x = os.system("/Library/TeX/texbin/pdflatex %s > latex.log2 2>&1" % filelatex)
    if x !=0:
        print ('Exit code not 0, check result! %s ' % filepdf)
    os.system("open %s" % filepdf)

if spellcheck:
    #spell checking and provide latex file with proposed corrections
    #we do not touch the original questions
    #the users must make the changes themselves
    import copy
    MyNewQuestions=copy.deepcopy(MyQuestions)

    for question in MyNewQuestions:
        question.Text=correctstring(question.Text)
        for i, choice in enumerate(question.Choice):
            question.Choice[i]=correctstring(question.Choice[i])

    filepdf=yamlfile.rsplit(".",1)[0]+"SPELLCHECKED.pdf"
    latexquestionnaire(MyNewQuestions,False,filepdf)

#now the original file



latexquestionnaire(MyQuestions,solutions,yamlfile)

if create_LMS_text:
 #This is for un-latexized version of the questions
    filename=yamlfile.rsplit(".",1)[0]+"_LMS_text.txt"
    f = open(filename, "w")
    for q in MyQuestions: #run over all questions
        f.write(q.out().replace("$","$$"))
    f.close()

#ID = "THERMO_"+yamlfile.rsplit(".",1)[0] #we remove suffix but only last one
ID = dir+"_"+yamlfile.rsplit(".",1)[0] #we remove suffix but only last one
if create_LMS:
    myfolder='Questions_%s' % ID
    scp_string='scp -r '+myfolder+'  meuniv@rcs.rpi.edu:~/public_html/Images/TSM_F20/.'

    print("PNG files will be stored at %s " % myfolder)
    if not os.path.exists(myfolder):
        print("Directory does not exist, creating it\n")
        os.makedirs(myfolder)
    else:
        print("Directory already exists. Files will be replaced.\n")

    #this is for latexized version of the questions
    filename=yamlfile.rsplit(".",1)[0]+"_LMS_png.txt"

    fpng = open(filename, "w")
    j=0
    for q in MyQuestions: #run over all questions
        p=j+1
    # one directory per question
        myfolder2=myfolder+"/Q%s" % j
        if not os.path.exists(myfolder2):
            os.makedirs(myfolder2)

        print("\t Question type: %s" % q.Type)
        filename=myfolder2+"/Q%s.png" % j
        latexsize(q.Text,filename)
        print(q.Text)
        filename=base+filename
        q.TextString="<p><img src=\"%s\" height=\"33\" /></p>" % filename


        for i in range(len(q.Choice)):
            filename=myfolder2+"/Q%s_%s.png" % (j, i)
            latexsize(q.Choice[i],filename)
            filename=base+filename
            q.ChoiceString.append("<p><img src=\"%s\" height=\"33\" /></p>" % filename)

            if q.Type.lower() == "mat" :
                filename=myfolder2+"/S%s.png" % i
                latexsize(q.Valid[i],filename)
                filename=base+filename
                q.ValidString.append("<p><img src=\"%s\" height=\"33\" /></p>" % filename)
            else :
                q.ValidString.append(q.Valid[i])


        fpng.write(q.outpng())
        j=j+1

    fpng.close()
    print("To copy for LMS use, executive: %s" % scp_string)