filesystem: JsonEditor: offer interactive retry on error

When json.loads() fails (e.g. the user made a syntax mistake), prompt
the user with "Re-open file for editing? [y]es/[n]o:" and loop back to
the editor if they answer 'y' or 'yes'.  If the user declines, return
the original unmodified value so no write is attempted; the temp file
is still cleaned up by __exit__() in that case.

Change-Id: I9161b7becea0d8dfd3f5f740fbb253da2f061a1d
Related: OS#6899
This commit is contained in:
Vadim Yanitskiy
2026-04-07 22:01:19 +07:00
parent 5828c92c66
commit 45220e00d5

View File

@@ -609,16 +609,24 @@ class JsonEditor:
def __enter__(self) -> object: def __enter__(self) -> object:
"""Write JSON + examples to a temp file, run the editor, return parsed result. """Write JSON + examples to a temp file, run the editor, return parsed result.
The temp file is kept on JSONDecodeError so the user can correct and On JSONDecodeError the user is offered the option to re-open the file
re-open it manually. It is removed by __exit__() on success.""" and fix the mistake interactively. The temp file is removed by __exit__()
on success, or when the user declines to retry."""
self._file = tempfile.NamedTemporaryFile(prefix='pysim_', suffix='.json', self._file = tempfile.NamedTemporaryFile(prefix='pysim_', suffix='.json',
mode='w', delete=False) mode='w', delete=False)
json.dump(self._orig_json, self._file, indent=4, cls=JsonEncoder) json.dump(self._orig_json, self._file, indent=4, cls=JsonEncoder)
self._append_examples_as_comments(self._file) self._append_examples_as_comments(self._file)
self._file.close() self._file.close()
self._cmd.run_editor(self._file.name) while True:
with open(self._file.name, 'r') as text_file: self._cmd.run_editor(self._file.name)
return json.loads(self._strip_comments(text_file.read())) try:
with open(self._file.name, 'r') as f:
return json.loads(self._strip_comments(f.read()))
except json.JSONDecodeError as e:
self._cmd.perror(f'Invalid JSON: {e}')
answer = self._cmd.read_input('Re-open file for editing? [y]es/[n]o: ')
if answer not in ('y', 'yes'):
return self._orig_json
def __exit__(self, *args): def __exit__(self, *args):
os.unlink(self._file.name) os.unlink(self._file.name)