Source code for pynbody.util.iter_subclasses

"""Provides a mix-in class for iterating over all subclasses of a given class, possibly in a user-specified order."""

from __future__ import annotations

from typing import Iterable


[docs] class IterableSubclasses: """A mixin for classes where we need to be able to iterate over their subclasses, possibly in a user-specified order. This is used by HaloCatalogue and SimSnap to find a suitable loader for a given file. """
[docs] @classmethod def iter_subclasses(cls) -> Iterable[type]: """Iterate over all subclasses of this class, recursively. This is used by HaloCatalogue and SimSnap to find a suitable loader for a given file.""" for c in cls.__subclasses__(): yield from c.iter_subclasses() yield c
[docs] @classmethod def iter_subclasses_with_priority(cls, priority: Iterable[str | type]) -> Iterable[type]: """Iterate over all subclasses, starting with the given priorities The priorities can be provided either as a string or a class""" all_subclasses = list(cls.iter_subclasses()) all_subclasses_name = [s.__name__ for s in all_subclasses] for next_priority in priority: if isinstance(next_priority, type): if next_priority in all_subclasses: index = all_subclasses.index(next_priority) del all_subclasses[index] del all_subclasses_name[index] yield next_priority else: if next_priority not in all_subclasses_name: raise ValueError(f"Unknown class {next_priority}") next_priority_index = all_subclasses_name.index(next_priority) yield all_subclasses[next_priority_index] del all_subclasses[next_priority_index] del all_subclasses_name[next_priority_index] # now iterate the rest yield from all_subclasses