Skip to content

deeplabcut.utils.auxiliaryfunctions

DeepLabCut2.0 Toolbox (deeplabcut.org) © A. & M. Mathis Labs https://github.com/DeepLabCut/DeepLabCut Please see AUTHORS for contributors.

https://github.com/DeepLabCut/DeepLabCut/blob/master/AUTHORS Licensed under GNU Lesser General Public License v3.0

Functions:

Name Description
attempt_to_make_folder

Attempts to create a folder with specified name.

check_if_post_processing

Checks if filtered/bone lengths were already calculated.

filter_files_by_patterns

Filters files in a folder based on start, contain, and end patterns.

find_analyzed_data

Find potential data files from the hints given to the function.

find_video_metadata

For backward compatibility, let us search the substring 'meta'.

get_bodyparts

Get the bodyparts.

get_data_and_metadata_filenames

Paths to data and metadata files relative to the project root.

get_deeplabcut_path

Get path of where deeplabcut is currently running.

get_evaluation_folder

Get the evaluation folder.

get_model_folder

Get the model folder.

get_scorer_name

Extract the scorer/network name for a particular shuffle, training fraction, etc.

get_snapshots_from_folder

Returns an ordered list of existing snapshot names in the train folder, sorted by

get_training_set_folder

Training Set folder for config file based on parameters.

get_unique_bodyparts

Get the unique bodyparts.

get_video_list

Get list of videos in a path (if filetype == all), otherwise just a specific

grab_files_in_folder

Return the paths of files with extension ext present in folder.

intersection_of_body_parts_and_ones_given_by_user

Returns all body parts when comparisonbodyparts=='all', otherwise all bpts that

read_pickle

Read the pickle file.

read_plainconfig

Load a YAML config (alias for read_config_as_dict). See deeplabcut.core.config.

safe_resolve

Return a resolved Path that is safe to use with str-based I/O.

save_data

Save predicted data as h5 file and metadata as pickle file; created by

write_pickle

Write the pickle file.

write_plainconfig

Write a config dict to YAML (alias for write_config). See deeplabcut.core.config.

attempt_to_make_folder

attempt_to_make_folder(foldername, recursive=False)

Attempts to create a folder with specified name.

Does nothing if it already exists.

Source code in deeplabcut/utils/auxiliaryfunctions.py
def attempt_to_make_folder(foldername, recursive=False):
    """Attempts to create a folder with specified name.

    Does nothing if it already exists.
    """
    foldername = Path(foldername)

    if foldername.is_dir():
        return

    if recursive:
        foldername.mkdir(parents=True, exist_ok=True)
    else:
        foldername.mkdir(exist_ok=True, parents=True)

check_if_post_processing

check_if_post_processing(folder, vname, DLCscorer, DLCscorerlegacy, suffix='filtered')

Checks if filtered/bone lengths were already calculated.

If not, figures out if data was already analyzed (either with legacy scorer name or new one!)

Source code in deeplabcut/utils/auxiliaryfunctions.py
def check_if_post_processing(folder, vname, DLCscorer, DLCscorerlegacy, suffix="filtered"):
    """Checks if filtered/bone lengths were already calculated.

    If not, figures out if data was already analyzed (either with legacy scorer name or
    new one!)
    """
    folder = Path(folder)
    outdataname = str(folder / (vname + DLCscorer + suffix + ".h5"))
    sourcedataname = str(folder / (vname + DLCscorer + ".h5"))
    if Path(outdataname).is_file():  # was data already processed?
        if suffix == "filtered":
            print("Video already filtered...", outdataname)
        elif suffix == "_skeleton":
            print("Skeleton in video already processed...", outdataname)

        return False, outdataname, sourcedataname, DLCscorer
    else:
        odn = str(folder / (vname + DLCscorerlegacy + suffix + ".h5"))
        if Path(odn).is_file():  # was it processed by DLC <2.1 project?
            if suffix == "filtered":
                print("Video already filtered...(with DLC<2.1)!", odn)
            elif suffix == "_skeleton":
                print("Skeleton in video already processed... (with DLC<2.1)!", odn)
            return False, odn, odn, DLCscorerlegacy
        else:
            sdn = str(folder / (vname + DLCscorerlegacy + ".h5"))
            tracks = sourcedataname.replace(".h5", "tracks.h5")
            if Path(sourcedataname).is_file():  # Was the video already analyzed?
                return True, outdataname, sourcedataname, DLCscorer
            elif Path(sdn).is_file():  # was it analyzed with DLC<2.1?
                return True, odn, sdn, DLCscorerlegacy
            elif Path(tracks).is_file():  # May be a MA project with tracklets
                return True, tracks.replace(".h5", f"{suffix}.h5"), tracks, DLCscorer
            else:
                print("Video not analyzed -- Run analyze_videos first.")
                return False, outdataname, sourcedataname, DLCscorer

filter_files_by_patterns

filter_files_by_patterns(
    folder: str | Path,
    start_patterns: set[str] | None = None,
    contain_patterns: set[str] | None = None,
    end_patterns: set[str] | None = None,
) -> list[Path]

Filters files in a folder based on start, contain, and end patterns.

Parameters:

Name Type Description Default

folder

str | Path

The folder to search for files.

required

start_patterns

Set[str] | None

Patterns the filenames should start with. If None or empty, this pattern is not taken into account.

None

contain_patterns

set[str]

Patterns the filenames should contain. If None or empty, this pattern is not taken into account.

None

end_patterns

set[str]

Patterns the filenames should end with. If None or empty, this pattern is not taken into account.

None

Returns:

Type Description
list[Path]

List[Path]: List of files that match the criteria.

Source code in deeplabcut/utils/auxiliaryfunctions.py
def filter_files_by_patterns(
    folder: str | Path,
    start_patterns: set[str] | None = None,
    contain_patterns: set[str] | None = None,
    end_patterns: set[str] | None = None,
) -> list[Path]:
    """Filters files in a folder based on start, contain, and end patterns.

    Args:
        folder (str | Path): The folder to search for files.

        start_patterns (Set[str] | None): Patterns the filenames should start with.
            If None or empty, this pattern is not taken into account.

        contain_patterns (set[str]): Patterns the filenames should contain.
            If None or empty, this pattern is not taken into account.

        end_patterns (set[str]): Patterns the filenames should end with.
            If None or empty, this pattern is not taken into account.

    Returns:
        List[Path]: List of files that match the criteria.
    """
    folder = Path(folder)  # Ensure the folder is a Path object
    if not folder.is_dir():
        raise ValueError(f"{folder} is not a valid directory.")

    # Filter files based on the given patterns
    matching_files = [
        file
        for file in folder.iterdir()
        if file.is_file()
        and (not start_patterns or any(file.name.startswith(start) for start in start_patterns))
        and (not contain_patterns or any(contain in file.name for contain in contain_patterns))
        and (not end_patterns or any(file.name.endswith(end) for end in end_patterns))
    ]

    return matching_files

find_analyzed_data

find_analyzed_data(folder, videoname: str, scorer: str, filtered=False, track_method='')

Find potential data files from the hints given to the function.

Source code in deeplabcut/utils/auxiliaryfunctions.py
def find_analyzed_data(folder, videoname: str, scorer: str, filtered=False, track_method=""):
    """Find potential data files from the hints given to the function."""
    scorer_legacy = scorer.replace("DLC", "DeepCut")
    suffix = "_filtered" if filtered else ""
    tracker = TRACK_METHODS.get(track_method, "")

    candidates = []
    for file in collect_video_paths(folder, extensions=".h5"):
        stem = file.stem.replace("_filtered", "")
        starts_by_scorer = file.name.startswith((videoname + scorer, videoname + scorer_legacy))
        if tracker:
            matches_tracker = stem.endswith(tracker)
        else:
            matches_tracker = not any(stem.endswith(s) for s in TRACK_METHODS.values())
        if all(
            (
                starts_by_scorer,
                "skeleton" not in file.name,
                matches_tracker,
                (filtered and "filtered" in file.name) or (not filtered and "filtered" not in file.name),
            )
        ):
            candidates.append(file)

    if not len(candidates):
        msg = (
            f"No {'un' if not filtered else ''}filtered data file found in {folder} "
            f"for video {videoname} and scorer {scorer}"
        )
        if track_method:
            msg += f" and {track_method} tracker"
        msg += "."
        raise FileNotFoundError(msg)

    n_candidates = len(candidates)
    if n_candidates > 1:  # This should not be happening anyway...
        print(f"{n_candidates} possible data files were found: {candidates}.\nPicking the first by default...")
    filepath = str(candidates[0])
    scorer = scorer if scorer in filepath else scorer_legacy
    return filepath, scorer, suffix

find_video_metadata

find_video_metadata(folder, videoname: str, scorer: str)

For backward compatibility, let us search the substring 'meta'.

Source code in deeplabcut/utils/auxiliaryfunctions.py
def find_video_metadata(folder, videoname: str, scorer: str):
    """For backward compatibility, let us search the substring 'meta'."""
    scorer_legacy = scorer.replace("DLC", "DeepCut")
    meta_files = filter_files_by_patterns(
        folder=folder,
        start_patterns={videoname + scorer, videoname + scorer_legacy},
        contain_patterns={"meta"},
        end_patterns={"pickle"},
    )
    if not meta_files:
        raise FileNotFoundError(f"No metadata found in {folder} for video {videoname} and scorer {scorer}.")
    return meta_files[0]

get_bodyparts

get_bodyparts(cfg: dict) -> list[str]

Get the bodyparts.

Parameters:

Name Type Description Default

cfg

dict

a project configuration file

required

Returns: bodyparts listed in the project (does not include the unique_bodyparts entry)

Source code in deeplabcut/utils/auxiliaryfunctions.py
def get_bodyparts(cfg: dict) -> list[str]:
    """Get the bodyparts.

    Args:
        cfg: a project configuration file

    Returns: bodyparts listed in the project (does not include the unique_bodyparts entry)
    """
    if cfg.get("multianimalproject", False):
        (
            _,
            _,
            multianimal_bodyparts,
        ) = auxfun_multianimal.extractindividualsandbodyparts(cfg)
        return multianimal_bodyparts

    return cfg["bodyparts"]

get_data_and_metadata_filenames

get_data_and_metadata_filenames(
    trainingsetfolder: str | Path, trainFraction: float, shuffle: int, cfg: dict
) -> tuple[Path, Path]

Paths to data and metadata files relative to the project root.

Source code in deeplabcut/utils/auxiliaryfunctions.py
def get_data_and_metadata_filenames(
    trainingsetfolder: str | Path,
    trainFraction: float,
    shuffle: int,
    cfg: dict,
) -> tuple[Path, Path]:
    """Paths to data and metadata files relative to the project root."""
    base = Path(trainingsetfolder)
    datafn = base / (
        cfg["Task"] + "_" + cfg["scorer"] + str(int(100 * trainFraction)) + "shuffle" + str(shuffle) + ".mat"
    )
    metadatafn = base / (
        "Documentation_data-" + cfg["Task"] + "_" + str(int(trainFraction * 100)) + "shuffle" + str(shuffle) + ".pickle"
    )
    return datafn, metadatafn

get_deeplabcut_path

get_deeplabcut_path() -> Path

Get path of where deeplabcut is currently running.

Source code in deeplabcut/utils/auxiliaryfunctions.py
def get_deeplabcut_path() -> Path:
    """Get path of where deeplabcut is currently running."""
    import importlib.util

    return Path(importlib.util.find_spec("deeplabcut").origin).parent

get_evaluation_folder

get_evaluation_folder(
    trainFraction: float, shuffle: int, cfg: dict, engine: Engine | None = None, modelprefix: str = ""
) -> Path

Get the evaluation folder.

Parameters:

Name Type Description Default

trainFraction

float

the training fraction (as defined in the project configuration) for which to get the evaluation folder

required

shuffle

int

the index of the shuffle for which to get the evaluation folder

required

cfg

dict

the project configuration

required

engine

Engine | None

The engine for which we want the model folder. Defaults to None, which automatically gets the engine for the shuffle from the training dataset metadata file.

None

modelprefix

str

The name of the folder

''

Returns:

Type Description
Path

the relative path from the project root to the folder containing the model files for a shuffle (configuration files, snapshots, training logs, ...)

Source code in deeplabcut/utils/auxiliaryfunctions.py
def get_evaluation_folder(
    trainFraction: float,
    shuffle: int,
    cfg: dict,
    engine: Engine | None = None,
    modelprefix: str = "",
) -> Path:
    """Get the evaluation folder.

    Args:
        trainFraction: the training fraction (as defined in the project configuration)
            for which to get the evaluation folder
        shuffle: the index of the shuffle for which to get the evaluation folder
        cfg: the project configuration
        engine: The engine for which we want the model folder. Defaults to None,
            which automatically gets the engine for the shuffle from the training
            dataset metadata file.
        modelprefix: The name of the folder

    Returns:
        the relative path from the project root to the folder containing the model files
        for a shuffle (configuration files, snapshots, training logs, ...)
    """
    if engine is None:
        from deeplabcut.generate_training_dataset.metadata import get_shuffle_engine

        engine = get_shuffle_engine(
            cfg=cfg,
            trainingsetindex=cfg["TrainingFraction"].index(trainFraction),
            shuffle=shuffle,
            modelprefix=modelprefix,
        )

    Task = cfg["Task"]
    date = cfg["date"]
    iterate = "iteration-" + str(cfg["iteration"])
    if "eval_prefix" in cfg:
        eval_prefix = cfg["eval_prefix"]
    else:
        eval_prefix = engine.results_folder_name
    return Path(
        modelprefix,
        eval_prefix,
        iterate,
        Task + date + "-trainset" + str(int(trainFraction * 100)) + "shuffle" + str(shuffle),
    )

get_model_folder

get_model_folder(
    trainFraction: float, shuffle: int, cfg: dict, modelprefix: str = "", engine: Engine = Engine.TF
) -> Path

Get the model folder.

Parameters:

Name Type Description Default

trainFraction

float

the training fraction (as defined in the project configuration) for which to get the model folder

required

shuffle

int

the index of the shuffle for which to get the model folder

required

cfg

dict

the project configuration

required

modelprefix

str

The name of the folder

''

engine

Engine

The engine for which we want the model folder. Defaults to tensorflow for backwards compatibility with DeepLabCut 2.X

TF

Returns:

Type Description
Path

the relative path from the project root to the folder containing the model files for a shuffle (configuration files, snapshots, training logs, ...)

Source code in deeplabcut/utils/auxiliaryfunctions.py
def get_model_folder(
    trainFraction: float,
    shuffle: int,
    cfg: dict,
    modelprefix: str = "",
    engine: Engine = Engine.TF,
) -> Path:
    """Get the model folder.

    Args:
        trainFraction: the training fraction (as defined in the project configuration)
            for which to get the model folder
        shuffle: the index of the shuffle for which to get the model folder
        cfg: the project configuration
        modelprefix: The name of the folder
        engine: The engine for which we want the model folder. Defaults to `tensorflow`
            for backwards compatibility with DeepLabCut 2.X

    Returns:
        the relative path from the project root to the folder containing the model files
        for a shuffle (configuration files, snapshots, training logs, ...)
    """
    proj_id = f"{cfg['Task']}{cfg['date']}"
    return Path(
        modelprefix,
        engine.model_folder_name,
        f"iteration-{cfg['iteration']}",
        f"{proj_id}-trainset{int(trainFraction * 100)}shuffle{shuffle}",
    )

get_scorer_name

get_scorer_name(
    cfg: dict,
    shuffle: int,
    trainFraction: float,
    trainingsiterations: str | int = "unknown",
    modelprefix: str = "",
    engine: Engine | None = None,
    **kwargs
)

Extract the scorer/network name for a particular shuffle, training fraction, etc.

If the engine is not specified, determines which to use from the project configuration.

Parameters:

Name Type Description Default

**kwargs

Additional arguments. For torch-based shuffles, can be used to specify: - snapshot_index - detector_snapshot_index

{}

Returns:

Name Type Description
tuple

DLCscorer and DLCscorerlegacy (old naming convention).

Source code in deeplabcut/utils/auxiliaryfunctions.py
def get_scorer_name(
    cfg: dict,
    shuffle: int,
    trainFraction: float,
    trainingsiterations: str | int = "unknown",
    modelprefix: str = "",
    engine: Engine | None = None,
    **kwargs,
):
    """Extract the scorer/network name for a particular shuffle, training fraction, etc.

    If the engine is not specified, determines which to use from the project
    configuration.

    Args:
        **kwargs: Additional arguments. For torch-based shuffles, can be used to specify:
            - snapshot_index
            - detector_snapshot_index

    Returns:
        tuple: DLCscorer and DLCscorerlegacy (old naming convention).
    """
    if engine is None:
        from deeplabcut.generate_training_dataset.metadata import get_shuffle_engine

        engine = get_shuffle_engine(
            cfg=cfg,
            trainingsetindex=cfg["TrainingFraction"].index(trainFraction),
            shuffle=shuffle,
            modelprefix=modelprefix,
        )

    if engine == Engine.PYTORCH:
        from deeplabcut.pose_estimation_pytorch.apis.utils import get_scorer_name

        snapshot_index = kwargs.get("snapshot_index", None)
        detector_snapshot_index = kwargs.get("detector_snapshot_index", None)
        dlc3_scorer = get_scorer_name(
            cfg=cfg,
            shuffle=shuffle,
            train_fraction=trainFraction,
            snapshot_index=snapshot_index,
            detector_index=detector_snapshot_index,
            modelprefix=modelprefix,
        )
        return dlc3_scorer, dlc3_scorer

    Task = cfg["Task"]
    date = cfg["date"]

    if trainingsiterations == "unknown":
        snapshotindex = get_snapshot_index_for_scorer("snapshotindex", cfg["snapshotindex"])
        model_folder = get_model_folder(trainFraction, shuffle, cfg, engine=engine, modelprefix=modelprefix)
        train_folder = Path(cfg["project_path"]) / model_folder / "train"
        snapshot_names = get_snapshots_from_folder(train_folder)
        snapshot_name = snapshot_names[snapshotindex]
        trainingsiterations = Path(snapshot_name).parts[-1].split("-")[-1]

    dlc_cfg = read_plainconfig(
        str(
            Path(cfg["project_path"])
            / get_model_folder(trainFraction, shuffle, cfg, engine=engine, modelprefix=modelprefix)
            / "train"
            / engine.pose_cfg_name
        )
    )
    # ABBREVIATE NETWORK NAMES -- esp. for mobilenet!
    if "resnet" in dlc_cfg["net_type"]:
        if dlc_cfg.get("multi_stage", False):
            netname = "dlcrnetms5"
        else:
            netname = dlc_cfg["net_type"].replace("_", "")
    elif "mobilenet" in dlc_cfg["net_type"]:  # mobilenet >> mobnet_100; mobnet_35 etc.
        netname = "mobnet_" + str(int(float(dlc_cfg["net_type"].split("_")[-1]) * 100))
    elif "efficientnet" in dlc_cfg["net_type"]:
        netname = "effnet_" + dlc_cfg["net_type"].split("-")[1]
    else:
        raise ValueError(f"Failed to abbreviate network name: {dlc_cfg['net_type']}")

    scorer = "DLC_" + netname + "_" + Task + str(date) + "shuffle" + str(shuffle) + "_" + str(trainingsiterations)
    # legacy scorername until DLC 2.1. (cfg['resnet'] is deprecated / which is why we get the resnet_xyz name from
    # dlc_cfg!
    # scorer_legacy = 'DeepCut' + "_resnet" + str(cfg['resnet']) + "_" + Task + str(date) + 'shuffle' + str(shuffle) +
    # '_' + str(trainingsiterations)
    scorer_legacy = scorer.replace("DLC", "DeepCut")
    return scorer, scorer_legacy

get_snapshots_from_folder

get_snapshots_from_folder(train_folder: Path) -> list[str]

Returns an ordered list of existing snapshot names in the train folder, sorted by increasing training iterations.

Raises:

Type Description
FileNotFoundError

If no snapshot_names are found in the train_folder.

Source code in deeplabcut/utils/auxiliaryfunctions.py
def get_snapshots_from_folder(train_folder: Path) -> list[str]:
    """Returns an ordered list of existing snapshot names in the train folder, sorted by
    increasing training iterations.

    Raises:
        FileNotFoundError: If no snapshot_names are found in the train_folder.
    """
    snapshot_names = [file.stem for file in train_folder.iterdir() if "index" in file.name]

    if len(snapshot_names) == 0:
        raise FileNotFoundError(
            f"No snapshots were found in {train_folder}! Please ensure the network has "
            f"been trained and verify the iteration, shuffle and trainFraction are "
            f"correct."
        )

    # sort in ascending order of iteration number
    return sorted(snapshot_names, key=lambda name: int(name.split("-")[1]))

get_training_set_folder

get_training_set_folder(cfg: dict) -> Path

Training Set folder for config file based on parameters.

Source code in deeplabcut/utils/auxiliaryfunctions.py
def get_training_set_folder(cfg: dict) -> Path:
    """Training Set folder for config file based on parameters."""
    Task = cfg["Task"]
    date = cfg["date"]
    iterate = "iteration-" + str(cfg["iteration"])
    return Path("training-datasets") / iterate / ("UnaugmentedDataSet_" + Task + date)

get_unique_bodyparts

get_unique_bodyparts(cfg: dict) -> list[str]

Get the unique bodyparts.

Parameters:

Name Type Description Default

cfg

dict

a project configuration file

required

Returns: all unique bodyparts listed in the project

Source code in deeplabcut/utils/auxiliaryfunctions.py
def get_unique_bodyparts(cfg: dict) -> list[str]:
    """Get the unique bodyparts.

    Args:
        cfg: a project configuration file

    Returns: all unique bodyparts listed in the project
    """
    if cfg.get("multianimalproject", False):
        (
            _,
            unique_bodyparts,
            _,
        ) = auxfun_multianimal.extractindividualsandbodyparts(cfg)
        return unique_bodyparts

    return []

get_video_list

get_video_list(filename, videopath, videtype)

Get list of videos in a path (if filetype == all), otherwise just a specific file.

Source code in deeplabcut/utils/auxiliaryfunctions.py
@deprecated(replacement="deeplabcut.collect_video_paths", since="3.0.0")
def get_video_list(filename, videopath, videtype):
    """Get list of videos in a path (if filetype == all), otherwise just a specific
    file.
    """
    videos = list(grab_files_in_folder(videopath, videtype))
    if filename == "all":
        return videos
    else:
        if filename in videos:
            videos = [filename]
        else:
            videos = []
            print("Video not found!", filename)
    return videos

grab_files_in_folder

grab_files_in_folder(folder, ext='', relative=True)

Return the paths of files with extension ext present in folder.

Source code in deeplabcut/utils/auxiliaryfunctions.py
@deprecated(replacement="deeplabcut.collect_video_paths", since="3.0.1")
def grab_files_in_folder(folder, ext="", relative=True):
    """Return the paths of files with extension *ext* present in *folder*."""
    for file in Path(folder).iterdir():
        if file.name.endswith(ext):
            yield file.name if relative else str(file)

intersection_of_body_parts_and_ones_given_by_user

intersection_of_body_parts_and_ones_given_by_user(cfg, comparisonbodyparts)

Returns all body parts when comparisonbodyparts=='all', otherwise all bpts that are in the intersection of comparisonbodyparts and the actual bodyparts.

Source code in deeplabcut/utils/auxiliaryfunctions.py
def intersection_of_body_parts_and_ones_given_by_user(cfg, comparisonbodyparts):
    """Returns all body parts when comparisonbodyparts=='all', otherwise all bpts that
    are in the intersection of comparisonbodyparts and the actual bodyparts.
    """
    # if "MULTI!" in allbpts:
    if cfg["multianimalproject"]:
        allbpts = cfg["multianimalbodyparts"] + cfg["uniquebodyparts"]
    else:
        allbpts = cfg["bodyparts"]

    if comparisonbodyparts == "all":
        return list(allbpts)
    else:  # take only items in list that are actually bodyparts...
        cpbpts = [bp for bp in allbpts if bp in comparisonbodyparts]
        # Ensure same order as in config.yaml
        return cpbpts

read_pickle

read_pickle(filename)

Read the pickle file.

Source code in deeplabcut/utils/auxiliaryfunctions.py
def read_pickle(filename):
    """Read the pickle file."""
    with Path(filename).open("rb") as handle:
        return pickle.load(handle)

read_plainconfig

read_plainconfig(configname: str | Path) -> dict

Load a YAML config (alias for read_config_as_dict). See deeplabcut.core.config.

Source code in deeplabcut/utils/auxiliaryfunctions.py
def read_plainconfig(configname: str | Path) -> dict:
    """Load a YAML config (alias for read_config_as_dict). See deeplabcut.core.config."""
    return core_config.read_config_as_dict(config_path=configname)

safe_resolve

safe_resolve(path: Path) -> Path

Return a resolved Path that is safe to use with str-based I/O.

Prefers Path.resolve() so that symlinks are followed (useful on Linux). Falls back to Path.absolute() when resolve() fails or the resolved path cannot be stat'd via its plain string form — e.g. on Windows 11 + SMB network drives where resolve() may return an unusable \?\Volume{GUID}... form.

See https://github.com/DeepLabCut/DeepLabCut/issues/3348

Source code in deeplabcut/utils/auxiliaryfunctions.py
def safe_resolve(path: Path) -> Path:
    """Return a resolved Path that is safe to use with str-based I/O.

    Prefers Path.resolve() so that symlinks are followed (useful on Linux).
    Falls back to Path.absolute() when resolve() fails or the resolved path
    cannot be stat'd via its plain string form — e.g. on Windows 11 + SMB
    network drives where resolve() may return an unusable
    \\\\?\\Volume{GUID}\\... form.

    See https://github.com/DeepLabCut/DeepLabCut/issues/3348
    """
    try:
        resolved = path.resolve()
        os.stat(os.fspath(resolved))
        return resolved
    except OSError as exc:
        fallback = path.absolute()
        logger.debug(
            "safe_resolve: using absolute() fallback for %s (%s)",
            path,
            exc,
        )
        return fallback

save_data

save_data(PredicteData, metadata, dataname, pdindex, imagenames, save_as_csv)

Save predicted data as h5 file and metadata as pickle file; created by predict_videos.py.

Source code in deeplabcut/utils/auxiliaryfunctions.py
def save_data(PredicteData, metadata, dataname, pdindex, imagenames, save_as_csv):
    """Save predicted data as h5 file and metadata as pickle file; created by
    predict_videos.py.
    """
    dataname = Path(dataname)
    DataMachine = pd.DataFrame(PredicteData, columns=pdindex, index=imagenames)
    if save_as_csv:
        print("Saving csv poses!")
        DataMachine.to_csv(dataname.with_suffix(".csv"))
    DataMachine.to_hdf(dataname, key="df_with_missing", format="table", mode="w")
    with dataname.with_name(dataname.stem + "_meta.pickle").open("wb") as f:
        # Pickle the 'data' dictionary using the highest protocol available.
        pickle.dump(metadata, f, pickle.HIGHEST_PROTOCOL)

write_pickle

write_pickle(filename, data)

Write the pickle file.

Source code in deeplabcut/utils/auxiliaryfunctions.py
def write_pickle(filename, data):
    """Write the pickle file."""
    with Path(filename).open("wb") as handle:
        pickle.dump(data, handle, protocol=pickle.HIGHEST_PROTOCOL)

write_plainconfig

write_plainconfig(configname: str | Path, cfg: dict, overwrite: bool = True) -> None

Write a config dict to YAML (alias for write_config). See deeplabcut.core.config.

Source code in deeplabcut/utils/auxiliaryfunctions.py
def write_plainconfig(configname: str | Path, cfg: dict, overwrite: bool = True) -> None:
    """Write a config dict to YAML (alias for write_config). See deeplabcut.core.config."""
    core_config.write_config(config_path=configname, config=cfg, overwrite=overwrite)