@@ -100,20 +100,20 @@ def shape(self) -> Tuple[int, ...]:
100100 array, based on the hierarchy of slicing operations performed.
101101
102102 Raises:
103- ValueError: The underlying data is ragged (non-rectangular). Use
104- .is_ragged to check first, or use .values() to extract values
105- as a flat list.
103+ ValueError: The underlying data is ragged (non-rectangular).
104+ Use .is_ragged to check first, or use .values() to extract
105+ values as a flat list.
106106
107107 Returns:
108108 Tuple of dimensions.
109109 """
110110 if self .is_ragged :
111111 raise ValueError (
112- f "Cannot get shape of ragged array: dimensions have varying sizes. "
113- f" Use .is_ragged to check if data is ragged, or .values() to "
114- f" get a flat list of elements."
112+ "Cannot get shape of ragged array: dimensions have varying "
113+ "sizes. Use .is_ragged to check if data is ragged, or .values() "
114+ "to get a flat list of elements."
115115 )
116-
116+
117117 # Build shape from hierarchy
118118 shape = []
119119 for i , hierarchy_level in enumerate (self ._element_hierarchy ):
@@ -129,7 +129,7 @@ def shape(self) -> Tuple[int, ...]:
129129 else :
130130 # This is a single count
131131 shape .append (hierarchy_level )
132-
132+
133133 return tuple (shape )
134134
135135 def __len__ (self ) -> int :
@@ -211,13 +211,15 @@ def _handle_list_slice(self, item: slice) -> "IDSSlice":
211211 IDSSlice with updated shape and hierarchy
212212 """
213213 from imas .ids_struct_array import IDSStructArray
214-
214+
215215 slice_str = self ._format_slice (item )
216216 # Full path: current path + slice operation
217217 full_path = self ._path + slice_str
218218
219219 # Check if matched elements are IDSStructArray (nested arrays)
220- if self ._matched_elements and isinstance (self ._matched_elements [0 ], IDSStructArray ):
220+ if self ._matched_elements and isinstance (
221+ self ._matched_elements [0 ], IDSStructArray
222+ ):
221223 # When slicing nested arrays, apply slice to each array and then flatten
222224 flattened_elements = []
223225 new_hierarchy_values = []
@@ -227,25 +229,28 @@ def _handle_list_slice(self, item: slice) -> "IDSSlice":
227229 # Flatten: add each element from the sliced array to flattened list
228230 for element in sliced_array :
229231 flattened_elements .append (element )
230-
232+
231233 # Build new hierarchy
232- # The key is: if we have a multi-level grouped hierarchy (like [3, [2, 2, 2], ...]),
233- # we're dealing with a nested structure that's already been flattened.
234- # We should only update the innermost level, NOT create a new top-level grouping.
235-
234+ # The key is: if we have a multi-level grouped hierarchy
235+ # (like [3, [2, 2, 2], ...]), we're dealing with a nested
236+ # structure that's already been flattened. We should only update
237+ # the innermost level, NOT create a new top-level grouping.
238+
236239 num_groups = len (self ._matched_elements )
237-
238- if (len (self ._element_hierarchy ) >= 2 and
239- isinstance (self ._element_hierarchy [0 ], int ) and
240- isinstance (self ._element_hierarchy [1 ], list )):
240+
241+ if (
242+ len (self ._element_hierarchy ) >= 2
243+ and isinstance (self ._element_hierarchy [0 ], int )
244+ and isinstance (self ._element_hierarchy [1 ], list )
245+ ):
241246 # Multi-level hierarchy like [3, [2, 2, 2], ...]
242247 # The top level is the original grouping, so DON'T recreate it
243248 # Just replace the last (innermost) level
244249 new_hierarchy = self ._element_hierarchy [:- 1 ] + [new_hierarchy_values ]
245250 else :
246251 # Single level or not grouped yet - create new grouping
247252 new_hierarchy = [num_groups , new_hierarchy_values ]
248-
253+
249254 return IDSSlice (
250255 self .metadata ,
251256 flattened_elements ,
@@ -257,7 +262,7 @@ def _handle_list_slice(self, item: slice) -> "IDSSlice":
257262 else :
258263 # Normal slice on outer list
259264 sliced_elements = self ._matched_elements [item ]
260-
265+
261266 # Update shape to reflect the slice on first dimension
262267 new_virtual_shape = (len (sliced_elements ),) + self ._virtual_shape [1 :]
263268 new_element_hierarchy = [len (sliced_elements )] + self ._element_hierarchy [1 :]
@@ -316,7 +321,9 @@ def __getattr__(self, name: str) -> "IDSSlice":
316321
317322 # Get attributes from all non-empty matched elements
318323 # Special case: if matched_elements are IDSStructArray, keep them grouped
319- if self ._matched_elements and isinstance (self ._matched_elements [0 ], IDSStructArray ):
324+ if self ._matched_elements and isinstance (
325+ self ._matched_elements [0 ], IDSStructArray
326+ ):
320327 # For nested arrays, return the arrays themselves, not attributes from them
321328 # This allows chaining like .ion[:].element[:] to work
322329 child_elements = self ._matched_elements
@@ -335,19 +342,21 @@ def __getattr__(self, name: str) -> "IDSSlice":
335342 element_hierarchy = self ._element_hierarchy ,
336343 )
337344
338- # If matched_elements are IDSStructArray and we're accessing an attribute on them,
339- # we need to get that attribute from each array's elements
345+ # If matched_elements are IDSStructArray and we're accessing an
346+ # attribute on them, we need to get that attribute from each
347+ # array's elements
340348 if isinstance (self ._matched_elements [0 ], IDSStructArray ):
341- # Accessing attribute on nested arrays: need to get attr from each array's elements
349+ # Accessing attribute on nested arrays: get attr from each
350+ # array's elements
342351 flattened_elements = []
343352 for array in child_elements :
344- # array is IDSStructArray, get the attribute from its elements
353+ # array is IDSStructArray, get attribute from its elements
345354 for element in array :
346355 flattened_elements .append (getattr (element , name ))
347-
356+
348357 # Keep track of grouping for shape preservation
349358 child_sizes = [len (array ) for array in child_elements ]
350-
359+
351360 return IDSSlice (
352361 child_metadata ,
353362 flattened_elements ,
@@ -417,21 +426,24 @@ def __repr__(self) -> str:
417426 """
418427 ids_name = self .metadata .ids_name
419428 item_word = "item" if len (self ) == 1 else "items"
420- return f"<{ type (self ).__name__ } (IDS:{ ids_name } , { self ._path } with { len (self )} { item_word } )>"
429+ return (
430+ f"<{ type (self ).__name__ } (IDS:{ ids_name } , { self ._path } with "
431+ f"{ len (self )} { item_word } )>"
432+ )
421433
422434 def values (self ) -> List [Any ]:
423435 """Extract raw values from elements in this slice.
424436
425437 For IDSPrimitive elements, this extracts the wrapped value.
426438 For other element types, returns them as-is.
427439
428- Returns a flat list of extracted values. This is useful for getting
429- the actual data without the IDS wrapper when accessing scalar fields
430- through a slice, without requiring explicit looping through the
440+ Returns a flat list of extracted values. This is useful for getting
441+ the actual data without the IDS wrapper when accessing scalar fields
442+ through a slice, without requiring explicit looping through the
431443 original collection.
432444
433445 For multi-dimensional access to values:
434- - Use direct indexing: ``ids_obj[i1].collection[i2].value`` for best
446+ - Use direct indexing: ``ids_obj[i1].collection[i2].value`` for best
435447 performance and clarity
436448 - Use ``.to_array()`` if you need numpy array integration
437449
@@ -491,12 +503,14 @@ def to_array(self) -> np.ndarray:
491503 Tensorize a 1D slice of numeric data::
492504
493505 # Works: leaf nodes are numeric arrays
494- array = core_profiles.profiles_1d[:].te.to_array() # Shape: (n_profiles,)
506+ array = core_profiles.profiles_1d[:].te.to_array()
507+ # Shape: (n_profiles,)
495508
496509 Multi-dimensional tensorization::
497510
498511 # Works: accessing leaf nodes from nested structure
499- array = core_profiles.profiles_1d[:].te.to_array() # Shape: (n_profiles,)
512+ array = core_profiles.profiles_1d[:].te.to_array()
513+ # Shape: (n_profiles,)
500514
501515 Direct indexing for non-leaf nodes::
502516
@@ -516,17 +530,17 @@ def to_array(self) -> np.ndarray:
516530 first = self ._matched_elements [0 ]
517531 if isinstance (first , (IDSStructure , IDSStructArray )):
518532 raise ValueError (
519- f"Cannot tensorize { type (first ).__name__ } slice - only works for "
520- f"leaf nodes (scalars, numeric arrays). Use direct indexing instead: "
521- f"ids[i][j] to access structures."
533+ f"Cannot tensorize { type (first ).__name__ } slice - only "
534+ f"works for leaf nodes (scalars, numeric arrays). Use "
535+ f"direct indexing instead: ids[i][j] to access structures."
522536 )
523537
524538 # Validate: data must be rectangular (not ragged)
525539 if self .is_ragged :
526540 raise ValueError (
527- f "Cannot tensorize ragged array - dimensions have varying sizes. "
528- f" Use .values() to get a flat list, or use direct indexing for "
529- f" multi-dimensional access."
541+ "Cannot tensorize ragged array - dimensions have varying "
542+ "sizes. Use .values() to get a flat list, or use direct "
543+ "indexing for multi-dimensional access."
530544 )
531545
532546 # Get the target shape (we validated it's not ragged)
@@ -548,11 +562,11 @@ def to_array(self) -> np.ndarray:
548562
549563 # Tensorize to target shape
550564 arr = np .array (flat_values )
551-
565+
552566 # For 1D, no reshape needed
553567 if len (actual_shape ) == 1 :
554568 return arr
555-
569+
556570 # For multi-dimensional, reshape to target shape
557571 try :
558572 return arr .reshape (actual_shape )
0 commit comments