Skip to content
Merged
Changes from 1 commit
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
2d41bee
Update `list_video_files_in_folder` only filter explicitly provided f…
deruyter92 May 4, 2026
96e31be
add test for list_videos_in_folder
deruyter92 May 4, 2026
3c63e90
Add deprecation utils: decorator for deprecated functions
deruyter92 May 7, 2026
b92103e
move `list_videos_in_folder` to `collect_video_paths` in auxfun_video…
deruyter92 May 7, 2026
ee4d9b1
export `deeplabcut.collect_video_paths(..)` from auxfun_videos.py
deruyter92 May 8, 2026
2014a59
update `collect_video_paths`: add exclude patterns
deruyter92 May 8, 2026
f6f1ee5
deprecate auxfun `get_list_of_videos` in favor of `collect_video_paths`
deruyter92 May 8, 2026
f6b33d2
add pytest deprecation marker `test_get_list_of_videos`
deruyter92 May 8, 2026
659bf7d
Mark `get_video_list` as deprecated (keep for now for backward compat…
deruyter92 May 8, 2026
983951d
fix test_collect_video_paths: rename keyword -> extensions
deruyter92 May 8, 2026
7d71306
Adjust `extensions` parameter: flexibly coerce str / list / tuple ->…
deruyter92 May 8, 2026
bce0ba9
Merge branch 'main' into jaap/update_list_videos_in_folder
C-Achard May 12, 2026
adadf08
`collect_video_paths`: sort videos if shuffle=False
deruyter92 May 12, 2026
ce8bcf5
update docstring non-recursive directory scanning.
deruyter92 May 12, 2026
75a4d0a
update collect_video_paths: DEFAULT_EXCLUDE_PATTERNS
deruyter92 May 12, 2026
481d3fa
update _coerce_extensions: only "" and None normalize to None
deruyter92 May 12, 2026
8ca9b49
fix instance check in _coerce_video_extensions
deruyter92 May 12, 2026
39557ec
fix pytest: assert alphabetic ordering if shuffle=False
deruyter92 May 12, 2026
39cfd94
fix empty string case in _coerce_extensions
deruyter92 May 12, 2026
77a05dc
Add structured deprecation info and warnings (#3326)
C-Achard May 12, 2026
5610a49
Merge branch 'main' into jaap/update_list_videos_in_folder
C-Achard May 13, 2026
792d35d
guarantee unchanged behavior for deprecated `get_list_of_videos` and …
deruyter92 May 13, 2026
fe38152
add warning if still unsupported extensions encountered
deruyter92 May 13, 2026
69981f1
Consequently adjust `videotype` signatures of collect_video_path callers
deruyter92 May 15, 2026
096973e
refactor collect_video_paths: add warnings, raise for empty sequence.
deruyter92 May 15, 2026
0929e7b
update tests for collect_video_paths
deruyter92 May 15, 2026
996b220
Merge branch 'main' into jaap/update_list_videos_in_folder
MMathisLab May 15, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
refactor collect_video_paths: add warnings, raise for empty sequence.
  • Loading branch information
deruyter92 committed May 15, 2026
commit 096973ebdbac1f8b4df3a710ceb97df8568e6ada
74 changes: 45 additions & 29 deletions deeplabcut/utils/auxfun_videos.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
from skimage import io
from skimage.util import img_as_ubyte

from deeplabcut.utils.deprecation import DLCDeprecationWarning

# more videos are in principle covered, as OpenCV is used and allows many formats.
SUPPORTED_VIDEOS = "avi", "mp4", "mov", "mpeg", "mpg", "mpv", "mkv", "flv", "qt", "yuv"
DEFAULT_EXCLUDE_PATTERNS: tuple[str, ...] = "*_labeled.*", "*_full.*"
Expand Down Expand Up @@ -656,50 +658,64 @@ def collect_video_paths(
exclude_patterns: Sequence[str] = DEFAULT_EXCLUDE_PATTERNS,
) -> list[Path]:
"""
Collects video paths from a given set of data paths: directories, files or mix of both. Directories are
only scanned single level, non-recursively.
Collects video paths from a given set of data paths: directories, files, or a mix
of both. Directories are scanned one level deep (non-recursively).

Optionally filters paths by extension and excludes patterns. Files and directories are treated differently:
- Files are not filtered by extension by default. Set ``extensions`` if needed, to filter also supplied files.
- Directory contents are filtered by ``SUPPORTED_VIDEOS`` by default. Specify custom ``extensions`` if needed.
- exclude patterns are ALWAYS applied for directory contents and supplied files. Set to `[]` to exclude no patterns.
Files and directories are treated differently with respect to extension filtering:
- File paths are accepted as-is when ``extensions`` is ``None``; only filtered when
``extensions`` is explicitly set.
- Directory contents are always filtered by extension: by ``SUPPORTED_VIDEOS`` when
``extensions`` is ``None``, or by the given value(s) otherwise.
- ``exclude_patterns`` are always applied to both files and directory contents.

Args:
data_path: Path or list of paths to folders containing videos, or individual
video files. Can be a mix of directories and files.
extensions: The types of videos to select, by filtering the extension (e.g., ".mp4", ".avi", etc.).
- If set: select all videos with the given extensions. Both for directory contents and supplied files.
- If ``None``, provided files are not filtered, but directory contents are filtered by ``SUPPORTED_VIDEOS``.
- An empty str "" is equivalent to None (for backwards compatibility).
- An empty sequence: select only files without extension.
shuffle: Whether to shuffle the order of videos. If False, videos are returned
in sorted order for deterministic behavior.
exclude_patterns: Patterns to exclude from the collection. Defaults to DEFAULT_EXCLUDE_PATTERNS.
Set to an empty sequence e.g. `[]` to exclude no patterns.
extensions: Controls extension filtering for collected video files.
- ``None`` (default): file paths are accepted without extension filtering;
directories are scanned for files with a recognized video extension.
- ``str`` or ``Sequence[str]`` (e.g. ``"mp4"`` or ``["mp4", "avi"]``):
both file paths and directory contents are filtered to only include files
matching the given extension(s).
- Empty ``str`` ``""`` is treated as ``None`` (deprecated, keep for backwards
compatibility).
shuffle: Whether to shuffle the order of videos. If ``False``, videos are
returned in sorted order for deterministic behavior.
exclude_patterns: Patterns to exclude from the collection. Defaults to
``DEFAULT_EXCLUDE_PATTERNS``. Set to ``[]`` to disable pattern exclusion.

Returns:
The paths of videos to analyze. Duplicate paths are removed.

Raises:
FileNotFoundError: If any path in data_path does not exist.
FileNotFoundError: If any path in ``data_path`` does not exist.
ValueError: If ``extensions`` is an empty sequence.
"""
if isinstance(data_path, (str, Path)):
data_path = [data_path]

def _coerce_extensions(extensions: str | Sequence[str] | None) -> set[str] | None:
"""Flexible coercion of extensions to a set of suffixes"""
# NOTE @deruyter92: support legacy API, which mixed strings and iterables.
if isinstance(extensions, (list, tuple, set)):
explicit_suffixes = {f".{e.lstrip('.').lower()}" for e in extensions}
elif isinstance(extensions, str) and not extensions == "":
explicit_suffixes = {f".{extensions.lstrip('.').lower()}"}
else:
explicit_suffixes = None
"""Coerce the extensions argument to a set of dot-prefixed suffixes, or None."""
if extensions is None:
return None

if extensions in ["", ("",), [""], {""}]:
warnings.warn(
"Passing an empty string for filtering video type extensions is deprecated; pass None instead.",
DLCDeprecationWarning,
stacklevel=3,
)
return None

if isinstance(extensions, str):
return {f".{extensions.lstrip('.').lower()}"}

if not isinstance(extensions, Sequence):
raise TypeError(f"extensions must be a string, a sequence or None, got {type(extensions)}")

# Normalize empty string to None
if explicit_suffixes == {""}:
explicit_suffixes = None
return explicit_suffixes
if len(extensions) == 0:
raise ValueError("Video type extensions filter needs to be an non-empty sequence.")
return {f".{e.lstrip('.').lower()}" for e in extensions}

explicit_suffixes = _coerce_extensions(extensions)
implicit_suffixes = {f".{ext.lower()}" for ext in SUPPORTED_VIDEOS}
Expand Down Expand Up @@ -732,7 +748,7 @@ def _coerce_extensions(extensions: str | Sequence[str] | None) -> set[str] | Non
else:
unique_videos.sort()

if any([fn.suffix not in SUPPORTED_VIDEOS for fn in unique_videos]):
if any(fn.suffix.lower().lstrip(".") not in SUPPORTED_VIDEOS for fn in unique_videos if fn.suffix):
warnings.warn(
f"Some videos have unsupported extensions: {unique_videos} \nSupported extensions are: {SUPPORTED_VIDEOS}",
stacklevel=2,
Expand Down