Support evaluation-local configuration and names overrides

This commit is contained in:
sebastien committed 2026-11-03 18:44:56 +01:00
1 parent 0bb6f7d97c
commit d4404e4c27
36 files changed
+409 -184

No files matched your search

+4 -4
View File
@@ -44,7 +44,7 @@ class AddFinalScoreTests(unittest.TestCase):
merged.write_bytes(b'merged')
output = root / 'output'
output.mkdir()
with patch.object(add_final_score, 'HISTOGRAM_PATH', histogram):
with patch.object(add_final_score.configuration, 'FINAL_SCORE_HISTOGRAM_PATH', histogram):
add_final_score.copy_histogram(output)
self.assertFalse((output / merged.name).exists())
add_final_score.copy_histogram(output, copy_merged_histogramme=True)
@@ -54,7 +54,7 @@ class AddFinalScoreTests(unittest.TestCase):
def test_cli_forwards_merged_histogram_option(self):
with tempfile.TemporaryDirectory() as temporary:
root = Path(temporary)
with patch.object(add_final_score, 'OUTPUT_DIR', root / 'output'), patch.object(
with patch.object(add_final_score.configuration, 'FINAL_SCORE_OUTPUT_DIR', root / 'output'), patch.object(
add_final_score, 'process_images'
) as process:
self.assertEqual(add_final_score.main([str(root), '--copy-merged-histogramme']), 0)
@@ -83,7 +83,7 @@ class AddFinalScoreTests(unittest.TestCase):
histogram = root / "histogramme.pdf"
histogram.write_bytes(b"histogram")
with patch.object(add_final_score.pd, "read_excel", return_value=scores), \
patch.object(add_final_score, "HISTOGRAM_PATH", histogram), \
patch.object(add_final_score.configuration, "FINAL_SCORE_HISTOGRAM_PATH", histogram), \
contextlib.redirect_stdout(io.StringIO()):
add_final_score.process_images(root, output)
@@ -137,7 +137,7 @@ class AddFinalScoreTests(unittest.TestCase):
with patch.object(
add_final_score.pd, "read_excel", return_value=scores
), patch.object(
add_final_score, "HISTOGRAM_PATH", root / "missing.pdf"
add_final_score.configuration, "FINAL_SCORE_HISTOGRAM_PATH", root / "missing.pdf"
), contextlib.redirect_stdout(messages):
add_final_score.process_images(root, output)
+1 -1
View File
@@ -16,7 +16,7 @@ class AnnotationHeightConfigTests(unittest.TestCase):
[sys.executable, "-c",
"from copienator.commands import annotating_by_label as grouped; "
"from copienator.commands import annotating_with_checks as checks; "
f"print(grouped.{attribute}, checks.{attribute})"],
f"print(grouped.annotation_limits()[{0 if attribute == 'MAX_HEIGHT_PX' else 1}], checks.annotation_limits()[{0 if attribute == 'MAX_HEIGHT_PX' else 1}])"],
cwd=Path(__file__).resolve().parents[1],
env={**os.environ, "COPIENATOR_CONFIG": str(config)},
capture_output=True, text=True, check=False,
+3 -3
View File
@@ -24,7 +24,7 @@ class AnnotationImportCleanupTests(unittest.TestCase):
(self.workspace.root / "correction.json").write_text("{}")
self.import_dir = self.root / "Annotées"
self.import_dir.mkdir()
self.patch = patch.object(import_annotations, "IMPORT_DIR", self.import_dir)
self.patch = patch.object(import_annotations.configuration, "IMPORT_DIR", self.import_dir)
self.patch.start()
self.addCleanup(self.patch.stop)
@@ -45,12 +45,12 @@ class AnnotationImportCleanupTests(unittest.TestCase):
def test_cleanup_handles_unconfigured_or_missing_folder(self):
for configured in (None, "", self.root / "absent"):
with self.subTest(configured=configured), \
patch.object(import_annotations, "IMPORT_DIR", configured):
patch.object(import_annotations.configuration, "IMPORT_DIR", configured):
import_annotations.clear_import_directory(self.workspace)
self.assertFalse((self.root / "absent").exists())
def test_cleanup_rejects_an_ancestor_of_evaluation(self):
with patch.object(import_annotations, "IMPORT_DIR", self.root), \
with patch.object(import_annotations.configuration, "IMPORT_DIR", self.root), \
self.assertRaises(CliError):
import_annotations.clear_import_directory(self.workspace)
self.assertTrue(self.workspace.root.is_dir())
+8 -7
View File
@@ -6,9 +6,10 @@ from unittest.mock import patch
from PIL import Image, ImageDraw
from copienator import configuration
from copienator import CliError, EvaluationWorkspace, ExitCode, read_json
from copienator.annotation_data import AnnotationLoadResult
from copienator.annotation_documents import MAX_HEIGHT_PX, copy_documents
from copienator.annotation_documents import annotation_limits, copy_documents
from copienator.commands import annotating_with_checks as checks
from copienator.commands import export, import_annotations, reading_annotations as reader
from copienator.commands import reading_grouped_annotations as grouped_reader
@@ -46,7 +47,7 @@ class CheckedDocumentTests(unittest.TestCase):
def generate(self, overwrite=False):
with (
patch.object(checks, 'MAX_HEIGHT_PX', 100),
patch.object(configuration, 'ANNOTATION_MAX_HEIGHT_PX', 100),
patch.object(checks.annotating, 'make_base_image', return_value=(None, 0, 0)),
patch.object(checks.annotating, 'compose_label_image', side_effect=self.compose),
):
@@ -54,7 +55,7 @@ class CheckedDocumentTests(unittest.TestCase):
overwrite=overwrite, output_mode='checks')
def test_splits_on_labels_and_resets_geometry_at_each_part(self):
self.assertEqual(MAX_HEIGHT_PX, 33000)
self.assertEqual(annotation_limits()[0], 33000)
self.assertEqual(self.generate(), 'success')
parts = copy_documents(self.output)
self.assertEqual([part.name for part in parts], ['Part1', 'Part2'])
@@ -76,7 +77,7 @@ class CheckedDocumentTests(unittest.TestCase):
self.assertFalse((self.output / 'Part1').exists())
def test_pixel_limit_splits_documents_at_exact_boundary(self):
with patch.object(checks, 'MAX_PIXELS', 6000):
with patch.object(configuration, 'ANNOTATION_MAX_PIXELS', 6000):
self.assertEqual(self.generate(), 'success')
parts = copy_documents(self.output)
self.assertEqual([read_json(p / 'bnote.json')['height'] for p in parts], [60, 40, 60])
@@ -88,13 +89,13 @@ class CheckedDocumentTests(unittest.TestCase):
if label == 'Ex 2':
image = image.resize((200, image.height))
return image, header
with patch.object(self, 'compose', side_effect=wider), patch.object(checks, 'MAX_PIXELS', 12000):
with patch.object(self, 'compose', side_effect=wider), patch.object(configuration, 'ANNOTATION_MAX_PIXELS', 12000):
self.assertEqual(self.generate(), 'success')
parts = copy_documents(self.output)
self.assertEqual([read_json(p / 'bnote.json')['width'] for p in parts], [100, 200, 100])
sentinel = self.output / 'sentinel'
sentinel.write_text('previous')
with patch.object(checks, 'MAX_PIXELS', 5999):
with patch.object(configuration, 'ANNOTATION_MAX_PIXELS', 5999):
with self.assertRaisesRegex(CliError, 'Copie01.*Ex 1'):
self.generate(overwrite=True)
self.assertEqual(sentinel.read_text(), 'previous')
@@ -121,7 +122,7 @@ class CheckedDocumentTests(unittest.TestCase):
def returned_parts(self):
self.generate()
export_root = self.root / 'Export'
with patch.object(export, 'EXPORT_DIR', export_root):
with patch.object(export.configuration, 'EXPORT_DIR', export_root):
self.assertEqual(export.run(self.workspace, annotation_dir='Bnot'), ExitCode.SUCCESS)
self.assertEqual(sorted(p.name for p in (export_root / 'Exam').iterdir()),
['Copie01 Part1.pdf', 'Copie01 Part2.pdf'])
+1 -1
View File
@@ -99,7 +99,7 @@ class GeminiConfigTests(unittest.TestCase):
]
config = types.GenerateContentConfig(thinking_config=thinking_config("high"))
with patch.object(correction, "client", client), patch.object(
correction, "MODEL_ID_pro", "pro-model"
configuration, "MODEL_PRO_ID", "pro-model"
), patch.object(correction, "pro_quota_exhausted", False), patch.object(
configuration, "THINKING_LEVEL_FLASH", "low"
), patch.object(correction, "tprint"), patch.object(correction, "stop_requested") as stop:
+2 -2
View File
@@ -88,7 +88,7 @@ class GroupedRedoTests(unittest.TestCase):
[("01", "Ex 1"), ("02", "Ex 1")],
)
export_root = Path(self.temp.name) / "Export"
with patch.object(export, "EXPORT_DIR", export_root):
with patch.object(export.configuration, "EXPORT_DIR", export_root):
self.assertEqual(export.run(self.workspace, refaire=True), ExitCode.SUCCESS)
self.assertEqual(len(list((export_root / "Exam").glob("*.pdf"))), 1)
imported_root = Path(self.temp.name) / "Import"
@@ -99,7 +99,7 @@ class GroupedRedoTests(unittest.TestCase):
draw.rectangle((17, 17, 43, 43), fill="black")
draw.rectangle((70, 170, 90, 190), fill="black")
annotated.save(imported_root / f"{directory.name}.pdf", "PDF", resolution=72)
with patch.object(import_annotations, "IMPORT_DIR", imported_root):
with patch.object(import_annotations.configuration, "IMPORT_DIR", imported_root):
self.assertEqual(
import_annotations.run(self.workspace, refaire=True), ExitCode.SUCCESS
)
+15 -14
View File
@@ -18,6 +18,7 @@ from unittest.mock import Mock, patch
from PIL import Image
from pypdf import PdfReader, PdfWriter
from copienator import configuration
from copienator import (
CliError,
EvaluationWorkspace,
@@ -531,7 +532,7 @@ class StandardCliTests(unittest.TestCase):
evaluation = base / "Exam"
evaluation.mkdir()
export_dir = base / "Export"
with patch.object(module, "EXPORT_DIR", export_dir), redirect_stderr(
with patch.object(module.configuration, "EXPORT_DIR", export_dir), redirect_stderr(
io.StringIO()
):
self.assertEqual(module.main([str(evaluation)]), 3)
@@ -706,7 +707,7 @@ class StandardCliTests(unittest.TestCase):
source = evaluation / "BGnot" / "Ex 1"
source.mkdir(parents=True)
(source / "Concat.pdf").write_bytes(b"annotated")
with patch.object(module, "EXPORT_DIR", base / "Export"):
with patch.object(module.configuration, "EXPORT_DIR", base / "Export"):
self.assertEqual(module.main([str(evaluation)]), 0)
exported = base / "Export" / "Exam" / "Ex 1.pdf"
self.assertEqual(exported.read_bytes(), b"annotated")
@@ -721,7 +722,7 @@ class StandardCliTests(unittest.TestCase):
source.mkdir(parents=True)
suffix = ".jpg" if annotation_dir == "Anot" else ".pdf"
(source / f"Concat{suffix}").write_bytes(annotation_dir.encode())
with patch.object(module, "EXPORT_DIR", base / "Export"):
with patch.object(module.configuration, "EXPORT_DIR", base / "Export"):
self.assertEqual(module.main([str(evaluation), annotation_dir]), 0)
self.assertEqual(
(base / "Export" / "Exam" / f"Copie01{suffix}").read_bytes(),
@@ -738,7 +739,7 @@ class StandardCliTests(unittest.TestCase):
import_dir = base / "Import"
import_dir.mkdir()
(import_dir / "Ex 1.pdf").write_bytes(b"handwritten")
with patch.object(module, "IMPORT_DIR", import_dir):
with patch.object(module.configuration, "IMPORT_DIR", import_dir):
self.assertEqual(module.main([str(evaluation)]), 0)
self.assertEqual(
(target / "Concat_annotated.pdf").read_bytes(), b"handwritten"
@@ -756,7 +757,7 @@ class StandardCliTests(unittest.TestCase):
import_dir.mkdir()
suffix = ".jpg" if annotation_dir == "Anot" else ".pdf"
(import_dir / f"Copie01{suffix}").write_bytes(b"handwritten")
with patch.object(module, "IMPORT_DIR", import_dir):
with patch.object(module.configuration, "IMPORT_DIR", import_dir):
self.assertEqual(module.main([str(evaluation), annotation_dir]), 0)
self.assertEqual(
(target / f"Concat_annotated{suffix}").read_bytes(), b"handwritten"
@@ -2323,7 +2324,7 @@ class StandardCliTests(unittest.TestCase):
("02", "Ex 1", small, 0, []),
("02", "Ex 2", small, 0, []),
]
with patch.object(module, "MAX_HEIGHT_PX", 100):
with patch.object(configuration, "ANNOTATION_MAX_HEIGHT_PX", 100):
batches = module.split_batches(rendered)
self.assertEqual([len(batch) for batch in batches], [1, 2])
self.assertTrue(
@@ -2338,14 +2339,14 @@ class StandardCliTests(unittest.TestCase):
("01", "Ex 2", image, 0, []),
("02", "Ex 1", image, 0, []),
]
with patch.object(module, "MAX_HEIGHT_PX", 100):
with patch.object(configuration, "ANNOTATION_MAX_HEIGHT_PX", 100):
batches = module.split_batches(rendered)
self.assertEqual(batches, [[rendered[0]], [rendered[1]], [rendered[2]]])
def test_grouped_oversized_answer_is_rejected(self) -> None:
module = self.modules["annotating_by_label"]
rendered = [("02", "Ex 1", Image.new("RGB", (10, 120)), 0, [])]
with tempfile.TemporaryDirectory() as directory, patch.object(module, "MAX_HEIGHT_PX", 100):
with tempfile.TemporaryDirectory() as directory, patch.object(configuration, "ANNOTATION_MAX_HEIGHT_PX", 100):
with self.assertRaisesRegex(CliError, "Copie02.*Ex 1"):
module.split_batches(rendered)
with self.assertRaises(CliError):
@@ -2359,7 +2360,7 @@ class StandardCliTests(unittest.TestCase):
("02", "Ex 1", Image.new("RGB", (30, 20)), 0, []),
("03", "Ex 1", Image.new("RGB", (10, 40)), 0, []),
]
with patch.object(module, "MAX_HEIGHT_PX", 100), patch.object(module, "MAX_PIXELS", 2000):
with patch.object(configuration, "ANNOTATION_MAX_HEIGHT_PX", 100), patch.object(configuration, "ANNOTATION_MAX_PIXELS", 2000):
batches = module.split_batches(rendered)
self.assertEqual(batches, [[rendered[0], rendered[2]], [rendered[1]]])
with tempfile.TemporaryDirectory() as directory:
@@ -2372,9 +2373,9 @@ class StandardCliTests(unittest.TestCase):
module = self.modules["annotating_by_label"]
image = Image.new("RGB", (30, 40))
rendered = [("01", label, image, 0, []) for label in ("Ex 1", "Ex 2")]
with patch.object(module, "MAX_HEIGHT_PX", 100), patch.object(module, "MAX_PIXELS", 1200):
with patch.object(configuration, "ANNOTATION_MAX_HEIGHT_PX", 100), patch.object(configuration, "ANNOTATION_MAX_PIXELS", 1200):
self.assertEqual(module.split_batches(rendered), [[rendered[0]], [rendered[1]]])
with patch.object(module, "MAX_PIXELS", 1199):
with patch.object(configuration, "ANNOTATION_MAX_PIXELS", 1199):
with self.assertRaisesRegex(CliError, "single answer cannot be split"):
module.split_batches(rendered)
@@ -2387,7 +2388,7 @@ class StandardCliTests(unittest.TestCase):
("04", "Ex 1", Image.new("RGB", (10, 15)), 0, []),
("04", "Ex 2", Image.new("RGB", (10, 15)), 0, []),
]
with patch.object(module, "MAX_HEIGHT_PX", 100):
with patch.object(configuration, "ANNOTATION_MAX_HEIGHT_PX", 100):
batches = module.split_batches(rendered)
self.assertEqual([[item[0] for item in batch] for batch in batches],
[["01", "04", "04"], ["02", "03"]])
@@ -2397,7 +2398,7 @@ class StandardCliTests(unittest.TestCase):
def test_grouped_annotation_height_limit_is_33000_pixels(self) -> None:
module = self.modules["annotating_by_label"]
self.assertEqual(module.MAX_HEIGHT_PX, 33000)
self.assertEqual(module.annotation_limits()[0], 33000)
class WorkflowTests(unittest.TestCase):
@@ -2511,7 +2512,7 @@ class WorkflowTests(unittest.TestCase):
def test_crop_auto_start_follows_always_crop_configuration(self) -> None:
for enabled in (False, True):
with self.subTest(enabled=enabled), patch(
"copienator_gui.workflow.ALWAYS_CROP", enabled
"copienator_gui.workflow.configuration.ALWAYS_CROP", enabled
):
steps = {step.id: step for step in build_workflow(False)}
self.assertEqual(
+151
View File
@@ -0,0 +1,151 @@
"""Evaluation files override shared settings without leaking across evaluations."""
import contextlib
import os
from pathlib import Path
import subprocess
import sys
import tempfile
import unittest
from copienator import EvaluationWorkspace
REPOSITORY = Path(__file__).resolve().parents[1]
class LocalConfigurationTests(unittest.TestCase):
def setUp(self):
self.temporary = tempfile.TemporaryDirectory()
self.addCleanup(self.temporary.cleanup)
self.root = Path(self.temporary.name)
self.evaluation = self.root / "Exam"
self.evaluation.mkdir()
(self.evaluation / "labels").write_text("Ex 1\n")
self.global_config = self.root / "config.py"
self.global_config.write_text("MODEL_FLASH_ID = 'global-model'\nRETURN_PDF_ENABLED = False\n")
def run_python(self, source, *, explicit=True):
env = dict(os.environ, PYTHONPATH=str(REPOSITORY))
env.pop("COPIENATOR_CONFIG", None)
if explicit:
env["COPIENATOR_CONFIG"] = str(self.global_config)
result = subprocess.run([sys.executable, "-c", source], cwd=self.root, env=env,
capture_output=True, text=True)
self.assertEqual(result.returncode, 0, result.stdout + result.stderr)
return result.stdout
def test_partial_local_config_inherits_global_and_defaults(self):
(self.evaluation / "config.py").write_text("MODEL_FLASH_ID = 'local-model'\n")
for explicit in (False, True):
with self.subTest(explicit=explicit):
self.run_python("""
from copienator import configuration as c
c.use_evaluation('Exam')
assert c.MODEL_FLASH_ID == 'local-model'
assert c.RETURN_PDF_ENABLED is False
assert c.RETURN_JPEG_ENABLED is True
assert c.CONFIG_PATH.name == 'config.py'
assert c.LOCAL_CONFIG_PATH.parent.name == 'Exam'
c.use_evaluation(None)
assert c.MODEL_FLASH_ID == 'global-model'
""", explicit=explicit)
def test_switching_evaluations_removes_previous_overrides(self):
(self.evaluation / "config.py").write_text("RETURN_JPEG_ENABLED = False\n")
(self.root / "Other").mkdir()
self.run_python("""
from copienator import configuration as c
c.use_evaluation('Exam')
assert c.RETURN_JPEG_ENABLED is False
c.use_evaluation('Other')
assert c.RETURN_JPEG_ENABLED is True
assert c.RETURN_PDF_ENABLED is False
assert c.LOCAL_CONFIG_PATH is None
""")
def test_command_loads_config_for_directory_and_nested_target(self):
(self.evaluation / "config.py").write_text("MODEL_FLASH_ID = 'local-model'\n")
self.run_python("""
from copienator import configuration as c
from copienator.cli import execute, evaluation_parser, target_parser
from copienator.commands import correction
def check(args):
assert correction.settings.MODEL_FLASH_ID == 'local-model'
return 0
assert execute(evaluation_parser('test'), ['Exam'], check) == 0
c.use_evaluation(None)
assert execute(target_parser('test'), ['Exam/labels'], check) == 0
""")
def test_annotation_limits_and_gui_defaults_follow_active_config(self):
(self.evaluation / "config.py").write_text(
"ANNOTATION_MAX_HEIGHT_PX = 12345\nALWAYS_CROP = True\n")
self.run_python("""
from copienator import configuration as c
from copienator.commands import annotating_by_label, annotating_with_checks
from copienator_gui.workflow import build_workflow
c.use_evaluation('Exam')
assert annotating_by_label.annotation_limits()[0] == 12345
assert annotating_with_checks.annotation_limits()[0] == 12345
steps = {step.id: step for step in build_workflow(False)}
assert steps['crop_blank_margins'].auto_start_first_visit
""")
@unittest.skipUnless(os.environ.get("DISPLAY"), "GUI display unavailable")
def test_gui_switches_evaluation_settings(self):
(self.evaluation / "config.py").write_text("ALWAYS_CROP = True\n")
(self.root / "Other").mkdir()
self.run_python("""
from pathlib import Path
from copienator import configuration as c
from copienator_gui.app import CopienatorApp
app = CopienatorApp(Path.cwd(), False, Path('Exam').resolve())
try:
assert app.step_by_id['crop_blank_margins'].auto_start_first_visit
app.evaluation_var.set(str(Path('Other').resolve()))
app._load_evaluation()
assert not app.step_by_id['crop_blank_margins'].auto_start_first_visit
assert c.LOCAL_CONFIG_PATH is None
finally:
app.destroy()
""")
def test_explicit_command_option_overrides_local_config(self):
(self.evaluation / "config.py").write_text("RETURN_ANSWERS_CONTEXT = True\n")
self.run_python("""
from unittest.mock import patch
from copienator.commands import reading_annotations as command
from copienator import configuration as c
def check(workspace, **options):
assert c.RETURN_ANSWERS_CONTEXT is True
assert options['return_answers_context'] is False
return 0
with patch.object(command, 'run', check):
assert command.main(['Exam', '--no-return-answers-context']) == 0
""")
def test_invalid_local_config_reports_error_before_handler(self):
(self.evaluation / "config.py").write_text("ANNOTATION_MAX_HEIGHT_PX = 0\n")
self.run_python("""
from unittest.mock import Mock
from copienator.cli import execute, evaluation_parser
handler = Mock()
assert execute(evaluation_parser('test'), ['Exam'], handler) == 1
handler.assert_not_called()
""")
def test_local_names_replace_global_including_an_empty_roster(self):
(self.root / "names").write_text("Global\n")
workspace = EvaluationWorkspace(self.evaluation, self.root)
self.assertEqual(workspace.names_file(), self.root / "names")
local = self.evaluation / "names"
local.write_text("Local\n")
self.assertEqual(workspace.names_file(), local)
local.write_text("")
self.assertEqual(workspace.names_file().read_text(), "")
with contextlib.chdir(self.root):
self.assertEqual(EvaluationWorkspace(self.evaluation).names_file(), local)
local.unlink()
self.assertEqual(EvaluationWorkspace(self.evaluation).names_file(), self.root / "names")
+1 -1
View File
@@ -116,7 +116,7 @@ class MarkedCopiesTests(unittest.TestCase):
def test_personal_crop_binding_follows_personal_workflow_option(self):
from copienator.configuration import SHOW_PERSONAL_STEPS
self.assertEqual(cutleft.personnal_binding, bool(SHOW_PERSONAL_STEPS))
self.assertEqual(cutleft.personal_bindings_enabled(), bool(SHOW_PERSONAL_STEPS))
def test_process_single_pdf_enlarges_crop_and_caps_it_at_page_edge(self):
page = Image.new("RGB", (900, 300), "white")
+1 -1
View File
@@ -153,7 +153,7 @@ class NameGridTests(unittest.TestCase):
self.assertEqual(len(requests), 4)
self.assertEqual(requests[0].kwargs['model'], 'custom-name-model')
self.assertEqual(requests[0].kwargs['config'].thinking_config.thinking_level.value, 'MEDIUM')
self.assertEqual(requests[1].kwargs['model'], labels.MODEL_ID)
self.assertEqual(requests[1].kwargs['model'], labels.config.MODEL_FOR_LABEL_ID)
for request in requests[1:3]:
text = request.kwargs['contents'][0].parts[1].text
self.assertNotIn('Alice', text)
+2 -1
View File
@@ -5,7 +5,8 @@ from unittest.mock import Mock
import pymupdf
from copienator.commands.page_splitter import PDFPreviewer, PAGE_SPLITTER_KB
from copienator.commands.page_splitter import PDFPreviewer
from copienator.configuration import PAGE_SPLITTER_KB
class ReversePagesTests(unittest.TestCase):
+2 -2
View File
@@ -120,7 +120,7 @@ class RefaireSessionTests(unittest.TestCase):
output = self.workspace.annotation_dir("refaire") / "Ex 1 G1"
output.mkdir(parents=True)
(output / "Concat.pdf").write_bytes(expected_id.encode())
with patch.object(export, "EXPORT_DIR", export_root):
with patch.object(export.configuration, "EXPORT_DIR", export_root):
self.assertEqual(
export.run(self.workspace, refaire=True), ExitCode.SUCCESS
)
@@ -131,7 +131,7 @@ class RefaireSessionTests(unittest.TestCase):
if expected_id == first:
(import_root / exported.name).write_bytes(b"old return")
current = self.workspace.annotation_dir("refaire") / "Ex 1 G1"
with patch.object(import_annotations, "IMPORT_DIR", import_root):
with patch.object(import_annotations.configuration, "IMPORT_DIR", import_root):
self.assertEqual(
import_annotations.run(self.workspace, refaire=True), ExitCode.PARTIAL
)
+1 -1
View File
@@ -325,7 +325,7 @@ class SelectiveGeminiTests(unittest.TestCase):
for label in self.labels:
(self.root / 'Persp' / label).write_text(label + '\nReviewed rubric')
before = self.snapshot()
with patch.object(gemini, 'api_key', ''), patch.object(gemini.genai, 'Client') as client:
with patch.object(gemini.config, 'API_KEY', ''), patch.object(gemini.genai, 'Client') as client:
self.assertEqual(gemini.refine_existing(self.workspace, 'persp'), ExitCode.SUCCESS)
client.assert_not_called()
self.assertEqual(self.snapshot(), before)