bolster.data_sources.justice.nicts_quarterly ============================================ .. py:module:: bolster.data_sources.justice.nicts_quarterly .. autoapi-nested-parse:: NICTS Quarterly Provisional Figures. Provides access to the Northern Ireland Courts and Tribunals Service (NICTS) quarterly business statistics, covering caseload across every tier of the NI court system: receipts, disposals, waiting times, and judicial sitting days. Ten court datasets are published in a single ODS workbook, one worksheet each: - ``court_of_appeal_criminal`` - criminal appeals by type and result. - ``court_of_appeal_civil`` - civil appeals received and disposed. - ``high_court_chancery_division`` - Chancery business (incl. mortgages). - ``high_court_kings_bench_division`` - King's Bench writs and outcomes. - ``high_court_family_division`` - divorce, ancillary relief, and wardship. - ``crown_court`` - Crown Court cases and defendants. - ``county_court`` - County Court civil, family, and appeal business. - ``magistrates_courts`` - Magistrates' Court criminal and civil business. - ``children_order`` - public and private law Children Order proceedings. - ``judge_court_sitting_days`` - sitting days and average sitting times. Every worksheet shares the same period columns, so all ten concatenate into a single tidy frame. Each row is one (court, category, subcategory, detail, period) observation. Data Source: **Publication Page**: https://www.justice-ni.gov.uk/publications/nicts-business-data The module scrapes this page for quarterly ODS bulletins (``nicts-quarterly-provisional-figures--.ods``) and selects the most recent. Each bulletin carries the full series from 2017, so a single download gives complete history. Update Frequency: Quarterly Geographic Coverage: Northern Ireland Reference Period: 2017 - present (annual totals to 2024, quarterly thereafter) .. note:: These are *provisional* figures and are revised in later bulletins. The frame mixes annual totals (``2024 Total``) and quarters (``2025 Q1``) in the same ``period`` column — filter on ``quarter.isna()`` to separate them, or summing across periods will double-count. .. rubric:: Example >>> from bolster.data_sources.justice import nicts_quarterly >>> df = nicts_quarterly.get_crown_court() >>> set(df["court"]) == {"crown_court"} True >>> "value" in df.columns True Attributes ---------- .. autoapisummary:: bolster.data_sources.justice.nicts_quarterly.logger bolster.data_sources.justice.nicts_quarterly.PUBLICATION_URL Exceptions ---------- .. autoapisummary:: bolster.data_sources.justice.nicts_quarterly.NICTSDataError bolster.data_sources.justice.nicts_quarterly.NICTSDataNotFoundError bolster.data_sources.justice.nicts_quarterly.NICTSValidationError Functions --------- .. autoapisummary:: bolster.data_sources.justice.nicts_quarterly.list_publications bolster.data_sources.justice.nicts_quarterly.find_latest_publication bolster.data_sources.justice.nicts_quarterly.download_file bolster.data_sources.justice.nicts_quarterly.parse_data bolster.data_sources.justice.nicts_quarterly.get_latest_data bolster.data_sources.justice.nicts_quarterly.list_courts bolster.data_sources.justice.nicts_quarterly.get_crown_court bolster.data_sources.justice.nicts_quarterly.get_magistrates_courts bolster.data_sources.justice.nicts_quarterly.get_county_court bolster.data_sources.justice.nicts_quarterly.get_sitting_days bolster.data_sources.justice.nicts_quarterly.validate_data bolster.data_sources.justice.nicts_quarterly.clear_cache Module Contents --------------- .. py:data:: logger .. py:data:: PUBLICATION_URL :value: 'https://www.justice-ni.gov.uk/publications/nicts-business-data' .. py:exception:: NICTSDataError Bases: :py:obj:`Exception` Base exception for NICTS quarterly figures errors. Initialize self. See help(type(self)) for accurate signature. .. py:exception:: NICTSDataNotFoundError Bases: :py:obj:`NICTSDataError` Raised when the bulletin cannot be located or downloaded. Initialize self. See help(type(self)) for accurate signature. .. py:exception:: NICTSValidationError Bases: :py:obj:`NICTSDataError` Raised when parsed data fails validation. Initialize self. See help(type(self)) for accurate signature. .. py:function:: list_publications(base_url = PUBLICATION_URL) List every quarterly bulletin linked from the publication page. :param base_url: URL of the NICTS business data listing page. :returns: List of dicts with ``url``, ``year`` and ``quarter``, newest first. :raises NICTSDataNotFoundError: If the page cannot be fetched or no bulletins are found. .. rubric:: Example >>> pubs = list_publications() >>> pubs[0]["url"].endswith(".ods") True >>> pubs[0]["year"] >= pubs[-1]["year"] True .. py:function:: find_latest_publication(base_url = PUBLICATION_URL) Find the most recent quarterly bulletin. :param base_url: URL of the NICTS business data listing page. :returns: Dict with ``url``, ``year`` and ``quarter`` for the newest bulletin. :raises NICTSDataNotFoundError: If no bulletin can be located. .. rubric:: Example >>> latest = find_latest_publication() >>> 1 <= latest["quarter"] <= 4 True .. py:function:: download_file(url, cache_ttl_hours = _CACHE_TTL_HOURS, force_refresh = False) Download a bulletin ODS file with caching. :param url: URL of the ODS file. :param cache_ttl_hours: Cache validity in hours (default: 90 days). :param force_refresh: If True, bypass the cache and re-download. :returns: Path to the downloaded (or cached) file. :raises NICTSDataNotFoundError: If the download fails. .. py:function:: parse_data(file_path) Parse every court worksheet from a bulletin into one tidy frame. :param file_path: Path to the ODS bulletin file. :returns: DataFrame with columns court, category, subcategory, detail, period, year, quarter, value — all ten courts concatenated. :raises NICTSDataError: If the workbook contains no parseable court data. .. py:function:: get_latest_data(court = 'all', force_refresh = False) Download and parse the latest quarterly bulletin. :param court: Court key to return (see :func:`list_courts`), or ``"all"`` for every court in one frame. :param force_refresh: If True, bypass the cache and download fresh data. :returns: Tidy DataFrame with columns court, category, subcategory, detail, period, year, quarter, value. :raises NICTSDataNotFoundError: If ``court`` is not a known court key. .. rubric:: Example >>> df = get_latest_data("county_court") >>> set(df["court"]) == {"county_court"} True .. py:function:: list_courts(force_refresh = False) List the court keys available in the latest bulletin. :param force_refresh: If True, bypass the cache and download fresh data. :returns: Sorted list of court keys. .. rubric:: Example >>> "crown_court" in list_courts() True .. py:function:: get_crown_court(force_refresh = False) Get Crown Court business (Table 6). :param force_refresh: If True, bypass the cache and download fresh data. :returns: Tidy DataFrame of Crown Court receipts, disposals, and waiting times at both case and defendant level. .. rubric:: Example >>> df = get_crown_court() >>> "Received" in set(df["subcategory"]) True .. py:function:: get_magistrates_courts(force_refresh = False) Get Magistrates' Courts business (Table 8). :param force_refresh: If True, bypass the cache and download fresh data. :returns: Tidy DataFrame of Magistrates' Court criminal and civil business. .. rubric:: Example >>> df = get_magistrates_courts() >>> set(df["court"]) == {"magistrates_courts"} True .. py:function:: get_county_court(force_refresh = False) Get County Court business (Table 7). :param force_refresh: If True, bypass the cache and download fresh data. :returns: Tidy DataFrame of County Court civil, family, and appeal business. .. rubric:: Example >>> df = get_county_court() >>> set(df["court"]) == {"county_court"} True .. py:function:: get_sitting_days(force_refresh = False) Get judicial sitting days and average sitting times (Table 10). Sitting *times* are reported as durations and are returned in fractional hours, so a published ``6485:30`` becomes ``6485.5``. :param force_refresh: If True, bypass the cache and download fresh data. :returns: Tidy DataFrame of sitting days and times by judge level and court type. .. rubric:: Example >>> df = get_sitting_days() >>> "Total Sitting Days" in set(df["category"]) True .. py:function:: validate_data(df, min_records = 1000) Validate a parsed NICTS quarterly DataFrame. Checks structure and sanity: - Required columns are present. - There are at least ``min_records`` rows. - Years fall within a plausible range (2017 onwards). - Quarters, where present, are 1-4. - All non-null values are non-negative. :param df: DataFrame to validate. :param min_records: Minimum acceptable number of rows. :returns: True if the data passes all checks. :raises NICTSValidationError: If any validation check fails. .. rubric:: Example >>> import pandas as pd >>> validate_data(pd.DataFrame()) Traceback (most recent call last): ... bolster.data_sources.justice.nicts_quarterly.NICTSValidationError: DataFrame is empty .. py:function:: clear_cache() Clear all cached NICTS bulletin files. :returns: Number of files deleted.