Skip to content

Commit 1844650

Browse files
committed
perf(validate): stream games in full validation
1 parent ccd9af1 commit 1844650

3 files changed

Lines changed: 29 additions & 13 deletions

File tree

app/validate.py

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -390,8 +390,7 @@ def validate() -> list[str]:
390390
cpus = _load("cpu")
391391
laptops = _load("laptop")
392392
monitors = _load("monitor")
393-
games = _load("game")
394-
software = _load("software")
393+
software = _load("software")
395394

396395
brand_slugs = {rec["slug"] for _, rec in brands if "slug" in rec}
397396
soc_slugs = {rec["slug"] for _, rec in socs if "slug" in rec}
@@ -409,8 +408,7 @@ def validate() -> list[str]:
409408
("cpu", cpus),
410409
("laptop", laptops),
411410
("monitor", monitors),
412-
("game", games),
413-
("software", software),
411+
("software", software),
414412
):
415413
_check_unique_slugs(category, records, errors)
416414

@@ -562,17 +560,17 @@ def validate() -> list[str]:
562560
errors.append(f"{fname}: brand '{rec.get('brand')}' not a known brand")
563561
_check_variant_path(fname, rec, "monitor", errors, allow_flat=True)
564562

565-
for fname, rec in games:
566-
_validate_game_record(fname, rec, errors)
567-
568-
for fname, rec in software:
563+
for fname, rec in software:
569564
_check_required(fname, rec, SOFTWARE_REQUIRED, errors)
570565
_check_source_urls(fname, rec, errors)
571566
_check_slug(fname, rec.get("slug"), errors)
572567
if rec.get("release_date") is not None:
573568
_check_date(fname, rec["release_date"], errors)
574569

575-
return errors
570+
# Game data is import-scale. Keep the default validator bounded by
571+
# streaming game records after the smaller cross-category checks.
572+
errors.extend(validate_games())
573+
return errors
576574

577575

578576
def run(argv: list[str] | None = None) -> int:

docs/DATA_LAYOUT.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,14 @@ them only prevents routine Git polling from scanning millions of files.
2424
For a focused data import, temporarily add only the family you need:
2525

2626
```
27-
git sparse-checkout add --cone data/cpu
27+
git sparse-checkout add data/cpu
2828
```
2929

3030
For a full game import, add `data/game` for the duration of the import, then
3131
return to the small default checkout:
3232

3333
```
34-
git sparse-checkout add --cone data/game
34+
git sparse-checkout add data/game
3535
git sparse-checkout set --cone .github app docs TechEngine
3636
```
3737

tests/test_game_validation.py

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import tempfile
77
import unittest
88
from pathlib import Path
9+
from unittest import mock
910

1011
from app import validate as validator
1112

@@ -47,7 +48,7 @@ def test_rejects_invalid_game_metadata(self) -> None:
4748
"name": " ",
4849
"verified": "yes",
4950
"source_urls": ["https://example.com/hades"],
50-
"platforms": ["PC", "pc"],
51+
"platforms": ["PC", 4],
5152
"rating_count": -1,
5253
"playtime_hours": -1,
5354
"esrb_rating": "Unknown",
@@ -56,7 +57,7 @@ def test_rejects_invalid_game_metadata(self) -> None:
5657
)
5758
self.assertTrue(any("name must be a non-empty string" in error for error in errors))
5859
self.assertTrue(any("verified must be a boolean" in error for error in errors))
59-
self.assertTrue(any("platforms contains duplicate values" in error for error in errors))
60+
self.assertTrue(any("platforms must be a list of non-empty strings" in error for error in errors))
6061
self.assertTrue(any("rating_count=-1 out of range" in error for error in errors))
6162
self.assertTrue(any("playtime_hours=-1 out of range" in error for error in errors))
6263
self.assertTrue(any("esrb_rating 'Unknown'" in error for error in errors))
@@ -74,6 +75,23 @@ def test_rejects_game_outside_slug_shard(self) -> None:
7475
)
7576
self.assertTrue(any("belongs in 'ha'" in error for error in errors))
7677

78+
def test_default_validation_streams_games_instead_of_loading_them(self) -> None:
79+
loaded_categories: list[str] = []
80+
81+
def load_without_games(category: str):
82+
loaded_categories.append(category)
83+
self.assertNotEqual(category, "game")
84+
return []
85+
86+
with (
87+
mock.patch.object(validator, "_load", side_effect=load_without_games),
88+
mock.patch.object(validator, "validate_games", return_value=[] ) as streamed_games,
89+
):
90+
self.assertEqual(validator.validate(), [])
91+
92+
self.assertNotIn("game", loaded_categories)
93+
streamed_games.assert_called_once_with()
94+
7795

7896
if __name__ == "__main__":
7997
unittest.main()

0 commit comments

Comments
 (0)