def parse(args: list = None): parser = ArgumentParser( description='Get, test and submit Kattis problems.', conflict_handler='resolve') parser.add_argument( '-n', '--no-override', action='store_true', help='Run the command without any of the overrides set in your config.' ) sub_parsers = parser.add_subparsers(dest='command', metavar='command') for p in parsers: p(sub_parsers) parsed = vars(parser.parse_args(args)) noOverride = parsed.get('no_override') if noOverride: return parsed cfg = getConfig() command = parsed.get('command') commandConfig = cfg.get('Default options', {}).get(command, '').strip() if commandConfig and args: configArgs = commandConfig.split() newArgs = unify_args(command, args, configArgs) return vars(parser.parse_args(newArgs)) else: return parsed
def get(problemName: str, data: dict): checkCorrectDomain(problemName, "get") message = "" folder = findProblemLocation(problemName) if folder is None: overrideLanguage = data['language'] fetchProblem(problemName, overrideLanguage) message = "👍 Successfully initialized exercise " + problemName + "!" elif folder != "": unarchive(problemName) message = "👍 Successfully unarchived exercise " + problemName + "!" if message != "": print(message) else: print("👍 You already have " + problemName) if "open" in data and data['open']: webCommand(problemName) fileOpener = getConfig().get('kat', {}).get('openfilecommand') if fileOpener: file = selectProgramFile(problemName) subprocess.run(formatCommand(fileOpener, file).split()) return folder
def collectProblems(args, options): session = requests.Session() config = getConfig() url = "https://open.kattis.com/problems/" parameters = buildParameters(args, options) login(config, session) problems = fetchProblems(url, parameters, args, session) return problems
def getRuntime(id, problemName, session): user = getConfig().get("user", "username") url = f"{getConfigUrl('usersurl', 'users')}/{user}/submissions/{problemName}" response = session.get(url, headers=HEADERS) body = response.content.decode("utf-8") soup = BeautifulSoup(body, "html.parser") data = soup.select( f'table.table-kattis tbody tr[data-submission-id="{id}"] td.runtime') if len(data) > 0: return data[0].text
def problem(problemName: str): if problemName.startswith(".\\"): problemName = problemName[2:] if problemName.endswith("\\"): problemName = problemName[:-1] if len(problemName) == 1: section = getConfig().get('contest') if problemName in section: return section[problemName] return problemName
def configCommand(data): if 'section' not in data: print("Adding/updating configuration to your .kattisrc...") if not getConfig(): print("""\ Something went wrong in locating the configuration file for kattis. Have you fetched the .kattisrc? Consult the README.md for more details.""") else: print( "Successfully added default configuration to your .kattisrc!") elif "value" in data: cfg, location = getConfig(shouldReturnLocation=True) section = data["section"] option = data["option"] value = data["value"] if not cfg: print("""\ Something went wrong in locating the configuration file for kattis. Have you fetched the .kattisrc? Consult the README.md for more details.""") elif cfg.has_section(section): if not cfg.has_option(section, option) and section.lower() in [ "kat", "kattis", "user" ]: print("Setting", option, "was not recognized for section [" + section + "]") else: cfg.set(section, option, value) with open(location, "w") as configFile: cfg.write(configFile) print("The setting", option, "from section [" + section + "]", "was set to", value) else: print("Section [" + section + "]", "was not found.") else: print("""\ Invalid number of arguments, expected 'config <section> <option> <value>'. Remember to put arguments with spaces in quotes.""")
def copyConfigStep(): print("💾 Adding/updating configuration to your .kattisrc...") if not getConfig(): print("""\ ❌ Something went wrong in locating the configuration file for kattis. Have you fetched the .kattisrc? Consult the README.md for more details.""") return False else: print("✅ Successfully added default configuration to your .kattisrc!") return True
def configCommand(args, options): if len(args) == 0: print("Adding/updating configuration to your .kattisrc...") if getConfig() == -1: print("""\ Something went wrong in locating the configuration file for kattis. Have you fetched the .kattisrc? Consult the README.md for more details.""") else: print( "Successfully added default configuration to your .kattisrc!") elif len(args) == 3: cfg, location = getConfig(shouldReturnLocation=True) if type(cfg) is int: print("""\ Something went wrong in locating the configuration file for kattis. Have you fetched the .kattisrc? Consult the README.md for more details.""") elif cfg.has_section(args[0]): if not cfg.has_option(args[0], args[1]) and args[0].lower() in [ "kat", "kattis", "user" ]: print("Setting", args[1], "was not recognized for section [" + args[0] + "]") else: cfg.set(args[0], args[1], args[2]) with open(location, "w") as configFile: cfg.write(configFile) print("The setting", args[1], "from section [" + args[0] + "]", "was set to", args[2]) else: print("Section [" + args[0] + "]", "was not found.") else: print("""\ Invalid number of arguments, expected 'config <section> <option> <value>'. Remember to put arguments with spaces in quotes.""")
def createBoilerplate(problemName, overrideLanguage=None): from helpers.programSelector import guessLanguage, formatProgramFile cfg = getConfig() if overrideLanguage: lang = overrideLanguage.lower() else: lang = cfg.get("kat", {}).get("language").lower() if lang in cfg["Initialize commands"]: cmd = cfg["Initialize commands"].get(lang).split() subprocess.run([p for p in cmd], cwd=problemName) if lang.lower() == 'rust': f = open(os.path.join(problemName, 'rust-toolchain'), 'w') f.write('1.26.0') f.close() return directory = os.path.dirname(os.path.realpath( __file__)) + "/../boilerplate" #todo please make this better boilerplates = { guessLanguage(formatProgramFile(f)): f for f in os.listdir(directory) if os.path.isfile(os.path.join(directory, f)) } fileName = problemName if lang in cfg["Naming"]: naming = cfg.get("Naming").get(lang) namingFn = namingSchemeConverters[naming] fileName = namingFn(fileName) if lang.lower() in boilerplates: boilerplate = boilerplates[lang] fileType = "." + boilerplates[lang].split(".")[-1] shutil.copy2( directory + "/" + boilerplate, problemName + "/" + fileName + fileType, ) else: fileType = [ file for (file, k) in cfg["File associations"].items() if k.lower() == lang.lower() ] if fileType: open(problemName + "/" + fileName + fileType[0], "a").close() else: #Language does not exist, delete the folder print( f"Error, unable to resolve {lang} to a language that could be run. Please check if your spelling matches the one used by kat tool." ) print(f"These are the supported languages:") print(", ".join(cfg["File associations"].values()))
def contestCommand(data): session = requests.Session() contest = data.get('contest-id') contestData = readContest(contest, session) if contestData.get('timeState') == TimeState.NotStarted: timeTo = contestData.get('timeTo') print('Contest has not started yet.') print(f'Contest begins in {timeTo}.') print("Do you want to run this command again when the contest starts?") if not yes(): return print("Waiting for contest to start...") while contestData.get('timeState') == TimeState.NotStarted: timeTo = contestData.get('timeTo') timeToInSeconds = timeTo.total_seconds() if timeTo is not None else -1 # the -1 denotes that we don't know how long it is to contest start, and will result in the code checking every second if timeToInSeconds > 10: time.sleep(timeToInSeconds - 10) else: time.sleep(1) contestData = readContest(contest, session) elif contestData.get('timeState') == TimeState.Ended: print('The contest seems to be over.') if len(contestData.get('problems')) > 0: print('Do you want to get the problems from the contest anyways?') if not yes(): return solved = getCommand({ **data, 'command': 'get', 'problem': contestData.get('problems'), 'language': None, }) #update config with new problems config = getConfig() config['contest'] = contestData['problemMap'] saveConfig() if solved: if not data.get('submit'): print("Some problems were unarchived from the .solved folder:") print(", ".join(solved)) print("Do you want to submit them?") if not yes(): return for problem in solved: submitCommand({"problem": problem, "force": True, "archive": True})
def login(session): config = getConfig() username = config.get("user", "username") token = config.get("user", "token") login_url = getConfigUrl("loginurl", "login") session.post( login_url, data={ "user": username, "token": token, "script": "true" }, headers=_HEADERS, )
def readCommand(arg, options): session = requests.Session() config = getConfig() problemName = arg problemUrl = "https://open.kattis.com/problems/" + problemName checkProblemExistence(problemName) if "console" not in options: webCommand(problemName) else: problemText = fetchProblemText(problemUrl, options, session) for line in problemText: print(line)
def languageStep(): cfg = getConfig() lang = cfg.get("kat", "language") allLangs = set(x.lower() for x in cfg["File associations"].values()) iter(cfg["Run commands"]) print('Choose your language') print('This tool works best with', ', '.join(cfg["Run commands"])) print( 'It also supports every language on Kattis, but you would need to tinker with the configurations to test optimally.' ) print('(These are', ', '.join(allLangs), ')') print('Leave blank for', lang) language = input('Your pick: ') cfg.set("kat", "language", language if language.lower() in allLangs else lang) return True
def submitCommand(args, options): problemName = args[0] directory = os.path.join(os.getcwd(), problemName) if not os.path.exists(problemName): promptToFetch(args, options) return Response.Error # if programFile is not given, we will attempt to guess it programFile = (formatProgramFile(args[1]) if args[1:] else selectProgramFile(problemName)) if programFile == -1: raise Exception("Could not guess programFile") if "force" not in options: response = confirm(problemName, programFile) if not response: return Response.Aborted config = getConfig() session = requests.Session() print("📨 Submitting " + problemName + "...") id = postSubmission(config, session, problemName, programFile) print("📬 Submission Successful (url https://open.kattis.com/submissions/" + id + ")") if id == -1: return False response = Response.Failure try: response = printUntilDone(id, problemName, config, session, options) except: pass if "sound" in options: if response == Response.Success: winsound() elif response == Response.Failure: losesound() if response == Response.Success: if "archive" in options: archiveCommand(problemName, options, ".solved/") return response
def createBoilerplate(problemName): from helpers.programSelector import formatCommand, guessLanguage, formatProgramFile cfg = getConfig() lang = cfg.get("kat", "language") if lang in cfg["Initialize commands"]: cmd = cfg["Initialize commands"].getcommand(lang) subprocess.run([p for p in cmd], cwd=problemName) return directory = os.path.dirname(os.path.realpath(__file__)) + "/../boilerplate" boilerplates = { guessLanguage(formatProgramFile(f)): f for f in os.listdir(directory) if os.path.isfile(os.path.join(directory, f)) } if lang in boilerplates: boilerplate = boilerplates[lang] fileType = "." + boilerplates[lang].split(".")[-1] shutil.copy2( directory + "/" + boilerplate, problemName + "/" + problemName + fileType, ) else: fileType = [file for (file, k) in cfg["File associations"].items() if k.lower() == lang.lower()] open(problemName + "/" + problemName + fileType[0], "a").close()
import os, re, subprocess from helpers.fileutils import getBytesFromFile from helpers.config import getConfig # import os, subprocess, re cfg = getConfig() _LANGUAGE_GUESS = cfg["File associations"] _LANGUAGE_RUN_COMMANDS = cfg["Run commands"] _LANGUAGE_COMPILE_COMMANDS = cfg["Compile commands"] def selectProgramFile(problemName): # Get all files, and format them files = [ formatProgramFile(os.path.join(problemName, f)) for f in os.listdir(problemName) ] # ..but only select those which we support files = list(filter(isValidProgramFile, files)) if len(files) == 0: print( "No source file fould for problem '" + problemName + "'.\nCreate a file inside the folder matching the problem (for example '" + problemName + "/answer.py')"