A '2025-26-revised' release read as an unknown year went last, behind the '2025-26' release, which then owned the year and dropped every revised row. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
101 lines
3.9 KiB
Python
101 lines
3.9 KiB
Python
"""DfE re-publishes earlier years inside later KS4 releases.
|
|
|
|
The 2024/25 results file holds 2022/23, 2023/24 and 2024/25 under current
|
|
column names. The 2023/24 release's own file, re-issued in March 2026 under
|
|
older names, was read after it and overwrote every 2023/24 row with blanks
|
|
(audit C2). For the KS4 results stream the newest release owns every year it
|
|
contains.
|
|
"""
|
|
import importlib.util
|
|
import re
|
|
from pathlib import Path
|
|
|
|
import pandas as pd
|
|
import pytest
|
|
|
|
TAP_DIR = (Path(__file__).resolve().parents[1] / 'plugins' / 'extractors' / 'tap-uk-ees'
|
|
/ 'tap_uk_ees')
|
|
|
|
|
|
@pytest.fixture
|
|
def precedence():
|
|
spec = importlib.util.spec_from_file_location(
|
|
'release_precedence', TAP_DIR / 'release_precedence.py')
|
|
module = importlib.util.module_from_spec(spec)
|
|
spec.loader.exec_module(module)
|
|
return module
|
|
|
|
|
|
def _release(period):
|
|
return {'id': f'release-{period}', 'time_period': period}
|
|
|
|
|
|
def test_releases_are_taken_newest_first_whatever_order_the_api_gives(precedence):
|
|
releases = [_release('202223'), _release('202425'), _release(None), _release('202324')]
|
|
ordered = precedence.newest_first(releases)
|
|
assert [r['time_period'] for r in ordered] == ['202425', '202324', '202223', None]
|
|
|
|
|
|
def test_a_year_a_newer_release_supplied_is_dropped_from_an_older_one(precedence):
|
|
newer = pd.DataFrame({'time_period': ['202425', '202324', '202223'], 'school_urn': ['1'] * 3})
|
|
older = pd.DataFrame({'time_period': ['202324', '202324', '201920'], 'school_urn': ['1', '2', '1']})
|
|
|
|
kept, skipped = precedence.drop_owned_periods(older, precedence.periods_in(newer))
|
|
|
|
assert list(kept['time_period']) == ['201920']
|
|
assert skipped == {'202324': 2}
|
|
|
|
|
|
def test_periods_match_despite_surrounding_spaces(precedence):
|
|
owned = precedence.periods_in(pd.DataFrame({'time_period': [' 202324 ']}))
|
|
kept, skipped = precedence.drop_owned_periods(pd.DataFrame({'time_period': ['202324']}), owned)
|
|
assert owned == {'202324'}
|
|
assert kept.empty
|
|
assert skipped == {'202324': 1}
|
|
|
|
|
|
def test_nothing_is_dropped_before_any_year_is_owned(precedence):
|
|
df = pd.DataFrame({'time_period': ['202324'], 'school_urn': ['1']})
|
|
kept, skipped = precedence.drop_owned_periods(df, set())
|
|
assert kept.equals(df)
|
|
assert skipped == {}
|
|
|
|
|
|
def test_a_file_without_time_period_is_left_alone(precedence):
|
|
df = pd.DataFrame({'school_urn': ['1']})
|
|
kept, skipped = precedence.drop_owned_periods(df, {'202324'})
|
|
assert kept.equals(df)
|
|
assert skipped == {}
|
|
assert precedence.periods_in(df) == set()
|
|
|
|
|
|
def test_only_the_ks4_results_stream_opts_in():
|
|
# A general rule would wipe KS2: the 2024/25 KS2 file holds 98,448 of the
|
|
# 955,956 rows the 2023/24 release has for 2023/24.
|
|
source = (TAP_DIR / 'tap.py').read_text()
|
|
opted_in = [chunk.split('(')[0] for chunk in source.split('\nclass ')[1:]
|
|
if re.search(r'_newest_release_owns_period\s*=\s*True', chunk)]
|
|
assert opted_in == ['EESKS4PerformanceStream']
|
|
|
|
|
|
@pytest.mark.parametrize('slug, period', [
|
|
('2024-25', '202425'),
|
|
('2024-25-revised', '202425'),
|
|
('2025-26-provisional', '202526'),
|
|
('latest', None),
|
|
('', None),
|
|
])
|
|
def test_a_release_slug_gives_its_year_whatever_its_suffix(precedence, slug, period):
|
|
# KS2 already publishes "2024-25-revised" and "2025-26-provisional". An
|
|
# unread suffix sent the release last, behind the provisional one for the
|
|
# same year, which then owned the year and dropped every revised row.
|
|
assert precedence.slug_to_time_period(slug) == period
|
|
|
|
|
|
def test_within_a_year_the_api_order_is_kept(precedence):
|
|
# The API lists a year's revised release before its first release.
|
|
releases = [{'id': 'revised', 'time_period': '202526'},
|
|
{'id': 'first', 'time_period': '202526'},
|
|
{'id': 'older', 'time_period': '202425'}]
|
|
assert [r['id'] for r in precedence.newest_first(releases)] == ['revised', 'first', 'older']
|