"""Every field the GIAS establishments stream declares must be a column of the extract GIAS publishes, or it silently loads as null. H4 adds UKPRN (matches Ofsted's further-education providers) and InspectorateName (name) ("ISI" for about 1,340 independent schools). HEADER is GIAS's own, from edubasealldata20261013.csv. """ import re from pathlib import Path TAP = (Path(__file__).resolve().parents[1] / 'plugins' / 'extractors' / 'tap-uk-gias' / 'tap_uk_gias' / 'tap.py') HEADER = ( 'URN', 'LA (code)', 'LA (name)', 'EstablishmentNumber', 'EstablishmentName', 'TypeOfEstablishment (code)', 'TypeOfEstablishment (name)', 'EstablishmentTypeGroup (code)', 'EstablishmentTypeGroup (name)', 'EstablishmentStatus (code)', 'EstablishmentStatus (name)', 'ReasonEstablishmentOpened (code)', 'ReasonEstablishmentOpened (name)', 'OpenDate', 'ReasonEstablishmentClosed (code)', 'ReasonEstablishmentClosed (name)', 'CloseDate', 'PhaseOfEducation (code)', 'PhaseOfEducation (name)', 'StatutoryLowAge', 'StatutoryHighAge', 'Boarders (code)', 'Boarders (name)', 'NurseryProvision (name)', 'OfficialSixthForm (code)', 'OfficialSixthForm (name)', 'Gender (code)', 'Gender (name)', 'ReligiousCharacter (code)', 'ReligiousCharacter (name)', 'ReligiousEthos (name)', 'Diocese (code)', 'Diocese (name)', 'AdmissionsPolicy (code)', 'AdmissionsPolicy (name)', 'SchoolCapacity', 'SpecialClasses (code)', 'SpecialClasses (name)', 'CensusDate', 'NumberOfPupils', 'NumberOfBoys', 'NumberOfGirls', 'PercentageFSM', 'TrustSchoolFlag (code)', 'TrustSchoolFlag (name)', 'Trusts (code)', 'Trusts (name)', 'SchoolSponsorFlag (name)', 'SchoolSponsors (name)', 'FederationFlag (name)', 'Federations (code)', 'Federations (name)', 'UKPRN', 'FEHEIdentifier', 'FurtherEducationType (name)', 'LastChangedDate', 'Street', 'Locality', 'Address3', 'Town', 'County (name)', 'Postcode', 'SchoolWebsite', 'TelephoneNum', 'HeadTitle (name)', 'HeadFirstName', 'HeadLastName', 'HeadPreferredJobTitle', 'BSOInspectorateName (name)', 'InspectorateReport', 'DateOfLastInspectionVisit', 'NextInspectionVisit', 'TeenMoth (name)', 'TeenMothPlaces', 'CCF (name)', 'SENPRU (name)', 'EBD (name)', 'PlacesPRU', 'FTProv (name)', 'EdByOther (name)', 'Section41Approved (name)', 'SEN1 (name)', 'SEN2 (name)', 'SEN3 (name)', 'SEN4 (name)', 'SEN5 (name)', 'SEN6 (name)', 'SEN7 (name)', 'SEN8 (name)', 'SEN9 (name)', 'SEN10 (name)', 'SEN11 (name)', 'SEN12 (name)', 'SEN13 (name)', 'TypeOfResourcedProvision (name)', 'ResourcedProvisionOnRoll', 'ResourcedProvisionCapacity', 'SenUnitOnRoll', 'SenUnitCapacity', 'GOR (code)', 'GOR (name)', 'DistrictAdministrative (code)', 'DistrictAdministrative (name)', 'AdministrativeWard (code)', 'AdministrativeWard (name)', 'ParliamentaryConstituency (code)', 'ParliamentaryConstituency (name)', 'UrbanRural (code)', 'UrbanRural (name)', 'GSSLACode (name)', 'Easting', 'Northing', 'MSOA (name)', 'LSOA (name)', 'InspectorateName (name)', 'SENStat', 'SENNoStat', 'BoardingEstablishment (name)', 'PropsName', 'PreviousLA (code)', 'PreviousLA (name)', 'PreviousEstablishmentNumber', 'Country (name)', 'UPRN', 'SiteName', 'QABName (code)', 'QABName (name)', 'EstablishmentAccredited (code)', 'EstablishmentAccredited (name)', 'QABReport', 'CHNumber', 'MSOA (code)', 'LSOA (code)', 'FSM', 'AccreditationExpiryDate', ) def declared(): source = TAP.read_text() block = source[source.index('class GIASEstablishmentsStream'):source.index('class GIASLinksStream')] return re.findall(r'th\.Property\("([^"]+)"', block) def test_every_declared_field_is_a_gias_column(): assert set(declared()) - set(HEADER) == set() def test_the_inspection_fields_are_declared(): assert {'UKPRN', 'InspectorateName (name)'} <= set(declared())