def open_project_json(projectFileName: str) -> tuple: """ open BORIS project file in json format or GZ compressed json format Args: projectFileName (str): path of project Returns: str: project path bool: True if project changed dict: BORIS project str: message """ logging.debug(f"open project: {projectFileName}") projectChanged = False msg = "" if not os.path.isfile(projectFileName): return projectFileName, projectChanged, { "error": f"File {projectFileName} not found" }, msg try: if projectFileName.endswith(".boris.gz"): file_in = gzip.open(projectFileName, mode="rt", encoding="utf-8") else: file_in = open(projectFileName, "r") file_content = file_in.read() except PermissionError: return projectFileName, projectChanged, { f"error": f"File {projectFileName}: Permission denied" }, msg except Exception: return projectFileName, projectChanged, { f"error": f"Error on file {projectFileName}: {sys.exc_info()[1]}" }, msg try: pj = json.loads(file_content) except json.decoder.JSONDecodeError: return projectFileName, projectChanged, { "error": "This project file seems corrupted" }, msg except Exception: return projectFileName, projectChanged, { f"error": f"Error on file {projectFileName}: {sys.exc_info()[1]}" }, msg # transform time to decimal pj = utilities.convert_time_to_decimal(pj) # add coding_map key to old project files if "coding_map" not in pj: pj["coding_map"] = {} projectChanged = True # add subject description if "project_format_version" in pj: for idx in [x for x in pj[SUBJECTS]]: if "description" not in pj[SUBJECTS][idx]: pj[SUBJECTS][idx]["description"] = "" projectChanged = True # check if project file version is newer than current BORIS project file version if "project_format_version" in pj and dec( pj["project_format_version"]) > dec(project_format_version): return ( projectFileName, projectChanged, { "error": ("This project file was created with a more recent version of BORIS.<br>" f"You must update BORIS to <b>v. >= {pj['project_format_version']}</b> to open this project" ) }, msg, ) # check if old version v. 0 *.obs if "project_format_version" not in pj: # convert VIDEO, AUDIO -> MEDIA pj["project_format_version"] = project_format_version projectChanged = True for obs in [x for x in pj[OBSERVATIONS]]: # remove 'replace audio' key if "replace audio" in pj[OBSERVATIONS][obs]: del pj[OBSERVATIONS][obs]["replace audio"] if pj[OBSERVATIONS][obs][TYPE] in ["VIDEO", "AUDIO"]: pj[OBSERVATIONS][obs][TYPE] = MEDIA # convert old media list in new one if len(pj[OBSERVATIONS][obs][FILE]): d1 = {PLAYER1: [pj[OBSERVATIONS][obs][FILE][0]]} if len(pj[OBSERVATIONS][obs][FILE]) == 2: d1[PLAYER2] = [pj[OBSERVATIONS][obs][FILE][1]] pj[OBSERVATIONS][obs][FILE] = d1 # convert VIDEO, AUDIO -> MEDIA for idx in [x for x in pj[SUBJECTS]]: key, name = pj[SUBJECTS][idx] pj[SUBJECTS][idx] = {"key": key, "name": name, "description": ""} msg = ( f"The project file was converted to the new format (v. {project_format_version}) in use with your version of BORIS.<br>" "Choose a new file name for saving it.") projectFileName = "" # update modifiers to JSON format # check if project format version < 4 (modifiers were str) project_lowerthan4 = False if "project_format_version" in pj and utilities.versiontuple( pj["project_format_version"]) < utilities.versiontuple("4.0"): for idx in pj[ETHOGRAM]: if pj[ETHOGRAM][idx]["modifiers"]: if isinstance(pj[ETHOGRAM][idx]["modifiers"], str): project_lowerthan4 = True modif_set_list = pj[ETHOGRAM][idx]["modifiers"].split("|") modif_set_dict = {} for modif_set in modif_set_list: modif_set_dict[str(len(modif_set_dict))] = { "name": "", "type": SINGLE_SELECTION, "values": modif_set.split(",") } pj[ETHOGRAM][idx]["modifiers"] = dict(modif_set_dict) else: pj[ETHOGRAM][idx]["modifiers"] = {} if not project_lowerthan4: msg = "The project version was updated from {} to {}".format( pj["project_format_version"], project_format_version) pj["project_format_version"] = project_format_version projectChanged = True # add category key if not found for idx in pj[ETHOGRAM]: if "category" not in pj[ETHOGRAM][idx]: pj[ETHOGRAM][idx]["category"] = "" # if one file is present in player #1 -> set "media_info" key with value of media_file_info for obs in pj[OBSERVATIONS]: if pj[OBSERVATIONS][obs][TYPE] in [ MEDIA ] and MEDIA_INFO not in pj[OBSERVATIONS][obs]: pj[OBSERVATIONS][obs][MEDIA_INFO] = { LENGTH: {}, "fps": {}, "hasVideo": {}, "hasAudio": {} } for player in [PLAYER1, PLAYER2]: # fix bug Anne Maijer 2017-07-17 if pj[OBSERVATIONS][obs][FILE] == []: pj[OBSERVATIONS][obs][FILE] = {"1": [], "2": []} for media_file_path in pj[OBSERVATIONS][obs]["file"][player]: # FIX: ffmpeg path ret, msg = utilities.check_ffmpeg_path() if not ret: return projectFileName, projectChanged, { "error": "FFmpeg path not found" }, "" else: ffmpeg_bin = msg r = utilities.accurate_media_analysis( ffmpeg_bin, media_file_path) if "duration" in r and r["duration"]: pj[OBSERVATIONS][obs][MEDIA_INFO][LENGTH][ media_file_path] = float(r["duration"]) pj[OBSERVATIONS][obs][MEDIA_INFO][FPS][ media_file_path] = float(r["fps"]) pj[OBSERVATIONS][obs][MEDIA_INFO]["hasVideo"][ media_file_path] = r["has_video"] pj[OBSERVATIONS][obs][MEDIA_INFO]["hasAudio"][ media_file_path] = r["has_audio"] project_updated, projectChanged = True, True else: # file path not found if ("media_file_info" in pj[OBSERVATIONS][obs] and len( pj[OBSERVATIONS][obs]["media_file_info"]) == 1 and len( pj[OBSERVATIONS][obs][FILE][PLAYER1]) == 1 and len(pj[OBSERVATIONS][obs][FILE][PLAYER2]) == 0): media_md5_key = list(pj[OBSERVATIONS][obs] ["media_file_info"].keys())[0] # duration pj[OBSERVATIONS][obs][MEDIA_INFO] = { LENGTH: { media_file_path: pj[OBSERVATIONS][obs]["media_file_info"] [media_md5_key]["video_length"] / 1000 } } projectChanged = True # FPS if "nframe" in pj[OBSERVATIONS][obs][ "media_file_info"][media_md5_key]: pj[OBSERVATIONS][obs][MEDIA_INFO][FPS] = { media_file_path: pj[OBSERVATIONS][obs]["media_file_info"] [media_md5_key]["nframe"] / (pj[OBSERVATIONS][obs]["media_file_info"] [media_md5_key]["video_length"] / 1000) } else: pj[OBSERVATIONS][obs][MEDIA_INFO][FPS] = { media_file_path: 0 } # update project to v.7 for time offset second player project_lowerthan7 = False for obs in pj[OBSERVATIONS]: if "time offset second player" in pj[OBSERVATIONS][obs]: if MEDIA_INFO not in pj[OBSERVATIONS][obs]: pj[OBSERVATIONS][obs][MEDIA_INFO] = {} if "offset" not in pj[OBSERVATIONS][obs][MEDIA_INFO]: pj[OBSERVATIONS][obs][MEDIA_INFO]["offset"] = {} for player in pj[OBSERVATIONS][obs][FILE]: pj[OBSERVATIONS][obs][MEDIA_INFO]["offset"][player] = 0.0 if pj[OBSERVATIONS][obs]["time offset second player"]: pj[OBSERVATIONS][obs][MEDIA_INFO]["offset"]["2"] = float( pj[OBSERVATIONS][obs]["time offset second player"]) del pj[OBSERVATIONS][obs]["time offset second player"] project_lowerthan7 = True msg = ( f"The project file was converted to the new format (v. {project_format_version}) in use with your version of BORIS.<br>" f"Please note that this new version will NOT be compatible with previous BORIS versions " f"(< v. {project_format_version}).<br>") projectChanged = True if project_lowerthan7: msg = ( f"The project was updated to the current project version ({project_format_version})." ) try: old_project_file_name = projectFileName.replace( ".boris", f".v{pj['project_format_version']}.boris") copyfile(projectFileName, old_project_file_name) msg += f"\n\nThe old file project was saved as {old_project_file_name}" except Exception: pass pj["project_format_version"] = project_format_version return projectFileName, projectChanged, pj, msg
def test_4(self): r = utilities.versiontuple("") assert r == ()
def test_2(self): r = utilities.versiontuple("1.2") assert r == (1, 2)
def test_3(self): r = utilities.versiontuple("1") assert r == (1, )
def test_1(self): r = utilities.versiontuple("1.2.3") assert r == (1, 2, 3)