Skip to content

Commit

Permalink
Fixed the issue with test case decoder function not getting invoked w…
Browse files Browse the repository at this point in the history
…hen dumping to string
  • Loading branch information
MartinXPN authored Dec 12, 2024
1 parent 5dcfc61 commit a5c3b35
Show file tree
Hide file tree
Showing 6 changed files with 34 additions and 17 deletions.
16 changes: 9 additions & 7 deletions coderunners/checkers.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,11 @@ def check(
...

@staticmethod
def from_mode(mode: str,
float_precision: float | None = None, delimiter: str | None = None,
executor: Executor | None = None) -> 'Checker':
def from_mode(
mode: str,
float_precision: float | None = None, delimiter: str | None = None,
executor: Executor | None = None,
) -> 'Checker':
if mode == 'ok':
return OkChecker()
if mode == 'whole':
Expand All @@ -59,10 +61,10 @@ def from_mode(mode: str,

class OkChecker(Checker):
def check(
self, inputs: str, output: str, target: str, code: dict[str, str],
input_files: dict[str, str] | None = None, output_files: dict[str, str] | None = None,
target_files: dict[str, str] | None = None, input_assets: dict[str, bytes] | None = None,
output_assets: dict[str, bytes] | None = None, target_assets: dict[str, bytes] | None = None,
self, inputs: str, output: str, target: str, code: dict[str, str],
input_files: dict[str, str] | None = None, output_files: dict[str, str] | None = None,
target_files: dict[str, str] | None = None, input_assets: dict[str, bytes] | None = None,
output_assets: dict[str, bytes] | None = None, target_assets: dict[str, bytes] | None = None,
) -> tuple[Status, float, str | None]:
return Status.OK, 100, None

Expand Down
4 changes: 2 additions & 2 deletions coderunners/executors.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,12 @@ def run(self, test: TestCase, time_limit: float, memory_limit_mb: int, output_li
# Crete input files and input assets
for filename, content in (test.input_files or {}).items():
file = self.ROOT / filename
print('Creating file at:', file)
print(f'Creating file at: {file} with content len: {len(content)} of type {type(content)}')
file.parent.mkdir(parents=True, exist_ok=True)
file.write_text(content)
for filename, content in (test.input_assets or {}).items():
file = self.ROOT / filename
print('Creating asset at:', file)
print(f'Creating asset at: {file} with content len: {len(content)} of type {type(content)}')
file.parent.mkdir(parents=True, exist_ok=True)
file.write_bytes(content)

Expand Down
10 changes: 7 additions & 3 deletions models.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,17 @@ class DataClassJsonCamelMixIn(DataClassJsonMixin):
dataclass_json_config = config(letter_case=LetterCase.CAMEL, undefined=Undefined.EXCLUDE)['dataclasses_json']


def base64_to_bytes(data: dict[str, str | bytes] | None) -> dict[str, bytes] | None:
def base64_to_bytes(data: dict[str, str] | None) -> dict[str, bytes] | None:
if data is not None:
print('base64_to_bytes:', {filename: type(content) for filename, content in (data or {}).items()})
if data is not None and all(isinstance(content, str) for content in data.values()):
return {filename: base64.b64decode(content.encode('utf-8')) for filename, content in data.items()}
return data


def bytes_to_base64(data: dict[str, bytes] | None) -> dict[str, str] | None:
if data is not None:
print('bytes_to_base64:', {filename: type(content) for filename, content in (data or {}).items()})
if data is not None and all(isinstance(content, bytes) for content in data.values()):
return {filename: base64.b64encode(content).decode('utf-8') for filename, content in data.items()}
return data
Expand Down Expand Up @@ -115,8 +119,8 @@ class RunResult(DataClassJsonCamelMixIn):
message: str | None = None
outputs: str | None = None
errors: str | None = None
output_files: dict[str, str] | None = None
output_assets: dict[str, bytes] | None = field(
output_files: dict[str, str] | None = None # mapping filename -> textual content
output_assets: dict[str, bytes] | None = field( # mapping filename -> binary content
metadata=config(encoder=bytes_to_base64, decoder=base64_to_bytes),
default=None,
)
Expand Down
5 changes: 5 additions & 0 deletions sync/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ def trigger_sync_s3_handler(event, context):
res = json.loads(res)
print('invocation result:', res)

if 'tests_truncated' not in res:
error = res.get('errorMessage', 'Could not process tests...')
print('There was an error and we could not get the tests', error)
return SummaryTable(dynamodb).log_error(problem, error)

tests = TestCase.schema().load(res['tests_truncated'], many=True)
print('tests:', tests)
SummaryTable(dynamodb).write(problem, tests)
Expand Down
5 changes: 4 additions & 1 deletion sync/services.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import gzip
import json
import sys
from glob import glob
from pathlib import Path
Expand Down Expand Up @@ -73,7 +74,9 @@ def encrypt_tests(tests: list[TestCase], encryption_key: str) -> bytes:

# Compress: (1) json.dumps (2) .encode('utf-8') (3) gzip.compress() (4) encrypt
# Decompress: (1) decrypt (2) gzip.decompress() (3) .decode('utf-8') (4) json.loads()
tests = TestCase.schema().dumps(tests, many=True) # (1)
# TestCase.schema().dumps(tests, many=True) does not invoke the decoder function properly
# https://github.com/lidatong/dataclasses-json/issues/551 => We'll use json.dumps([t.to_dict()...]) instead
tests = json.dumps([test.to_dict() for test in tests]) # (1)
print('initial sys.getsizeof of tests:', sys.getsizeof(tests))
big = sys.getsizeof(tests) > 50 * 1024 * 1024
tests = tests.encode('utf-8') # (2)
Expand Down
11 changes: 7 additions & 4 deletions sync/summary.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,20 @@ class SummaryTable:
def __init__(self, dynamodb):
self.table = dynamodb.Table(self.TABLE_NAME)

def log_error(self, problem_id: str, message: str) -> None:
self.table.put_item(Item={
'id': problem_id,
'message': message,
})

def write(self, problem_id: str, tests: list[TestCase]) -> None:
response = self.table.put_item(Item={
'id': problem_id,
'count': len(tests),
'tests': [t.to_dict() for t in tests],
})
if response['ResponseMetadata']['HTTPStatusCode'] not in range(200, 300):
self.table.put_item(Item={
'id': problem_id,
'message': 'Could not summarize the tests',
})
self.log_error(problem_id, 'Could not summarize the tests')
raise SummaryWriteError('Could not summarize the tests', response)


Expand Down

0 comments on commit a5c3b35

Please sign in to comment.