def create_subtitles(pj: dict, selected_observations: list, parameters: dict, export_dir: str) -> tuple: """ create subtitles for selected observations, subjects and behaviors Args: pj (dict): project selected_observations (list): list of observations parameters (dict): export_dir (str): directory to save subtitles Returns: bool: True if OK else False str: error message """ def subject_color(subject): """ subject color Args: subject (str): subject name Returns: str: HTML tag for color font (beginning) str: HTML tag for color font (closing) """ if subject == NO_FOCAL_SUBJECT: return "", "" else: return ( """<font color="{}">""".format( subtitlesColors[parameters["selected subjects"].index( row["subject"]) % len(subtitlesColors)]), "</font>", ) try: ok, msg, db_connector = db_functions.load_aggregated_events_in_db( pj, parameters["selected subjects"], selected_observations, parameters["selected behaviors"]) if not ok: return False, msg cursor = db_connector.cursor() flag_ok = True msg = "" for obsId in selected_observations: if pj[OBSERVATIONS][obsId][TYPE] in [LIVE]: out = "" cursor.execute( ("SELECT subject, behavior, start, stop, type, modifiers FROM aggregated_events " "WHERE observation = ? AND subject in ({}) " "AND behavior in ({}) " "ORDER BY start").format( ",".join(["?"] * len(parameters["selected subjects"])), ",".join(["?"] * len(parameters["selected behaviors"]))), [obsId] + parameters["selected subjects"] + parameters["selected behaviors"], ) for idx, row in enumerate(cursor.fetchall()): col1, col2 = subject_color(row["subject"]) if parameters["include modifiers"]: modifiers_str = "\n{}".format(row["modifiers"].replace( "|", ", ")) else: modifiers_str = "" out += ("{idx}\n" "{start} --> {stop}\n" "{col1}{subject}: {behavior}" "{modifiers}" "{col2}\n\n").format( idx=idx + 1, start=utilities.seconds2time( row["start"]).replace(".", ","), stop=utilities.seconds2time( row["stop"] if row["type"] == STATE else row["stop"] + POINT_EVENT_ST_DURATION).replace(".", ","), col1=col1, col2=col2, subject=row["subject"], behavior=row["behavior"], modifiers=modifiers_str, ) ''' file_name = str(pathlib.Path(pathlib.Path(export_dir) / utilities.safeFileName(obsId)).with suffix(".srt")) ''' file_name = f"{pathlib.Path(export_dir) / utilities.safeFileName(obsId)}.srt" try: with open(file_name, "w") as f: f.write(out) except Exception: flag_ok = False msg += "observation: {}\ngave the following error:\n{}\n".format( obsId, str(sys.exc_info()[1])) elif pj[OBSERVATIONS][obsId][TYPE] in [MEDIA]: for nplayer in ALL_PLAYERS: if not pj[OBSERVATIONS][obsId][FILE][nplayer]: continue init = 0 for mediaFile in pj[OBSERVATIONS][obsId][FILE][nplayer]: try: end = init + pj[OBSERVATIONS][obsId][MEDIA_INFO][ LENGTH][mediaFile] except KeyError: return False, f"The length for media file {mediaFile} is not available" out = "" cursor.execute( ("SELECT subject, behavior, type, start, stop, modifiers FROM aggregated_events " "WHERE observation = ? AND start BETWEEN ? and ? " "AND subject in ({}) " "AND behavior in ({}) " "ORDER BY start").format( ",".join( ["?"] * len(parameters["selected subjects"])), ",".join( ["?"] * len(parameters["selected behaviors"])), ), [obsId, init, end] + parameters["selected subjects"] + parameters["selected behaviors"], ) for idx, row in enumerate(cursor.fetchall()): col1, col2 = subject_color(row["subject"]) if parameters["include modifiers"]: modifiers_str = "\n{}".format( row["modifiers"].replace("|", ", ")) else: modifiers_str = "" out += ( "{idx}\n" "{start} --> {stop}\n" "{col1}{subject}: {behavior}" "{modifiers}" "{col2}\n\n").format( idx=idx + 1, start=utilities.seconds2time(row["start"] - init).replace( ".", ","), stop=utilities.seconds2time( (row["stop"] if row["type"] == STATE else row["stop"] + POINT_EVENT_ST_DURATION) - init).replace(".", ","), col1=col1, col2=col2, subject=row["subject"], behavior=row["behavior"], modifiers=modifiers_str, ) ''' file_name = str(pathlib.Path(pathlib.Path(export_dir) / pathlib.Path(mediaFile).name).with suffix(".srt")) ''' file_name = f"{pathlib.Path(export_dir) / pathlib.Path(mediaFile).name}.srt" try: with open(file_name, "w") as f: f.write(out) except Exception: flag_ok = False msg += f"observation: {obsId}\ngave the following error:\n{sys.exc_info()[1]}\n" init = end return flag_ok, msg except Exception: return False, str(sys.exc_info()[1])
def check_state_events_obs(obsId: str, ethogram: dict, observation: dict, time_format: str = HHMMSS) -> tuple: """ check state events for the observation obsId check if behaviors in observation are defined in ethogram check if number is odd Args: obsId (str): id of observation to check ethogram (dict): ethogram of project observation (dict): observation to be checked time_format (str): time format Returns: tuple (bool, str): if OK True else False , message """ out = "" # check if behaviors are defined as "state event" event_types = {ethogram[idx]["type"] for idx in ethogram} if not event_types or event_types == {"Point event"}: return (True, "No behavior is defined as `State event`") flagStateEvent = False subjects = [ event[EVENT_SUBJECT_FIELD_IDX] for event in observation[EVENTS] ] ethogram_behaviors = {ethogram[idx][BEHAVIOR_CODE] for idx in ethogram} for subject in sorted(set(subjects)): behaviors = [ event[EVENT_BEHAVIOR_FIELD_IDX] for event in observation[EVENTS] if event[EVENT_SUBJECT_FIELD_IDX] == subject ] for behavior in sorted(set(behaviors)): if behavior not in ethogram_behaviors: # return (False, "The behaviour <b>{}</b> is not defined in the ethogram.<br>".format(behavior)) continue else: if STATE in event_type(behavior, ethogram).upper(): flagStateEvent = True lst, memTime = [], {} for event in [ event for event in observation[EVENTS] if event[EVENT_BEHAVIOR_FIELD_IDX] == behavior and event[EVENT_SUBJECT_FIELD_IDX] == subject ]: behav_modif = [ event[EVENT_BEHAVIOR_FIELD_IDX], event[EVENT_MODIFIER_FIELD_IDX] ] if behav_modif in lst: lst.remove(behav_modif) del memTime[str(behav_modif)] else: lst.append(behav_modif) memTime[str( behav_modif)] = event[EVENT_TIME_FIELD_IDX] for event in lst: out += ( 'The behavior <b>{behavior}</b> {modifier} is not PAIRED for subject' ' "<b>{subject}</b>" at <b>{time}</b><br>').format( behavior=behavior, modifier=("(modifier " + event[1] + ") ") if event[1] else "", subject=subject if subject else NO_FOCAL_SUBJECT, time=memTime[str(event)] if time_format == S else utilities.seconds2time(memTime[str(event)]), ) return (False, out) if out else (True, "No problem detected")
def test_gt_86400(self): assert utilities.seconds2time(Decimal(86400.999)) == "24:00:00.999"
def test_10(self): assert utilities.seconds2time(Decimal(10.0)) == "00:00:10.000"
def test_negative(self): assert utilities.seconds2time(Decimal(-2.123)) == "-00:00:02.123"