figpack 0.2.15__tar.gz → 0.2.17__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.

Potentially problematic release.


This version of figpack might be problematic. Click here for more details.

Files changed (99) hide show
  1. {figpack-0.2.15/figpack.egg-info → figpack-0.2.17}/PKG-INFO +21 -2
  2. {figpack-0.2.15 → figpack-0.2.17}/figpack/__init__.py +4 -3
  3. figpack-0.2.17/figpack/core/__init__.py +5 -0
  4. {figpack-0.2.15 → figpack-0.2.17}/figpack/core/_bundle_utils.py +80 -33
  5. {figpack-0.2.15 → figpack-0.2.17}/figpack/core/_view_figure.py +1 -1
  6. figpack-0.2.17/figpack/core/extension_view.py +41 -0
  7. {figpack-0.2.15 → figpack-0.2.17}/figpack/core/figpack_extension.py +0 -71
  8. {figpack-0.2.15 → figpack-0.2.17}/figpack/core/figpack_view.py +2 -2
  9. figpack-0.2.17/figpack/core/zarr.py +61 -0
  10. figpack-0.2.17/figpack/figpack-figure-dist/assets/index-DBwmtEpB.js +91 -0
  11. figpack-0.2.15/figpack/figpack-figure-dist/assets/index-D9a3K6eW.css → figpack-0.2.17/figpack/figpack-figure-dist/assets/index-DHWczh-Q.css +1 -1
  12. {figpack-0.2.15 → figpack-0.2.17}/figpack/figpack-figure-dist/index.html +2 -2
  13. {figpack-0.2.15 → figpack-0.2.17}/figpack/views/Box.py +2 -3
  14. {figpack-0.2.15 → figpack-0.2.17}/figpack/views/DataFrame.py +6 -12
  15. {figpack-0.2.15 → figpack-0.2.17}/figpack/views/Gallery.py +2 -3
  16. {figpack-0.2.15 → figpack-0.2.17}/figpack/views/Image.py +3 -9
  17. {figpack-0.2.15 → figpack-0.2.17}/figpack/views/Markdown.py +3 -4
  18. {figpack-0.2.15 → figpack-0.2.17}/figpack/views/MatplotlibFigure.py +2 -11
  19. {figpack-0.2.15 → figpack-0.2.17}/figpack/views/MultiChannelTimeseries.py +2 -6
  20. figpack-0.2.17/figpack/views/PlotlyExtension/PlotlyExtension.py +69 -0
  21. figpack-0.2.17/figpack/views/PlotlyExtension/_plotly_extension.py +46 -0
  22. figpack-0.2.17/figpack/views/PlotlyExtension/plotly_view.js +110 -0
  23. {figpack-0.2.15 → figpack-0.2.17}/figpack/views/Spectrogram.py +2 -7
  24. {figpack-0.2.15 → figpack-0.2.17}/figpack/views/Splitter.py +2 -3
  25. {figpack-0.2.15 → figpack-0.2.17}/figpack/views/TabLayout.py +2 -3
  26. {figpack-0.2.15 → figpack-0.2.17}/figpack/views/TimeseriesGraph.py +6 -10
  27. {figpack-0.2.15 → figpack-0.2.17}/figpack/views/__init__.py +1 -0
  28. {figpack-0.2.15 → figpack-0.2.17/figpack.egg-info}/PKG-INFO +21 -2
  29. {figpack-0.2.15 → figpack-0.2.17}/figpack.egg-info/SOURCES.txt +4 -28
  30. {figpack-0.2.15 → figpack-0.2.17}/figpack.egg-info/requires.txt +22 -1
  31. {figpack-0.2.15 → figpack-0.2.17}/pyproject.toml +25 -3
  32. {figpack-0.2.15 → figpack-0.2.17}/tests/test_box.py +5 -2
  33. {figpack-0.2.15 → figpack-0.2.17}/tests/test_cli.py +0 -1
  34. {figpack-0.2.15 → figpack-0.2.17}/tests/test_core.py +4 -4
  35. {figpack-0.2.15 → figpack-0.2.17}/tests/test_dataframe.py +19 -20
  36. {figpack-0.2.15 → figpack-0.2.17}/tests/test_extension_system.py +7 -84
  37. {figpack-0.2.15 → figpack-0.2.17}/tests/test_gallery.py +5 -5
  38. {figpack-0.2.15 → figpack-0.2.17}/tests/test_image.py +7 -5
  39. {figpack-0.2.15 → figpack-0.2.17}/tests/test_markdown.py +11 -9
  40. {figpack-0.2.15 → figpack-0.2.17}/tests/test_matplotlib_figure.py +12 -20
  41. {figpack-0.2.15 → figpack-0.2.17}/tests/test_multichannel_timeseries.py +6 -4
  42. {figpack-0.2.15 → figpack-0.2.17}/tests/test_plotly_figure.py +9 -11
  43. {figpack-0.2.15 → figpack-0.2.17}/tests/test_server_manager.py +0 -6
  44. {figpack-0.2.15 → figpack-0.2.17}/tests/test_spectrogram.py +4 -42
  45. {figpack-0.2.15 → figpack-0.2.17}/tests/test_splitter.py +6 -4
  46. {figpack-0.2.15 → figpack-0.2.17}/tests/test_tablayout.py +8 -6
  47. {figpack-0.2.15 → figpack-0.2.17}/tests/test_timeseries_graph.py +4 -2
  48. {figpack-0.2.15 → figpack-0.2.17}/tests/test_upload_bundle.py +0 -7
  49. {figpack-0.2.15 → figpack-0.2.17}/tests/test_view_figure.py +1 -3
  50. figpack-0.2.15/figpack/core/__init__.py +0 -5
  51. figpack-0.2.15/figpack/core/extension_view.py +0 -59
  52. figpack-0.2.15/figpack/figpack-figure-dist/assets/index-DtOnN02w.js +0 -846
  53. figpack-0.2.15/figpack/franklab/__init__.py +0 -5
  54. figpack-0.2.15/figpack/franklab/views/TrackAnimation.py +0 -153
  55. figpack-0.2.15/figpack/franklab/views/__init__.py +0 -9
  56. figpack-0.2.15/figpack/spike_sorting/__init__.py +0 -5
  57. figpack-0.2.15/figpack/spike_sorting/views/AutocorrelogramItem.py +0 -32
  58. figpack-0.2.15/figpack/spike_sorting/views/Autocorrelograms.py +0 -118
  59. figpack-0.2.15/figpack/spike_sorting/views/AverageWaveforms.py +0 -147
  60. figpack-0.2.15/figpack/spike_sorting/views/CrossCorrelogramItem.py +0 -35
  61. figpack-0.2.15/figpack/spike_sorting/views/CrossCorrelograms.py +0 -132
  62. figpack-0.2.15/figpack/spike_sorting/views/RasterPlot.py +0 -288
  63. figpack-0.2.15/figpack/spike_sorting/views/RasterPlotItem.py +0 -28
  64. figpack-0.2.15/figpack/spike_sorting/views/SpikeAmplitudes.py +0 -374
  65. figpack-0.2.15/figpack/spike_sorting/views/SpikeAmplitudesItem.py +0 -38
  66. figpack-0.2.15/figpack/spike_sorting/views/UnitMetricsGraph.py +0 -129
  67. figpack-0.2.15/figpack/spike_sorting/views/UnitSimilarityScore.py +0 -40
  68. figpack-0.2.15/figpack/spike_sorting/views/UnitsTable.py +0 -89
  69. figpack-0.2.15/figpack/spike_sorting/views/UnitsTableColumn.py +0 -40
  70. figpack-0.2.15/figpack/spike_sorting/views/UnitsTableRow.py +0 -36
  71. figpack-0.2.15/figpack/spike_sorting/views/__init__.py +0 -41
  72. figpack-0.2.15/figpack/views/PlotlyExtension/PlotlyExtension.py +0 -121
  73. figpack-0.2.15/figpack/views/PlotlyExtension/plotly_view.js +0 -106
  74. figpack-0.2.15/tests/test_average_waveforms.py +0 -102
  75. figpack-0.2.15/tests/test_raster_plot.py +0 -58
  76. figpack-0.2.15/tests/test_show_view.py +0 -0
  77. figpack-0.2.15/tests/test_spike_amplitudes.py +0 -202
  78. figpack-0.2.15/tests/test_spike_sorting_correlograms.py +0 -160
  79. figpack-0.2.15/tests/test_track_animation.py +0 -230
  80. figpack-0.2.15/tests/test_units_table.py +0 -209
  81. {figpack-0.2.15 → figpack-0.2.17}/LICENSE +0 -0
  82. {figpack-0.2.15 → figpack-0.2.17}/MANIFEST.in +0 -0
  83. {figpack-0.2.15 → figpack-0.2.17}/README.md +0 -0
  84. {figpack-0.2.15 → figpack-0.2.17}/figpack/cli.py +0 -0
  85. {figpack-0.2.15 → figpack-0.2.17}/figpack/core/_save_figure.py +0 -0
  86. {figpack-0.2.15 → figpack-0.2.17}/figpack/core/_server_manager.py +0 -0
  87. {figpack-0.2.15 → figpack-0.2.17}/figpack/core/_show_view.py +0 -0
  88. {figpack-0.2.15 → figpack-0.2.17}/figpack/core/_upload_bundle.py +0 -0
  89. {figpack-0.2.15 → figpack-0.2.17}/figpack/core/config.py +0 -0
  90. {figpack-0.2.15 → figpack-0.2.17}/figpack/figpack-figure-dist/assets/neurosift-logo-CLsuwLMO.png +0 -0
  91. {figpack-0.2.15 → figpack-0.2.17}/figpack/views/GalleryItem.py +0 -0
  92. {figpack-0.2.15 → figpack-0.2.17}/figpack/views/LayoutItem.py +0 -0
  93. {figpack-0.2.15 → figpack-0.2.17}/figpack/views/PlotlyExtension/__init__.py +0 -0
  94. {figpack-0.2.15 → figpack-0.2.17}/figpack/views/TabLayoutItem.py +0 -0
  95. {figpack-0.2.15 → figpack-0.2.17}/figpack.egg-info/dependency_links.txt +0 -0
  96. {figpack-0.2.15 → figpack-0.2.17}/figpack.egg-info/entry_points.txt +0 -0
  97. {figpack-0.2.15 → figpack-0.2.17}/figpack.egg-info/top_level.txt +0 -0
  98. {figpack-0.2.15 → figpack-0.2.17}/setup.cfg +0 -0
  99. {figpack-0.2.15 → figpack-0.2.17}/tests/test_figpack_view.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: figpack
3
- Version: 0.2.15
3
+ Version: 0.2.17
4
4
  Summary: A Python package for creating shareable, interactive visualizations in the browser
5
5
  Author-email: Jeremy Magland <jmagland@flatironinstitute.org>
6
6
  License: Apache-2.0
@@ -25,7 +25,7 @@ Requires-Python: >=3.8
25
25
  Description-Content-Type: text/markdown
26
26
  License-File: LICENSE
27
27
  Requires-Dist: numpy
28
- Requires-Dist: zarr<3
28
+ Requires-Dist: zarr
29
29
  Requires-Dist: requests
30
30
  Requires-Dist: psutil
31
31
  Provides-Extra: test
@@ -37,6 +37,25 @@ Requires-Dist: matplotlib; extra == "test"
37
37
  Requires-Dist: plotly; extra == "test"
38
38
  Requires-Dist: Pillow; extra == "test"
39
39
  Requires-Dist: pandas; extra == "test"
40
+ Provides-Extra: test-zarr2
41
+ Requires-Dist: pytest>=7.0; extra == "test-zarr2"
42
+ Requires-Dist: pytest-cov>=4.0; extra == "test-zarr2"
43
+ Requires-Dist: pytest-mock>=3.10; extra == "test-zarr2"
44
+ Requires-Dist: spikeinterface; extra == "test-zarr2"
45
+ Requires-Dist: matplotlib; extra == "test-zarr2"
46
+ Requires-Dist: plotly; extra == "test-zarr2"
47
+ Requires-Dist: Pillow; extra == "test-zarr2"
48
+ Requires-Dist: pandas; extra == "test-zarr2"
49
+ Requires-Dist: zarr<3; extra == "test-zarr2"
50
+ Provides-Extra: test-zarr3
51
+ Requires-Dist: pytest>=7.0; extra == "test-zarr3"
52
+ Requires-Dist: pytest-cov>=4.0; extra == "test-zarr3"
53
+ Requires-Dist: pytest-mock>=3.10; extra == "test-zarr3"
54
+ Requires-Dist: matplotlib; extra == "test-zarr3"
55
+ Requires-Dist: plotly; extra == "test-zarr3"
56
+ Requires-Dist: Pillow; extra == "test-zarr3"
57
+ Requires-Dist: pandas; extra == "test-zarr3"
58
+ Requires-Dist: zarr>=3; extra == "test-zarr3"
40
59
  Provides-Extra: dev
41
60
  Requires-Dist: pytest>=7.0; extra == "dev"
42
61
  Requires-Dist: pytest-cov>=4.0; extra == "dev"
@@ -2,15 +2,16 @@
2
2
  figpack - A Python package for creating shareable, interactive visualizations in the browser
3
3
  """
4
4
 
5
- __version__ = "0.2.15"
5
+ __version__ = "0.2.17"
6
6
 
7
7
  from .cli import view_figure
8
- from .core import FigpackView, FigpackExtension, ExtensionRegistry, ExtensionView
8
+ from .core import FigpackView, FigpackExtension, ExtensionView
9
+ from .core.zarr import Group
9
10
 
10
11
  __all__ = [
11
12
  "view_figure",
12
13
  "FigpackView",
13
14
  "FigpackExtension",
14
- "ExtensionRegistry",
15
15
  "ExtensionView",
16
+ "Group",
16
17
  ]
@@ -0,0 +1,5 @@
1
+ from .figpack_view import FigpackView
2
+ from .figpack_extension import FigpackExtension
3
+ from .extension_view import ExtensionView
4
+
5
+ __all__ = ["FigpackView", "FigpackExtension", "ExtensionView"]
@@ -1,12 +1,14 @@
1
1
  import os
2
2
  import pathlib
3
+ import json
3
4
  from typing import Set
4
5
 
5
6
  import zarr
6
7
 
7
8
  from .figpack_view import FigpackView
8
- from .figpack_extension import ExtensionRegistry
9
+ from .figpack_extension import FigpackExtension
9
10
  from .extension_view import ExtensionView
11
+ from .zarr import Group, _check_zarr_version
10
12
 
11
13
  thisdir = pathlib.Path(__file__).parent.resolve()
12
14
 
@@ -45,24 +47,35 @@ def prepare_figure_bundle(
45
47
  target_sub = target / subitem.name
46
48
  target_sub.write_bytes(subitem.read_bytes())
47
49
 
48
- # Write the view data to the Zarr group
49
- zarr_group = zarr.open_group(
50
- pathlib.Path(tmpdir) / "data.zarr",
51
- mode="w",
52
- synchronizer=zarr.ThreadSynchronizer(),
53
- )
54
- view._write_to_zarr_group(zarr_group)
50
+ # If we are using zarr 3, then we set the default zarr format to 2 temporarily
51
+ # because we only support version 2 on the frontend right now.
52
+
53
+ if _check_zarr_version() == 3:
54
+ old_default_zarr_format = zarr.config.get("default_zarr_format")
55
+ zarr.config.set({"default_zarr_format": 2})
56
+
57
+ try:
58
+ # Write the view data to the Zarr group
59
+ zarr_group = zarr.open_group(pathlib.Path(tmpdir) / "data.zarr", mode="w")
60
+ zarr_group = Group(zarr_group)
61
+ view._write_to_zarr_group(zarr_group)
55
62
 
56
- # Add title and description as attributes on the top-level zarr group
57
- zarr_group.attrs["title"] = title
58
- if description is not None:
59
- zarr_group.attrs["description"] = description
63
+ # Add title and description as attributes on the top-level zarr group
64
+ zarr_group.attrs["title"] = title
65
+ if description is not None:
66
+ zarr_group.attrs["description"] = description
60
67
 
61
- # Discover and write extension JavaScript files
62
- required_extensions = _discover_required_extensions(view)
63
- _write_extension_files(required_extensions, tmpdir)
68
+ # Discover and write extension JavaScript files
69
+ required_extensions = _discover_required_extensions(view)
70
+ _write_extension_files(required_extensions, tmpdir)
64
71
 
65
- zarr.consolidate_metadata(zarr_group.store)
72
+ # Generate extension manifest
73
+ _write_extension_manifest(required_extensions, tmpdir)
74
+
75
+ zarr.consolidate_metadata(zarr_group._zarr_group.store)
76
+ finally:
77
+ if _check_zarr_version() == 3:
78
+ zarr.config.set({"default_zarr_format": old_default_zarr_format})
66
79
 
67
80
 
68
81
  def _discover_required_extensions(view: FigpackView) -> Set[str]:
@@ -75,7 +88,8 @@ def _discover_required_extensions(view: FigpackView) -> Set[str]:
75
88
  Returns:
76
89
  Set of extension names required by this view hierarchy
77
90
  """
78
- extensions = set()
91
+ extension_names_discovered = set()
92
+ extensions_discovered = []
79
93
  visited = set() # Prevent infinite recursion
80
94
 
81
95
  def _collect_extensions(v: FigpackView):
@@ -86,7 +100,9 @@ def _discover_required_extensions(view: FigpackView) -> Set[str]:
86
100
 
87
101
  # Check if this view is an extension view
88
102
  if isinstance(v, ExtensionView):
89
- extensions.add(v.extension_name)
103
+ if v.extension.name not in extension_names_discovered:
104
+ extension_names_discovered.add(v.extension.name)
105
+ extensions_discovered.append(v.extension)
90
106
 
91
107
  # Recursively check all attributes that might contain child views
92
108
  for attr_name in dir(v):
@@ -121,10 +137,10 @@ def _discover_required_extensions(view: FigpackView) -> Set[str]:
121
137
  continue
122
138
 
123
139
  _collect_extensions(view)
124
- return extensions
140
+ return extensions_discovered
125
141
 
126
142
 
127
- def _write_extension_files(extension_names: Set[str], tmpdir: str) -> None:
143
+ def _write_extension_files(extensions, tmpdir: str) -> None:
128
144
  """
129
145
  Write JavaScript files for the required extensions
130
146
 
@@ -132,20 +148,11 @@ def _write_extension_files(extension_names: Set[str], tmpdir: str) -> None:
132
148
  extension_names: Set of extension names to write
133
149
  tmpdir: Directory to write extension files to
134
150
  """
135
- if not extension_names:
136
- return
137
-
138
- registry = ExtensionRegistry.get_instance()
139
151
  tmpdir_path = pathlib.Path(tmpdir)
140
152
 
141
- for extension_name in extension_names:
142
- extension = registry.get_extension(extension_name)
143
- if extension is None:
144
- raise RuntimeError(
145
- f"Extension '{extension_name}' is required but not registered"
146
- )
147
-
148
- # Write the main JavaScript file
153
+ for extension in extensions:
154
+ if not isinstance(extension, FigpackExtension):
155
+ raise ValueError("Expected a FigpackExtension instance")
149
156
  js_filename = extension.get_javascript_filename()
150
157
  js_path = tmpdir_path / js_filename
151
158
 
@@ -155,7 +162,7 @@ def _write_extension_files(extension_names: Set[str], tmpdir: str) -> None:
155
162
  * Version: {extension.version}
156
163
  * Generated automatically - do not edit
157
164
  */
158
-
165
+
159
166
  {extension.javascript_code}
160
167
  """
161
168
 
@@ -178,3 +185,43 @@ def _write_extension_files(extension_names: Set[str], tmpdir: str) -> None:
178
185
  """
179
186
 
180
187
  additional_path.write_text(additional_js_content, encoding="utf-8")
188
+
189
+
190
+ def _write_extension_manifest(extensions, tmpdir: str) -> None:
191
+ """
192
+ Write the extension manifest file that lists all extensions and their files
193
+
194
+ Args:
195
+ extensions: List of FigpackExtension instances
196
+ tmpdir: Directory to write the manifest file to
197
+ """
198
+ tmpdir_path = pathlib.Path(tmpdir)
199
+ manifest_path = tmpdir_path / "extension_manifest.json"
200
+
201
+ # Build the manifest data
202
+ manifest_data = {"extensions": []}
203
+
204
+ for extension in extensions:
205
+ if not isinstance(extension, FigpackExtension):
206
+ raise ValueError("Expected a FigpackExtension instance")
207
+
208
+ # Get the main script filename
209
+ main_script = extension.get_javascript_filename()
210
+
211
+ # Get additional script filenames
212
+ additional_filenames = extension.get_additional_filenames()
213
+ additional_scripts = list(additional_filenames.values())
214
+
215
+ extension_entry = {
216
+ "name": extension.name,
217
+ "mainScript": main_script,
218
+ "additionalScripts": additional_scripts,
219
+ "version": extension.version,
220
+ }
221
+
222
+ manifest_data["extensions"].append(extension_entry)
223
+
224
+ # Write the manifest file
225
+ manifest_path.write_text(
226
+ json.dumps(manifest_data, indent=2, ensure_ascii=False), encoding="utf-8"
227
+ )
@@ -109,7 +109,7 @@ def view_figure(figure_path: str, port: Union[int, None] = None) -> None:
109
109
 
110
110
  try:
111
111
  with tarfile.open(figure_path, "r:gz") as tar:
112
- tar.extractall(temp_path)
112
+ tar.extractall(temp_path, filter="data")
113
113
 
114
114
  # Count extracted files
115
115
  extracted_files = list(temp_path.rglob("*"))
@@ -0,0 +1,41 @@
1
+ """
2
+ Base class for views that use figpack extensions
3
+ """
4
+
5
+ from .figpack_view import FigpackView
6
+ from .figpack_extension import FigpackExtension
7
+ from ..core.zarr import Group
8
+
9
+
10
+ class ExtensionView(FigpackView):
11
+ """
12
+ Base class for views that are rendered by figpack extensions
13
+ """
14
+
15
+ def __init__(self, *, extension: FigpackExtension, view_type: str):
16
+ """
17
+ Initialize an extension-based view
18
+
19
+ Args:
20
+ extension_name: Name of the extension that will render this view
21
+ """
22
+ super().__init__()
23
+ self.extension = extension
24
+ self.view_type = view_type
25
+
26
+ def _write_to_zarr_group(self, group: Group) -> None:
27
+ """
28
+ Write the extension view metadata to a Zarr group.
29
+ Subclasses should call super()._write_to_zarr_group(group) first,
30
+ then add their own data.
31
+
32
+ Args:
33
+ group: Zarr group to write data into
34
+ """
35
+ # Set the view type to indicate this is an extension view
36
+ group.attrs["view_type"] = self.view_type
37
+
38
+ # Store the extension name so the frontend knows which extension to use
39
+ group.attrs["extension_name"] = self.extension.name
40
+
41
+ group.attrs["extension_version"] = self.extension.version
@@ -64,74 +64,3 @@ class FigpackExtension:
64
64
  original_name: f"extension-{safe_name}-{original_name}"
65
65
  for original_name in self.additional_files.keys()
66
66
  }
67
-
68
-
69
- class ExtensionRegistry:
70
- """
71
- Singleton registry for managing figpack extensions
72
- """
73
-
74
- _instance: Optional["ExtensionRegistry"] = None
75
-
76
- def __init__(self):
77
- self._extensions: Dict[str, FigpackExtension] = {}
78
-
79
- @classmethod
80
- def get_instance(cls) -> "ExtensionRegistry":
81
- """Get the singleton instance of the extension registry"""
82
- if cls._instance is None:
83
- cls._instance = cls()
84
- return cls._instance
85
-
86
- @classmethod
87
- def register(cls, extension: FigpackExtension) -> None:
88
- """
89
- Register an extension with the global registry
90
-
91
- Args:
92
- extension: The extension to register
93
- """
94
- registry = cls.get_instance()
95
- registry._register_extension(extension)
96
-
97
- def _register_extension(self, extension: FigpackExtension) -> None:
98
- """
99
- Internal method to register an extension
100
-
101
- Args:
102
- extension: The extension to register
103
- """
104
- if extension.name in self._extensions:
105
- existing = self._extensions[extension.name]
106
- if existing.version != extension.version:
107
- print(
108
- f"Warning: Replacing extension '{extension.name}' "
109
- f"version {existing.version} with version {extension.version}"
110
- )
111
-
112
- self._extensions[extension.name] = extension
113
-
114
- def get_extension(self, name: str) -> Optional[FigpackExtension]:
115
- """
116
- Get an extension by name
117
-
118
- Args:
119
- name: Name of the extension to retrieve
120
-
121
- Returns:
122
- The extension if found, None otherwise
123
- """
124
- return self._extensions.get(name)
125
-
126
- def get_all_extensions(self) -> Dict[str, FigpackExtension]:
127
- """
128
- Get all registered extensions
129
-
130
- Returns:
131
- Dictionary mapping extension names to extension objects
132
- """
133
- return self._extensions.copy()
134
-
135
- def clear(self) -> None:
136
- """Clear all registered extensions (mainly for testing)"""
137
- self._extensions.clear()
@@ -7,7 +7,7 @@ import random
7
7
  import string
8
8
  from typing import Union
9
9
 
10
- import zarr
10
+ from .zarr import Group
11
11
 
12
12
 
13
13
  class FigpackView:
@@ -155,7 +155,7 @@ class FigpackView:
155
155
 
156
156
  _save_figure(self, output_path, title=title)
157
157
 
158
- def _write_to_zarr_group(self, group: zarr.Group) -> None:
158
+ def _write_to_zarr_group(self, group: Group) -> None:
159
159
  """
160
160
  Write the view data to a Zarr group. Must be implemented by subclasses.
161
161
 
@@ -0,0 +1,61 @@
1
+ from typing import Any, Dict
2
+ import zarr
3
+
4
+
5
+ _UNSPECIFIED = object()
6
+
7
+
8
+ class Group:
9
+ def __init__(self, zarr_group: zarr.Group):
10
+ self._zarr_group = zarr_group
11
+
12
+ def create_group(self, name: str) -> "Group":
13
+ return Group(self._zarr_group.create_group(name))
14
+
15
+ def create_dataset(
16
+ self,
17
+ name: str,
18
+ *,
19
+ data=_UNSPECIFIED,
20
+ dtype=_UNSPECIFIED,
21
+ chunks=_UNSPECIFIED,
22
+ compressor=_UNSPECIFIED,
23
+ ) -> None:
24
+ kwargs = {}
25
+ if data is not _UNSPECIFIED:
26
+ kwargs["data"] = data
27
+ if dtype is not _UNSPECIFIED:
28
+ kwargs["dtype"] = dtype
29
+ if chunks is not _UNSPECIFIED:
30
+ kwargs["chunks"] = chunks
31
+ if compressor is not _UNSPECIFIED:
32
+ kwargs["compressor"] = compressor
33
+ if _check_zarr_version() == 2:
34
+ self._zarr_group.create_dataset(name, **kwargs)
35
+ elif _check_zarr_version() == 3:
36
+ self._zarr_group.create_array(name, **kwargs)
37
+ else:
38
+ raise RuntimeError("Unsupported Zarr version")
39
+
40
+ @property
41
+ def attrs(self) -> Dict[str, Any]:
42
+ return self._zarr_group.attrs
43
+
44
+ def __getitem__(self, key: str) -> Any:
45
+ return self._zarr_group[key]
46
+
47
+ # implement in operator
48
+ def __contains__(self, key: str) -> bool:
49
+ return key in self._zarr_group
50
+
51
+ def __iter__(self):
52
+ return iter(self._zarr_group)
53
+
54
+ def __reversed__(self):
55
+ return reversed(self._zarr_group)
56
+
57
+
58
+ def _check_zarr_version():
59
+ version = zarr.__version__
60
+ major_version = int(version.split(".")[0])
61
+ return major_version