Skip to content

Commit 0533e6d

Browse files
authored
fix(sanity): check REC006 only if either SampleAnnotation or ObjectAnn is not empty (#239)
* fix: remove REC006 Signed-off-by: ktro2828 <kotaro.uetake@tier4.jp> * Revert "fix: remove REC006" This reverts commit a9b763e. Signed-off-by: ktro2828 <kotaro.uetake@tier4.jp> * fix: update to run checking only if either sample_ann or object_ann is not empty Signed-off-by: ktro2828 <kotaro.uetake@tier4.jp> --------- Signed-off-by: ktro2828 <kotaro.uetake@tier4.jp>
1 parent 2f7c80c commit 0533e6d

3 files changed

Lines changed: 60 additions & 9 deletions

File tree

docs/schema/requirement.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,14 @@
1616

1717
## Schema Record (`REC`)
1818

19-
| ID | Name | Severity | Description |
20-
| -------- | ----------------------------- | -------- | --------------------------------------- |
21-
| `REC001` | `scene-single` | `ERROR` | `Scene` record is a single. |
22-
| `REC002` | `sample-not-empty` | `ERROR` | `Sample` record is not empty. |
23-
| `REC003` | `sample-data-not-empty` | `ERROR` | `SampleData` record is not empty. |
24-
| `REC004` | `ego-pose-not-empty` | `ERROR` | `EgoPose` record is not empty. |
25-
| `REC005` | `calibrated-sensor-non-empty` | `ERROR` | `CalibratedSensor` record is not empty. |
26-
| `REC006` | `instance-not-empty` | `ERROR` | `Instance` record is not empty. |
19+
| ID | Name | Severity | Description |
20+
| -------- | ----------------------------- | -------- | ---------------------------------------------------------------------------------------- |
21+
| `REC001` | `scene-single` | `ERROR` | `Scene` record is a single. |
22+
| `REC002` | `sample-not-empty` | `ERROR` | `Sample` record is not empty. |
23+
| `REC003` | `sample-data-not-empty` | `ERROR` | `SampleData` record is not empty. |
24+
| `REC004` | `ego-pose-not-empty` | `ERROR` | `EgoPose` record is not empty. |
25+
| `REC005` | `calibrated-sensor-non-empty` | `ERROR` | `CalibratedSensor` record is not empty. |
26+
| `REC006` | `instance-not-empty` | `ERROR` | `Instance` record is not empty if either 'SampleAnnotation' or 'ObjectAnn' is not empty. |
2727

2828
## Reference (`REF`)
2929

t4_devkit/sanity/record/rec006.py

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,20 @@
11
from __future__ import annotations
22

3+
from typing import TYPE_CHECKING
4+
5+
from returns.maybe import Maybe, Nothing, Some
6+
37
from t4_devkit.schema import SchemaName
48

59
from ..checker import RuleID, RuleName, Severity
610
from ..registry import CHECKERS
711
from ..result import Reason
12+
from ..safety import load_json_safe
813
from .base import RecordCountChecker
914

15+
if TYPE_CHECKING:
16+
from ..context import SanityContext
17+
1018
__all__ = ["REC006"]
1119

1220

@@ -17,9 +25,39 @@ class REC006(RecordCountChecker):
1725
id = RuleID("REC006")
1826
name = RuleName("instance-not-empty")
1927
severity = Severity.ERROR
20-
description = "'Instance' record is not empty."
28+
description = (
29+
"'Instance' record is not empty if either 'SampleAnnotation' or 'ObjectAnn' is not empty."
30+
)
2131
schema = SchemaName.INSTANCE
2232

33+
def can_skip(self, context: SanityContext) -> Maybe[Reason]:
34+
# return skip reason if instance.json does not exist
35+
match super().can_skip(context):
36+
case Some(x):
37+
return Maybe.from_value(x)
38+
39+
# instance.json should contain any records if either
40+
# SampleAnnotation or ObjectAnn records exist
41+
sample_ann_file = context.to_schema_file(SchemaName.SAMPLE_ANNOTATION)
42+
object_ann_file = context.to_schema_file(SchemaName.OBJECT_ANN)
43+
44+
match (sample_ann_file.value_or(None), object_ann_file.value_or(None)):
45+
case (None, _) | (_, None):
46+
return Maybe.from_value(Reason("Missing 'annotation' directory"))
47+
case (s, o):
48+
sample_ann_count = len(load_json_safe(s).unwrap()) if s.exists() else 0
49+
object_ann_count = len(load_json_safe(o).unwrap()) if o.exists() else 0
50+
return (
51+
Maybe.from_value(
52+
Reason(
53+
f"Both {SchemaName.SAMPLE_ANNOTATION} "
54+
f"and {SchemaName.OBJECT_ANN} records are empty"
55+
)
56+
)
57+
if sample_ann_count == 0 and object_ann_count == 0
58+
else Nothing
59+
)
60+
2361
def check_count(self, records: list[dict]) -> list[Reason] | None:
2462
num_instance = len(records)
2563
return [Reason("'Instance' record must not be empty")] if num_instance == 0 else None

tests/sanity/test_record_checkers.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
from t4_devkit.sanity.record.rec004 import REC004
1414
from t4_devkit.sanity.record.rec005 import REC005
1515
from t4_devkit.sanity.record.rec006 import REC006
16+
from t4_devkit.schema.name import SchemaName
1617

1718
# Base sample dataset root (contains all mandatory annotation json files with non-empty records)
1819
SAMPLE_ROOT = Path(__file__).parent.parent.joinpath("sample", "t4dataset")
@@ -155,6 +156,18 @@ def test_rec006_pass_instance_not_empty() -> None:
155156
assert report.reasons is None
156157

157158

159+
def test_rec006_skip_annotation_empty(tmp_path: Path) -> None:
160+
root = _make_mutated_dataset(tmp_path, {"sample_annotation.json": [], "object_ann.json": []})
161+
checker = REC006()
162+
report = checker(_context(root))
163+
assert report.is_passed(strict=True)
164+
assert (
165+
report.reasons
166+
and report.reasons[0]
167+
== f"Both {SchemaName.SAMPLE_ANNOTATION} and {SchemaName.OBJECT_ANN} records are empty"
168+
)
169+
170+
158171
def test_rec006_fail_instance_empty(tmp_path: Path) -> None:
159172
root = _make_mutated_dataset(tmp_path, {"instance.json": []})
160173
checker = REC006()

0 commit comments

Comments
 (0)