Skip to content

Commit 110c8aa

Browse files
committed
feat(data): add mobile device variant fixtures
Refs #1
1 parent 49379a4 commit 110c8aa

4 files changed

Lines changed: 172 additions & 0 deletions

File tree

app/validate.py

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,19 @@
4444
"os",
4545
}
4646

47+
MOBILE_DEVICE_REQUIRED = {
48+
"slug",
49+
"name",
50+
"brand",
51+
"release_date",
52+
"ram_gb",
53+
"battery_mah",
54+
"weight_g",
55+
"os",
56+
"source_urls",
57+
"verified",
58+
}
59+
4760
GPU_REQUIRED = {
4861
"slug",
4962
"name",
@@ -135,12 +148,49 @@ def _check_source_urls(name: str, record: dict[str, Any], errors: list[str]) ->
135148
errors.append(f"{name}: source_urls must be a non-empty list of http(s) URL strings")
136149

137150

151+
def _check_variant_path(
152+
fname: str,
153+
rec: dict[str, Any],
154+
category: str,
155+
errors: list[str],
156+
*,
157+
allow_flat: bool = False,
158+
) -> None:
159+
parts = Path(fname).parts
160+
if allow_flat and len(parts) == 4:
161+
return
162+
if len(parts) != 5:
163+
errors.append(
164+
f"{fname}: {category} variants must live at "
165+
f"'{category}/<brand>/<year>/<base_model_slug>/<slug>.json'"
166+
)
167+
return
168+
_, brand, year, base_model_slug, filename = parts
169+
if rec.get("brand") != brand:
170+
errors.append(f"{fname}: lives in brand '{brand}' but brand='{rec.get('brand')}'")
171+
release_year = str(rec.get("release_date", ""))[:4]
172+
if release_year and year != release_year:
173+
errors.append(
174+
f"{fname}: lives in year '{year}' but release_date starts with '{release_year}'"
175+
)
176+
if rec.get("base_model_slug") and rec.get("base_model_slug") != base_model_slug:
177+
errors.append(
178+
f"{fname}: lives under base '{base_model_slug}' but "
179+
f"base_model_slug='{rec.get('base_model_slug')}'"
180+
)
181+
if filename != f"{rec.get('slug')}.json":
182+
errors.append(f"{fname}: filename must match slug '{rec.get('slug')}'")
183+
184+
138185
def validate() -> list[str]:
139186
errors: list[str] = []
140187

141188
brands = _load("brand")
142189
socs = _load("soc")
143190
phones = _load("smartphone")
191+
tablets = _load("tablet")
192+
watches = _load("watch")
193+
pdas = _load("pda")
144194
gpus = _load("gpu")
145195
cpus = _load("cpu")
146196

@@ -151,6 +201,9 @@ def validate() -> list[str]:
151201
("brand", brands),
152202
("soc", socs),
153203
("smartphone", phones),
204+
("tablet", tablets),
205+
("watch", watches),
206+
("pda", pdas),
154207
("gpu", gpus),
155208
("cpu", cpus),
156209
):
@@ -214,6 +267,25 @@ def validate() -> list[str]:
214267
errors.append(f"{fname}: brand '{rec.get('brand')}' not a known brand")
215268
if rec.get("soc") not in soc_slugs:
216269
errors.append(f"{fname}: soc '{rec.get('soc')}' not a known SoC")
270+
_check_variant_path(fname, rec, "smartphone", errors, allow_flat=True)
271+
272+
for category, records in (("tablet", tablets), ("watch", watches), ("pda", pdas)):
273+
for fname, rec in records:
274+
_check_required(fname, rec, MOBILE_DEVICE_REQUIRED, errors)
275+
_check_source_urls(fname, rec, errors)
276+
_check_slug(fname, rec.get("slug"), errors)
277+
if "release_date" in rec:
278+
_check_date(fname, rec["release_date"], errors)
279+
_check_range(fname, "ram_gb", rec.get("ram_gb"), 0.016, 64, errors)
280+
_check_range(fname, "battery_mah", rec.get("battery_mah"), 50, 20000, errors)
281+
_check_range(fname, "weight_g", rec.get("weight_g"), 10, 2000, errors)
282+
if "msrp_usd" in rec:
283+
_check_range(fname, "msrp_usd", rec["msrp_usd"], 10, 10000, errors)
284+
if rec.get("brand") not in brand_slugs:
285+
errors.append(f"{fname}: brand '{rec.get('brand')}' not a known brand")
286+
if rec.get("soc") is not None and rec.get("soc") not in soc_slugs:
287+
errors.append(f"{fname}: soc '{rec.get('soc')}' not a known SoC")
288+
_check_variant_path(fname, rec, category, errors)
217289

218290
for fname, rec in gpus:
219291
_check_required(fname, rec, GPU_REQUIRED, errors)
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
{
2+
"slug": "ipaq-h3600-base",
3+
"base_model_slug": "ipaq-h3600",
4+
"name": "HP iPAQ H3600",
5+
"brand": "hp",
6+
"release_date": "2000-04-01",
7+
"ram_gb": 0.032,
8+
"storage_options_gb": [],
9+
"variant": {
10+
"region": "global",
11+
"model_numbers": ["H3600"],
12+
"memory": {"ram_gb": 0.032},
13+
"network": {"cellular": "none"},
14+
"sim": "none"
15+
},
16+
"display": {
17+
"size_inch": 3.8,
18+
"resolution": "240x320",
19+
"type": "TFT LCD"
20+
},
21+
"cameras": [],
22+
"battery_mah": 950,
23+
"weight_g": 170,
24+
"dimensions": {"height_mm": 130, "width_mm": 84, "depth_mm": 16},
25+
"os": "Pocket PC",
26+
"connectivity": {},
27+
"verified": false,
28+
"source_urls": [
29+
"https://en.wikipedia.org/wiki/IPAQ"
30+
]
31+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
{
2+
"slug": "ipad-pro-11-m4-wifi-8gb-256gb",
3+
"base_model_slug": "ipad-pro-11-m4",
4+
"name": "iPad Pro 11-inch (M4, Wi-Fi, 8GB/256GB)",
5+
"brand": "apple",
6+
"release_date": "2024-05-15",
7+
"msrp_usd": 999,
8+
"ram_gb": 8,
9+
"storage_options_gb": [256],
10+
"variant": {
11+
"region": "global",
12+
"model_numbers": ["A2836"],
13+
"memory": {"ram_gb": 8, "storage_gb": 256},
14+
"network": {"cellular": "none", "carrier": "wifi-only"},
15+
"sim": "none"
16+
},
17+
"display": {
18+
"size_inch": 11.0,
19+
"resolution": "2420x1668",
20+
"refresh_hz": 120,
21+
"type": "Ultra Retina XDR OLED"
22+
},
23+
"cameras": [{"type": "main", "mp": 12}, {"type": "selfie", "mp": 12}],
24+
"battery_mah": 8160,
25+
"weight_g": 444,
26+
"dimensions": {"height_mm": 249.7, "width_mm": 177.5, "depth_mm": 5.3},
27+
"os": "iPadOS",
28+
"os_version": "17.5",
29+
"connectivity": {"wifi": "Wi-Fi 6E", "bluetooth": "5.3", "usb": "USB-C"},
30+
"verified": false,
31+
"source_urls": [
32+
"https://support.apple.com/en-us/119891"
33+
]
34+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
{
2+
"slug": "galaxy-watch-global-bluetooth-42mm",
3+
"base_model_slug": "galaxy-watch",
4+
"name": "Galaxy Watch (Bluetooth, 42mm)",
5+
"brand": "samsung",
6+
"soc": "exynos-9110",
7+
"release_date": "2018-08-24",
8+
"msrp_usd": 329,
9+
"ram_gb": 0.75,
10+
"storage_options_gb": [4],
11+
"variant": {
12+
"region": "global",
13+
"model_numbers": ["SM-R810"],
14+
"memory": {"ram_gb": 0.75, "storage_gb": 4},
15+
"network": {"cellular": "none", "carrier": "bluetooth-only"},
16+
"sim": "none"
17+
},
18+
"display": {
19+
"size_inch": 1.2,
20+
"resolution": "360x360",
21+
"type": "Super AMOLED"
22+
},
23+
"cameras": [],
24+
"battery_mah": 270,
25+
"weight_g": 49,
26+
"dimensions": {"height_mm": 45.7, "width_mm": 41.9, "depth_mm": 12.7},
27+
"ip_rating": "IP68",
28+
"os": "Tizen",
29+
"os_version": "4.0",
30+
"connectivity": {"wifi": "802.11 b/g/n", "bluetooth": "4.2", "nfc": true},
31+
"verified": false,
32+
"source_urls": [
33+
"https://www.samsung.com/us/support/answer/ANS00078020/"
34+
]
35+
}

0 commit comments

Comments
 (0)