def get_student_module(path): arg_abspath = os.path.abspath(path) parent_abspath, student_module_name = os.path.split(arg_abspath) sys.path.insert(0, arg_abspath) # Redirect stdout to the void while importing ui.mute_stdout() try: student_module = importlib.import_module("main") except Exception as e: ui.unmute_stdout() ui.report_error( "module_import_fail", module_name=student_module_name, dir=parent_abspath, exception=str(e), ) exit(51) if not hasattr(student_module, "__winc_id__"): ui.unmute_stdout() ui.report_error("module_no_winc_id", module_name=student_module_name, dir=parent_abspath) exit(52) # Restore stdout ui.unmute_stdout() return student_module
def exec_assignment_code(filename, quiet=False, skip_cache=False): """ Execs the code in filename and returns a dictionary with the variables in scope minus builtins. """ if not skip_cache and cache.get("output", None) and cache.get( "state", None): return cache["output"], cache["state"] with open(filename, "r") as fp: assignment_code = fp.read() try: f = io.StringIO() with redirect_stdout(f): state = {} exec(assignment_code, state) del state["__builtins__"] output = f.getvalue() except: ui.report_error("exec_failed") exit(50) if not quiet: ui.print_student_output(output) cache["output"], cache["state"] = output, state return output, state
def check(args): student_module = helpers.get_student_module(args.path) winc_id = student_module.__winc_id__ try: check_module = importlib.import_module(f".{winc_id}", "wincpy.checks") # solution_module = importlib.import_module(f'.{winc_id}', 'wincpy.solutions') except ImportError: ui.report_error("no_check_found", assignment_name=student_module.__human_name__) exit(4) checks = [ v for k, v in check_module.__dict__.items() if k.startswith("check_") ] if not checks: ui.report_error("empty_check", assignment_name=student_module.__human_name__) result = [] for check in checks: if not check.__doc__: fname = check.__qualname__ check.__doc__ = ("`" + fname[fname.find("_") + 1:] + "` is implemented correctly") try: check(student_module) result.append((check.__doc__, None)) except Exception as e: result.append((check.__doc__, e)) return result
def main(stdout, stderr): args = helpers.parse_args() ui.print_intro() if args.action == "start": start(args) elif args.action == "check": result = check(args) ui.report_check_result(result) if all([score for _, score in result]): exit(0) else: # No runtime errors but the solution didn't pass. exit(1) elif args.action == "update": update() elif args.action == "solve": result = check(args) passed = all([not x for _, x in result]) if passed: solve(args) else: ui.report_error("solve_first") exit(1) elif args.action == "version": ui.print_version()
def get_iddb(): iddb_url = "https://raw.githubusercontent.com/WincAcademy/wincid/master/iddb.json" iddb_bytes = urllib.request.urlopen(iddb_url, timeout=1).read() iddb = json.loads(iddb_bytes) try: iddb_bytes = urllib.request.urlopen(iddb_url, timeout=1).read() iddb = json.loads(iddb_bytes) except: ui.report_error("iddb_load_fail") exit(6) return iddb
def solve(args): student_module = helpers.get_student_module(args.path) winc_id = student_module.__winc_id__ solutions_abspath = solutions.__path__[0] solution_abspath = os.path.join(solutions_abspath, winc_id) if not os.path.isdir(solution_abspath): ui.report_error("no_solution_available", exercise_name=student_module.__human_name__) exit(5) try: dest_dir = student_module.__human_name__ + "_example_solution" shutil.copytree(solution_abspath, dest_dir) ui.report_success("solution_available", solution_dir=dest_dir) except: ui.report_error("dir_exists", dirname=dest_dir) exit(3)
def start(args): iddb = helpers.get_iddb() if args.winc_id not in iddb: ui.report_error("unknown_winc_id") exit(2) human_name = iddb[args.winc_id]["human_name"] ui.report_neutral("assignment_start", assignment_name=human_name) starts_abspath = starts.__path__[0] starts_dirs = list(os.walk(starts_abspath))[0][1] starts_dirs = {d: os.path.join(starts_abspath, d) for d in starts_dirs} # Winc ID is known, but does not require a particular start. if args.winc_id not in starts_dirs: try: os.mkdir(human_name) except FileExistsError: ui.report_error("dir_exists", dirname=human_name) exit(3) with open(os.path.join(human_name, "main.py"), "w") as fp: fp.write("# Do not modify these lines\n" + f"__winc_id__ = '{args.winc_id}'\n" + f"__human_name__ = '{human_name}'\n\n" + "# Add your code after this line\n") else: try: shutil.copytree(starts_dirs[args.winc_id], human_name) except FileExistsError: ui.report_error("dir_exists", dirname=human_name) exit(3) ui.report_success("assignment_start", assignment_name=human_name)