@@ -46,29 +46,52 @@ def load_component(
4646 location : NeXusLocationSpec ,
4747 * ,
4848 nx_class : type [snx .NXobject ],
49+ parent_class : type [snx .NXobject ] | None = None ,
4950 definitions : Mapping | None | NoNewDefinitionsType = NoNewDefinitions ,
5051) -> sc .DataGroup :
51- """Load a single component of a given class from NeXus."""
52+ """Load a single component of a given class from NeXus.
53+
54+ Parameters
55+ ----------
56+ location:
57+ Specifies (part of) the location of the component to load.
58+ nx_class:
59+ NeXus class of the component to load.
60+ parent_class:
61+ NeXus class of the parent of the component to load.
62+ If ``None``, is deduced from ``nx_class`` if possible.
63+ definitions:
64+ Application definitions to use for the file.
65+
66+ Returns
67+ -------
68+ :
69+ The loaded component as a data group.
70+ """
5271 selection = location .selection
53- group_name = location .component_name
54- with _open_component_parent (
55- location , nx_class = nx_class , definitions = definitions
56- ) as parent :
57- component = _unique_child_group (parent , nx_class , group_name )
58- loaded = cast (sc .DataGroup , component [selection ])
59- loaded ['nexus_component_name' ] = component .name .rsplit ('/' , 1 )[- 1 ]
72+ with open_component_group (
73+ location ,
74+ nx_class = nx_class ,
75+ parent_class = parent_class ,
76+ definitions = definitions ,
77+ ) as group :
78+ loaded = cast (sc .DataGroup , group [selection ])
79+ loaded ['nexus_component_name' ] = group .name .rsplit ('/' , 1 )[- 1 ]
6080 return loaded
6181
6282
6383def load_all_components (
6484 location : NeXusAllLocationSpec ,
6585 * ,
6686 nx_class : type [snx .NXobject ],
87+ parent_class : type [snx .NXobject ] | None = None ,
6788 definitions : Mapping | None | NoNewDefinitionsType = NoNewDefinitions ,
6889) -> sc .DataGroup :
6990 """Load all components of a given class from NeXus."""
7091 with _open_component_parent (
71- location , nx_class = nx_class , definitions = definitions
92+ location ,
93+ parent_class = _deduce_component_parent_class (nx_class , parent_class ),
94+ definitions = definitions ,
7295 ) as parent :
7396 components = sc .DataGroup ()
7497 for name , component in parent [nx_class ].items ():
@@ -119,6 +142,29 @@ def open_nexus_file(
119142 * ,
120143 locking : bool | str | None | NoLockingIfNeededType = NoLockingIfNeeded ,
121144) -> AbstractContextManager [snx .Group ]:
145+ """Open a NeXus file.
146+
147+ Parameters
148+ ----------
149+ file_path:
150+ Path of the file to open or a NeXus file or group handle.
151+ definitions:
152+ If set, application definitions to use for the file.
153+ If ``file_path`` is a NeXus file or group, this must be unset or match
154+ the existing definitions.
155+ locking:
156+ This is an advanced feature to work around a limitation of the DMSC file system.
157+ It may be removed in the future.
158+
159+ This flag can disable or force locking the HDF5 file.
160+ By default, the file is locked if possible but may remain unlocked
161+ if it is on a read-only filesystem.
162+
163+ Returns
164+ -------
165+ :
166+ A context manager for the opened file.
167+ """
122168 if isinstance (file_path , getattr (NeXusGroup , '__supertype__' , type (None ))):
123169 if (
124170 definitions is not NoNewDefinitions
@@ -203,21 +249,77 @@ def _open_nexus_file_from_path(
203249
204250
205251@contextmanager
206- def _open_component_parent (
252+ def open_component_group (
207253 location : NeXusLocationSpec ,
208254 * ,
209255 nx_class : type [snx .NXobject ],
256+ parent_class : type [snx .NXobject ] | None = None ,
257+ definitions : Mapping | None | NoNewDefinitionsType = NoNewDefinitions ,
258+ ) -> Generator [snx .Group , None , None ]:
259+ """Open the HDF5 group of a NeXus component.
260+
261+ Parameters
262+ ----------
263+ location:
264+ Specifies (part of) the location of the component to load.
265+ nx_class:
266+ NeXus class of the component to load.
267+ parent_class:
268+ NeXus class of the parent of the component to load.
269+ If ``None``, is deduced from ``nx_class`` if possible.
270+ definitions:
271+ Application definitions to use for the file.
272+
273+ Returns
274+ -------
275+ :
276+ A context manager for the group of the specified component.
277+ """
278+ group_name = location .component_name
279+ with _open_component_parent (
280+ location ,
281+ parent_class = _deduce_component_parent_class (nx_class , parent_class ),
282+ definitions = definitions ,
283+ ) as parent :
284+ yield _unique_child_group (parent , nx_class , group_name )
285+
286+
287+ @contextmanager
288+ def _open_component_parent (
289+ location : NeXusLocationSpec ,
290+ * ,
291+ parent_class : type [snx .NXobject ],
210292 definitions : Mapping | None | NoNewDefinitionsType = NoNewDefinitions ,
211293) -> Generator [snx .Group , None , None ]:
212294 """Locate the parent group of a NeXus component."""
213295 file_path = location .filename
214296 entry_name = location .entry_name
215297 with open_nexus_file (file_path , definitions = definitions ) as f :
216298 entry = _unique_child_group (f , snx .NXentry , entry_name )
217- if nx_class is snx .NXsample :
218- yield entry
219- else :
220- yield _unique_child_group (entry , snx .NXinstrument , None )
299+ match parent_class :
300+ case snx .NXentry :
301+ yield entry
302+ case snx .NXinstrument :
303+ yield _unique_child_group (entry , snx .NXinstrument , None )
304+ case _:
305+ raise NotImplementedError (
306+ f"No support for loading a NeXus component from a { parent_class } ."
307+ )
308+
309+
310+ def _deduce_component_parent_class (
311+ nx_class : type [snx .NXobject ], parent_class : type [snx .NXobject ] | None
312+ ) -> type [snx .NXobject ]:
313+ if parent_class is not None :
314+ return parent_class
315+
316+ match nx_class :
317+ case snx .NXsample :
318+ return snx .NXentry
319+ case _:
320+ # Most components are in the instrument,
321+ # callers need to override this for specialized components stored elsewhere.
322+ return snx .NXinstrument
221323
222324
223325def _unique_child_group (
0 commit comments