Source code for metobs_toolkit.dataset_settings_updater

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
Extension of the Dataset class (methods for updating settings).
@author: thoverga
"""
import logging
import pandas as pd
from metobs_toolkit import Dataset

logger = logging.getLogger(__name__)


class Dataset(Dataset):
    """Extension on the metobs_toolkit.Dataset class with updaters."""

[docs] def update_settings( self, output_folder=None, input_data_file=None, input_metadata_file=None, template_file=None, ): """Update the most common input-output (IO) settings. (This should be applied before importing the observations.) When an update value is None, the specific setting will not be updated. Parameters ---------- output_folder : string, optional A directory to store the output to. The default is None. input_data_file : string, optional Path to the input data file with observations. The default is None. input_metadata_file : string, optional Path to the input metadata file. The default is None. template_file : string, optional Path to the template (json) file to be used on the observations and metadata. The default is None. Returns ------- None. """ self.settings.update_IO( output_folder=output_folder, input_data_file=input_data_file, input_metadata_file=input_metadata_file, template_file=template_file, )
[docs] def update_timezone(self, timezonestr): """Change the timezone of the input data. By default UTC is assumed. A valid timezonestring is an element of the pytz.all_timezones. Parameters ---------- timezonestr : string Timezone string of the input observations. Element of pytz.all_timezones. Returns ------- None. """ self.settings.update_timezone(timezonestr)
[docs] def update_default_name(self, default_name): """Update the default name (the name of the station). This name will be used when no names are found in the observational dataset. (All observations are assumed to come from one station.) Parameters ---------- default_name : string Default name to use when no names are present in the data. Returns ------- None. """ self.settings.app["default_name"] = str(default_name)
[docs] def update_gap_and_missing_fill_settings( self, gap_interpolation_method=None, gap_interpolation_max_consec_fill=None, gap_debias_prefered_leading_period_hours=None, gap_debias_prefered_trailing_period_hours=None, gap_debias_minimum_leading_period_hours=None, gap_debias_minimum_trailing_period_hours=None, automatic_max_interpolation_duration_str=None, missing_obs_interpolation_method=None, ): """Update fill settings for gaps and missing observations. If None, the current setting is not updated. Parameters ---------- gap_interpolation_method : str, optional The interpolation method to pass to numpy.interpolate. The default is None. gap_interpolation_max_consec_fill : int, optional Maximum number of lacking observations to interpolate. This is passed to the limit argument of Numpy.interpolate. The default is None. gap_debias_prefered_leading_period_hours : int, optional The preferd size of the leading period for calculating hourly biasses wrt the model. The default is None. gap_debias_prefered_trailing_period_hours : int, optional The preferd size of the trailing period for calculating hourly biasses wrt the model. The default is None. gap_debias_minimum_leading_period_hours : int, optional The minimum size of the leading period for calculating hourly biasses wrt the model. The default is None. gap_debias_minimum_trailing_period_hours : int, optional The minimum size of the trailing period for calculating hourly biasses wrt the model. The default is None. automatic_max_interpolation_duration_str : Timedelta or str, optional Maximum duration to apply interpolation for gapfill when using the automatic gapfill method. Gaps with longer durations will be filled using debiased modeldata. The default is None. missing_obs_interpolation_method : str, optional The interpolation method to pass to numpy.interpolate. The default is None. Returns ------- None. """ # Gap linear interpolation if gap_interpolation_method is not None: logger.info( f' The gap interpolation method is updated: \ {self.settings.gap["gaps_fill_settings"]["linear"]["method"]} --> {str(gap_interpolation_method)}' ) self.settings.gap["gaps_fill_settings"]["linear"]["method"] = str( gap_interpolation_method ) if gap_interpolation_max_consec_fill is not None: logger.info( f' The gap max number of consecutive interpolations is updated: \ {self.settings.gap["gaps_fill_settings"]["linear"]["max_consec_fill"]} --> {abs(int(gap_interpolation_max_consec_fill))}' ) self.settings.gap["gaps_fill_settings"]["linear"]["max_consec_fill"] = abs( int(gap_interpolation_max_consec_fill) ) # Gap debias fill if gap_debias_prefered_leading_period_hours is not None: logger.info( f' The size of the prefered leading period for debias gapfill is updated: \ {self.settings.gap["gaps_fill_settings"]["model_debias"]["debias_period"]["prefered_leading_sample_duration_hours"]} --> {abs(int(gap_debias_prefered_leading_period_hours))}' ) self.settings.gap["gaps_fill_settings"]["model_debias"]["debias_period"][ "prefered_leading_sample_duration_hours" ] = abs(int(gap_debias_prefered_leading_period_hours)) if gap_debias_prefered_trailing_period_hours is not None: logger.info( f' The size of the prefered trailing period for debias gapfill is updated: \ {self.settings.gap["gaps_fill_settings"]["model_debias"]["debias_period"]["prefered_trailing_sample_duration_hours"]} --> {abs(int(gap_debias_prefered_trailing_period_hours))}' ) self.settings.gap["gaps_fill_settings"]["model_debias"]["debias_period"][ "prefered_trailing_sample_duration_hours" ] = abs(int(gap_debias_prefered_trailing_period_hours)) if gap_debias_minimum_leading_period_hours is not None: logger.info( f' The minimum size of the leading period for debias gapfill is updated: \ {self.settings.gap["gaps_fill_settings"]["model_debias"]["debias_period"]["minimum_leading_sample_duration_hours"]} --> {abs(int(gap_debias_minimum_leading_period_hours))}' ) self.settings.gap["gaps_fill_settings"]["model_debias"]["debias_period"][ "minimum_leading_sample_duration_hours" ] = abs(int(gap_debias_minimum_leading_period_hours)) if gap_debias_minimum_trailing_period_hours is not None: logger.info( f' The minimum size of the trailing period for debias gapfill is updated: \ {self.settings.gap["gaps_fill_settings"]["model_debias"]["debias_period"]["minimum_trailing_sample_duration_hours"]} --> {abs(int(gap_debias_minimum_trailing_period_hours))}' ) self.settings.gap["gaps_fill_settings"]["model_debias"]["debias_period"][ "minimum_trailing_sample_duration_hours" ] = abs(int(gap_debias_minimum_trailing_period_hours)) # Gapfill automatic if automatic_max_interpolation_duration_str is not None: if is_timedelta(str(automatic_max_interpolation_duration_str)): logger.info( f' The maximum interpolation duration for automatic gapfill is updated: \ {self.settings.gap["gaps_fill_settings"]["automatic"]["max_interpolation_duration_str"]} --> {str(automatic_max_interpolation_duration_str)}' ) self.settings.gap["gaps_fill_settings"]["automatic"][ "max_interpolation_duration_str" ] = str(automatic_max_interpolation_duration_str) else: logger.warning( f" {str(automatic_max_interpolation_duration_str)} is not a valid timedelta string. No update on this setting." ) # Missing obs interpolation if missing_obs_interpolation_method is not None: logger.info( f' The missing observations interpolation method is updated: \ {self.settings.missing_obs["missing_obs_fill_settings"]["linear"]["method"]} --> {str(missing_obs_interpolation_method)}' ) self.settings.missing_obs["missing_obs_fill_settings"]["linear"][ "method" ] = str(missing_obs_interpolation_method)
[docs] def update_qc_settings( self, obstype="temp", gapsize_in_records=None, dupl_timestamp_keep=None, persis_time_win_to_check=None, persis_min_num_obs=None, rep_max_valid_repetitions=None, gross_value_min_value=None, gross_value_max_value=None, win_var_max_increase_per_sec=None, win_var_max_decrease_per_sec=None, win_var_time_win_to_check=None, win_var_min_num_obs=None, step_max_increase_per_sec=None, step_max_decrease_per_sec=None, buddy_radius=None, buddy_min_sample_size=None, buddy_max_elev_diff=None, buddy_min_std=None, buddy_threshold=None, buddy_elev_gradient=None, ): """Update the QC settings for the specified observation type. If a argument value is None, the default settings will not be updated. Parameters ---------- obstype : str, optional The observation type to update the quality control settings for. The default is 'temp'. gapsize_in_records : int (> 0), optional A gap is defined as a sequence of missing observations with a length greater or equal to this number, on the input frequencies. The default is None. dupl_timestamp_keep : bool, optional Setting that determines to keep, or remove duplicated timestamps. The default is None. persis_time_win_to_check : Timedelta or str, optional Time window for persistance check. The default is None. persis_min_num_obs : int (> 0), optional Minimal window members for persistance check. The default is None. rep_max_valid_repetitions : int (> 0), optional Maximal valid repetitions for repetitions check. The default is None. gross_value_min_value : numeric, optional Minimal value for gross value check. The default is None. gross_value_max_value : numeric, optional Maximal value for gross value check. The default is None. win_var_max_increase_per_sec : numeric (> 0), optional Maximal increase per second for window variation check. The default is None. win_var_max_decrease_per_sec : numeric (> 0), optional Maximal decrease per second for window variation check. The default is None. win_var_time_win_to_check : Timedelta or str, optional Time window for window variation check. The default is None. win_var_min_num_obs : int (> 0), optional Minimal window members for window variation check. The default is None. step_max_increase_per_sec : numeric, optional Maximal increase per second for step check. The default is None. step_max_decrease_per_sec : numeric (< 0), optional Maximal decrease per second for step check. The default is None. buddy_radius : numeric (> 0), optional The radius to define neighbours in meters. The default is None. buddy_min_sample_size : int (> 2), optional The minimum sample size to calculate statistics on. The default is None. buddy_max_elev_diff : numeric (> 0), optional The maximum altitude difference allowed for buddies. The default is None. buddy_min_std : numeric (> 0), optional The minimum standard deviation for sample statistics. This should represent the accuracty of the observations. The default is None. buddy_threshold : numeric (> 0), optional The threshold (std units) for flaggging observations as buddy outliers. The default is None. buddy_elev_gradient : numeric, optional Describes how the obstype changes with altitude (in meters). The default is -0.0065. The default is None. Returns ------- None. Note ------- The gap defenition is independend of the observation type, and is thus set for all the observation types. """ assert ( obstype in self.obstypes.keys() ), f"{obstype} is not a known observation type" def _updater(dictionary, obstype, argname, value): """Update nested dictionaries.""" if obstype not in dictionary.keys(): dictionary[obstype] = {} printstr = f"{obstype} : unexisting --> {value}" elif argname not in dictionary[obstype]: printstr = f"{obstype} : unexisting --> {value}" else: printstr = f"{obstype} : {dictionary[obstype][argname]} --> {value}" dictionary[obstype][argname] = value return dictionary, printstr # Gap defenition if gapsize_in_records is not None: logger.info( f' The defenition of a gap (=gapsize) is updated: \ {self.settings.gap["gaps_settings"]["gaps_finder"]["gapsize_n"]} --> {abs(int(gapsize_in_records))}' ) self.settings.gap["gaps_settings"]["gaps_finder"]["gapsize_n"] = abs( int(gapsize_in_records) ) # Gross value check if gross_value_max_value is not None: self.settings.qc["qc_check_settings"]["gross_value"], updatestr = _updater( self.settings.qc["qc_check_settings"]["gross_value"], obstype=obstype, argname="max_value", value=float(gross_value_max_value), ) logger.info(f"Maximal value for gross value check updated: {updatestr}") if gross_value_min_value is not None: self.settings.qc["qc_check_settings"]["gross_value"], updatestr = _updater( self.settings.qc["qc_check_settings"]["gross_value"], obstype=obstype, argname="min_value", value=float(gross_value_min_value), ) logger.info(f"Minimal value for gross value check updated: {updatestr}") # Duplicate check if dupl_timestamp_keep is not None: logger.info( f'Setting to keep (True) are remove (False) duplicate timestamps updated: \ {self.settings.qc["qc_check_settings"]["duplicated_timestamp"]["keep"]} --> {bool(dupl_timestamp_keep)}' ) self.settings.qc["qc_check_settings"]["duplicated_timestamp"]["keep"] = ( bool(dupl_timestamp_keep) ) # Persistance check if persis_time_win_to_check is not None: if is_timedelta(str(persis_time_win_to_check)): ( self.settings.qc["qc_check_settings"]["persistance"], updatestr, ) = _updater( self.settings.qc["qc_check_settings"]["persistance"], obstype=obstype, argname="time_window_to_check", value=str(persis_time_win_to_check), ) logger.info( f"Time window size for persistance check updated: {updatestr}" ) else: logger.warning( f" {str(persis_time_win_to_check)} is not a valid timedelta string. No update on this setting." ) if persis_min_num_obs is not None: self.settings.qc["qc_check_settings"]["persistance"], updatestr = _updater( self.settings.qc["qc_check_settings"]["persistance"], obstype=obstype, argname="min_num_obs", value=abs(int(persis_min_num_obs)), ) logger.info( f"Minimal window members for persistance check updated: {updatestr}" ) # Repetitions check if rep_max_valid_repetitions is not None: self.settings.qc["qc_check_settings"]["repetitions"], updatestr = _updater( self.settings.qc["qc_check_settings"]["repetitions"], obstype=obstype, argname="max_valid_repetitions", value=abs(int(rep_max_valid_repetitions)), ) logger.info( f"Maximal valid repetitions for repetitions check updated: {updatestr}" ) # Window variation check if win_var_max_increase_per_sec is not None: ( self.settings.qc["qc_check_settings"]["window_variation"], updatestr, ) = _updater( self.settings.qc["qc_check_settings"]["window_variation"], obstype=obstype, argname="max_increase_per_second", value=abs(float(win_var_max_increase_per_sec)), ) logger.info( f"Maximal increase per second for window variation check updated: {updatestr}" ) if win_var_max_decrease_per_sec is not None: ( self.settings.qc["qc_check_settings"]["window_variation"], updatestr, ) = _updater( self.settings.qc["qc_check_settings"]["window_variation"], obstype=obstype, argname="max_decrease_per_second", value=abs(float(win_var_max_decrease_per_sec)), ) logger.info( f"Maximal decrease per second for window variation check updated: {updatestr}" ) if win_var_time_win_to_check is not None: if is_timedelta(str(win_var_time_win_to_check)): ( self.settings.qc["qc_check_settings"]["window_variation"], updatestr, ) = _updater( self.settings.qc["qc_check_settings"]["window_variation"], obstype=obstype, argname="time_window_to_check", value=str(win_var_time_win_to_check), ) logger.info( f"Time window for window variation check updated: {updatestr}" ) else: logger.warning( f" {str(persis_time_win_to_check)} is not a valid timedelta string. No update on this setting." ) if win_var_min_num_obs is not None: ( self.settings.qc["qc_check_settings"]["window_variation"], updatestr, ) = _updater( self.settings.qc["qc_check_settings"]["window_variation"], obstype=obstype, argname="min_window_members", value=abs(int(win_var_min_num_obs)), ) logger.info( f"Minimal window members for window variation check updated: {updatestr}" ) # Step check if step_max_increase_per_sec is not None: self.settings.qc["qc_check_settings"]["step"], updatestr = _updater( self.settings.qc["qc_check_settings"]["step"], obstype=obstype, argname="max_increase_per_second", value=abs(float(step_max_increase_per_sec)), ) logger.info( f"Maximal increase per second for step check updated: {updatestr}" ) if step_max_decrease_per_sec is not None: self.settings.qc["qc_check_settings"]["step"], updatestr = _updater( self.settings.qc["qc_check_settings"]["step"], obstype=obstype, argname="max_decrease_per_second", value=-1.0 * abs(float(step_max_decrease_per_sec)), ) logger.info( f"Maximal decrease per second for step check updated: {updatestr}" ) # Buddy check buddy_elev_gradient = None if buddy_radius is not None: self.settings.qc["qc_check_settings"]["buddy_check"], updatestr = _updater( self.settings.qc["qc_check_settings"]["buddy_check"], obstype=obstype, argname="radius", value=abs(float(buddy_radius)), ) logger.info(f"Buddy radius for buddy check updated: {updatestr}") if buddy_min_sample_size is not None: value = abs(int(buddy_min_sample_size)) if value >= 2: ( self.settings.qc["qc_check_settings"]["buddy_check"], updatestr, ) = _updater( self.settings.qc["qc_check_settings"]["buddy_check"], obstype=obstype, argname="num_min", value=value, ) logger.info( f"Minimum number of buddies for buddy check updated: {updatestr}" ) else: logger.warning( f"Minimum number of buddies must be >= 2, but {value} is given. Not updated." ) if buddy_max_elev_diff is not None: self.settings.qc["qc_check_settings"]["buddy_check"], updatestr = _updater( self.settings.qc["qc_check_settings"]["buddy_check"], obstype=obstype, argname="max_elev_diff", value=abs(float(buddy_max_elev_diff)), ) logger.info( f"Max elevation differences for buddy check updated: {updatestr}" ) if buddy_min_std is not None: self.settings.qc["qc_check_settings"]["buddy_check"], updatestr = _updater( self.settings.qc["qc_check_settings"]["buddy_check"], obstype=obstype, argname="min_std", value=abs(float(buddy_min_std)), ) logger.info(f"Minimum std in sample for buddy check updated: {updatestr}") if buddy_threshold is not None: self.settings.qc["qc_check_settings"]["buddy_check"], updatestr = _updater( self.settings.qc["qc_check_settings"]["buddy_check"], obstype=obstype, argname="threshold", value=abs(float(buddy_threshold)), ) logger.info( f"Outlier threshold (in sigma) for buddy check updated: {updatestr}" ) if buddy_elev_gradient is not None: self.settings.qc["qc_check_settings"]["buddy_check"], updatestr = _updater( self.settings.qc["qc_check_settings"]["buddy_check"], obstype=obstype, argname="elev_gradient", value=float(buddy_max_elev_diff), ) logger.info(f"Elevation gradient for buddy check updated: {updatestr}")
[docs] def update_titan_qc_settings( self, obstype="temp", # buddy settings buddy_radius=None, buddy_num_min=None, buddy_threshold=None, buddy_max_elev_diff=None, buddy_elev_gradient=None, buddy_min_std=None, buddy_num_iterations=None, buddy_debug=None, # sct settings sct_num_min_outer=None, sct_num_max_outer=None, sct_inner_radius=None, sct_outer_radius=None, sct_num_iterations=None, sct_num_min_prof=None, sct_min_elev_diff=None, sct_min_horizontal_scale=None, sct_max_horizontal_scale=None, sct_kth_closest_obs_horizontal_scale=None, sct_vertical_scale=None, sct_mina_deviation=None, # vec Minimum admissible value sct_maxa_deviation=None, # vec Maximum admissible value sct_minv_deviation=None, # vec Minimum valid value sct_maxv_deviation=None, # vec Maximum valid value sct_eps2=None, # Ratio of observation error variance to background variance sct_tpos=None, # vec Positive deviation allowed sct_tneg=None, # vec Negative deviation allowed sct_basic=None, sct_debug=None, ): """Update the TITAN QC settings for the specified observation type. If a argument value is None, the default settings will not be updated. For a detailed explanation of the settings, we refer to the [TITAN documetation](https://github.com/metno/titanlib/wiki) Parameters ---------- The observation type to update the quality control settings for. The default is 'temp'. buddy_radius : int (> 0), optional Search radius in m. The default is None. buddy_num_min : int (> 0), optional The minimum number of buddies a station can have. The default is None. buddy_threshold : num (> 0), optional The variance threshold for flagging a station. The default is None. buddy_max_elev_diff : num, optional The maximum difference in elevation for a buddy (if negative will not check for heigh difference). The default is None. buddy_elev_gradient : num, optional Linear elevation temperature gradient with height. The default is None. buddy_min_std : num (> 0), optional If the standard deviation of values in a neighborhood are less than min_std, min_std will be used instead. The default is None. buddy_num_iterations : int (> 0), optional The number of iterations to perform. The default is None. buddy_debug : bool, optional If True, print out debug information. The default is None. sct_num_min_outer : int (> 0), optional Minimal points in outer circle. The default is None. sct_num_max_outer : int (> 0), optional Maximal points in outer circle. The default is None. sct_inner_radius : num (> 0), optional Radius of inner circle. The default is None. sct_outer_radius : num (> 0), optional Radius of outer circle. The default is None. sct_num_iterations : int (> 0), optional Number of iterations. The default is None. sct_num_min_prof : int (> 0), optional Minimum number of observations to compute vertical profile. The default is None. sct_min_elev_diff : num (> 0), optional Minimum elevation difference to compute vertical profile. The default is None. sct_min_horizontal_scale : num (> 0), optional Minimum horizontal decorrelation length. The default is None. sct_max_horizontal_scale : num (> 0), optional Maximum horizontal decorrelation length. The default is None. sct_kth_closest_obs_horizontal_scale : int (> 0), optional Number of closest observations to consider. The default is None. sct_vertical_scale : num (> 0), optional Vertical decorrelation length. The default is None. sct_mina_deviation : num (> 0), optional Minimum admissible value deviation. The default is None. sct_maxa_deviation : num (> 0), optional Maximum admissible value deviation. The default is None. sct_minv_deviation : num (> 0), optional Minimum valid value deviation. The default is None. sct_maxv_deviation : num (> 0), optional Maximum valid value deviation. The default is None. sct_eps2 : num (> 0), optional Ratio of observation error variance to background variance. The default is None. sct_tpos : num (> 0), optional Positive deviation allowed. The default is None. sct_tneg : num (> 0), optional Positive deviation allowed. The default is None. sct_basic : bool, optional Basic mode. The default is None. sct_debug : bool, optional If True, print out debug information. The default is None. Returns ------- None. """ assert ( obstype in self.obstypes.keys() ), f"{obstype} is not a known observation type" # check buddy settings for updates buddy_attrs = { "buddy_radius": {"new_value": buddy_radius, "dtype": "numeric"}, "buddy_num_min": {"new_value": buddy_num_min, "dtype": "int"}, "buddy_threshold": {"new_value": buddy_threshold, "dtype": "numeric"}, "buddy_max_elev_diff": { "new_value": buddy_max_elev_diff, "dtype": "numeric", }, "buddy_elev_gradient": { "new_value": buddy_elev_gradient, "dtype": "numeric", }, "buddy_min_std": {"new_value": buddy_min_std, "dtype": "numeric"}, "buddy_num_iterations": {"new_value": buddy_num_iterations, "dtype": "int"}, "buddy_debug": {"new_value": buddy_debug, "dtype": "bool"}, } sct_attrs = { "sct_num_min_outer": {"new_value": sct_num_min_outer, "dtype": "int"}, "sct_num_max_outer": {"new_value": sct_num_max_outer, "dtype": "int"}, "sct_inner_radius": {"new_value": sct_inner_radius, "dtype": "numeric"}, "sct_outer_radius": {"new_value": sct_outer_radius, "dtype": "numeric"}, "sct_num_iterations": {"new_value": sct_num_iterations, "dtype": "int"}, "sct_num_min_prof": {"new_value": sct_num_min_prof, "dtype": "int"}, "sct_min_elev_diff": {"new_value": sct_min_elev_diff, "dtype": "numeric"}, "sct_min_horizontal_scale": { "new_value": sct_min_horizontal_scale, "dtype": "numeric", }, "sct_max_horizontal_scale": { "new_value": sct_max_horizontal_scale, "dtype": "numeric", }, "sct_kth_closest_obs_horizontal_scale": { "new_value": sct_kth_closest_obs_horizontal_scale, "dtype": "int", }, "sct_vertical_scale": {"new_value": sct_vertical_scale, "dtype": "numeric"}, "sct_mina_deviation": {"new_value": sct_mina_deviation, "dtype": "numeric"}, "sct_minv_deviation": {"new_value": sct_minv_deviation, "dtype": "numeric"}, "sct_maxv_deviation": {"new_value": sct_maxv_deviation, "dtype": "numeric"}, "sct_eps2": {"new_value": sct_eps2, "dtype": "numeric"}, "sct_tpos": {"new_value": sct_tpos, "dtype": "numeric"}, "sct_tneg": {"new_value": sct_tneg, "dtype": "numeric"}, "sct_basic": {"new_value": sct_basic, "dtype": "bool"}, "sct_debug": {"new_value": sct_debug, "dtype": "bool"}, } def _iterate_attributes(obstype, attr_dict, attr_prefix, checkname): if obstype not in self.settings.qc["titan_check_settings"][checkname]: self.settings.qc["titan_check_settings"][checkname][obstype] = {} for key, val in attr_dict.items(): if not val["new_value"] is None: settings_key = key.split(attr_prefix)[1] # remove 'buddy_' if val["dtype"] == "numeric": new_val = float(val["new_value"]) elif val["dtype"] == "int": new_val = int(val["new_value"]) elif val["dtype"] == "bool": new_val = bool(val["new_value"]) else: # val['dtype'] == 'str': new_val = str(val["new_value"]) try: old_value = self.settings.qc["titan_check_settings"][checkname][ obstype ][settings_key] print( f'{key.replace("_", " ")} for the TITAN buddy check updated: {old_value}--> {new_val}' ) except KeyError: print( f'{key.replace("_", " ")} for the TITAN buddy check added: --> {new_val}' ) self.settings.qc["titan_check_settings"][checkname][obstype][ settings_key ] = new_val _iterate_attributes(obstype, buddy_attrs, "buddy_", "titan_buddy_check") _iterate_attributes(obstype, sct_attrs, "sct_", "titan_sct_resistant_check")
# ============================================================================= # dtype check functions # ============================================================================= def is_timedelta(timedeltastr): """Test if string can be timedelta representation. Parameters ---------- timedeltastr : str Representation of timedelta. Returns ------- bool """ try: pd.to_timedelta(timedeltastr) return True except ValueError: return False