Skip to content

Commit

Permalink
feat: exit with positive exit code in the end when found similarity. (#…
Browse files Browse the repository at this point in the history
…210)

Refs: #210, #153.
  • Loading branch information
Artanias authored Jan 3, 2025
1 parent 9875f8a commit f1323ba
Show file tree
Hide file tree
Showing 14 changed files with 155 additions and 59 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
UTIL_VERSION := 0.5.11
UTIL_VERSION := 0.5.12
UTIL_NAME := codeplag
PWD := $(shell pwd)

Expand Down
12 changes: 10 additions & 2 deletions locales/codeplag.pot
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: codeplag 0.5.11\n"
"POT-Creation-Date: 2025-01-02 18:42+0300\n"
"Project-Id-Version: codeplag 0.5.12\n"
"POT-Creation-Date: 2025-01-03 14:06+0300\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: Artyom Semidolin\n"
"Language-Team: LANGUAGE <[email protected]>\n"
Expand Down Expand Up @@ -216,6 +216,14 @@ msgid ""
"user', or 'github-project-folder' options."
msgstr ""

#: src/codeplag/codeplagcli.py:421 src/codeplag/handlers/report.py:95
msgid "All paths must be provided."
msgstr ""

#: src/codeplag/handlers/report.py:92
msgid "Invalid report type."
msgstr ""

#: src/templates/general.templ:5 src/templates/sources.templ:5
msgid "Comparative report"
msgstr ""
Expand Down
10 changes: 9 additions & 1 deletion locales/translations/en/LC_MESSAGES/codeplag.po
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: codeplag 0.5.11\n"
"Project-Id-Version: codeplag 0.5.12\n"
"POT-Creation-Date: 2024-05-21 09:28+0300\n"
"PO-Revision-Date: 2024-05-16 19:15+0300\n"
"Last-Translator: Artyom Semidolin\n"
Expand Down Expand Up @@ -242,6 +242,14 @@ msgstr ""
"The'path-regexp' option requires the provided 'directories', 'github-"
"user', or 'github-project-folder' options."

#: src/codeplag/codeplagcli.py:421 src/codeplag/handlers/report.py:95
msgid "All paths must be provided."
msgstr "All or none of the root paths must be specified."

#: src/codeplag/handlers/report.py:92
msgid "Invalid report type."
msgstr "Invalid report type."

#: src/templates/general.templ:5 src/templates/sources.templ:5
msgid "Comparative report"
msgstr "Comparative report"
Expand Down
10 changes: 9 additions & 1 deletion locales/translations/ru/LC_MESSAGES/codeplag.po
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
#
msgid ""
msgstr ""
"Project-Id-Version: codeplag 0.5.11\n"
"Project-Id-Version: codeplag 0.5.12\n"
"POT-Creation-Date: 2024-05-21 09:28+0300\n"
"PO-Revision-Date: 2024-05-11 12:05+0300\n"
"Last-Translator: Artyom Semidolin\n"
Expand Down Expand Up @@ -256,6 +256,14 @@ msgstr ""
"Аргумент 'path-regexp' требует заданного параметра 'directories', "
"'github-user' или 'github-project-folder'."

#: src/codeplag/codeplagcli.py:421 src/codeplag/handlers/report.py:95
msgid "All paths must be provided."
msgstr "Необходимо указать все корневые пути или не указывать ни одного."

#: src/codeplag/handlers/report.py:92
msgid "Invalid report type."
msgstr "Некорректный тип отчёта."

#: src/templates/general.templ:5 src/templates/sources.templ:5
msgid "Comparative report"
msgstr "Сравнительный отчёт"
Expand Down
8 changes: 4 additions & 4 deletions src/codeplag/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from typing import Literal
from codeplag.types import ExitCode


def main() -> Literal[0, 1, 2]:
def main() -> ExitCode:
import argcomplete
import pandas as pd

Expand Down Expand Up @@ -29,14 +29,14 @@ def main() -> Literal[0, 1, 2]:
code = codeplag_util.run()
except KeyboardInterrupt:
logger.warning("The util stopped by keyboard interrupt.")
return 1
return ExitCode.EXIT_KEYBOARD
except Exception:
logger.error(
"An unexpected error occurred while running the utility. "
"For getting more information, check file '%s'.",
LOG_PATH,
)
logger.debug("Trace:", exc_info=True)
return 2
return ExitCode.EXIT_UNKNOWN

return code
7 changes: 7 additions & 0 deletions src/codeplag/codeplagcli.py
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,13 @@ def validate_args(self: Self, parsed_args: argparse.Namespace) -> None:
"'github-user', or 'github-project-folder' options."
)
)
elif (
root == "report"
and command == "create"
and not all([parsed_args.first_root_path, parsed_args.second_root_path])
and any([parsed_args.first_root_path, parsed_args.second_root_path])
):
self.error(_("All paths must be provided."))

def parse_args(self: Self, args: list[str] | None = None) -> argparse.Namespace:
parsed_args = super(CodeplagCLI, self).parse_args(args)
Expand Down
54 changes: 36 additions & 18 deletions src/codeplag/handlers/check.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
from codeplag.types import (
ASTFeatures,
CompareInfo,
ExitCode,
Extension,
Flag,
MaxDepth,
Expand Down Expand Up @@ -151,7 +152,7 @@ def check(
github_files: list[str] | None = None,
github_project_folders: list[str] | None = None,
github_user: str = "",
) -> None:
) -> ExitCode:
if files is None:
files = []
if directories is None:
Expand All @@ -167,16 +168,17 @@ def check(
features_from_gh_files = self.features_getter.get_from_github_files(github_files)

logger.info("Starting searching for plagiarism ...")
exit_code = ExitCode.EXIT_SUCCESS
if self.mode == "many_to_many":
self.__many_to_many_check(
exit_code = self.__many_to_many_check(
features_from_files,
directories,
features_from_gh_files,
github_project_folders,
github_user,
)
elif self.mode == "one_to_one":
self.__one_to_one_check(
exit_code = self.__one_to_one_check(
features_from_files,
directories,
features_from_gh_files,
Expand All @@ -187,6 +189,7 @@ def check(
logger.info("Ending searching for plagiarism ...")
if isinstance(self.reporter, CSVReporter):
self.reporter._write_df_to_fs()
return exit_code

def __many_to_many_check(
self: Self,
Expand All @@ -195,7 +198,7 @@ def __many_to_many_check(
features_from_gh_files: list[ASTFeatures],
github_project_folders: list[str],
github_user: str,
) -> None:
) -> ExitCode:
works: list[ASTFeatures] = []
works.extend(features_from_files)
works.extend(self.features_getter.get_from_dirs(directories))
Expand All @@ -212,15 +215,19 @@ def __many_to_many_check(
iterations,
)
self.progress = Progress(iterations)
exit_code = ExitCode.EXIT_SUCCESS
with ProcessPoolExecutor(max_workers=self.workers) as executor:
processing: list[ProcessingWorks] = []
futures: set[Future] = set()
for i, work1 in enumerate(works):
for j, work2 in enumerate(works):
if i <= j:
continue
self._do_step(executor, processing, futures, work1, work2)
self._handle_completed_futures(processing, futures)
exit_code = ExitCode(
exit_code | self._do_step(executor, processing, futures, work1, work2)
)
exit_code = ExitCode(exit_code | self._handle_completed_futures(processing, futures))
return exit_code

def __one_to_one_check(
self: Self,
Expand All @@ -229,7 +236,7 @@ def __one_to_one_check(
features_from_gh_files: list[ASTFeatures],
github_project_folders: list[str],
github_user: str,
) -> None:
) -> ExitCode:
combined_elements = filter(
bool,
(
Expand All @@ -253,6 +260,7 @@ def __one_to_one_check(
)
self.progress = ComplexProgress(iterations)
cases = combinations(combined_elements, r=2)
exit_code = ExitCode.EXIT_SUCCESS
with ProcessPoolExecutor(max_workers=self.workers) as executor:
processing: list[ProcessingWorks] = []
futures: set[Future] = set()
Expand All @@ -269,8 +277,11 @@ def __one_to_one_check(
self.progress.add_internal_progress(internal_iterations)
for work1 in first_sequence:
for work2 in second_sequence:
self._do_step(executor, processing, futures, work1, work2)
self._handle_completed_futures(processing, futures)
exit_code = ExitCode(
exit_code | self._do_step(executor, processing, futures, work1, work2)
)
exit_code = ExitCode(exit_code | self._handle_completed_futures(processing, futures))
return exit_code

def _do_step(
self: Self,
Expand All @@ -279,10 +290,10 @@ def _do_step(
futures: set[Future],
work1: ASTFeatures,
work2: ASTFeatures,
) -> None:
) -> ExitCode:
if work1.filepath == work2.filepath:
_print_pretty_progress_if_need_and_increase(self.progress, self.workers)
return
return ExitCode.EXIT_SUCCESS

work1, work2 = sorted([work1, work2])
metrics = None
Expand All @@ -293,23 +304,24 @@ def _do_step(
future.id = len(processing) # type: ignore
futures.add(future)
processing.append(ProcessingWorks(work1, work2))
return
return ExitCode.EXIT_SUCCESS
self._handle_compare_result(work1, work2, metrics)
_print_pretty_progress_if_need_and_increase(self.progress, self.workers)
return ExitCode.EXIT_FOUND_SIM

def _handle_compare_result(
self: Self,
work1: ASTFeatures,
work2: ASTFeatures,
metrics: CompareInfo,
save: bool = False,
) -> None:
) -> ExitCode:
if metrics.structure is None:
return
return ExitCode.EXIT_SUCCESS
if self.reporter and save:
self.reporter.save_result(work1, work2, metrics)
if self.short_output:
return
return ExitCode.EXIT_FOUND_SIM

if self.threshold and (metrics.structure.similarity * 100) <= self.threshold:
print_compare_result(work1, work2, metrics)
Expand All @@ -324,19 +336,25 @@ def _handle_compare_result(
work2.head_nodes,
),
)
return ExitCode.EXIT_FOUND_SIM

def _handle_completed_futures(
self: Self,
processing: list[ProcessingWorks],
futures: set[Future],
) -> None:
) -> ExitCode:
exit_code = ExitCode.EXIT_SUCCESS
for future in as_completed(futures):
metrics: CompareInfo = future.result()
proc_works_info = processing[future.id] # type: ignore
self._handle_compare_result(
proc_works_info.work1, proc_works_info.work2, metrics, save=True
exit_code = ExitCode(
exit_code
| self._handle_compare_result(
proc_works_info.work1, proc_works_info.work2, metrics, save=True
)
)
_print_pretty_progress_if_need_and_increase(self.progress, self.workers)
return exit_code

def _create_future_compare(
self: Self,
Expand Down
19 changes: 10 additions & 9 deletions src/codeplag/handlers/report.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from collections import defaultdict
from copy import deepcopy
from pathlib import Path
from typing import Generator, Literal, TypedDict
from typing import Generator, TypedDict

import jinja2
import numpy as np
Expand All @@ -25,6 +25,7 @@
from codeplag.translate import get_translations
from codeplag.types import (
CompareInfo,
ExitCode,
Language,
ReportType,
SameFuncs,
Expand All @@ -48,7 +49,7 @@ def html_report_create(
report_type: ReportType,
first_root_path: Path | str | None = None,
second_root_path: Path | str | None = None,
) -> Literal[0, 1]:
) -> ExitCode:
"""Creates an HTML report based on the configuration settings.
Args:
Expand All @@ -60,7 +61,7 @@ def html_report_create(
Returns:
-------
Literal[0, 1]: 0 if the report was successfully created, 1 otherwise.
ExitCode: 0 if the report was successfully created, 1 otherwise.
Raises:
-------
Expand All @@ -76,22 +77,22 @@ def html_report_create(
reports_path = settings_config.get("reports")
if not reports_path:
logger.error("Can't create general report without provided in settings 'report' path.")
return 1
return ExitCode.EXIT_INVAL
if settings_config["reports_extension"] != "csv":
logger.error("Can create report only when 'reports_extension' is csv.")
return 1
return ExitCode.EXIT_INVAL
if not (reports_path / CSV_REPORT_FILENAME).exists():
logger.error(f"There is nothing in '{reports_path}' to create a basic html report from.")
return 1
return ExitCode.EXIT_INVAL
if report_type == "general":
create_report_function = _create_general_report
elif report_type == "sources":
create_report_function = _create_sources_report
else:
raise ValueError("Invalid report type.")
raise ValueError(_("Invalid report type."))
all_paths_provided = all([first_root_path, second_root_path])
if not all_paths_provided and any([first_root_path, second_root_path]):
raise ValueError("All paths must be provided.")
raise ValueError(_("All paths must be provided."))

df = read_df(reports_path / CSV_REPORT_FILENAME)
if all_paths_provided:
Expand All @@ -110,7 +111,7 @@ def html_report_create(
settings_config["language"],
paths, # type: ignore
)
return 0
return ExitCode.EXIT_SUCCESS


def calculate_general_total_similarity(
Expand Down
Loading

0 comments on commit f1323ba

Please sign in to comment.