From f62c91f01fe0fccfd820552d84b7cfb23adf24ed Mon Sep 17 00:00:00 2001 From: diatlova Date: Tue, 13 Apr 2021 12:39:13 +0300 Subject: [PATCH 01/78] updating requirements --- requirements.txt | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index 60409ee1..7af2b55a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -setuptools==47.3.1 +setuptools~=47.3.2 # python code analysis tools pylint==2.5.3 @@ -26,4 +26,9 @@ radon==4.5.0 # extra libraries and frameworks django==3.0.8 -requests==2.24.0 \ No newline at end of file +requests==2.24.0 +argparse~=1.4.0 +pandas~=1.2.3 +pytest~=5.4.3 +openpyxl~=3.0.7 +jsonschema~=3.2.0 \ No newline at end of file From daee49b3365a49d7f5c28977be5c9504a28d0810 Mon Sep 17 00:00:00 2001 From: diatlova Date: Tue, 13 Apr 2021 12:41:48 +0300 Subject: [PATCH 02/78] adding script to run tool on xlsx file --- src/python/evaluation/__init__.py | 8 ++ src/python/evaluation/xlsx_run_tool.py | 129 +++++++++++++++++++++++++ 2 files changed, 137 insertions(+) create mode 100644 src/python/evaluation/__init__.py create mode 100644 src/python/evaluation/xlsx_run_tool.py diff --git a/src/python/evaluation/__init__.py b/src/python/evaluation/__init__.py new file mode 100644 index 00000000..a68f28dd --- /dev/null +++ b/src/python/evaluation/__init__.py @@ -0,0 +1,8 @@ +ScriptStructureRule = ("Please, make sure your XLSX-file matches following script standards: \n" + "1. Your XLSX-file should have 2 obligatory columns named: \"lang\" & \"code\". \n" + "\"code\" column -- relates to the code-sample. \n" + "\"lang\" column -- relates to the language of a particular code-sample. \n" + "2. Your code samples should belong to the one of the supported languages. \n" + "Supported languages are: Java, Kotlin, Python. \n" + "3. Check that \"lang\" column cells are filled with acceptable language-names: \n" + "Acceptable language-names are: \"python3\", \"java8\", \"java11\" and \"kotlin\".") diff --git a/src/python/evaluation/xlsx_run_tool.py b/src/python/evaluation/xlsx_run_tool.py new file mode 100644 index 00000000..a180e73b --- /dev/null +++ b/src/python/evaluation/xlsx_run_tool.py @@ -0,0 +1,129 @@ +import argparse +import logging.config +import os +import pandas as pd +import re +import sys +import tempfile +import traceback + +from pathlib import Path +from typing import NoReturn + +sys.path.append('') +sys.path.append('../../..') + +from src.python import MAIN_FOLDER +from src.python.evaluation import ScriptStructureRule +from src.python.review.common.subprocess_runner import run_in_subprocess +from src.python.review.run_tool import positive_int +from src.python.review.reviewers.perform_review import OutputFormat + +logger = logging.getLogger(__name__) + + +def configure_arguments(parser: argparse.ArgumentParser) -> NoReturn: + parser.add_argument('-t', '--tool_path', + default=Path('src/python/review/run_tool.py').absolute(), + type=lambda value: Path(value).absolute(), + help='Path to script to run on files.') + + parser.add_argument('data_path', + type=lambda value: Path(value).absolute(), + help="Local XLSX-file path. " + "Your XLSX-file must include column-names: \"code\" and \"lang. " + "Acceptable values for \"lang\" column are: python3, java8, java11, kotlin.") + + parser.add_argument('--n_cpu', '--n-cpu', + help='Specify number of cpu that can be used to run inspectors.', + default=1, + type=positive_int) + + parser.add_argument('--traceback', '--traceback', + help='If True – grades are substituted with the full inspector feedback.', + default=False, + type=bool) + + parser.add_argument('-f', '--format', + default=OutputFormat.JSON.value, + choices=OutputFormat.values(), + type=str, + help='The output format of inspectors traceback. ' + 'Default is JSON.' + 'More details on output format options in README.md') + + +def main() -> int: + report = pd.DataFrame( + { + "language": [], + "code": [], + "grade": [], + }, + ) + + lang_suffixes = {'python3': '.py', 'java8': '.java', 'java11': '.java', 'kotlin': '.kt'} + + parser = argparse.ArgumentParser() + configure_arguments(parser) + + try: + args = parser.parse_args() + dataframe = pd.read_excel(args.data_path) + + for lang, code in zip(dataframe['lang'], dataframe['code']): + file = tempfile.NamedTemporaryFile( + dir=(MAIN_FOLDER.parent / 'evaluation/temporary_files'), + suffix=lang_suffixes[lang], + delete=False, mode="w", + ) + + file = open(file.name, "w") + file.writelines(code) + file.close() + + if lang == 'java8' or lang == 'java11': + results = run_in_subprocess([ + 'python3', args.tool_path, file.name, '--language_version', lang]) + + else: + results = run_in_subprocess(['python3', args.tool_path, file.name]) + + os.unlink(file.name) + + # this regular expression matches final tool grade: EXCELLENT, GOOD, MODERATE or BAD + regex_match = re.match(r'^.*{"code":\s"([A-Z]+)"', results).group(1) + + if args.traceback: + output = results + else: + output = regex_match + + report = report.append(pd.DataFrame( + { + "language": [lang], + "code": [code], + "grade": [output], + }, + )) + + with pd.ExcelWriter(args.data_path, engine='openpyxl', mode='a') as writer: + report.to_excel(writer, sheet_name='Inspection results', index=False) + return 0 + + except FileNotFoundError: + logger.error('XLSX-file with the specified name does not exists.') + return 2 + + except KeyError: + logger.error(ScriptStructureRule) + return 2 + + except Exception: + traceback.print_exc() + logger.exception('An unexpected error.') + return 2 + + +if __name__ == '__main__': + sys.exit(main()) From 52d971ceb5cf65611ff09efcd44ecc42c20cceae Mon Sep 17 00:00:00 2001 From: diatlova Date: Tue, 13 Apr 2021 12:42:42 +0300 Subject: [PATCH 03/78] adding testing files --- .../resources/evaluation/xlsx_files/__init__.py | 0 .../xlsx_files/test_empty_lang_cell.xlsx | Bin 0 -> 5162 bytes .../evaluation/xlsx_files/test_empty_table.xlsx | Bin 0 -> 4589 bytes .../xlsx_files/test_java_no_version.xlsx | Bin 0 -> 5156 bytes .../xlsx_files/test_sorted_order.xlsx | Bin 0 -> 6420 bytes .../xlsx_files/test_unsorted_order.xlsx | Bin 0 -> 6264 bytes .../xlsx_files/test_wrong_column_name.xlsx | Bin 0 -> 5175 bytes .../evaluation/xlsx_target_files/__init__.py | 0 .../xlsx_target_files/target_sorted_order.xlsx | Bin 0 -> 31483 bytes .../target_unsorted_order.xlsx | Bin 0 -> 30873 bytes 10 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 test/resources/evaluation/xlsx_files/__init__.py create mode 100644 test/resources/evaluation/xlsx_files/test_empty_lang_cell.xlsx create mode 100644 test/resources/evaluation/xlsx_files/test_empty_table.xlsx create mode 100644 test/resources/evaluation/xlsx_files/test_java_no_version.xlsx create mode 100644 test/resources/evaluation/xlsx_files/test_sorted_order.xlsx create mode 100644 test/resources/evaluation/xlsx_files/test_unsorted_order.xlsx create mode 100644 test/resources/evaluation/xlsx_files/test_wrong_column_name.xlsx create mode 100644 test/resources/evaluation/xlsx_target_files/__init__.py create mode 100644 test/resources/evaluation/xlsx_target_files/target_sorted_order.xlsx create mode 100644 test/resources/evaluation/xlsx_target_files/target_unsorted_order.xlsx diff --git a/test/resources/evaluation/xlsx_files/__init__.py b/test/resources/evaluation/xlsx_files/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/test/resources/evaluation/xlsx_files/test_empty_lang_cell.xlsx b/test/resources/evaluation/xlsx_files/test_empty_lang_cell.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..91cdada068a9aa8ebe487d14c970a6f7415b1b8c GIT binary patch literal 5162 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 literal 0 HcmV?d00001 diff --git a/test/resources/evaluation/xlsx_files/test_empty_table.xlsx b/test/resources/evaluation/xlsx_files/test_empty_table.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..486b83a16a6b512ee860cc18323274db8588882b GIT binary patch literal 4589 zcmai12RzjO|L5#=cbvUtlblWV2$4-jM)ui4cJ^NBj8GCXGvY+{%FakdC}f2r*^%+T z)9?37{=aX(*R9Vz9`||P`~7^qU(eU`rLB&IO^$(&kB?DInxKnuE~ru0zRvtM9+o~1 zuJ)e)z7V+L>*Aa}V&>WbCC2*>SpynOJD5;I6v@p;G@-y*c2~Lw_xpkQpMu`1i8=&e zGP(@N9&8M{de#0=vVsJ%u2z%b_*2wuny~^m+z@G8;$h>r!+VrXle=7h*3gKQ4>uKE zS`RQUswTac&}pJ}Q~K(xAo23M8j=O(Lip7Zf}!i)H;10DUfYtx&kA_`Du-ikwH+%9 zYkvDgV?3f(gm7OzoBmLoC4$oG5NF?RwyXrNLPuKr2(vplOehWzEt<~r3dud8s&Fht zAbvu-`?*)QrT>FP?`QHJOa`sa%k_%>z0p-1<}E3<%0Ayh>tI+6p##0I#DC0xuHxwv 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 V<6}n&000U0m5FVIK9r|-{|8~OR4o7i literal 0 HcmV?d00001 diff --git a/test/resources/evaluation/xlsx_files/test_sorted_order.xlsx b/test/resources/evaluation/xlsx_files/test_sorted_order.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..9c7d28116b346bfecd520fd01ce65a278a379478 GIT binary patch literal 6420 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 literal 0 HcmV?d00001 diff --git a/test/resources/evaluation/xlsx_files/test_unsorted_order.xlsx b/test/resources/evaluation/xlsx_files/test_unsorted_order.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..6d2f0d4c0d4a220f6ef0429bbb99205afe789c59 GIT binary patch literal 6264 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 Z{1;;BsAFOO{se4yxa8{{sTX{UQJW literal 0 HcmV?d00001 diff --git a/test/resources/evaluation/xlsx_files/test_wrong_column_name.xlsx b/test/resources/evaluation/xlsx_files/test_wrong_column_name.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..d1fc1415a11b9f89c5e3f1d8f1df9428067e2f47 GIT binary patch literal 5175 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 K9v07UpZ*_lgf_4M literal 0 HcmV?d00001 diff --git a/test/resources/evaluation/xlsx_target_files/target_unsorted_order.xlsx b/test/resources/evaluation/xlsx_target_files/target_unsorted_order.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..a43f5a94d330405ec45e45ada86dfcf264152e95 GIT binary patch literal 30873 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

5-SWL$ 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 F`#*;d6;=QM literal 0 HcmV?d00001 From 45b59192c4b0363beb9ed27ff8d5eca2a2410505 Mon Sep 17 00:00:00 2001 From: diatlova Date: Tue, 13 Apr 2021 12:43:09 +0300 Subject: [PATCH 04/78] adding tests --- test/python/evaluation/__init__.py | 7 +++ test/python/evaluation/conftest.py | 43 +++++++++++++++++++ .../evaluation/support_scripts/clear_up.py | 7 +++ test/python/evaluation/test_data_path.py | 19 ++++++++ test/python/evaluation/test_output_results.py | 32 ++++++++++++++ .../evaluation/test_remove_temp_files.py | 18 ++++++++ test/python/evaluation/test_tool_path.py | 32 ++++++++++++++ .../evaluation/test_xlsx_file_structure.py | 35 +++++++++++++++ 8 files changed, 193 insertions(+) create mode 100644 test/python/evaluation/__init__.py create mode 100644 test/python/evaluation/conftest.py create mode 100644 test/python/evaluation/support_scripts/clear_up.py create mode 100644 test/python/evaluation/test_data_path.py create mode 100644 test/python/evaluation/test_output_results.py create mode 100644 test/python/evaluation/test_remove_temp_files.py create mode 100644 test/python/evaluation/test_tool_path.py create mode 100644 test/python/evaluation/test_xlsx_file_structure.py diff --git a/test/python/evaluation/__init__.py b/test/python/evaluation/__init__.py new file mode 100644 index 00000000..6b141f7b --- /dev/null +++ b/test/python/evaluation/__init__.py @@ -0,0 +1,7 @@ +from test.python import TEST_DATA_FOLDER + +CURRENT_TEST_DATA_FOLDER = TEST_DATA_FOLDER / 'evaluation' + +XLSX_DATA_FOLDER = CURRENT_TEST_DATA_FOLDER / 'xlsx_files' + +TARGET_XLSX_DATA_FOLDER = CURRENT_TEST_DATA_FOLDER / 'xlsx_target_files' diff --git a/test/python/evaluation/conftest.py b/test/python/evaluation/conftest.py new file mode 100644 index 00000000..5413f231 --- /dev/null +++ b/test/python/evaluation/conftest.py @@ -0,0 +1,43 @@ +import pytest + +from dataclasses import dataclass +from pathlib import Path +from typing import List, Optional + +from src.python import MAIN_FOLDER + + +@dataclass +class EvalLocalCommandBuilder: + path: Optional[Path] = None + xlsx_tool_path: Optional[Path] = MAIN_FOLDER.parent / 'evaluation/xlsx_run_tool.py' + tool_path: Optional[Path] = MAIN_FOLDER.parent / 'review/run_tool.py' + traceback: Optional[str] = None + + def build(self) -> List[str]: + assert self.path is not None + command = ['python3', self.xlsx_tool_path, str(self.path), '-t', self.tool_path] + if self.traceback is not None: + command.extend(['--traceback', self.traceback]) + return command + + +@pytest.fixture +def eval_command_builder() -> EvalLocalCommandBuilder: + return EvalLocalCommandBuilder() + + +@dataclass +class BrokenLocalCommandBuilder: + path: Optional[Path] = None + tool_path: Optional[Path] = MAIN_FOLDER.parent / 'evaluation/do_not_exist.py' + + def build(self) -> List[str]: + assert self.path is not None + command = ['python3', '-t', self.tool_path, str(self.path)] + return command + + +@pytest.fixture +def broken_command_builder() -> BrokenLocalCommandBuilder: + return BrokenLocalCommandBuilder() diff --git a/test/python/evaluation/support_scripts/clear_up.py b/test/python/evaluation/support_scripts/clear_up.py new file mode 100644 index 00000000..b455b677 --- /dev/null +++ b/test/python/evaluation/support_scripts/clear_up.py @@ -0,0 +1,7 @@ +import openpyxl + + +def remove_sheet_with_results(path: str): + file = openpyxl.load_workbook(path) + file.remove(file['Inspection results']) + file.save(path) diff --git a/test/python/evaluation/test_data_path.py b/test/python/evaluation/test_data_path.py new file mode 100644 index 00000000..78bc30e0 --- /dev/null +++ b/test/python/evaluation/test_data_path.py @@ -0,0 +1,19 @@ +import subprocess + +from test.python.evaluation import XLSX_DATA_FOLDER +from test.python.evaluation.conftest import EvalLocalCommandBuilder + + +def test_incorrect_data_path(eval_command_builder: EvalLocalCommandBuilder): + file_path = XLSX_DATA_FOLDER / 'do_not_exist.xlsx' + + eval_command_builder.path = file_path + process = subprocess.run( + eval_command_builder.build(), + stderr=subprocess.PIPE, + stdout=subprocess.PIPE, + text=True, + ) + + assert process.returncode == 2 + assert 'XLSX-file with the specified name does not exists.\n' == process.stderr diff --git a/test/python/evaluation/test_output_results.py b/test/python/evaluation/test_output_results.py new file mode 100644 index 00000000..3f5d8533 --- /dev/null +++ b/test/python/evaluation/test_output_results.py @@ -0,0 +1,32 @@ +import pandas as pd +import pytest +import subprocess + +from test.python.evaluation import TARGET_XLSX_DATA_FOLDER, XLSX_DATA_FOLDER +from test.python.evaluation.conftest import EvalLocalCommandBuilder +from test.python.evaluation.support_scripts.clear_up import remove_sheet_with_results + +FILE_NAMES = [ + ('test_sorted_order.xlsx', 'target_sorted_order.xlsx', 'grades'), + ('test_sorted_order.xlsx', 'target_sorted_order.xlsx', 'traceback'), + ('test_unsorted_order.xlsx', 'target_unsorted_order.xlsx', 'grades'), + ('test_unsorted_order.xlsx', 'target_unsorted_order.xlsx', 'traceback'), +] + + +@pytest.mark.parametrize(('test_file', 'target_file', 'output_type'), FILE_NAMES) +def test_correct_output(test_file: str, target_file: str, output_type: str, + eval_command_builder: EvalLocalCommandBuilder): + eval_command_builder.path = XLSX_DATA_FOLDER / test_file + + if output_type == 'traceback': + eval_command_builder.traceback = str(True) + + subprocess.run(eval_command_builder.build()) + + test_dataframe = pd.read_excel(XLSX_DATA_FOLDER / test_file, sheet_name='Inspection results') + target_dataframe = pd.read_excel(TARGET_XLSX_DATA_FOLDER / target_file, sheet_name=output_type) + + remove_sheet_with_results(XLSX_DATA_FOLDER / test_file) + + assert test_dataframe.equals(target_dataframe) diff --git a/test/python/evaluation/test_remove_temp_files.py b/test/python/evaluation/test_remove_temp_files.py new file mode 100644 index 00000000..8401a2a9 --- /dev/null +++ b/test/python/evaluation/test_remove_temp_files.py @@ -0,0 +1,18 @@ +import subprocess + +from src.python import MAIN_FOLDER + +from test.python.evaluation import XLSX_DATA_FOLDER +from test.python.evaluation.conftest import EvalLocalCommandBuilder +from test.python.evaluation.support_scripts.clear_up import remove_sheet_with_results + +from src.python.review.common.file_system import get_all_file_system_items + + +def test_temp_files_remove(eval_command_builder: EvalLocalCommandBuilder): + file_path = XLSX_DATA_FOLDER / 'test_unsorted_order.xlsx' + eval_command_builder.path = file_path + subprocess.run(eval_command_builder.build()) + remove_sheet_with_results(file_path) + temporary_files = get_all_file_system_items(MAIN_FOLDER.parent / 'evaluation/temporary_files') + assert temporary_files == [] diff --git a/test/python/evaluation/test_tool_path.py b/test/python/evaluation/test_tool_path.py new file mode 100644 index 00000000..d9db801e --- /dev/null +++ b/test/python/evaluation/test_tool_path.py @@ -0,0 +1,32 @@ +import subprocess + +from test.python.evaluation import XLSX_DATA_FOLDER +from test.python.evaluation.conftest import EvalLocalCommandBuilder, BrokenLocalCommandBuilder +from test.python.evaluation.support_scripts.clear_up import remove_sheet_with_results + + +def test_correct_tool_path(eval_command_builder: EvalLocalCommandBuilder): + file_path = XLSX_DATA_FOLDER / 'test_unsorted_order.xlsx' + + eval_command_builder.path = file_path + process = subprocess.run( + eval_command_builder.build(), + stderr=subprocess.PIPE, + stdout=subprocess.PIPE, + ) + + remove_sheet_with_results(file_path) + assert process.returncode == 0 + + +def test_incorrect_tool_path(broken_command_builder: BrokenLocalCommandBuilder): + file_path = XLSX_DATA_FOLDER / 'test_unsorted_order.xlsx' + + broken_command_builder.path = file_path + process = subprocess.run( + broken_command_builder.build(), + stderr=subprocess.PIPE, + stdout=subprocess.PIPE, + ) + + assert process.returncode == 2 diff --git a/test/python/evaluation/test_xlsx_file_structure.py b/test/python/evaluation/test_xlsx_file_structure.py new file mode 100644 index 00000000..b6255071 --- /dev/null +++ b/test/python/evaluation/test_xlsx_file_structure.py @@ -0,0 +1,35 @@ +import pytest +import string +import subprocess + +from src.python.evaluation import ScriptStructureRule + +from test.python.evaluation import XLSX_DATA_FOLDER +from test.python.evaluation.conftest import EvalLocalCommandBuilder + +FILE_NAMES = [ + 'test_wrong_column_name.xlsx', + 'test_java_no_version.xlsx', + 'test_empty_lang_cell.xlsx', + 'test_empty_table.xlsx', +] + + +def compare(string_error: str): + return string_error.translate(string.whitespace + string.punctuation) + + +@pytest.mark.parametrize('file_name', FILE_NAMES) +def test_wrong_column(file_name: str, eval_command_builder: EvalLocalCommandBuilder): + file_path = XLSX_DATA_FOLDER / file_name + + eval_command_builder.path = file_path + process = subprocess.run( + eval_command_builder.build(), + stderr=subprocess.PIPE, + stdout=subprocess.PIPE, + text=True, + ) + + assert process.returncode == 2 + assert compare(process.stderr) == compare(ScriptStructureRule) + '%' From e7971911d3a8e10c8bf19d681a28cfe8af5dce5c Mon Sep 17 00:00:00 2001 From: diatlova Date: Wed, 14 Apr 2021 10:40:51 +0300 Subject: [PATCH 05/78] Requirements for xlsx tool --- requirements.txt | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/requirements.txt b/requirements.txt index 7af2b55a..325e241a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -setuptools~=47.3.2 +setuptools~=47.3.1 # python code analysis tools pylint==2.5.3 @@ -29,6 +29,4 @@ django==3.0.8 requests==2.24.0 argparse~=1.4.0 pandas~=1.2.3 -pytest~=5.4.3 -openpyxl~=3.0.7 -jsonschema~=3.2.0 \ No newline at end of file +openpyxl~=3.0.7 \ No newline at end of file From 2172286dacd5b0909e9344a1b0c1d6a14f77f12d Mon Sep 17 00:00:00 2001 From: diatlova Date: Wed, 14 Apr 2021 10:42:10 +0300 Subject: [PATCH 06/78] XLSX run_tool --- src/python/evaluation/xlsx_run_tool.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/python/evaluation/xlsx_run_tool.py b/src/python/evaluation/xlsx_run_tool.py index a180e73b..223efb0c 100644 --- a/src/python/evaluation/xlsx_run_tool.py +++ b/src/python/evaluation/xlsx_run_tool.py @@ -108,7 +108,7 @@ def main() -> int: )) with pd.ExcelWriter(args.data_path, engine='openpyxl', mode='a') as writer: - report.to_excel(writer, sheet_name='Inspection results', index=False) + report.to_excel(writer, sheet_name='inspection_results', index=False) return 0 except FileNotFoundError: From 52b28ae2db8ffd5bfb33952282dcbe0c90353a65 Mon Sep 17 00:00:00 2001 From: diatlova Date: Wed, 14 Apr 2021 10:43:26 +0300 Subject: [PATCH 07/78] Files to test xlsx run tool --- .../xlsx_files/test_sorted_order.xlsx | Bin 6420 -> 12042 bytes .../xlsx_files/test_unsorted_order.xlsx | Bin 6264 -> 8725 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/test/resources/evaluation/xlsx_files/test_sorted_order.xlsx b/test/resources/evaluation/xlsx_files/test_sorted_order.xlsx index 9c7d28116b346bfecd520fd01ce65a278a379478..92190fa9bd3c87f909b7b082683e901f6d12969c 100644 GIT binary patch delta 6846 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 Riv_|04gKCa2j^cB{{!lWmpT9d delta 1204 zcmeB*n_|Qp;LXe;!oa}5!EiUBcOvf^W+1h3k2oWU-h7QQj2X<(XU*aQGtQ}OW&$xL zx2Qj>2hu@)b`>8@7#SFBm>3xNf#y`?=$GdgWhdq5XX{nu=JWcrDDy3foY) z&R1|#=wX$Ojd?RaMXc>rIoJP8_~ou=qPJhXQmLO=q``OC(#S{P_|{Fl`MPgz{yUr+ zeVAh_Z?a$4JTIYj3G;Z*-Q#trEZd#&c1;hq-M%RLrpkRz`?))xniB+O zOsPKbX2o$EUa1O=)jN~ETotzUD}To?Gwt?CwK$u{MMkq9WNy^`u&ak_&kVKC6?0uK z*6coV@M#T~SG}H$vGgMj7N>BRH|)-eEWFF7tUMQe?{}?~=wgkp?vr$kzc~Lim;RwO zh3CWeLyZyNwx8NDUGo3JX1VzHJGJH)h39D=yBs;iAz*%s#-De-dowOAzpZNV$NL{E zN~8oCzka-HEih<*1A|!#62$REsX4`y*|mh~w@$R>Yc}9%T`%;ML1M*~g-pxz)`*IC zH2oB8blJH2&|B$)3?8z(3?k1@+y6Z!UEidu+B)#Mwb17bwNt6b-^ej6v6c~az4lN< zt@rEVM+&vvelH!ja%9TfKPWG`=|rDTpf2Bk#aqi>n%b?c>$mvGZ&0&FeuZ<2rq-)c$Lubq6}@2~;SvG}F0O0$eD3LIYR^=Q92z}<2rcJZ_M zN%TN|U^>875S&0oy9@04)Fna#@$H>QW~?71kV+FAej z(Sxu2ULRdGb{3sDc+4fHz-eCR<_^U#+7Cm1R5eWLY0J?T-s^EZbJ1p|ml=$wPfMlm z;wjA)d9mPIpSM>J=aOS=4RdteFCG;&`8Xl*&%LvG2@`gDJh_s~C3tfyOa1e?IWJdt zpKzLRBF6GbOUm1u>Mi#Qd4Gjj`2SE|Qucx6sLqBn@}JA+tN)Fbs^nkz_kH!X^-Cuo z^XKh&XuIB?F~FOVNrV}mQzu*MScCInxsDB(-lk&*roZbrgXxpH(zgA;3<=DS#U+(F zsl}k&h-OI8cK6p^2Y@L`448Sjfiw&>FuDp&R@9SJz?Q=iiu8mhN9oCe6``k5gra_t t$$vFvbkMCv#61IpFibU&ZeT1Co%~TtR4l-ol?^1$350e)_Z<)e@c;-+>umr4 diff --git a/test/resources/evaluation/xlsx_files/test_unsorted_order.xlsx b/test/resources/evaluation/xlsx_files/test_unsorted_order.xlsx index 6d2f0d4c0d4a220f6ef0429bbb99205afe789c59..75102c81655ab6825551ab3d401cf1f78656d8bb 100644 GIT binary patch delta 3575 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 delta 1088 zcmbR0^22~Pz?+#xgn@y9gF!p7cOvf^W+1h3j~F9}-h7oYj2X<(W3}M|GZsl~W&$xL zM@T=b2hu^Ox7^b_4%F|!$iTo4q$_gt%kzt}lk)Sk^(u06dixIg9X8-;i&s6xJRvv9 zBP3V6c}$dsfb$!&PqbV&%1+#%*_5 zZhm4u7tq4GBxiNcmrR3}7Y|tP+B&a%w&Av|WPMXg_K`!ub0XJo`@f??ZNohEhFO;1a;kwPuE-%H1>9GNor56Vk! zI??A7sLS_X@z%1Jrgm%V`Yk^48`P|kU*Vjhsr5AaNz9>~Z}nyeqb6xgSgP?l=GP{_ zB@L&A1ohc6`!~OwTwk@+zCHHN+wh&H=iPU#RebQ}^&@UnzszoPYLNy;-gRaM24P?X zMmy){m89mC#D`QCq!!15B602H^PosP7QggWX_m1?fx~OP9_=>=xLc0IE`ByYDZjoX zzyJ0ouLT=!Yj2&Y}|skGaGYIL+(a+@bhI`(enBs)i{&^=&!Y!h1cAXD-^z^fH6-^l7Q|T|A|^ zA}+|;N;aqZztznL?`^BT8CLbpx{<(KHFJZz?k0)1hxdd-+WvPEYH|OQ*?h{TE zPQ+L~X-Ro|Q@!P0A@8p+3;!R=OUgd59Nln6{&V?!^}o?lmHZ3;zOTNve(B_6{=6Lz zZP(i~26!{_Fo`h3^U&ljd24VEIU#QYrr8zjz_f>gvjQl`98{Us0M#OlY!>qGT+#T!zr|UkD@50bPXbAZTg@B~}IoDVR Date: Wed, 14 Apr 2021 10:44:40 +0300 Subject: [PATCH 08/78] XLSX run tool tests --- test/python/evaluation/support_scripts/clear_up.py | 2 +- test/python/evaluation/test_output_results.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/python/evaluation/support_scripts/clear_up.py b/test/python/evaluation/support_scripts/clear_up.py index b455b677..e68659e5 100644 --- a/test/python/evaluation/support_scripts/clear_up.py +++ b/test/python/evaluation/support_scripts/clear_up.py @@ -3,5 +3,5 @@ def remove_sheet_with_results(path: str): file = openpyxl.load_workbook(path) - file.remove(file['Inspection results']) + file.remove(file['inspection_results']) file.save(path) diff --git a/test/python/evaluation/test_output_results.py b/test/python/evaluation/test_output_results.py index 3f5d8533..c157eccf 100644 --- a/test/python/evaluation/test_output_results.py +++ b/test/python/evaluation/test_output_results.py @@ -24,7 +24,7 @@ def test_correct_output(test_file: str, target_file: str, output_type: str, subprocess.run(eval_command_builder.build()) - test_dataframe = pd.read_excel(XLSX_DATA_FOLDER / test_file, sheet_name='Inspection results') + test_dataframe = pd.read_excel(XLSX_DATA_FOLDER / test_file, sheet_name='inspection_results') target_dataframe = pd.read_excel(TARGET_XLSX_DATA_FOLDER / target_file, sheet_name=output_type) remove_sheet_with_results(XLSX_DATA_FOLDER / test_file) From 5c1c7cf57e2bb4247b67d96f10cc6fc6800e178b Mon Sep 17 00:00:00 2001 From: Daria Diatlova Date: Wed, 14 Apr 2021 14:34:48 +0300 Subject: [PATCH 09/78] Update build.yml --- .github/workflows/build.yml | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4cc2a22b..c8bf2f31 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -38,6 +38,15 @@ jobs: java-version: '11' - name: Check java version run: java -version + - name: Test with pytest run: | - pytest + pytest + + - name: Upload a Build Artifact + uses: actions/upload-artifact@v2.2.3 + with: + name: pytest-results-${{ matrix.python-version }} + path: junit/test-results-${{ matrix.python-version }}.xml + # Use always() to always run this step to publish test results when there are test failures + if: ${{ always() }} From db4eca871ad18e1a13ef71d1708e46d1057b9727 Mon Sep 17 00:00:00 2001 From: Daria Diatlova Date: Wed, 14 Apr 2021 14:40:13 +0300 Subject: [PATCH 10/78] Update build.yml --- .github/workflows/build.yml | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c8bf2f31..e54d3b13 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -40,13 +40,11 @@ jobs: run: java -version - name: Test with pytest - run: | - pytest - - - name: Upload a Build Artifact - uses: actions/upload-artifact@v2.2.3 + run: pytest tests.py --doctest-modules --junitxml=junit/test-results-${{ matrix.python-version }}.xml + - name: Upload pytest test results + uses: actions/upload-artifact@v2 with: name: pytest-results-${{ matrix.python-version }} path: junit/test-results-${{ matrix.python-version }}.xml - # Use always() to always run this step to publish test results when there are test failures - if: ${{ always() }} + # Use always() to always run this step to publish test results when there are test failures + if: ${{ always() }} From 8f2f19f18374a2952f2af04fb6cf83ed360ac30f Mon Sep 17 00:00:00 2001 From: Daria Diatlova Date: Wed, 14 Apr 2021 15:06:57 +0300 Subject: [PATCH 11/78] Update build.yml --- .github/workflows/build.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e54d3b13..8677a2e4 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -40,11 +40,12 @@ jobs: run: java -version - name: Test with pytest - run: pytest tests.py --doctest-modules --junitxml=junit/test-results-${{ matrix.python-version }}.xml + run: | + pytest - name: Upload pytest test results uses: actions/upload-artifact@v2 with: name: pytest-results-${{ matrix.python-version }} - path: junit/test-results-${{ matrix.python-version }}.xml + path: test # Use always() to always run this step to publish test results when there are test failures if: ${{ always() }} From 6ac1154d39883bdb16003fb74a1bd5ec2cd2354d Mon Sep 17 00:00:00 2001 From: diatlova Date: Wed, 14 Apr 2021 15:19:47 +0300 Subject: [PATCH 12/78] Clean xlsx --- .../xlsx_files/test_sorted_order.xlsx | Bin 12042 -> 7319 bytes .../xlsx_files/test_unsorted_order.xlsx | Bin 8725 -> 6264 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/test/resources/evaluation/xlsx_files/test_sorted_order.xlsx b/test/resources/evaluation/xlsx_files/test_sorted_order.xlsx index 92190fa9bd3c87f909b7b082683e901f6d12969c..d654e61af88fd66da8f2f42aa3b5a789765f712a 100644 GIT binary patch delta 6436 zcmaJ_1yEG`_g@-Bx?5V7S|p^qd8~j4h;&PL!*R@g%C;*QLkawX1joJmmMEGzjRC)rsk{y{IJPEgEXf zqucS)%PYt8iRjQ))DRI|dUSt%tP*SWL2j&IKE|MetHxl#rp$pjda_q%Z93EPW*bs6 z(#qkr@?>B&@4XX=ca-P+w1LD%=O`y;ONIGp#i}AImk8Z}KX(`+j4uIPyTvjsFL@=5 z!GBHu@@T$St-0^Be(yYC4+7Pb4z@Ze&t6y=lU{S2sjS;~zZwf9D!=~TTK?0O`7$t^ zuj(PIb(!8m(Le=VjlPN!8akTM%K#Jv5C{zk1o|&9<1*NZfWN_eI~$wAj~kqBu;`cN zXcZ8MyHx&;Jes?zPRSIfPNP)V3@t{f9hP6@bAoQzpV1v^Wyc@Va&yfEkuX4=K^sKf3t)GF=M zhTQ2Pe?a`JkRBH=k(b^U^9x$miS-v}(^>mw|zjWp27?hk&jDe`|3-cK^mn((qM` zu?(qBcu$#@?YoaX*4q?y@x6|=Y%RTCbtsd|Kb(%P^Q@N5l%DWQ64OSWoYCwaQ+}K%n{}Bo|9d>@!cr*I;0YDH z=Q0^dY^2o&Q-Mo^QCX14iu`cb&vVwH0TV1hRvMk_upr6?%R0Zd$p{@uq%4RX(IPYe zm54(dd3e-;$7m!ZJOTHWtoZVP1bvGRFXFHY{~+;;YWG&+k^6?N#7KOr8nYpt>@`sQ z6GpeqNNqvE_eu~21gfC?d4G!6wa$d2T`SI^IZCL`&!sKU*YOjR1)b^f-*Wgl!})aq z%Z*V{UCARpM6nRUTqspNUg*=LEy8iC=BI8+IsL)TiGk?DrVn^sx3CpKx~LP_D-ME$ z3%-6*Fi!Z==5y5{K}V1r&#S#GGPVbG0aLRKF^B#N_xgvzJSWP+`Li-P===-Z^AJaD z8pNk0B0BJ-YYh!*(0h15c(&yH4FT@JET76MUDP%Ox-F*aI-MkzbYO~HAZ2I9Bx$J> zy3EGRCb zcpq7gR(nIg7?K4CnrnFT|5D0uUH)NG;noBnvPd}O(5lgeeLQv!ALF%~bZ`Nh_M!@P zPH#%-xu2qMuVmO|*x60bd?p*jjIs!bG-1AChR0R74jvq$CLtdKBL`@A1wMla&w77b z+%K^HtHA01?v`$Lj#f?*#o?}?2;vuD&0Ix+l=p4GvGE7z z9h#7c3A7_CDi{ni(UqG%LV1k)9y_FZn~;^MwkO6eV&Z+4N2Pa5vxa(-+|LybmT*@m zp_I1{Gh)?i&qFwR3)g0+t*l3$U{AX)(_MTLh7Hxln*Om8G>ouYr^Uo|Kc2zuy#%Z<|@47hY8cpjRlRCa?mL4UnJoS+AJ44glndgLVZk(rQ zCGv|#m5je$xsIpZc)1~{EMv+msE+BqZ~z`Lp|Bl)ZR7aCmc8;e-3*~F8}CGluTaRf z0s4>vMvy*#e@iUtdP?{s0f#W(zJJV!p^t>e)mQj#lmH2G!XwebCqan~MZ`2uHU?H) z`Sb3Z6?a&yVVsiASDp%IEd)McA*#su{IUk;1^1A-%Oh-Krr;xLt;i&RVocLAV>Ta1 zr*yhm)k-~$TS?#-u>Hc!OLs~3DH?^k0Uj+uh*Afg^%$}4XrUjqZHQWNO&1G-xe9Tf zhP!>mEIB}%gKB%lERi`xu-7qa=Yy^T4aRRX z2Q-iKwlmz;9Vsw}M^BVsbuip}7Yt;W$frVUCdDXmM=f7#J`IV%=Q_z(@T&kl`?_Uen~*^^v9<_YC*+$$@VD3olh z5eO8iIiZ2=jo46zwOw!@%ui2SJrdMRFYtT%C`GARNa*T|&_Uik0(VQy?!b!L_sp;m;ri%8X7pDA^Vp!C`jm?R^xX zA42F8cvaLP?O(+*lOCa<(5Qt)7_{u4s{5-3@d^%JwT#gXuu^8?qWC^EYT_|u^o+n= zLC#35qBlP(8(R07p}wc5k?BGdjBrHiO=$I)?AsNbxfC&!yNwEQLlyuNvp6fWvG6b` zGnXK6lC{UtZV(QQGN3+%l-VqN0aa+7WFfgg*V zwEDaHM~C=?ZfMb$=T_aidylaZ3Et0$r54}U>wlgtt60_qCULUQzl7?PggD#_ErcQ* zpuNi@OS;I%@v^4+U~>h$TJE3H!0R{k^1!~I(;m#?YBLmjl83A|Xu&6;8Jc&+&7$o0 z**Q$$q!gjo;sgGZGe#=acvedFd~$e%IW!iM7~$NuF2%^M?eoAy+RsJ`%4RyQcC^k> zlxU#l^@gF#a@ui){B5X{qi}jEs&lg-%$M$fnMYqI433NU5rznuSe|Z8;V|*2@l{CO z3mZs$Qz8}`Sg4L`hqDyS+&pTA7C#@ta$nTP5)r9FN%NU$8HZngt&x|Lg%48#jzA%L zI4dtBofqZ6o(h0J_JduZJujT%MI7el1_hX#(S>LC1A$^MVfoB5V1)2SrzPd z-PboVo8gbOsW}a3%F)K%dg&=0S84c&D5Lqy`RR6H93v~QkR?(Mck?H z;!fjKR_4s%(cD~G$?jQw{jv8|OGHV*5>HcVkXt2NCz}r-g@EDMUEo7sYKMFr+1iZv zu;KRW#*#kcncXDz`Z6V~BB_T-pr(-W`f`C}g#{cxnmbSB6*FUb_-cRMn|H0%{4pKe zg-CVR*a7?%!Nl*ibXPbO~3WoHOT4E)YNGXM9t(E&XxSZjp(d zuRz~;EQ+0xqFg&IYU#&yd&X>@QiHVR);`Cv5u044Q$e?}_ij@53COkMV=&2T4al_A zGG+ZdeU0vcRay7#fihNcS`SB#938e->)0yer&K#Ez5B*Zd&zsdVTUXm6ZWmX&=Wm#Aj(0j2 z1J?L{P~CstU-htanXDNtP73ec(ry@xmKnFd)&dYq{|uKbJz<_H?vO0nDCSDC|7%wqoD2&wNp19ya2nQ3R%FkYACmxvm# zB7J6mBYTJ+J-5=ZDfOk};hEHshxn@upU?~3ZFbtUBOTS2M+sJ?&fNeDxw!L-<)W3! zBQAM`^1*VetPjKdv~$>J%zcCQ@dktLV?jjRVTr{A5$W{vF%**1{_h73^)j+Qc+E|- zzN+F0k(I~m4kaoM8(d$);})V)ymZh|4+3PLsJDxnma4u7C%*2ct+7$mnVkM1U6mWg z+~dXkAp#r=8f}<{p&9^a4axfWM+qStE3|6zbtT4;aarJurPg=F65@xR+}f``+xKFa z9b5#|5YCEvJ2(s9OA?K#<0=lS)^_~nt|~J*jn3=9LSw{wwGGvQVKb(e*o0;>)328Y z_O0bC^k{$?HMk|$9eoXsbqa5gP)ARYsXJDHI(t1_*-M=hiMG5KxlOw1}JgI zzV;ICd0OzS1wjS4&75VtWwY~JqDp?7J^w~lK_Hx8l-u1sH9j;j59!)?R7=psdP*Ci(ypaoU(=Vta*RCiN>jz4Soy7 zQsf3$)Ck>09mQ3WxXTnqYD!MN6AH}WzK&D7CqKe%;VcAj&ni{vD%81HHxILbBl7Vh zc-dbO?7;5@iab~93N6c=G0DCJ#tAuPr63%rw@85e<8eFR|St+(PZKu6K9gig~rz0P3EV(}3?06P4 zB}e(h{1o}JEz>aB}q5iOfUpx4@`wm(-BhTXJ`>kr*`H7<0dY32j*W}4#6t4c?q54Eou#Kb})Vm%upWGIU zfd~TaBL7z=k^h}ZKR3QOG%!9;6f0rb0l}4dGAtA_Jy{;7rWl&4{Lo}J7Y%oG>QNaZ zt@6zI@jJdHL0m}^z0jMk%bQ_~iYs!@eLohrHr5Ye_{g3F*56*B?84q&Fykgw*3{!r z6GbE%zF4%;E1T@(o_68F#NL1IM;|t%X0~EKT!)S)vdBY=m8_MkA!`!_)XUU?`{k0> z$W-)A!kV7N99JVckkVf>3-KtM+mj5u6n~-#X4q$Q%z(1T`s;h}75I0E>zQk@!((1< zpJ6eFR5U+p(W_k82t1C&=X8g1)!4NOvtb;PjdBS|pCcs|(x{8(cJ+qSXaY!gC?$}! zJ>9&;pzao_yLtoue?<}V_LaZ4;@e&LZWWfm_J`o24BxK8X2)vwh7p;iTujzj)EU)M zwBmU$3)**f)FLt8#+@Dd<`%y7Fv9s^_<%K|*U`X&XrqlBVe+_91ca%o&CXo@(4Y(C zQpLi_4^Om}6srYV@r?priORaI3V)zBCwt^*F_ud&)}JVAR~u&;k9x*2bTZdMq2iNR zID+V%jcKs6xkr;yZ>!=?=aN3sO+%y~%AjNixu?Z+%^&&hK~>Y#`PMjdxW^Rs`3usRdk^eBrUOWvGin#m-zGfJ`auVI$Vbm#}@BGP}LnISH8`DKrRU4?GH*s4vVC>OUNDGR~O_xrp|qeuCm z>~V18!6%07eSQ4Q;z&uV@fin21uj|(OWcZzuYB*HJ>KPAeDIaT{x7hbhHn5v1B3ond!>6P`LzQ1?K zyNUYCuy23N?Z0sc$p7Z+pU%HGj=LuM%hZYEu2?8d|8)4h`0m=tFAFC5M|1hp@%M!K g2h1P`(ztyv5wVIA$}QX=(7oGF@@*gcMt1k~e^d$olK=n! delta 11160 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 fKd0k=V*(hS$2DW?j diff --git a/test/resources/evaluation/xlsx_files/test_unsorted_order.xlsx b/test/resources/evaluation/xlsx_files/test_unsorted_order.xlsx index 75102c81655ab6825551ab3d401cf1f78656d8bb..438c73494a4811359d64592dc32866630dbf43d0 100644 GIT binary patch delta 1341 zcmbR0^22~9z?+#xgn@y9gW*uoM4q)Ahl=`w4oROmF!7*5eb!+Ep0@aY|OU;F=Za*y;Eq2CVv3%`rp2#D$3RvftK zeu{dUKBLmS6RRRr4lVs~fqk__>|wz@hssM;R-F38r?c@=m#EL7JNn1oEV{BoXzH$ zBMx1^FZk(ydcHCHLG;F*XZ~qTh+E1z>HIvio2Hd3-^+jNkBpu=^~C8?y=&EqDO3Ia zn(eIna=&HU^=AqH68CW3VypWb{hJdx4Elmn7dIwqFf%Z$-F%x9gI|oJv27Vx2k)vOpUzDAcpP#K)k(<-ochC%}>nd0$Ny?o1Y~}eaOfTa)_t{N<&Hgc=29NRU$Gg@t zurM(EW}F-@t5CmnqAg#u0Z;3Cp{EQIE3PbLTBf%~RJ^0A006Q|A6b zdC5&D`g{U)`Ti^3TK3Y^Zf#w^#YcXFnlUR2HNb$AThp?d0>INIVw5^i^q=u|Im0Ha{u9 zz9hf@_9m|d8+oUCFFy9|d+{ID)!UO<&RC_}hE+O?$hSINZI~R<#xYO1)Wc8c|FXFq zL0gO1AJy%w5zwk&@@M@j^|NYgW7Ip{)bq0Wi#hk55{@{tdAZ@n^w6C>7o}7?A3u8V zmEY^5tH#cv69)hO-_(l6+$d9UqDLwUVIoiT|J&tEC+RXGagYoofsq|eu zrMV(67JTdT_UhqWa*VBEj;{N~qoO7sCnWy4cQ!9!!cLDTS8}-oZ*FC&e?B+o_$Ple__n<2FP7sAMNKqn!&s4obTTtTUofk6tU u6G%5Oeioh_Eh{s5pCS*~Vd!ZArnZ6chREbsin4s144e#hK$okCfusQJ!8^AA delta 3806 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 aZv5-QT~@dbBMT)N;L^%pHW0*i_4hw5vIFb@ From f0cce197fae0aacaffdf21b1a9564bc335c81034 Mon Sep 17 00:00:00 2001 From: diatlova Date: Wed, 14 Apr 2021 17:56:07 +0300 Subject: [PATCH 13/78] Tempfiles substituted with regular --- src/python/evaluation/xlsx_run_tool.py | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/src/python/evaluation/xlsx_run_tool.py b/src/python/evaluation/xlsx_run_tool.py index 223efb0c..db1e4c68 100644 --- a/src/python/evaluation/xlsx_run_tool.py +++ b/src/python/evaluation/xlsx_run_tool.py @@ -4,7 +4,6 @@ import pandas as pd import re import sys -import tempfile import traceback from pathlib import Path @@ -70,17 +69,13 @@ def main() -> int: try: args = parser.parse_args() dataframe = pd.read_excel(args.data_path) + temp_dir_path = MAIN_FOLDER.parent / 'evaluation/temporary_files' for lang, code in zip(dataframe['lang'], dataframe['code']): - file = tempfile.NamedTemporaryFile( - dir=(MAIN_FOLDER.parent / 'evaluation/temporary_files'), - suffix=lang_suffixes[lang], - delete=False, mode="w", - ) + temp_file_path = os.path.join(temp_dir_path, ('file.' + lang_suffixes[lang])) - file = open(file.name, "w") - file.writelines(code) - file.close() + with open(temp_file_path, 'w') as file: + file.writelines(code) if lang == 'java8' or lang == 'java11': results = run_in_subprocess([ @@ -89,7 +84,7 @@ def main() -> int: else: results = run_in_subprocess(['python3', args.tool_path, file.name]) - os.unlink(file.name) + os.remove(file.name) # this regular expression matches final tool grade: EXCELLENT, GOOD, MODERATE or BAD regex_match = re.match(r'^.*{"code":\s"([A-Z]+)"', results).group(1) From 5db8e3d311c081854cdce86da09362195b56aeb5 Mon Sep 17 00:00:00 2001 From: diatlova Date: Wed, 14 Apr 2021 18:14:00 +0300 Subject: [PATCH 14/78] File name substituted with absolute path --- src/python/evaluation/xlsx_run_tool.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/python/evaluation/xlsx_run_tool.py b/src/python/evaluation/xlsx_run_tool.py index db1e4c68..91683f5c 100644 --- a/src/python/evaluation/xlsx_run_tool.py +++ b/src/python/evaluation/xlsx_run_tool.py @@ -79,12 +79,12 @@ def main() -> int: if lang == 'java8' or lang == 'java11': results = run_in_subprocess([ - 'python3', args.tool_path, file.name, '--language_version', lang]) + 'python3', args.tool_path, temp_file_path, '--language_version', lang]) else: - results = run_in_subprocess(['python3', args.tool_path, file.name]) + results = run_in_subprocess(['python3', args.tool_path, temp_file_path]) - os.remove(file.name) + os.remove(temp_file_path) # this regular expression matches final tool grade: EXCELLENT, GOOD, MODERATE or BAD regex_match = re.match(r'^.*{"code":\s"([A-Z]+)"', results).group(1) From b708c1d39e1f16bf9e7f1ad5cb4a795335eccbde Mon Sep 17 00:00:00 2001 From: diatlova Date: Thu, 15 Apr 2021 09:27:42 +0300 Subject: [PATCH 15/78] Adding new func names --- src/python/__init__.py | 3 --- test/python/evaluation/support_scripts/clear_up.py | 7 ------- whitelist.txt | 10 ++++++++++ 3 files changed, 10 insertions(+), 10 deletions(-) delete mode 100644 src/python/__init__.py delete mode 100644 test/python/evaluation/support_scripts/clear_up.py diff --git a/src/python/__init__.py b/src/python/__init__.py deleted file mode 100644 index 496da56c..00000000 --- a/src/python/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from pathlib import Path - -MAIN_FOLDER = Path(__file__) diff --git a/test/python/evaluation/support_scripts/clear_up.py b/test/python/evaluation/support_scripts/clear_up.py deleted file mode 100644 index e68659e5..00000000 --- a/test/python/evaluation/support_scripts/clear_up.py +++ /dev/null @@ -1,7 +0,0 @@ -import openpyxl - - -def remove_sheet_with_results(path: str): - file = openpyxl.load_workbook(path) - file.remove(file['inspection_results']) - file.save(path) diff --git a/whitelist.txt b/whitelist.txt index c2473e99..dfe8b9ce 100644 --- a/whitelist.txt +++ b/whitelist.txt @@ -63,3 +63,13 @@ nom wmc multiline sqrt +hyperstyle +XLSX +Eval +eval +src +openpyxl +dataframe +writelines +dedent +rmdir \ No newline at end of file From c5c75d9bfefde2be0cfddeeb883fb372b2a8af63 Mon Sep 17 00:00:00 2001 From: diatlova Date: Thu, 15 Apr 2021 09:28:57 +0300 Subject: [PATCH 16/78] Update evaluation tests --- test/python/evaluation/__init__.py | 4 ++++ test/python/evaluation/conftest.py | 5 ++--- test/python/evaluation/test_data_path.py | 1 - test/python/evaluation/test_output_results.py | 20 +++++++++++-------- .../evaluation/test_remove_temp_files.py | 14 +++++++------ test/python/evaluation/test_tool_path.py | 15 ++++++++------ .../evaluation/test_xlsx_file_structure.py | 7 +++---- 7 files changed, 38 insertions(+), 28 deletions(-) diff --git a/test/python/evaluation/__init__.py b/test/python/evaluation/__init__.py index 6b141f7b..31b1b86f 100644 --- a/test/python/evaluation/__init__.py +++ b/test/python/evaluation/__init__.py @@ -1,7 +1,11 @@ from test.python import TEST_DATA_FOLDER +from src.python import MAIN_FOLDER + CURRENT_TEST_DATA_FOLDER = TEST_DATA_FOLDER / 'evaluation' XLSX_DATA_FOLDER = CURRENT_TEST_DATA_FOLDER / 'xlsx_files' TARGET_XLSX_DATA_FOLDER = CURRENT_TEST_DATA_FOLDER / 'xlsx_target_files' + +RESULTS_DIR_PATH = MAIN_FOLDER.parent / 'evaluation/results' diff --git a/test/python/evaluation/conftest.py b/test/python/evaluation/conftest.py index 5413f231..1bbec42d 100644 --- a/test/python/evaluation/conftest.py +++ b/test/python/evaluation/conftest.py @@ -1,9 +1,8 @@ -import pytest - from dataclasses import dataclass from pathlib import Path from typing import List, Optional +import pytest from src.python import MAIN_FOLDER @@ -34,7 +33,7 @@ class BrokenLocalCommandBuilder: def build(self) -> List[str]: assert self.path is not None - command = ['python3', '-t', self.tool_path, str(self.path)] + command = ['python3', str(self.path), '-t', self.tool_path] return command diff --git a/test/python/evaluation/test_data_path.py b/test/python/evaluation/test_data_path.py index 78bc30e0..e0368a3a 100644 --- a/test/python/evaluation/test_data_path.py +++ b/test/python/evaluation/test_data_path.py @@ -1,5 +1,4 @@ import subprocess - from test.python.evaluation import XLSX_DATA_FOLDER from test.python.evaluation.conftest import EvalLocalCommandBuilder diff --git a/test/python/evaluation/test_output_results.py b/test/python/evaluation/test_output_results.py index c157eccf..ea2159d2 100644 --- a/test/python/evaluation/test_output_results.py +++ b/test/python/evaluation/test_output_results.py @@ -1,10 +1,13 @@ -import pandas as pd -import pytest +import os import subprocess -from test.python.evaluation import TARGET_XLSX_DATA_FOLDER, XLSX_DATA_FOLDER +import time +from test.python.evaluation import RESULTS_DIR_PATH, TARGET_XLSX_DATA_FOLDER, XLSX_DATA_FOLDER from test.python.evaluation.conftest import EvalLocalCommandBuilder -from test.python.evaluation.support_scripts.clear_up import remove_sheet_with_results + +import pandas as pd + +import pytest FILE_NAMES = [ ('test_sorted_order.xlsx', 'target_sorted_order.xlsx', 'grades'), @@ -23,10 +26,11 @@ def test_correct_output(test_file: str, target_file: str, output_type: str, eval_command_builder.traceback = str(True) subprocess.run(eval_command_builder.build()) - - test_dataframe = pd.read_excel(XLSX_DATA_FOLDER / test_file, sheet_name='inspection_results') + # wait before conduct output check as files appear with a delay + time.sleep(180) + test_dataframe = pd.read_excel(RESULTS_DIR_PATH / 'results.xlsx', sheet_name='inspection_results') target_dataframe = pd.read_excel(TARGET_XLSX_DATA_FOLDER / target_file, sheet_name=output_type) - - remove_sheet_with_results(XLSX_DATA_FOLDER / test_file) + os.remove(RESULTS_DIR_PATH / 'results.xlsx') + os.rmdir(RESULTS_DIR_PATH) assert test_dataframe.equals(target_dataframe) diff --git a/test/python/evaluation/test_remove_temp_files.py b/test/python/evaluation/test_remove_temp_files.py index 8401a2a9..2e150086 100644 --- a/test/python/evaluation/test_remove_temp_files.py +++ b/test/python/evaluation/test_remove_temp_files.py @@ -1,11 +1,10 @@ +import os import subprocess - -from src.python import MAIN_FOLDER - -from test.python.evaluation import XLSX_DATA_FOLDER +import time +from test.python.evaluation import RESULTS_DIR_PATH, XLSX_DATA_FOLDER from test.python.evaluation.conftest import EvalLocalCommandBuilder -from test.python.evaluation.support_scripts.clear_up import remove_sheet_with_results +from src.python import MAIN_FOLDER from src.python.review.common.file_system import get_all_file_system_items @@ -13,6 +12,9 @@ def test_temp_files_remove(eval_command_builder: EvalLocalCommandBuilder): file_path = XLSX_DATA_FOLDER / 'test_unsorted_order.xlsx' eval_command_builder.path = file_path subprocess.run(eval_command_builder.build()) - remove_sheet_with_results(file_path) temporary_files = get_all_file_system_items(MAIN_FOLDER.parent / 'evaluation/temporary_files') assert temporary_files == [] + # wait before deleting file and directory as they appear with a delay + time.sleep(180) + os.remove(RESULTS_DIR_PATH / 'results.xlsx') + os.rmdir(RESULTS_DIR_PATH) diff --git a/test/python/evaluation/test_tool_path.py b/test/python/evaluation/test_tool_path.py index d9db801e..3f33b264 100644 --- a/test/python/evaluation/test_tool_path.py +++ b/test/python/evaluation/test_tool_path.py @@ -1,8 +1,8 @@ +import os import subprocess - -from test.python.evaluation import XLSX_DATA_FOLDER -from test.python.evaluation.conftest import EvalLocalCommandBuilder, BrokenLocalCommandBuilder -from test.python.evaluation.support_scripts.clear_up import remove_sheet_with_results +import time +from test.python.evaluation import RESULTS_DIR_PATH, XLSX_DATA_FOLDER +from test.python.evaluation.conftest import BrokenLocalCommandBuilder, EvalLocalCommandBuilder def test_correct_tool_path(eval_command_builder: EvalLocalCommandBuilder): @@ -15,8 +15,11 @@ def test_correct_tool_path(eval_command_builder: EvalLocalCommandBuilder): stdout=subprocess.PIPE, ) - remove_sheet_with_results(file_path) assert process.returncode == 0 + # wait before deleting file and directory as they appear with a delay + time.sleep(180) + os.remove(RESULTS_DIR_PATH / 'results.xlsx') + os.rmdir(RESULTS_DIR_PATH) def test_incorrect_tool_path(broken_command_builder: BrokenLocalCommandBuilder): @@ -29,4 +32,4 @@ def test_incorrect_tool_path(broken_command_builder: BrokenLocalCommandBuilder): stdout=subprocess.PIPE, ) - assert process.returncode == 2 + assert process.returncode == 1 diff --git a/test/python/evaluation/test_xlsx_file_structure.py b/test/python/evaluation/test_xlsx_file_structure.py index b6255071..f195bcec 100644 --- a/test/python/evaluation/test_xlsx_file_structure.py +++ b/test/python/evaluation/test_xlsx_file_structure.py @@ -1,12 +1,11 @@ -import pytest import string import subprocess - -from src.python.evaluation import ScriptStructureRule - from test.python.evaluation import XLSX_DATA_FOLDER from test.python.evaluation.conftest import EvalLocalCommandBuilder +import pytest +from src.python.evaluation import ScriptStructureRule + FILE_NAMES = [ 'test_wrong_column_name.xlsx', 'test_java_no_version.xlsx', From f90177147b2afa3a42a1daa902a88761daa98856 Mon Sep 17 00:00:00 2001 From: diatlova Date: Thu, 15 Apr 2021 09:30:01 +0300 Subject: [PATCH 17/78] Files for evaluation testing --- .../xlsx_files/test_sorted_order.xlsx | Bin 7319 -> 6418 bytes .../xlsx_files/test_unsorted_order.xlsx | Bin 6264 -> 6264 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/test/resources/evaluation/xlsx_files/test_sorted_order.xlsx b/test/resources/evaluation/xlsx_files/test_sorted_order.xlsx index d654e61af88fd66da8f2f42aa3b5a789765f712a..6cb55179e62d16a576622b5c63c120662f4c8f37 100644 GIT binary patch delta 5491 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 diff --git a/test/resources/evaluation/xlsx_files/test_unsorted_order.xlsx b/test/resources/evaluation/xlsx_files/test_unsorted_order.xlsx index 438c73494a4811359d64592dc32866630dbf43d0..83f6c31751e2dc87b566a06b71c75d408391a8b4 100644 GIT binary patch delta 143 zcmexi@WX&7z?+#xgn@y9gJI>wi9BnWR!-cwTbvO{ZN9=7&J3b;S#7yMbPoR(CLldo zN$5F<;uih{qW%j%21z~<@d0U?Y$Rp_q6)-pLDYINdl2 Date: Thu, 15 Apr 2021 09:32:09 +0300 Subject: [PATCH 18/78] Update functionality xlsx-run tool --- src/python/evaluation/support_functions.py | 22 +++++++++ src/python/evaluation/xlsx_run_tool.py | 53 ++++++++++++++++------ 2 files changed, 62 insertions(+), 13 deletions(-) create mode 100644 src/python/evaluation/support_functions.py diff --git a/src/python/evaluation/support_functions.py b/src/python/evaluation/support_functions.py new file mode 100644 index 00000000..1b6fc82b --- /dev/null +++ b/src/python/evaluation/support_functions.py @@ -0,0 +1,22 @@ +import os +from pathlib import Path +from typing import NoReturn, Union + +from openpyxl import load_workbook + + +def create_folder(directory: Union[str, Path]) -> NoReturn: + try: + if not os.path.exists(directory): + os.makedirs(directory) + except OSError: + pass + + +def remove_sheet(path: str, name: str) -> NoReturn: + file = load_workbook(path) + try: + file.remove(file[name]) + file.save(path) + except KeyError: + pass diff --git a/src/python/evaluation/xlsx_run_tool.py b/src/python/evaluation/xlsx_run_tool.py index 91683f5c..facc51a6 100644 --- a/src/python/evaluation/xlsx_run_tool.py +++ b/src/python/evaluation/xlsx_run_tool.py @@ -1,38 +1,39 @@ import argparse import logging.config import os -import pandas as pd import re import sys import traceback - from pathlib import Path from typing import NoReturn sys.path.append('') sys.path.append('../../..') +import pandas as pd +from openpyxl import Workbook from src.python import MAIN_FOLDER from src.python.evaluation import ScriptStructureRule +from src.python.evaluation.support_functions import create_folder, remove_sheet from src.python.review.common.subprocess_runner import run_in_subprocess -from src.python.review.run_tool import positive_int from src.python.review.reviewers.perform_review import OutputFormat +from src.python.review.run_tool import positive_int logger = logging.getLogger(__name__) def configure_arguments(parser: argparse.ArgumentParser) -> NoReturn: + parser.add_argument('data_path', + type=lambda value: Path(value).absolute(), + help='Local XLSX-file path. ' + 'Your XLSX-file must include column-names: \"code\" and \"lang. ' + 'Acceptable values for \"lang\" column are: python3, java8, java11, kotlin.') + parser.add_argument('-t', '--tool_path', default=Path('src/python/review/run_tool.py').absolute(), type=lambda value: Path(value).absolute(), help='Path to script to run on files.') - parser.add_argument('data_path', - type=lambda value: Path(value).absolute(), - help="Local XLSX-file path. " - "Your XLSX-file must include column-names: \"code\" and \"lang. " - "Acceptable values for \"lang\" column are: python3, java8, java11, kotlin.") - parser.add_argument('--n_cpu', '--n-cpu', help='Specify number of cpu that can be used to run inspectors.', default=1, @@ -43,6 +44,19 @@ def configure_arguments(parser: argparse.ArgumentParser) -> NoReturn: default=False, type=bool) + parser.add_argument('--folder_path', '--folder_path', + help='An absolute path to the folder where file with evaluation results' + 'will be stored.' + 'Default is \"hyperstyle/src/python/evaluation/results\"', + default=None, + type=str) + + parser.add_argument('--file_name', '--file_name', + help='Filename for that will be created to store inspection results.' + 'Default is \"results.xlsx\"', + default='results.xlsx', + type=str) + parser.add_argument('-f', '--format', default=OutputFormat.JSON.value, choices=OutputFormat.values(), @@ -72,7 +86,7 @@ def main() -> int: temp_dir_path = MAIN_FOLDER.parent / 'evaluation/temporary_files' for lang, code in zip(dataframe['lang'], dataframe['code']): - temp_file_path = os.path.join(temp_dir_path, ('file.' + lang_suffixes[lang])) + temp_file_path = os.path.join(temp_dir_path, ('file' + lang_suffixes[lang])) with open(temp_file_path, 'w') as file: file.writelines(code) @@ -89,10 +103,9 @@ def main() -> int: # this regular expression matches final tool grade: EXCELLENT, GOOD, MODERATE or BAD regex_match = re.match(r'^.*{"code":\s"([A-Z]+)"', results).group(1) + output = regex_match if args.traceback: output = results - else: - output = regex_match report = report.append(pd.DataFrame( { @@ -102,8 +115,22 @@ def main() -> int: }, )) - with pd.ExcelWriter(args.data_path, engine='openpyxl', mode='a') as writer: + folder_path = args.folder_path + + if folder_path is None: + folder_path = MAIN_FOLDER.parent / 'evaluation/results' + create_folder(folder_path) + + workbook = Workbook() + workbook_path = Path(folder_path) / args.file_name + workbook.save(workbook_path) + + with pd.ExcelWriter(workbook_path, engine='openpyxl', mode='a') as writer: report.to_excel(writer, sheet_name='inspection_results', index=False) + + # remove empty sheet that was initially created with the workbook + remove_sheet(workbook_path, 'Sheet') + return 0 except FileNotFoundError: From 61a054f15e431d2126d9c531eeccb17ee05f2a23 Mon Sep 17 00:00:00 2001 From: diatlova Date: Thu, 15 Apr 2021 09:44:25 +0300 Subject: [PATCH 19/78] Adding MAIN_FOLDER --- src/python/__init__.py | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 src/python/__init__.py diff --git a/src/python/__init__.py b/src/python/__init__.py new file mode 100644 index 00000000..496da56c --- /dev/null +++ b/src/python/__init__.py @@ -0,0 +1,3 @@ +from pathlib import Path + +MAIN_FOLDER = Path(__file__) From 62bce7dde67b77d6bfe861da70a415a07af1bb70 Mon Sep 17 00:00:00 2001 From: diatlova Date: Fri, 16 Apr 2021 02:40:16 +0300 Subject: [PATCH 20/78] Evaluation tool-interface update --- src/python/evaluation/evaluation_config.py | 33 +++++++++ src/python/evaluation/results/results.xlsx | Bin 0 -> 4761 bytes src/python/evaluation/xlsx_run_tool.py | 81 ++++++++++----------- 3 files changed, 70 insertions(+), 44 deletions(-) create mode 100644 src/python/evaluation/evaluation_config.py create mode 100644 src/python/evaluation/results/results.xlsx diff --git a/src/python/evaluation/evaluation_config.py b/src/python/evaluation/evaluation_config.py new file mode 100644 index 00000000..fd8ad116 --- /dev/null +++ b/src/python/evaluation/evaluation_config.py @@ -0,0 +1,33 @@ +from pathlib import Path + +from src.python import MAIN_FOLDER +from src.python.evaluation.support_functions import create_folder + + +class ApplicationConfig: + def __init__(self, args): + self.tool_path = args.tool_path + self.output_format = args.format + self.data_path = args.data_path + self.traceback = args.traceback + self.folder_path = args.folder_path + self.file_name = args.file_name + + def build_command(self, file_path, lang): + command = ['python3', self.tool_path, file_path, '-f', self.output_format] + if lang == 'java8' or lang == 'java11': + command.extend(['--language_version', lang]) + return command + + def get_data_path(self): + return self.data_path + + def get_traceback(self): + return self.traceback + + def get_file_path(self): + if self.folder_path is None: + self.folder_path = MAIN_FOLDER.parent / 'evaluation/results' + create_folder(self.folder_path) + + return Path(self.folder_path) / self.file_name diff --git a/src/python/evaluation/results/results.xlsx b/src/python/evaluation/results/results.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..5506d9b9bc4d03499e5775fef71c5a0fd4e2ee8d GIT binary patch literal 4761 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 c^Zb{mpTWUDPo4n(2d-x=&j0`b literal 0 HcmV?d00001 diff --git a/src/python/evaluation/xlsx_run_tool.py b/src/python/evaluation/xlsx_run_tool.py index facc51a6..b0ccd3cc 100644 --- a/src/python/evaluation/xlsx_run_tool.py +++ b/src/python/evaluation/xlsx_run_tool.py @@ -14,10 +14,10 @@ from openpyxl import Workbook from src.python import MAIN_FOLDER from src.python.evaluation import ScriptStructureRule -from src.python.evaluation.support_functions import create_folder, remove_sheet +from src.python.evaluation.evaluation_config import ApplicationConfig +from src.python.evaluation.support_functions import remove_sheet from src.python.review.common.subprocess_runner import run_in_subprocess from src.python.review.reviewers.perform_review import OutputFormat -from src.python.review.run_tool import positive_int logger = logging.getLogger(__name__) @@ -34,11 +34,6 @@ def configure_arguments(parser: argparse.ArgumentParser) -> NoReturn: type=lambda value: Path(value).absolute(), help='Path to script to run on files.') - parser.add_argument('--n_cpu', '--n-cpu', - help='Specify number of cpu that can be used to run inspectors.', - default=1, - type=positive_int) - parser.add_argument('--traceback', '--traceback', help='If True – grades are substituted with the full inspector feedback.', default=False, @@ -66,7 +61,7 @@ def configure_arguments(parser: argparse.ArgumentParser) -> NoReturn: 'More details on output format options in README.md') -def main() -> int: +def create_dataframe(config) -> pd.DataFrame: report = pd.DataFrame( { "language": [], @@ -75,58 +70,56 @@ def main() -> int: }, ) - lang_suffixes = {'python3': '.py', 'java8': '.java', 'java11': '.java', 'kotlin': '.kt'} - - parser = argparse.ArgumentParser() - configure_arguments(parser) + dataframe = pd.read_excel(config.get_data_path()) - try: - args = parser.parse_args() - dataframe = pd.read_excel(args.data_path) - temp_dir_path = MAIN_FOLDER.parent / 'evaluation/temporary_files' + temp_dir_path = MAIN_FOLDER.parent / 'evaluation/temporary_files' + lang_suffixes = {'python3': '.py', 'java8': '.java', 'java11': '.java', 'kotlin': '.kt'} - for lang, code in zip(dataframe['lang'], dataframe['code']): - temp_file_path = os.path.join(temp_dir_path, ('file' + lang_suffixes[lang])) + for lang, code in zip(dataframe['lang'], dataframe['code']): + temp_file_path = os.path.join(temp_dir_path, ('file' + lang_suffixes[lang])) - with open(temp_file_path, 'w') as file: - file.writelines(code) + with open(temp_file_path, 'w') as file: + file.writelines(code) - if lang == 'java8' or lang == 'java11': - results = run_in_subprocess([ - 'python3', args.tool_path, temp_file_path, '--language_version', lang]) + command = config.build_command(temp_file_path, lang) + results = run_in_subprocess(command) + os.remove(temp_file_path) - else: - results = run_in_subprocess(['python3', args.tool_path, temp_file_path]) + # this regular expression matches final tool grade: EXCELLENT, GOOD, MODERATE or BAD + regex_match = re.match(r'^.*{"code":\s"([A-Z]+)"', results).group(1) - os.remove(temp_file_path) + output = regex_match + if config.get_traceback(): + output = results - # this regular expression matches final tool grade: EXCELLENT, GOOD, MODERATE or BAD - regex_match = re.match(r'^.*{"code":\s"([A-Z]+)"', results).group(1) + report = report.append(pd.DataFrame( + { + "language": [lang], + "code": [code], + "grade": [output], + }, + )) - output = regex_match - if args.traceback: - output = results + return report - report = report.append(pd.DataFrame( - { - "language": [lang], - "code": [code], - "grade": [output], - }, - )) - folder_path = args.folder_path +def main() -> int: + parser = argparse.ArgumentParser() + configure_arguments(parser) - if folder_path is None: - folder_path = MAIN_FOLDER.parent / 'evaluation/results' - create_folder(folder_path) + try: + args = parser.parse_args() + config = ApplicationConfig(args) workbook = Workbook() - workbook_path = Path(folder_path) / args.file_name + workbook_path = config.get_file_path() workbook.save(workbook_path) + results = create_dataframe(config) + print(results, workbook_path) + with pd.ExcelWriter(workbook_path, engine='openpyxl', mode='a') as writer: - report.to_excel(writer, sheet_name='inspection_results', index=False) + results.to_excel(writer, sheet_name='inspection_results', index=False) # remove empty sheet that was initially created with the workbook remove_sheet(workbook_path, 'Sheet') From 90edf16f7f46c47d2f360e9b140136708488e396 Mon Sep 17 00:00:00 2001 From: diatlova Date: Fri, 16 Apr 2021 02:41:02 +0300 Subject: [PATCH 21/78] Updating evaluation tests --- test/python/evaluation/test_output_results.py | 54 +++++++++---------- .../evaluation/test_remove_temp_files.py | 25 +++++---- test/python/evaluation/test_tool_path.py | 38 ++++++------- test/python/evaluation/testing_config.py | 12 +++++ 4 files changed, 68 insertions(+), 61 deletions(-) create mode 100644 test/python/evaluation/testing_config.py diff --git a/test/python/evaluation/test_output_results.py b/test/python/evaluation/test_output_results.py index ea2159d2..6ba2190b 100644 --- a/test/python/evaluation/test_output_results.py +++ b/test/python/evaluation/test_output_results.py @@ -1,36 +1,36 @@ -import os -import subprocess - -import time -from test.python.evaluation import RESULTS_DIR_PATH, TARGET_XLSX_DATA_FOLDER, XLSX_DATA_FOLDER -from test.python.evaluation.conftest import EvalLocalCommandBuilder +from test.python.evaluation import TARGET_XLSX_DATA_FOLDER, XLSX_DATA_FOLDER +from test.python.evaluation.testing_config import get_parser +from typing import Union import pandas as pd - import pytest +from src.python import MAIN_FOLDER +from src.python.evaluation.evaluation_config import ApplicationConfig +from src.python.evaluation.xlsx_run_tool import create_dataframe + FILE_NAMES = [ - ('test_sorted_order.xlsx', 'target_sorted_order.xlsx', 'grades'), - ('test_sorted_order.xlsx', 'target_sorted_order.xlsx', 'traceback'), - ('test_unsorted_order.xlsx', 'target_unsorted_order.xlsx', 'grades'), - ('test_unsorted_order.xlsx', 'target_unsorted_order.xlsx', 'traceback'), + ('test_sorted_order.xlsx', 'target_sorted_order.xlsx', False), + ('test_sorted_order.xlsx', 'target_sorted_order.xlsx', 'True'), + ('test_unsorted_order.xlsx', 'target_unsorted_order.xlsx', False), + ('test_unsorted_order.xlsx', 'target_unsorted_order.xlsx', 'True'), ] @pytest.mark.parametrize(('test_file', 'target_file', 'output_type'), FILE_NAMES) -def test_correct_output(test_file: str, target_file: str, output_type: str, - eval_command_builder: EvalLocalCommandBuilder): - eval_command_builder.path = XLSX_DATA_FOLDER / test_file - - if output_type == 'traceback': - eval_command_builder.traceback = str(True) - - subprocess.run(eval_command_builder.build()) - # wait before conduct output check as files appear with a delay - time.sleep(180) - test_dataframe = pd.read_excel(RESULTS_DIR_PATH / 'results.xlsx', sheet_name='inspection_results') - target_dataframe = pd.read_excel(TARGET_XLSX_DATA_FOLDER / target_file, sheet_name=output_type) - os.remove(RESULTS_DIR_PATH / 'results.xlsx') - os.rmdir(RESULTS_DIR_PATH) - - assert test_dataframe.equals(target_dataframe) +def test_correct_output(test_file: str, target_file: str, output_type: Union[bool, str]): + + parser = get_parser() + parser.add_argument('-data_path', '--data_path', default=XLSX_DATA_FOLDER / test_file) + parser.add_argument('-t', '--tool_path', default=MAIN_FOLDER.parent / 'review/run_tool.py') + parser.add_argument('--traceback', '--traceback', default=output_type) + args = parser.parse_args([]) + config = ApplicationConfig(args) + test_dataframe = create_dataframe(config) + + sheet = 'grades' + if output_type: + sheet = 'traceback' + + target_dataframe = pd.read_excel(TARGET_XLSX_DATA_FOLDER / target_file, sheet_name=sheet) + assert test_dataframe.reset_index(drop=True).equals(target_dataframe.reset_index(drop=True)) diff --git a/test/python/evaluation/test_remove_temp_files.py b/test/python/evaluation/test_remove_temp_files.py index 2e150086..bbc419a1 100644 --- a/test/python/evaluation/test_remove_temp_files.py +++ b/test/python/evaluation/test_remove_temp_files.py @@ -1,20 +1,19 @@ -import os -import subprocess -import time -from test.python.evaluation import RESULTS_DIR_PATH, XLSX_DATA_FOLDER -from test.python.evaluation.conftest import EvalLocalCommandBuilder +from test.python.evaluation import XLSX_DATA_FOLDER +from test.python.evaluation.testing_config import get_parser from src.python import MAIN_FOLDER +from src.python.evaluation.evaluation_config import ApplicationConfig +from src.python.evaluation.xlsx_run_tool import create_dataframe from src.python.review.common.file_system import get_all_file_system_items -def test_temp_files_remove(eval_command_builder: EvalLocalCommandBuilder): - file_path = XLSX_DATA_FOLDER / 'test_unsorted_order.xlsx' - eval_command_builder.path = file_path - subprocess.run(eval_command_builder.build()) +def test_temp_files_remove(): + parser = get_parser() + parser.add_argument('-data_path', '--data_path', default=XLSX_DATA_FOLDER / 'test_sorted_order.xlsx') + parser.add_argument('-t', '--tool_path', default=MAIN_FOLDER.parent / 'review/run_tool.py') + parser.add_argument('--traceback', '--traceback', default=False) + args = parser.parse_args([]) + config = ApplicationConfig(args) + create_dataframe(config) temporary_files = get_all_file_system_items(MAIN_FOLDER.parent / 'evaluation/temporary_files') assert temporary_files == [] - # wait before deleting file and directory as they appear with a delay - time.sleep(180) - os.remove(RESULTS_DIR_PATH / 'results.xlsx') - os.rmdir(RESULTS_DIR_PATH) diff --git a/test/python/evaluation/test_tool_path.py b/test/python/evaluation/test_tool_path.py index 3f33b264..5cbf5956 100644 --- a/test/python/evaluation/test_tool_path.py +++ b/test/python/evaluation/test_tool_path.py @@ -1,25 +1,21 @@ -import os import subprocess -import time -from test.python.evaluation import RESULTS_DIR_PATH, XLSX_DATA_FOLDER -from test.python.evaluation.conftest import BrokenLocalCommandBuilder, EvalLocalCommandBuilder - - -def test_correct_tool_path(eval_command_builder: EvalLocalCommandBuilder): - file_path = XLSX_DATA_FOLDER / 'test_unsorted_order.xlsx' - - eval_command_builder.path = file_path - process = subprocess.run( - eval_command_builder.build(), - stderr=subprocess.PIPE, - stdout=subprocess.PIPE, - ) - - assert process.returncode == 0 - # wait before deleting file and directory as they appear with a delay - time.sleep(180) - os.remove(RESULTS_DIR_PATH / 'results.xlsx') - os.rmdir(RESULTS_DIR_PATH) +from test.python.evaluation import XLSX_DATA_FOLDER +from test.python.evaluation.testing_config import get_parser +from test.python.evaluation.conftest import BrokenLocalCommandBuilder + +from src.python import MAIN_FOLDER +from src.python.evaluation.evaluation_config import ApplicationConfig +from src.python.evaluation.xlsx_run_tool import create_dataframe + + +def test_correct_tool_path(): + parser = get_parser() + parser.add_argument('-data_path', '--data_path', default=XLSX_DATA_FOLDER / 'test_unsorted_order.xlsx') + parser.add_argument('-t', '--tool_path', default=MAIN_FOLDER.parent / 'review/run_tool.py') + parser.add_argument('--traceback', '--traceback', default=False) + args = parser.parse_args([]) + config = ApplicationConfig(args) + create_dataframe(config) def test_incorrect_tool_path(broken_command_builder: BrokenLocalCommandBuilder): diff --git a/test/python/evaluation/testing_config.py b/test/python/evaluation/testing_config.py new file mode 100644 index 00000000..16e95e3e --- /dev/null +++ b/test/python/evaluation/testing_config.py @@ -0,0 +1,12 @@ +import argparse +from typing import NoReturn + +from src.python.review.reviewers.perform_review import OutputFormat + + +def get_parser() -> NoReturn: + parser = argparse.ArgumentParser() + parser.add_argument('--folder_path', '--folder_path', default=None) + parser.add_argument('--file_name', '--file_name', default='results.xlsx') + parser.add_argument('-f', '--format', default=OutputFormat.JSON.value) + return parser From c0eeed2d7f0eb791c3a0e2ffbfecbb9893b666a2 Mon Sep 17 00:00:00 2001 From: diatlova Date: Fri, 16 Apr 2021 10:14:33 +0300 Subject: [PATCH 22/78] Change mode for opening file --- src/python/evaluation/results/results.xlsx | Bin 4761 -> 0 bytes src/python/evaluation/xlsx_run_tool.py | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) delete mode 100644 src/python/evaluation/results/results.xlsx diff --git a/src/python/evaluation/results/results.xlsx b/src/python/evaluation/results/results.xlsx deleted file mode 100644 index 5506d9b9bc4d03499e5775fef71c5a0fd4e2ee8d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4761 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 c^Zb{mpTWUDPo4n(2d-x=&j0`b diff --git a/src/python/evaluation/xlsx_run_tool.py b/src/python/evaluation/xlsx_run_tool.py index b0ccd3cc..c90aa823 100644 --- a/src/python/evaluation/xlsx_run_tool.py +++ b/src/python/evaluation/xlsx_run_tool.py @@ -78,7 +78,7 @@ def create_dataframe(config) -> pd.DataFrame: for lang, code in zip(dataframe['lang'], dataframe['code']): temp_file_path = os.path.join(temp_dir_path, ('file' + lang_suffixes[lang])) - with open(temp_file_path, 'w') as file: + with open(temp_file_path, 'w+') as file: file.writelines(code) command = config.build_command(temp_file_path, lang) From 7439faa84448b5f789515e1562e607902870adc1 Mon Sep 17 00:00:00 2001 From: diatlova Date: Fri, 16 Apr 2021 10:32:28 +0300 Subject: [PATCH 23/78] Adding file exist exception --- src/python/evaluation/xlsx_run_tool.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/python/evaluation/xlsx_run_tool.py b/src/python/evaluation/xlsx_run_tool.py index c90aa823..026f6d87 100644 --- a/src/python/evaluation/xlsx_run_tool.py +++ b/src/python/evaluation/xlsx_run_tool.py @@ -78,6 +78,12 @@ def create_dataframe(config) -> pd.DataFrame: for lang, code in zip(dataframe['lang'], dataframe['code']): temp_file_path = os.path.join(temp_dir_path, ('file' + lang_suffixes[lang])) + try: + assert os.path.exists(temp_file_path) + except AssertionError: + logger.exception('Path does not exist.') + return 2 + with open(temp_file_path, 'w+') as file: file.writelines(code) From 46412762d8fdb0caf63b7f9ee08b1230877a1f07 Mon Sep 17 00:00:00 2001 From: diatlova Date: Fri, 16 Apr 2021 12:32:04 +0300 Subject: [PATCH 24/78] Assertation update --- src/python/evaluation/xlsx_run_tool.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/python/evaluation/xlsx_run_tool.py b/src/python/evaluation/xlsx_run_tool.py index 026f6d87..e085fcd8 100644 --- a/src/python/evaluation/xlsx_run_tool.py +++ b/src/python/evaluation/xlsx_run_tool.py @@ -78,16 +78,17 @@ def create_dataframe(config) -> pd.DataFrame: for lang, code in zip(dataframe['lang'], dataframe['code']): temp_file_path = os.path.join(temp_dir_path, ('file' + lang_suffixes[lang])) - try: - assert os.path.exists(temp_file_path) - except AssertionError: - logger.exception('Path does not exist.') - return 2 - with open(temp_file_path, 'w+') as file: file.writelines(code) + try: + assert os.path.exists(temp_file_path) + + except AssertionError: + logger.exception('Path does not exist.') + return 2 + + command = config.build_command(temp_file_path, lang) - command = config.build_command(temp_file_path, lang) results = run_in_subprocess(command) os.remove(temp_file_path) From 685d0bb9f78af3a68729056602f59a0ccfc45197 Mon Sep 17 00:00:00 2001 From: diatlova Date: Fri, 16 Apr 2021 13:02:06 +0300 Subject: [PATCH 25/78] Adding gitkeep --- test/python/evaluation/test_remove_temp_files.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/python/evaluation/test_remove_temp_files.py b/test/python/evaluation/test_remove_temp_files.py index bbc419a1..cdb8900f 100644 --- a/test/python/evaluation/test_remove_temp_files.py +++ b/test/python/evaluation/test_remove_temp_files.py @@ -16,4 +16,4 @@ def test_temp_files_remove(): config = ApplicationConfig(args) create_dataframe(config) temporary_files = get_all_file_system_items(MAIN_FOLDER.parent / 'evaluation/temporary_files') - assert temporary_files == [] + assert temporary_files == [MAIN_FOLDER.parent / 'evaluation/temporary_files/.gitkeep'] From 296efac2f7618d21f7e3070ab90ad7f86e8a8d77 Mon Sep 17 00:00:00 2001 From: diatlova Date: Fri, 16 Apr 2021 13:02:49 +0300 Subject: [PATCH 26/78] Adiing gitkeep --- src/python/evaluation/temporary_files/.gitkeep | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/python/evaluation/temporary_files/.gitkeep diff --git a/src/python/evaluation/temporary_files/.gitkeep b/src/python/evaluation/temporary_files/.gitkeep new file mode 100644 index 00000000..e69de29b From 6acc24622791fccdfeaff168e3f60fb0d74c4777 Mon Sep 17 00:00:00 2001 From: diatlova Date: Sat, 17 Apr 2021 20:50:47 +0300 Subject: [PATCH 27/78] Fixed typing issue --- test/python/evaluation/testing_config.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/test/python/evaluation/testing_config.py b/test/python/evaluation/testing_config.py index 16e95e3e..878cff3d 100644 --- a/test/python/evaluation/testing_config.py +++ b/test/python/evaluation/testing_config.py @@ -1,10 +1,8 @@ import argparse -from typing import NoReturn - from src.python.review.reviewers.perform_review import OutputFormat -def get_parser() -> NoReturn: +def get_parser() -> argparse.ArgumentParser: parser = argparse.ArgumentParser() parser.add_argument('--folder_path', '--folder_path', default=None) parser.add_argument('--file_name', '--file_name', default='results.xlsx') From fe4877f8be8f678b83ceab6848e678f79a4f1f88 Mon Sep 17 00:00:00 2001 From: diatlova Date: Sat, 17 Apr 2021 20:51:19 +0300 Subject: [PATCH 28/78] Resolving conflicts --- requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/requirements.txt b/requirements.txt index 325e241a..bed20794 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -setuptools~=47.3.1 +setuptools~=56.0.0 # python code analysis tools pylint==2.5.3 @@ -25,8 +25,8 @@ cohesion==1.0.0 radon==4.5.0 # extra libraries and frameworks -django==3.0.8 -requests==2.24.0 +django==3.2 +requests==2.25.1 argparse~=1.4.0 pandas~=1.2.3 openpyxl~=3.0.7 \ No newline at end of file From 8082f78c57ed35b494c05d605bea0dada107a8ad Mon Sep 17 00:00:00 2001 From: Ilya Vlasov <55441714+GirZ0n@users.noreply.github.com> Date: Sun, 18 Apr 2021 16:22:05 +0300 Subject: [PATCH 29/78] Fixed imports --- test/python/evaluation/testing_config.py | 1 + 1 file changed, 1 insertion(+) diff --git a/test/python/evaluation/testing_config.py b/test/python/evaluation/testing_config.py index 878cff3d..a5cb17d1 100644 --- a/test/python/evaluation/testing_config.py +++ b/test/python/evaluation/testing_config.py @@ -1,4 +1,5 @@ import argparse + from src.python.review.reviewers.perform_review import OutputFormat From ab62d8a2ed55fab219de28b30526dd13764085a4 Mon Sep 17 00:00:00 2001 From: Ilya Vlasov <55441714+GirZ0n@users.noreply.github.com> Date: Sun, 18 Apr 2021 16:25:05 +0300 Subject: [PATCH 30/78] Fixed imports --- test/python/evaluation/test_tool_path.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/python/evaluation/test_tool_path.py b/test/python/evaluation/test_tool_path.py index 5cbf5956..c0166da5 100644 --- a/test/python/evaluation/test_tool_path.py +++ b/test/python/evaluation/test_tool_path.py @@ -1,7 +1,7 @@ import subprocess from test.python.evaluation import XLSX_DATA_FOLDER -from test.python.evaluation.testing_config import get_parser from test.python.evaluation.conftest import BrokenLocalCommandBuilder +from test.python.evaluation.testing_config import get_parser from src.python import MAIN_FOLDER from src.python.evaluation.evaluation_config import ApplicationConfig From b8d615612b8ca0daef7ec3e57423d1c1cc595cd1 Mon Sep 17 00:00:00 2001 From: diatlova Date: Wed, 21 Apr 2021 21:15:33 +0300 Subject: [PATCH 31/78] Updated evaluation module --- src/python/evaluation/__init__.py | 8 -- .../.gitkeep => common/__init__.py} | 0 src/python/evaluation/common/util.py | 33 +++++ src/python/evaluation/common/xlsx_util.py | 28 +++++ src/python/evaluation/evaluation_config.py | 55 +++++---- src/python/evaluation/support_functions.py | 22 ---- src/python/evaluation/xlsx_run_tool.py | 116 +++++++++--------- .../evaluation/test_remove_temp_files.py | 19 --- .../xlsx_files/test_sorted_order.xlsx | Bin 6418 -> 0 bytes .../target_sorted_order.xlsx | Bin 31483 -> 0 bytes .../target_unsorted_order.xlsx | Bin 30873 -> 0 bytes 11 files changed, 151 insertions(+), 130 deletions(-) rename src/python/evaluation/{temporary_files/.gitkeep => common/__init__.py} (100%) create mode 100644 src/python/evaluation/common/util.py create mode 100644 src/python/evaluation/common/xlsx_util.py delete mode 100644 src/python/evaluation/support_functions.py delete mode 100644 test/python/evaluation/test_remove_temp_files.py delete mode 100644 test/resources/evaluation/xlsx_files/test_sorted_order.xlsx delete mode 100644 test/resources/evaluation/xlsx_target_files/target_sorted_order.xlsx delete mode 100644 test/resources/evaluation/xlsx_target_files/target_unsorted_order.xlsx diff --git a/src/python/evaluation/__init__.py b/src/python/evaluation/__init__.py index a68f28dd..e69de29b 100644 --- a/src/python/evaluation/__init__.py +++ b/src/python/evaluation/__init__.py @@ -1,8 +0,0 @@ -ScriptStructureRule = ("Please, make sure your XLSX-file matches following script standards: \n" - "1. Your XLSX-file should have 2 obligatory columns named: \"lang\" & \"code\". \n" - "\"code\" column -- relates to the code-sample. \n" - "\"lang\" column -- relates to the language of a particular code-sample. \n" - "2. Your code samples should belong to the one of the supported languages. \n" - "Supported languages are: Java, Kotlin, Python. \n" - "3. Check that \"lang\" column cells are filled with acceptable language-names: \n" - "Acceptable language-names are: \"python3\", \"java8\", \"java11\" and \"kotlin\".") diff --git a/src/python/evaluation/temporary_files/.gitkeep b/src/python/evaluation/common/__init__.py similarity index 100% rename from src/python/evaluation/temporary_files/.gitkeep rename to src/python/evaluation/common/__init__.py diff --git a/src/python/evaluation/common/util.py b/src/python/evaluation/common/util.py new file mode 100644 index 00000000..02b2bc93 --- /dev/null +++ b/src/python/evaluation/common/util.py @@ -0,0 +1,33 @@ +from enum import Enum +from typing import List + +from src.python.review.application_config import LanguageVersion + + +class EvaluationProcessNames(Enum): + CODE = "code" + LANG = "lang" + LANGUAGE = "language" + GRADE = "grade" + TRACEBACK = "traceback" + RESULTS = "results" + RESULTS_EXT = "results.xlsx" + + @classmethod + def values(cls) -> List[str]: + return [member.value for member in cls.__members__.values()] + + +script_structure_rule = ("Please, make sure your XLSX-file matches following script standards: \n" + "1. Your XLSX-file should have 2 obligatory columns named:" + f"'{EvaluationProcessNames.CODE.value}' & '{EvaluationProcessNames.LANG.value}'. \n" + f"'{EvaluationProcessNames.CODE.value}' column -- relates to the code-sample. \n" + f"'{EvaluationProcessNames.LANG.value}' column -- relates to the language of a " + "particular code-sample. \n" + "2. Your code samples should belong to the one of the supported languages. \n" + "Supported languages are: Java, Kotlin, Python. \n" + f"3. Check that '{EvaluationProcessNames.LANG.value}' column cells are filled with " + "acceptable language-names: \n" + f"Acceptable language-names are: {LanguageVersion.PYTHON_3.value}, " + f"{LanguageVersion.JAVA_8.value} ," + f"{LanguageVersion.JAVA_11.value} and {LanguageVersion.KOTLIN.value}.") diff --git a/src/python/evaluation/common/xlsx_util.py b/src/python/evaluation/common/xlsx_util.py new file mode 100644 index 00000000..5ec2ed20 --- /dev/null +++ b/src/python/evaluation/common/xlsx_util.py @@ -0,0 +1,28 @@ +import logging.config +from pathlib import Path +from typing import NoReturn, Union + +import pandas as pd +from openpyxl import load_workbook + +logger = logging.getLogger(__name__) + + +def remove_sheet(workbook_path: Union[str, Path], sheet_name: str, not_exist_ok=True) -> NoReturn: + try: + workbook = load_workbook(workbook_path) + workbook.remove(workbook[sheet_name]) + workbook.save(workbook_path) + except KeyError: + # if not_exist_ok=True – do not raise KeyError if sheet does not exist + if not_exist_ok: + pass + else: + logger.exception(f'Sheet with specified name: {sheet_name} does not exist.') + + +def write_dataframe_to_xlsx_sheet(xlsx_file_path: Union[str, Path], context_dataframe: pd.DataFrame, + sheet_name: str, engine: str, mode='a', index=False): + + with pd.ExcelWriter(xlsx_file_path, engine=engine, mode=mode) as writer: + context_dataframe.to_excel(writer, sheet_name=sheet_name, index=index) diff --git a/src/python/evaluation/evaluation_config.py b/src/python/evaluation/evaluation_config.py index fd8ad116..4ba09fec 100644 --- a/src/python/evaluation/evaluation_config.py +++ b/src/python/evaluation/evaluation_config.py @@ -1,33 +1,36 @@ from pathlib import Path +from typing import List, Union -from src.python import MAIN_FOLDER -from src.python.evaluation.support_functions import create_folder +from src.python.common.tool_arguments import RunToolArguments +from src.python.evaluation.common.util import EvaluationProcessNames +from src.python.review.application_config import LanguageVersion +from src.python.review.common.file_system import create_directory -class ApplicationConfig: +class EvaluationConfig: def __init__(self, args): - self.tool_path = args.tool_path - self.output_format = args.format - self.data_path = args.data_path - self.traceback = args.traceback - self.folder_path = args.folder_path - self.file_name = args.file_name - - def build_command(self, file_path, lang): - command = ['python3', self.tool_path, file_path, '-f', self.output_format] - if lang == 'java8' or lang == 'java11': - command.extend(['--language_version', lang]) + self.tool_path: Union[str, Path] = args.tool_path + self.output_format: str = args.format + self.xlsx_file_path: Union[str, Path] = args.xlsx_file_path + self.traceback: bool = args.traceback + self.output_folder_path: Union[str, Path] = args.output_folder_path + self.output_file_name: str = args.output_file_name + + def build_command(self, inspected_file_path: Union[str, Path], lang: str, + run_tool_arguments=RunToolArguments) -> List[str]: + + command = [LanguageVersion.PYTHON_3.value, + self.tool_path, + inspected_file_path, + run_tool_arguments.FORMAT.value.short_name, self.output_format] + + if lang == LanguageVersion.JAVA_8.value or lang == LanguageVersion.JAVA_11.value: + command.extend([run_tool_arguments.LANG_VERSION.value.short_name, lang]) return command - def get_data_path(self): - return self.data_path - - def get_traceback(self): - return self.traceback - - def get_file_path(self): - if self.folder_path is None: - self.folder_path = MAIN_FOLDER.parent / 'evaluation/results' - create_folder(self.folder_path) - - return Path(self.folder_path) / self.file_name + def get_file_path(self) -> Path: + if self.output_folder_path is None: + self.output_folder_path = ( + Path(self.xlsx_file_path).parent.parent / EvaluationProcessNames.RESULTS.value) + create_directory(self.output_folder_path) + return Path(self.output_folder_path) / self.output_file_name diff --git a/src/python/evaluation/support_functions.py b/src/python/evaluation/support_functions.py deleted file mode 100644 index 1b6fc82b..00000000 --- a/src/python/evaluation/support_functions.py +++ /dev/null @@ -1,22 +0,0 @@ -import os -from pathlib import Path -from typing import NoReturn, Union - -from openpyxl import load_workbook - - -def create_folder(directory: Union[str, Path]) -> NoReturn: - try: - if not os.path.exists(directory): - os.makedirs(directory) - except OSError: - pass - - -def remove_sheet(path: str, name: str) -> NoReturn: - file = load_workbook(path) - try: - file.remove(file[name]) - file.save(path) - except KeyError: - pass diff --git a/src/python/evaluation/xlsx_run_tool.py b/src/python/evaluation/xlsx_run_tool.py index e085fcd8..90ac3c5b 100644 --- a/src/python/evaluation/xlsx_run_tool.py +++ b/src/python/evaluation/xlsx_run_tool.py @@ -1,136 +1,142 @@ import argparse +import enum import logging.config import os import re import sys import traceback from pathlib import Path -from typing import NoReturn +from typing import NoReturn, Union sys.path.append('') sys.path.append('../../..') import pandas as pd from openpyxl import Workbook -from src.python import MAIN_FOLDER -from src.python.evaluation import ScriptStructureRule -from src.python.evaluation.evaluation_config import ApplicationConfig -from src.python.evaluation.support_functions import remove_sheet +from src.python.common.tool_arguments import RunToolArguments +from src.python.evaluation.common.util import EvaluationProcessNames, script_structure_rule +from src.python.evaluation.common.xlsx_util import remove_sheet, write_dataframe_to_xlsx_sheet +from src.python.evaluation.evaluation_config import EvaluationConfig +from src.python.review.application_config import LanguageVersion +from src.python.review.common.file_system import create_file, new_temp_dir from src.python.review.common.subprocess_runner import run_in_subprocess from src.python.review.reviewers.perform_review import OutputFormat logger = logging.getLogger(__name__) -def configure_arguments(parser: argparse.ArgumentParser) -> NoReturn: - parser.add_argument('data_path', +def configure_arguments(parser: argparse.ArgumentParser, run_tool_arguments: enum.EnumMeta) -> NoReturn: + parser.add_argument('xlsx_file_path', type=lambda value: Path(value).absolute(), help='Local XLSX-file path. ' - 'Your XLSX-file must include column-names: \"code\" and \"lang. ' - 'Acceptable values for \"lang\" column are: python3, java8, java11, kotlin.') - - parser.add_argument('-t', '--tool_path', + 'Your XLSX-file must include column-names: ' + f'"{EvaluationProcessNames.CODE.value}" and ' + f'"{EvaluationProcessNames.LANG.value}". Acceptable values for ' + f'"{EvaluationProcessNames.LANG.value}" column are: ' + f'{LanguageVersion.PYTHON_3.value}, {LanguageVersion.JAVA_8.value}, ' + f'{LanguageVersion.JAVA_11.value}, {LanguageVersion.KOTLIN.value}.') + + parser.add_argument('-tool_path', '--tool_path', default=Path('src/python/review/run_tool.py').absolute(), type=lambda value: Path(value).absolute(), help='Path to script to run on files.') parser.add_argument('--traceback', '--traceback', - help='If True – grades are substituted with the full inspector feedback.', + help='If True, column with the full inspector feedback will be added ' + 'to the output file with results.', default=False, type=bool) - parser.add_argument('--folder_path', '--folder_path', + parser.add_argument('--output_folder_path', '--output_folder_path', help='An absolute path to the folder where file with evaluation results' 'will be stored.' - 'Default is \"hyperstyle/src/python/evaluation/results\"', + 'Default is the path to a directory, where is the folder with xlsx_file.', + # if None default path will be specified based on xlsx_file_path. default=None, type=str) - parser.add_argument('--file_name', '--file_name', + parser.add_argument('--output_file_name', '--output_file_name', help='Filename for that will be created to store inspection results.' - 'Default is \"results.xlsx\"', - default='results.xlsx', + f'Default is "{EvaluationProcessNames.RESULTS_EXT.value}"', + default=f'{EvaluationProcessNames.RESULTS_EXT.value}', type=str) - parser.add_argument('-f', '--format', + parser.add_argument(run_tool_arguments.FORMAT.value.short_name, + run_tool_arguments.FORMAT.value.long_name, default=OutputFormat.JSON.value, choices=OutputFormat.values(), type=str, - help='The output format of inspectors traceback. ' - 'Default is JSON.' - 'More details on output format options in README.md') + help=run_tool_arguments.FORMAT.value.description) -def create_dataframe(config) -> pd.DataFrame: +def create_dataframe(config) -> Union[int, pd.DataFrame]: report = pd.DataFrame( { - "language": [], - "code": [], - "grade": [], + EvaluationProcessNames.LANGUAGE.value: [], + EvaluationProcessNames.CODE.value: [], + EvaluationProcessNames.GRADE.value: [], }, ) - dataframe = pd.read_excel(config.get_data_path()) + if config.traceback: + report[EvaluationProcessNames.TRACEBACK.value] = [] + + lang_code_dataframe = pd.read_excel(config.xlsx_file_path) - temp_dir_path = MAIN_FOLDER.parent / 'evaluation/temporary_files' - lang_suffixes = {'python3': '.py', 'java8': '.java', 'java11': '.java', 'kotlin': '.kt'} + for lang, code in zip(lang_code_dataframe[EvaluationProcessNames.LANG.value], + lang_code_dataframe[EvaluationProcessNames.CODE.value]): - for lang, code in zip(dataframe['lang'], dataframe['code']): - temp_file_path = os.path.join(temp_dir_path, ('file' + lang_suffixes[lang])) + with new_temp_dir() as create_temp_dir: + temp_dir_path = create_temp_dir + lang_extension = LanguageVersion.language_extension()[lang] + temp_file_path = os.path.join(temp_dir_path, ('file' + lang_extension)) + temp_file_path = next(create_file(temp_file_path, code)) - with open(temp_file_path, 'w+') as file: - file.writelines(code) try: assert os.path.exists(temp_file_path) - except AssertionError: logger.exception('Path does not exist.') return 2 command = config.build_command(temp_file_path, lang) - - results = run_in_subprocess(command) - os.remove(temp_file_path) + results = run_in_subprocess(command) + os.remove(temp_file_path) + temp_dir_path.rmdir() # this regular expression matches final tool grade: EXCELLENT, GOOD, MODERATE or BAD - regex_match = re.match(r'^.*{"code":\s"([A-Z]+)"', results).group(1) + grades = re.match(r'^.*{"code":\s"([A-Z]+)"', results).group(1) - output = regex_match - if config.get_traceback(): - output = results + output_row_values = [lang, code, grades] + column_indices = [EvaluationProcessNames.LANGUAGE.value, EvaluationProcessNames.CODE.value, + EvaluationProcessNames.GRADE.value] - report = report.append(pd.DataFrame( - { - "language": [lang], - "code": [code], - "grade": [output], - }, - )) + if config.traceback: + output_row_values.append(results) + column_indices.append(EvaluationProcessNames.TRACEBACK.value) + + new_file_report_row = pd.Series(data=output_row_values, index=column_indices) + report = report.append(new_file_report_row, ignore_index=True) return report def main() -> int: parser = argparse.ArgumentParser() - configure_arguments(parser) + configure_arguments(parser, RunToolArguments) try: args = parser.parse_args() - config = ApplicationConfig(args) + config = EvaluationConfig(args) workbook = Workbook() workbook_path = config.get_file_path() workbook.save(workbook_path) results = create_dataframe(config) - print(results, workbook_path) - - with pd.ExcelWriter(workbook_path, engine='openpyxl', mode='a') as writer: - results.to_excel(writer, sheet_name='inspection_results', index=False) + write_dataframe_to_xlsx_sheet(workbook_path, results, 'inspection_results', 'openpyxl') # remove empty sheet that was initially created with the workbook remove_sheet(workbook_path, 'Sheet') - return 0 except FileNotFoundError: @@ -138,7 +144,7 @@ def main() -> int: return 2 except KeyError: - logger.error(ScriptStructureRule) + logger.error(script_structure_rule) return 2 except Exception: diff --git a/test/python/evaluation/test_remove_temp_files.py b/test/python/evaluation/test_remove_temp_files.py deleted file mode 100644 index cdb8900f..00000000 --- a/test/python/evaluation/test_remove_temp_files.py +++ /dev/null @@ -1,19 +0,0 @@ -from test.python.evaluation import XLSX_DATA_FOLDER -from test.python.evaluation.testing_config import get_parser - -from src.python import MAIN_FOLDER -from src.python.evaluation.evaluation_config import ApplicationConfig -from src.python.evaluation.xlsx_run_tool import create_dataframe -from src.python.review.common.file_system import get_all_file_system_items - - -def test_temp_files_remove(): - parser = get_parser() - parser.add_argument('-data_path', '--data_path', default=XLSX_DATA_FOLDER / 'test_sorted_order.xlsx') - parser.add_argument('-t', '--tool_path', default=MAIN_FOLDER.parent / 'review/run_tool.py') - parser.add_argument('--traceback', '--traceback', default=False) - args = parser.parse_args([]) - config = ApplicationConfig(args) - create_dataframe(config) - temporary_files = get_all_file_system_items(MAIN_FOLDER.parent / 'evaluation/temporary_files') - assert temporary_files == [MAIN_FOLDER.parent / 'evaluation/temporary_files/.gitkeep'] diff --git a/test/resources/evaluation/xlsx_files/test_sorted_order.xlsx b/test/resources/evaluation/xlsx_files/test_sorted_order.xlsx deleted file mode 100644 index 6cb55179e62d16a576622b5c63c120662f4c8f37..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6418 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 diff --git a/test/resources/evaluation/xlsx_target_files/target_sorted_order.xlsx b/test/resources/evaluation/xlsx_target_files/target_sorted_order.xlsx deleted file mode 100644 index e24e867ad3fd8fb4cef7213fd7ecd95cbe54b55d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 31483 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 K9v07UpZ*_lgf_4M diff --git a/test/resources/evaluation/xlsx_target_files/target_unsorted_order.xlsx b/test/resources/evaluation/xlsx_target_files/target_unsorted_order.xlsx deleted file mode 100644 index a43f5a94d330405ec45e45ada86dfcf264152e95..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 30873 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

5-SWL$ zer1tz7G`{ljlcw-b0H2dAd1gZKekb}*fT`bhZqP^7 zCk>raA7-+=BthmQdETd^-Kg#!I#_pGO80g7+{+Oir`XD!B@zY?s-Wmn9NKI0?Mh#g zeTCcFwML0}o{4{G4a`i-q6F5M4pbdyM{@GQ2S1TpdwMqt+ZbHpc%!eBS{l16L)`?6 zmKQ0YWM>f4sia2O@OT$z((?;?e3l5*Qt;~i6P6GiVBxK7^qv!MUZ!{IXz91!!vlAwv z=#DsKL?ph`%6wh~JyL9;$G((6E*?+KWA>i)My{ma^F+DVcDH?R5J_g9zsoB8Mjg+O zvoTK~O2Y774EunwlbipikEXD?n}9wBYl9TkOV`Ms+c4J4tC@P(G^7?j z$2;Xe#$&~OT(EG_L6d<#_|aWCOLJC5bp#@+>sa?AAuHju((RYSX5~ok3ctvWam6yd z*R|J~<+ffix11NDW0FZFtS`^trckrVwKzOSQf$oBip)qCoaP2@D_$8R{zN$=e80>t zf@9(1cDFt!SeOeBhu$w8UtPxumvN>zgNAx`w|BQ++aW|)1*-5xkMps$b(YugM4C+0 zt93bdchobUNq*T0RgwpQhsp+zx^SJFF13TjBEvdHw6CPSD<0HHX^ndt?8uzty?kEL zWp~-Uh~$0mdWL1S6w1Q1_fmSmBg^eamc^G9SY`u=Ofsi2vkY%b2W9Ukeeu8Fsr4rI zt#MFp=xPR7e)@5Bl~G)kHiuKPc*-Yg%_J;d;80>TRE=pgT~#SMH=ndEmLg5zfV9eLH^ zy!uv&#;|&swUbc4NdNp?GKo*3m+z0B3Rr32Kc?g`tdk~>?5lXxUwn~-;lkFSKCQ*+ zQ-GJ$?q$9@x+H*R#9s<biqk)@TpdrGhl!-;j!MT+&5ook>dSB}8a<-F0Fpy0A7#3l5$mVrc;Te*Zu(Ug)? zPV&Re14WXZk8#4KQ4Tl9Z_i-y8G7g)rPto&y)N(g{5Zr_!D^6h&KcrEd!c58ffuLB&W&ZV~|K4L~AY-w<9&O_(LnDDO# z66bk=PF~UG13YxyQ8k$iT?7h8)Ne@NzYm^JJ#2y>-Q?OqPQ0GuFU*l7e^i)=fABV`4 zGa-P!swY^#jr?gh2eYaq-pXqDL@KxutiQFd`QgHb*#4CU+CaKnNwOMVik|syC{8%!;*?~s=|WZBFw2+GR?91w-%PUf?oZ#Dnxv~6 zA!ZF~svTF1!A>grBotp&b*Vz{#(9zskCq{20WLSK4s6CcXa#`Y%AWO_|6wK=6GG-o z_8yI;u5qD%&M*w$+HI_gFtn!@)pQa$P>*Vw^{B)cq<7c94R$oTIH$Tw$>DR6sFz{| zj&fAOAf1-4MGDdJz987XZ0o0@*aC}vj6EnLnkyogsX#?(BHM)=8QA2Oe97c|;{5V0kVrXMZg<4BLCEQe#sg~|k_e$&kJmz8zdgmdTIT99#_xA!jGy&&;I&9(MN5(5 z##FctT;qOah4+j(J7a-N!F68#2-tE_jI5w!LyG@)qiuZK=^pve+__QlnoCm=B-$Y^9k`U?dNf zOQ)hhjqjP(CJ0R^XCt1!agED)mV`?F5|4Pst4MX@(%j^Q#BE!U;nD=Rz(6}0fh?M= z_^Gc%yD=@f%TXuOp6We+Bf;s3;5^hqr_uqkr751pv{3nj1LpkKf%LSok2Wqo7S^Q1 z9}T1l|1yxab2c;hHiDjf)@d=${_R<{$yK&XE*Kb2_7<1CzAT{XK_OUNO|0q?W8$Nu zV9miX#nZzLuJvT@T@;#2Qy* zqY$|~y_aW|^i0AvAXd#dc{b#R!sJbt6cRg_w<4oL-0OCRS`Gaw=1de@Eay`JzA5#G z2JEjdUBOU}D-y3g7}A#=tiGxryK#GKU>?=sl^kw!x066pG|Af`>AB_u-2Cy~f^+^f zD@@H_JQSQ{it|vEGPMt-FkT<=^<=VpbvBF`;w6$EX*my48u+^tird>*OIab5X-Ps~ zExGRw#zXb7oN!F0XgTjQ@EwHkq}pR=_EbeVp8I52K6L$Dc7;gaqG_DYNae$PInrpe z$-%o%v*iM~Le?xEn&vzC24*(5YH8n>rHmxr?M{lR%9ptRUb%)^Oed^`_lw}$6(3D= zzlP*^k;4Y!#b`_nbVxLp?bLpY&V6&vAd4LmJ5#;3nnAURa>nv$Cu=G{@C3BB#JqPfI$mF-ituAFH)5*@lkeU4U6R+x@M~l@%}9xxly& zWg+C(6Aj;$T_29)Ysu_=@Hi4%wQ1Xmol5UvtQfAyTQ;5S^=PH4r)6Z<*UzPSk**HL zCy-~R2Cfj?q8j>;oxiTk6v~+OLN}Y)>EQtBLvO7#sVnt&gOfxlovFBq?H@0{30Y!_4x)U-{2TDYz$UJtbTT(j?I;kbIjYX2_eJb>e%*KzsMEL_qM z_ST{gBSy^Mhr|R`z!XQW)U0An*<;PqyokT^c;r6bvLU65$wginJaN0V3WP-L!+wP31=A4CQ4jnMO{t908UZYufstgFMdWH8N==IJz9_yW z{Aew3?RNOMUbd7nnK(;YLEb^0^Jb*vl$o$x*HqIHjd^<{^JjuQ5zX=Y^Mxl_tFGMw z((ep{Deh1CERLU=>=NX^WuJdnv&-VEn!Fv9?Rus8-Q`zbt~zM9$a!^3UG9IA7Mc5+ z=_NQ6*&G6L@`&zq;G4I|BJJLH$HjEEr)851r14P|ft7ABe-ybCRdC_MVVD3+nyk4h z7Ah5^zcpAnONje2J?S0fo;pMt_t;NEbt_iatfy&$1#j1@V4EB(@d3^%E$6k;;OcsI zSw7s-2KJ98M4vZ^U-3DK>;^w!h`uLw7722lR#)%E+h|6Gbsy5pZKI1l@Uu(vtRrEL zG^0E-dy4%by=T`k)-T+C<1-^%&g6_w358z%m!lo?`bv)i6Xb5|QwF)d$N^XQ-3tki z;;MERPc8FjxvbgUbKnFzX=!6yNmO8LakH>OD>7x!Hbw3ebZS!1jJ&=UNWjpG%SfVh~;WwAMEw)sgsgSAHCySsSRcUqC_&!pO` zYP+Kp>^rYMR|>RqitUQd*nLJLsRToLov3^HPtx}+vg~+ezI-vhr-KgSBwzD0pD(!c zq0Dl35?T}gbXz#1epy>;_hPe3zy;IXNdgMP^5AMmb2e#{PfRhP&E+O~mBq5W2?Vh& zOdn3H&E2bBcU4(mr2l*)HGh_p`#+ zCDLjfeTOlIN6hi@?*|>_6cZ`^?8vGDzM%L}X{6O3pEpi<){0vN% z7oLQa0xv`@uyX5R$5!U0meU1P_%NRoxU4YYE3L^&cNgi-D5d^GTE80DpNm>r*cn*Z zL7q5U8Q5xm?GzAC$G^V)5#@~%eS^#)WH*KZFB8`aSV-y7YtzI?lu47t%V0c=y`=SI z&*vMt8b{ELFOJwx%sMH*>ANgwZ2GuQ!G%F2QY`}^K)yM!cqlK{s!bL(tbNCXk%LZ? zFsocN$h$Q43E9UDtw$d&=e;0V?Y+QQ*>IjnQaFaF# z0S29YE&J}IeB?74IiQ&o8GmgCm$3_0cT0J@NKc0A1??qyDQtnmw~upGo;K(AYQM&yP~R z4_)@v|M+WSx%H!z-woOJqrmSMAN{sk?94w3{5AgBk5ay0z4O~@!5{o6<-2PAx@_r3 zf!}*ze_O5Ahd&DZR;}OV{CgMXZ>y!G`lFQZs`X9Qw|?lyYJKm=`|A1pH9b@N9Y5%g z#lQDXe7zU_n$pz2)#pdo-;V;me=7Ux#P~JgYkd>&f4MY%l<@t?`Rmi$ujz^LFB1Ot zEcav4?*~d>ht|KQ9n-(D`PYH=kA=S<27Db${hEX9}9lpL;SX2p4GPs{I#?FvEcW&so$P7Y@6ThP84M>p54)~ut?7SKAw$wDs8`h F`#*;d6;=QM From fa2c37604d21c8dc449d2b09b833b2fe68efca18 Mon Sep 17 00:00:00 2001 From: diatlova Date: Wed, 21 Apr 2021 21:17:07 +0300 Subject: [PATCH 32/78] Added common class with run_tool arguments --- src/python/common/__init__.py | 0 src/python/common/tool_arguments.py | 71 +++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+) create mode 100644 src/python/common/__init__.py create mode 100644 src/python/common/tool_arguments.py diff --git a/src/python/common/__init__.py b/src/python/common/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/src/python/common/tool_arguments.py b/src/python/common/tool_arguments.py new file mode 100644 index 00000000..4a0c4f44 --- /dev/null +++ b/src/python/common/tool_arguments.py @@ -0,0 +1,71 @@ +from dataclasses import dataclass +from enum import Enum, unique +from typing import List, Union +from src.python.review.inspectors.inspector_type import InspectorType + + +@unique +class VerbosityLevel(Enum): + """ + Same meaning as the logging level. Should be used in command-line args. + """ + DEBUG = '3' + INFO = '2' + ERROR = '1' + DISABLE = '0' + + @classmethod + def values(cls) -> List[str]: + return [member.value for _, member in VerbosityLevel.__members__.items()] + + +@dataclass(frozen=True) +class ArgumentsCharacteristics: + short_name: Union[str, None] + long_name: str + description: str + + +inspectors = [inspector.lower() for inspector in InspectorType.available_values()] +example = f'-d {inspectors[0].lower()},{inspectors[1].lower()}' + + +@unique +class RunToolArguments(Enum): + VERBOSITY = ArgumentsCharacteristics('-v', + '--verbosity', + 'Choose logging level: ' + f'{VerbosityLevel.ERROR.value} - ERROR; ' + f'{VerbosityLevel.INFO.value} - INFO; ' + f'{VerbosityLevel.DEBUG.value} - DEBUG; ' + f'{VerbosityLevel.DISABLE.value} - disable logging; ' + 'default is 0') + + DISABLE = ArgumentsCharacteristics('-d', '--disable', + 'Disable inspectors. ' + f'Allowed values: {", ".join(inspectors)}. ' + f'Example: {example}') + + DUPLICATES = ArgumentsCharacteristics(None, '--allow-duplicates', + 'Allow duplicate issues found by different linters. ' + 'By default, duplicates are skipped.') + + LANG_VERSION = ArgumentsCharacteristics('--language_version', '--language_version', + 'Specify the language version for JAVA inspectors.') + + CPU = ArgumentsCharacteristics('--n_cpu', '--n-cpu', + 'Specify number of cpu that can be used to run inspectors') + + PATH = ArgumentsCharacteristics(None, 'path', 'Path to file or directory to inspect.') + + FORMAT = ArgumentsCharacteristics('-f', '--format', + 'The output format. Default is JSON.') + + START_LINE = ArgumentsCharacteristics('-s', '--start-line', + 'The first line to be analyzed. It starts from 1.') + + END_LINE = ArgumentsCharacteristics('-e', '--end-line', 'The end line to be analyzed or None.') + + NEW_FORMAT = ArgumentsCharacteristics(None, '--new-format', + 'The argument determines whether the tool ' + 'should use the new format') From 85973c0be255671930339f9482249745dc5d79e9 Mon Sep 17 00:00:00 2001 From: diatlova Date: Wed, 21 Apr 2021 21:18:29 +0300 Subject: [PATCH 33/78] Updated run_tool argnames and several functions --- src/python/review/application_config.py | 12 ++++ src/python/review/common/file_system.py | 5 +- src/python/review/run_tool.py | 86 ++++++++++--------------- 3 files changed, 49 insertions(+), 54 deletions(-) diff --git a/src/python/review/application_config.py b/src/python/review/application_config.py index c678605f..1f4c0d77 100644 --- a/src/python/review/application_config.py +++ b/src/python/review/application_config.py @@ -2,6 +2,7 @@ from enum import Enum, unique from typing import Optional, Set, List +from src.python.review.common.file_system import Extension from src.python.review.inspectors.inspector_type import InspectorType @@ -22,7 +23,18 @@ class LanguageVersion(Enum): JAVA_8 = 'java8' JAVA_9 = 'java9' JAVA_11 = 'java11' + PYTHON_3 = 'python3' + KOTLIN = 'kotlin' @classmethod def values(cls) -> List[str]: return [member.value for member in cls.__members__.values()] + + @classmethod + def language_extension(cls) -> dict: + return {cls.PYTHON_3.value: Extension.PY.value, + cls.JAVA_7.value: Extension.JAVA.value, + cls.JAVA_8.value: Extension.JAVA.value, + cls.JAVA_9.value: Extension.JAVA.value, + cls.JAVA_11.value: Extension.JAVA.value, + cls.KOTLIN.value: Extension.KT.value} diff --git a/src/python/review/common/file_system.py b/src/python/review/common/file_system.py index 3faa962c..10ec7790 100644 --- a/src/python/review/common/file_system.py +++ b/src/python/review/common/file_system.py @@ -66,8 +66,9 @@ def create_file(file_path: Union[str, Path], content: str): file_path = Path(file_path) create_directory(os.path.dirname(file_path)) - with open(file_path, 'w') as f: - f.write(content) + with open(file_path, 'w+') as f: + f.writelines(content) + yield Path(file_path) def create_directory(directory: str) -> None: diff --git a/src/python/review/run_tool.py b/src/python/review/run_tool.py index 1b879972..d001fb68 100644 --- a/src/python/review/run_tool.py +++ b/src/python/review/run_tool.py @@ -1,11 +1,11 @@ import argparse +import enum import logging.config import os import sys import traceback -from enum import Enum, unique from pathlib import Path -from typing import Set, List +from typing import Set sys.path.append('') sys.path.append('../../..') @@ -13,7 +13,6 @@ from src.python.review.application_config import ApplicationConfig, LanguageVersion from src.python.review.inspectors.inspector_type import InspectorType from src.python.review.logging_config import logging_config - from src.python.review.reviewers.perform_review import ( OutputFormat, PathNotExists, @@ -21,22 +20,9 @@ UnsupportedLanguage, ) -logger = logging.getLogger(__name__) - - -@unique -class VerbosityLevel(Enum): - """ - Same meaning as the logging level. Should be used in command-line args. - """ - DEBUG = '3' - INFO = '2' - ERROR = '1' - DISABLE = '0' +from src.python.common.tool_arguments import RunToolArguments, VerbosityLevel - @classmethod - def values(cls) -> List[str]: - return [member.value for _, member in VerbosityLevel.__members__.items()] +logger = logging.getLogger(__name__) def parse_disabled_inspectors(value: str) -> Set[InspectorType]: @@ -56,70 +42,66 @@ def positive_int(value: str) -> int: return value_int -def configure_arguments(parser: argparse.ArgumentParser) -> None: - parser.add_argument('-v', '--verbosity', - help='Choose logging level: ' - f'{VerbosityLevel.ERROR.value} - ERROR; ' - f'{VerbosityLevel.INFO.value} - INFO; ' - f'{VerbosityLevel.DEBUG.value} - DEBUG; ' - f'{VerbosityLevel.DISABLE.value} - disable logging; ' - 'default is 0', +def configure_arguments(parser: argparse.ArgumentParser, tool_arguments: enum.EnumMeta) -> None: + parser.add_argument(tool_arguments.VERBOSITY.value.short_name, + tool_arguments.VERBOSITY.value.long_name, + help=tool_arguments.VERBOSITY.value.description, default=VerbosityLevel.DISABLE.value, choices=VerbosityLevel.values(), type=str) # Usage example: -d Flake8,Intelli - inspectors = [inspector.lower() for inspector in InspectorType.available_values()] - example = f'-d {inspectors[0].lower()},{inspectors[1].lower()}' - - parser.add_argument('-d', '--disable', - help='Disable inspectors. ' - f'Allowed values: {", ".join(inspectors)}. ' - f'Example: {example}', + parser.add_argument(tool_arguments.DISABLE.value.short_name, + tool_arguments.DISABLE.value.long_name, + help=tool_arguments.DISABLE.value.description, type=parse_disabled_inspectors, default=set()) - parser.add_argument('--allow-duplicates', action='store_true', - help='Allow duplicate issues found by different linters. ' - 'By default, duplicates are skipped.') + parser.add_argument(tool_arguments.DUPLICATES.value.long_name, + action='store_true', + help=tool_arguments.DUPLICATES.value.description) # TODO: deprecated argument: language_version. Delete after several releases. - parser.add_argument('--language_version', '--language-version', - help='Specify the language version for JAVA inspectors.', + parser.add_argument(tool_arguments.LANG_VERSION.value.short_name, + tool_arguments.LANG_VERSION.value.long_name, + help=tool_arguments.LANG_VERSION.value.description, default=None, choices=LanguageVersion.values(), type=str) # TODO: deprecated argument: --n_cpu. Delete after several releases. - parser.add_argument('--n_cpu', '--n-cpu', - help='Specify number of cpu that can be used to run inspectors', + parser.add_argument(tool_arguments.CPU.value.short_name, + tool_arguments.CPU.value.long_name, + help=tool_arguments.CPU.value.description, default=1, type=positive_int) - parser.add_argument('path', + parser.add_argument(tool_arguments.PATH.value.long_name, type=lambda value: Path(value).absolute(), - help='Path to file or directory to inspect.') + help=tool_arguments.PATH.value.description) - parser.add_argument('-f', '--format', + parser.add_argument(tool_arguments.FORMAT.value.short_name, + tool_arguments.FORMAT.value.long_name, default=OutputFormat.JSON.value, choices=OutputFormat.values(), type=str, - help='The output format. Default is JSON.') + help=tool_arguments.FORMAT.value.description) - parser.add_argument('-s', '--start-line', + parser.add_argument(tool_arguments.START_LINE.value.short_name, + tool_arguments.START_LINE.value.long_name, default=1, type=positive_int, - help='The first line to be analyzed. It starts from 1.') + help=tool_arguments.START_LINE.value.description) - parser.add_argument('-e', '--end-line', + parser.add_argument(tool_arguments.END_LINE.value.short_name, + tool_arguments.END_LINE.value.long_name, default=None, type=positive_int, - help='The end line to be analyzed or None.') + help=tool_arguments.END_LINE.value.description) - parser.add_argument('--new-format', + parser.add_argument(tool_arguments.NEW_FORMAT.value.long_name, action='store_true', - help='The argument determines whether the tool ' - 'should use the new format') + help=tool_arguments.NEW_FORMAT.value.description) def configure_logging(verbosity: VerbosityLevel) -> None: @@ -137,7 +119,7 @@ def configure_logging(verbosity: VerbosityLevel) -> None: def main() -> int: parser = argparse.ArgumentParser() - configure_arguments(parser) + configure_arguments(parser, RunToolArguments) try: args = parser.parse_args() From 11772d66b301439cffeb57109c9e20bc8932a60f Mon Sep 17 00:00:00 2001 From: diatlova Date: Wed, 21 Apr 2021 21:20:28 +0300 Subject: [PATCH 34/78] Updated evaluation tests --- test/python/evaluation/test_output_results.py | 18 +++++++++--------- test/python/evaluation/test_tool_path.py | 11 ++++++----- .../evaluation/test_xlsx_file_structure.py | 4 ++-- test/python/evaluation/testing_config.py | 13 +++++++++---- 4 files changed, 26 insertions(+), 20 deletions(-) diff --git a/test/python/evaluation/test_output_results.py b/test/python/evaluation/test_output_results.py index 6ba2190b..46fbce61 100644 --- a/test/python/evaluation/test_output_results.py +++ b/test/python/evaluation/test_output_results.py @@ -5,10 +5,10 @@ import pandas as pd import pytest from src.python import MAIN_FOLDER -from src.python.evaluation.evaluation_config import ApplicationConfig +from src.python.common.tool_arguments import RunToolArguments +from src.python.evaluation.evaluation_config import EvaluationConfig from src.python.evaluation.xlsx_run_tool import create_dataframe - FILE_NAMES = [ ('test_sorted_order.xlsx', 'target_sorted_order.xlsx', False), ('test_sorted_order.xlsx', 'target_sorted_order.xlsx', 'True'), @@ -20,17 +20,17 @@ @pytest.mark.parametrize(('test_file', 'target_file', 'output_type'), FILE_NAMES) def test_correct_output(test_file: str, target_file: str, output_type: Union[bool, str]): - parser = get_parser() - parser.add_argument('-data_path', '--data_path', default=XLSX_DATA_FOLDER / test_file) - parser.add_argument('-t', '--tool_path', default=MAIN_FOLDER.parent / 'review/run_tool.py') + parser = get_parser(RunToolArguments) + parser.add_argument('-xlsx_file_path', '--xlsx_file_path', default=XLSX_DATA_FOLDER / test_file) + parser.add_argument('-tool_path', '--tool_path', default=MAIN_FOLDER.parent / 'review/run_tool.py') parser.add_argument('--traceback', '--traceback', default=output_type) args = parser.parse_args([]) - config = ApplicationConfig(args) + config = EvaluationConfig(args) test_dataframe = create_dataframe(config) - sheet = 'grades' + sheet_name = 'grades' if output_type: - sheet = 'traceback' + sheet_name = 'traceback' - target_dataframe = pd.read_excel(TARGET_XLSX_DATA_FOLDER / target_file, sheet_name=sheet) + target_dataframe = pd.read_excel(TARGET_XLSX_DATA_FOLDER / target_file, sheet_name=sheet_name) assert test_dataframe.reset_index(drop=True).equals(target_dataframe.reset_index(drop=True)) diff --git a/test/python/evaluation/test_tool_path.py b/test/python/evaluation/test_tool_path.py index 5cbf5956..9774c1d8 100644 --- a/test/python/evaluation/test_tool_path.py +++ b/test/python/evaluation/test_tool_path.py @@ -4,17 +4,18 @@ from test.python.evaluation.conftest import BrokenLocalCommandBuilder from src.python import MAIN_FOLDER -from src.python.evaluation.evaluation_config import ApplicationConfig +from src.python.common.tool_arguments import RunToolArguments +from src.python.evaluation.evaluation_config import EvaluationConfig from src.python.evaluation.xlsx_run_tool import create_dataframe def test_correct_tool_path(): - parser = get_parser() - parser.add_argument('-data_path', '--data_path', default=XLSX_DATA_FOLDER / 'test_unsorted_order.xlsx') - parser.add_argument('-t', '--tool_path', default=MAIN_FOLDER.parent / 'review/run_tool.py') + parser = get_parser(RunToolArguments) + parser.add_argument('-xlsx_file_path', default=XLSX_DATA_FOLDER / 'test_unsorted_order.xlsx') + parser.add_argument('-tool_path', '--tool_path', default=MAIN_FOLDER.parent / 'review/run_tool.py') parser.add_argument('--traceback', '--traceback', default=False) args = parser.parse_args([]) - config = ApplicationConfig(args) + config = EvaluationConfig(args) create_dataframe(config) diff --git a/test/python/evaluation/test_xlsx_file_structure.py b/test/python/evaluation/test_xlsx_file_structure.py index f195bcec..62eb2460 100644 --- a/test/python/evaluation/test_xlsx_file_structure.py +++ b/test/python/evaluation/test_xlsx_file_structure.py @@ -4,7 +4,7 @@ from test.python.evaluation.conftest import EvalLocalCommandBuilder import pytest -from src.python.evaluation import ScriptStructureRule +from src.python.evaluation.common.util import script_structure_rule FILE_NAMES = [ 'test_wrong_column_name.xlsx', @@ -31,4 +31,4 @@ def test_wrong_column(file_name: str, eval_command_builder: EvalLocalCommandBuil ) assert process.returncode == 2 - assert compare(process.stderr) == compare(ScriptStructureRule) + '%' + assert compare(process.stderr) == compare(script_structure_rule) + '%' diff --git a/test/python/evaluation/testing_config.py b/test/python/evaluation/testing_config.py index 878cff3d..4654b095 100644 --- a/test/python/evaluation/testing_config.py +++ b/test/python/evaluation/testing_config.py @@ -1,10 +1,15 @@ import argparse +import enum from src.python.review.reviewers.perform_review import OutputFormat +from src.python.evaluation.common.util import EvaluationProcessNames -def get_parser() -> argparse.ArgumentParser: +def get_parser(run_tool_arguments: enum.EnumMeta) -> argparse.ArgumentParser: parser = argparse.ArgumentParser() - parser.add_argument('--folder_path', '--folder_path', default=None) - parser.add_argument('--file_name', '--file_name', default='results.xlsx') - parser.add_argument('-f', '--format', default=OutputFormat.JSON.value) + parser.add_argument('--output_folder_path', '--output_folder_path', default=None) + parser.add_argument('--output_file_name', '--output_file_name', + default=EvaluationProcessNames.RESULTS_EXT.value) + parser.add_argument(run_tool_arguments.FORMAT.value.short_name, + run_tool_arguments.FORMAT.value.long_name, + default=OutputFormat.JSON.value) return parser From 9ceeb735d45e7ee7f900b69d6698160eafaa4f0c Mon Sep 17 00:00:00 2001 From: diatlova Date: Wed, 21 Apr 2021 21:21:05 +0300 Subject: [PATCH 35/78] Updated evaluation resources --- .../xlsx_files/test_sorted_order.xlsx | Bin 0 -> 7317 bytes .../xlsx_files/test_unsorted_order.xlsx | Bin 6264 -> 6995 bytes .../target_sorted_order.xlsx | Bin 0 -> 37914 bytes .../target_unsorted_order.xlsx | Bin 0 -> 30898 bytes 4 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 test/resources/evaluation/xlsx_files/test_sorted_order.xlsx create mode 100644 test/resources/evaluation/xlsx_target_files/target_sorted_order.xlsx create mode 100644 test/resources/evaluation/xlsx_target_files/target_unsorted_order.xlsx diff --git a/test/resources/evaluation/xlsx_files/test_sorted_order.xlsx b/test/resources/evaluation/xlsx_files/test_sorted_order.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..bfdca3b2a22591703e61d6ba572aac5e027d4ce3 GIT binary patch literal 7317 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 z z&NCUKFGAf$nvg@A*Vc~FDqoq3y|;JG`BIY`(t&{G6?s2}14-xDH(e@#!hsFtj|}jh zM96iX)DGj>n1uU1;qx|Ddb#kY}ntOib!e+rEDE z*B8P1V857Bf3&FIu4ccpDQNwJy-RU_FD?cdI=%X+{qXse%s3LTnxpJ{=w7QzYW)hb zvdvuP>GNce6R|Yk-H!?e3@8PUQaE+LPc@lfnuJj`;#Hif4Q+ib`i@hV_`%H5mQhyq z&aL}ylV>T;jYlqyqhcnoT+thq;p3riJN37+4dJRq2WxIC@MbIUG*5aaX4F-O!ZxdJ zTyB)6S89Kt1y<+`+3eKgz8DspVT+w9 z524kWytsFd*}lshff`a;Zm<^-9D=M)x zR98aDQ%Q@7sZ!B4x;__^+JTzj7t}(WB%lPaMzWVY5&7%PvQ$$-RIGu#NbO#T$-z(n zipiLtn2N4`QW>D%vyklqkr>4Z#RpbKV$io}J_^rLd6|x)P)d>(Yue1j9%hUE(jyu6 z<1@)-Ok$#3a!=q83ithysYn(^)QCf9T2L?@Dp(eC>J_45iDsltteQLv*F&+4#(G!5 zH}kVwP|qq30XPK8EY4Rx2L;n6%M(?3<=h@VoRsbwUpZ<8qELElN*{r7mkL;>2f`?V_%DiTiAc|*oJ)3^j8D|5LGYKz?I0Rotp``G$YSqOa zxi3)WpAe>M0YerGz{9uB39{h4h*$~9KfenCQT`FJ2euaO*7vkM+%NI{64tj2eILvS zQ=FR#e5E&k$eU#!$;>w8#`(JF**Erv{D(%xZ)cbJ^$n4#!jzog%xg7=o~_-%tl!Aw zyBqEla6|*Wxq;m+BzlIyim+fJN1JrW#6Fbpj`=6CC!ctOV@6bCc$qf`3&Rl4 z@Lsi8(;t2+RiCz{?FosRk&UGVp9}X4t+Zv%OG*G)XX^wv4{bOk9{G$eWh~?Guhxq~ z>X-9HarNTYP7+V69opv+mDhV2#AF>98Lk&AeJgJAaBAWkfIV94NJFx;u}0*uIcKP0 zC21YNs6zr=p!JYl-39fA8S2@@EGgMpt&{Z@VG~*5LZ)IUqp)k1f5@g)0kC}V zeO%^D@?MZS?TsTb_EER+GIlCBZyaZoUnoFMyh^?MT=u%0wn#p81NI`RcC)#L@w=Ya zs*4KL!Rg~gV=Xa`GZiFhiz6qL63)5JQf49KvVK7{0#bbN0$!*nZH*zf(`Wy>-iCB8qukf2FPVF6KO zg=fAo??^g-)BVz_TodnU^C*msA-t�>Pl8E?SKLHd!DwV6FQjM5~{7`Pj~wXK6W4 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 delta 5366 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 DC$?vL diff --git a/test/resources/evaluation/xlsx_target_files/target_sorted_order.xlsx b/test/resources/evaluation/xlsx_target_files/target_sorted_order.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..27321600ae3d53b333a399e96612d9e552e9c9d3 GIT binary patch literal 37914 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 literal 0 HcmV?d00001 From 965313348f8b9fc71a5dbedf8c2fb4175804f7a8 Mon Sep 17 00:00:00 2001 From: diatlova Date: Wed, 21 Apr 2021 21:36:40 +0300 Subject: [PATCH 36/78] Fixed merging issue --- src/python/review/run_tool.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/python/review/run_tool.py b/src/python/review/run_tool.py index 8bcd1d4e..8b318119 100644 --- a/src/python/review/run_tool.py +++ b/src/python/review/run_tool.py @@ -5,11 +5,8 @@ import sys import traceback from pathlib import Path -<<<<<<< HEAD -from typing import Set -======= from typing import List, Set ->>>>>>> ab62d8a2ed55fab219de28b30526dd13764085a4 + sys.path.append('') sys.path.append('../../..') From 1a52079dd56f7d72f5c0a72863fc9e8574f07b92 Mon Sep 17 00:00:00 2001 From: diatlova Date: Wed, 21 Apr 2021 21:39:48 +0300 Subject: [PATCH 37/78] Fixed merging issue --- test/python/evaluation/testing_config.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/test/python/evaluation/testing_config.py b/test/python/evaluation/testing_config.py index 5593196f..8af6db6a 100644 --- a/test/python/evaluation/testing_config.py +++ b/test/python/evaluation/testing_config.py @@ -1,9 +1,6 @@ import argparse -<<<<<<< HEAD import enum -======= ->>>>>>> ab62d8a2ed55fab219de28b30526dd13764085a4 from src.python.review.reviewers.perform_review import OutputFormat from src.python.evaluation.common.util import EvaluationProcessNames From 4c8a54d24d69a74a2d577229f15a13f928d54afd Mon Sep 17 00:00:00 2001 From: diatlova Date: Wed, 21 Apr 2021 21:50:30 +0300 Subject: [PATCH 38/78] Fixed Flake inspection --- src/python/common/tool_arguments.py | 1 + src/python/review/run_tool.py | 5 ++--- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/python/common/tool_arguments.py b/src/python/common/tool_arguments.py index 4a0c4f44..237eb2ff 100644 --- a/src/python/common/tool_arguments.py +++ b/src/python/common/tool_arguments.py @@ -1,6 +1,7 @@ from dataclasses import dataclass from enum import Enum, unique from typing import List, Union + from src.python.review.inspectors.inspector_type import InspectorType diff --git a/src/python/review/run_tool.py b/src/python/review/run_tool.py index 8b318119..a171c832 100644 --- a/src/python/review/run_tool.py +++ b/src/python/review/run_tool.py @@ -5,12 +5,13 @@ import sys import traceback from pathlib import Path -from typing import List, Set +from typing import Set sys.path.append('') sys.path.append('../../..') +from src.python.common.tool_arguments import RunToolArguments, VerbosityLevel from src.python.review.application_config import ApplicationConfig, LanguageVersion from src.python.review.inspectors.inspector_type import InspectorType from src.python.review.logging_config import logging_config @@ -21,8 +22,6 @@ UnsupportedLanguage, ) -from src.python.common.tool_arguments import RunToolArguments, VerbosityLevel - logger = logging.getLogger(__name__) From b7187fdd483e00443681c9a6f2145d82ae6c3517 Mon Sep 17 00:00:00 2001 From: diatlova Date: Wed, 21 Apr 2021 21:51:13 +0300 Subject: [PATCH 39/78] Fixed Flake inspection issue --- test/python/evaluation/testing_config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/python/evaluation/testing_config.py b/test/python/evaluation/testing_config.py index 8af6db6a..4efbb789 100644 --- a/test/python/evaluation/testing_config.py +++ b/test/python/evaluation/testing_config.py @@ -1,8 +1,8 @@ import argparse import enum -from src.python.review.reviewers.perform_review import OutputFormat from src.python.evaluation.common.util import EvaluationProcessNames +from src.python.review.reviewers.perform_review import OutputFormat def get_parser(run_tool_arguments: enum.EnumMeta) -> argparse.ArgumentParser: From 6ec424038e32fe27b2cf27bd29a7ecb4a12d674f Mon Sep 17 00:00:00 2001 From: diatlova Date: Wed, 21 Apr 2021 21:53:57 +0300 Subject: [PATCH 40/78] Added util --- whitelist.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/whitelist.txt b/whitelist.txt index a0a7d450..042e8c0d 100644 --- a/whitelist.txt +++ b/whitelist.txt @@ -88,3 +88,4 @@ lcom noc nom wmc +util \ No newline at end of file From 21f4cfd9c213227e1ff07853ecb17a77f3a16230 Mon Sep 17 00:00:00 2001 From: diatlova Date: Wed, 21 Apr 2021 23:35:20 +0300 Subject: [PATCH 41/78] Added logger to check test output --- test/python/evaluation/test_output_results.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/test/python/evaluation/test_output_results.py b/test/python/evaluation/test_output_results.py index 46fbce61..f53dd9ae 100644 --- a/test/python/evaluation/test_output_results.py +++ b/test/python/evaluation/test_output_results.py @@ -1,3 +1,4 @@ +import logging.config from test.python.evaluation import TARGET_XLSX_DATA_FOLDER, XLSX_DATA_FOLDER from test.python.evaluation.testing_config import get_parser from typing import Union @@ -16,6 +17,8 @@ ('test_unsorted_order.xlsx', 'target_unsorted_order.xlsx', 'True'), ] +logger = logging.getLogger(__name__) + @pytest.mark.parametrize(('test_file', 'target_file', 'output_type'), FILE_NAMES) def test_correct_output(test_file: str, target_file: str, output_type: Union[bool, str]): @@ -33,4 +36,7 @@ def test_correct_output(test_file: str, target_file: str, output_type: Union[boo sheet_name = 'traceback' target_dataframe = pd.read_excel(TARGET_XLSX_DATA_FOLDER / target_file, sheet_name=sheet_name) - assert test_dataframe.reset_index(drop=True).equals(target_dataframe.reset_index(drop=True)) + try: + assert test_dataframe.reset_index(drop=True).equals(target_dataframe.reset_index(drop=True)) + except Exception: + logger.exception(f'{test_dataframe} is not equal to {test_dataframe}') From 530370650ed6fc2fae76b8015c6deb9dc0173508 Mon Sep 17 00:00:00 2001 From: diatlova Date: Thu, 22 Apr 2021 00:07:11 +0300 Subject: [PATCH 42/78] Added logger to check test output --- test/python/evaluation/test_output_results.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/python/evaluation/test_output_results.py b/test/python/evaluation/test_output_results.py index f53dd9ae..d1e60a79 100644 --- a/test/python/evaluation/test_output_results.py +++ b/test/python/evaluation/test_output_results.py @@ -36,7 +36,7 @@ def test_correct_output(test_file: str, target_file: str, output_type: Union[boo sheet_name = 'traceback' target_dataframe = pd.read_excel(TARGET_XLSX_DATA_FOLDER / target_file, sheet_name=sheet_name) - try: - assert test_dataframe.reset_index(drop=True).equals(target_dataframe.reset_index(drop=True)) - except Exception: + equality_compression = test_dataframe.reset_index(drop=True).equals(target_dataframe.reset_index(drop=True)) + assert equality_compression + if not equality_compression: logger.exception(f'{test_dataframe} is not equal to {test_dataframe}') From 39d3a38a256766e23523c9b1b76960d66a4cf2fa Mon Sep 17 00:00:00 2001 From: diatlova Date: Thu, 22 Apr 2021 14:09:00 +0300 Subject: [PATCH 43/78] Save artifacts for debugging --- test/python/evaluation/test_output_results.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/test/python/evaluation/test_output_results.py b/test/python/evaluation/test_output_results.py index d1e60a79..2e9b1a92 100644 --- a/test/python/evaluation/test_output_results.py +++ b/test/python/evaluation/test_output_results.py @@ -5,8 +5,10 @@ import pandas as pd import pytest +from openpyxl import Workbook from src.python import MAIN_FOLDER from src.python.common.tool_arguments import RunToolArguments +from src.python.evaluation.common.xlsx_util import remove_sheet, write_dataframe_to_xlsx_sheet from src.python.evaluation.evaluation_config import EvaluationConfig from src.python.evaluation.xlsx_run_tool import create_dataframe @@ -30,13 +32,14 @@ def test_correct_output(test_file: str, target_file: str, output_type: Union[boo args = parser.parse_args([]) config = EvaluationConfig(args) test_dataframe = create_dataframe(config) - + workbook = Workbook() + workbook_path = config.get_file_path() + workbook.save(workbook_path) + write_dataframe_to_xlsx_sheet(workbook_path, test_dataframe, 'inspection_results', 'openpyxl') + remove_sheet(workbook_path, 'Sheet') sheet_name = 'grades' if output_type: sheet_name = 'traceback' - target_dataframe = pd.read_excel(TARGET_XLSX_DATA_FOLDER / target_file, sheet_name=sheet_name) - equality_compression = test_dataframe.reset_index(drop=True).equals(target_dataframe.reset_index(drop=True)) - assert equality_compression - if not equality_compression: - logger.exception(f'{test_dataframe} is not equal to {test_dataframe}') + + assert test_dataframe.reset_index(drop=True).equals(target_dataframe.reset_index(drop=True)) From 137f8006c60987a070539186d6316efa0f65fbcb Mon Sep 17 00:00:00 2001 From: diatlova Date: Thu, 22 Apr 2021 17:40:31 +0300 Subject: [PATCH 44/78] Updated tests to save artefacts --- test/python/evaluation/conftest.py | 42 ------------------- test/python/evaluation/test_data_path.py | 24 +++++------ test/python/evaluation/test_output_results.py | 14 ++++--- test/python/evaluation/test_tool_path.py | 29 +++++-------- .../evaluation/test_xlsx_file_structure.py | 32 +++++--------- test/python/evaluation/testing_config.py | 13 ++++-- 6 files changed, 50 insertions(+), 104 deletions(-) delete mode 100644 test/python/evaluation/conftest.py diff --git a/test/python/evaluation/conftest.py b/test/python/evaluation/conftest.py deleted file mode 100644 index 1bbec42d..00000000 --- a/test/python/evaluation/conftest.py +++ /dev/null @@ -1,42 +0,0 @@ -from dataclasses import dataclass -from pathlib import Path -from typing import List, Optional - -import pytest -from src.python import MAIN_FOLDER - - -@dataclass -class EvalLocalCommandBuilder: - path: Optional[Path] = None - xlsx_tool_path: Optional[Path] = MAIN_FOLDER.parent / 'evaluation/xlsx_run_tool.py' - tool_path: Optional[Path] = MAIN_FOLDER.parent / 'review/run_tool.py' - traceback: Optional[str] = None - - def build(self) -> List[str]: - assert self.path is not None - command = ['python3', self.xlsx_tool_path, str(self.path), '-t', self.tool_path] - if self.traceback is not None: - command.extend(['--traceback', self.traceback]) - return command - - -@pytest.fixture -def eval_command_builder() -> EvalLocalCommandBuilder: - return EvalLocalCommandBuilder() - - -@dataclass -class BrokenLocalCommandBuilder: - path: Optional[Path] = None - tool_path: Optional[Path] = MAIN_FOLDER.parent / 'evaluation/do_not_exist.py' - - def build(self) -> List[str]: - assert self.path is not None - command = ['python3', str(self.path), '-t', self.tool_path] - return command - - -@pytest.fixture -def broken_command_builder() -> BrokenLocalCommandBuilder: - return BrokenLocalCommandBuilder() diff --git a/test/python/evaluation/test_data_path.py b/test/python/evaluation/test_data_path.py index e0368a3a..187e73b8 100644 --- a/test/python/evaluation/test_data_path.py +++ b/test/python/evaluation/test_data_path.py @@ -1,18 +1,14 @@ -import subprocess from test.python.evaluation import XLSX_DATA_FOLDER -from test.python.evaluation.conftest import EvalLocalCommandBuilder +from test.python.evaluation.testing_config import get_parser +from src.python.common.tool_arguments import RunToolArguments +from src.python.evaluation.evaluation_config import EvaluationConfig +from src.python.evaluation.xlsx_run_tool import create_dataframe -def test_incorrect_data_path(eval_command_builder: EvalLocalCommandBuilder): - file_path = XLSX_DATA_FOLDER / 'do_not_exist.xlsx' - eval_command_builder.path = file_path - process = subprocess.run( - eval_command_builder.build(), - stderr=subprocess.PIPE, - stdout=subprocess.PIPE, - text=True, - ) - - assert process.returncode == 2 - assert 'XLSX-file with the specified name does not exists.\n' == process.stderr +def test_incorrect_data_path(): + parser = get_parser(RunToolArguments, n_args=5) + parser.add_argument('-xlsx_file_path', '--xlsx_file_path', default=XLSX_DATA_FOLDER / 'do_not_exist.xlsx') + args = parser.parse_args([]) + config = EvaluationConfig(args) + assert create_dataframe(config) == 2 diff --git a/test/python/evaluation/test_output_results.py b/test/python/evaluation/test_output_results.py index 2e9b1a92..c55fde6a 100644 --- a/test/python/evaluation/test_output_results.py +++ b/test/python/evaluation/test_output_results.py @@ -13,22 +13,24 @@ from src.python.evaluation.xlsx_run_tool import create_dataframe FILE_NAMES = [ - ('test_sorted_order.xlsx', 'target_sorted_order.xlsx', False), - ('test_sorted_order.xlsx', 'target_sorted_order.xlsx', 'True'), - ('test_unsorted_order.xlsx', 'target_unsorted_order.xlsx', False), - ('test_unsorted_order.xlsx', 'target_unsorted_order.xlsx', 'True'), + ('test_sorted_order.xlsx', 'target_sorted_order.xlsx', False, 'test1.xlsx'), + ('test_sorted_order.xlsx', 'target_sorted_order.xlsx', 'True', 'test2.xlsx'), + ('test_unsorted_order.xlsx', 'target_unsorted_order.xlsx', False, 'test3.xlsx'), + ('test_unsorted_order.xlsx', 'target_unsorted_order.xlsx', 'True', 'test4.xlsx'), ] logger = logging.getLogger(__name__) -@pytest.mark.parametrize(('test_file', 'target_file', 'output_type'), FILE_NAMES) -def test_correct_output(test_file: str, target_file: str, output_type: Union[bool, str]): +@pytest.mark.parametrize(('test_file', 'target_file', 'output_type', 'output_file_name'), FILE_NAMES) +def test_correct_output(test_file: str, target_file: str, output_type: Union[bool, str], + output_file_name: str): parser = get_parser(RunToolArguments) parser.add_argument('-xlsx_file_path', '--xlsx_file_path', default=XLSX_DATA_FOLDER / test_file) parser.add_argument('-tool_path', '--tool_path', default=MAIN_FOLDER.parent / 'review/run_tool.py') parser.add_argument('--traceback', '--traceback', default=output_type) + parser.add_argument('--output_file_name', '--output_file_name', default=output_file_name) args = parser.parse_args([]) config = EvaluationConfig(args) test_dataframe = create_dataframe(config) diff --git a/test/python/evaluation/test_tool_path.py b/test/python/evaluation/test_tool_path.py index 3849e7e1..04d50a94 100644 --- a/test/python/evaluation/test_tool_path.py +++ b/test/python/evaluation/test_tool_path.py @@ -1,32 +1,25 @@ -import subprocess from test.python.evaluation import XLSX_DATA_FOLDER -from test.python.evaluation.conftest import BrokenLocalCommandBuilder from test.python.evaluation.testing_config import get_parser +import pandas as pd from src.python import MAIN_FOLDER from src.python.common.tool_arguments import RunToolArguments from src.python.evaluation.evaluation_config import EvaluationConfig from src.python.evaluation.xlsx_run_tool import create_dataframe -def test_correct_tool_path(): - parser = get_parser(RunToolArguments) +def test_correct_tool_path(run_tool_arguments=RunToolArguments): + parser = get_parser(run_tool_arguments, n_args=5) parser.add_argument('-xlsx_file_path', default=XLSX_DATA_FOLDER / 'test_unsorted_order.xlsx') - parser.add_argument('-tool_path', '--tool_path', default=MAIN_FOLDER.parent / 'review/run_tool.py') - parser.add_argument('--traceback', '--traceback', default=False) args = parser.parse_args([]) config = EvaluationConfig(args) - create_dataframe(config) + assert type(create_dataframe(config)) == pd.DataFrame -def test_incorrect_tool_path(broken_command_builder: BrokenLocalCommandBuilder): - file_path = XLSX_DATA_FOLDER / 'test_unsorted_order.xlsx' - - broken_command_builder.path = file_path - process = subprocess.run( - broken_command_builder.build(), - stderr=subprocess.PIPE, - stdout=subprocess.PIPE, - ) - - assert process.returncode == 1 +def test_incorrect_tool_path(run_tool_arguments=RunToolArguments): + parser = get_parser(run_tool_arguments, n_args=4) + parser.add_argument('-xlsx_file_path', default=XLSX_DATA_FOLDER / 'test_unsorted_order.xlsx') + parser.add_argument('-tool_path', '--tool_path', default=MAIN_FOLDER.parent / 'review/incorrect_path.py') + args = parser.parse_args([]) + config = EvaluationConfig(args) + assert create_dataframe(config) == 2 diff --git a/test/python/evaluation/test_xlsx_file_structure.py b/test/python/evaluation/test_xlsx_file_structure.py index 62eb2460..3459d105 100644 --- a/test/python/evaluation/test_xlsx_file_structure.py +++ b/test/python/evaluation/test_xlsx_file_structure.py @@ -1,10 +1,11 @@ -import string -import subprocess from test.python.evaluation import XLSX_DATA_FOLDER -from test.python.evaluation.conftest import EvalLocalCommandBuilder +from test.python.evaluation.testing_config import get_parser import pytest -from src.python.evaluation.common.util import script_structure_rule +from src.python.common.tool_arguments import RunToolArguments +from src.python.evaluation.evaluation_config import EvaluationConfig +from src.python.evaluation.xlsx_run_tool import create_dataframe + FILE_NAMES = [ 'test_wrong_column_name.xlsx', @@ -14,21 +15,10 @@ ] -def compare(string_error: str): - return string_error.translate(string.whitespace + string.punctuation) - - @pytest.mark.parametrize('file_name', FILE_NAMES) -def test_wrong_column(file_name: str, eval_command_builder: EvalLocalCommandBuilder): - file_path = XLSX_DATA_FOLDER / file_name - - eval_command_builder.path = file_path - process = subprocess.run( - eval_command_builder.build(), - stderr=subprocess.PIPE, - stdout=subprocess.PIPE, - text=True, - ) - - assert process.returncode == 2 - assert compare(process.stderr) == compare(script_structure_rule) + '%' +def test_wrong_column(file_name: str): + parser = get_parser(RunToolArguments, n_args=5) + parser.add_argument('-xlsx_file_path', '--xlsx_file_path', default=XLSX_DATA_FOLDER / file_name) + args = parser.parse_args([]) + config = EvaluationConfig(args) + assert create_dataframe(config) == 2 diff --git a/test/python/evaluation/testing_config.py b/test/python/evaluation/testing_config.py index 4efbb789..97159c68 100644 --- a/test/python/evaluation/testing_config.py +++ b/test/python/evaluation/testing_config.py @@ -1,16 +1,23 @@ import argparse import enum +from src.python import MAIN_FOLDER from src.python.evaluation.common.util import EvaluationProcessNames from src.python.review.reviewers.perform_review import OutputFormat -def get_parser(run_tool_arguments: enum.EnumMeta) -> argparse.ArgumentParser: +def get_parser(run_tool_arguments: enum.EnumMeta, n_args=2) -> argparse.ArgumentParser: parser = argparse.ArgumentParser() parser.add_argument('--output_folder_path', '--output_folder_path', default=None) - parser.add_argument('--output_file_name', '--output_file_name', - default=EvaluationProcessNames.RESULTS_EXT.value) parser.add_argument(run_tool_arguments.FORMAT.value.short_name, run_tool_arguments.FORMAT.value.long_name, default=OutputFormat.JSON.value) + if n_args > 2: + parser.add_argument('--output_file_name', '--output_file_name', + default=EvaluationProcessNames.RESULTS_EXT.value) + parser.add_argument('--traceback', '--traceback', default=False) + + if n_args == 5: + parser.add_argument('-tool_path', '--tool_path', + default=MAIN_FOLDER.parent / 'review/run_tool.py') return parser From 168678540fc4144ab9345da25c14e81120f00154 Mon Sep 17 00:00:00 2001 From: diatlova Date: Thu, 22 Apr 2021 17:43:37 +0300 Subject: [PATCH 45/78] Dedugging loggits --- src/python/evaluation/evaluation_config.py | 13 +++- src/python/evaluation/xlsx_run_tool.py | 82 +++++++++++++--------- 2 files changed, 58 insertions(+), 37 deletions(-) diff --git a/src/python/evaluation/evaluation_config.py b/src/python/evaluation/evaluation_config.py index 4ba09fec..b928c185 100644 --- a/src/python/evaluation/evaluation_config.py +++ b/src/python/evaluation/evaluation_config.py @@ -1,3 +1,4 @@ +import logging.config from pathlib import Path from typing import List, Union @@ -6,6 +7,8 @@ from src.python.review.application_config import LanguageVersion from src.python.review.common.file_system import create_directory +logger = logging.getLogger(__name__) + class EvaluationConfig: def __init__(self, args): @@ -30,7 +33,11 @@ def build_command(self, inspected_file_path: Union[str, Path], lang: str, def get_file_path(self) -> Path: if self.output_folder_path is None: - self.output_folder_path = ( - Path(self.xlsx_file_path).parent.parent / EvaluationProcessNames.RESULTS.value) - create_directory(self.output_folder_path) + try: + self.output_folder_path = ( + Path(self.xlsx_file_path).parent.parent / EvaluationProcessNames.RESULTS.value) + create_directory(self.output_folder_path) + except FileNotFoundError: + logger.error('XLSX-file with the specified name does not exists.') + return 2 return Path(self.output_folder_path) / self.output_file_name diff --git a/src/python/evaluation/xlsx_run_tool.py b/src/python/evaluation/xlsx_run_tool.py index 90ac3c5b..f18429cc 100644 --- a/src/python/evaluation/xlsx_run_tool.py +++ b/src/python/evaluation/xlsx_run_tool.py @@ -55,7 +55,7 @@ def configure_arguments(parser: argparse.ArgumentParser, run_tool_arguments: enu default=None, type=str) - parser.add_argument('--output_file_name', '--output_file_name', + parser.add_argument('--output_file_name', '', help='Filename for that will be created to store inspection results.' f'Default is "{EvaluationProcessNames.RESULTS_EXT.value}"', default=f'{EvaluationProcessNames.RESULTS_EXT.value}', @@ -81,43 +81,57 @@ def create_dataframe(config) -> Union[int, pd.DataFrame]: if config.traceback: report[EvaluationProcessNames.TRACEBACK.value] = [] - lang_code_dataframe = pd.read_excel(config.xlsx_file_path) - - for lang, code in zip(lang_code_dataframe[EvaluationProcessNames.LANG.value], - lang_code_dataframe[EvaluationProcessNames.CODE.value]): - - with new_temp_dir() as create_temp_dir: - temp_dir_path = create_temp_dir - lang_extension = LanguageVersion.language_extension()[lang] - temp_file_path = os.path.join(temp_dir_path, ('file' + lang_extension)) - temp_file_path = next(create_file(temp_file_path, code)) - - try: - assert os.path.exists(temp_file_path) - except AssertionError: - logger.exception('Path does not exist.') - return 2 - - command = config.build_command(temp_file_path, lang) - results = run_in_subprocess(command) - os.remove(temp_file_path) - temp_dir_path.rmdir() - - # this regular expression matches final tool grade: EXCELLENT, GOOD, MODERATE or BAD - grades = re.match(r'^.*{"code":\s"([A-Z]+)"', results).group(1) + try: + lang_code_dataframe = pd.read_excel(config.xlsx_file_path) - output_row_values = [lang, code, grades] - column_indices = [EvaluationProcessNames.LANGUAGE.value, EvaluationProcessNames.CODE.value, - EvaluationProcessNames.GRADE.value] + except FileNotFoundError: + logger.error('XLSX-file with the specified name does not exists.') + return 2 - if config.traceback: - output_row_values.append(results) - column_indices.append(EvaluationProcessNames.TRACEBACK.value) + try: + for lang, code in zip(lang_code_dataframe[EvaluationProcessNames.LANG.value], + lang_code_dataframe[EvaluationProcessNames.CODE.value]): + + with new_temp_dir() as create_temp_dir: + temp_dir_path = create_temp_dir + lang_extension = LanguageVersion.language_extension()[lang] + temp_file_path = os.path.join(temp_dir_path, ('file' + lang_extension)) + temp_file_path = next(create_file(temp_file_path, code)) + + try: + assert os.path.exists(temp_file_path) + except AssertionError: + logger.exception('Path does not exist.') + return 2 + + command = config.build_command(temp_file_path, lang) + results = run_in_subprocess(command) + os.remove(temp_file_path) + temp_dir_path.rmdir() + # this regular expression matches final tool grade: EXCELLENT, GOOD, MODERATE or BAD + grades = re.match(r'^.*{"code":\s"([A-Z]+)"', results).group(1) + output_row_values = [lang, code, grades] + column_indices = [EvaluationProcessNames.LANGUAGE.value, + EvaluationProcessNames.CODE.value, + EvaluationProcessNames.GRADE.value] + + if config.traceback: + output_row_values.append(results) + column_indices.append(EvaluationProcessNames.TRACEBACK.value) + + new_file_report_row = pd.Series(data=output_row_values, index=column_indices) + report = report.append(new_file_report_row, ignore_index=True) + + return report - new_file_report_row = pd.Series(data=output_row_values, index=column_indices) - report = report.append(new_file_report_row, ignore_index=True) + except KeyError: + logger.error(script_structure_rule) + return 2 - return report + except Exception: + traceback.print_exc() + logger.exception('An unexpected error.') + return 2 def main() -> int: From ec560a8c58118ea05b5921d534b8f871a55ae0df Mon Sep 17 00:00:00 2001 From: diatlova Date: Thu, 22 Apr 2021 18:24:32 +0300 Subject: [PATCH 46/78] Updated resources --- .../target_sorted_order.xlsx | Bin 37914 -> 38024 bytes .../target_unsorted_order.xlsx | Bin 30898 -> 30970 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/test/resources/evaluation/xlsx_target_files/target_sorted_order.xlsx b/test/resources/evaluation/xlsx_target_files/target_sorted_order.xlsx index 27321600ae3d53b333a399e96612d9e552e9c9d3..8cbc432f93a77f3644267dc7be0886d6f0113bb4 100644 GIT binary patch delta 13418 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 delta 13359 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 z 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 Dw!4uR diff --git a/test/resources/evaluation/xlsx_target_files/target_unsorted_order.xlsx b/test/resources/evaluation/xlsx_target_files/target_unsorted_order.xlsx index 41607c8a9ba3e242aafb5b8d161803db09099170..25ed61462f273535632efd1ca804ad1b33e3dd7a 100644 GIT binary patch delta 12630 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 Herx^@mcy^u From e6111e154dfd15cd7a60064005dc7b52b217c962 Mon Sep 17 00:00:00 2001 From: diatlova Date: Thu, 22 Apr 2021 19:05:33 +0300 Subject: [PATCH 47/78] Remove saved files after debugging --- test/python/evaluation/test_output_results.py | 25 ++++++------------- test/python/evaluation/testing_config.py | 4 +-- 2 files changed, 9 insertions(+), 20 deletions(-) diff --git a/test/python/evaluation/test_output_results.py b/test/python/evaluation/test_output_results.py index c55fde6a..36b495df 100644 --- a/test/python/evaluation/test_output_results.py +++ b/test/python/evaluation/test_output_results.py @@ -1,44 +1,33 @@ -import logging.config from test.python.evaluation import TARGET_XLSX_DATA_FOLDER, XLSX_DATA_FOLDER from test.python.evaluation.testing_config import get_parser from typing import Union import pandas as pd import pytest -from openpyxl import Workbook from src.python import MAIN_FOLDER from src.python.common.tool_arguments import RunToolArguments -from src.python.evaluation.common.xlsx_util import remove_sheet, write_dataframe_to_xlsx_sheet from src.python.evaluation.evaluation_config import EvaluationConfig from src.python.evaluation.xlsx_run_tool import create_dataframe FILE_NAMES = [ - ('test_sorted_order.xlsx', 'target_sorted_order.xlsx', False, 'test1.xlsx'), - ('test_sorted_order.xlsx', 'target_sorted_order.xlsx', 'True', 'test2.xlsx'), - ('test_unsorted_order.xlsx', 'target_unsorted_order.xlsx', False, 'test3.xlsx'), - ('test_unsorted_order.xlsx', 'target_unsorted_order.xlsx', 'True', 'test4.xlsx'), + ('test_sorted_order.xlsx', 'target_sorted_order.xlsx', False), + ('test_sorted_order.xlsx', 'target_sorted_order.xlsx', 'True'), + ('test_unsorted_order.xlsx', 'target_unsorted_order.xlsx', False), + ('test_unsorted_order.xlsx', 'target_unsorted_order.xlsx', 'True'), ] -logger = logging.getLogger(__name__) - -@pytest.mark.parametrize(('test_file', 'target_file', 'output_type', 'output_file_name'), FILE_NAMES) -def test_correct_output(test_file: str, target_file: str, output_type: Union[bool, str], - output_file_name: str): +@pytest.mark.parametrize(('test_file', 'target_file', 'output_type'), FILE_NAMES) +def test_correct_output(test_file: str, target_file: str, output_type: Union[bool, str]): parser = get_parser(RunToolArguments) parser.add_argument('-xlsx_file_path', '--xlsx_file_path', default=XLSX_DATA_FOLDER / test_file) parser.add_argument('-tool_path', '--tool_path', default=MAIN_FOLDER.parent / 'review/run_tool.py') parser.add_argument('--traceback', '--traceback', default=output_type) - parser.add_argument('--output_file_name', '--output_file_name', default=output_file_name) args = parser.parse_args([]) config = EvaluationConfig(args) test_dataframe = create_dataframe(config) - workbook = Workbook() - workbook_path = config.get_file_path() - workbook.save(workbook_path) - write_dataframe_to_xlsx_sheet(workbook_path, test_dataframe, 'inspection_results', 'openpyxl') - remove_sheet(workbook_path, 'Sheet') + sheet_name = 'grades' if output_type: sheet_name = 'traceback' diff --git a/test/python/evaluation/testing_config.py b/test/python/evaluation/testing_config.py index 97159c68..0a8d5b10 100644 --- a/test/python/evaluation/testing_config.py +++ b/test/python/evaluation/testing_config.py @@ -12,9 +12,9 @@ def get_parser(run_tool_arguments: enum.EnumMeta, n_args=2) -> argparse.Argument parser.add_argument(run_tool_arguments.FORMAT.value.short_name, run_tool_arguments.FORMAT.value.long_name, default=OutputFormat.JSON.value) + parser.add_argument('--output_file_name', '--output_file_name', + default=EvaluationProcessNames.RESULTS_EXT.value) if n_args > 2: - parser.add_argument('--output_file_name', '--output_file_name', - default=EvaluationProcessNames.RESULTS_EXT.value) parser.add_argument('--traceback', '--traceback', default=False) if n_args == 5: From 31f12355b3cad862ebb567939cb3f743582bafc2 Mon Sep 17 00:00:00 2001 From: diatlova Date: Fri, 23 Apr 2021 00:19:58 +0300 Subject: [PATCH 48/78] Added evaluation README.me --- src/python/evaluation/README.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 src/python/evaluation/README.md diff --git a/src/python/evaluation/README.md b/src/python/evaluation/README.md new file mode 100644 index 00000000..dfedacfa --- /dev/null +++ b/src/python/evaluation/README.md @@ -0,0 +1,21 @@ +**Usage** + +Run the xlsx_run_tool.py with the arguments. + +Required arguments: + +xlsx_file_path — path to xlsx-file with code samples to inspect. +Please, note that your file should consist of at least 2 obligatory columns: +- **code** +- **lang** + +Possible values for column lang: python3, kotlin, java8, java11. + +Original arguments: +|Argument | Description| +| --- | --- | +|‑f, ‑‑format| the output format. Available values: json, text. The default value is json .| +|-tool_path, --tool_path| path to run-tool. Default is src/python/review/run_tool.py .| +|--traceback, --traceback| If true column with errors traceback is included to the output file. Default is False.| +|--output_folder_path, --output_folder_path| path to the folder to store file with results. Default is a parent directory of a folder with xlsx-file sent for inspection. | +|--output_file_name, --output_file_name| the name of the output file where evaluation results will be stored. Default is results.xlsx .| \ No newline at end of file From 76ecafe01ff385019c7e0f785bd4ecbb7785add4 Mon Sep 17 00:00:00 2001 From: diatlova Date: Fri, 23 Apr 2021 00:32:15 +0300 Subject: [PATCH 49/78] Updated readme and fixed argname --- src/python/evaluation/README.md | 14 +++++++------- src/python/evaluation/xlsx_run_tool.py | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/python/evaluation/README.md b/src/python/evaluation/README.md index dfedacfa..4dc41ec7 100644 --- a/src/python/evaluation/README.md +++ b/src/python/evaluation/README.md @@ -9,13 +9,13 @@ Please, note that your file should consist of at least 2 obligatory columns: - **code** - **lang** -Possible values for column lang: python3, kotlin, java8, java11. +Possible values for column **lang** are: python3, kotlin, java8, java11. -Original arguments: +Optional arguments: |Argument | Description| | --- | --- | -|‑f, ‑‑format| the output format. Available values: json, text. The default value is json .| -|-tool_path, --tool_path| path to run-tool. Default is src/python/review/run_tool.py .| -|--traceback, --traceback| If true column with errors traceback is included to the output file. Default is False.| -|--output_folder_path, --output_folder_path| path to the folder to store file with results. Default is a parent directory of a folder with xlsx-file sent for inspection. | -|--output_file_name, --output_file_name| the name of the output file where evaluation results will be stored. Default is results.xlsx .| \ No newline at end of file +|‑f, ‑‑format| The output format. Available values: `json`, `text`. The default value is json .| +|-tool_path, --tool_path| Path to run-tool. Default is src/python/review/run_tool.py .| +|--traceback, --traceback| If true column with errors traceback is included to an output file. Default is `False`.| +|--output_folder_path, --output_folder_path| An explicit folder path to store file with results. Default is a parent directory of a folder with xlsx-file sent for inspection. | +|--output_file_name, --output_file_name| A name of an output file where evaluation results will be stored. Default is `results.xlsx`.| \ No newline at end of file diff --git a/src/python/evaluation/xlsx_run_tool.py b/src/python/evaluation/xlsx_run_tool.py index f18429cc..7365d90d 100644 --- a/src/python/evaluation/xlsx_run_tool.py +++ b/src/python/evaluation/xlsx_run_tool.py @@ -55,7 +55,7 @@ def configure_arguments(parser: argparse.ArgumentParser, run_tool_arguments: enu default=None, type=str) - parser.add_argument('--output_file_name', '', + parser.add_argument('--output_file_name', '--output_file_name', help='Filename for that will be created to store inspection results.' f'Default is "{EvaluationProcessNames.RESULTS_EXT.value}"', default=f'{EvaluationProcessNames.RESULTS_EXT.value}', From 53f45f108a08cba04bdc9f3bdae1d39e12fe1c7c Mon Sep 17 00:00:00 2001 From: diatlova Date: Mon, 26 Apr 2021 11:15:00 +0300 Subject: [PATCH 50/78] Resolved pull request issues --- src/python/evaluation/evaluation_config.py | 5 +++-- src/python/evaluation/xlsx_run_tool.py | 13 ++++++------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/python/evaluation/evaluation_config.py b/src/python/evaluation/evaluation_config.py index b928c185..4ff75cdd 100644 --- a/src/python/evaluation/evaluation_config.py +++ b/src/python/evaluation/evaluation_config.py @@ -28,14 +28,15 @@ def build_command(self, inspected_file_path: Union[str, Path], lang: str, run_tool_arguments.FORMAT.value.short_name, self.output_format] if lang == LanguageVersion.JAVA_8.value or lang == LanguageVersion.JAVA_11.value: - command.extend([run_tool_arguments.LANG_VERSION.value.short_name, lang]) + command.extend(['--language_version', lang]) return command def get_file_path(self) -> Path: if self.output_folder_path is None: try: self.output_folder_path = ( - Path(self.xlsx_file_path).parent.parent / EvaluationProcessNames.RESULTS.value) + Path(self.xlsx_file_path).parent.parent / EvaluationProcessNames.RESULTS.value + ) create_directory(self.output_folder_path) except FileNotFoundError: logger.error('XLSX-file with the specified name does not exists.') diff --git a/src/python/evaluation/xlsx_run_tool.py b/src/python/evaluation/xlsx_run_tool.py index 7365d90d..fa56397c 100644 --- a/src/python/evaluation/xlsx_run_tool.py +++ b/src/python/evaluation/xlsx_run_tool.py @@ -36,18 +36,17 @@ def configure_arguments(parser: argparse.ArgumentParser, run_tool_arguments: enu f'{LanguageVersion.PYTHON_3.value}, {LanguageVersion.JAVA_8.value}, ' f'{LanguageVersion.JAVA_11.value}, {LanguageVersion.KOTLIN.value}.') - parser.add_argument('-tool_path', '--tool_path', + parser.add_argument('-tp', '--tool-path', default=Path('src/python/review/run_tool.py').absolute(), type=lambda value: Path(value).absolute(), help='Path to script to run on files.') - parser.add_argument('--traceback', '--traceback', + parser.add_argument('-tr', '--traceback', help='If True, column with the full inspector feedback will be added ' 'to the output file with results.', - default=False, - type=bool) + action='store_true') - parser.add_argument('--output_folder_path', '--output_folder_path', + parser.add_argument('-ofp', '--output-folder-path', help='An absolute path to the folder where file with evaluation results' 'will be stored.' 'Default is the path to a directory, where is the folder with xlsx_file.', @@ -55,7 +54,7 @@ def configure_arguments(parser: argparse.ArgumentParser, run_tool_arguments: enu default=None, type=str) - parser.add_argument('--output_file_name', '--output_file_name', + parser.add_argument('-ofn', '--output-file-name', help='Filename for that will be created to store inspection results.' f'Default is "{EvaluationProcessNames.RESULTS_EXT.value}"', default=f'{EvaluationProcessNames.RESULTS_EXT.value}', @@ -66,7 +65,7 @@ def configure_arguments(parser: argparse.ArgumentParser, run_tool_arguments: enu default=OutputFormat.JSON.value, choices=OutputFormat.values(), type=str, - help=run_tool_arguments.FORMAT.value.description) + help=run_tool_arguments.FORMAT.value.help) def create_dataframe(config) -> Union[int, pd.DataFrame]: From f07a717bfa26425cf7465bba44d5b3002c27e3bf Mon Sep 17 00:00:00 2001 From: diatlova Date: Mon, 26 Apr 2021 11:15:41 +0300 Subject: [PATCH 51/78] Resolved pull request issues --- src/python/common/tool_arguments.py | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/python/common/tool_arguments.py b/src/python/common/tool_arguments.py index 237eb2ff..ef9ae1c6 100644 --- a/src/python/common/tool_arguments.py +++ b/src/python/common/tool_arguments.py @@ -1,6 +1,6 @@ from dataclasses import dataclass from enum import Enum, unique -from typing import List, Union +from typing import List, Optional from src.python.review.inspectors.inspector_type import InspectorType @@ -22,19 +22,18 @@ def values(cls) -> List[str]: @dataclass(frozen=True) class ArgumentsCharacteristics: - short_name: Union[str, None] + short_name: Optional[str] long_name: str - description: str + help: str inspectors = [inspector.lower() for inspector in InspectorType.available_values()] -example = f'-d {inspectors[0].lower()},{inspectors[1].lower()}' +disabled_inspectors_example = f'-d {inspectors[0].lower()},{inspectors[1].lower()}' @unique class RunToolArguments(Enum): - VERBOSITY = ArgumentsCharacteristics('-v', - '--verbosity', + VERBOSITY = ArgumentsCharacteristics('-v', '--verbosity', 'Choose logging level: ' f'{VerbosityLevel.ERROR.value} - ERROR; ' f'{VerbosityLevel.INFO.value} - INFO; ' @@ -45,16 +44,16 @@ class RunToolArguments(Enum): DISABLE = ArgumentsCharacteristics('-d', '--disable', 'Disable inspectors. ' f'Allowed values: {", ".join(inspectors)}. ' - f'Example: {example}') + f'Example: {disabled_inspectors_example}') DUPLICATES = ArgumentsCharacteristics(None, '--allow-duplicates', 'Allow duplicate issues found by different linters. ' 'By default, duplicates are skipped.') - LANG_VERSION = ArgumentsCharacteristics('--language_version', '--language_version', + LANG_VERSION = ArgumentsCharacteristics(None, '--language-version', 'Specify the language version for JAVA inspectors.') - CPU = ArgumentsCharacteristics('--n_cpu', '--n-cpu', + CPU = ArgumentsCharacteristics(None, '--n-cpu', 'Specify number of cpu that can be used to run inspectors') PATH = ArgumentsCharacteristics(None, 'path', 'Path to file or directory to inspect.') From 7b1a14ab83436adf2c79140698526f5dd6222462 Mon Sep 17 00:00:00 2001 From: diatlova Date: Mon, 26 Apr 2021 11:16:22 +0300 Subject: [PATCH 52/78] Resolved pull request issues --- src/python/review/run_tool.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/python/review/run_tool.py b/src/python/review/run_tool.py index a171c832..a41a08cb 100644 --- a/src/python/review/run_tool.py +++ b/src/python/review/run_tool.py @@ -45,7 +45,7 @@ def positive_int(value: str) -> int: def configure_arguments(parser: argparse.ArgumentParser, tool_arguments: enum.EnumMeta) -> None: parser.add_argument(tool_arguments.VERBOSITY.value.short_name, tool_arguments.VERBOSITY.value.long_name, - help=tool_arguments.VERBOSITY.value.description, + help=tool_arguments.VERBOSITY.value.help, default=VerbosityLevel.DISABLE.value, choices=VerbosityLevel.values(), type=str) @@ -53,55 +53,55 @@ def configure_arguments(parser: argparse.ArgumentParser, tool_arguments: enum.En # Usage example: -d Flake8,Intelli parser.add_argument(tool_arguments.DISABLE.value.short_name, tool_arguments.DISABLE.value.long_name, - help=tool_arguments.DISABLE.value.description, + help=tool_arguments.DISABLE.value.help, type=parse_disabled_inspectors, default=set()) parser.add_argument(tool_arguments.DUPLICATES.value.long_name, action='store_true', - help=tool_arguments.DUPLICATES.value.description) + help=tool_arguments.DUPLICATES.value.help) # TODO: deprecated argument: language_version. Delete after several releases. - parser.add_argument(tool_arguments.LANG_VERSION.value.short_name, + parser.add_argument('--language_version', tool_arguments.LANG_VERSION.value.long_name, - help=tool_arguments.LANG_VERSION.value.description, + help=tool_arguments.LANG_VERSION.value.help, default=None, choices=LanguageVersion.values(), type=str) # TODO: deprecated argument: --n_cpu. Delete after several releases. - parser.add_argument(tool_arguments.CPU.value.short_name, + parser.add_argument('--n_cpu', tool_arguments.CPU.value.long_name, - help=tool_arguments.CPU.value.description, + help=tool_arguments.CPU.value.help, default=1, type=positive_int) parser.add_argument(tool_arguments.PATH.value.long_name, type=lambda value: Path(value).absolute(), - help=tool_arguments.PATH.value.description) + help=tool_arguments.PATH.value.help) parser.add_argument(tool_arguments.FORMAT.value.short_name, tool_arguments.FORMAT.value.long_name, default=OutputFormat.JSON.value, choices=OutputFormat.values(), type=str, - help=tool_arguments.FORMAT.value.description) + help=tool_arguments.FORMAT.value.help) parser.add_argument(tool_arguments.START_LINE.value.short_name, tool_arguments.START_LINE.value.long_name, default=1, type=positive_int, - help=tool_arguments.START_LINE.value.description) + help=tool_arguments.START_LINE.value.help) parser.add_argument(tool_arguments.END_LINE.value.short_name, tool_arguments.END_LINE.value.long_name, default=None, type=positive_int, - help=tool_arguments.END_LINE.value.description) + help=tool_arguments.END_LINE.value.help) parser.add_argument(tool_arguments.NEW_FORMAT.value.long_name, action='store_true', - help=tool_arguments.NEW_FORMAT.value.description) + help=tool_arguments.NEW_FORMAT.value.help) def configure_logging(verbosity: VerbosityLevel) -> None: From ede99f85f7b1da4977b4be39f5dbc79b830a3c60 Mon Sep 17 00:00:00 2001 From: diatlova Date: Mon, 26 Apr 2021 11:17:11 +0300 Subject: [PATCH 53/78] Resolved pull request issues --- test/python/evaluation/test_data_path.py | 2 +- test/python/evaluation/test_output_results.py | 14 +++++++++----- test/python/evaluation/test_tool_path.py | 2 +- test/python/evaluation/test_xlsx_file_structure.py | 2 +- test/python/evaluation/testing_config.py | 8 ++++---- 5 files changed, 16 insertions(+), 12 deletions(-) diff --git a/test/python/evaluation/test_data_path.py b/test/python/evaluation/test_data_path.py index 187e73b8..4601e116 100644 --- a/test/python/evaluation/test_data_path.py +++ b/test/python/evaluation/test_data_path.py @@ -8,7 +8,7 @@ def test_incorrect_data_path(): parser = get_parser(RunToolArguments, n_args=5) - parser.add_argument('-xlsx_file_path', '--xlsx_file_path', default=XLSX_DATA_FOLDER / 'do_not_exist.xlsx') + parser.add_argument('-xlsx_file_path', default=XLSX_DATA_FOLDER / 'do_not_exist.xlsx') args = parser.parse_args([]) config = EvaluationConfig(args) assert create_dataframe(config) == 2 diff --git a/test/python/evaluation/test_output_results.py b/test/python/evaluation/test_output_results.py index 36b495df..a459969c 100644 --- a/test/python/evaluation/test_output_results.py +++ b/test/python/evaluation/test_output_results.py @@ -11,9 +11,9 @@ FILE_NAMES = [ ('test_sorted_order.xlsx', 'target_sorted_order.xlsx', False), - ('test_sorted_order.xlsx', 'target_sorted_order.xlsx', 'True'), + ('test_sorted_order.xlsx', 'target_sorted_order.xlsx', True), ('test_unsorted_order.xlsx', 'target_unsorted_order.xlsx', False), - ('test_unsorted_order.xlsx', 'target_unsorted_order.xlsx', 'True'), + ('test_unsorted_order.xlsx', 'target_unsorted_order.xlsx', True), ] @@ -21,9 +21,13 @@ def test_correct_output(test_file: str, target_file: str, output_type: Union[bool, str]): parser = get_parser(RunToolArguments) - parser.add_argument('-xlsx_file_path', '--xlsx_file_path', default=XLSX_DATA_FOLDER / test_file) - parser.add_argument('-tool_path', '--tool_path', default=MAIN_FOLDER.parent / 'review/run_tool.py') - parser.add_argument('--traceback', '--traceback', default=output_type) + parser.add_argument('-xlsx_file_path', default=XLSX_DATA_FOLDER / test_file) + parser.add_argument('-tp', '--tool-path', default=MAIN_FOLDER.parent / 'review/run_tool.py') + if output_type: + parser.add_argument('-tr', '--traceback', action='store_false') + else: + parser.add_argument('-tr', '--traceback', action='store_true') + args = parser.parse_args([]) config = EvaluationConfig(args) test_dataframe = create_dataframe(config) diff --git a/test/python/evaluation/test_tool_path.py b/test/python/evaluation/test_tool_path.py index 04d50a94..fd845909 100644 --- a/test/python/evaluation/test_tool_path.py +++ b/test/python/evaluation/test_tool_path.py @@ -19,7 +19,7 @@ def test_correct_tool_path(run_tool_arguments=RunToolArguments): def test_incorrect_tool_path(run_tool_arguments=RunToolArguments): parser = get_parser(run_tool_arguments, n_args=4) parser.add_argument('-xlsx_file_path', default=XLSX_DATA_FOLDER / 'test_unsorted_order.xlsx') - parser.add_argument('-tool_path', '--tool_path', default=MAIN_FOLDER.parent / 'review/incorrect_path.py') + parser.add_argument('-tp', '--tool-path', default=MAIN_FOLDER.parent / 'review/incorrect_path.py') args = parser.parse_args([]) config = EvaluationConfig(args) assert create_dataframe(config) == 2 diff --git a/test/python/evaluation/test_xlsx_file_structure.py b/test/python/evaluation/test_xlsx_file_structure.py index 3459d105..f315dc32 100644 --- a/test/python/evaluation/test_xlsx_file_structure.py +++ b/test/python/evaluation/test_xlsx_file_structure.py @@ -18,7 +18,7 @@ @pytest.mark.parametrize('file_name', FILE_NAMES) def test_wrong_column(file_name: str): parser = get_parser(RunToolArguments, n_args=5) - parser.add_argument('-xlsx_file_path', '--xlsx_file_path', default=XLSX_DATA_FOLDER / file_name) + parser.add_argument('-xlsx_file_path', default=XLSX_DATA_FOLDER / file_name) args = parser.parse_args([]) config = EvaluationConfig(args) assert create_dataframe(config) == 2 diff --git a/test/python/evaluation/testing_config.py b/test/python/evaluation/testing_config.py index 0a8d5b10..1d9af73f 100644 --- a/test/python/evaluation/testing_config.py +++ b/test/python/evaluation/testing_config.py @@ -8,16 +8,16 @@ def get_parser(run_tool_arguments: enum.EnumMeta, n_args=2) -> argparse.ArgumentParser: parser = argparse.ArgumentParser() - parser.add_argument('--output_folder_path', '--output_folder_path', default=None) + parser.add_argument('-ofp', '--output-folder-path', default=None) parser.add_argument(run_tool_arguments.FORMAT.value.short_name, run_tool_arguments.FORMAT.value.long_name, default=OutputFormat.JSON.value) - parser.add_argument('--output_file_name', '--output_file_name', + parser.add_argument('-ofn', '--output-file-name', default=EvaluationProcessNames.RESULTS_EXT.value) if n_args > 2: - parser.add_argument('--traceback', '--traceback', default=False) + parser.add_argument('-tr', '--traceback', action='store_true') if n_args == 5: - parser.add_argument('-tool_path', '--tool_path', + parser.add_argument('-tp', '--tool-path', default=MAIN_FOLDER.parent / 'review/run_tool.py') return parser From a7fd99f046b451737bc688abb4c3965cbc206a9d Mon Sep 17 00:00:00 2001 From: diatlova Date: Mon, 26 Apr 2021 12:17:29 +0300 Subject: [PATCH 54/78] Updated flags in README.md --- README.md | 4 ++-- src/python/evaluation/README.md | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 43370839..defa140b 100644 --- a/README.md +++ b/README.md @@ -97,8 +97,8 @@ Argument | Description **‑v**, **‑‑verbosity** | choose logging level according [this](https://docs.python.org/3/library/logging.html#levels) list: `1` - **ERROR**; `2` - **INFO**; `3` - **DEBUG**; `0` - disable logging (**CRITICAL** value); default value is `0` (**CRITICAL**). **‑d**, **‑‑disable** | disable inspectors. Available values: for **Python** language: `pylint` for [Pylint](https://github.com/PyCQA/pylint), `flake8` for [flake8](https://flake8.pycqa.org/en/latest/), `radon` for [Radon](https://radon.readthedocs.io/en/latest/), `python_ast` to check different measures providing by AST; for **Java** language: `checkstyle` for the [Checkstyle](https://checkstyle.sourceforge.io/), `pmd` for [PMD](https://pmd.github.io/); for `Kotlin` language: detekt for [Detekt](https://detekt.github.io/detekt/); for **JavaScript** language: `eslint` for [ESlint](https://eslint.org/). Example: `-d pylint,flake8`. **‑‑allow-duplicates** | allow duplicate issues found by different linters. By default, duplicates are skipped. -**‑‑language-version**, **‑‑language_version** | specify the language version for JAVA inspectors. Available values: `java7`, `java8`, `java9`, `java11`. **Note**: **‑‑language_version** is deprecated. Will be deleted in the future. -**‑‑n-cpu**, **‑‑n_cpu** | specify number of _cpu_ that can be used to run inspectors. **Note**: **‑‑n_cpu** is deprecated. Will be deleted in the future. +**‑‑language-version** | specify the language version for JAVA inspectors. Available values: `java7`, `java8`, `java9`, `java11`. **Note**: **‑‑language_version** is deprecated. Will be deleted in the future. +**‑‑n-cpu** | specify number of _cpu_ that can be used to run inspectors. **Note**: **‑‑n_cpu** is deprecated. Will be deleted in the future. **‑f**, **‑‑format** | the output format. Available values: `json`, `text`. Default value is `json`. **‑s**, **‑‑start-line**| the first line to be analyzed. By default it starts from `1`. **‑e**, **‑‑end-line** | the end line to be analyzed. The default value is `None`, which meant to handle file by the end. diff --git a/src/python/evaluation/README.md b/src/python/evaluation/README.md index 4dc41ec7..d7a4ae37 100644 --- a/src/python/evaluation/README.md +++ b/src/python/evaluation/README.md @@ -15,7 +15,7 @@ Optional arguments: |Argument | Description| | --- | --- | |‑f, ‑‑format| The output format. Available values: `json`, `text`. The default value is json .| -|-tool_path, --tool_path| Path to run-tool. Default is src/python/review/run_tool.py .| -|--traceback, --traceback| If true column with errors traceback is included to an output file. Default is `False`.| -|--output_folder_path, --output_folder_path| An explicit folder path to store file with results. Default is a parent directory of a folder with xlsx-file sent for inspection. | -|--output_file_name, --output_file_name| A name of an output file where evaluation results will be stored. Default is `results.xlsx`.| \ No newline at end of file +|-tp, --tool_path| Path to run-tool. Default is src/python/review/run_tool.py .| +|--tr, --traceback| If true column with errors traceback is included to an output file. Default is `False`.| +|--ofp, --output_folder_path| An explicit folder path to store file with results. Default is a parent directory of a folder with xlsx-file sent for inspection. | +|--ofn, --output_file_name| A name of an output file where evaluation results will be stored. Default is `results.xlsx`.| \ No newline at end of file From 5dd2adcb7dd13b6dca4f9207dc919da545ebdc38 Mon Sep 17 00:00:00 2001 From: Daria Diatlova Date: Mon, 26 Apr 2021 13:55:33 +0300 Subject: [PATCH 55/78] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index defa140b..9f3012a7 100644 --- a/README.md +++ b/README.md @@ -97,8 +97,8 @@ Argument | Description **‑v**, **‑‑verbosity** | choose logging level according [this](https://docs.python.org/3/library/logging.html#levels) list: `1` - **ERROR**; `2` - **INFO**; `3` - **DEBUG**; `0` - disable logging (**CRITICAL** value); default value is `0` (**CRITICAL**). **‑d**, **‑‑disable** | disable inspectors. Available values: for **Python** language: `pylint` for [Pylint](https://github.com/PyCQA/pylint), `flake8` for [flake8](https://flake8.pycqa.org/en/latest/), `radon` for [Radon](https://radon.readthedocs.io/en/latest/), `python_ast` to check different measures providing by AST; for **Java** language: `checkstyle` for the [Checkstyle](https://checkstyle.sourceforge.io/), `pmd` for [PMD](https://pmd.github.io/); for `Kotlin` language: detekt for [Detekt](https://detekt.github.io/detekt/); for **JavaScript** language: `eslint` for [ESlint](https://eslint.org/). Example: `-d pylint,flake8`. **‑‑allow-duplicates** | allow duplicate issues found by different linters. By default, duplicates are skipped. -**‑‑language-version** | specify the language version for JAVA inspectors. Available values: `java7`, `java8`, `java9`, `java11`. **Note**: **‑‑language_version** is deprecated. Will be deleted in the future. -**‑‑n-cpu** | specify number of _cpu_ that can be used to run inspectors. **Note**: **‑‑n_cpu** is deprecated. Will be deleted in the future. +**‑‑language_version**, **‑‑language-version** | specify the language version for JAVA inspectors. Available values: `java7`, `java8`, `java9`, `java11`. **Note**: **‑‑language_version** is deprecated. Will be deleted in the future. +**‑‑n_cpu**, **‑‑n-cpu** | specify number of _cpu_ that can be used to run inspectors. **Note**: **‑‑n_cpu** is deprecated. Will be deleted in the future. **‑f**, **‑‑format** | the output format. Available values: `json`, `text`. Default value is `json`. **‑s**, **‑‑start-line**| the first line to be analyzed. By default it starts from `1`. **‑e**, **‑‑end-line** | the end line to be analyzed. The default value is `None`, which meant to handle file by the end. From 04123e023d54db8f915d29798cce58ea92a4b72b Mon Sep 17 00:00:00 2001 From: Daria Diatlova Date: Mon, 26 Apr 2021 14:01:28 +0300 Subject: [PATCH 56/78] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 9f3012a7..6b73a18f 100644 --- a/README.md +++ b/README.md @@ -97,8 +97,8 @@ Argument | Description **‑v**, **‑‑verbosity** | choose logging level according [this](https://docs.python.org/3/library/logging.html#levels) list: `1` - **ERROR**; `2` - **INFO**; `3` - **DEBUG**; `0` - disable logging (**CRITICAL** value); default value is `0` (**CRITICAL**). **‑d**, **‑‑disable** | disable inspectors. Available values: for **Python** language: `pylint` for [Pylint](https://github.com/PyCQA/pylint), `flake8` for [flake8](https://flake8.pycqa.org/en/latest/), `radon` for [Radon](https://radon.readthedocs.io/en/latest/), `python_ast` to check different measures providing by AST; for **Java** language: `checkstyle` for the [Checkstyle](https://checkstyle.sourceforge.io/), `pmd` for [PMD](https://pmd.github.io/); for `Kotlin` language: detekt for [Detekt](https://detekt.github.io/detekt/); for **JavaScript** language: `eslint` for [ESlint](https://eslint.org/). Example: `-d pylint,flake8`. **‑‑allow-duplicates** | allow duplicate issues found by different linters. By default, duplicates are skipped. -**‑‑language_version**, **‑‑language-version** | specify the language version for JAVA inspectors. Available values: `java7`, `java8`, `java9`, `java11`. **Note**: **‑‑language_version** is deprecated. Will be deleted in the future. -**‑‑n_cpu**, **‑‑n-cpu** | specify number of _cpu_ that can be used to run inspectors. **Note**: **‑‑n_cpu** is deprecated. Will be deleted in the future. +**‑‑language-version**, **‑‑language_version** | specify the language version for JAVA inspectors. Available values: `java7`, `java8`, `java9`, `java11`. **Note**: **‑‑language_version** is deprecated. Will be deleted in the future. +**‑‑n-cpu**, **‑‑n_cpu** | specify number of _cpu_ that can be used to run inspectors. **Note**: **‑‑n_cpu** is deprecated. Will be deleted in the future. **‑f**, **‑‑format** | the output format. Available values: `json`, `text`. Default value is `json`. **‑s**, **‑‑start-line**| the first line to be analyzed. By default it starts from `1`. **‑e**, **‑‑end-line** | the end line to be analyzed. The default value is `None`, which meant to handle file by the end. From 9e3873f62f13385d5f8dd89e0240445749c6a636 Mon Sep 17 00:00:00 2001 From: Daria Diatlova Date: Mon, 26 Apr 2021 14:09:13 +0300 Subject: [PATCH 57/78] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6b73a18f..43370839 100644 --- a/README.md +++ b/README.md @@ -97,7 +97,7 @@ Argument | Description **‑v**, **‑‑verbosity** | choose logging level according [this](https://docs.python.org/3/library/logging.html#levels) list: `1` - **ERROR**; `2` - **INFO**; `3` - **DEBUG**; `0` - disable logging (**CRITICAL** value); default value is `0` (**CRITICAL**). **‑d**, **‑‑disable** | disable inspectors. Available values: for **Python** language: `pylint` for [Pylint](https://github.com/PyCQA/pylint), `flake8` for [flake8](https://flake8.pycqa.org/en/latest/), `radon` for [Radon](https://radon.readthedocs.io/en/latest/), `python_ast` to check different measures providing by AST; for **Java** language: `checkstyle` for the [Checkstyle](https://checkstyle.sourceforge.io/), `pmd` for [PMD](https://pmd.github.io/); for `Kotlin` language: detekt for [Detekt](https://detekt.github.io/detekt/); for **JavaScript** language: `eslint` for [ESlint](https://eslint.org/). Example: `-d pylint,flake8`. **‑‑allow-duplicates** | allow duplicate issues found by different linters. By default, duplicates are skipped. -**‑‑language-version**, **‑‑language_version** | specify the language version for JAVA inspectors. Available values: `java7`, `java8`, `java9`, `java11`. **Note**: **‑‑language_version** is deprecated. Will be deleted in the future. +**‑‑language-version**, **‑‑language_version** | specify the language version for JAVA inspectors. Available values: `java7`, `java8`, `java9`, `java11`. **Note**: **‑‑language_version** is deprecated. Will be deleted in the future. **‑‑n-cpu**, **‑‑n_cpu** | specify number of _cpu_ that can be used to run inspectors. **Note**: **‑‑n_cpu** is deprecated. Will be deleted in the future. **‑f**, **‑‑format** | the output format. Available values: `json`, `text`. Default value is `json`. **‑s**, **‑‑start-line**| the first line to be analyzed. By default it starts from `1`. From 4ca46100a9b95895588c526fa8bc5be350b9f942 Mon Sep 17 00:00:00 2001 From: Daria Diatlova Date: Tue, 27 Apr 2021 15:44:37 +0300 Subject: [PATCH 58/78] Update README.md --- src/python/evaluation/README.md | 40 ++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/src/python/evaluation/README.md b/src/python/evaluation/README.md index d7a4ae37..ad0a4b1d 100644 --- a/src/python/evaluation/README.md +++ b/src/python/evaluation/README.md @@ -1,21 +1,31 @@ -**Usage** +# Hyperstyle evaluation -Run the xlsx_run_tool.py with the arguments. +This tool allows running the `Hyperstyle` tool on an xlsx table to get code quality for all code fragments. Please, note that your input file should consist of at least 2 obligatory columns to run xlsx-tool on its code fragments: -Required arguments: +- `code` +- `lang` + +Possible values for column `lang` are: python3, kotlin, java8, java11. + +Output file is a new xlsx file with 3 columns: +- `code` +- `lang` +- `grade` +Grade assesesment is condicted by [`run_tool.py`](https://github.com/hyperskill/hyperstyle/blob/main/README.md) with default arguments. Avaliable values for column `grade` are: BAD, MODERATE, GOOD, EXCELLENT. It is also possible add fourth column: `traceback` to get full inspectors feedback on each code fragment. More details on enabling traceback column in **Optional Arguments** table. -xlsx_file_path — path to xlsx-file with code samples to inspect. -Please, note that your file should consist of at least 2 obligatory columns: -- **code** -- **lang** +## Usage + +Run the xlsx_run_tool.py with the arguments from command line. + +Required arguments: -Possible values for column **lang** are: python3, kotlin, java8, java11. +`xlsx_file_path` — path to xlsx-file with code samples to inspect. Optional arguments: -|Argument | Description| -| --- | --- | -|‑f, ‑‑format| The output format. Available values: `json`, `text`. The default value is json .| -|-tp, --tool_path| Path to run-tool. Default is src/python/review/run_tool.py .| -|--tr, --traceback| If true column with errors traceback is included to an output file. Default is `False`.| -|--ofp, --output_folder_path| An explicit folder path to store file with results. Default is a parent directory of a folder with xlsx-file sent for inspection. | -|--ofn, --output_file_name| A name of an output file where evaluation results will be stored. Default is `results.xlsx`.| \ No newline at end of file +Argument | Description +--- | --- +|**‑f**, **‑‑format**| The output format. Available values: `json`, `text`. The default value is json .| +|**‑tp**, **‑‑tool_path**| Path to run-tool. Default is src/python/review/run_tool.py .| +|**‑tr**, **‑‑traceback**| If true column with errors traceback is included to an output file. Default is `False`.| +|**‑ofp**, **‑‑output_folder_path**| An explicit folder path to store file with results. Default is a parent directory of a folder with xlsx-file sent for inspection. | +|**‑ofn**, **‑‑output_file_name**| A name of an output file where evaluation results will be stored. Default is `results.xlsx`.| From bed4b5361cab5ec749c11552be7dacd273dc94be Mon Sep 17 00:00:00 2001 From: Daria Diatlova Date: Wed, 28 Apr 2021 14:15:16 +0300 Subject: [PATCH 59/78] Update README.md --- src/python/evaluation/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/python/evaluation/README.md b/src/python/evaluation/README.md index ad0a4b1d..490b93bf 100644 --- a/src/python/evaluation/README.md +++ b/src/python/evaluation/README.md @@ -24,7 +24,7 @@ Required arguments: Optional arguments: Argument | Description --- | --- -|**‑f**, **‑‑format**| The output format. Available values: `json`, `text`. The default value is json .| +|**‑f**, **‑‑format**| The output format. Available values: `json`, `text`. The default value is json . Use this argument when `traceback` is enabled, otherwise it will not be used.| |**‑tp**, **‑‑tool_path**| Path to run-tool. Default is src/python/review/run_tool.py .| |**‑tr**, **‑‑traceback**| If true column with errors traceback is included to an output file. Default is `False`.| |**‑ofp**, **‑‑output_folder_path**| An explicit folder path to store file with results. Default is a parent directory of a folder with xlsx-file sent for inspection. | From d6bbc115f8677034fc2c10534d9fba37bd264a62 Mon Sep 17 00:00:00 2001 From: diatlova Date: Wed, 28 Apr 2021 16:54:13 +0300 Subject: [PATCH 60/78] Added a separate requirements file for evaluation module --- .github/workflows/build.yml | 5 +++-- requirements-evaluation.txt | 2 ++ requirements.txt | 2 -- whitelist.txt | 1 + 4 files changed, 6 insertions(+), 4 deletions(-) create mode 100644 requirements-evaluation.txt diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e051428e..d4385934 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -22,6 +22,7 @@ jobs: pip install flake8 pytest pip install -r requirements.txt pip install -r requirements-test.txt + pip install -r requirements-evaluation.txt - name: Lint with flake8 run: | # stop the build if there are Python syntax errors or undefined names @@ -38,10 +39,10 @@ jobs: java-version: '11' - name: Check java version run: java -version - + - name: Test with pytest run: | - pytest + pytest - name: Upload pytest test results uses: actions/upload-artifact@v2 with: diff --git a/requirements-evaluation.txt b/requirements-evaluation.txt new file mode 100644 index 00000000..11910373 --- /dev/null +++ b/requirements-evaluation.txt @@ -0,0 +1,2 @@ +openpyxl==3.0.7 +pandas==1.2.3 \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index e173598f..c61d633a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -28,5 +28,3 @@ radon==4.5.0 django==3.2 requests==2.25.1 argparse==1.4.0 -pandas==1.2.3 -openpyxl==3.0.7 diff --git a/whitelist.txt b/whitelist.txt index 042e8c0d..501f7d0c 100644 --- a/whitelist.txt +++ b/whitelist.txt @@ -81,6 +81,7 @@ openpyxl dataframe writelines rmdir +df # Springlint issues cbo dit From 753545271d0325d1abe83d43e3632d9ab5c3bf3d Mon Sep 17 00:00:00 2001 From: diatlova Date: Wed, 28 Apr 2021 16:57:00 +0300 Subject: [PATCH 61/78] Resolved PR issues --- src/python/common/tool_arguments.py | 71 ++++++++++--------- src/python/evaluation/common/util.py | 23 +++--- src/python/evaluation/common/xlsx_util.py | 35 ++++++--- src/python/evaluation/evaluation_config.py | 41 ++++++----- src/python/evaluation/xlsx_run_tool.py | 64 ++++++++--------- src/python/review/common/file_system.py | 1 + src/python/review/run_tool.py | 24 +++---- test/python/evaluation/test_data_path.py | 14 ++-- test/python/evaluation/test_output_results.py | 20 ++---- test/python/evaluation/test_tool_path.py | 27 ++++--- .../evaluation/test_xlsx_file_structure.py | 13 ++-- test/python/evaluation/testing_config.py | 25 +++---- 12 files changed, 183 insertions(+), 175 deletions(-) diff --git a/src/python/common/tool_arguments.py b/src/python/common/tool_arguments.py index ef9ae1c6..3fe3ddda 100644 --- a/src/python/common/tool_arguments.py +++ b/src/python/common/tool_arguments.py @@ -2,6 +2,7 @@ from enum import Enum, unique from typing import List, Optional +from src.python.review.application_config import LanguageVersion from src.python.review.inspectors.inspector_type import InspectorType @@ -21,51 +22,53 @@ def values(cls) -> List[str]: @dataclass(frozen=True) -class ArgumentsCharacteristics: +class ArgumentsInfo: short_name: Optional[str] long_name: str - help: str - - -inspectors = [inspector.lower() for inspector in InspectorType.available_values()] -disabled_inspectors_example = f'-d {inspectors[0].lower()},{inspectors[1].lower()}' + description: str @unique -class RunToolArguments(Enum): - VERBOSITY = ArgumentsCharacteristics('-v', '--verbosity', - 'Choose logging level: ' - f'{VerbosityLevel.ERROR.value} - ERROR; ' - f'{VerbosityLevel.INFO.value} - INFO; ' - f'{VerbosityLevel.DEBUG.value} - DEBUG; ' - f'{VerbosityLevel.DISABLE.value} - disable logging; ' - 'default is 0') +class RunToolArgument(Enum): + VERBOSITY = ArgumentsInfo('-v', '--verbosity', + 'Choose logging level: ' + f'{VerbosityLevel.ERROR.value} - ERROR; ' + f'{VerbosityLevel.INFO.value} - INFO; ' + f'{VerbosityLevel.DEBUG.value} - DEBUG; ' + f'{VerbosityLevel.DISABLE.value} - disable logging; ' + 'default is 0') + + inspectors = [inspector.lower() for inspector in InspectorType.available_values()] + disabled_inspectors_example = f'-d {inspectors[0].lower()},{inspectors[1].lower()}' - DISABLE = ArgumentsCharacteristics('-d', '--disable', - 'Disable inspectors. ' - f'Allowed values: {", ".join(inspectors)}. ' - f'Example: {disabled_inspectors_example}') + DISABLE = ArgumentsInfo('-d', '--disable', + 'Disable inspectors. ' + f'Available values: {", ".join(inspectors)}. ' + f'Example: {disabled_inspectors_example}') - DUPLICATES = ArgumentsCharacteristics(None, '--allow-duplicates', - 'Allow duplicate issues found by different linters. ' - 'By default, duplicates are skipped.') + DUPLICATES = ArgumentsInfo(None, '--allow-duplicates', + 'Allow duplicate issues found by different linters. ' + 'By default, duplicates are skipped.') - LANG_VERSION = ArgumentsCharacteristics(None, '--language-version', - 'Specify the language version for JAVA inspectors.') + LANG_VERSION = ArgumentsInfo(None, '--language-version', + 'Specify the language version for JAVA inspectors.' + 'Available values are: ' + f'{LanguageVersion.PYTHON_3.value}, {LanguageVersion.JAVA_8.value}, ' + f'{LanguageVersion.JAVA_11.value}, {LanguageVersion.KOTLIN.value}.') - CPU = ArgumentsCharacteristics(None, '--n-cpu', - 'Specify number of cpu that can be used to run inspectors') + CPU = ArgumentsInfo(None, '--n-cpu', + 'Specify number of cpu that can be used to run inspectors') - PATH = ArgumentsCharacteristics(None, 'path', 'Path to file or directory to inspect.') + PATH = ArgumentsInfo(None, 'path', 'Path to file or directory to inspect.') - FORMAT = ArgumentsCharacteristics('-f', '--format', - 'The output format. Default is JSON.') + FORMAT = ArgumentsInfo('-f', '--format', + 'The output format. Default is JSON.') - START_LINE = ArgumentsCharacteristics('-s', '--start-line', - 'The first line to be analyzed. It starts from 1.') + START_LINE = ArgumentsInfo('-s', '--start-line', + 'The first line to be analyzed. It starts from 1.') - END_LINE = ArgumentsCharacteristics('-e', '--end-line', 'The end line to be analyzed or None.') + END_LINE = ArgumentsInfo('-e', '--end-line', 'The end line to be analyzed or None.') - NEW_FORMAT = ArgumentsCharacteristics(None, '--new-format', - 'The argument determines whether the tool ' - 'should use the new format') + NEW_FORMAT = ArgumentsInfo(None, '--new-format', + 'The argument determines whether the tool ' + 'should use the new format') diff --git a/src/python/evaluation/common/util.py b/src/python/evaluation/common/util.py index 02b2bc93..5035dad8 100644 --- a/src/python/evaluation/common/util.py +++ b/src/python/evaluation/common/util.py @@ -1,32 +1,31 @@ from enum import Enum -from typing import List from src.python.review.application_config import LanguageVersion +from src.python.review.common.file_system import Extension -class EvaluationProcessNames(Enum): +class ColumnName(Enum): CODE = "code" LANG = "lang" LANGUAGE = "language" GRADE = "grade" - TRACEBACK = "traceback" - RESULTS = "results" - RESULTS_EXT = "results.xlsx" - @classmethod - def values(cls) -> List[str]: - return [member.value for member in cls.__members__.values()] + +class EvaluationArgument(Enum): + TRACEBACK = "traceback" + RESULT_FILE_NAME = "results" + RESULT_FILE_NAME_EXT = f"{RESULT_FILE_NAME}{Extension.XLSX.value}" script_structure_rule = ("Please, make sure your XLSX-file matches following script standards: \n" "1. Your XLSX-file should have 2 obligatory columns named:" - f"'{EvaluationProcessNames.CODE.value}' & '{EvaluationProcessNames.LANG.value}'. \n" - f"'{EvaluationProcessNames.CODE.value}' column -- relates to the code-sample. \n" - f"'{EvaluationProcessNames.LANG.value}' column -- relates to the language of a " + f"'{ColumnName.CODE.value}' & '{ColumnName.LANG.value}'. \n" + f"'{ColumnName.CODE.value}' column -- relates to the code-sample. \n" + f"'{ColumnName.LANG.value}' column -- relates to the language of a " "particular code-sample. \n" "2. Your code samples should belong to the one of the supported languages. \n" "Supported languages are: Java, Kotlin, Python. \n" - f"3. Check that '{EvaluationProcessNames.LANG.value}' column cells are filled with " + f"3. Check that '{ColumnName.LANG.value}' column cells are filled with " "acceptable language-names: \n" f"Acceptable language-names are: {LanguageVersion.PYTHON_3.value}, " f"{LanguageVersion.JAVA_8.value} ," diff --git a/src/python/evaluation/common/xlsx_util.py b/src/python/evaluation/common/xlsx_util.py index 5ec2ed20..41d63cc9 100644 --- a/src/python/evaluation/common/xlsx_util.py +++ b/src/python/evaluation/common/xlsx_util.py @@ -3,26 +3,39 @@ from typing import NoReturn, Union import pandas as pd -from openpyxl import load_workbook +from openpyxl import load_workbook, Workbook logger = logging.getLogger(__name__) -def remove_sheet(workbook_path: Union[str, Path], sheet_name: str, not_exist_ok=True) -> NoReturn: +def remove_sheet(workbook_path: Union[str, Path], sheet_name: str, to_raise_error=False) -> NoReturn: try: workbook = load_workbook(workbook_path) workbook.remove(workbook[sheet_name]) workbook.save(workbook_path) - except KeyError: - # if not_exist_ok=True – do not raise KeyError if sheet does not exist - if not_exist_ok: - pass + + except KeyError as e: + message = f'Sheet with specified name: {sheet_name} does not exist.' + if to_raise_error: + logger.exception(message) + raise e else: - logger.exception(f'Sheet with specified name: {sheet_name} does not exist.') + logger.info(message) + + +def create_and_get_workbook_path(config) -> Path: + workbook = Workbook() + workbook_path = config.get_output_file_path() + workbook.save(workbook_path) + return workbook_path -def write_dataframe_to_xlsx_sheet(xlsx_file_path: Union[str, Path], context_dataframe: pd.DataFrame, - sheet_name: str, engine: str, mode='a', index=False): +def write_dataframe_to_xlsx_sheet(xlsx_file_path: Union[str, Path], df: pd.DataFrame, + sheet_name: str, mode='a', index=False): + """ + mode: str Available values are {'w', 'a'}. File mode to use (write or append). + index: bool Write row names. + """ - with pd.ExcelWriter(xlsx_file_path, engine=engine, mode=mode) as writer: - context_dataframe.to_excel(writer, sheet_name=sheet_name, index=index) + with pd.ExcelWriter(xlsx_file_path, mode=mode) as writer: + df.to_excel(writer, sheet_name=sheet_name, index=index) diff --git a/src/python/evaluation/evaluation_config.py b/src/python/evaluation/evaluation_config.py index 4ff75cdd..343896f9 100644 --- a/src/python/evaluation/evaluation_config.py +++ b/src/python/evaluation/evaluation_config.py @@ -2,8 +2,8 @@ from pathlib import Path from typing import List, Union -from src.python.common.tool_arguments import RunToolArguments -from src.python.evaluation.common.util import EvaluationProcessNames +from src.python.common.tool_arguments import RunToolArgument +from src.python.evaluation.common.util import EvaluationArgument from src.python.review.application_config import LanguageVersion from src.python.review.common.file_system import create_directory @@ -12,33 +12,40 @@ class EvaluationConfig: def __init__(self, args): - self.tool_path: Union[str, Path] = args.tool_path - self.output_format: str = args.format - self.xlsx_file_path: Union[str, Path] = args.xlsx_file_path - self.traceback: bool = args.traceback - self.output_folder_path: Union[str, Path] = args.output_folder_path - self.output_file_name: str = args.output_file_name - - def build_command(self, inspected_file_path: Union[str, Path], lang: str, - run_tool_arguments=RunToolArguments) -> List[str]: - + # Pass dictionary when run tests + if type(args) == dict: + self.tool_path: Union[str, Path] = args['tool_path'] + self.output_format: str = args['format'] + self.xlsx_file_path: Union[str, Path] = args['xlsx_file_path'] + self.traceback: bool = args['traceback'] + self.output_folder_path: Union[str, Path] = args['output_folder_path'] + self.output_file_name: str = args['output_file_name'] + else: + self.tool_path: Union[str, Path] = args.tool_path + self.output_format: str = args.format + self.xlsx_file_path: Union[str, Path] = args.xlsx_file_path + self.traceback: bool = args.traceback + self.output_folder_path: Union[str, Path] = args.output_folder_path + self.output_file_name: str = args.output_file_name + + def build_command(self, inspected_file_path: Union[str, Path], lang: str) -> List[str]: command = [LanguageVersion.PYTHON_3.value, self.tool_path, inspected_file_path, - run_tool_arguments.FORMAT.value.short_name, self.output_format] + RunToolArgument.FORMAT.value.short_name, self.output_format] if lang == LanguageVersion.JAVA_8.value or lang == LanguageVersion.JAVA_11.value: - command.extend(['--language_version', lang]) + command.extend([RunToolArgument.LANG_VERSION.value.long_name, lang]) return command - def get_file_path(self) -> Path: + def get_output_file_path(self) -> Path: if self.output_folder_path is None: try: self.output_folder_path = ( - Path(self.xlsx_file_path).parent.parent / EvaluationProcessNames.RESULTS.value + Path(self.xlsx_file_path).parent.parent / EvaluationArgument.RESULT_FILE_NAME.value ) create_directory(self.output_folder_path) except FileNotFoundError: logger.error('XLSX-file with the specified name does not exists.') - return 2 + raise FileNotFoundError return Path(self.output_folder_path) / self.output_file_name diff --git a/src/python/evaluation/xlsx_run_tool.py b/src/python/evaluation/xlsx_run_tool.py index fa56397c..7d1af53a 100644 --- a/src/python/evaluation/xlsx_run_tool.py +++ b/src/python/evaluation/xlsx_run_tool.py @@ -12,10 +12,13 @@ sys.path.append('../../..') import pandas as pd -from openpyxl import Workbook -from src.python.common.tool_arguments import RunToolArguments -from src.python.evaluation.common.util import EvaluationProcessNames, script_structure_rule -from src.python.evaluation.common.xlsx_util import remove_sheet, write_dataframe_to_xlsx_sheet +from src.python.common.tool_arguments import RunToolArgument +from src.python.evaluation.common.util import ColumnName, EvaluationArgument, script_structure_rule +from src.python.evaluation.common.xlsx_util import ( + create_and_get_workbook_path, + remove_sheet, + write_dataframe_to_xlsx_sheet, +) from src.python.evaluation.evaluation_config import EvaluationConfig from src.python.review.application_config import LanguageVersion from src.python.review.common.file_system import create_file, new_temp_dir @@ -30,9 +33,9 @@ def configure_arguments(parser: argparse.ArgumentParser, run_tool_arguments: enu type=lambda value: Path(value).absolute(), help='Local XLSX-file path. ' 'Your XLSX-file must include column-names: ' - f'"{EvaluationProcessNames.CODE.value}" and ' - f'"{EvaluationProcessNames.LANG.value}". Acceptable values for ' - f'"{EvaluationProcessNames.LANG.value}" column are: ' + f'"{ColumnName.CODE.value}" and ' + f'"{ColumnName.LANG.value}". Acceptable values for ' + f'"{ColumnName.LANG.value}" column are: ' f'{LanguageVersion.PYTHON_3.value}, {LanguageVersion.JAVA_8.value}, ' f'{LanguageVersion.JAVA_11.value}, {LanguageVersion.KOTLIN.value}.') @@ -56,8 +59,8 @@ def configure_arguments(parser: argparse.ArgumentParser, run_tool_arguments: enu parser.add_argument('-ofn', '--output-file-name', help='Filename for that will be created to store inspection results.' - f'Default is "{EvaluationProcessNames.RESULTS_EXT.value}"', - default=f'{EvaluationProcessNames.RESULTS_EXT.value}', + f'Default is "{EvaluationArgument.RESULT_FILE_NAME_EXT.value}"', + default=f'{EvaluationArgument.RESULT_FILE_NAME_EXT.value}', type=str) parser.add_argument(run_tool_arguments.FORMAT.value.short_name, @@ -65,31 +68,33 @@ def configure_arguments(parser: argparse.ArgumentParser, run_tool_arguments: enu default=OutputFormat.JSON.value, choices=OutputFormat.values(), type=str, - help=run_tool_arguments.FORMAT.value.help) + help=f'{run_tool_arguments.FORMAT.value.description}' + f'Use this argument when {EvaluationArgument.TRACEBACK.value} argument' + 'is enabled argument will not be used otherwise.') def create_dataframe(config) -> Union[int, pd.DataFrame]: report = pd.DataFrame( { - EvaluationProcessNames.LANGUAGE.value: [], - EvaluationProcessNames.CODE.value: [], - EvaluationProcessNames.GRADE.value: [], + ColumnName.LANGUAGE.value: [], + ColumnName.CODE.value: [], + ColumnName.GRADE.value: [], }, ) if config.traceback: - report[EvaluationProcessNames.TRACEBACK.value] = [] + report[EvaluationArgument.TRACEBACK.value] = [] try: lang_code_dataframe = pd.read_excel(config.xlsx_file_path) except FileNotFoundError: logger.error('XLSX-file with the specified name does not exists.') - return 2 + raise FileNotFoundError try: - for lang, code in zip(lang_code_dataframe[EvaluationProcessNames.LANG.value], - lang_code_dataframe[EvaluationProcessNames.CODE.value]): + for lang, code in zip(lang_code_dataframe[ColumnName.LANG.value], + lang_code_dataframe[ColumnName.CODE.value]): with new_temp_dir() as create_temp_dir: temp_dir_path = create_temp_dir @@ -101,7 +106,7 @@ def create_dataframe(config) -> Union[int, pd.DataFrame]: assert os.path.exists(temp_file_path) except AssertionError: logger.exception('Path does not exist.') - return 2 + raise AssertionError command = config.build_command(temp_file_path, lang) results = run_in_subprocess(command) @@ -110,13 +115,13 @@ def create_dataframe(config) -> Union[int, pd.DataFrame]: # this regular expression matches final tool grade: EXCELLENT, GOOD, MODERATE or BAD grades = re.match(r'^.*{"code":\s"([A-Z]+)"', results).group(1) output_row_values = [lang, code, grades] - column_indices = [EvaluationProcessNames.LANGUAGE.value, - EvaluationProcessNames.CODE.value, - EvaluationProcessNames.GRADE.value] + column_indices = [ColumnName.LANGUAGE.value, + ColumnName.CODE.value, + ColumnName.GRADE.value] if config.traceback: output_row_values.append(results) - column_indices.append(EvaluationProcessNames.TRACEBACK.value) + column_indices.append(EvaluationArgument.TRACEBACK.value) new_file_report_row = pd.Series(data=output_row_values, index=column_indices) report = report.append(new_file_report_row, ignore_index=True) @@ -125,29 +130,24 @@ def create_dataframe(config) -> Union[int, pd.DataFrame]: except KeyError: logger.error(script_structure_rule) - return 2 + raise KeyError except Exception: traceback.print_exc() logger.exception('An unexpected error.') - return 2 + raise Exception def main() -> int: parser = argparse.ArgumentParser() - configure_arguments(parser, RunToolArguments) + configure_arguments(parser, RunToolArgument) try: args = parser.parse_args() config = EvaluationConfig(args) - - workbook = Workbook() - workbook_path = config.get_file_path() - workbook.save(workbook_path) - + workbook_path = create_and_get_workbook_path(config) results = create_dataframe(config) - - write_dataframe_to_xlsx_sheet(workbook_path, results, 'inspection_results', 'openpyxl') + write_dataframe_to_xlsx_sheet(workbook_path, results, 'inspection_results') # remove empty sheet that was initially created with the workbook remove_sheet(workbook_path, 'Sheet') return 0 diff --git a/src/python/review/common/file_system.py b/src/python/review/common/file_system.py index e4ade5fd..3ab06061 100644 --- a/src/python/review/common/file_system.py +++ b/src/python/review/common/file_system.py @@ -29,6 +29,7 @@ class Extension(Enum): KT = '.kt' JS = '.js' KTS = '.kts' + XLSX = '.xlsx' ItemCondition = Callable[[str], bool] diff --git a/src/python/review/run_tool.py b/src/python/review/run_tool.py index a41a08cb..bdfbb41f 100644 --- a/src/python/review/run_tool.py +++ b/src/python/review/run_tool.py @@ -11,7 +11,7 @@ sys.path.append('') sys.path.append('../../..') -from src.python.common.tool_arguments import RunToolArguments, VerbosityLevel +from src.python.common.tool_arguments import RunToolArgument, VerbosityLevel from src.python.review.application_config import ApplicationConfig, LanguageVersion from src.python.review.inspectors.inspector_type import InspectorType from src.python.review.logging_config import logging_config @@ -45,7 +45,7 @@ def positive_int(value: str) -> int: def configure_arguments(parser: argparse.ArgumentParser, tool_arguments: enum.EnumMeta) -> None: parser.add_argument(tool_arguments.VERBOSITY.value.short_name, tool_arguments.VERBOSITY.value.long_name, - help=tool_arguments.VERBOSITY.value.help, + help=tool_arguments.VERBOSITY.value.description, default=VerbosityLevel.DISABLE.value, choices=VerbosityLevel.values(), type=str) @@ -53,18 +53,18 @@ def configure_arguments(parser: argparse.ArgumentParser, tool_arguments: enum.En # Usage example: -d Flake8,Intelli parser.add_argument(tool_arguments.DISABLE.value.short_name, tool_arguments.DISABLE.value.long_name, - help=tool_arguments.DISABLE.value.help, + help=tool_arguments.DISABLE.value.description, type=parse_disabled_inspectors, default=set()) parser.add_argument(tool_arguments.DUPLICATES.value.long_name, action='store_true', - help=tool_arguments.DUPLICATES.value.help) + help=tool_arguments.DUPLICATES.value.description) # TODO: deprecated argument: language_version. Delete after several releases. parser.add_argument('--language_version', tool_arguments.LANG_VERSION.value.long_name, - help=tool_arguments.LANG_VERSION.value.help, + help=tool_arguments.LANG_VERSION.value.description, default=None, choices=LanguageVersion.values(), type=str) @@ -72,36 +72,36 @@ def configure_arguments(parser: argparse.ArgumentParser, tool_arguments: enum.En # TODO: deprecated argument: --n_cpu. Delete after several releases. parser.add_argument('--n_cpu', tool_arguments.CPU.value.long_name, - help=tool_arguments.CPU.value.help, + help=tool_arguments.CPU.value.description, default=1, type=positive_int) parser.add_argument(tool_arguments.PATH.value.long_name, type=lambda value: Path(value).absolute(), - help=tool_arguments.PATH.value.help) + help=tool_arguments.PATH.value.description) parser.add_argument(tool_arguments.FORMAT.value.short_name, tool_arguments.FORMAT.value.long_name, default=OutputFormat.JSON.value, choices=OutputFormat.values(), type=str, - help=tool_arguments.FORMAT.value.help) + help=tool_arguments.FORMAT.value.description) parser.add_argument(tool_arguments.START_LINE.value.short_name, tool_arguments.START_LINE.value.long_name, default=1, type=positive_int, - help=tool_arguments.START_LINE.value.help) + help=tool_arguments.START_LINE.value.description) parser.add_argument(tool_arguments.END_LINE.value.short_name, tool_arguments.END_LINE.value.long_name, default=None, type=positive_int, - help=tool_arguments.END_LINE.value.help) + help=tool_arguments.END_LINE.value.description) parser.add_argument(tool_arguments.NEW_FORMAT.value.long_name, action='store_true', - help=tool_arguments.NEW_FORMAT.value.help) + help=tool_arguments.NEW_FORMAT.value.description) def configure_logging(verbosity: VerbosityLevel) -> None: @@ -119,7 +119,7 @@ def configure_logging(verbosity: VerbosityLevel) -> None: def main() -> int: parser = argparse.ArgumentParser() - configure_arguments(parser, RunToolArguments) + configure_arguments(parser, RunToolArgument) try: args = parser.parse_args() diff --git a/test/python/evaluation/test_data_path.py b/test/python/evaluation/test_data_path.py index 4601e116..eff42a29 100644 --- a/test/python/evaluation/test_data_path.py +++ b/test/python/evaluation/test_data_path.py @@ -1,14 +1,14 @@ from test.python.evaluation import XLSX_DATA_FOLDER -from test.python.evaluation.testing_config import get_parser +from test.python.evaluation.testing_config import get_testing_arguments -from src.python.common.tool_arguments import RunToolArguments +import pytest from src.python.evaluation.evaluation_config import EvaluationConfig from src.python.evaluation.xlsx_run_tool import create_dataframe def test_incorrect_data_path(): - parser = get_parser(RunToolArguments, n_args=5) - parser.add_argument('-xlsx_file_path', default=XLSX_DATA_FOLDER / 'do_not_exist.xlsx') - args = parser.parse_args([]) - config = EvaluationConfig(args) - assert create_dataframe(config) == 2 + with pytest.raises(FileNotFoundError): + testing_arguments_dict = get_testing_arguments(n_args=5) + testing_arguments_dict['xlsx_file_path'] = XLSX_DATA_FOLDER / 'do_not_exist.xlsx' + config = EvaluationConfig(testing_arguments_dict) + assert create_dataframe(config) diff --git a/test/python/evaluation/test_output_results.py b/test/python/evaluation/test_output_results.py index a459969c..861ea06e 100644 --- a/test/python/evaluation/test_output_results.py +++ b/test/python/evaluation/test_output_results.py @@ -1,11 +1,9 @@ from test.python.evaluation import TARGET_XLSX_DATA_FOLDER, XLSX_DATA_FOLDER -from test.python.evaluation.testing_config import get_parser -from typing import Union +from test.python.evaluation.testing_config import get_testing_arguments import pandas as pd import pytest from src.python import MAIN_FOLDER -from src.python.common.tool_arguments import RunToolArguments from src.python.evaluation.evaluation_config import EvaluationConfig from src.python.evaluation.xlsx_run_tool import create_dataframe @@ -18,18 +16,14 @@ @pytest.mark.parametrize(('test_file', 'target_file', 'output_type'), FILE_NAMES) -def test_correct_output(test_file: str, target_file: str, output_type: Union[bool, str]): +def test_correct_output(test_file: str, target_file: str, output_type: bool): - parser = get_parser(RunToolArguments) - parser.add_argument('-xlsx_file_path', default=XLSX_DATA_FOLDER / test_file) - parser.add_argument('-tp', '--tool-path', default=MAIN_FOLDER.parent / 'review/run_tool.py') - if output_type: - parser.add_argument('-tr', '--traceback', action='store_false') - else: - parser.add_argument('-tr', '--traceback', action='store_true') + testing_arguments_dict = get_testing_arguments() + testing_arguments_dict['xlsx_file_path'] = XLSX_DATA_FOLDER / test_file + testing_arguments_dict['tool_path'] = MAIN_FOLDER.parent / 'review/run_tool.py' + testing_arguments_dict['traceback'] = output_type - args = parser.parse_args([]) - config = EvaluationConfig(args) + config = EvaluationConfig(testing_arguments_dict) test_dataframe = create_dataframe(config) sheet_name = 'grades' diff --git a/test/python/evaluation/test_tool_path.py b/test/python/evaluation/test_tool_path.py index fd845909..aa6dde36 100644 --- a/test/python/evaluation/test_tool_path.py +++ b/test/python/evaluation/test_tool_path.py @@ -1,25 +1,24 @@ from test.python.evaluation import XLSX_DATA_FOLDER -from test.python.evaluation.testing_config import get_parser +from test.python.evaluation.testing_config import get_testing_arguments import pandas as pd +import pytest from src.python import MAIN_FOLDER -from src.python.common.tool_arguments import RunToolArguments from src.python.evaluation.evaluation_config import EvaluationConfig from src.python.evaluation.xlsx_run_tool import create_dataframe -def test_correct_tool_path(run_tool_arguments=RunToolArguments): - parser = get_parser(run_tool_arguments, n_args=5) - parser.add_argument('-xlsx_file_path', default=XLSX_DATA_FOLDER / 'test_unsorted_order.xlsx') - args = parser.parse_args([]) - config = EvaluationConfig(args) +def test_correct_tool_path(): + testing_arguments_dict = get_testing_arguments(n_args=5) + testing_arguments_dict['xlsx_file_path'] = XLSX_DATA_FOLDER / 'test_unsorted_order.xlsx' + config = EvaluationConfig(testing_arguments_dict) assert type(create_dataframe(config)) == pd.DataFrame -def test_incorrect_tool_path(run_tool_arguments=RunToolArguments): - parser = get_parser(run_tool_arguments, n_args=4) - parser.add_argument('-xlsx_file_path', default=XLSX_DATA_FOLDER / 'test_unsorted_order.xlsx') - parser.add_argument('-tp', '--tool-path', default=MAIN_FOLDER.parent / 'review/incorrect_path.py') - args = parser.parse_args([]) - config = EvaluationConfig(args) - assert create_dataframe(config) == 2 +def test_incorrect_tool_path(): + with pytest.raises(Exception): + testing_arguments_dict = get_testing_arguments(n_args=4) + testing_arguments_dict['xlsx_file_path'] = XLSX_DATA_FOLDER / 'test_unsorted_order.xlsx' + testing_arguments_dict['tool_path'] = MAIN_FOLDER.parent / 'review/incorrect_path.py' + config = EvaluationConfig(testing_arguments_dict) + assert create_dataframe(config) diff --git a/test/python/evaluation/test_xlsx_file_structure.py b/test/python/evaluation/test_xlsx_file_structure.py index f315dc32..03cbd561 100644 --- a/test/python/evaluation/test_xlsx_file_structure.py +++ b/test/python/evaluation/test_xlsx_file_structure.py @@ -1,8 +1,7 @@ from test.python.evaluation import XLSX_DATA_FOLDER -from test.python.evaluation.testing_config import get_parser +from test.python.evaluation.testing_config import get_testing_arguments import pytest -from src.python.common.tool_arguments import RunToolArguments from src.python.evaluation.evaluation_config import EvaluationConfig from src.python.evaluation.xlsx_run_tool import create_dataframe @@ -17,8 +16,8 @@ @pytest.mark.parametrize('file_name', FILE_NAMES) def test_wrong_column(file_name: str): - parser = get_parser(RunToolArguments, n_args=5) - parser.add_argument('-xlsx_file_path', default=XLSX_DATA_FOLDER / file_name) - args = parser.parse_args([]) - config = EvaluationConfig(args) - assert create_dataframe(config) == 2 + with pytest.raises(KeyError): + testing_arguments_dict = get_testing_arguments(n_args=5) + testing_arguments_dict['xlsx_file_path'] = XLSX_DATA_FOLDER / file_name + config = EvaluationConfig(testing_arguments_dict) + assert create_dataframe(config) diff --git a/test/python/evaluation/testing_config.py b/test/python/evaluation/testing_config.py index 1d9af73f..d1d4fdf2 100644 --- a/test/python/evaluation/testing_config.py +++ b/test/python/evaluation/testing_config.py @@ -1,23 +1,16 @@ -import argparse -import enum - from src.python import MAIN_FOLDER -from src.python.evaluation.common.util import EvaluationProcessNames +from src.python.evaluation.common.util import EvaluationArgument from src.python.review.reviewers.perform_review import OutputFormat -def get_parser(run_tool_arguments: enum.EnumMeta, n_args=2) -> argparse.ArgumentParser: - parser = argparse.ArgumentParser() - parser.add_argument('-ofp', '--output-folder-path', default=None) - parser.add_argument(run_tool_arguments.FORMAT.value.short_name, - run_tool_arguments.FORMAT.value.long_name, - default=OutputFormat.JSON.value) - parser.add_argument('-ofn', '--output-file-name', - default=EvaluationProcessNames.RESULTS_EXT.value) +def get_testing_arguments(n_args=2) -> dict: + testing_arguments_dict = {'format': OutputFormat.JSON.value, + 'output_file_name': EvaluationArgument.RESULT_FILE_NAME_EXT.value, + 'output_folder_path': None} if n_args > 2: - parser.add_argument('-tr', '--traceback', action='store_true') + testing_arguments_dict['traceback'] = True if n_args == 5: - parser.add_argument('-tp', '--tool-path', - default=MAIN_FOLDER.parent / 'review/run_tool.py') - return parser + testing_arguments_dict['tool_path'] = MAIN_FOLDER.parent / 'review/run_tool.py' + + return testing_arguments_dict From 1c96bee1bb6755097d6ae3ad2d128220208b20c0 Mon Sep 17 00:00:00 2001 From: diatlova Date: Sat, 1 May 2021 13:43:45 +0300 Subject: [PATCH 62/78] Small fixes after pr --- README.md | 1 + test/python/evaluation/test_data_path.py | 4 ++-- test/python/evaluation/test_output_results.py | 8 +++----- test/python/evaluation/test_tool_path.py | 18 +++++++++-------- .../evaluation/test_xlsx_file_structure.py | 4 ++-- test/python/evaluation/testing_config.py | 20 ++++++++++--------- 6 files changed, 29 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index 43370839..67ce8430 100644 --- a/README.md +++ b/README.md @@ -79,6 +79,7 @@ Simply clone the repository and run the following commands: 1. `pip install -r requirements.txt` 2. `pip install -r requirements-test.txt` for tests +3. `pip install -r requirements-evaluation.txt` for evaluation ## Usage diff --git a/test/python/evaluation/test_data_path.py b/test/python/evaluation/test_data_path.py index eff42a29..0d8e3502 100644 --- a/test/python/evaluation/test_data_path.py +++ b/test/python/evaluation/test_data_path.py @@ -8,7 +8,7 @@ def test_incorrect_data_path(): with pytest.raises(FileNotFoundError): - testing_arguments_dict = get_testing_arguments(n_args=5) - testing_arguments_dict['xlsx_file_path'] = XLSX_DATA_FOLDER / 'do_not_exist.xlsx' + testing_arguments_dict = get_testing_arguments(to_add_traceback=True, to_add_tool_path=True) + testing_arguments_dict.xlsx_file_path = XLSX_DATA_FOLDER / 'do_not_exist.xlsx' config = EvaluationConfig(testing_arguments_dict) assert create_dataframe(config) diff --git a/test/python/evaluation/test_output_results.py b/test/python/evaluation/test_output_results.py index 861ea06e..519652e5 100644 --- a/test/python/evaluation/test_output_results.py +++ b/test/python/evaluation/test_output_results.py @@ -3,7 +3,6 @@ import pandas as pd import pytest -from src.python import MAIN_FOLDER from src.python.evaluation.evaluation_config import EvaluationConfig from src.python.evaluation.xlsx_run_tool import create_dataframe @@ -18,10 +17,9 @@ @pytest.mark.parametrize(('test_file', 'target_file', 'output_type'), FILE_NAMES) def test_correct_output(test_file: str, target_file: str, output_type: bool): - testing_arguments_dict = get_testing_arguments() - testing_arguments_dict['xlsx_file_path'] = XLSX_DATA_FOLDER / test_file - testing_arguments_dict['tool_path'] = MAIN_FOLDER.parent / 'review/run_tool.py' - testing_arguments_dict['traceback'] = output_type + testing_arguments_dict = get_testing_arguments(to_add_tool_path=True) + testing_arguments_dict.xlsx_file_path = XLSX_DATA_FOLDER / test_file + testing_arguments_dict.traceback = output_type config = EvaluationConfig(testing_arguments_dict) test_dataframe = create_dataframe(config) diff --git a/test/python/evaluation/test_tool_path.py b/test/python/evaluation/test_tool_path.py index aa6dde36..0581caad 100644 --- a/test/python/evaluation/test_tool_path.py +++ b/test/python/evaluation/test_tool_path.py @@ -1,7 +1,6 @@ from test.python.evaluation import XLSX_DATA_FOLDER from test.python.evaluation.testing_config import get_testing_arguments -import pandas as pd import pytest from src.python import MAIN_FOLDER from src.python.evaluation.evaluation_config import EvaluationConfig @@ -9,16 +8,19 @@ def test_correct_tool_path(): - testing_arguments_dict = get_testing_arguments(n_args=5) - testing_arguments_dict['xlsx_file_path'] = XLSX_DATA_FOLDER / 'test_unsorted_order.xlsx' - config = EvaluationConfig(testing_arguments_dict) - assert type(create_dataframe(config)) == pd.DataFrame + try: + testing_arguments_dict = get_testing_arguments(to_add_traceback=True, to_add_tool_path=True) + testing_arguments_dict.xlsx_file_path = XLSX_DATA_FOLDER / 'test_unsorted_order.xlsx' + config = EvaluationConfig(testing_arguments_dict) + create_dataframe(config) + except Exception: + pytest.fail("Unexpected error") def test_incorrect_tool_path(): with pytest.raises(Exception): - testing_arguments_dict = get_testing_arguments(n_args=4) - testing_arguments_dict['xlsx_file_path'] = XLSX_DATA_FOLDER / 'test_unsorted_order.xlsx' - testing_arguments_dict['tool_path'] = MAIN_FOLDER.parent / 'review/incorrect_path.py' + testing_arguments_dict = get_testing_arguments(to_add_traceback=True) + testing_arguments_dict.xlsx_file_path = XLSX_DATA_FOLDER / 'test_unsorted_order.xlsx' + testing_arguments_dict.tool_path = MAIN_FOLDER.parent / 'review/incorrect_path.py' config = EvaluationConfig(testing_arguments_dict) assert create_dataframe(config) diff --git a/test/python/evaluation/test_xlsx_file_structure.py b/test/python/evaluation/test_xlsx_file_structure.py index 03cbd561..9965992e 100644 --- a/test/python/evaluation/test_xlsx_file_structure.py +++ b/test/python/evaluation/test_xlsx_file_structure.py @@ -17,7 +17,7 @@ @pytest.mark.parametrize('file_name', FILE_NAMES) def test_wrong_column(file_name: str): with pytest.raises(KeyError): - testing_arguments_dict = get_testing_arguments(n_args=5) - testing_arguments_dict['xlsx_file_path'] = XLSX_DATA_FOLDER / file_name + testing_arguments_dict = get_testing_arguments(to_add_traceback=True, to_add_tool_path=True) + testing_arguments_dict.xlsx_file_path = XLSX_DATA_FOLDER / file_name config = EvaluationConfig(testing_arguments_dict) assert create_dataframe(config) diff --git a/test/python/evaluation/testing_config.py b/test/python/evaluation/testing_config.py index d1d4fdf2..70341635 100644 --- a/test/python/evaluation/testing_config.py +++ b/test/python/evaluation/testing_config.py @@ -1,16 +1,18 @@ +from argparse import Namespace + from src.python import MAIN_FOLDER from src.python.evaluation.common.util import EvaluationArgument from src.python.review.reviewers.perform_review import OutputFormat -def get_testing_arguments(n_args=2) -> dict: - testing_arguments_dict = {'format': OutputFormat.JSON.value, - 'output_file_name': EvaluationArgument.RESULT_FILE_NAME_EXT.value, - 'output_folder_path': None} - if n_args > 2: - testing_arguments_dict['traceback'] = True +def get_testing_arguments(to_add_traceback=None, to_add_tool_path=None) -> Namespace: + testing_arguments = Namespace(format=OutputFormat.JSON.value, + output_file_name=EvaluationArgument.RESULT_FILE_NAME_EXT.value, + output_folder_path=None) + if to_add_traceback: + testing_arguments.traceback = True - if n_args == 5: - testing_arguments_dict['tool_path'] = MAIN_FOLDER.parent / 'review/run_tool.py' + if to_add_tool_path: + testing_arguments.tool_path = MAIN_FOLDER.parent / 'review/run_tool.py' - return testing_arguments_dict + return testing_arguments From ca36a3dad032639435bb8456bbc4f9b386d9e5a4 Mon Sep 17 00:00:00 2001 From: diatlova Date: Sat, 1 May 2021 13:46:04 +0300 Subject: [PATCH 63/78] Small fixes after pr --- src/python/evaluation/README.md | 14 +++++++------- src/python/evaluation/common/xlsx_util.py | 12 +++++++----- src/python/evaluation/xlsx_run_tool.py | 18 +++++++++--------- src/python/review/application_config.py | 6 +++++- 4 files changed, 28 insertions(+), 22 deletions(-) diff --git a/src/python/evaluation/README.md b/src/python/evaluation/README.md index 490b93bf..67e1d45e 100644 --- a/src/python/evaluation/README.md +++ b/src/python/evaluation/README.md @@ -5,17 +5,17 @@ This tool allows running the `Hyperstyle` tool on an xlsx table to get code qual - `code` - `lang` -Possible values for column `lang` are: python3, kotlin, java8, java11. +Possible values for column `lang` are: `python3`, `kotlin`, `java8`, `java11`. -Output file is a new xlsx file with 3 columns: +Output file is a new `xlsx` file with 3 columns: - `code` - `lang` - `grade` -Grade assesesment is condicted by [`run_tool.py`](https://github.com/hyperskill/hyperstyle/blob/main/README.md) with default arguments. Avaliable values for column `grade` are: BAD, MODERATE, GOOD, EXCELLENT. It is also possible add fourth column: `traceback` to get full inspectors feedback on each code fragment. More details on enabling traceback column in **Optional Arguments** table. +Grade assessment is conducted by [`run_tool.py`](https://github.com/hyperskill/hyperstyle/blob/main/README.md) with default arguments. Avaliable values for column `grade` are: BAD, MODERATE, GOOD, EXCELLENT. It is also possible add fourth column: `traceback` to get full inspectors feedback on each code fragment. More details on enabling traceback column in **Optional Arguments** table. ## Usage -Run the xlsx_run_tool.py with the arguments from command line. +Run the [xlsx_run_tool.py](xlsx_run_tool.py) with the arguments from command line. Required arguments: @@ -24,8 +24,8 @@ Required arguments: Optional arguments: Argument | Description --- | --- -|**‑f**, **‑‑format**| The output format. Available values: `json`, `text`. The default value is json . Use this argument when `traceback` is enabled, otherwise it will not be used.| -|**‑tp**, **‑‑tool_path**| Path to run-tool. Default is src/python/review/run_tool.py .| -|**‑tr**, **‑‑traceback**| If true column with errors traceback is included to an output file. Default is `False`.| +|**‑f**, **‑‑format**| The output format. Available values: `json`, `text`. The default value is `json` . Use this argument when `traceback` is enabled, otherwise it will not be used.| +|**‑tp**, **‑‑tool_path**| Path to run-tool. Default is `src/python/review/run_tool.py` .| +|**‑tr**, **‑‑traceback**| To include a column with errors traceback into an output file. Default is `False`.| |**‑ofp**, **‑‑output_folder_path**| An explicit folder path to store file with results. Default is a parent directory of a folder with xlsx-file sent for inspection. | |**‑ofn**, **‑‑output_file_name**| A name of an output file where evaluation results will be stored. Default is `results.xlsx`.| diff --git a/src/python/evaluation/common/xlsx_util.py b/src/python/evaluation/common/xlsx_util.py index 41d63cc9..e75a2505 100644 --- a/src/python/evaluation/common/xlsx_util.py +++ b/src/python/evaluation/common/xlsx_util.py @@ -1,11 +1,13 @@ import logging.config from pathlib import Path -from typing import NoReturn, Union +from typing import NoReturn, TypeVar, Union import pandas as pd from openpyxl import load_workbook, Workbook +from src.python.evaluation.evaluation_config import EvaluationConfig logger = logging.getLogger(__name__) +E = TypeVar('E', bound=EvaluationConfig) def remove_sheet(workbook_path: Union[str, Path], sheet_name: str, to_raise_error=False) -> NoReturn: @@ -23,7 +25,7 @@ def remove_sheet(workbook_path: Union[str, Path], sheet_name: str, to_raise_erro logger.info(message) -def create_and_get_workbook_path(config) -> Path: +def create_and_get_workbook_path(config: E) -> Path: workbook = Workbook() workbook_path = config.get_output_file_path() workbook.save(workbook_path) @@ -31,11 +33,11 @@ def create_and_get_workbook_path(config) -> Path: def write_dataframe_to_xlsx_sheet(xlsx_file_path: Union[str, Path], df: pd.DataFrame, - sheet_name: str, mode='a', index=False): + sheet_name: str, mode='a', to_write_row_names=False): """ mode: str Available values are {'w', 'a'}. File mode to use (write or append). - index: bool Write row names. + to_write_row_names: bool Write row names. """ with pd.ExcelWriter(xlsx_file_path, mode=mode) as writer: - df.to_excel(writer, sheet_name=sheet_name, index=index) + df.to_excel(writer, sheet_name=sheet_name, index=to_write_row_names) diff --git a/src/python/evaluation/xlsx_run_tool.py b/src/python/evaluation/xlsx_run_tool.py index 7d1af53a..84eba4ab 100644 --- a/src/python/evaluation/xlsx_run_tool.py +++ b/src/python/evaluation/xlsx_run_tool.py @@ -88,9 +88,9 @@ def create_dataframe(config) -> Union[int, pd.DataFrame]: try: lang_code_dataframe = pd.read_excel(config.xlsx_file_path) - except FileNotFoundError: + except FileNotFoundError as e: logger.error('XLSX-file with the specified name does not exists.') - raise FileNotFoundError + raise e try: for lang, code in zip(lang_code_dataframe[ColumnName.LANG.value], @@ -98,15 +98,15 @@ def create_dataframe(config) -> Union[int, pd.DataFrame]: with new_temp_dir() as create_temp_dir: temp_dir_path = create_temp_dir - lang_extension = LanguageVersion.language_extension()[lang] + lang_extension = LanguageVersion.language_by_extension(lang) temp_file_path = os.path.join(temp_dir_path, ('file' + lang_extension)) temp_file_path = next(create_file(temp_file_path, code)) try: assert os.path.exists(temp_file_path) - except AssertionError: + except AssertionError as e: logger.exception('Path does not exist.') - raise AssertionError + raise e command = config.build_command(temp_file_path, lang) results = run_in_subprocess(command) @@ -128,14 +128,14 @@ def create_dataframe(config) -> Union[int, pd.DataFrame]: return report - except KeyError: + except KeyError as e: logger.error(script_structure_rule) - raise KeyError + raise e - except Exception: + except Exception as e: traceback.print_exc() logger.exception('An unexpected error.') - raise Exception + raise e def main() -> int: diff --git a/src/python/review/application_config.py b/src/python/review/application_config.py index 738340fb..8d9a56f5 100644 --- a/src/python/review/application_config.py +++ b/src/python/review/application_config.py @@ -31,10 +31,14 @@ def values(cls) -> List[str]: return [member.value for member in cls.__members__.values()] @classmethod - def language_extension(cls) -> dict: + def language_to_extension_dict(cls) -> dict: return {cls.PYTHON_3.value: Extension.PY.value, cls.JAVA_7.value: Extension.JAVA.value, cls.JAVA_8.value: Extension.JAVA.value, cls.JAVA_9.value: Extension.JAVA.value, cls.JAVA_11.value: Extension.JAVA.value, cls.KOTLIN.value: Extension.KT.value} + + @classmethod + def language_by_extension(cls, lang: str) -> str: + return cls.language_to_extension_dict()[lang] From b2728214a32b97ba5c1d93f11c2592ab3e91140b Mon Sep 17 00:00:00 2001 From: Daria Diatlova Date: Mon, 3 May 2021 11:36:07 +0300 Subject: [PATCH 64/78] Update src/python/evaluation/common/util.py Co-authored-by: Alexander Petrov --- src/python/evaluation/common/util.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/python/evaluation/common/util.py b/src/python/evaluation/common/util.py index 5035dad8..c9e4fe95 100644 --- a/src/python/evaluation/common/util.py +++ b/src/python/evaluation/common/util.py @@ -4,6 +4,7 @@ from src.python.review.common.file_system import Extension +@unique class ColumnName(Enum): CODE = "code" LANG = "lang" From de2b0cea538d04e6dcaafc64471a61e3a32595f1 Mon Sep 17 00:00:00 2001 From: Daria Diatlova Date: Mon, 3 May 2021 11:42:06 +0300 Subject: [PATCH 65/78] Update src/python/evaluation/common/xlsx_util.py Co-authored-by: Alexander Petrov --- src/python/evaluation/common/xlsx_util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/python/evaluation/common/xlsx_util.py b/src/python/evaluation/common/xlsx_util.py index e75a2505..fd59f1e2 100644 --- a/src/python/evaluation/common/xlsx_util.py +++ b/src/python/evaluation/common/xlsx_util.py @@ -10,7 +10,7 @@ E = TypeVar('E', bound=EvaluationConfig) -def remove_sheet(workbook_path: Union[str, Path], sheet_name: str, to_raise_error=False) -> NoReturn: +def remove_sheet(workbook_path: Union[str, Path], sheet_name: str, to_raise_error=False) -> None: try: workbook = load_workbook(workbook_path) workbook.remove(workbook[sheet_name]) From b712c52eaeab8d0e80919ed1e828bd0b631d470e Mon Sep 17 00:00:00 2001 From: diatlova Date: Mon, 3 May 2021 11:51:59 +0300 Subject: [PATCH 66/78] added unique to whitelist --- src/python/evaluation/common/xlsx_util.py | 7 +++---- src/python/evaluation/xlsx_run_tool.py | 2 +- whitelist.txt | 1 + 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/python/evaluation/common/xlsx_util.py b/src/python/evaluation/common/xlsx_util.py index fd59f1e2..bb2ebec7 100644 --- a/src/python/evaluation/common/xlsx_util.py +++ b/src/python/evaluation/common/xlsx_util.py @@ -1,13 +1,12 @@ import logging.config from pathlib import Path -from typing import NoReturn, TypeVar, Union +from typing import Union import pandas as pd from openpyxl import load_workbook, Workbook from src.python.evaluation.evaluation_config import EvaluationConfig logger = logging.getLogger(__name__) -E = TypeVar('E', bound=EvaluationConfig) def remove_sheet(workbook_path: Union[str, Path], sheet_name: str, to_raise_error=False) -> None: @@ -25,7 +24,7 @@ def remove_sheet(workbook_path: Union[str, Path], sheet_name: str, to_raise_erro logger.info(message) -def create_and_get_workbook_path(config: E) -> Path: +def create_and_get_workbook_path(config: EvaluationConfig) -> Path: workbook = Workbook() workbook_path = config.get_output_file_path() workbook.save(workbook_path) @@ -33,7 +32,7 @@ def create_and_get_workbook_path(config: E) -> Path: def write_dataframe_to_xlsx_sheet(xlsx_file_path: Union[str, Path], df: pd.DataFrame, - sheet_name: str, mode='a', to_write_row_names=False): + sheet_name: str, mode='a', to_write_row_names=False) -> None: """ mode: str Available values are {'w', 'a'}. File mode to use (write or append). to_write_row_names: bool Write row names. diff --git a/src/python/evaluation/xlsx_run_tool.py b/src/python/evaluation/xlsx_run_tool.py index 84eba4ab..da19e993 100644 --- a/src/python/evaluation/xlsx_run_tool.py +++ b/src/python/evaluation/xlsx_run_tool.py @@ -73,7 +73,7 @@ def configure_arguments(parser: argparse.ArgumentParser, run_tool_arguments: enu 'is enabled argument will not be used otherwise.') -def create_dataframe(config) -> Union[int, pd.DataFrame]: +def create_dataframe(config) -> pd.DataFrame: report = pd.DataFrame( { ColumnName.LANGUAGE.value: [], diff --git a/whitelist.txt b/whitelist.txt index 501f7d0c..c60ec292 100644 --- a/whitelist.txt +++ b/whitelist.txt @@ -82,6 +82,7 @@ dataframe writelines rmdir df +unique # Springlint issues cbo dit From fb04b4a31d24fc6cd5e68b757ce5edaf3efa3dd1 Mon Sep 17 00:00:00 2001 From: diatlova Date: Mon, 3 May 2021 11:55:41 +0300 Subject: [PATCH 67/78] Added unique import --- src/python/evaluation/common/util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/python/evaluation/common/util.py b/src/python/evaluation/common/util.py index c9e4fe95..75313d18 100644 --- a/src/python/evaluation/common/util.py +++ b/src/python/evaluation/common/util.py @@ -1,4 +1,4 @@ -from enum import Enum +from enum import Enum, unique from src.python.review.application_config import LanguageVersion from src.python.review.common.file_system import Extension From fb7dfbae4659575376f8802746f91855402e15ef Mon Sep 17 00:00:00 2001 From: Daria Diatlova Date: Mon, 3 May 2021 11:56:17 +0300 Subject: [PATCH 68/78] Update src/python/evaluation/common/util.py Co-authored-by: Alexander Petrov --- src/python/evaluation/common/util.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/python/evaluation/common/util.py b/src/python/evaluation/common/util.py index 75313d18..c306d3b7 100644 --- a/src/python/evaluation/common/util.py +++ b/src/python/evaluation/common/util.py @@ -12,6 +12,7 @@ class ColumnName(Enum): GRADE = "grade" +@unique class EvaluationArgument(Enum): TRACEBACK = "traceback" RESULT_FILE_NAME = "results" From 82f46d7c01ee3a114c5115aa4ced980edea08355 Mon Sep 17 00:00:00 2001 From: Daria Diatlova Date: Mon, 3 May 2021 11:57:58 +0300 Subject: [PATCH 69/78] Update src/python/evaluation/xlsx_run_tool.py Co-authored-by: Alexander Petrov --- src/python/evaluation/xlsx_run_tool.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/python/evaluation/xlsx_run_tool.py b/src/python/evaluation/xlsx_run_tool.py index da19e993..60510cf0 100644 --- a/src/python/evaluation/xlsx_run_tool.py +++ b/src/python/evaluation/xlsx_run_tool.py @@ -28,7 +28,7 @@ logger = logging.getLogger(__name__) -def configure_arguments(parser: argparse.ArgumentParser, run_tool_arguments: enum.EnumMeta) -> NoReturn: +def configure_arguments(parser: argparse.ArgumentParser, run_tool_arguments: enum.EnumMeta) -> None: parser.add_argument('xlsx_file_path', type=lambda value: Path(value).absolute(), help='Local XLSX-file path. ' From 62b510b555643b4ca5e2eeddd1087c3f47831f10 Mon Sep 17 00:00:00 2001 From: diatlova Date: Mon, 3 May 2021 12:00:12 +0300 Subject: [PATCH 70/78] removed NoReturn import --- src/python/evaluation/xlsx_run_tool.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/python/evaluation/xlsx_run_tool.py b/src/python/evaluation/xlsx_run_tool.py index 60510cf0..b24545e7 100644 --- a/src/python/evaluation/xlsx_run_tool.py +++ b/src/python/evaluation/xlsx_run_tool.py @@ -6,7 +6,6 @@ import sys import traceback from pathlib import Path -from typing import NoReturn, Union sys.path.append('') sys.path.append('../../..') From 2c8a3c86fd77ca4a0f1cb30323a4f5d8f22d8654 Mon Sep 17 00:00:00 2001 From: Daria Diatlova Date: Mon, 3 May 2021 12:00:56 +0300 Subject: [PATCH 71/78] Update src/python/evaluation/evaluation_config.py Co-authored-by: Alexander Petrov --- src/python/evaluation/evaluation_config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/python/evaluation/evaluation_config.py b/src/python/evaluation/evaluation_config.py index 343896f9..f5876185 100644 --- a/src/python/evaluation/evaluation_config.py +++ b/src/python/evaluation/evaluation_config.py @@ -13,7 +13,7 @@ class EvaluationConfig: def __init__(self, args): # Pass dictionary when run tests - if type(args) == dict: + if isinstance(args, dict): self.tool_path: Union[str, Path] = args['tool_path'] self.output_format: str = args['format'] self.xlsx_file_path: Union[str, Path] = args['xlsx_file_path'] From a329e77d7b04185a28eeba9caec34f77f6d96161 Mon Sep 17 00:00:00 2001 From: diatlova Date: Mon, 3 May 2021 12:05:12 +0300 Subject: [PATCH 72/78] Fixed Namespace issue --- src/python/evaluation/evaluation_config.py | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/src/python/evaluation/evaluation_config.py b/src/python/evaluation/evaluation_config.py index f5876185..9f4b7ef9 100644 --- a/src/python/evaluation/evaluation_config.py +++ b/src/python/evaluation/evaluation_config.py @@ -12,21 +12,12 @@ class EvaluationConfig: def __init__(self, args): - # Pass dictionary when run tests - if isinstance(args, dict): - self.tool_path: Union[str, Path] = args['tool_path'] - self.output_format: str = args['format'] - self.xlsx_file_path: Union[str, Path] = args['xlsx_file_path'] - self.traceback: bool = args['traceback'] - self.output_folder_path: Union[str, Path] = args['output_folder_path'] - self.output_file_name: str = args['output_file_name'] - else: - self.tool_path: Union[str, Path] = args.tool_path - self.output_format: str = args.format - self.xlsx_file_path: Union[str, Path] = args.xlsx_file_path - self.traceback: bool = args.traceback - self.output_folder_path: Union[str, Path] = args.output_folder_path - self.output_file_name: str = args.output_file_name + self.tool_path: Union[str, Path] = args.tool_path + self.output_format: str = args.format + self.xlsx_file_path: Union[str, Path] = args.xlsx_file_path + self.traceback: bool = args.traceback + self.output_folder_path: Union[str, Path] = args.output_folder_path + self.output_file_name: str = args.output_file_name def build_command(self, inspected_file_path: Union[str, Path], lang: str) -> List[str]: command = [LanguageVersion.PYTHON_3.value, From 04bc2d7bf4e1089d256525cdf6033d947b6348bc Mon Sep 17 00:00:00 2001 From: Daria Diatlova Date: Mon, 3 May 2021 12:05:36 +0300 Subject: [PATCH 73/78] Update src/python/common/tool_arguments.py Co-authored-by: Alexander Petrov --- src/python/common/tool_arguments.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/python/common/tool_arguments.py b/src/python/common/tool_arguments.py index 3fe3ddda..9fe4181b 100644 --- a/src/python/common/tool_arguments.py +++ b/src/python/common/tool_arguments.py @@ -18,7 +18,7 @@ class VerbosityLevel(Enum): @classmethod def values(cls) -> List[str]: - return [member.value for _, member in VerbosityLevel.__members__.items()] + return [member.value for member in VerbosityLevel.__members__.values()] @dataclass(frozen=True) From 9b467092aa1d215dbc542c7de705dee78bdb4045 Mon Sep 17 00:00:00 2001 From: diatlova Date: Mon, 3 May 2021 12:10:26 +0300 Subject: [PATCH 74/78] Fixed error raising --- src/python/evaluation/evaluation_config.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/python/evaluation/evaluation_config.py b/src/python/evaluation/evaluation_config.py index 9f4b7ef9..0278d699 100644 --- a/src/python/evaluation/evaluation_config.py +++ b/src/python/evaluation/evaluation_config.py @@ -36,7 +36,7 @@ def get_output_file_path(self) -> Path: Path(self.xlsx_file_path).parent.parent / EvaluationArgument.RESULT_FILE_NAME.value ) create_directory(self.output_folder_path) - except FileNotFoundError: + except FileNotFoundError as e: logger.error('XLSX-file with the specified name does not exists.') - raise FileNotFoundError + raise e return Path(self.output_folder_path) / self.output_file_name From 12244f86f53fdbf7037d76a3460a2295e34fc669 Mon Sep 17 00:00:00 2001 From: diatlova Date: Mon, 3 May 2021 12:50:49 +0300 Subject: [PATCH 75/78] Fixed typing --- src/python/evaluation/xlsx_run_tool.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/python/evaluation/xlsx_run_tool.py b/src/python/evaluation/xlsx_run_tool.py index b24545e7..c0e9ec54 100644 --- a/src/python/evaluation/xlsx_run_tool.py +++ b/src/python/evaluation/xlsx_run_tool.py @@ -27,7 +27,7 @@ logger = logging.getLogger(__name__) -def configure_arguments(parser: argparse.ArgumentParser, run_tool_arguments: enum.EnumMeta) -> None: +def configure_arguments(parser: argparse.ArgumentParser, run_tool_arguments: RunToolArgument) -> None: parser.add_argument('xlsx_file_path', type=lambda value: Path(value).absolute(), help='Local XLSX-file path. ' From e4cc0c3a247980d82b93e29a3e85af568da46362 Mon Sep 17 00:00:00 2001 From: diatlova Date: Mon, 3 May 2021 12:53:38 +0300 Subject: [PATCH 76/78] Fixed typing --- src/python/evaluation/xlsx_run_tool.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/python/evaluation/xlsx_run_tool.py b/src/python/evaluation/xlsx_run_tool.py index c0e9ec54..c4925564 100644 --- a/src/python/evaluation/xlsx_run_tool.py +++ b/src/python/evaluation/xlsx_run_tool.py @@ -1,5 +1,4 @@ import argparse -import enum import logging.config import os import re From 275128f43321c8b3d763f544e809740d8528278b Mon Sep 17 00:00:00 2001 From: diatlova Date: Mon, 3 May 2021 14:00:02 +0300 Subject: [PATCH 77/78] Fixed Typing --- src/python/evaluation/common/xlsx_util.py | 4 ++-- src/python/evaluation/evaluation_config.py | 3 ++- src/python/evaluation/xlsx_run_tool.py | 5 +++-- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/python/evaluation/common/xlsx_util.py b/src/python/evaluation/common/xlsx_util.py index bb2ebec7..0b783de5 100644 --- a/src/python/evaluation/common/xlsx_util.py +++ b/src/python/evaluation/common/xlsx_util.py @@ -31,8 +31,8 @@ def create_and_get_workbook_path(config: EvaluationConfig) -> Path: return workbook_path -def write_dataframe_to_xlsx_sheet(xlsx_file_path: Union[str, Path], df: pd.DataFrame, - sheet_name: str, mode='a', to_write_row_names=False) -> None: +def write_dataframe_to_xlsx_sheet(xlsx_file_path: Union[str, Path], df: pd.DataFrame, sheet_name: str, + mode: str = 'a', to_write_row_names: bool = False) -> None: """ mode: str Available values are {'w', 'a'}. File mode to use (write or append). to_write_row_names: bool Write row names. diff --git a/src/python/evaluation/evaluation_config.py b/src/python/evaluation/evaluation_config.py index 0278d699..5cee71dc 100644 --- a/src/python/evaluation/evaluation_config.py +++ b/src/python/evaluation/evaluation_config.py @@ -1,4 +1,5 @@ import logging.config +from argparse import Namespace from pathlib import Path from typing import List, Union @@ -11,7 +12,7 @@ class EvaluationConfig: - def __init__(self, args): + def __init__(self, args: Namespace): self.tool_path: Union[str, Path] = args.tool_path self.output_format: str = args.format self.xlsx_file_path: Union[str, Path] = args.xlsx_file_path diff --git a/src/python/evaluation/xlsx_run_tool.py b/src/python/evaluation/xlsx_run_tool.py index c4925564..7235b041 100644 --- a/src/python/evaluation/xlsx_run_tool.py +++ b/src/python/evaluation/xlsx_run_tool.py @@ -5,6 +5,7 @@ import sys import traceback from pathlib import Path +from typing import Type sys.path.append('') sys.path.append('../../..') @@ -26,7 +27,7 @@ logger = logging.getLogger(__name__) -def configure_arguments(parser: argparse.ArgumentParser, run_tool_arguments: RunToolArgument) -> None: +def configure_arguments(parser: argparse.ArgumentParser, run_tool_arguments: Type[RunToolArgument]) -> None: parser.add_argument('xlsx_file_path', type=lambda value: Path(value).absolute(), help='Local XLSX-file path. ' @@ -71,7 +72,7 @@ def configure_arguments(parser: argparse.ArgumentParser, run_tool_arguments: Run 'is enabled argument will not be used otherwise.') -def create_dataframe(config) -> pd.DataFrame: +def create_dataframe(config: EvaluationConfig) -> pd.DataFrame: report = pd.DataFrame( { ColumnName.LANGUAGE.value: [], From 6f61f6b5eb105d421f4b637a191af8148adb2b8c Mon Sep 17 00:00:00 2001 From: diatlova Date: Mon, 3 May 2021 14:27:20 +0300 Subject: [PATCH 78/78] Fixed Typing --- src/python/evaluation/common/xlsx_util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/python/evaluation/common/xlsx_util.py b/src/python/evaluation/common/xlsx_util.py index 0b783de5..032a5ce6 100644 --- a/src/python/evaluation/common/xlsx_util.py +++ b/src/python/evaluation/common/xlsx_util.py @@ -9,7 +9,7 @@ logger = logging.getLogger(__name__) -def remove_sheet(workbook_path: Union[str, Path], sheet_name: str, to_raise_error=False) -> None: +def remove_sheet(workbook_path: Union[str, Path], sheet_name: str, to_raise_error: bool = False) -> None: try: workbook = load_workbook(workbook_path) workbook.remove(workbook[sheet_name])