def _act(self) -> None: pypi_info = requests.get(_PYPI_PACKAGE_INFO) releases = list(pypi_info.json()['releases']) if len(releases) == 0: log_red('Hmm seems like there is currently no pypi releases :-?') return current_latest_version = releases[-1] if current_latest_version != version: subprocess.check_call([ sys.executable, "-m", "pip", "install", "--upgrade", "--no-cache-dir", f"kttool=={current_latest_version}" ]) log(f'Installed version {color_green(current_latest_version)} successfully!' ) else: log(f'You already have the {color_green("latest")} version!')
def remove_template(self) -> None: ''' Remove a template from ktconfig file''' existed_templates = self.load_kt_config() log(f'Which template would you like to {color_red("delete")} ? For eg cpp, cc, ...' ) for k in existed_templates.keys(): log(k) res = input() assert res in existed_templates, f'Invalid template chosen. Template {res} is not in ur config file' move_default = existed_templates[res]['default'] existed_templates.pop(res, None) if existed_templates and move_default: # move default to the first key of template existed_templates[next(iter(existed_templates))] = True with open(self.kt_config, 'w') as kt_config: json.dump(existed_templates, kt_config, indent=2)
def update_default(self) -> None: default_key = '' existed_templates = self.load_kt_config() log(f'Which template would you like to gen as {color_cyan("default")} ? For eg cpp, cc, ...' ) for k, v in existed_templates.items(): log(f'{k} {color_green("(default)") if v["default"] else ""}') if v["default"]: default_key = k res = input() assert res in existed_templates, f'Invalid template chosen. Template {res} is not in ur config file' existed_templates[default_key]["default"] = False existed_templates[res]["default"] = True with open(self.kt_config, 'w') as kt_config: json.dump(existed_templates, kt_config, indent=2) log_green('Yosh, your configuration has been saved')
def _act(self) -> None: """ Run the executable file against sample input and output files present in the folder The sample files will only be recognized if the conditions hold: - Naming style should be in{idx}.txt and ans{txt}.txt - for in{idx}.txt, there must exist a ans{idx}.txt with the same `idx` """ self.detect_file_name() # Get sample files that match the condition usable_samples = self._gather_samples() # run test log(f'Problem ID : {color_cyan(self.get_problem_id())}') log(f'Lanuage : {self.lang}') if self.pre_script: log_cyan(f'running {self.pre_script}') subprocess.check_call(shlex.split(self.pre_script)) self._compare_samples(usable_samples) if self.post_script: log_cyan(f'running {self.post_script}') subprocess.check_call(shlex.split(self.post_script))
def _act(self) -> None: log(f'Current version: {color_cyan(version)}')
def add_template(self) -> None: question = 'Which template would you like to add:\n' selectable_lang = {} idx = 1 existed_templates = {} options = {} log_green('Adapted from xalanq\'s cf tool') log(''' Template will run 3 scripts in sequence when you run "kt test": - before_script (execute once) - script (execute the number of samples times) - after_script (execute once) You could set "before_script" or "after_script" to empty string, meaning not executing. You have to run your program in "script" with standard input/output (no need to redirect). You can insert some placeholders in your scripts. When execute a script, cf will replace all placeholders by following rules: $%path%$ Path to source file (Excluding $%full%$, e.g. "/home/user/") $%full%$ Full name of source file (e.g. "a.cpp") $%file%$ Name of source file (Excluding suffix, e.g. "a") $%rand%$ Random string with 8 character (including "a-z" "0-9") ''') existed_templates = self.load_kt_config() for template_type, lang in MAP_TEMPLATE_TO_PLANG.items(): if template_type not in existed_templates: temp = f'{idx} ({lang.extension}): {lang.full_name}\n' question += temp selectable_lang[idx] = (template_type, lang) idx += 1 res = input(question) ret = int(res) assert 1 <= ret < idx, 'Invalid input' selected_lang = selectable_lang[ret][1] import readline, glob def complete(text, state): return (glob.glob(os.path.expanduser(text) + '*') + [None])[state] readline.set_completer_delims(' \t\n;') readline.parse_and_bind("tab: complete") readline.set_completer(complete) options['path'] = os.path.expanduser(input('Path to template file: ')) options['pre_script'] = ask_with_default('Pre-script', selected_lang.pre_script) options['script'] = ask_with_default('Script', selected_lang.script) options['post_script'] = ask_with_default('Post-script', selected_lang.post_script) options['default'] = False if existed_templates else True existed_templates[selected_lang.alias] = options with open(self.kt_config, 'w') as kt_config: json.dump(existed_templates, kt_config, indent=2) log_green( f'Yosh, your configuration has been saved to {self.kt_config}')
def _compare_samples(self, samples: List[Sample]) -> None: rusage_denom = 1 << 20 actual = [] expected = [] diff = [] for sample in samples: is_ac = True actual.clear() expected.clear() diff.clear() try: with open(sample.output_file, 'r') as f: expected = [l.strip(" \n") for l in f.readlines()] with open(sample.input_file, 'rb') as f: raw_input = f.read() # log_cyan(f'running {self.script}') p = subprocess.Popen(shlex.split(f'{self.script} -'), stdin=subprocess.PIPE, stdout=subprocess.PIPE, shell=False, preexec_fn=os.setsid) register_subprocess(p) proc = psutil.Process(p.pid) mem_used = proc.memory_info().rss / rusage_denom start_time = time.perf_counter() raw_output = p.communicate(raw_input)[0].decode() p.wait() taken = time.perf_counter() - start_time actual = [z.strip(" \n") for z in raw_output.split('\n')] make_list_equal(actual, expected) for i in range(len(expected)): ''' Compare the values line by line For each line, compare the values from left to right. ''' ith_line_exp = [z for z in expected[i].split(' ')] ith_line_actual = [z for z in actual[i].split(' ')] make_list_equal(ith_line_exp, ith_line_actual) current_diff = '' for j in range(len(ith_line_exp)): lhs = ith_line_exp[j] rhs = ith_line_actual[j] is_good, now_diff = compare_entity(rhs, lhs) is_ac &= is_good current_diff += now_diff diff.append(current_diff) if is_ac: log( color_green( f'Test Case #{sample.index}: {"Accepted".ljust(13, " ")} ... {taken:.3f} s {mem_used:.2f} M' )) else: log( color_red( f'Test Case #{sample.index}: {"Wrong Answer".ljust(13, " ")} ... {taken:.3f} s {mem_used:.2f} M' )) log(color_cyan('--- Input ---')) log(raw_input.decode()) log(color_cyan('--- Diff ---')) for i in range(len(diff)): log(diff[i]) except subprocess.CalledProcessError as e: log( color_red( f'Test case #{sample.index}: Runtime Error {e!r}')) except Exception as e: import traceback tmp_file = get_temp_log_file() with open(tmp_file, 'w+') as f: f.write(traceback.format_exc()) log( color_red( f'Test case #{sample.index}: Internal Error {e!r}. More info at {tmp_file}' ))
def _act(self) -> None: log(f'Openning {self.get_problem_url()}') webbrowser.open(self.get_problem_url())
def _act(self) -> None: log(f'Problem is {self.problem_id}') problem_dir = self.cwd / self.problem_id problem_dir.mkdir(parents=True, exist_ok=True) self._gen_samples()