tensorneko-util 0.3.18__tar.gz → 0.3.20__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (129) hide show
  1. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/PKG-INFO +1 -1
  2. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/README.md +1 -1
  3. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/io/image/image_reader.py +4 -1
  4. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/io/json/json_writer.py +3 -3
  5. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/io/pickle/pickle_reader.py +3 -3
  6. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/util/__init__.py +3 -1
  7. tensorneko_util-0.3.20/src/tensorneko_util/util/multi_layer_indexer.py +113 -0
  8. tensorneko_util-0.3.20/src/tensorneko_util/version.txt +1 -0
  9. tensorneko_util-0.3.18/src/tensorneko_util/visualization/watcher/web/dist/assets/index.3222e532.js → tensorneko_util-0.3.20/src/tensorneko_util/visualization/watcher/web/dist/assets/index.7498e230.js +7 -7
  10. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/visualization/watcher/web/dist/index.html +1 -1
  11. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util.egg-info/PKG-INFO +1 -1
  12. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util.egg-info/SOURCES.txt +2 -1
  13. tensorneko_util-0.3.18/src/tensorneko_util/version.txt +0 -1
  14. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/setup.cfg +0 -0
  15. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/setup.py +0 -0
  16. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/setup_util.py +0 -0
  17. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/__init__.py +0 -0
  18. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/_rich.py +0 -0
  19. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/backend/__init__.py +0 -0
  20. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/backend/audio_lib.py +0 -0
  21. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/backend/blocking.py +0 -0
  22. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/backend/parallel.py +0 -0
  23. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/backend/tqdm.py +0 -0
  24. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/backend/visual_lib.py +0 -0
  25. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/debug/__init__.py +0 -0
  26. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/debug/logger.py +0 -0
  27. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/debug/parser.py +0 -0
  28. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/io/__init__.py +0 -0
  29. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/io/_default_backends.py +0 -0
  30. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/io/_path_conversion.py +0 -0
  31. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/io/audio/__init__.py +0 -0
  32. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/io/audio/audio_data.py +0 -0
  33. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/io/audio/audio_reader.py +0 -0
  34. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/io/audio/audio_writer.py +0 -0
  35. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/io/hdf5/__init__.py +0 -0
  36. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/io/hdf5/hdf5_reader.py +0 -0
  37. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/io/hdf5/hdf5_writer.py +0 -0
  38. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/io/image/__init__.py +0 -0
  39. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/io/image/image_writer.py +0 -0
  40. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/io/json/__init__.py +0 -0
  41. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/io/json/json_data.py +0 -0
  42. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/io/json/json_reader.py +0 -0
  43. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/io/matlab/__init__.py +0 -0
  44. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/io/matlab/mat_reader.py +0 -0
  45. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/io/matlab/mat_writer.py +0 -0
  46. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/io/npy/__init__.py +0 -0
  47. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/io/npy/npy_reader.py +0 -0
  48. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/io/npy/npy_writer.py +0 -0
  49. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/io/pickle/__init__.py +0 -0
  50. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/io/pickle/pickle_writer.py +0 -0
  51. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/io/reader.py +0 -0
  52. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/io/text/__init__.py +0 -0
  53. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/io/text/text_reader.py +0 -0
  54. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/io/text/text_writer.py +0 -0
  55. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/io/toml/__init__.py +0 -0
  56. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/io/toml/toml_reader.py +0 -0
  57. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/io/toml/toml_writer.py +0 -0
  58. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/io/video/__init__.py +0 -0
  59. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/io/video/video_data.py +0 -0
  60. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/io/video/video_reader.py +0 -0
  61. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/io/video/video_writer.py +0 -0
  62. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/io/writer.py +0 -0
  63. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/io/yaml/__init__.py +0 -0
  64. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/io/yaml/yaml_reader.py +0 -0
  65. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/io/yaml/yaml_writer.py +0 -0
  66. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/msg/__init__.py +0 -0
  67. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/msg/gotify.py +0 -0
  68. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/notebook/__init__.py +0 -0
  69. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/notebook/animation.py +0 -0
  70. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/notebook/display.py +0 -0
  71. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/preprocess/__init__.py +0 -0
  72. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/preprocess/crop.py +0 -0
  73. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/preprocess/face_detector/__init__.py +0 -0
  74. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/preprocess/face_detector/_utils.py +0 -0
  75. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/preprocess/face_detector/abstract_face_detector.py +0 -0
  76. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/preprocess/face_detector/anime_face_detector.py +0 -0
  77. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/preprocess/face_detector/facexzoo_face_detector.py +0 -0
  78. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/preprocess/face_detector/opencv_face_detector.py +0 -0
  79. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/preprocess/ffmpeg.py +0 -0
  80. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/preprocess/image.py +0 -0
  81. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/preprocess/video.py +0 -0
  82. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/util/average_meter.py +0 -0
  83. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/util/bimap.py +0 -0
  84. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/util/dispatched_misc.py +0 -0
  85. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/util/dispatcher.py +0 -0
  86. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/util/downloader.py +0 -0
  87. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/util/eventbus/__init__.py +0 -0
  88. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/util/eventbus/bus.py +0 -0
  89. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/util/eventbus/decorator.py +0 -0
  90. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/util/eventbus/event.py +0 -0
  91. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/util/fp/__init__.py +0 -0
  92. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/util/fp/args.py +0 -0
  93. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/util/fp/array/__init__.py +0 -0
  94. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/util/fp/array/abstract_seq.py +0 -0
  95. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/util/fp/array/seq.py +0 -0
  96. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/util/fp/array/stream.py +0 -0
  97. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/util/fp/func.py +0 -0
  98. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/util/fp/monad/__init__.py +0 -0
  99. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/util/fp/monad/eval.py +0 -0
  100. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/util/fp/monad/monad.py +0 -0
  101. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/util/fp/monad/option.py +0 -0
  102. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/util/fp/underscore.py +0 -0
  103. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/util/misc.py +0 -0
  104. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/util/ref.py +0 -0
  105. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/util/registry.py +0 -0
  106. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/util/server.py +0 -0
  107. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/util/singleton.py +0 -0
  108. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/util/timer.py +0 -0
  109. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/util/type.py +0 -0
  110. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/util/window_merger.py +0 -0
  111. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/visualization/__init__.py +0 -0
  112. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/visualization/color.py +0 -0
  113. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/visualization/image_browser/__init__.py +0 -0
  114. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/visualization/image_browser/server.py +0 -0
  115. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/visualization/image_browser/web/index.html +0 -0
  116. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/visualization/matplotlib.py +0 -0
  117. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/visualization/multi_plots.py +0 -0
  118. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/visualization/seaborn.py +0 -0
  119. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/visualization/tensorboard.py +0 -0
  120. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/visualization/watcher/__init__.py +0 -0
  121. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/visualization/watcher/component.py +0 -0
  122. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/visualization/watcher/server.py +0 -0
  123. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/visualization/watcher/view.py +0 -0
  124. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util/visualization/watcher/web/dist/assets/index.cf95019d.css +0 -0
  125. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util.egg-info/dependency_links.txt +0 -0
  126. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util.egg-info/requires.txt +0 -0
  127. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/src/tensorneko_util.egg-info/top_level.txt +0 -0
  128. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/test/test_library_info.py +0 -0
  129. {tensorneko_util-0.3.18 → tensorneko_util-0.3.20}/test/test_version.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: tensorneko_util
3
- Version: 0.3.18
3
+ Version: 0.3.20
4
4
  Summary: The Utils for Library TensorNeko.
5
5
  Home-page: https://github.com/ControlNet/tensorneko
6
6
  Author: ControlNet
@@ -12,7 +12,7 @@
12
12
  <div align="center">
13
13
  <a href="https://www.python.org/"><img src="https://img.shields.io/pypi/pyversions/tensorneko?style=flat-square"></a>
14
14
  <a href="https://pytorch.org/"><img src="https://img.shields.io/badge/PyTorch-%3E%3D1.9.0-EE4C2C?style=flat-square&logo=pytorch"></a>
15
- <a href="https://www.pytorchlightning.ai/"><img src="https://img.shields.io/badge/Lightning-2.0.*%20|%202.1.*%20|%202.2.*-792EE5?style=flat-square&logo=lightning"></a>
15
+ <a href="https://www.pytorchlightning.ai/"><img src="https://img.shields.io/badge/Lightning-2.*-792EE5?style=flat-square&logo=lightning"></a>
16
16
  </div>
17
17
 
18
18
  <div align="center">
@@ -35,7 +35,10 @@ class ImageReader:
35
35
  if not VisualLib.opencv_available():
36
36
  raise ValueError("OpenCV is not installed.")
37
37
  import cv2
38
- img = cv2.imread(path).astype(np.float32) / 255.0
38
+ img = cv2.imread(path)
39
+ if img is None:
40
+ raise ValueError("Invalid image path: {}".format(path))
41
+ img = img.astype(np.float32) / 255.0
39
42
  img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
40
43
  elif backend == VisualLib.MATPLOTLIB:
41
44
  if not VisualLib.matplotlib_available():
@@ -9,7 +9,7 @@ from .._path_conversion import _path2str
9
9
  class JsonWriter:
10
10
 
11
11
  @staticmethod
12
- def _write_json(path: str, obj: Union[dict, list], encoding: str = "UTF-8", indent: int = 4,
12
+ def _write_json(path: str, obj: Union[dict, list], encoding: str = "UTF-8", indent: int = 2,
13
13
  ensure_ascii: bool = False, fast: bool = True
14
14
  ) -> None:
15
15
  if not fast:
@@ -28,7 +28,7 @@ class JsonWriter:
28
28
  file.write(orjson.dumps(obj, option=option))
29
29
 
30
30
  @classmethod
31
- def to(cls, path: Union[str, Path], obj: Union[dict, list, object], encoding: str = "UTF-8", indent: int = 4,
31
+ def to(cls, path: Union[str, Path], obj: Union[dict, list, object], encoding: str = "UTF-8", indent: int = 2,
32
32
  ensure_ascii: bool = False, fast: bool = True
33
33
  ) -> None:
34
34
  """
@@ -68,7 +68,7 @@ class JsonWriter:
68
68
  else:
69
69
  raise TypeError("Not implemented type. Only support dict, list, json_data.")
70
70
 
71
- def __new__(cls, path: Union[str, Path], obj: Union[dict, list, object], encoding: str = "UTF-8", indent: int = 4,
71
+ def __new__(cls, path: Union[str, Path], obj: Union[dict, list, object], encoding: str = "UTF-8", indent: int = 2,
72
72
  ensure_ascii: bool = False, fast: bool = True
73
73
  ) -> None:
74
74
  """Alias of :meth:`~tensorneko.io.json.json_writer.JsonWriter.to`."""
@@ -1,5 +1,5 @@
1
1
  import pickle
2
- from typing import Union
2
+ from typing import Union, Any
3
3
  from pathlib import Path
4
4
 
5
5
  from .._path_conversion import _path2str
@@ -8,7 +8,7 @@ from .._path_conversion import _path2str
8
8
  class PickleReader:
9
9
 
10
10
  @classmethod
11
- def of(cls, path: Union[str, Path]) -> None:
11
+ def of(cls, path: Union[str, Path]) -> Any:
12
12
  """
13
13
  Save the object to a file.
14
14
 
@@ -19,7 +19,7 @@ class PickleReader:
19
19
  with open(path, 'rb') as f:
20
20
  return pickle.load(f)
21
21
 
22
- def __new__(cls, path: Union[str, Path]) -> None:
22
+ def __new__(cls, path: Union[str, Path]) -> Any:
23
23
  """Alias to :meth:`~tensorneko_util.io.pickle.PickleReader.of`."""
24
24
  path = _path2str(path)
25
25
  return cls.of(path)
@@ -12,6 +12,7 @@ from .eventbus import Event, EventBus, EventHandler, subscribe
12
12
  from .singleton import Singleton
13
13
  from .downloader import download_file, download_file_thread, download_files_thread
14
14
  from .window_merger import WindowMerger
15
+ from .multi_layer_indexer import MultiLayerIndexer
15
16
 
16
17
  tensorneko_util_path = get_tensorneko_util_path()
17
18
 
@@ -56,5 +57,6 @@ __all__ = [
56
57
  "download_file_thread",
57
58
  "download_files_thread",
58
59
  "WindowMerger",
59
- "Registry"
60
+ "Registry",
61
+ "MultiLayerIndexer"
60
62
  ]
@@ -0,0 +1,113 @@
1
+ from typing import Union, List
2
+
3
+ T_Counts = Union[int, List["Counts"]]
4
+
5
+
6
+ class MultiLayerIndexer:
7
+ """
8
+ Multi-layer indexer for hierarchical indexing structures.
9
+
10
+ Args:
11
+ counts (``int`` | ``List[int | List]``): A nested structure representing the counts at each layer.
12
+ It can be an integer or a list of counts (which can themselves be lists).
13
+
14
+ Examples::
15
+
16
+ # Test Case 1
17
+ counts = [5, 10, 15]
18
+ indexer = MultiLayerIndexer(counts)
19
+ print(len(indexer), indexer(12)) # Output: 30 [1, 7]
20
+
21
+ # Test Case 2
22
+ counts = [[3, 2], 4, [1, 1, 1]]
23
+ indexer = MultiLayerIndexer(counts)
24
+ print(len(indexer), indexer(8)) # Output: 12 [1, 3]
25
+
26
+ # Test Case 3 (Error Handling)
27
+ try:
28
+ counts = [2, [3, [4, 5]]]
29
+ indexer = MultiLayerIndexer(counts)
30
+ print(len(indexer), indexer(20)) # Should raise IndexError
31
+ except IndexError as e:
32
+ print(e) # Output: Index out of bounds
33
+
34
+ """
35
+
36
+ def __init__(self, counts: T_Counts):
37
+ self._counts = counts
38
+ self._total = self._total_counts(counts)
39
+
40
+ def __call__(self, index: int) -> List[int]:
41
+ """
42
+ Given a global index, return the indices at each layer.
43
+
44
+ Args:
45
+ index (``int``): The global index.
46
+
47
+ Returns:
48
+ ``List[int]``: A list of indices at each layer corresponding to the global index.
49
+
50
+ Raises:
51
+ ``IndexError``: If the provided global index is out of bounds.
52
+ """
53
+ return self._multi_layer_index(self._counts, index)
54
+
55
+ @classmethod
56
+ def _multi_layer_index(cls, counts: T_Counts, index: int) -> List[int]:
57
+ """
58
+ A recursive helper function to compute the indices at each layer.
59
+
60
+ Args:
61
+ counts (``int`` | ``List[int | List]``): The counts at the current layer.
62
+ index (``int``): The index at the current layer.
63
+
64
+ Returns:
65
+ ``list``: A list of indices at each layer.
66
+
67
+ Raises:
68
+ ``IndexError``: If the provided index exceeds the available counts.
69
+ """
70
+ if isinstance(counts, int):
71
+ if index < counts:
72
+ return [index]
73
+ else:
74
+ raise IndexError("Index out of bounds")
75
+ elif isinstance(counts, list):
76
+ cumulative_counts = [0]
77
+ for c in counts:
78
+ total_c = cls._total_counts(c)
79
+ cumulative_counts.append(cumulative_counts[-1] + total_c)
80
+ for i in range(len(cumulative_counts) - 1):
81
+ if cumulative_counts[i] <= index < cumulative_counts[i + 1]:
82
+ sub_idx = index - cumulative_counts[i]
83
+ sub_indices = cls._multi_layer_index(counts[i], sub_idx)
84
+ return [i] + sub_indices
85
+ raise IndexError("Index out of bounds")
86
+ else:
87
+ raise ValueError("Invalid counts structure")
88
+
89
+ @classmethod
90
+ def _total_counts(cls, counts: T_Counts) -> int:
91
+ """
92
+ Compute the total counts of items under the given counts structure.
93
+
94
+ Args:
95
+ counts (``int`` | ``List[int | List]``): The counts structure.
96
+
97
+ Returns:
98
+ ``int``: The total count of items.
99
+
100
+ Raises:
101
+ ``ValueError``: If the counts structure is invalid.
102
+ """
103
+ if isinstance(counts, int):
104
+ if counts < 0:
105
+ raise ValueError("Counts cannot be negative")
106
+ return counts
107
+ elif isinstance(counts, list):
108
+ return sum(cls._total_counts(c) for c in counts)
109
+ else:
110
+ raise ValueError("Invalid counts structure")
111
+
112
+ def __len__(self) -> int:
113
+ return self._total