Skip to content
Snippets Groups Projects
Select Git revision
  • 94ec3ae520adab6b0da561592fa04a63b9f22733
  • main default protected
  • devel
3 results

setup.py

Blame
  • Code owners
    Assign users and groups as approvers for specific file changes. Learn more.
    hidden_create_files.py 5.70 KiB
    from src.unitgrade2 import cache_write, unitgrade_helpers2
    import jinja2
    import pickle
    import inspect
    import os
    from unitgrade_private2 import hidden_gather_upload
    import sys
    
    data = """
    {{head}}
    
    report1_source = {{source}}
    report1_payload = '{{payload}}'
    name="{{Report1}}"
    
    report = source_instantiate(name, report1_source, report1_payload)
    output_dir = os.path.dirname(__file__)
    gather_upload_to_campusnet(report, output_dir)
    """
    
    def setup_answers(report):
        """
        Obtain student answers by executing the test in the report and then same them to the disk.
        """
        payloads = {}
        import tabulate
        from collections import defaultdict
        rs = defaultdict(lambda: [])
        for q, _ in report.questions:
            # for q, _ in report.questions:
            q()._save_cache()
    
            q.name = q.__class__
            payloads[q.name] = {}
            print("> Setting up question", q)
            # start = time.time()
            # q.init_all_item_questions() # Initialize all this questions items questions (i.e. make sure the items can run).
            # payloads[q.name]['time'] = time.time()-start
            # for item in q.items:
            #     print("    Setting up item", item)
            #     start = time.time()
            #     item._precomputed_payload = item.precompute_payload()
            #     answer = item.compute_answer(unmute=True)
            #
            #     rs['Name'].append(str(item))
            #     rs['Answer'].append( sys.getsizeof(pickle.dumps(answer)) )
            #     rs['Precomputed'].append( sys.getsizeof( pickle.dumps(item._precomputed_payload)))
            #     payloads[q.name][item.name] = {'payload': answer, 'precomputed': item._precomputed_payload, 'time': time.time() - start, 'title': item.title}
    
        print(tabulate.tabulate(rs, headers="keys"))
        cache_write(payloads, report.computed_answers_file, verbose=False)
    
    
    def strip_main(report1_source):
        dx = report1_source.find("__main__")
        report1_source = report1_source[:dx]
        report1_source = report1_source[:report1_source.rfind("\n")]
        return report1_source
    
    # def pack_report_for_students(Report1, obfuscate=False, minify=False, bzip=True, nonlatin=False):
    
    def setup_grade_file_report(ReportClass, execute=True, obfuscate=True, minify=True, bzip=True, nonlatin=False, source_process_fun=None,
                                with_coverage=True):
        print("Setting up answers...")
        # ReportClass()
        payload = ReportClass()._setup_answers(with_coverage=with_coverage)
        # setup_answers(ReportClass())
        import time
        time.sleep(0.1)
        print("Packing student files...")
        # pack report into a binary blob thingy the students can run on their own.
        # report = ReportClass()
        fn = inspect.getfile(ReportClass)
        with open(fn, 'r') as f:
            report1_source = f.read()
        report1_source = strip_main(report1_source)
    
        # Do fixing of source. Do it dirty/fragile:
        if source_process_fun == None:
            source_process_fun = lambda s: s
    
        report1_source = source_process_fun(report1_source)
    
        # payload = cache_read(report.computed_answers_file)
        picklestring = pickle.dumps(payload)
    
        from src import unitgrade2
        excl = ["unitgrade2.unitgrade_helpers2",
                "from . import",
                "from unitgrade2.",
                "from unitgrade2 ",
                "import unitgrade2"]
    
        def rmimports(s, excl):
            s = "\n".join([l for l in s.splitlines() if not any([l.strip().startswith(e) for e in excl])])
            return s
    
        def lload(flist, excl):
            s = ""
            for fname in flist:
                with open(fname, 'r', encoding="utf-8") as f:
                    s += f.read() + "\n" + "\n"
            s = rmimports(s, excl)  # remove import statements from helper class.
            return s
        report1_source = rmimports(report1_source, excl)
    
        pyhead = lload([unitgrade_helpers2.__file__, hidden_gather_upload.__file__], excl)
        from src.unitgrade2 import version
        report1_source = lload([unitgrade2.__file__, src.unitgrade2.unitgrade2.__file__, unitgrade_helpers2.__file__, hidden_gather_upload.__file__, version.__file__], excl) + "\n" + report1_source
    
        print(sys.getsizeof(picklestring))
        print(len(picklestring))
        s = jinja2.Environment().from_string(data).render({'Report1': ReportClass.__name__,
                                                           'source': repr(report1_source),
                                                           'payload': picklestring.hex(), #repr(picklestring),
                                                           'token_out': repr(fn[:-3] + "_handin"),
                                                           'head': pyhead})
        output = fn[:-3] + "_grade.py"
        print("> Writing student script to", output, "(this script may be shared)")
        with open(output, 'w', encoding="utf-8") as f:
            f.write(s)
    
        if minify:  # obfuscate:
            obs = '-O ' if obfuscate else ""
            # output_obfuscated = output[:-3]+"_obfuscated.py"
            extra = [  # "--nonlatin",
                # '--bzip2',
            ]
            if bzip: extra.append("--bzip2")
            cmd = f'pyminifier {obs} {" ".join(extra)} --replacement-length=20 -o {output} {output}'
            print(cmd)
            os.system(cmd)
            import time
            time.sleep(0.2)
            with open(output, 'r') as f:
                sauce = f.read().splitlines()
            wa = """WARNING: Modifying, decompiling or otherwise tampering with this script, it's data or the resulting .token file will be investigated as a cheating attempt."""
            sauce = ["'''" + wa + "'''"] + sauce[:-1]
            sauce = "\n".join(sauce)
            with open(output, 'w') as f:
                f.write(sauce)
    
        if execute:
            time.sleep(0.1)
            print("Testing packed files...")
            fn = inspect.getfile(ReportClass)
            s = os.path.basename(fn)[:-3] + "_grade"
            exec("import " + s)
        a = 234