diff --git a/pisek/opendata/managers.py b/pisek/opendata/managers.py
index ec6d7bc9..90256342 100644
--- a/pisek/opendata/managers.py
+++ b/pisek/opendata/managers.py
@@ -1,7 +1,7 @@
from pisek.jobs.jobs import Job
from pisek.jobs.status import StatusJobManager
from pisek.jobs.job_pipeline import JobPipeline
-from pisek.utils.paths import InputPath, OutputPath, RawPath
+from pisek.utils.paths import IInputPath, IOutputPath, IRawPath
from pisek.task_jobs.tools import sanitize_job, sanitize_job_direct
from pisek.task_jobs.data.testcase_info import TestcaseInfo, TestcaseGenerationMode
@@ -17,12 +17,12 @@ def __init__(
gen_input: bool,
gen_output: bool,
check: bool,
- input_: InputPath,
+ input_: IInputPath,
info: TestcaseInfo,
test: int,
seed: int | None,
- correct_output: OutputPath,
- contestant_output: RawPath | None,
+ correct_output: IOutputPath,
+ contestant_output: IRawPath | None,
):
super().__init__()
self.job_managers = []
@@ -51,7 +51,7 @@ def verdict(self) -> OpendataVerdict:
class InputManager(StatusJobManager):
- def __init__(self, input_: InputPath, info: TestcaseInfo, seed: int | None):
+ def __init__(self, input_: IInputPath, info: TestcaseInfo, seed: int | None):
super().__init__(f"Generate input {input_:n}")
self._input = input_
self._info = info
@@ -76,7 +76,7 @@ def _get_jobs(self) -> list[Job]:
class OutputManager(StatusJobManager):
- def __init__(self, input_: InputPath, info: TestcaseInfo, output: OutputPath):
+ def __init__(self, input_: IInputPath, info: TestcaseInfo, output: IOutputPath):
self._input = input_
self._info = info
self._output = output
@@ -107,11 +107,11 @@ def _get_jobs(self) -> list[Job]:
class CheckerManager(StatusJobManager):
def __init__(
self,
- input_: InputPath,
+ input_: IInputPath,
test: int,
seed: int | None,
- correct_output: OutputPath,
- contestant_output: RawPath,
+ correct_output: IOutputPath,
+ contestant_output: IRawPath,
):
self._input = input_
self._test = test
diff --git a/pisek/task_jobs/checker/checker.py b/pisek/task_jobs/checker/checker.py
index 5d44ebd6..95b7c5e2 100644
--- a/pisek/task_jobs/checker/checker.py
+++ b/pisek/task_jobs/checker/checker.py
@@ -13,7 +13,7 @@
from typing import Optional
from pisek.env.env import Env
-from pisek.utils.paths import InputPath, OutputPath
+from pisek.utils.paths import IInputPath, IOutputPath
from pisek.config.config_types import OutCheck, JudgeType
from pisek.task_jobs.solution.solution_result import Verdict
@@ -28,9 +28,9 @@
def checker_job(
- input_: InputPath,
- output: OutputPath,
- correct_output: OutputPath,
+ input_: IInputPath,
+ output: IOutputPath,
+ correct_output: IOutputPath,
test: int,
seed: Optional[int],
expected_verdict: Optional[Verdict],
diff --git a/pisek/task_jobs/checker/checker_base.py b/pisek/task_jobs/checker/checker_base.py
index 1353128d..5a3c8028 100644
--- a/pisek/task_jobs/checker/checker_base.py
+++ b/pisek/task_jobs/checker/checker_base.py
@@ -16,7 +16,7 @@
from functools import cache
from pisek.utils.text import tab
-from pisek.utils.paths import InputPath, OutputPath, LogPath
+from pisek.utils.paths import IInputPath, IOutputPath, LogPath
from pisek.env.env import Env
from pisek.config.config_types import DataFormat
from pisek.task_jobs.tools import SanitizationResultKind
@@ -40,7 +40,7 @@ def __init__(
name: str,
test: int,
checker_name: str,
- input_: InputPath,
+ input_: IInputPath,
checker_log_file: LogPath,
expected_verdict: Optional[Verdict],
**kwargs,
@@ -216,9 +216,9 @@ def __init__(
env: Env,
checker_name: str,
test: int,
- input_: InputPath,
- output: OutputPath,
- correct_output: OutputPath,
+ input_: IInputPath,
+ output: IOutputPath,
+ correct_output: IOutputPath,
expected_verdict: Optional[Verdict],
**kwargs,
) -> None:
diff --git a/pisek/task_jobs/checker/cms_judge.py b/pisek/task_jobs/checker/cms_judge.py
index 71477936..9394c150 100644
--- a/pisek/task_jobs/checker/cms_judge.py
+++ b/pisek/task_jobs/checker/cms_judge.py
@@ -16,7 +16,7 @@
from tempfile import gettempdir
from uuid import uuid4
-from pisek.utils.paths import InputPath, OutputPath
+from pisek.utils.paths import IInputPath, IOutputPath
from pisek.env.env import Env
from pisek.config.task_config import RunSection
from pisek.config.config_types import ProgramRole
@@ -101,9 +101,9 @@ def __init__(
env: Env,
judge: RunSection,
test: int,
- input_: InputPath,
- output: OutputPath,
- correct_output: OutputPath,
+ input_: IInputPath,
+ output: IOutputPath,
+ correct_output: IOutputPath,
expected_verdict: Optional[Verdict],
**kwargs,
) -> None:
diff --git a/pisek/task_jobs/checker/diff_checker.py b/pisek/task_jobs/checker/diff_checker.py
index a5ceb9b6..35642101 100644
--- a/pisek/task_jobs/checker/diff_checker.py
+++ b/pisek/task_jobs/checker/diff_checker.py
@@ -15,7 +15,7 @@
from typing import Optional
from pisek.env.env import Env
-from pisek.utils.paths import InputPath, OutputPath
+from pisek.utils.paths import IInputPath, IOutputPath
from pisek.jobs.jobs import PipelineItemFailure
from pisek.utils.text import tab
from pisek.task_jobs.run_result import RunResult, RunResultKind
@@ -34,9 +34,9 @@ def __init__(
self,
env: Env,
test: int,
- input_: InputPath,
- output: OutputPath,
- correct_output: OutputPath,
+ input_: IInputPath,
+ output: IOutputPath,
+ correct_output: IOutputPath,
expected_verdict: Optional[Verdict],
) -> None:
super().__init__(
diff --git a/pisek/task_jobs/checker/judgelib_checker.py b/pisek/task_jobs/checker/judgelib_checker.py
index 4794e564..dca7ce2c 100644
--- a/pisek/task_jobs/checker/judgelib_checker.py
+++ b/pisek/task_jobs/checker/judgelib_checker.py
@@ -16,7 +16,7 @@
from typing import Optional
from pisek.env.env import Env
-from pisek.utils.paths import TaskPath, InputPath, OutputPath
+from pisek.utils.paths import TaskPath, IInputPath, IOutputPath
from pisek.jobs.jobs import PipelineItemFailure
from pisek.utils.text import tab
from pisek.task_jobs.run_result import RunResult, RunResultKind
@@ -92,9 +92,9 @@ def __init__(
self,
env: Env,
test: int,
- input_: InputPath,
- output: OutputPath,
- correct_output: OutputPath,
+ input_: IInputPath,
+ output: IOutputPath,
+ correct_output: IOutputPath,
expected_verdict: Optional[Verdict],
) -> None:
super().__init__(
@@ -133,9 +133,9 @@ def __init__(
self,
env: Env,
test: int,
- input_: InputPath,
- output: OutputPath,
- correct_output: OutputPath,
+ input_: IInputPath,
+ output: IOutputPath,
+ correct_output: IOutputPath,
expected_verdict: Optional[Verdict],
) -> None:
super().__init__(
diff --git a/pisek/task_jobs/checker/opendata_judge.py b/pisek/task_jobs/checker/opendata_judge.py
index d90f1a97..3604676e 100644
--- a/pisek/task_jobs/checker/opendata_judge.py
+++ b/pisek/task_jobs/checker/opendata_judge.py
@@ -15,7 +15,7 @@
import logging
from typing import Any
-from pisek.utils.paths import InputPath, OutputPath
+from pisek.utils.paths import IInputPath, IOutputPath
from pisek.env.env import Env
from pisek.config.config_types import ProgramRole
from pisek.config.task_config import RunSection
@@ -52,9 +52,9 @@ def __init__(
env: Env,
judge: RunSection,
test: int,
- input_: InputPath,
- output: OutputPath,
- correct_output: OutputPath,
+ input_: IInputPath,
+ output: IOutputPath,
+ correct_output: IOutputPath,
seed: int | None,
expected_verdict: Verdict | None,
**kwargs,
diff --git a/pisek/task_jobs/data/data.py b/pisek/task_jobs/data/data.py
index 5c148013..52f82dbe 100644
--- a/pisek/task_jobs/data/data.py
+++ b/pisek/task_jobs/data/data.py
@@ -16,7 +16,7 @@
from pisek.jobs.jobs import PipelineItemFailure
from pisek.env.env import Env
-from pisek.utils.paths import TaskPath, InputPath, OutputPath
+from pisek.utils.paths import TaskPath, IInputPath, IOutputPath
from pisek.task_jobs.task_job import TaskJob
@@ -62,7 +62,7 @@ def _run(self):
class InputSmall(DataJob):
"""Checks that input is small enough to download."""
- def __init__(self, env: Env, input_: InputPath, **kwargs) -> None:
+ def __init__(self, env: Env, input_: IInputPath, **kwargs) -> None:
super().__init__(
env=env,
name=f"Input {input_:p} is smaller than {env.config.limits.input_max_size}MB",
@@ -81,7 +81,7 @@ def _run(self):
class OutputSmall(DataJob):
"""Checks that output is small enough to upload."""
- def __init__(self, env: Env, output: OutputPath, **kwargs) -> None:
+ def __init__(self, env: Env, output: IOutputPath, **kwargs) -> None:
super().__init__(
env=env,
name=f"Output {output:p} is smaller than {env.config.limits.output_max_size}MB",
diff --git a/pisek/task_jobs/data/testcase_info.py b/pisek/task_jobs/data/testcase_info.py
index 1f086c4b..a3fa4ac8 100644
--- a/pisek/task_jobs/data/testcase_info.py
+++ b/pisek/task_jobs/data/testcase_info.py
@@ -16,7 +16,15 @@
from pisek.env.env import Env
from pisek.task_jobs.task_job import TaskJob
-from pisek.utils.paths import TESTS_DIR, INPUTS_LIST, InputPath, OutputPath, TaskPath
+from pisek.utils.paths import (
+ TESTS_DIR,
+ INPUTS_LIST,
+ InputPath,
+ IInputPath,
+ IOutputPath,
+ OutputPath,
+ TaskPath,
+)
class TestcaseGenerationMode(StrEnum):
@@ -46,7 +54,7 @@ def static(name: str) -> "TestcaseInfo":
def input_path(
self, seed: int | None = None, solution: str | None = None
- ) -> InputPath:
+ ) -> IInputPath:
filename = self.name
if self.seeded:
assert seed is not None
@@ -57,10 +65,11 @@ def input_path(
def reference_output(
self, env: Env, seed: int | None = None, solution: str | None = None
- ) -> OutputPath:
+ ) -> IOutputPath:
is_static = self.generation_mode == TestcaseGenerationMode.static
input_path = self.input_path(seed, solution=env.config.primary_solution)
+ path: IOutputPath
if is_static:
path = OutputPath.static(input_path.replace_suffix(".out").name)
else:
diff --git a/pisek/task_jobs/generator/base_classes.py b/pisek/task_jobs/generator/base_classes.py
index ef3a65bf..94e27652 100644
--- a/pisek/task_jobs/generator/base_classes.py
+++ b/pisek/task_jobs/generator/base_classes.py
@@ -16,7 +16,7 @@
from pisek.env.env import Env
from pisek.jobs.jobs import PipelineItemFailure
from pisek.config.task_config import RunSection
-from pisek.utils.paths import InputPath
+from pisek.utils.paths import IInputPath
from pisek.task_jobs.task_job import TaskJob
from pisek.task_jobs.program import ProgramsJob
from pisek.task_jobs.data.testcase_info import TestcaseInfo, TestcaseGenerationMode
@@ -45,7 +45,7 @@ def __init__(
generator: RunSection,
testcase_info: TestcaseInfo,
seed: Optional[int],
- input_path: InputPath,
+ input_path: IInputPath,
*,
name: str = "",
**kwargs,
diff --git a/pisek/task_jobs/generator/generator_manager.py b/pisek/task_jobs/generator/generator_manager.py
index acd11db0..6f8c4678 100644
--- a/pisek/task_jobs/generator/generator_manager.py
+++ b/pisek/task_jobs/generator/generator_manager.py
@@ -18,7 +18,7 @@
from hashlib import blake2b
from pisek.env.env import Env
-from pisek.utils.paths import InputPath, OutputPath
+from pisek.utils.paths import IInputPath, IOutputPath
from pisek.config.config_types import GenType
from pisek.config.task_config import RunSection
from pisek.jobs.jobs import Job, JobManager
@@ -91,7 +91,7 @@ def generate_input(
def generate_input_direct(
- env: Env, testcase_info: TestcaseInfo, seed: Optional[int], input_path: InputPath
+ env: Env, testcase_info: TestcaseInfo, seed: Optional[int], input_path: IInputPath
) -> GenerateInput:
assert env.config.tests.in_gen is not None
assert env.config.tests.gen_type is not None
@@ -126,7 +126,7 @@ def generator_test_determinism(
class TestcaseInfoMixin(JobManager):
def __init__(self, name: str, **kwargs) -> None:
self.inputs: dict[str, tuple[set[int], int | None]] = {}
- self.input_dataset: set[InputPath] = set()
+ self.input_dataset: set[IInputPath] = set()
self._gen_inputs_job: dict[Optional[int], GenerateInput] = {}
self._jobs: list[Job] = []
@@ -240,7 +240,7 @@ def _add_generate_input_jobs(
)
)
- def _validate(self, input_path: InputPath, test_num: int) -> ValidatorJob:
+ def _validate(self, input_path: IInputPath, test_num: int) -> ValidatorJob:
assert self._env.config.tests.validator is not None
assert self._env.config.tests.validator_type is not None
@@ -283,7 +283,7 @@ def _add_respects_seed_jobs(
for i in range(2):
check_seeded.add_prerequisite(self._gen_inputs_job[seeds[i]])
- def _check_input_jobs(self, input_path: InputPath) -> None:
+ def _check_input_jobs(self, input_path: IInputPath) -> None:
self._add_job(
sanitize_job(self._env, input_path, True),
new_last=True,
@@ -294,7 +294,7 @@ def _check_input_jobs(self, input_path: InputPath) -> None:
def _add_check_output_jobs(
self,
- output_path: OutputPath,
+ output_path: IOutputPath,
) -> None:
self._add_job(
sanitize_job(self._env, output_path, False),
diff --git a/pisek/task_jobs/generator/opendata_v1.py b/pisek/task_jobs/generator/opendata_v1.py
index 223211ad..7746eae6 100644
--- a/pisek/task_jobs/generator/opendata_v1.py
+++ b/pisek/task_jobs/generator/opendata_v1.py
@@ -15,7 +15,7 @@
from pisek.env.env import Env
from pisek.config.config_types import ProgramRole
from pisek.config.task_config import RunSection
-from pisek.utils.paths import InputPath
+from pisek.utils.paths import IInputPath
from pisek.task_jobs.program import ProgramsJob, RunResultKind
from pisek.task_jobs.data.testcase_info import TestcaseInfo
@@ -45,7 +45,7 @@ class OpendataV1GeneratorJob(ProgramsJob):
generator: RunSection
seed: Optional[int]
testcase_info: TestcaseInfo
- input_path: InputPath
+ input_path: IInputPath
def __init__(self, env: Env, *, name: str = "", **kwargs) -> None:
super().__init__(env=env, name=name, **kwargs)
diff --git a/pisek/task_jobs/generator/pisek_v1.py b/pisek/task_jobs/generator/pisek_v1.py
index 7df8b556..2cc2e3d5 100644
--- a/pisek/task_jobs/generator/pisek_v1.py
+++ b/pisek/task_jobs/generator/pisek_v1.py
@@ -17,7 +17,7 @@
from pisek.env.env import Env
from pisek.config.config_types import ProgramRole
from pisek.config.task_config import RunSection
-from pisek.utils.paths import TaskPath, InputPath, LogPath
+from pisek.utils.paths import TaskPath, IInputPath, LogPath
from pisek.task_jobs.program import ProgramsJob, RunResultKind
from pisek.task_jobs.data.testcase_info import TestcaseInfo
@@ -89,7 +89,7 @@ class PisekV1GeneratorJob(ProgramsJob):
generator: RunSection
seed: Optional[int]
testcase_info: TestcaseInfo
- input_path: InputPath
+ input_path: IInputPath
def __init__(self, env: Env, *, name: str = "", **kwargs) -> None:
super().__init__(env=env, name=name, **kwargs)
diff --git a/pisek/task_jobs/solution/solution.py b/pisek/task_jobs/solution/solution.py
index d35e506c..e8eb667a 100644
--- a/pisek/task_jobs/solution/solution.py
+++ b/pisek/task_jobs/solution/solution.py
@@ -18,7 +18,7 @@
from pisek.env.env import Env
from pisek.jobs.jobs import State
-from pisek.utils.paths import InputPath, OutputPath
+from pisek.utils.paths import IInputPath, IOutputPath
from pisek.config.config_types import ProgramRole
from pisek.config.task_config import RunSection
from pisek.task_jobs.program import RunResult, ProgramsJob
@@ -65,8 +65,8 @@ def __init__(
env: Env,
solution: RunSection,
is_primary: bool,
- input_: InputPath,
- output: OutputPath,
+ input_: IInputPath,
+ output: IOutputPath,
**kwargs,
) -> None:
super().__init__(
@@ -98,7 +98,7 @@ def __init__(
is_primary: bool,
judge: RunSection,
test: int,
- input_: InputPath,
+ input_: IInputPath,
expected_verdict: Optional[Verdict] = None,
**kwargs,
):
diff --git a/pisek/task_jobs/solution/solution_manager.py b/pisek/task_jobs/solution/solution_manager.py
index daf62389..00a5cc65 100644
--- a/pisek/task_jobs/solution/solution_manager.py
+++ b/pisek/task_jobs/solution/solution_manager.py
@@ -20,7 +20,7 @@
from pisek.jobs.jobs import State, Job, PipelineItemFailure
from pisek.env.env import Env
-from pisek.utils.paths import InputPath
+from pisek.utils.paths import IInputPath
from pisek.config.config_types import TaskType
from pisek.utils.text import pad, pad_left, tab
from pisek.utils.terminal import MSG_LEN, right_aligned_text
@@ -57,9 +57,9 @@ def _get_jobs(self) -> list[Job]:
self.is_primary: bool = self._env.config.solutions[self.solution_label].primary
self._solution = self._env.config.solutions[self.solution_label].run
- self._sols: dict[InputPath, RunSolution] = {}
- self._checkers: dict[InputPath, RunChecker] = {}
- self._static_out_checkers: dict[InputPath, RunChecker] = {}
+ self._sols: dict[IInputPath, RunSolution] = {}
+ self._checkers: dict[IInputPath, RunChecker] = {}
+ self._static_out_checkers: dict[IInputPath, RunChecker] = {}
for sub_num, inputs in self._all_testcases().items():
self.tests.append(TestJobGroup(self._env, sub_num))
@@ -209,7 +209,7 @@ def _create_batch_jobs(
return (run_solution, run_checker)
- def _create_interactive_jobs(self, inp: InputPath, test: int) -> RunInteractive:
+ def _create_interactive_jobs(self, inp: IInputPath, test: int) -> RunInteractive:
"""Create RunInteractive job for interactive task type."""
if self._env.config.tests.out_judge is None:
raise RuntimeError("Unset judge for interactive.")
diff --git a/pisek/task_jobs/task_manager.py b/pisek/task_jobs/task_manager.py
index 62bb483e..9a8e2997 100644
--- a/pisek/task_jobs/task_manager.py
+++ b/pisek/task_jobs/task_manager.py
@@ -10,7 +10,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
-from pisek.utils.paths import InputPath, OutputPath
+from pisek.utils.paths import IInputPath, IOutputPath
from pisek.config.task_config import TestSection
from pisek.jobs.status import StatusJobManager
from pisek.task_jobs.task_job import TaskHelper
@@ -29,7 +29,7 @@
class TaskJobManager(StatusJobManager, TaskHelper):
"""JobManager class that implements useful methods"""
- def _get_samples(self) -> list[tuple[InputPath, OutputPath]]:
+ def _get_samples(self) -> list[tuple[IInputPath, IOutputPath]]:
"""Returns the list [(sample1.in, sample1.out), …]."""
return [
(
diff --git a/pisek/task_jobs/tools.py b/pisek/task_jobs/tools.py
index 063356d4..47244ea9 100644
--- a/pisek/task_jobs/tools.py
+++ b/pisek/task_jobs/tools.py
@@ -23,7 +23,7 @@
from pisek.jobs.jobs import Job, PipelineItemFailure
from pisek.config.config_types import DataFormat
from pisek.env.env import Env
-from pisek.utils.paths import TaskPath, RawPath, SanitizedPath
+from pisek.utils.paths import TaskPath, IRawPath, ISanitizedPath
from pisek.task_jobs.task_job import TaskJob
from pisek.task_jobs.task_manager import TaskJobManager
from pisek.task_jobs.program import ProgramsJob
@@ -174,7 +174,7 @@ class TextPreprocAbstract(ProgramsJob):
"""Abstract job that has method for file sanitization."""
def _run_text_preproc(
- self, input_: RawPath, output: SanitizedPath
+ self, input_: IRawPath, output: ISanitizedPath
) -> SanitizationResult:
try:
os.remove(output.path)
@@ -222,7 +222,7 @@ class Sanitize(SanitizeAbstract, TextPreprocAbstract):
"""Sanitize text file using Text Preprocessor."""
def __init__(
- self, env: Env, input_: RawPath, output: SanitizedPath, **kwargs
+ self, env: Env, input_: IRawPath, output: ISanitizedPath, **kwargs
) -> None:
super().__init__(
env, input_, output, name=f"Sanitize {input_:p} -> {output:p}", **kwargs
@@ -236,7 +236,7 @@ class IsClean(SanitizeAbstract, TextPreprocAbstract):
"""Check that file is same after sanitizing with Text Preprocessor."""
def __init__(
- self, env: Env, input_: RawPath, output: SanitizedPath, **kwargs
+ self, env: Env, input_: IRawPath, output: ISanitizedPath, **kwargs
) -> None:
super().__init__(
env, input_, output, name=f"Check {input_:p} is clean", **kwargs
@@ -257,14 +257,14 @@ def _sanitize_get_format(env: Env, is_input: bool) -> DataFormat:
return env.config.tests.out_format
-def sanitize_job(env: Env, path: SanitizedPath, is_input: bool) -> Job | None:
+def sanitize_job(env: Env, path: ISanitizedPath, is_input: bool) -> Job | None:
return sanitize_job_direct(
env, path.to_raw(_sanitize_get_format(env, is_input)), path, is_input
)
def sanitize_job_direct(
- env: Env, path_from: RawPath, path_to: SanitizedPath, is_input: bool
+ env: Env, path_from: IRawPath, path_to: ISanitizedPath, is_input: bool
) -> Job | None:
format_ = _sanitize_get_format(env, is_input)
diff --git a/pisek/task_jobs/validator/validator_base.py b/pisek/task_jobs/validator/validator_base.py
index 461bd7a4..434af89c 100644
--- a/pisek/task_jobs/validator/validator_base.py
+++ b/pisek/task_jobs/validator/validator_base.py
@@ -13,7 +13,7 @@
from abc import abstractmethod
from pisek.env.env import Env
-from pisek.utils.paths import InputPath
+from pisek.utils.paths import IInputPath
from pisek.config.task_config import ProgramRole, RunSection
from pisek.task_jobs.run_result import RunResult
from pisek.task_jobs.program import ProgramsJob
@@ -26,7 +26,7 @@ def __init__(
self,
env: Env,
validator: RunSection,
- input_: InputPath,
+ input_: IInputPath,
test: int,
**kwargs,
):
diff --git a/pisek/utils/paths.py b/pisek/utils/paths.py
index 8226a2fd..c94b922d 100644
--- a/pisek/utils/paths.py
+++ b/pisek/utils/paths.py
@@ -14,6 +14,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
+from abc import ABC, abstractmethod
from dataclasses import dataclass
import os
from typing import TYPE_CHECKING
@@ -115,19 +116,75 @@ def generated_path(*path: str) -> "TaskPath":
return TaskPath.data_path(GENERATED_SUBDIR, *path)
-class JudgeablePath(TaskPath):
+# ----- interfaces -----
+
+
+class IJudgeablePath(TaskPath, ABC):
+ @abstractmethod
+ def to_checker_log(self, judge: str) -> "LogPath":
+ pass
+
+
+class ISanitizedPath(TaskPath, ABC):
+ @abstractmethod
+ def to_raw(self, format: DataFormat) -> "IRawPath":
+ pass
+
+
+class IInputPath(ISanitizedPath):
+ @abstractmethod
+ def to_second(self) -> "IInputPath":
+ pass
+
+ @abstractmethod
+ def to_output(self) -> "IOutputPath":
+ pass
+
+ @abstractmethod
+ def to_log(self, program: str) -> "LogPath":
+ pass
+
+
+class IOutputPath(IJudgeablePath, ISanitizedPath):
+ @abstractmethod
+ def to_reference_output(self) -> "IOutputPath":
+ pass
+
+ @abstractmethod
+ def to_fuzzing(self, seed: int) -> "IOutputPath":
+ pass
+
+
+class IRawPath(TaskPath, ABC):
+ @abstractmethod
+ def to_sanitized_input(self) -> IInputPath:
+ pass
+
+ @abstractmethod
+ def to_sanitized_output(self) -> IOutputPath:
+ pass
+
+ @abstractmethod
+ def to_sanitization_log(self) -> "LogPath":
+ pass
+
+
+# ----- paths inside task -----
+
+
+class JudgeablePath(IJudgeablePath):
def to_checker_log(self, judge: str) -> "LogPath":
return LogPath(self.replace_suffix(f".{os.path.basename(judge)}.log").path)
-class SanitizedPath(TaskPath):
+class SanitizedPath(ISanitizedPath):
def to_raw(self, format: DataFormat) -> "RawPath":
if format == DataFormat.binary:
return RawPath(self.path)
return RawPath(self.path + ".raw")
-class InputPath(SanitizedPath):
+class InputPath(SanitizedPath, IInputPath):
@staticmethod
def new(*path: str, solution: str | None = None) -> "InputPath":
if solution is None:
@@ -135,25 +192,25 @@ def new(*path: str, solution: str | None = None) -> "InputPath":
else:
return InputPath(TESTS_DIR, solution, *path)
- def to_second(self) -> "InputPath":
+ def to_second(self) -> IInputPath:
return InputPath(self.replace_suffix(".in2").path)
- def to_output(self) -> "OutputPath":
+ def to_output(self) -> IOutputPath:
return OutputPath(self.replace_suffix(f".out").path)
def to_log(self, program: str) -> "LogPath":
return LogPath(self.replace_suffix(f".{os.path.basename(program)}.log").path)
-class OutputPath(JudgeablePath, SanitizedPath):
+class OutputPath(JudgeablePath, SanitizedPath, IOutputPath):
@staticmethod
def static(*path) -> "OutputPath":
return OutputPath(TESTS_DIR, INPUTS_SUBDIR, *path)
- def to_reference_output(self) -> "OutputPath":
+ def to_reference_output(self) -> IOutputPath:
return OutputPath(self.replace_suffix(f".ok").path)
- def to_fuzzing(self, seed: int) -> "OutputPath":
+ def to_fuzzing(self, seed: int) -> IOutputPath:
return OutputPath(
TESTS_DIR,
FUZZING_OUTPUTS_SUBDIR,
@@ -167,34 +224,46 @@ def generator_log(generator: str) -> "LogPath":
return LogPath(TESTS_DIR, INPUTS_SUBDIR, f"{os.path.basename(generator)}.log")
-class RawPath(TaskPath):
- def to_sanitized_output(self) -> OutputPath:
- return OutputPath(self.path.removesuffix(".raw"))
-
- def to_sanitized_input(self) -> InputPath:
+class RawPath(IRawPath):
+ def to_sanitized_input(self) -> IInputPath:
return InputPath(self.path.removesuffix(".raw"))
+ def to_sanitized_output(self) -> IOutputPath:
+ return OutputPath(self.path.removesuffix(".raw"))
+
def to_sanitization_log(self) -> LogPath:
return LogPath(self.replace_suffix(".sanitizer.log").path)
-class OpendataPath(TaskPath):
+# ----- opendata paths = paths outside task -----
+
+
+class OpendatadPath(TaskPath):
def __init__(self, tmp_dir: str, *path: str):
self._tmp_dir = tmp_dir
super().__init__(*path)
- def to_raw(self, format: DataFormat) -> "RawPath":
+
+class OpendataJudgeablePath(OpendatadPath, IJudgeablePath):
+ def to_checker_log(self, judge: str) -> "LogPath":
+ return LogPath(
+ self._tmp_dir, self.replace_suffix(f".{os.path.basename(judge)}.log").name
+ )
+
+
+class OpendataSanitizedPath(OpendatadPath, ISanitizedPath):
+ def to_raw(self, format: DataFormat) -> IRawPath:
if format == DataFormat.binary:
return OpendataRawPath(self._tmp_dir, self.path)
return RawPath(self._tmp_dir, self.name + ".raw")
-class OpendataInputPath(OpendataPath, InputPath):
- def to_second(self) -> "InputPath":
- assert False
+class OpendataInputPath(OpendataSanitizedPath, IInputPath):
+ def to_second(self) -> IInputPath:
+ return InputPath(self._tmp_dir, self.replace_suffix(".in2").name)
- def to_output(self) -> "OutputPath":
- assert False
+ def to_output(self) -> IOutputPath:
+ return OutputPath(self._tmp_dir, self.replace_suffix(f".out").name)
def to_log(self, program: str) -> "LogPath":
return LogPath(
@@ -202,20 +271,23 @@ def to_log(self, program: str) -> "LogPath":
)
-class OpendataOutputPath(OpendataPath, OutputPath):
- def to_reference_output(self) -> "OutputPath":
- assert False
+class OpendataOutputPath(OpendataSanitizedPath, OpendataJudgeablePath, IOutputPath):
+ def to_reference_output(self) -> IOutputPath:
+ return OutputPath(self._tmp_dir, self.replace_suffix(f".ok").name)
+
+ def to_fuzzing(self, seed: int) -> IOutputPath:
+ return OutputPath(
+ self._tmp_dir,
+ self.replace_suffix(f".{seed:x}.out").name,
+ )
- def to_fuzzing(self, seed: int) -> "OutputPath":
- assert False
+class OpendataRawPath(OpendataSanitizedPath, IRawPath):
+ def to_sanitized_input(self) -> IInputPath:
+ return InputPath(self._tmp_dir, self.name.removesuffix(".raw"))
-class OpendataRawPath(OpendataPath, RawPath):
- def to_sanitized_output(self) -> OutputPath:
+ def to_sanitized_output(self) -> IOutputPath:
return OutputPath(self._tmp_dir, self.name.removesuffix(".raw"))
- def to_sanitized_input(self) -> InputPath:
- assert False
-
- def to_sanitization_log(self):
+ def to_sanitization_log(self) -> LogPath:
return LogPath(self._tmp_dir, self.replace_suffix(".sanitizer.log").name)