fix: log append reports an unreadable --body-file as ERROR, not a traceback (#145)
Files changed: - CHANGES.md - VERSION - tools/CONTRACT.md - tools/chemenu/commands/log_append.py - tools/chemenu/tests/test_log_append.py
This commit is contained in:
1 parent
685fc2e15e
commit
a70d904274
5 files changed
+83
-6
No files matched your search
+14
-1
@@ -59,7 +59,7 @@ concern - readable here, never shipped as something to parse.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 7.1.0-beta.23 - 2026-09-26 - network: property defined; sync, publish and upstream merge marked networked
|
## 7.1.0-beta.24 - 2026-09-26 - log append: unreadable --body-file is an ERROR line, not a traceback
|
||||||
|
|
||||||
**Author:** Torben Nehmer
|
**Author:** Torben Nehmer
|
||||||
|
|
||||||
@@ -92,6 +92,7 @@ concern - readable here, never shipped as something to parse.
|
|||||||
- Command records, Instance health group: one bullet per check, examples
|
- Command records, Instance health group: one bullet per check, examples
|
||||||
- Command records: NOTES is always a tuple of bullets; every record's examples are tested
|
- Command records: NOTES is always a tuple of bullets; every record's examples are tested
|
||||||
- network: property defined; sync, publish and upstream merge marked networked
|
- network: property defined; sync, publish and upstream merge marked networked
|
||||||
|
- log append: unreadable --body-file is an ERROR line, not a traceback
|
||||||
<!-- /wikitool:bumps -->
|
<!-- /wikitool:bumps -->
|
||||||
|
|
||||||
### CalDAV task-tracker provider (Nextcloud Tasks, iOS Reminders); review reports unknown-value findings instead of skipping them
|
### CalDAV task-tracker provider (Nextcloud Tasks, iOS Reminders); review reports unknown-value findings instead of skipping them
|
||||||
@@ -376,6 +377,18 @@ is gone from `version check`'s record, from two docstrings in `version_cmd.py`,
|
|||||||
CalDAV and Super Productivity providers do too. A test over the real registry pins the set of
|
CalDAV and Super Productivity providers do too. A test over the real registry pins the set of
|
||||||
`network: yes` commands, so a change to it is an edit to that test rather than silent drift.
|
`network: yes` commands, so a change to it is an edit to that test rather than silent drift.
|
||||||
|
|
||||||
|
### log append: unreadable --body-file is an ERROR line, not a traceback
|
||||||
|
|
||||||
|
`log append --body-file <pfad>` rief `Path.read_text()` ungeschützt auf; fehlte die Datei, war
|
||||||
|
sie ein Verzeichnis oder kein gültiges UTF-8, endete der Aufruf mit einem Python-Traceback statt
|
||||||
|
mit der `ERROR`-Zeile, die der Datensatz seit jeher versprach - Fall 4 des Tool error contract
|
||||||
|
(unerwarteter Fehler, nicht wiederholen) statt Fall 2 (Validierungsfehler, einmal korrigiert
|
||||||
|
wiederholen), obwohl der Datensatz Fall 2 dokumentierte. Das Lesen ist jetzt in
|
||||||
|
`try/except (OSError, UnicodeDecodeError)` gefasst und bricht über `fail()` ab, bevor
|
||||||
|
`kb/log.md` geöffnet wird; die Datei bleibt in jedem Fehlerfall byte-identisch zum Vorher. Der
|
||||||
|
Datensatz benennt die Ursache jetzt genauer ("missing, not a readable file, or not valid
|
||||||
|
UTF-8"). Gefunden beim Datensatz-Durchgang für #142/#143 (Gitea #145).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 7.0.0 - 2026-09-22 - Task-Tracker-Anbindung: Vorhaben als Seitenart, Verpflichtungsschicht, Weekly Review als Read-Time-Join
|
## 7.0.0 - 2026-09-22 - Task-Tracker-Anbindung: Vorhaben als Seitenart, Verpflichtungsschicht, Weekly Review als Read-Time-Join
|
||||||
|
|||||||
+2
-2
@@ -999,12 +999,12 @@ Append a formatted entry to `kb/log.md`.
|
|||||||
|
|
||||||
- 0 success
|
- 0 success
|
||||||
- 1 `--op` is not one of ingest, query, lint, create, update, delete, rename, move
|
- 1 `--op` is not one of ingest, query, lint, create, update, delete, rename, move
|
||||||
- 1 `--body-file` cannot be read
|
- 1 `--body-file` is missing, not a readable file, or not valid UTF-8
|
||||||
|
|
||||||
**ON FAILURE**
|
**ON FAILURE**
|
||||||
|
|
||||||
- `--op` is not one of ingest, query, lint, create, update, delete, rename, move -> Nothing was written - fix the argument and retry once
|
- `--op` is not one of ingest, query, lint, create, update, delete, rename, move -> Nothing was written - fix the argument and retry once
|
||||||
- `--body-file` cannot be read -> Nothing was written - fix the path and retry once
|
- `--body-file` is missing, not a readable file, or not valid UTF-8 -> Nothing was written - fix the path and retry once
|
||||||
|
|
||||||
**NEVER**
|
**NEVER**
|
||||||
|
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ def ingests_since_last_lint(entries: list[tuple[str, str, str]]) -> int:
|
|||||||
reaction="Nothing was written - fix the argument and retry once",
|
reaction="Nothing was written - fix the argument and retry once",
|
||||||
),
|
),
|
||||||
cli_contract.Failure(
|
cli_contract.Failure(
|
||||||
cause="`--body-file` cannot be read",
|
cause="`--body-file` is missing, not a readable file, or not valid UTF-8",
|
||||||
reaction="Nothing was written - fix the path and retry once",
|
reaction="Nothing was written - fix the path and retry once",
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -104,7 +104,10 @@ def log_append(
|
|||||||
fail(f"--op must be one of {VALID_OPS}")
|
fail(f"--op must be one of {VALID_OPS}")
|
||||||
text = body
|
text = body
|
||||||
if body_file:
|
if body_file:
|
||||||
text = body_file.read_text(encoding="utf-8")
|
try:
|
||||||
|
text = body_file.read_text(encoding="utf-8")
|
||||||
|
except (OSError, UnicodeDecodeError) as exc:
|
||||||
|
fail(f"Cannot read --body-file {body_file}: {exc}")
|
||||||
entry = format_log_entry(op, title, text)
|
entry = format_log_entry(op, title, text)
|
||||||
with config.LOG_FILE.open("a", encoding="utf-8") as f:
|
with config.LOG_FILE.open("a", encoding="utf-8") as f:
|
||||||
f.write("\n" + entry)
|
f.write("\n" + entry)
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
|
import pytest
|
||||||
|
import typer
|
||||||
|
|
||||||
from chemenu.commands.log_append import (
|
from chemenu.commands.log_append import (
|
||||||
format_log_entry,
|
format_log_entry,
|
||||||
ingests_since_last_lint,
|
ingests_since_last_lint,
|
||||||
|
log_append,
|
||||||
log_status,
|
log_status,
|
||||||
parse_log_entries,
|
parse_log_entries,
|
||||||
)
|
)
|
||||||
@@ -75,3 +79,60 @@ def test_log_status_warns_at_the_ten_ingest_threshold(tmp_path, monkeypatch, cap
|
|||||||
out = capsys.readouterr().out
|
out = capsys.readouterr().out
|
||||||
assert "Ingests since last lint: 10" in out
|
assert "Ingests since last lint: 10" in out
|
||||||
assert "Threshold reached" in out
|
assert "Threshold reached" in out
|
||||||
|
|
||||||
|
|
||||||
|
# --- log_append --body-file: unreadable is an ERROR line, never a traceback (Gitea #145) ---
|
||||||
|
|
||||||
|
|
||||||
|
def _make_missing(tmp_path):
|
||||||
|
return tmp_path / "nonexistent.md"
|
||||||
|
|
||||||
|
|
||||||
|
def _make_directory(tmp_path):
|
||||||
|
d = tmp_path / "a-directory"
|
||||||
|
d.mkdir()
|
||||||
|
return d
|
||||||
|
|
||||||
|
|
||||||
|
def _make_non_utf8(tmp_path):
|
||||||
|
p = tmp_path / "not-utf8.md"
|
||||||
|
p.write_bytes(b"\xff\xfe garbage")
|
||||||
|
return p
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"make_bad_file",
|
||||||
|
[_make_missing, _make_directory, _make_non_utf8],
|
||||||
|
ids=["missing", "directory", "non-utf8"],
|
||||||
|
)
|
||||||
|
def test_log_append_reports_an_unreadable_body_file_as_an_error(make_bad_file, tmp_path, monkeypatch, capsys):
|
||||||
|
import chemenu.config as config
|
||||||
|
|
||||||
|
log_file = tmp_path / "log.md"
|
||||||
|
before = "# Wiki Log\n"
|
||||||
|
log_file.write_text(before, encoding="utf-8")
|
||||||
|
monkeypatch.setattr(config, "LOG_FILE", log_file)
|
||||||
|
bad_file = make_bad_file(tmp_path)
|
||||||
|
|
||||||
|
with pytest.raises(typer.Exit) as exc:
|
||||||
|
log_append(op="ingest", title="raw/notes/a.md", body="", body_file=bad_file)
|
||||||
|
assert exc.value.exit_code == 1
|
||||||
|
|
||||||
|
out = capsys.readouterr().out
|
||||||
|
assert out.startswith("ERROR ")
|
||||||
|
assert str(bad_file) in out
|
||||||
|
assert log_file.read_text(encoding="utf-8") == before
|
||||||
|
|
||||||
|
|
||||||
|
def test_log_append_reads_the_body_from_body_file(tmp_path, monkeypatch):
|
||||||
|
import chemenu.config as config
|
||||||
|
|
||||||
|
log_file = tmp_path / "log.md"
|
||||||
|
log_file.write_text("# Wiki Log\n", encoding="utf-8")
|
||||||
|
monkeypatch.setattr(config, "LOG_FILE", log_file)
|
||||||
|
body_file = tmp_path / "body.md"
|
||||||
|
body_file.write_text("Created [[Docker]].", encoding="utf-8")
|
||||||
|
|
||||||
|
log_append(op="ingest", title="raw/notes/a.md", body="", body_file=body_file)
|
||||||
|
|
||||||
|
assert "Created [[Docker]]." in log_file.read_text(encoding="utf-8")
|
||||||
Reference in new issue
Block a user