Skip to content

Commit b1158f5

Browse files
committed
fix video downloading in check_install.
Added a more robust downloading function in `utils.py` that handles errors more gracefully. The download is skipped if the file already exists. In previous implementation, the benchmarking video was downloaded to the home directory, which in windows could result in permission issues when reading the file. This is now changed to the check_install directory. OpenCV was silently failing to read the video file, resulting in a frame count of zero. Now a ValueError is raised when the video cannot be read.
1 parent 9db0752 commit b1158f5

2 files changed

Lines changed: 88 additions & 17 deletions

File tree

dlclive/check_install/check_install.py

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,28 +9,22 @@
99
import urllib.request
1010
import argparse
1111
import shutil
12-
import sys
12+
1313
import urllib.request
1414
import warnings
1515
from pathlib import Path
1616

17+
from dlclive.utils import download_file
1718
from dlclibrary.dlcmodelzoo.modelzoo_download import download_huggingface_model
1819

20+
import dlclive
1921
from dlclive.benchmark import benchmark_videos
2022
from dlclive.engine import Engine
2123

2224
MODEL_NAME = "superanimal_quadruped"
2325
SNAPSHOT_NAME = "snapshot-700000.pb"
2426

2527

26-
def urllib_pbar(count, blockSize, totalSize):
27-
percent = int(count * blockSize * 100 / totalSize)
28-
outstr = f"{round(percent)}%"
29-
sys.stdout.write(outstr)
30-
sys.stdout.write("\b" * len(outstr))
31-
sys.stdout.flush()
32-
33-
3428
def main():
3529
parser = argparse.ArgumentParser(
3630
description="Test DLC-Live installation by downloading and evaluating a demo DLC project!"
@@ -46,22 +40,25 @@ def main():
4640
if not display:
4741
print("Running without displaying video")
4842

49-
# make temporary directory in $HOME
50-
# TODO: why create this temp directory in $HOME?
43+
# make temporary directory
5144
print("\nCreating temporary directory...\n")
52-
tmp_dir = Path().home() / "dlc-live-tmp"
45+
tmp_dir = Path(dlclive.__file__).parent / "check_install" / "dlc-live-tmp"
5346
tmp_dir.mkdir(mode=0o775, exist_ok=True)
5447

5548
video_file = str(tmp_dir / "dog_clip.avi")
5649
model_dir = tmp_dir / "DLC_Dog_resnet_50_iteration-0_shuffle-0"
5750

5851
# download dog test video from github:
59-
if not os.path.exists(video_file):
52+
# Use raw.githubusercontent.com for direct file access
53+
if not Path(video_file).exists():
6054
print(f"Downloading Video to {video_file}")
61-
url_link = "https://github.com/DeepLabCut/DeepLabCut-live/blob/main/check_install/dog_clip.avi?raw=True"
62-
urllib.request.urlretrieve(url_link, video_file, reporthook=urllib_pbar)
55+
url_link = "https://raw.githubusercontent.com/DeepLabCut/DeepLabCut-live/master/check_install/dog_clip.avi"
56+
try:
57+
download_file(url_link, video_file)
58+
except (urllib.error.URLError, IOError) as e:
59+
raise RuntimeError(f"Failed to download video file: {e}") from e
6360
else:
64-
print(f"Video already exists at {video_file}")
61+
print(f"Video file already exists at {video_file}, skipping download.")
6562

6663
# download model from the DeepLabCut Model Zoo
6764
if Path(model_dir / SNAPSHOT_NAME).exists():

dlclive/utils.py

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@
66
"""
77

88
import warnings
9-
9+
from pathlib import Path
1010
import numpy as np
11+
import urllib.request
12+
import urllib.error
1113

1214
from dlclive.exceptions import DLCLiveWarning
1315

@@ -31,6 +33,13 @@
3133
DLCLiveWarning,
3234
)
3335

36+
try:
37+
from tqdm import tqdm
38+
39+
has_tqdm = True
40+
except ImportError:
41+
has_tqdm = False
42+
3443

3544
def convert_to_ubyte(frame: np.ndarray) -> np.ndarray:
3645
"""Converts an image to unsigned 8-bit integer numpy array.
@@ -203,3 +212,68 @@ def decode_fourcc(cc):
203212
decoded = ""
204213

205214
return decoded
215+
216+
217+
def download_file(url: str, filepath: str, chunk_size: int = 8192) -> None:
218+
"""
219+
Download a file from a URL with progress bar and error handling.
220+
221+
Args:
222+
url: URL to download from
223+
filepath: Local path to save the file
224+
chunk_size: Size of chunks to read (default: 8192 bytes)
225+
226+
Raises:
227+
urllib.error.URLError: If the download fails
228+
IOError: If the file cannot be written
229+
"""
230+
filepath = Path(filepath)
231+
232+
# Check if file already exists
233+
if filepath.exists():
234+
print(f"File already exists at {filepath}, skipping download.")
235+
return
236+
237+
# Ensure parent directory exists
238+
filepath.parent.mkdir(parents=True, exist_ok=True)
239+
240+
try:
241+
# Open the URL
242+
with urllib.request.urlopen(url) as response:
243+
# Get file size if available
244+
total_size = int(response.headers.get('Content-Length', 0))
245+
246+
# Create progress bar if tqdm is available
247+
if has_tqdm and total_size > 0:
248+
pbar = tqdm(total=total_size, unit='B', unit_scale=True, desc="Downloading")
249+
else:
250+
pbar = None
251+
print("Downloading...")
252+
253+
# Download and write file
254+
downloaded = 0
255+
with open(filepath, 'wb') as f:
256+
while True:
257+
chunk = response.read(chunk_size)
258+
if not chunk:
259+
break
260+
f.write(chunk)
261+
downloaded += len(chunk)
262+
if pbar:
263+
pbar.update(len(chunk))
264+
265+
if pbar:
266+
pbar.close()
267+
268+
# Verify file was written
269+
if not filepath.exists() or filepath.stat().st_size == 0:
270+
raise IOError(f"Downloaded file is empty or was not written to {filepath}")
271+
272+
print(f"Successfully downloaded to {filepath}")
273+
274+
except urllib.error.HTTPError as e:
275+
raise urllib.error.URLError(f"HTTP error {e.code}: {e.reason} when downloading from {url}")
276+
except urllib.error.URLError as e:
277+
raise urllib.error.URLError(f"Failed to download from {url}: {e.reason}")
278+
except IOError as e:
279+
raise IOError(f"Failed to write file to {filepath}: {e}")

0 commit comments

Comments
 (0)