From 49dfcfc8a09448ee664cc3927dc1698d367710b9 Mon Sep 17 00:00:00 2001 From: Niko Strijbol Date: Fri, 12 Apr 2024 14:52:03 +0200 Subject: [PATCH] Fix formatting & type checks --- .github/workflows/ci.yml | 2 +- tested/descriptions/converters.py | 2 +- tested/dodona.py | 1 + tested/dsl/ast_translator.py | 4 ++-- tested/dsl/translate_parser.py | 2 +- tested/judge/execution.py | 12 +++++++----- tested/languages/config.py | 23 ++++++++--------------- tested/languages/csharp/config.py | 10 ++++++---- tested/languages/haskell/config.py | 8 ++++---- tested/languages/java/config.py | 4 ++-- tested/languages/javascript/config.py | 8 ++++---- tested/languages/kotlin/config.py | 16 +++++++++------- tested/languages/preparation.py | 1 + tested/languages/python/config.py | 6 +++--- tested/languages/runhaskell/config.py | 2 +- tested/parsing.py | 2 +- tests/test_serialisation.py | 5 ++++- 17 files changed, 56 insertions(+), 52 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cb13e041..cff163f4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -67,6 +67,6 @@ jobs: - run: echo "$(pipenv --venv)/bin" >> $GITHUB_PATH - uses: jakebailey/pyright-action@v1 with: - version: '1.1.316' + version: '1.1.354' warnings: true working-directory: tested/ diff --git a/tested/descriptions/converters.py b/tested/descriptions/converters.py index a3a64fa5..84005feb 100644 --- a/tested/descriptions/converters.py +++ b/tested/descriptions/converters.py @@ -152,7 +152,7 @@ def _construct_datatype( locale=bundle.config.natural_language, language=bundle.language, type_=enum_type, - others=others, + others=others, # type: ignore ) diff --git a/tested/dodona.py b/tested/dodona.py index 90e5f768..92047d1b 100644 --- a/tested/dodona.py +++ b/tested/dodona.py @@ -11,6 +11,7 @@ """ import json +import typing from enum import StrEnum, auto, unique from typing import IO, Literal, Union diff --git a/tested/dsl/ast_translator.py b/tested/dsl/ast_translator.py index 115b0196..910574b3 100644 --- a/tested/dsl/ast_translator.py +++ b/tested/dsl/ast_translator.py @@ -70,7 +70,7 @@ def _is_and_get_allowed_empty(node: ast.Call) -> Value | None: Returns the empty value if allowed, otherwise None. """ assert isinstance(node.func, ast.Name) - type_ = get_converter().structure(node.func.id, AllTypes) + type_ = get_converter().structure(node.func.id, AllTypes) # type: ignore if isinstance(type_, AdvancedSequenceTypes): return SequenceType(type=cast(AdvancedSequenceTypes, type_), data=[]) elif isinstance(type_, BasicSequenceTypes): @@ -223,7 +223,7 @@ def _convert_expression(node: ast.expr, is_return: bool) -> Expression: raise InvalidDslError( "The argument of a cast function must resolve to a value." ) - return evolve(value, type=get_converter().structure(node.func.id, AllTypes)) + return evolve(value, type=get_converter().structure(node.func.id, AllTypes)) # type: ignore elif isinstance(node, ast.Call): if is_return: raise InvalidDslError( diff --git a/tested/dsl/translate_parser.py b/tested/dsl/translate_parser.py index 2ee33e8d..435e7749 100644 --- a/tested/dsl/translate_parser.py +++ b/tested/dsl/translate_parser.py @@ -272,7 +272,7 @@ def _validate_dsl(dsl_object: YamlObject): def _tested_type_to_value(tested_type: TestedType) -> Value: - type_enum = get_converter().structure(tested_type.type, AllTypes) + type_enum = get_converter().structure(tested_type.type, AllTypes) # type: ignore if isinstance(type_enum, NumericTypes): # Some special cases for advanced numeric types. if type_enum == AdvancedNumericTypes.FIXED_PRECISION: diff --git a/tested/judge/execution.py b/tested/judge/execution.py index bf677cf1..46326e8a 100644 --- a/tested/judge/execution.py +++ b/tested/judge/execution.py @@ -232,11 +232,13 @@ def execute_unit( main_file_name = unit.name argument = None - executable, status = bundle.language.find_main_file(files, main_file_name) - _logger.debug(f"Found main file: {executable}") + executable_or_status = bundle.language.find_main_file(files, main_file_name) + _logger.debug(f"Found main file or not: {executable_or_status}") - if status != Status.CORRECT: - return None, status + if not isinstance(executable_or_status, Path): + return None, executable_or_status + + executable = executable_or_status files.remove(executable) stdin = unit.get_stdin(bundle.config.resources) @@ -269,4 +271,4 @@ def execute_unit( memory=base_result.memory, ) - return result, status + return result, Status.CORRECT diff --git a/tested/languages/config.py b/tested/languages/config.py index 288654d5..945c6961 100644 --- a/tested/languages/config.py +++ b/tested/languages/config.py @@ -159,7 +159,7 @@ def execution(self, cwd: Path, file: str, arguments: list[str]) -> Command: """ raise NotImplementedError - def get_string_quote(self): + def get_string_quote(self) -> str: """ :return: The symbol used to quote strings. """ @@ -348,37 +348,30 @@ def filter_function(file: Path) -> bool: return list(x for x in files if filter_function(x)) - @typing.overload def find_main_file( self, files: list[Path], name: str, - ) -> tuple[Path, typing.Literal[Status.CORRECT]]: ... - - @typing.overload - def find_main_file(self, files: list[Path], name: str) -> tuple[None, Status]: ... - - def find_main_file( - self, - files: list[Path], - name: str, - ) -> tuple[Path | None, Status]: + ) -> Path | Status: """ Find the "main" file in a list of files. This method is invoked to find the "main" file, i.e. the file with the main method (or at least the file that should be executed). + If the "status" is correct, the main file is returned. Otherwise, an error + status is returned instead. + :param files: A list of files. :param name: The name of the main file. - :return: The main file or a list of messages. + :return: The main file or the error status. """ _logger.debug("Finding %s in %s", name, files) possible_main_files = [x for x in files if x.name.startswith(name)] if possible_main_files: - return possible_main_files[0], Status.CORRECT + return possible_main_files[0] else: - return None, Status.COMPILATION_ERROR + return Status.COMPILATION_ERROR def cleanup_stacktrace(self, stacktrace: str) -> str: """ diff --git a/tested/languages/csharp/config.py b/tested/languages/csharp/config.py index 651d2ed0..3db20e4f 100644 --- a/tested/languages/csharp/config.py +++ b/tested/languages/csharp/config.py @@ -123,8 +123,10 @@ def execution(self, cwd: Path, file: str, arguments: list[str]) -> Command: return ["dotnet", file, *arguments] def find_main_file( - self, files: list[Path], name: str - ) -> tuple[Path | None, Status]: + self, + files: list[Path], + name: str, + ) -> Path | Status: # TODO: specify the extension (if any) of the output files, so we don't need to # override this. logger.debug("Finding %s in %s", name, files) @@ -132,9 +134,9 @@ def find_main_file( x for x in files if x.name.startswith(name) and x.suffix == ".dll" ] if possible_main_files: - return possible_main_files[0], Status.CORRECT + return possible_main_files[0] else: - return None, Status.COMPILATION_ERROR + return Status.COMPILATION_ERROR def modify_solution(self, solution: Path): with open(solution, "r") as file: diff --git a/tested/languages/haskell/config.py b/tested/languages/haskell/config.py index db674995..524264ac 100644 --- a/tested/languages/haskell/config.py +++ b/tested/languages/haskell/config.py @@ -109,10 +109,10 @@ def linter(self, remaining: float) -> tuple[list[Message], list[AnnotateCode]]: assert self.config return linter.run_hlint(self.config.dodona, remaining) - def cleanup_description(self, description: str) -> str: - return cleanup_description(self, description) + def cleanup_description(self, statement: str) -> str: + return cleanup_description(self, statement) - def cleanup_stacktrace(self, traceback_str: str) -> str: + def cleanup_stacktrace(self, stacktrace: str) -> str: filename = submission_file(self) context_file_regex = re.compile(r"(Context[0-9]+|Selector)") compile_line_regex = re.compile(r"^([0-9]+)(\s*\|.*)$") @@ -121,7 +121,7 @@ def cleanup_stacktrace(self, traceback_str: str) -> str: ) parse_module = r"error: parse error on input ‘module’" replace_module = r"error: unexpected ‘module’" - traceback = traceback_str.splitlines() + traceback = stacktrace.splitlines() skip_line, lines = False, [] for line in traceback: if not line or line == "undefined": diff --git a/tested/languages/java/config.py b/tested/languages/java/config.py index 2d67f641..7b870954 100644 --- a/tested/languages/java/config.py +++ b/tested/languages/java/config.py @@ -136,8 +136,8 @@ def linter(self, remaining: float) -> tuple[list[Message], list[AnnotateCode]]: assert self.config return linter.run_checkstyle(self.config.dodona, remaining) - def cleanup_stacktrace(self, traceback: str) -> str: - return jvm_cleanup_stacktrace(traceback, submission_file(self)) + def cleanup_stacktrace(self, stacktrace: str) -> str: + return jvm_cleanup_stacktrace(stacktrace, submission_file(self)) def generate_statement(self, statement: Statement) -> str: from tested.languages.java import generators diff --git a/tested/languages/javascript/config.py b/tested/languages/javascript/config.py index 624374d5..857c2404 100644 --- a/tested/languages/javascript/config.py +++ b/tested/languages/javascript/config.py @@ -153,7 +153,7 @@ def linter(self, remaining: float) -> tuple[list[Message], list[AnnotateCode]]: assert self.config return linter.run_eslint(self.config.dodona, remaining) - def cleanup_stacktrace(self, traceback: str) -> str: + def cleanup_stacktrace(self, stacktrace: str) -> str: assert self.config # What this does: # 1a. While inside the submission code, replace all references to the location with @@ -168,7 +168,7 @@ def cleanup_stacktrace(self, traceback: str) -> str: submission_namespace = f"{submission_name(self)}." resulting_lines = "" - for line in traceback.splitlines(keepends=True): + for line in stacktrace.splitlines(keepends=True): # If we encounter an execution location, we are done. if re.search(execution_location_regex, line): break @@ -183,8 +183,8 @@ def cleanup_stacktrace(self, traceback: str) -> str: return resulting_lines - def cleanup_description(self, description: str) -> str: - description = cleanup_description(self, description) + def cleanup_description(self, statement: str) -> str: + description = cleanup_description(self, statement) await_regex = re.compile(r"await\s+") return await_regex.sub("", description) diff --git a/tested/languages/kotlin/config.py b/tested/languages/kotlin/config.py index c3467605..fb2c3842 100644 --- a/tested/languages/kotlin/config.py +++ b/tested/languages/kotlin/config.py @@ -185,12 +185,14 @@ def linter(self, remaining: float) -> tuple[list[Message], list[AnnotateCode]]: return linter.run_ktlint(self.config.dodona, remaining) def find_main_file( - self, files: list[Path], name: str - ) -> tuple[Path | None, Status]: + self, + files: list[Path], + name: str, + ) -> Path | Status: logger.debug("Finding %s in %s", name, files) - main, status = Language.find_main_file(self, files, name + "Kt") - if status == Status.CORRECT: - return main, status + path_or_status = Language.find_main_file(self, files, name + "Kt") + if isinstance(path_or_status, Path): + return path_or_status else: return Language.find_main_file(self, files, name) @@ -207,8 +209,8 @@ def filter_function(file_path: Path) -> bool: return list(x for x in files if filter_function(x)) - def cleanup_stacktrace(self, traceback: str) -> str: - return jvm_cleanup_stacktrace(traceback, submission_file(self)) + def cleanup_stacktrace(self, stacktrace: str) -> str: + return jvm_cleanup_stacktrace(stacktrace, submission_file(self)) def generate_statement(self, statement: Statement) -> str: from tested.languages.kotlin import generators diff --git a/tested/languages/preparation.py b/tested/languages/preparation.py index 6d36e608..a6c5c982 100644 --- a/tested/languages/preparation.py +++ b/tested/languages/preparation.py @@ -300,6 +300,7 @@ def _create_handling_function( evaluator = output.oracle.for_language(bundle.config.programming_language) evaluator_name = conventionalize_namespace(lang_config, evaluator.file.stem) else: + evaluator = None evaluator_name = None def generator(expression: Expression) -> Statement: diff --git a/tested/languages/python/config.py b/tested/languages/python/config.py index 91138f0a..503aa6d4 100644 --- a/tested/languages/python/config.py +++ b/tested/languages/python/config.py @@ -158,14 +158,14 @@ def linter(self, remaining: float) -> tuple[list[Message], list[AnnotateCode]]: return linter.run_pylint(self.config.dodona, remaining) # Idea and original code: dodona/judge-pythia - def cleanup_stacktrace(self, stacktrace_str: str) -> str: + def cleanup_stacktrace(self, stacktrace: str) -> str: context_file_regex = re.compile(r"context_[0-9]+_[0-9]+\.py") file_line_regex = re.compile(rf"\({submission_file(self)}, line (\d+)\)") file_full_regex = re.compile(rf'File "./{submission_file(self)}", line (\d+)') - stacktrace = stacktrace_str.splitlines(True) + split_stacktrace = stacktrace.splitlines(True) skip_line, lines = False, [] - for line in stacktrace: + for line in split_stacktrace: line = line.strip("\n") logger.debug(line) diff --git a/tested/languages/runhaskell/config.py b/tested/languages/runhaskell/config.py index 10741ed7..b0cfebb5 100644 --- a/tested/languages/runhaskell/config.py +++ b/tested/languages/runhaskell/config.py @@ -17,7 +17,7 @@ def compilation(self, files: list[str]) -> CallbackResult: def execution(self, cwd: Path, file: str, arguments: list[str]) -> Command: return ["runhaskell", file, *arguments] - def filter_dependencies(self, files: list[str], context_name: str) -> list[str]: + def filter_dependencies(self, files: list[Path], context_name: str) -> list[Path]: return files def path_to_dependencies(self) -> list[Path]: diff --git a/tested/parsing.py b/tested/parsing.py index c2a26759..fdc193f5 100644 --- a/tested/parsing.py +++ b/tested/parsing.py @@ -95,7 +95,7 @@ def parse_json_value(value: str) -> "Value": initialise_converter() from tested.serialisation import Value - return _suite_converter.loads(value, Value) + return _suite_converter.loads(value, Value) # type: ignore def parse_json_suite(value: str) -> "Suite": diff --git a/tests/test_serialisation.py b/tests/test_serialisation.py index 9dde21c0..e77cc905 100644 --- a/tests/test_serialisation.py +++ b/tests/test_serialisation.py @@ -190,7 +190,10 @@ def run_encoder(bundle: Bundle, values: list[Value]) -> list[str]: files = filter_files(files, dest) files = bundle.language.filter_dependencies(files, name) - executable, _ = bundle.language.find_main_file(files, name) + executable = bundle.language.find_main_file(files, name) + assert isinstance( + executable, Path + ), f"Could not find main file? Files: {files}, needle: {name}" # Run the code. r = execute_file(bundle, executable.name, dest, None)