Skip to content

Commit 919ec9e

Browse files
npy_to_clip: Works now
1 parent 59f3ac4 commit 919ec9e

File tree

4 files changed

+88
-53
lines changed

4 files changed

+88
-53
lines changed

lvsfunc/exceptions.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
11
from __future__ import annotations
22

3-
from vstools import CustomTypeError, FuncExceptT
3+
from typing import Any
4+
5+
from stgpytools import SupportsString
6+
from vstools import CustomTypeError, CustomValueError, FuncExceptT
47

58
__all__ = [
69
'ClipsAndNamedClipsError',
10+
11+
'NumpyArrayLoadError',
712
]
813

914

@@ -14,3 +19,13 @@ def __init__(
1419
self, func: FuncExceptT, message: str = 'Positional clips and named keyword clips cannot both be given!'
1520
) -> None:
1621
super().__init__(message, func)
22+
23+
24+
class NumpyArrayLoadError(CustomValueError):
25+
"""Raised when there's an issue with loading a numpy array."""
26+
27+
def __init__(
28+
self, message: SupportsString | None = None, func: FuncExceptT | None = None, reason: Any = None, **kwargs: Any
29+
) -> None:
30+
31+
super().__init__(message, func, reason, **kwargs)

lvsfunc/models/base.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
from vsscale import autoselect_backend
99
from vstools import (ColorRange, CustomValueError, DependencyNotFoundError,
1010
FileWasNotFoundError, FunctionUtil, Matrix, SPath, depth,
11-
inject_self, iterate, join, normalize_planes, split, vs, get_peak_value)
11+
get_peak_value, inject_self, iterate, join,
12+
normalize_planes, split, vs)
1213

1314
__all__: list[str] = []
1415

lvsfunc/nn/func.py

Lines changed: 67 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@
22

33
import numpy as np
44
from vsexprtools import norm_expr
5-
from vstools import (CustomValueError, FuncExceptT, FunctionUtil, SPath,
6-
SPathLike, clip_async_render, core, fallback, get_depth,
7-
initialize_clip, vs)
5+
from vstools import (CustomValueError, FileWasNotFoundError, FuncExceptT,
6+
FunctionUtil, SPath, SPathLike, clip_async_render, core,
7+
fallback, get_depth, initialize_clip, vs)
88

9+
from ..exceptions import NumpyArrayLoadError
910
from .util import get_format_from_npy
1011

1112
__all__: list[str] = [
@@ -183,100 +184,116 @@ def npy_to_clip(
183184
:param func_except: Function returned for custom error handling.
184185
This should only be set by VS package developers.
185186
186-
:return: The numpy array as a clip.
187+
:return: VapourSynth clip created from the numpy files.
187188
"""
188189

189190
func = fallback(func_except, npy_to_clip)
191+
paths = [SPath(file_paths)] if not isinstance(file_paths, list) else [SPath(x) for x in file_paths]
190192
is_npz = False
191193

192-
if not isinstance(file_paths, list):
193-
file_paths_list = [SPath(file_paths)]
194-
else:
195-
file_paths_list = [SPath(fp) for fp in file_paths]
196-
197-
if file_paths_list and file_paths_list[0].is_dir():
198-
file_paths_list = list(file_paths_list[0].glob("*.np[yz]"))
194+
if not paths:
195+
raise FileWasNotFoundError("No files provided!", func)
199196

200-
if not file_paths_list:
201-
raise CustomValueError("No .npy or .npz files found in the directory", func)
202-
elif not file_paths_list:
203-
raise CustomValueError("No files provided", func)
204-
205-
is_npz = file_paths_list[0].suffix == '.npz'
197+
if paths[0].is_dir():
198+
if npy_files := list(paths[0].glob("*.npy")):
199+
paths = npy_files
200+
elif npz_files := list(paths[0].glob("*.npz")):
201+
paths = npz_files
202+
is_npz = True
203+
else:
204+
raise FileWasNotFoundError("No .npy or .npz files found in the given directory!", func)
205+
elif paths[0].suffix == '.npz':
206+
is_npz = True
206207

207208
if not is_npz:
208-
file_paths_list = sorted(
209-
file_paths_list, key=lambda x: int(x.stem) if x.stem.isdigit() else float('inf')
210-
)
209+
try:
210+
paths = sorted(paths, key=lambda x: int(x.stem) if x.stem.isdigit() else float('inf'))
211+
except ValueError as e:
212+
if "invalid literal for int() with base 10" in str(e):
213+
raise CustomValueError("Error sorting paths: File names must be valid integers!", func)
214+
else:
215+
raise
216+
except Exception as e:
217+
raise CustomValueError(f"Error sorting paths! {str(e)}", func)
211218

212219
if is_npz:
213-
with np.load(file_paths_list[0], allow_pickle=True) as npz_data:
214-
first_frame = next(iter(npz_data.values())).item()
220+
npz_data = np.load(paths[0], allow_pickle=True)
221+
first_key = list(npz_data.keys())[0]
222+
first_frame = npz_data[first_key]
223+
224+
if isinstance(first_frame, np.ndarray) and first_frame.shape == ():
225+
first_frame = first_frame.item()
215226
else:
216-
first_frame = np.load(file_paths_list[0], allow_pickle=True).item()
227+
first_frame = np.load(paths[0], allow_pickle=True).item()
217228

218229
if isinstance(first_frame, dict):
219-
plane_0 = first_frame.get('plane_0')
230+
plane_0_missing = 'plane_0' not in first_frame
231+
plane_0_not_array = not isinstance(first_frame['plane_0'], np.ndarray)
232+
plane_0_low_dim = first_frame['plane_0'].ndim < 2
220233

221-
if not isinstance(plane_0, np.ndarray) or plane_0.ndim < 2:
222-
raise CustomValueError(
223-
"Invalid frame data structure. 'plane_0' is missing, not a numpy array, "
224-
"or has less than 2 dimensions!", func
225-
)
234+
if plane_0_missing or plane_0_not_array or plane_0_low_dim:
235+
error_message = "Invalid frame data structure."
236+
237+
if plane_0_missing:
238+
error_message += " 'plane_0' is missing from the frame dictionary."
239+
elif plane_0_not_array:
240+
error_message += " 'plane_0' is not a numpy array."
241+
elif plane_0_low_dim:
242+
error_message += " 'plane_0' has less than 2 dimensions."
226243

227-
height, width = plane_0.shape
244+
raise NumpyArrayLoadError(error_message, func)
245+
246+
height, width = first_frame['plane_0'].shape
228247
elif isinstance(first_frame, np.ndarray):
229248
if first_frame.ndim < 2:
230-
raise CustomValueError(
231-
f"Invalid frame shape: {first_frame.shape}. Expected at least 2 dimensions!", func
249+
raise NumpyArrayLoadError(
250+
f"Invalid frame shape: {first_frame.shape}. Expected at least 2 dimensions.", func
232251
)
233252

234253
height, width = first_frame.shape[:2]
235254
else:
236-
raise CustomValueError(f"Unsupported frame data type: {type(first_frame)}", func)
255+
raise NumpyArrayLoadError(f"Unsupported frame data type: {type(first_frame)}", func)
237256

238257
fmt = get_format_from_npy(first_frame)
239258

259+
clip_length = len(npz_data.keys()) if is_npz else len(paths)
240260
blank_clip = core.std.BlankClip(
241-
None, width, height, fmt,
242-
length=len(npz_data.keys()) if is_npz else len(file_paths_list),
243-
keep=True
261+
None, width, height, fmt, length=clip_length, keep=True
244262
)
245263

246264
def _read_frame(n: int, f: vs.VideoFrame) -> vs.VideoFrame:
247265
if is_npz:
248-
loaded_frame = next(iter(npz_data.values()))
266+
loaded_frame = npz_data[list(npz_data.keys())[n]]
267+
if isinstance(loaded_frame, np.ndarray) and loaded_frame.shape == ():
268+
loaded_frame = loaded_frame.item()
249269
else:
250-
loaded_frame = np.load(file_paths_list[n], allow_pickle=True)
251-
252-
loaded_frame = loaded_frame.item()
270+
loaded_frame = np.load(paths[n], allow_pickle=True).item()
253271

254272
fout = f.copy()
255273

256274
if isinstance(loaded_frame, np.ndarray):
257275
if loaded_frame.ndim < 2:
258-
raise CustomValueError(
259-
f"Invalid frame shape at index {n}: {loaded_frame.shape}. "
260-
"Expected at least 2 dimensions!", func
276+
raise NumpyArrayLoadError(
277+
f"Invalid frame shape at index {n}: {loaded_frame.shape}. Expected at least 2 dimensions.", func
261278
)
279+
262280
np.copyto(np.asarray(fout[0]), loaded_frame)
263281
elif isinstance(loaded_frame, dict):
264282
for plane in range(f.format.num_planes):
265283
plane_key = f'plane_{plane}'
266-
plane_data = loaded_frame.get(plane_key)
267284

268-
if plane_data is None or plane_data.ndim < 2:
269-
raise CustomValueError(
285+
if plane_key not in loaded_frame or loaded_frame[plane_key].ndim < 2:
286+
raise NumpyArrayLoadError(
270287
f"Invalid frame data structure at index {n}. '{plane_key}' "
271-
"is missing or has less than 2 dimensions!", func=func
288+
"is missing or has less than 2 dimensions.", func
272289
)
273290

274-
np.copyto(np.asarray(fout[plane]), plane_data)
291+
np.copyto(np.asarray(fout[plane]), loaded_frame[plane_key])
275292
else:
276-
raise CustomValueError(f"Unsupported frame data type at index {n}: {type(loaded_frame)}", func=func)
293+
raise CustomValueError(f"Unsupported frame data type at index {n}: {type(loaded_frame)}", func)
277294

278295
return fout
279296

280297
proc_clip = blank_clip.std.ModifyFrame(blank_clip, _read_frame)
281298

282-
return initialize_clip(proc_clip, ref or get_depth(proc_clip), func=func)
299+
return initialize_clip(proc_clip, ref or get_depth(proc_clip), func=func) # type:ignore[arg-type]

lvsfunc/nn/util.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
from vstools import (CustomTypeError, FuncExceptT, InvalidVideoFormatError,
33
core, depth, fallback, get_video_format, vs)
44

5+
from ..exceptions import NumpyArrayLoadError
6+
57
__all__: list[str] = [
68
'get_format_from_npy',
79
]
@@ -35,7 +37,7 @@ def get_format_from_npy(frame_data: np.ndarray, func_except: FuncExceptT | None
3537
y_data = frame_data
3638
num_planes = y_data.ndim if y_data.ndim <= 2 else y_data.shape[2]
3739
else:
38-
raise CustomTypeError(f"Unsupported data type: {type(frame_data)}", func)
40+
raise NumpyArrayLoadError(f"Unsupported data type: {type(frame_data)}", func)
3941

4042
bit_depth = 32 if y_data.dtype == np.float32 else y_data.itemsize * 8
4143

0 commit comments

Comments
 (0)