Information about an array in an npz file.
| 13 | |
| 14 | @dataclass |
| 15 | class NumpyArrayInfo: |
| 16 | """ |
| 17 | Information about an array in an npz file. |
| 18 | """ |
| 19 | |
| 20 | name: str |
| 21 | dtype: np.dtype |
| 22 | shape: Tuple[int] |
| 23 | |
| 24 | @classmethod |
| 25 | def infos_from_first_file(cls, glob_path: str) -> Dict[str, "NumpyArrayInfo"]: |
| 26 | paths, _ = _npz_paths_and_length(glob_path) |
| 27 | return cls.infos_from_file(paths[0]) |
| 28 | |
| 29 | @classmethod |
| 30 | def infos_from_file(cls, npz_path: str) -> Dict[str, "NumpyArrayInfo"]: |
| 31 | """ |
| 32 | Extract the info of every array in an npz file. |
| 33 | """ |
| 34 | if not os.path.exists(npz_path): |
| 35 | raise FileNotFoundError(f"batch of samples was not found: {npz_path}") |
| 36 | results = {} |
| 37 | with open(npz_path, "rb") as f: |
| 38 | with zipfile.ZipFile(f, "r") as zip_f: |
| 39 | for name in zip_f.namelist(): |
| 40 | if not name.endswith(".npy"): |
| 41 | continue |
| 42 | key_name = name[: -len(".npy")] |
| 43 | with zip_f.open(name, "r") as arr_f: |
| 44 | version = np.lib.format.read_magic(arr_f) |
| 45 | if version == (1, 0): |
| 46 | header = np.lib.format.read_array_header_1_0(arr_f) |
| 47 | elif version == (2, 0): |
| 48 | header = np.lib.format.read_array_header_2_0(arr_f) |
| 49 | else: |
| 50 | raise ValueError(f"unknown numpy array version: {version}") |
| 51 | shape, _, dtype = header |
| 52 | results[key_name] = cls(name=key_name, dtype=dtype, shape=shape) |
| 53 | return results |
| 54 | |
| 55 | @property |
| 56 | def elem_shape(self) -> Tuple[int]: |
| 57 | return self.shape[1:] |
| 58 | |
| 59 | def validate(self): |
| 60 | if self.name in {"R", "G", "B"}: |
| 61 | if len(self.shape) != 2: |
| 62 | raise ValueError( |
| 63 | f"expecting exactly 2-D shape for '{self.name}' but got: {self.shape}" |
| 64 | ) |
| 65 | elif self.name == "arr_0": |
| 66 | if len(self.shape) < 2: |
| 67 | raise ValueError(f"expecting at least 2-D shape but got: {self.shape}") |
| 68 | elif len(self.shape) == 3: |
| 69 | # For audio, we require continuous samples. |
| 70 | if not np.issubdtype(self.dtype, np.floating): |
| 71 | raise ValueError( |
| 72 | f"invalid dtype for audio batch: {self.dtype} (expected float)" |
nothing calls this directly
no outgoing calls
no test coverage detected