|
#!/usr/bin/env python3 |
|
|
|
import requests |
|
import re |
|
import json |
|
import html |
|
import sys |
|
|
|
class EMKCWrapper: |
|
BASE_URL="https://emkc.org" |
|
@staticmethod |
|
def get_contest_by_id(id): |
|
contests_html = requests.get(f'{EMKCWrapper.BASE_URL}/contests').text |
|
select_regex = re.compile(f'"/contests/{id}/(.*?)"') |
|
slug = select_regex.search(contests_html).group(1) |
|
|
|
contest_url = f'{EMKCWrapper.BASE_URL}/contests/{id}/{slug}' |
|
contest_html = requests.get(contest_url).text |
|
contest_regex = re.compile(r'data-contest="(.*?)"') |
|
|
|
contest_data_raw = contest_regex.search(contest_html).group(1) |
|
contest_data = html.unescape(contest_data_raw) |
|
|
|
json_data = json.loads(contest_data) |
|
return EMKCWrapper.Contest(json_data) |
|
|
|
class Contest: |
|
def __init__(self, data): |
|
self.data = data |
|
|
|
def get_test_cases(self): |
|
data = self.data |
|
inputs = data['input'].split('\n') |
|
outputs = data['output'].split('\n') |
|
|
|
cases = [] |
|
|
|
for i,output in enumerate(outputs): |
|
inp = inputs[i] |
|
cases.append(EMKCWrapper.Contest.TestCase(inp.split('|'), output)) |
|
return cases |
|
|
|
def get_disallowed_languages(self): |
|
return self.data['disallowed_languages'].split(',') |
|
|
|
class TestCase: |
|
def __init__(self, args, output): |
|
self.args = args |
|
self.output = output.strip() |
|
|
|
def __repr__(self): |
|
return f"TestCase(args={repr(self.args)}, output=\"{self.output}\")" |
|
|
|
def evaluate(self, program, language): |
|
result = PistonWrapper.execute(language, |
|
program, |
|
'\n'.join(self.args), |
|
self.args) |
|
passed = result['stdout'].strip() == self.output |
|
return (passed, result) |
|
|
|
class PistonWrapper: |
|
BASE_URL="https://emkc.org/api/v1/piston" |
|
|
|
@staticmethod |
|
def get_languages(): |
|
api_response = requests.get(f"{PistonWrapper.BASE_URL}/versions").json() |
|
return api_response |
|
|
|
@staticmethod |
|
def execute(language, source, stdin="", args=[]): |
|
body = { |
|
'language': language, |
|
'source': source, |
|
'stdin': stdin, |
|
'args': args |
|
} |
|
request = requests.post(f"{PistonWrapper.BASE_URL}/execute", json=body) |
|
return request.json() |
|
|
|
|
|
def bench(contest_id, source, language_or_filename): |
|
contest = EMKCWrapper.get_contest_by_id(contest_id) |
|
test_cases = contest.get_test_cases() |
|
|
|
print(f"Contest: {contest.data['name']} ({contest_id})") |
|
print(f"Active? {contest.data['active']}") |
|
print() |
|
print(f"Code Length: {len(source)}") |
|
|
|
language = None |
|
alias = language_or_filename.split(".")[-1].lower() |
|
|
|
for lang in PistonWrapper.get_languages(): |
|
name = lang['name'] |
|
aliases = lang['aliases'] |
|
|
|
if name == alias or alias in aliases: |
|
language = name |
|
|
|
if language is None: |
|
print(f"Code Language: Unknown ({alias})") |
|
exit(1) |
|
|
|
print(f"Code Language: {language} ({alias})") |
|
print() |
|
|
|
program = source |
|
if type(program) == bytes: |
|
program = source.decode() |
|
|
|
for test_case in test_cases: |
|
sys.stdout.write(f"[WAIT] {test_case}") |
|
passed, trace = test_case.evaluate(program, language) |
|
|
|
if passed: |
|
print(f"\r[GOOD] {test_case}") |
|
else: |
|
print(f"\r[FAIL] {test_case}") |
|
print("Got:") |
|
print('\t' + trace['stdout'].replace('\n', '\t')) |
|
|
|
|
|
|
|
|
|
def main(): |
|
import argparse |
|
parser = argparse.ArgumentParser() |
|
parser.add_argument('contest_id') |
|
parser.add_argument('source_file') |
|
args = parser.parse_args() |
|
with open(args.source_file, "rb") as f: |
|
bench(args.contest_id, f.read(), args.source_file) |
|
|
|
|
|
if __name__ == '__main__': |
|
main() |
|
|
|
|