Source code for phise.classes.target

import astropy.units as u
from copy import deepcopy as copy
from typing import Union
from .companion import Companion

class CompanionList(list):
    """Custom list to manage companions with type checking.

    Args:
        companions (iterable, optional): Iterable of Companion objects to initialize the list.

    Raises:
        TypeError: If any item in the iterable is not a Companion.
    """

    def __init__(self, companions=None):
        if companions is None:
            companions = []
        else:
            for companion in companions:
                if not isinstance(companion, Companion):
                    raise TypeError('Only Companion objects can be added to CompanionList')
        super().__init__(companions)

    def append(self, companion: Companion):
        """Append a companion after type checking.

        Args:
            companion (Companion): Companion to append.

        Raises:
            TypeError: If the item is not a Companion.
        """
        if not isinstance(companion, Companion):
            raise TypeError('Only Companion objects can be added to CompanionList')
        super().append(companion)

    def extend(self, companions):
        """Extend the list with multiple companions after type checking.

        Args:
            companions (iterable): Iterable of companions to add.

        Raises:
            TypeError: If any item is not a Companion.
        """
        for companion in companions:
            if not isinstance(companion, Companion):
                raise TypeError('Only Companion objects can be added to CompanionList')
        super().extend(companions)

    def __setitem__(self, index, companion: Companion):
        """Set an item after type checking.
        
        Args:
            index (int): Index to set.
            companion (Companion): Companion to set.

        Raises:
            TypeError: If the item is not a Companion."""
        if not isinstance(companion, Companion):
            raise TypeError('Only Companion objects can be assigned in CompanionList')
        super().__setitem__(index, companion)

    def insert(self, index: int, companion: Companion):
        """Insert a companion after type checking.

        Args:
            index (int): Index to insert at.
            companion (Companion): Companion to insert. 

        Raises:
            TypeError: If the item is not a Companion.
        """
        if not isinstance(companion, Companion):
            raise TypeError('Only Companion objects can be inserted in CompanionList')
        super().insert(index, companion)

[docs] class Target: """Target star with declination, spectral flux, and companions. Args: f (u.Quantity): Spectral flux of the star. δ (u.Quantity): Declination of the star. companions (list[Companion]): List of companions. name (str, optional): Target name (default: "Unnamed Target"). """ __slots__ = ('_parent_ctx', '_f', '_f_unit', '_δ', '_δ_unit', '_companions', '_name') def __init__(self, f: u.Quantity, δ: u.Quantity, companions: Union[list[Companion], CompanionList], name: str='Unnamed Target'): self._parent_ctx = None self.f = f self.δ = δ self.companions = companions self.name = name def __str__(self) -> str: res = f'Target "{self.name}"\n' res += f' f: {self.f:.2g}\n' res += f' δ: {self.δ:.2g}\n' res += f' Companions:\n' lines = [] for companion in self.companions: lines += str(companion).split('\n') res += f' ' + '\n '.join(lines) return res def __repr__(self) -> str: return self.__str__() @property def f(self) -> u.Quantity: """Spectral flux (W m^-2 nm^-1). Returns: u.Quantity: Spectral flux density converted to W/m^2/nm when set. """ return (self._f * u.W / u.m**2 / u.nm).to(self._f_unit) @f.setter def f(self, f: u.Quantity): """Set spectral flux. Args: f (u.Quantity): Flux in a convertible spectral density unit. Raises: TypeError: If not an ``astropy.units.Quantity``. ValueError: If not convertible to W/m^2/nm. """ if not isinstance(f, u.Quantity): raise TypeError('f must be an astropy Quantity') try: new_f = f.to(u.W / u.m **2 / u.nm).value except u.UnitConversionError: raise ValueError('f must be in spectral flux units (equivalent to W/m^2/nm)') self._f_unit = f.unit self._f = new_f if self.parent_ctx is not None: self.parent_ctx._update_pf() @property def δ(self) -> u.Quantity: """Declination (degrees). Returns: u.Quantity: Declination in degrees. """ return (self. * u.deg).to(self._δ_unit) .setter def δ(self, δ: u.Quantity): """Set declination. Args: δ (u.Quantity): Declination in a convertible angular unit. Raises: TypeError: If not an ``astropy.units.Quantity``. ValueError: If not convertible to degrees. """ if not isinstance(δ, u.Quantity): raise TypeError('δ must be an astropy Quantity') try: new_δ = δ.to(u.deg).value except u.UnitConversionError: raise ValueError('δ must be in degrees') self._δ_unit = δ.unit self. = new_δ if self.parent_ctx is not None: self.parent_ctx._update_p() @property def companions(self) -> list[Companion]: """List of companions. Returns: list[Companion]: Managed list of companion objects. """ return self._companions @companions.setter def companions(self, companions: list[Companion]): """Set companions. Args: companions (list[Companion]): List of ``Companion`` objects. Raises: TypeError: If the list contains non-``Companion`` items or is not iterable. """ if not all((isinstance(companion, Companion) for companion in companions)): raise TypeError('`companions` must be a list of Companion objects.') try: companions = CompanionList(companions) except TypeError: raise TypeError('companions must be a list of Companion or a CompanionList objects') self._companions = copy(companions) for companion in self._companions: companion._parent_target = self @property def name(self) -> str: """Target name. Returns: str: Readable target name. """ return self._name @name.setter def name(self, name: str): """Set target name. Args: name (str): Readable name. Raises: TypeError: If not a string. """ if not isinstance(name, str): raise TypeError('name must be a string') self._name = name @property def parent_ctx(self) -> list: """Parent observing context (read-only). Returns: Any: Parent context reference or ``None``. """ return self._parent_ctx @parent_ctx.setter def parent_ctx(self, parent_ctx): """Setter is disabled; ``parent_ctx`` is read-only. Raises: AttributeError: Always raised. """ raise AttributeError('parent_ctx is read-only')