1+ # /// script
2+ # dependencies = [
3+ # "zarr",
4+ # "numpy",
5+ # "fsspec",
6+ # ]
7+ # ///
18"""
29ZEP 8 URL Syntax Demo
310
2027
2128import zarr
2229from zarr .core .url_syntax import URLParser , is_zep8_url
23- from zarr .registry import get_store_adapter
2430from zarr .storage import ZipStore
2531
2632
2733def demo_basic_zep8 () -> None :
2834 """Demonstrate basic ZEP 8 URL syntax features."""
2935 print ("=== Basic ZEP 8 URL Demo ===" )
3036
31- try :
32- print ("📝 Testing basic ZEP 8 URL formats" )
33-
34- # Memory store
35- print ("\n 1. Memory store:" )
36- memory_url = "memory:"
37- root = zarr .open_group (memory_url , mode = "w" )
38- arr = root .create_array ("test_data" , shape = (10 ,), dtype = "f4" )
39- arr [:] = np .random .random (10 )
40- print (f"✅ Created array via { memory_url } " )
41- print (f" Data shape: { arr .shape } , dtype: { arr .dtype } " )
42-
43- # File store
44- print ("\n 2. File store:" )
45- with tempfile .TemporaryDirectory () as tmpdir :
46- file_url = f"file:{ tmpdir } /test.zarr"
47- root2 = zarr .open_group (file_url , mode = "w" )
48- arr2 = root2 .create_array ("persistent_data" , shape = (20 ,), dtype = "i4" )
49- arr2 [:] = range (20 )
50- print (f"✅ Created array via { file_url } " )
51- print (f" Data: { list (arr2 [:5 ])} ... (first 5 elements)" )
37+ print ("📝 Testing basic ZEP 8 URL formats" )
5238
53- except Exception as e :
54- print (f"❌ Demo failed: { e } " )
39+ # Memory store
40+ print ("\n 1. Memory store:" )
41+ memory_url = "memory:"
42+ root = zarr .open_group (memory_url , mode = "w" )
43+ arr = root .create_array ("test_data" , shape = (10 ,), dtype = "f4" )
44+ arr [:] = np .random .random (10 )
45+ print (f"✅ Created array via { memory_url } " )
46+ print (f" Data shape: { arr .shape } , dtype: { arr .dtype } " )
47+
48+ # File store
49+ print ("\n 2. File store:" )
50+ with tempfile .TemporaryDirectory () as tmpdir :
51+ file_url = f"file:{ tmpdir } /test.zarr"
52+ root2 = zarr .open_group (file_url , mode = "w" )
53+ arr2 = root2 .create_array ("persistent_data" , shape = (20 ,), dtype = "i4" )
54+ arr2 [:] = range (20 )
55+ print (f"✅ Created array via { file_url } " )
56+ print (f" Data: { list (arr2 [:5 ])} ... (first 5 elements)" )
5557
5658
5759def demo_zip_chaining () -> None :
5860 """Demonstrate ZIP file chaining with ZEP 8 URLs."""
5961 print ("\n === ZIP Chaining Demo ===" )
6062
61- try :
62- print ("📝 Creating ZIP file with zarr data, then accessing via ZEP 8 URL" )
63-
64- with tempfile .TemporaryDirectory () as tmpdir :
65- zip_path = Path (tmpdir ) / "data.zip"
66-
67- # Step 1: Create ZIP file with zarr data
68- print (f"Creating ZIP file at: { zip_path } " )
69- with ZipStore (str (zip_path ), mode = "w" ) as zip_store :
70- root = zarr .open_group (zip_store , mode = "w" )
71-
72- # Create sample datasets
73- temps = root .create_array ("temperatures" , shape = (365 ,), dtype = "f4" )
74- temps [:] = (
75- 20 + 10 * np .sin (np .arange (365 ) * 2 * np .pi / 365 ) + np .random .normal (0 , 2 , 365 )
76- )
77- temps .attrs ["units" ] = "celsius"
78- temps .attrs ["description" ] = "Daily temperature readings"
79-
80- metadata = root .create_group ("metadata" )
81- info = metadata .create_array ("info" , shape = (1 ,), dtype = "U50" )
82- info [0 ] = "Weather data from ZIP demo"
83-
84- print ("✅ Created temperature data in ZIP file" )
85- print (f" Temperature range: { temps [:].min ():.1f} °C to { temps [:].max ():.1f} °C" )
86-
87- # Step 2: Access via ZEP 8 URL syntax
88- print ("\n Accessing ZIP data via ZEP 8 URL" )
89- zip_url = f"file:{ zip_path } |zip:"
90- root_read = zarr .open_group (zip_url , mode = "r" )
91-
92- temps_read = root_read ["temperatures" ]
93- info_read = root_read ["metadata/info" ]
94-
95- print (f"✅ Successfully read via URL: { zip_url } " )
96- print (f" Temperature units: { temps_read .attrs ['units' ]} " )
97- print (f" Description: { temps_read .attrs ['description' ]} " )
98- print (f" Metadata: { info_read [0 ]} " )
99- print (f" Data integrity: { np .array_equal (temps [:], temps_read [:])} " )
100-
101- except ImportError as e :
102- print (f"❌ Required dependencies missing: { e } " )
103- except Exception as e :
104- print (f"❌ Demo failed: { e } " )
63+ print ("📝 Creating ZIP file with zarr data, then accessing via ZEP 8 URL" )
10564
65+ with tempfile .TemporaryDirectory () as tmpdir :
66+ zip_path = Path (tmpdir ) / "data.zip"
10667
107- def demo_adapter_registry () -> None :
108- """Show available store adapters and their usage."""
109- print ("\n === Store Adapter Registry Demo ===" )
68+ # Step 1: Create ZIP file with zarr data
69+ print (f"Creating ZIP file at: { zip_path } " )
70+ with ZipStore (str (zip_path ), mode = "w" ) as zip_store :
71+ root = zarr .open_group (zip_store , mode = "w" )
11072
111- try :
112- print ("📋 Testing common store adapters:" )
73+ # Create sample datasets
74+ temps = root .create_array ("temperatures" , shape = (365 ,), dtype = "f4" )
75+ temp_data = (
76+ 20 + 10 * np .sin (np .arange (365 ) * 2 * np .pi / 365 ) + np .random .normal (0 , 2 , 365 )
77+ )
78+ temps [:] = temp_data
79+ temps .attrs ["units" ] = "celsius"
80+ temps .attrs ["description" ] = "Daily temperature readings"
11381
114- # Test builtin adapters
115- builtin_adapters = ["memory" , "file" , "zip" ]
82+ metadata = root .create_group ("metadata" )
83+ info = metadata .create_array ("info" , shape = (1 ,), dtype = "U50" )
84+ info [0 ] = "Weather data from ZIP demo"
11685
117- for adapter_name in builtin_adapters :
118- try :
119- adapter_cls = get_store_adapter (adapter_name )
120- print (f"✅ { adapter_name } : { adapter_cls .__name__ } " )
121- except KeyError :
122- print (f"❌ { adapter_name } : Not registered" )
86+ print ("✅ Created temperature data in ZIP file" )
87+ print (f" Temperature range: { temps [:].min ():.1f} °C to { temps [:].max ():.1f} °C" )
12388
124- # Test optional adapters
125- optional_adapters = ["icechunk" , "ic" , "s3" , "gcs" ]
126- print ("\n 📋 Testing optional adapters:" )
89+ # Step 2: Access via ZEP 8 URL syntax
90+ print ("\n Accessing ZIP data via ZEP 8 URL" )
91+ zip_url = f"file:{ zip_path } |zip:"
92+ root_read = zarr .open_group (zip_url , mode = "r" )
12793
128- for adapter_name in optional_adapters :
129- try :
130- adapter_cls = get_store_adapter (adapter_name )
131- print (f"✅ { adapter_name } : { adapter_cls .__name__ } " )
132- except KeyError :
133- print (f"i { adapter_name } : Not available (requires additional packages)" )
94+ temps_read = root_read ["temperatures" ]
95+ info_read = root_read ["metadata/info" ]
13496
135- except Exception as e :
136- print (f"❌ Demo failed: { e } " )
97+ print (f"✅ Successfully read via URL: { zip_url } " )
98+ print (f" Temperature units: { temps_read .attrs ['units' ]} " )
99+ print (f" Description: { temps_read .attrs ['description' ]} " )
100+ print (f" Metadata: { info_read [0 ]} " )
101+ print (f" Data integrity: { np .array_equal (temp_data , temps_read [:])} " )
137102
138103
139104def demo_url_parsing () -> None :
140105 """Demonstrate ZEP 8 URL parsing and validation."""
141106 print ("\n === URL Parsing Demo ===" )
142107
143- try :
144- parser = URLParser ()
145-
146- test_urls = [
147- "memory:" ,
148- "file:/tmp/data.zarr" ,
149- "file:/tmp/data.zip|zip:" ,
150- "s3://bucket/data.zip|zip:|zarr3:" ,
151- "memory:|icechunk:branch:main" , # This would be rejected by icechunk adapter
152- "/regular/file/path" , # Not a ZEP 8 URL
153- ]
154-
155- print ("📝 Testing URL parsing:" )
156-
157- for url in test_urls :
158- is_zep8 = is_zep8_url (url )
159- print (f"\n URL: { url } " )
160- print (f" ZEP 8: { is_zep8 } " )
161-
162- if is_zep8 :
163- try :
164- segments = parser .parse (url )
165- print (f" Segments: { len (segments )} " )
166- for i , seg in enumerate (segments ):
167- scheme_part = f"scheme={ seg .scheme } " if seg .scheme else ""
168- adapter_part = f"adapter={ seg .adapter } " if seg .adapter else ""
169- path_part = f"path='{ seg .path } '" if seg .path else ""
170- parts = [p for p in [scheme_part , adapter_part , path_part ] if p ]
171- print (f" { i } : { ', ' .join (parts )} " )
172- except Exception as e :
173- print (f" Parse error: { e } " )
108+ parser = URLParser ()
174109
175- except Exception as e :
176- print (f"❌ Demo failed: { e } " )
110+ test_urls = [
111+ "memory:" ,
112+ "file:/tmp/data.zarr" ,
113+ "file:/tmp/data.zip|zip:" ,
114+ "s3://bucket/data.zip|zip:|zarr3:" ,
115+ "memory:|icechunk:branch:main" , # This would be rejected by icechunk adapter
116+ "/regular/file/path" , # Not a ZEP 8 URL
117+ ]
118+
119+ print ("📝 Testing URL parsing:" )
120+
121+ for url in test_urls :
122+ is_zep8 = is_zep8_url (url )
123+ print (f"\n URL: { url } " )
124+ print (f" ZEP 8: { is_zep8 } " )
125+
126+ if is_zep8 :
127+ try :
128+ segments = parser .parse (url )
129+ print (f" Segments: { len (segments )} " )
130+ for i , seg in enumerate (segments ):
131+ scheme_part = f"scheme={ seg .scheme } " if seg .scheme else ""
132+ adapter_part = f"adapter={ seg .adapter } " if seg .adapter else ""
133+ path_part = f"path='{ seg .path } '" if seg .path else ""
134+ parts = [p for p in [scheme_part , adapter_part , path_part ] if p ]
135+ print (f" { i } : { ', ' .join (parts )} " )
136+ except Exception as e :
137+ print (f" Parse error: { e } " )
177138
178139
179140def demo_error_cases () -> None :
180141 """Demonstrate common error cases and their handling."""
181142 print ("\n === Error Handling Demo ===" )
182143
183- try :
184- print ("🚫 Testing error cases:" )
185-
186- # Test 1: Invalid URL format
187- print ("\n 1. Invalid URL formats:" )
188- invalid_urls = [
189- "|invalid:start" , # Starts with pipe
190- "memory:|" , # Ends with pipe
191- "memory:||zip:" , # Double pipe
192- "" , # Empty URL
193- ]
194-
195- for url in invalid_urls :
196- try :
197- zarr .open_group (url , mode = "r" )
198- print (f"❌ Should have failed: { url } " )
199- except Exception as e :
200- print (f"✅ Correctly rejected: { url } -> { type (e ).__name__ } " )
144+ print ("🚫 Testing error cases:" )
145+
146+ # Test 1: Invalid URL format
147+ print ("\n 1. Invalid URL formats:" )
148+ invalid_urls = [
149+ "|invalid:start" , # Starts with pipe
150+ "memory:|" , # Ends with pipe
151+ "memory:||zip:" , # Double pipe
152+ "" , # Empty URL
153+ ]
201154
202- # Test 2: Unknown adapters
203- print ("\n 2. Unknown adapters:" )
155+ for url in invalid_urls :
204156 try :
205- zarr .open_group ("memory:|unknown_adapter:" , mode = "r" )
206- print ("❌ Should have failed: unknown adapter " )
157+ zarr .open_group (url , mode = "r" )
158+ print (f "❌ Should have failed: { url } " )
207159 except Exception as e :
208- print (f"✅ Correctly rejected unknown adapter -> { type (e ).__name__ } " )
160+ print (f"✅ Correctly rejected: { url } -> { type (e ).__name__ } " )
209161
210- # Test 3: Fallback behavior
211- print ("\n 3. Fallback to regular stores:" )
212- regular_urls = ["memory:" , f"file:{ tempfile .mkdtemp ()} /fallback.zarr" ]
162+ # Test 2: Unknown adapters
163+ print ("\n 2. Unknown adapters:" )
164+ try :
165+ zarr .open_group ("memory:|unknown_adapter:" , mode = "r" )
166+ print ("❌ Should have failed: unknown adapter" )
167+ except Exception as e :
168+ print (f"✅ Correctly rejected unknown adapter -> { type (e ).__name__ } " )
213169
214- for url in regular_urls :
215- try :
216- root = zarr .open_group (url , mode = "w" )
217- arr = root .create_array ("data" , shape = (5 ,), dtype = "i4" )
218- arr [:] = [1 , 2 , 3 , 4 , 5 ]
219- print (f"✅ Fallback works: { url } " )
220- except Exception as e :
221- print (f"❌ Fallback failed: { url } -> { e } " )
170+ # Test 3: Fallback behavior
171+ print ("\n 3. Fallback to regular stores:" )
172+ regular_urls = ["memory:" , f"file:{ tempfile .mkdtemp ()} /fallback.zarr" ]
222173
223- except Exception as e :
224- print (f"❌ Demo failed: { e } " )
174+ for url in regular_urls :
175+ try :
176+ root = zarr .open_group (url , mode = "w" )
177+ arr = root .create_array ("data" , shape = (5 ,), dtype = "i4" )
178+ arr [:] = [1 , 2 , 3 , 4 , 5 ]
179+ print (f"✅ Fallback works: { url } " )
180+ except Exception as e :
181+ print (f"❌ Fallback failed: { url } -> { e } " )
225182
226183
227184if __name__ == "__main__" :
@@ -230,7 +187,6 @@ def demo_error_cases() -> None:
230187
231188 demo_basic_zep8 ()
232189 demo_zip_chaining ()
233- demo_adapter_registry ()
234190 demo_url_parsing ()
235191 demo_error_cases ()
236192
0 commit comments