Source code for astra.observatory_loader

import importlib.util
import logging
from pathlib import Path
from typing import List, Optional, Type

from astra import Config
from astra.observatory import Observatory


[docs] class ObservatoryLoader: """ Load an Observatory subclass based on the observatory name. Examples: >>> from astra.observatory_loader import ObservatoryLoader >>> ObservatoryLoader(observatory_name="MyObservatory").load() """ def __init__(self, observatory_name: Optional[str] = None): self.observatory_name = observatory_name self.custom_observatories = Config().paths.custom_observatories
[docs] def load(self) -> Type[Observatory]: """Return an Observatory class: plugin-provided subclass if available, else default.""" if self.observatory_name is None: return Observatory target = self.observatory_name.lower() for observatory_path in self.custom_observatories.glob("*.py"): classes = self._try_load_from_path(observatory_path) for cls in classes: if not isinstance(cls, type) or not issubclass(cls, Observatory): continue # Match against class name and aliases candidates = {cls.__name__.lower()} | { item.lower() for item in getattr(cls, "OBSERVATORY_ALIASES", []) if isinstance(item, str) } if target in candidates: return cls return Observatory
[docs] def _try_load_from_path(self, path: Path) -> List[Type[Observatory]]: """Attempt to load all Observatory subclasses from the specified path.""" found: List[Type[Observatory]] = [] try: spec = importlib.util.spec_from_file_location(path.stem, path) if spec and spec.loader: module = importlib.util.module_from_spec(spec) spec.loader.exec_module(module) for attr_name in dir(module): attr = getattr(module, attr_name) if ( isinstance(attr, type) and issubclass(attr, Observatory) and attr is not Observatory ): found.append(attr) except Exception as e: logging.error(f"Error loading module from {path}: {e}") return found