Add full type annotations and black formatting across all modules

Annotated all functions with mypy --strict-compatible types (-> None, dict[str,
Any], Generator types, etc.), added # type: ignore for untyped third-party libs
(lxml), and reformatted with black. All 18 source files now pass mypy --strict
with zero errors.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Edward Betts 2026-05-25 21:48:53 +01:00
parent 453d6244ec
commit 13c4341f3a
14 changed files with 1802 additions and 974 deletions

View file

@ -1,71 +1,74 @@
import pytest
from scraper.realtime_trains import _fmt, _parse_services
# ---------------------------------------------------------------------------
# _fmt
# ---------------------------------------------------------------------------
def test_fmt_four_digits():
assert _fmt('0830') == '08:30'
def test_fmt_already_colon():
assert _fmt('08:30') == '08:30'
def test_fmt_four_digits() -> None:
assert _fmt("0830") == "08:30"
def test_fmt_strips_non_digits():
assert _fmt('08h30') == '08:30'
def test_fmt_already_colon() -> None:
assert _fmt("08:30") == "08:30"
def test_fmt_strips_non_digits() -> None:
assert _fmt("08h30") == "08:30"
# ---------------------------------------------------------------------------
# _parse_services
# ---------------------------------------------------------------------------
def _make_html(services: list[tuple[str, str]], time_class: str) -> str:
"""Build a minimal servicelist HTML with (train_id, time) pairs."""
items = ''
items = ""
for tid, time in services:
items += f'''
items += f"""
<a class="service">
<div class="tid">{tid}</div>
<div class="time plan {time_class}">{time}</div>
</a>'''
</a>"""
return f'<div class="servicelist">{items}</div>'
def test_parse_services_departures():
html = _make_html([('1A23', '0700'), ('2B45', '0830')], 'd')
result = _parse_services(html, 'div.time.plan.d')
assert result == {'1A23': '07:00', '2B45': '08:30'}
def test_parse_services_departures() -> None:
html = _make_html([("1A23", "0700"), ("2B45", "0830")], "d")
result = _parse_services(html, "div.time.plan.d")
assert result == {"1A23": "07:00", "2B45": "08:30"}
def test_parse_services_arrivals():
html = _make_html([('1A23', '0845')], 'a')
result = _parse_services(html, 'div.time.plan.a')
assert result == {'1A23': '08:45'}
def test_parse_services_arrivals() -> None:
html = _make_html([("1A23", "0845")], "a")
result = _parse_services(html, "div.time.plan.a")
assert result == {"1A23": "08:45"}
def test_parse_services_no_servicelist():
assert _parse_services('<html></html>', 'div.time.plan.d') == {}
def test_parse_services_no_servicelist() -> None:
assert _parse_services("<html></html>", "div.time.plan.d") == {}
def test_parse_services_skips_missing_time():
html = '''
def test_parse_services_skips_missing_time() -> None:
html = """
<div class="servicelist">
<a class="service"><div class="tid">1A23</div></a>
<a class="service"><div class="tid">2B45</div><div class="time plan d">0900</div></a>
</div>'''
result = _parse_services(html, 'div.time.plan.d')
assert '1A23' not in result
assert result == {'2B45': '09:00'}
</div>"""
result = _parse_services(html, "div.time.plan.d")
assert "1A23" not in result
assert result == {"2B45": "09:00"}
def test_parse_services_skips_empty_time():
html = '''
def test_parse_services_skips_empty_time() -> None:
html = """
<div class="servicelist">
<a class="service">
<div class="tid">1A23</div>
<div class="time plan d"> </div>
</a>
</div>'''
result = _parse_services(html, 'div.time.plan.d')
</div>"""
result = _parse_services(html, "div.time.plan.d")
assert result == {}