"""Every committed registry line is loadable and consistent; the universe is large and diversified (docs/SEEDS.md).""" from __future__ import annotations import csv from collections import Counter import pytest from companyatlas.registry.industries import REGISTRY_DIR, is_valid_slug, load_industries, top_level_of, top_level_slugs from companyatlas.registry.seed import load_registry_rows, registry_files from companyatlas.urls import registrable_domain MIN_TOTAL = 30000 US_CAP = 0.37 # 35 % target + tolerance for the industry top-up OTHER_CAP = 0.13 TIER_SHARES = (0.01, 0.0667, 0.2667) # quantiles of importance → tiers 1–3 (scripts/seed_wikidata.py TIER_SHARES) REQUIRED = {"wikidata_id", "display_name", "website", "canonical_domain", "country", "industries", "importance", "tier", "source", "harvested_at"} def tier_cutoffs(n: int) -> tuple[int, int, int]: t1 = round(n * TIER_SHARES[0]) t2 = t1 + round(n * TIER_SHARES[1]) return t1, t2, t2 + round(n * TIER_SHARES[2]) @pytest.fixture(scope="module") def rows() -> list[dict]: files = registry_files() assert files, "registry/companies/*.ndjson missing — run scripts/seed_wikidata.py" return load_registry_rows(files) @pytest.fixture(scope="module") def countries() -> dict[str, dict]: with (REGISTRY_DIR / "countries.csv").open(encoding="utf-8") as f: return {r["code"]: r for r in csv.DictReader(f)} def test_countries_csv(countries: dict[str, dict]) -> None: assert len(countries) >= 245 for code, r in countries.items(): assert len(code) == 2 and code.isupper() and r["name"] assert -90 <= float(r["lat"]) <= 90 and -180 <= float(r["lon"]) <= 180 for must in ("US", "CA", "GB", "DE", "FR", "JP", "KR", "IN", "AU", "BR", "NG", "TW", "HK", "XK"): assert must in countries assert countries["TW"]["region"] == "Asia" def test_every_line_is_valid(rows: list[dict], countries: dict[str, dict]) -> None: assert len(rows) >= MIN_TOTAL, f"only {len(rows)} companies" slugs = {i.slug for i in load_industries()} domains: Counter[str] = Counter() qids: Counter[str] = Counter() for r in rows: assert REQUIRED <= set(r), r.get("wikidata_id") assert r["wikidata_id"].startswith("Q") and r["wikidata_id"][1:].isdigit() assert r["display_name"].strip() assert r["website"].startswith(("https://", "http://")), r["website"] assert "/" not in r["website"].split("://", 1)[1], "website must be scheme + host only" assert r["canonical_domain"] == registrable_domain(r["website"]) assert r["country"] is None or r["country"] in countries, r["country"] assert all(is_valid_slug(s) for s in r["industries"]), r["industries"] assert all(s in slugs for s in r["industries"]) assert 0.0 <= r["importance"] <= 1.0 and r["tier"] in (1, 2, 3, 4) # Listed companies and large companies (employees / revenue bands) may have no Wikipedia article at all; class-band items need ≥ 2. assert r["source"] == "wikidata" and isinstance(r["sitelinks"], int) and r["sitelinks"] >= 0 assert r["founded_year"] is None or 1000 <= r["founded_year"] <= 2026 assert r["lat"] is None or -90 <= r["lat"] <= 90 assert r["lon"] is None or -180 <= r["lon"] <= 180 assert r["parent"] is None or set(r["parent"]) == {"wikidata_id", "name"} domains[r["canonical_domain"]] += 1 qids[r["wikidata_id"]] += 1 assert not [d for d, n in domains.items() if n > 1], "duplicate domains" assert not [q for q, n in qids.items() if n > 1], "duplicate wikidata ids" def test_diversification(rows: list[dict]) -> None: n = len(rows) by_country = Counter(r["country"] for r in rows) assert by_country["US"] / n <= US_CAP, by_country["US"] / n for code, count in by_country.items(): if code not in ("US", None): assert count / n <= OTHER_CAP, (code, count / n) assert by_country[None] / n <= 0.05 for code, minimum in {"CA": 150, "GB": 150, "DE": 150, "FR": 150, "JP": 150, "IN": 150, "AU": 150}.items(): assert by_country[code] >= minimum, (code, by_country[code]) tiers = Counter(r["tier"] for r in rows) t1, t2, t3 = tier_cutoffs(n) assert (tiers[1], tiers[2], tiers[3], tiers[4]) == (t1, t2 - t1, t3 - t2, n - t3), dict(tiers) assert 250 <= tiers[1] <= 400 and 1800 <= tiers[2] <= 2500 and 7000 <= tiers[3] <= 10000 # The atlas is listed-companies-first: a substantial share carries a stock exchange or ticker. assert sum(1 for r in rows if r["public_company"]) / n >= 0.30 by_top: Counter[str] = Counter() for r in rows: for t in {top_level_of(s) for s in r["industries"]}: by_top[t] += 1 covered = [t for t in top_level_slugs() if by_top[t] >= 60] assert len(covered) >= len(top_level_slugs()) - 2, {t: by_top[t] for t in top_level_slugs() if by_top[t] < 60} # Listed small caps (TSE, Bursa Malaysia, KRX, TASE …) often carry no P452 and a bare "public company" description on Wikidata; the # LLM classify_industry job and the crawl fill those later (docs/SEEDS.md, Known gaps). assert sum(1 for r in rows if r["industries"]) / n >= 0.80 def test_files_are_split_by_region(rows: list[dict], countries: dict[str, dict]) -> None: for path in registry_files(): region = path.stem.removeprefix("wikidata-") for r in load_registry_rows([path]): actual = (countries.get(r["country"] or "", {}).get("region") or "other").lower().replace(" ", "-") assert actual == region, (path.name, r["wikidata_id"], actual)