Skip to content

Commit df4cda7

Browse files
turbomamclaude
andauthored
Address Copilot review on #460 (encoding, docstring, CURIE-parent DEF-FORM) (#481)
* lint: address Copilot review on #460 (encoding, docstring, CURIE-parent DEF-FORM) - check_definition_form now compares the genus only against LABEL-form parents; CURIE-form parents (governed by PARENT/HOUSE-STYLE) no longer trigger a spurious DEF-FORM mismatch. - baseline write_text/read_text use encoding='utf-8' for deterministic CI. - docstring corrected: the ratchet is '--baseline PATH --write-baseline'. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * lint: DEF-FORM 'not Aristotelian' message cites label-form parents only (Copilot #481) So a CURIE-only-parent row is not told 'genus must be the parent label <CURIE>', matching the genus check which already ignores CURIE parents. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
1 parent b0a8abc commit df4cda7

2 files changed

Lines changed: 17 additions & 7 deletions

File tree

metpo/scripts/metpo_proposal_lint.py

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
via CURIE form, and definitions whose genus disagrees with the asserted parent
2121
(DEF-FORM; the hierarchy/label/definition compatibility principle, #64/#377).
2222
23-
Baseline ratchet: ``--write-baseline PATH`` records the currently-accepted findings;
23+
Baseline ratchet: ``--baseline PATH --write-baseline`` records the currently-accepted findings;
2424
a later run with ``--baseline PATH`` fails only on findings BEYOND that floor, so a
2525
large existing-debt audit can gate new additions without first paying down the debt.
2626
Regenerate the baseline as debt is fixed -- the count can only go down.
@@ -303,6 +303,11 @@ def check_definition_form(rid, typ, definition, parent_cell, mode):
303303
return []
304304
sev = "ERROR" if mode == "submit" else "WARN"
305305
parents = [p.strip() for p in parent_cell.split("|") if p.strip()]
306+
# CURIE-form parents (e.g. METPO:1000000) are governed by PARENT/HOUSE-STYLE; the
307+
# genus is compared only against LABEL-form parents (the sheet convention), so a
308+
# CURIE parent never triggers a spurious DEF-FORM mismatch and is not cited as the
309+
# expected genus.
310+
label_parents = [p for p in parents if not re.match(r"^[A-Za-z][\w.]*:\S", p)]
306311
m = _DEF_GENUS_RE.match(definition)
307312
if not m:
308313
return [
@@ -311,7 +316,7 @@ def check_definition_form(rid, typ, definition, parent_cell, mode):
311316
"DEF-FORM",
312317
rid,
313318
"definition is not Aristotelian 'A <genus> that/in-which/... <differentia>' "
314-
f"(genus must be the parent label {parents or ['<none>']})",
319+
f"(genus must be the parent label {label_parents or ['<none>']})",
315320
)
316321
]
317322
genus = m.group(1).strip()
@@ -322,15 +327,15 @@ def check_definition_form(rid, typ, definition, parent_cell, mode):
322327
# still hierarchy/label/definition compatible.
323328
_heads = ("phenotype", "preference", "quality")
324329
genus_ok = any(
325-
glow == p.lower() or glow in {f"{p.lower()} {h}" for h in _heads} for p in parents
330+
glow == p.lower() or glow in {f"{p.lower()} {h}" for h in _heads} for p in label_parents
326331
)
327-
if parents and not genus_ok:
332+
if label_parents and not genus_ok:
328333
return [
329334
Finding(
330335
sev,
331336
"DEF-FORM",
332337
rid,
333-
f"definition genus '{genus}' does not match asserted parent(s) {parents} "
338+
f"definition genus '{genus}' does not match asserted parent(s) {label_parents} "
334339
"(hierarchy/label/definition must be compatible)",
335340
)
336341
]
@@ -537,13 +542,15 @@ def _fp(f):
537542
if write_baseline:
538543
if not baseline:
539544
raise click.UsageError("--write-baseline requires --baseline PATH")
540-
Path(baseline).write_text(json.dumps(sorted({_fp(f) for f in findings}), indent=1) + "\n")
545+
Path(baseline).write_text(
546+
json.dumps(sorted({_fp(f) for f in findings}), indent=1) + "\n", encoding="utf-8"
547+
)
541548
click.echo(f"# wrote baseline: {baseline} ({len(findings)} findings recorded)")
542549
raise SystemExit(0)
543550

544551
baseline_set = set()
545552
if baseline and Path(baseline).exists():
546-
baseline_set = set(json.loads(Path(baseline).read_text()))
553+
baseline_set = set(json.loads(Path(baseline).read_text(encoding="utf-8")))
547554
new_findings = [f for f in findings if _fp(f) not in baseline_set]
548555
baselined = len(findings) - len(new_findings)
549556
# When a baseline is in play, only findings beyond it count toward pass/fail.

tests/test_metpo_proposal_lint.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ def test_cli_warn_only_exits_zero(tmp_path):
115115
"METPO:1007104\tin-which ok\towl:Class\ttrophic type\tA trophic type in which an organism fixes carbon.\tPMID:1\n"
116116
"METPO:1007105\tcharacterized ok\towl:Class\tcell shape\tA cell shape characterized by a rod morphology.\tPMID:1\n"
117117
"METPO:1007106\tparent phenotype genus\towl:Class\thalophilic\tA halophilic phenotype in which an organism requires high salt.\tPMID:1\n"
118+
"METPO:1007107\tcurie parent\towl:Class\tMETPO:9999999\tA phenotype that is observable.\tPMID:1\n"
118119
)
119120

120121

@@ -140,6 +141,8 @@ def test_def_form(tmp_path):
140141
# 'in which' / 'characterized by' are valid connectors when genus == parent
141142
assert "DEF-FORM" not in by_id.get("METPO:1007104", set())
142143
assert "DEF-FORM" not in by_id.get("METPO:1007105", set())
144+
# CURIE-form parent: genus comparison is skipped (PARENT/HOUSE-STYLE governs it)
145+
assert "DEF-FORM" not in by_id.get("METPO:1007107", set())
143146
# genus "<parent> phenotype" (adjectival parent) is accepted
144147
assert "DEF-FORM" not in by_id.get("METPO:1007106", set())
145148

0 commit comments

Comments
 (0)