Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions src/codeplag/codeplagcli.py
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,16 @@ def __add_settings_path(self: Self, subparsers: argparse._SubParsersAction) -> N
"show",
help=_("Show the '{util_name}' util settings.").format(util_name=UTIL_NAME),
)
# settings reset
settings_reset = settings_commands.add_parser(
"reset",
help=_("Reset the value of key to default")
)
settings_reset.add_argument(
"key",
type=str,
help=_("Key to value reset")
)

def __add_check_path(self: Self, subparsers: argparse._SubParsersAction) -> None:
check = subparsers.add_parser("check", help=_("Start searching similar works."))
Expand Down
172 changes: 78 additions & 94 deletions src/codeplag/config.py
Original file line number Diff line number Diff line change
@@ -1,99 +1,83 @@
import json
from pathlib import Path
from typing import Any, Literal, Mapping, overload
from typing import Any

from typing_extensions import Self

from codeplag.consts import (
CONFIG_PATH,
DEFAULT_LANGUAGE,
DEFAULT_LOG_LEVEL,
DEFAULT_MAX_DEPTH,
DEFAULT_MONGO_HOST,
DEFAULT_MONGO_PORT,
DEFAULT_MONGO_USER,
DEFAULT_NGRAMS_LENGTH,
DEFAULT_REPORT_EXTENSION,
DEFAULT_THRESHOLD,
DEFAULT_WORKERS,
DEFAULT_MODE,
UTIL_NAME,
UTIL_VERSION,
)
from codeplag.logger import codeplag_logger as logger
from codeplag.types import Settings, ShortOutput

Config = dict[str, Any]


@overload
def read_config(file: Path, safe: Literal[False] = False) -> Config: ...


@overload
def read_config(file: Path, safe: bool = False) -> Config | None: ...


def read_config(file: Path, safe: bool = False) -> Config | None:
config = None
try:
with file.open(mode="r") as f:
config = json.load(f)
except (json.decoder.JSONDecodeError, FileNotFoundError, PermissionError):
if not safe:
raise

return config


# TODO: Handle permission denied
def write_config(file: Path, config: Mapping[str, Any]) -> None:
config_for_dump = dict(config)
for key in config_for_dump:
if isinstance(config_for_dump[key], Path):
config_for_dump[key] = str(config_for_dump[key])

with file.open(mode="w", encoding="utf-8") as f:
json.dump(config_for_dump, f, indent=4)


def read_settings_conf() -> Settings:
loaded_settings_config = read_config(CONFIG_PATH, safe=True)
if loaded_settings_config is None:
logger.warning(
"Unsuccessful attempt to read config '%s'. Returning default config.",
CONFIG_PATH,
)
return DefaultSettingsConfig

for key in Settings.__annotations__:
if key not in loaded_settings_config:
if key in DefaultSettingsConfig:
loaded_settings_config[key] = DefaultSettingsConfig[key]
continue

if key in ["environment", "reports"]:
loaded_settings_config[key] = Path(loaded_settings_config[key])

return Settings(
**{
key: loaded_settings_config[key]
for key in Settings.__annotations__
if key in loaded_settings_config
}
)


def write_settings_conf(settings: Settings) -> None:
write_config(CONFIG_PATH, settings)


DefaultSettingsConfig = Settings(
threshold=DEFAULT_THRESHOLD,
max_depth=DEFAULT_MAX_DEPTH,
ngrams_length=DEFAULT_NGRAMS_LENGTH,
show_progress=0,
short_output=ShortOutput.SHOW_ALL,
reports_extension=DEFAULT_REPORT_EXTENSION,
language=DEFAULT_LANGUAGE,
log_level=DEFAULT_LOG_LEVEL,
workers=DEFAULT_WORKERS,
mongo_host=DEFAULT_MONGO_HOST,
mongo_port=DEFAULT_MONGO_PORT,
mongo_user=DEFAULT_MONGO_USER,
from codeplag.handlers.check import IgnoreThresholdWorksComparator, WorksComparator
from codeplag.handlers.report import (
html_report_create,
)
from codeplag.handlers.settings import settings_modify, settings_show, settings_reset
from codeplag.logger import codeplag_logger as logger
from codeplag.types import ExitCode, ReportType


class CodeplagEngine:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Это изменение кажется не должно было сюда попасть.

def __init__(self: Self, parsed_args: dict[str, Any]) -> None:
self.root: str = parsed_args.pop("root")
self.command: str | None = None
# TODO: tmp
if self.root == "settings":
self.command = parsed_args.pop(self.root)
if self.command == "reset":
self.key = parsed_args.pop("key", None)
if self.command == "show":
return

self.parsed_args = parsed_args
elif self.root == "report":
self.path: Path = parsed_args.pop("path")
self.report_type: ReportType = parsed_args.pop("type")
self.first_root_path = parsed_args.pop("first_root_path", None)
self.second_root_path = parsed_args.pop("second_root_path", None)
else:
self.github_urls: list[str] = parsed_args.pop("github_urls", [])
self.github_user: str = parsed_args.pop("github_user", "") or ""
ignore_threshold: bool = parsed_args.pop("ignore_threshold")
if ignore_threshold:
comparator_class = IgnoreThresholdWorksComparator
else:
comparator_class = WorksComparator
self.comparator: WorksComparator = comparator_class(
extension=parsed_args.pop("extension"),
repo_regexp=parsed_args.pop("repo_regexp", None),
path_regexp=parsed_args.pop("path_regexp", None),
mode=parsed_args.pop("mode", DEFAULT_MODE),
set_github_parser=bool(self.github_urls or self.github_user),
all_branches=parsed_args.pop("all_branches", False),
)

self.files: list[Path] = parsed_args.pop("files", [])
self.directories: list[Path] = parsed_args.pop("directories", [])

def run(self: Self) -> ExitCode:
logger.info("Starting %s util (%s) ...", UTIL_NAME, UTIL_VERSION)

if self.root == "settings":
if self.command == "show":
settings_show()
elif self.command == "modify":
settings_modify(self.parsed_args)
settings_show()
elif self.command == "reset":
if not hasattr(self, 'key') or not self.key:
return ExitCode.EXIT_INVAL
return settings_reset(self.key)

elif self.root == "report":
return html_report_create(
self.path, self.report_type, self.first_root_path, self.second_root_path
)
else:
return self.comparator.check(
self.files,
self.directories,
self.github_urls,
self.github_user,
)
return ExitCode.EXIT_SUCCESS
18 changes: 16 additions & 2 deletions src/codeplag/handlers/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
import numpy as np
import pandas as pd

from codeplag.config import read_settings_conf, write_settings_conf
from codeplag.types import Settings
from codeplag.config import read_settings_conf, write_settings_conf, read_config, write_config, CONFIG_PATH
from codeplag.types import Settings, ExitCode


def settings_show() -> None:
Expand All @@ -32,3 +32,17 @@ def settings_modify(parsed_args: dict[str, Any]) -> None:
settings_config[key] = new_value

write_settings_conf(settings_config)

def settings_reset(key: str) -> ExitCode:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Хотелось бы по возможности отделаться только settings_modify, почему решено разделить на reset?

config = read_config(CONFIG_PATH, safe=True)

if config is None:
return ExitCode.EXIT_SUCCESS

if key not in Settings.__annotations__:
return ExitCode.EXIT_INVAL

if key in config:
del config[key]
write_config(CONFIG_PATH, config)
return ExitCode.EXIT_SUCCESS