diff --git a/everyvoice/tests/test_wizard.py b/everyvoice/tests/test_wizard.py index 2fe032ac..568ada7c 100644 --- a/everyvoice/tests/test_wizard.py +++ b/everyvoice/tests/test_wizard.py @@ -1881,11 +1881,28 @@ def test_control_c_save_progress(self): changed_version = tmpdir / "changed-version" with open(changed_version, "w", encoding="utf8") as f: f.write(progress_lines[0]) - f.write(progress_lines[1].replace("\n", "changed\n")) + incremented_version = progress_lines[1][:-2] + str( + int(progress_lines[1][-2:-1]) + 1 + ) + f.write(incremented_version + "\n") + f.write("".join(progress_lines[2:])) + tour = make_trivial_tour() + with patch_input("email@mail.com"), capture_stdout() as out: + tour.run(resume_from=changed_version) + self.assertRegex(out.getvalue(), r"(?s)expected.*to.*be.*compatible") + self.assertRegex(out.getvalue(), r"(?s)Proceeding.*anyway") + self.assertIn("Applying saved response", out.getvalue()) + self.assertEqual(tour.state, self.trivial_tour_results) + + # resume from a potentially incompatible older version + with open(changed_version, "w", encoding="utf8") as f: + f.write(progress_lines[0]) + f.write(" - 0.1.2\n") f.write("".join(progress_lines[2:])) tour = make_trivial_tour() with patch_input("email@mail.com"), capture_stdout() as out: tour.run(resume_from=changed_version) + self.assertRegex(out.getvalue(), r"(?s)not.*fully.*compatible") self.assertRegex(out.getvalue(), r"(?s)Proceeding.*anyway") self.assertIn("Applying saved response", out.getvalue()) self.assertEqual(tour.state, self.trivial_tour_results) diff --git a/everyvoice/wizard/tour.py b/everyvoice/wizard/tour.py index 8f40d4f0..3042e2ce 100644 --- a/everyvoice/wizard/tour.py +++ b/everyvoice/wizard/tour.py @@ -6,6 +6,7 @@ import questionary import yaml from anytree import PreOrderIter, RenderTree +from packaging.version import Version from rich import print as rich_print from rich.panel import Panel @@ -305,12 +306,27 @@ def resume(self, resume_from: Path) -> Optional[Step]: q_and_a_iter = iter(q_and_a_list) software, version = next(q_and_a_iter) + # When we introduce breaking changes to the wizard question sequence, code + # is to be added here to automatically fix resume-from files, adding defaults + # for new questions if possible, or else giving a warning explaining what needs + # to be changed if auto upgrade is not possible. + # Regression testing should warn us when such auto-upgrade code is required here. + compatible_since = Version("0.2.0a0") if software != "EveryVoice Wizard" or version != VERSION: - rich_print( - f"[yellow]Warning: saved progress file is for {software} version '{version}', " - f"but this is version '{VERSION}'. Proceeding anyway, but be aware that " - "the saved responses may not be compatible.[/yellow]" - ) + if Version(version) >= compatible_since: + rich_print( + f"[yellow]Warning: saved progress file is for {software} version '{version}', " + f"but this is version '{VERSION}', which is expected to be compatible. " + "Proceeding anyway, but be aware that some things may have changed " + "between versions.[/yellow]" + ) + else: + rich_print( + f"[yellow]Warning: saved progress file is for {software} version '{version}', " + f"but this is version '{VERSION}', which is not fully compatible. " + "Proceeding anyway, but be aware that some saved responses may no " + "longer be compatible.[/yellow]" + ) q_and_a = next(q_and_a_iter, None) node = self.root while node is not None and q_and_a is not None: diff --git a/pyproject.toml b/pyproject.toml index 1bd2cb95..77dbd364 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -57,6 +57,7 @@ dependencies = [ "merge-args", "nltk==3.9.1", "numpy<2", # torch < 2.4.1 requires numpy < 2 but fails to declare it + "packaging>=20.9", "pandas~=2.0", "panphon==0.20.0", "protobuf~=4.25", # https://github.com/EveryVoiceTTS/EveryVoice/issues/387