#!/usr/bin/env python # -*- coding: utf-8 -*- import yaml import json import urllib.request, urllib.parse, urllib.error import urllib.request, urllib.error, urllib.parse try: from dialog import Dialog except: Dialog = None import os import inspect import sys from bson.son import SON import kpov_random_helpers import random import argparse import locale locale.setlocale(locale.LC_ALL, ['C', 'utf8']) # SERVER_URL = "http://localhost/kpov_judge/" #SERVER_URL = "http://kpov.fri.uni-lj.si/kpov_judge/" #TASK_URL = SERVER_URL + '{task_id}/task.py' #PARAMS_URL = SERVER_URL + '{task_id}/params.json' #SUBMIT_URL = SERVER_URL + '{task_id}/results.json' TASK_URL = "file://" + os.getcwd() + '/tasks' PARAMS_FILE = os.path.expanduser("~/.kpov_params.yaml") DEFAULT_LANGUAGE = 'si' """get the parameters for a task either from the user or from a file.""" def get_params_dialog(params, meta, param_name_list=None, dialog=None, language = None): if param_name_list is None: param_name_list = list(meta.keys()) if language is None: language = params.get('language', DEFAULT_LANGUAGE) for name in param_name_list: if name not in meta: pass got_param = False while not got_param: m = meta.get(name, {}) try: description = m['descriptions'][language] except KeyError: description = name if params.get(name, None) is None: init = '' else: init = params[name] ret, s = dialog.inputbox(description, init=init) # print ret, type(ret) if ret == 'ok': if m.get('w', True): params[name] = s elif name not in params: params[name] = None got_param = (ret == 'ok') and name in params return params def add_meta_to_argparser(argparser, meta, defaults = {}): language = defaults.get('language', DEFAULT_LANGUAGE) for k, v in meta.items(): try: desc = v['descriptions'][language].encode("utf-8") except: desc = k # print("{} {}".format(desc, type(desc))) argparser.add_argument('--'+k, nargs='?', help=desc, type=str, default=defaults.get(k, None)) return argparser def http_auth(url, username, password): password_mgr = urllib.request.HTTPPasswordMgrWithDefaultRealm() # Add the username and password. # If we knew the realm, we could use it instead of None. password_mgr.add_password(None, url, username, password) handler = urllib.request.HTTPBasicAuthHandler(password_mgr) # create "opener" (OpenerDirector instance) opener = urllib.request.build_opener(handler) # use the opener to fetch a URL # opener.open(SERVER_URL) # Install the opener. # Now all calls to urllib2.urlopen use our opener. urllib.request.install_opener(opener) def load_task(stream): # the stream should compile into at least the function # task(...) and a dictionary "params_meta". source = stream.read() t = compile(source, 'task.py', 'exec') d = {} exec(t, d) # get a list of arguments for task(...) # args_list = inspect.getargs(task.func_code)[0] return d['task'], d['task_check'], d['params_meta'], d['gen_params'] def locate_task(params, argparser, dialog): # first the URL where all tasks are stored url_meta = { 'task_url': {'descriptions': {'si': 'URL z nalogami', 'en': 'Root URL for all tasks'}, } } if 'task_url' not in params: params['task_url'] = TASK_URL argparser = add_meta_to_argparser(argparser, meta = url_meta, defaults = params) args, unknown_args = argparser.parse_known_args() params['task_url'] = args.task_url if dialog is not None: params = get_params_dialog(params, url_meta, dialog = dialog) # then the student's ID (and password if neccessarry) fetch_params_meta = { 'username':{'descriptions': {'si': 'Uporabniško ime', 'en': 'Username'}, }, } if params['task_url'] is not None and ( params['task_url'].startswith('http')): fetch_params_meta['password'] = {'descriptions': {'si': 'Geslo', 'en': 'Password'}, } # and finally, the name of the task fetch_params_meta['task_name'] = {'descriptions': {'si': 'Ime naloge', 'en': 'Task name'}, } argparser = add_meta_to_argparser(argparser, meta = fetch_params_meta, defaults = params) args, unknown_args = argparser.parse_known_args() # update params with the now known args for k, v in fetch_params_meta.items(): params[k] = vars(args).get(k, params.get(k, None)) if dialog is not None: params = get_params_dialog(params, fetch_params_meta, dialog=dialog) return argparser, params def load_params(filename): try: with open(filename) as f: saved_params = yaml.load(f) except: saved_params = dict() if saved_params is None: saved_params = dict() return saved_params if __name__ == '__main__': # get the parameters needed to get to the task, such as the URLs, the name of the task and optionally an ID from the student # start with the the parameters needed for the dialog gui to work basic_argparser = argparse.ArgumentParser(description='Get the task parameters', conflict_handler='resolve', add_help=False) basic_argparser.add_argument('-h', '--help', action='store_true') basic_argparser.add_argument('-q', '--quiet', action='store_true', help='disable dialog', default=False) basic_argparser.add_argument('-g', '--generate_params', action='store_true', help='Generate initial values the task parameters', default=False) basic_argparser.add_argument('-pf','--params_file', nargs='?', help='a local file containing saved param values', default=PARAMS_FILE) basic_args, unknown_args = basic_argparser.parse_known_args() # get default parameters including language params = load_params(basic_args.params_file) basic_argparser.add_argument('-l', '--language', nargs='?', help='the language used', default=params.get('language', DEFAULT_LANGUAGE)) basic_args, unknown_args = basic_argparser.parse_known_args() params['language'] = basic_args.language if not basic_args.help and ( not basic_args.quiet and Dialog is not None): dialog = Dialog(dialog="dialog") else: dialog = None # continue with the parameters needed to get the task argparser, params = locate_task(params, basic_argparser, dialog=dialog) # TODO: if the task name is missing or invalid, try to get a list of tasks # get task source and generate params if neccessarry try: task_url = params['task_url'] task_name = params['task_name'] if task_url.startswith('http'): http_auth(task_url, params['username'], params['password']) print("fetching {task_url}/{task_name}/task.py".format(**params)) req = urllib.request.Request("{task_url}/{task_name}/task.py".format(**params)) source = urllib.request.urlopen(req) task, task_check, task_params_meta, gen_params = load_task(source) except Exception as e: print(params) print(e) if basic_args.help: argparser.print_help() else: argparser.print_usage() with open(basic_args.params_file, 'w') as f: yaml.dump(params, f) exit(1) # get task parameters params['task_params'] = params.get('task_params', dict()) params['task_params'][params['task_name']] = params['task_params'].get(params['task_name'], dict()) task_params = params['task_params'][params['task_name']] if basic_args.generate_params: #prejema lahko samo stringe in ne številk (potrebno je str(int) # print ("params before: {} {}".format(params, task_params)) task_params.update(gen_params(params['username'], task_params_meta)) # print ("params after: {} {}".format(params, task_params)) if task_url.startswith('http'): req = urllib.request.Request("{task_url}/{task_name}/params.json".format(**params)) web_task_params = json.load(urllib.request.urlopen(req)) task_params.update(web_task_params) params_argparser = argparse.ArgumentParser(parents=[argparser], conflict_handler='resolve', add_help=True) params_argparser = add_meta_to_argparser(params_argparser, task_params_meta, defaults=task_params) args = vars(params_argparser.parse_args()) for k in task_params_meta: if k in args and args[k] is not None: task_params[k] = args[k] if dialog is not None: task_params = get_params_dialog(task_params, task_params_meta, dialog=dialog, language = params['language']) # print(task_params) if basic_args.help: # params_argparser.print_help() print(params_argparser.format_help()) exit(0) # run task.task() public_params = dict() for k in inspect.getargs(task.__code__)[0]: public_params[k] = task_params[k] params['task_params'][params['task_name']] = task_params # save parameters for the next run with open(basic_args.params_file, 'w') as f: # print "dumping", params yaml.dump(params, f) try: task_result = task(**public_params) # run task.task_check() except Exception as e: print("Error running task(...):") print(e) exit(1) try: result, hints = task_check(task_result, task_params) print(result, hints) except Exception as e: print("Error running task_check(results, params):") print(e)