Skip to content
Snippets Groups Projects
Select Git revision
  • af7a90c2a62d45003e0202dba11c3d4a0288e2f0
  • master default protected
2 results

about.html

Blame
  • Code owners
    Assign users and groups as approvers for specific file changes. Learn more.
    unitgrade_helpers.py 7.02 KiB
    import numpy as np
    from tabulate import tabulate
    from datetime import datetime
    import pyfiglet
    from unitgrade import Hidden, myround, msum, mfloor
    from unitgrade import __version__
    
    # from unitgrade.unitgrade import Hidden
    # import unitgrade as ug
    # import unitgrade.unitgrade as ug
    import inspect
    import os
    import argparse
    import sys
    
    parser = argparse.ArgumentParser(description='Evaluate your report.', epilog="""Example: 
    To run all tests in a report: 
    
    > python assignment1_dp.py
    
    To run only question 2 or question 2.1
    
    > python assignment1_dp.py -q 2
    > python assignment1_dp.py -q 2.1
    
    Note this scripts does not grade your report. To grade your report, use:
    
    > python report1_grade.py
    
    Finally, note that if your report is part of a module (package), and the report script requires part of that package, the -m option for python may be useful.
    For instance, if the report file is in Documents/course_package/report1.py, and `course_package` is a python package, then change directory to 'Documents/` and run:
    
    > python -m course_package.report1
    
    see https://docs.python.org/3.9/using/cmdline.html
    """, formatter_class=argparse.RawTextHelpFormatter)
    parser.add_argument('-q', nargs='?', type=str, default=None, help='Only evaluate this question (e.g.: -q 2)')
    parser.add_argument('--showexpected',  action="store_true",  help='Show the expected/desired result')
    parser.add_argument('--showcomputed',  action="store_true",  help='Show the answer your code computes')
    parser.add_argument('--unmute',  action="store_true",  help='Show result of print(...) commands in code')
    parser.add_argument('--passall',  action="store_true",  help='Automatically pass all tests. Useful when debugging.')
    
    # parser.add_argument('integers', metavar='N', type=int, nargs='+',
    #                     help='an integer for the accumulator')
    # parser.add_argument('--sum', dest='accumulate', action='store_const',
    #                     const=sum, default=max,
    #                     help='sum the integers (default: find the max)')
    
    def evaluate_report_student(report, question=None, qitem=None, unmute=None, passall=None, ignore_missing_file=False):
        args = parser.parse_args()
        if question is None and args.q is not None:
            question = args.q
            if "." in question:
                question, qitem = [int(v) for v in question.split(".")]
            else:
                question = int(question)
    
        if not os.path.isfile(report.computed_answers_file) and not ignore_missing_file:
            raise Exception("> Error: The pre-computed answer file", os.path.abspath(report.computed_answers_file), "does not exist. Check your package installation")
    
        if unmute is None:
            unmute = args.unmute
        if passall is None:
            passall = args.passall
        # print(passall)
        results, table_data = evaluate_report(report, question=question, qitem=qitem, verbose=False, passall=passall, show_expected=args.showexpected, show_computed=args.showcomputed,unmute=unmute)
    
        if question is None:
            print("Provisional evaluation")
            tabulate(table_data)
            table = table_data
            print(tabulate(table))
            print(" ")
        print("Note your results have not yet been registered. \nTo register your results, please run the file:")
    
        fr = inspect.getouterframes(inspect.currentframe())[1].filename
        print(">>>", os.path.basename(fr)[:-3] + "_grade.py")
        print("In the same manner as you ran this file.")
        return results
    
    
    def upack(q):
        # h = zip([(i['w'], i['possible'], i['obtained']) for i in q.values()])
        h =[(i['w'], i['possible'], i['obtained']) for i in q.values()]
        h = np.asarray(h)
        return h[:,0], h[:,1], h[:,2],
    
    def evaluate_report(report, question=None, qitem=None, passall=False, verbose=False,  show_expected=False, show_computed=False,unmute=False, show_help_flag=True, silent=False):
        from unitgrade.version import __version__
        now = datetime.now()
        ascii_banner = pyfiglet.figlet_format("UnitGrade", font="doom")
        b = "\n".join( [l for l in ascii_banner.splitlines() if len(l.strip()) > 0] )
        print(b + " v" + __version__)
        dt_string = now.strftime("%d/%m/%Y %H:%M:%S")
        print("Started: " + dt_string)
        s = report.title
        if report.version is not None:
            s += " version " + report.version
        print("Evaluating " + s, "(use --help for options)" if show_help_flag else "")
        print(f"Loaded answers from: ", report.computed_answers_file, "\n")
        table_data = []
        nL = 80
    
        score = {}
        for n, (q, w) in enumerate(report.questions):
            q_hidden = issubclass(q.__class__, Hidden)
            if question is not None and n+1 != question:
                continue
    
            # Don't use f format strings.
            print(f"Question {n+1}: {q.title}" + (" (" + str( np.round(report.payloads[q.name].get('time', 0), 2) ) + " seconds)"  if q.name in report.payloads else "" ) )
            print("="*nL)
            q.possible = 0
            q.obtained = 0
    
            q_ = {} # Gather score in this class.
            for j, (item, iw) in enumerate(q.items):
                if qitem is not None and question is not None and item is not None and j+1 != qitem:
                    continue
    
                ss = f"*** q{n+1}.{j+1}) {item.title}"
                el = nL-4
                if len(ss) < el:
                    ss += '.'*(el-len(ss))
                hidden = issubclass(item.__class__, Hidden)
                if not hidden:
                    print(ss, end="")
                sys.stdout.flush()
                import time
                start = time.time()
                (current, possible) = item.get_points(show_expected=show_expected, show_computed=show_computed,unmute=unmute, passall=passall, silent=silent)
                q_[j] = {'w': iw, 'possible': possible, 'obtained': current, 'hidden': hidden, 'computed': str(item._computed_answer), 'title': item.title}
                tsecs = np.round(time.time()-start, 2)
    
                # q.possible += possible * iw
                # q.obtained += current * iw
                if not hidden:
                    ss = "PASS" if current == possible else "*** FAILED"
                    ss += " ("+ str(tsecs) + " seconds)"
                    print(ss)
    
            ws, possible, obtained = upack(q_)
            possible = int(ws @ possible)
            obtained = int(ws @ obtained)
            obtained = int(myround(int((w * obtained) / possible ))) if possible > 0 else 0
            score[n] = {'w': w, 'possible': w, 'obtained': obtained, 'items': q_, 'hidden': q_hidden, 'title': q.title}
    
            q.obtained = obtained
            q.possible = possible
    
            s1 = f"*** Question q{n+1}"
            s2 = f" {q.obtained}/{w}"
            print(s1 + ("."* (nL-len(s1)-len(s2) )) + s2 )
            print(" ")
            table_data.append([f"Question q{n+1}", f"{q.obtained}/{w}"])
    
        ws, possible, obtained = upack(score)
        possible = int( msum(possible) )
        obtained = int( msum(obtained) ) # Cast to python int
        report.possible = possible
        report.obtained = obtained
        now = datetime.now()
        dt_string = now.strftime("%H:%M:%S")
        print(f"Completed: "+ dt_string)
        table_data.append(["Total", ""+str(report.obtained)+"/"+str(report.possible) ])
        results = {'total': (obtained, possible), 'details': score}
        return results, table_data