Restructuration de l'application
This commit is contained in:
+50
-27
@@ -1,6 +1,6 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import importlib.util
|
||||
import importlib
|
||||
import io
|
||||
import json
|
||||
import os
|
||||
@@ -31,6 +31,7 @@ from copienator import (
|
||||
from copienator.annotation_actions import apply_checkbox_actions, apply_score_overrides
|
||||
from copienator.annotation_data import AnnotationLoadResult, load_annotation_data
|
||||
from copienator.filesystem import staged_directory, staged_files
|
||||
from copienator.dispatcher import COMMANDS, main as dispatcher_main
|
||||
from copienator_gui.app import (
|
||||
CopienatorApp,
|
||||
DEFAULT_HTTPS_PROXY,
|
||||
@@ -45,8 +46,8 @@ from copienator_gui.diagnostics import collect_diagnostics
|
||||
from copienator_gui.runner import ProcessRunner
|
||||
from copienator_gui.state import StateStore
|
||||
from copienator_gui.workflow import build_command, build_workflow, evaluation_argument
|
||||
from copies_tools import rename_all, rotate_all
|
||||
from platform_utils import (
|
||||
from copienator.commands.copies_tools import rename_all, rotate_all
|
||||
from copienator.platform import (
|
||||
WindowsLabelError,
|
||||
replace_with_link_or_copy,
|
||||
safe_filename,
|
||||
@@ -57,18 +58,16 @@ from platform_utils import (
|
||||
REPOSITORY = Path(__file__).resolve().parents[1]
|
||||
|
||||
|
||||
def load_script_module(filename: str, module_name: str):
|
||||
spec = importlib.util.spec_from_file_location(module_name, REPOSITORY / filename)
|
||||
if spec is None or spec.loader is None:
|
||||
raise RuntimeError(f"Could not load {filename}")
|
||||
module = importlib.util.module_from_spec(spec)
|
||||
sys.modules[module_name] = module
|
||||
try:
|
||||
spec.loader.exec_module(module)
|
||||
except Exception:
|
||||
sys.modules.pop(module_name, None)
|
||||
raise
|
||||
return module
|
||||
def load_script_module(filename: str, _module_name: str):
|
||||
stem = Path(filename).stem.replace("-", "_")
|
||||
if stem == "import":
|
||||
stem = "import_annotations"
|
||||
return importlib.import_module(f"copienator.commands.{stem}")
|
||||
|
||||
|
||||
def command_arguments(command: list[str]) -> list[str]:
|
||||
assert command[2:4] == ["-m", "copienator"]
|
||||
return command[5:]
|
||||
|
||||
|
||||
class WorkspaceTests(unittest.TestCase):
|
||||
@@ -129,6 +128,24 @@ class WorkspaceTests(unittest.TestCase):
|
||||
self.assertEqual(workspace.names_file(), root / "names")
|
||||
|
||||
|
||||
class DispatcherTests(unittest.TestCase):
|
||||
def test_unknown_command_has_argument_error_code(self) -> None:
|
||||
with redirect_stderr(io.StringIO()):
|
||||
self.assertEqual(dispatcher_main(["does-not-exist"]), 2)
|
||||
|
||||
def test_every_gui_python_command_is_registered(self) -> None:
|
||||
for step in build_workflow(True):
|
||||
for variant in step.variants:
|
||||
if variant.kind == "python":
|
||||
with self.subTest(step=step.id, command=variant.program):
|
||||
self.assertIn(variant.program, COMMANDS)
|
||||
|
||||
def test_root_contains_only_configuration_python_modules(self) -> None:
|
||||
root_modules = {path.name for path in REPOSITORY.glob("*.py")}
|
||||
self.assertIn("default_config.py", root_modules)
|
||||
self.assertLessEqual(root_modules, {"config.py", "default_config.py"})
|
||||
|
||||
|
||||
class AtomicJsonTests(unittest.TestCase):
|
||||
def test_atomic_binary_round_trip(self) -> None:
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
@@ -561,7 +578,9 @@ class StandardCliTests(unittest.TestCase):
|
||||
variant = next(item for item in step.variants if item.id == variant_id)
|
||||
command = build_command(REPOSITORY, step, variant, values, evaluation)
|
||||
with self.subTest(script=module_name):
|
||||
parsed = self.modules[module_name].build_parser().parse_args(command[3:])
|
||||
parsed = self.modules[module_name].build_parser().parse_args(
|
||||
command_arguments(command)
|
||||
)
|
||||
parsed_path = getattr(parsed, "evaluation", None) or parsed.target
|
||||
self.assertEqual(str(parsed_path), evaluation)
|
||||
|
||||
@@ -577,7 +596,7 @@ class StandardCliTests(unittest.TestCase):
|
||||
)
|
||||
with self.subTest(script=f"copies_tools:{step_id}"):
|
||||
parsed = self.modules["copies_tools"].build_parser().parse_args(
|
||||
command[3:]
|
||||
command_arguments(command)
|
||||
)
|
||||
self.assertEqual(parsed.operation, step_id)
|
||||
self.assertEqual(str(parsed.evaluation), evaluation)
|
||||
@@ -1521,7 +1540,7 @@ class WorkflowTests(unittest.TestCase):
|
||||
"default",
|
||||
{"target": self.evaluation, "annotation_dir": "Bnot"},
|
||||
)
|
||||
self.assertEqual(command[3:], [self.evaluation, "Bnot"])
|
||||
self.assertEqual(command_arguments(command), [self.evaluation, "Bnot"])
|
||||
|
||||
def test_copy_listing_prefers_processed_copies(self) -> None:
|
||||
with tempfile.TemporaryDirectory() as directory:
|
||||
@@ -1607,27 +1626,31 @@ class WorkflowTests(unittest.TestCase):
|
||||
"live",
|
||||
{"target": self.evaluation, "overwrite": True, "limit": "0"},
|
||||
)
|
||||
self.assertEqual(command[3:], [self.evaluation, "--overwrite", "--limit", "0"])
|
||||
self.assertIn("correction.py", command[2])
|
||||
self.assertEqual(
|
||||
command_arguments(command),
|
||||
[self.evaluation, "--overwrite", "--limit", "0"],
|
||||
)
|
||||
self.assertEqual(command[4], "correct")
|
||||
|
||||
def test_hybrid_correction_arguments(self) -> None:
|
||||
command = self.command(
|
||||
"correction", "hybrid", {"target": self.evaluation, "batch_from": "Ex 4"}
|
||||
)
|
||||
self.assertEqual(command[3:], [self.evaluation, "--batch-from", "Ex 4"])
|
||||
self.assertEqual(
|
||||
command_arguments(command), [self.evaluation, "--batch-from", "Ex 4"]
|
||||
)
|
||||
|
||||
def test_annotation_variants_are_exclusive_commands(self) -> None:
|
||||
command = self.command(
|
||||
"annotation", "grouped", {"target": self.evaluation, "overwrite": True}
|
||||
)
|
||||
self.assertIn("annotating_by_label.py", command[2])
|
||||
self.assertNotIn("annotating.py", command[2])
|
||||
self.assertEqual(command[4], "annotate-grouped")
|
||||
|
||||
def test_copy_preparation_commands_are_python(self) -> None:
|
||||
rotate = self.command("rotate", "rotate", {"target": self.evaluation})
|
||||
rename = self.command("rename", "rename", {"target": self.evaluation})
|
||||
self.assertEqual(rotate[2:], [str(REPOSITORY / "copies_tools.py"), "rotate", self.evaluation])
|
||||
self.assertEqual(rename[2:], [str(REPOSITORY / "copies_tools.py"), "rename", self.evaluation])
|
||||
self.assertEqual(rotate[2:], ["-m", "copienator", "copies", "rotate", self.evaluation])
|
||||
self.assertEqual(rename[2:], ["-m", "copienator", "copies", "rename", self.evaluation])
|
||||
|
||||
|
||||
class CrossPlatformFileTests(unittest.TestCase):
|
||||
@@ -1665,8 +1688,8 @@ class CrossPlatformFileTests(unittest.TestCase):
|
||||
source = root / "source.txt"
|
||||
destination = root / "destination.txt"
|
||||
source.write_text("content", encoding="utf-8")
|
||||
with patch("platform_utils.os.link", side_effect=OSError), patch(
|
||||
"platform_utils.os.symlink", side_effect=OSError
|
||||
with patch("copienator.platform.os.link", side_effect=OSError), patch(
|
||||
"copienator.platform.os.symlink", side_effect=OSError
|
||||
):
|
||||
method = replace_with_link_or_copy(source, destination)
|
||||
self.assertEqual(method, "copy")
|
||||
|
||||
Reference in New Issue
Block a user