Source code for bhf_smarthealth.process.qualtrics_process

"""This module utilises functions from the parse.qualtrics_parser module to process raw daily Qualtrics data"""

import logging
from datetime import date
from pathlib import Path

import pandas as pd

from bhf_smarthealth.log import metadata_logs
from bhf_smarthealth.models import DataStreamNames
from bhf_smarthealth.parse import qualtrics_parser as bhf_qualtrics
from bhf_smarthealth.utils import data_io

logger = logging.getLogger(__name__)


[docs] def process_day(in_paths: dict[str, Path], out_paths: dict[str, Path], date_str: str): """Process daily Qualtrics base and bridge .csv files Parameters ---------- in_dir : Path Path of the directory containing raw data to process out_paths : dict[str, Path] Dictionary of paths to save each of the output DataFrames to date : date datetime.date object containing date to process """ # ensure date in correct format for Qualtrics filename (YYYY-MM-DD) date_str = date.fromisoformat(date_str).strftime("%Y-%m-%d") logger.info(f"Processing Qualtrics data stream for {date_str}") bridge_path = in_paths.get("bridge") base_path = in_paths.get("base") # if no file paths are passed, i.e. there is no Qualtrics data, save out empty files if (bridge_path is None) and (base_path is None): for table in ["base", "bridge"]: logger.warning( f"No Qualtrics data recieved for date {date_str}. Saving empty parquet files..." ) data_io.save_dataframe_ouput( df=pd.DataFrame(), file_out_path=out_paths[table] ) # No IDs seen for this stream today all_IDs = [] # else both paths are available elif (bridge_path is not None) and (base_path is not None): # no errors handled here as an error with this stream should be handled at a higher level to either stop the pipeline, or continue without this stream but flag for re-processing bridge_data = bhf_qualtrics.load_qualtrics_csv(bridge_path) base_data = bhf_qualtrics.load_qualtrics_csv(base_path) validated_data = bhf_qualtrics.validate_data( base_questions_data=base_data, bridge_data=bridge_data ) out_dict: dict[str, pd.DataFrame] = bhf_qualtrics.create_dataframes( validated_data ) # Save out the base and bridge DataFrames for table in ["base", "bridge"]: data_io.save_dataframe_ouput(out_dict[table], out_paths[table]) logger.info( f"Saved {table} DataFrame to {out_paths[table]} with shape: {out_dict[table].shape} and columns: {out_dict[table].columns}" ) # Generate receipt of IDs "seen" today # validate_data() checks all IDs are unique and identical between bridge and base files all_IDs = out_dict["base"].reset_index()["sheffield_id"].tolist() metadata_logs.generate_daily_IDs_receipt( all_IDs=all_IDs, valid_IDs=all_IDs, # all processed IDs will be valid data_stream=DataStreamNames.QUALTRICS, date_str=date_str, out_path=out_paths["metadata"], )