Skip to content

Commit 0121c59

Browse files
committed
Added time limit for io
1 parent 6db76b1 commit 0121c59

24 files changed

+560
-852
lines changed

cyaron/compare.py

Lines changed: 29 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ def __init__(self, name, mismatch):
1717
self.mismatch = mismatch
1818

1919
def __str__(self):
20-
return "In program: '{}'. {}".format(self.name, self.mismatch)
20+
return 'In program: \'{}\'. {}'.format(self.name,self.mismatch)
2121

2222

2323
class Compare:
@@ -37,7 +37,7 @@ def __process_file(file):
3737
file.output_file.seek(0)
3838
return file.output_filename, file.output_file.read()
3939
else:
40-
with open(file, "r", newline="\n") as f:
40+
with open(file, "r", newline='\n') as f:
4141
return file, f.read()
4242

4343
@staticmethod
@@ -50,43 +50,26 @@ def __normal_max_workers(workers):
5050

5151
@classmethod
5252
def output(cls, *files, **kwargs):
53-
kwargs = unpack_kwargs(
54-
"output",
55-
kwargs,
56-
(
57-
"std",
58-
("grader", DEFAULT_GRADER),
59-
("max_workers", -1),
60-
("job_pool", None),
61-
("stop_on_incorrect", None),
62-
),
63-
)
64-
std = kwargs["std"]
65-
grader = kwargs["grader"]
66-
max_workers = kwargs["max_workers"]
67-
job_pool = kwargs["job_pool"]
68-
if kwargs["stop_on_incorrect"] is not None:
53+
kwargs = unpack_kwargs('output', kwargs, ('std', ('grader', DEFAULT_GRADER), ('max_workers', -1),
54+
('job_pool', None), ('stop_on_incorrect', None)))
55+
std = kwargs['std']
56+
grader = kwargs['grader']
57+
max_workers = kwargs['max_workers']
58+
job_pool = kwargs['job_pool']
59+
if kwargs['stop_on_incorrect'] is not None:
6960
log.warn("parameter stop_on_incorrect is deprecated and has no effect.")
7061

7162
if (max_workers is None or max_workers >= 0) and job_pool is None:
7263
max_workers = cls.__normal_max_workers(max_workers)
7364
try:
7465
from concurrent.futures import ThreadPoolExecutor
75-
7666
with ThreadPoolExecutor(max_workers=max_workers) as job_pool:
77-
return cls.output(
78-
*files,
79-
std=std,
80-
grader=grader,
81-
max_workers=max_workers,
82-
job_pool=job_pool
83-
)
67+
return cls.output(*files, std=std, grader=grader, max_workers=max_workers, job_pool=job_pool)
8468
except ImportError:
8569
pass
8670

8771
def get_std():
8872
return cls.__process_file(std)[1]
89-
9073
if job_pool is not None:
9174
std = job_pool.submit(get_std).result()
9275
else:
@@ -103,121 +86,61 @@ def do(file):
10386

10487
@classmethod
10588
def program(cls, *programs, **kwargs):
106-
kwargs = unpack_kwargs(
107-
"program",
108-
kwargs,
109-
(
110-
"input",
111-
("std", None),
112-
("std_program", None),
113-
("grader", DEFAULT_GRADER),
114-
("max_workers", -1),
115-
("job_pool", None),
116-
("stop_on_incorrect", None),
117-
),
118-
)
119-
input = kwargs["input"]
120-
std = kwargs["std"]
121-
std_program = kwargs["std_program"]
122-
grader = kwargs["grader"]
123-
max_workers = kwargs["max_workers"]
124-
job_pool = kwargs["job_pool"]
125-
time_limit = kwargs["time_limit"]
126-
memory_limit = kwargs["memory_limit"]
127-
128-
if kwargs["stop_on_incorrect"] is not None:
89+
kwargs = unpack_kwargs('program', kwargs, ('input', ('std', None), ('std_program', None),
90+
('grader', DEFAULT_GRADER), ('max_workers', -1),
91+
('job_pool', None), ('stop_on_incorrect', None)))
92+
input = kwargs['input']
93+
std = kwargs['std']
94+
std_program = kwargs['std_program']
95+
grader = kwargs['grader']
96+
max_workers = kwargs['max_workers']
97+
job_pool = kwargs['job_pool']
98+
if kwargs['stop_on_incorrect'] is not None:
12999
log.warn("parameter stop_on_incorrect is deprecated and has no effect.")
130100

131101
if (max_workers is None or max_workers >= 0) and job_pool is None:
132102
max_workers = cls.__normal_max_workers(max_workers)
133103
try:
134104
from concurrent.futures import ThreadPoolExecutor
135-
136105
with ThreadPoolExecutor(max_workers=max_workers) as job_pool:
137-
return cls.program(
138-
*programs,
139-
input=input,
140-
std=std,
141-
std_program=std_program,
142-
grader=grader,
143-
max_workers=max_workers,
144-
job_pool=job_pool
145-
)
106+
return cls.program(*programs, input=input, std=std, std_program=std_program, grader=grader, max_workers=max_workers, job_pool=job_pool)
146107
except ImportError:
147108
pass
148109

149110
if not isinstance(input, IO):
150-
raise TypeError(
151-
"expect {}, got {}".format(type(IO).__name__, type(input).__name__)
152-
)
111+
raise TypeError("expect {}, got {}".format(type(IO).__name__, type(input).__name__))
153112
input.flush_buffer()
154113
input.input_file.seek(0)
155114

156115
if std_program is not None:
157-
158116
def get_std():
159-
with open(
160-
os.dup(input.input_file.fileno()), "r", newline="\n"
161-
) as input_file:
162-
content = make_unicode(
163-
subprocess.check_output(
164-
std_program,
165-
shell=(not list_like(std_program)),
166-
stdin=input.input_file,
167-
universal_newlines=True,
168-
)
169-
)
117+
with open(os.dup(input.input_file.fileno()), 'r', newline='\n') as input_file:
118+
content = make_unicode(subprocess.check_output(std_program, shell=(not list_like(std_program)), stdin=input.input_file, universal_newlines=True))
170119
input_file.seek(0)
171120
return content
172-
173121
if job_pool is not None:
174122
std = job_pool.submit(get_std).result()
175123
else:
176124
std = get_std()
177125
elif std is not None:
178-
179126
def get_std():
180127
return cls.__process_file(std)[1]
181-
182128
if job_pool is not None:
183129
std = job_pool.submit(get_std).result()
184130
else:
185131
std = get_std()
186132
else:
187-
raise TypeError(
188-
"program() missing 1 required non-None keyword-only argument: 'std' or 'std_program'"
189-
)
133+
raise TypeError('program() missing 1 required non-None keyword-only argument: \'std\' or \'std_program\'')
190134

191135
def do(program_name):
192136
timeout = None
193-
if (
194-
list_like(program_name)
195-
and len(program_name) == 2
196-
and int_like(program_name[-1])
197-
):
137+
if list_like(program_name) and len(program_name) == 2 and int_like(program_name[-1]):
198138
program_name, timeout = program_name
199-
with open(
200-
os.dup(input.input_file.fileno()), "r", newline="\n"
201-
) as input_file:
139+
with open(os.dup(input.input_file.fileno()), 'r', newline='\n') as input_file:
202140
if timeout is None:
203-
content = make_unicode(
204-
subprocess.check_output(
205-
program_name,
206-
shell=(not list_like(program_name)),
207-
stdin=input_file,
208-
universal_newlines=True,
209-
)
210-
)
141+
content = make_unicode(subprocess.check_output(program_name, shell=(not list_like(program_name)), stdin=input_file, universal_newlines=True))
211142
else:
212-
content = make_unicode(
213-
subprocess.check_output(
214-
program_name,
215-
shell=(not list_like(program_name)),
216-
stdin=input_file,
217-
universal_newlines=True,
218-
timeout=timeout,
219-
)
220-
)
143+
content = make_unicode(subprocess.check_output(program_name, shell=(not list_like(program_name)), stdin=input_file, universal_newlines=True, timeout=timeout))
221144
input_file.seek(0)
222145
cls.__compare_two(program_name, content, std, grader)
223146

cyaron/consts.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
ALPHABET_CAPITAL = string.ascii_uppercase
1919
ALPHABET = ALPHABET_SMALL + ALPHABET_CAPITAL
2020
NUMBERS = string.digits
21-
SENTENCE_SEPARATORS = ",,,,,,,;;:" # 70% ',' 20% ';' 10% ':'
22-
SENTENCE_TERMINATORS = "....!" # 80% '.' 20% '!'
21+
SENTENCE_SEPARATORS = ',,,,,,,;;:' # 70% ',' 20% ';' 10% ':'
22+
SENTENCE_TERMINATORS = '....!' # 80% '.' 20% '!'
2323

2424
DEFAULT_GRADER = "NOIPStyle"

cyaron/graders/fulltext.py

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,9 @@
22
from .graderregistry import CYaRonGraders
33
from .mismatch import HashMismatch
44

5-
65
@CYaRonGraders.grader("FullText")
76
def fulltext(content, std):
8-
content_hash = hashlib.sha256(content.encode("utf-8")).hexdigest()
9-
std_hash = hashlib.sha256(std.encode("utf-8")).hexdigest()
10-
return (
11-
(True, None)
12-
if content_hash == std_hash
13-
else (False, HashMismatch(content, std, content_hash, std_hash))
14-
)
7+
content_hash = hashlib.sha256(content.encode('utf-8')).hexdigest()
8+
std_hash = hashlib.sha256(std.encode('utf-8')).hexdigest()
9+
return (True, None) if content_hash == std_hash else (False, HashMismatch(content, std, content_hash, std_hash))
10+

cyaron/graders/graderregistry.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,4 @@ def check(self, name):
1515
return name in self._registry
1616

1717

18-
CYaRonGraders = GraderRegistry()
18+
CYaRonGraders = GraderRegistry()

cyaron/graders/mismatch.py

Lines changed: 3 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
class Mismatch(ValueError):
22
"""exception for content mismatch"""
3-
43
def __init__(self, content, std, *args):
54
"""
65
content -> content got
@@ -10,10 +9,8 @@ def __init__(self, content, std, *args):
109
self.content = content
1110
self.std = std
1211

13-
1412
class HashMismatch(Mismatch):
1513
"""exception for hash mismatch"""
16-
1714
def __init__(self, content, std, content_hash, std_hash):
1815
"""
1916
content -> content got
@@ -26,25 +23,11 @@ def __init__(self, content, std, content_hash, std_hash):
2623
self.std_hash = std_hash
2724

2825
def __str__(self):
29-
return "Hash mismatch: read %s, expected %s" % (
30-
self.content_hash,
31-
self.std_hash,
32-
)
33-
26+
return "Hash mismatch: read %s, expected %s" % (self.content_hash, self.std_hash)
3427

3528
class TextMismatch(Mismatch):
3629
"""exception for text mismatch"""
37-
38-
def __init__(
39-
self,
40-
content,
41-
std,
42-
err_msg,
43-
lineno=None,
44-
colno=None,
45-
content_token=None,
46-
std_token=None,
47-
):
30+
def __init__(self, content, std, err_msg, lineno=None, colno=None, content_token=None, std_token=None):
4831
"""
4932
content -> content got
5033
std -> content expected
@@ -54,9 +37,7 @@ def __init__(
5437
content_token -> the token of content mismatch
5538
std_token -> the token of std
5639
"""
57-
super(TextMismatch, self).__init__(
58-
content, std, err_msg, lineno, colno, content_token, std_token
59-
)
40+
super(TextMismatch, self).__init__(content, std, err_msg, lineno, colno, content_token, std_token)
6041
self.err_msg = err_msg.format(lineno, colno, content_token, std_token)
6142
self.lineno = lineno
6243
self.colno = colno

cyaron/graders/noipstyle.py

Lines changed: 13 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -5,46 +5,28 @@
55

66
@CYaRonGraders.grader("NOIPStyle")
77
def noipstyle(content, std):
8-
content_lines = strtolines(content.replace("\r\n", "\n"))
9-
std_lines = strtolines(std.replace("\r\n", "\n"))
8+
content_lines = strtolines(content.replace('\r\n', '\n'))
9+
std_lines = strtolines(std.replace('\r\n', '\n'))
1010
if len(content_lines) != len(std_lines):
11-
return False, TextMismatch(content, std, "Too many or too few lines.")
11+
return False, TextMismatch(content, std, 'Too many or too few lines.')
1212

1313
for i in range(len(content_lines)):
1414
if std_lines[i] != content_lines[i]:
1515
for j in range(min(len(std_lines[i]), len(content_lines[i]))):
1616
if std_lines[i][j] != content_lines[i][j]:
17-
return (
18-
False,
19-
TextMismatch(
20-
content,
21-
std,
22-
"On line {} column {}, read {}, expected {}.",
23-
i + 1,
24-
j + 1,
25-
content_lines[i][j : j + 5],
26-
std_lines[i][j : j + 5],
27-
),
28-
)
17+
return (False,
18+
TextMismatch(
19+
content, std,
20+
'On line {} column {}, read {}, expected {}.',
21+
i + 1, j + 1, content_lines[i][j:j + 5],
22+
std_lines[i][j:j + 5]))
2923
if len(std_lines[i]) > len(content_lines[i]):
3024
return False, TextMismatch(
31-
content,
32-
std,
33-
"Too short on line {}.",
34-
i + 1,
35-
j + 1,
36-
content_lines[i][j : j + 5],
37-
std_lines[i][j : j + 5],
38-
)
25+
content, std, 'Too short on line {}.', i + 1, j + 1,
26+
content_lines[i][j:j + 5], std_lines[i][j:j + 5])
3927
if len(std_lines[i]) < len(content_lines[i]):
4028
return False, TextMismatch(
41-
content,
42-
std,
43-
"Too long on line {}.",
44-
i + 1,
45-
j + 1,
46-
content_lines[i][j : j + 5],
47-
std_lines[i][j : j + 5],
48-
)
29+
content, std, 'Too long on line {}.', i + 1, j + 1,
30+
content_lines[i][j:j + 5], std_lines[i][j:j + 5])
4931

5032
return True, None

0 commit comments

Comments
 (0)