Question: return world[0] if self.world_n_dim == 1 else tuple(world)      def world_to_pixel_values(self, *world_arrays):        pixel = self.all_world2pix(*world_arrays, 0)        # avoid circular import        from astropy.wcs.wcs import NoConvergence        try:            pixel = self.all_world2pix(*world_arrays, 0)        except NoConvergence as e:            warnings.warn(str(e))            # use best_solution contained in the exception and format the same            # way as all_world2pix does (using _array_converter)            pixel = self._array_converter(lambda *args: e.best_solution,                                         'input', *world_arrays, 0)         return pixel[0] if self.pixel_n_dim == 1 else tuple(pixel)      @property

'WCS.allworld2pix' failed to converge when plotting WCS with non linear distortions <!-- This comments are hidden when you submit the issue, so you do not need to remove them! --<!-- Please be sure to check out our contributing guidelines, . Please be sure to check out our code of conduct, . --<!-- Please have a search on our GitHub repository to see if a similar issue has already been posted. If a similar issue is closed, have a quick look to see if you are satisfied by the resolution. If not please go ahead and open an issue! --<!-- Please check that the development version still produces the same bug. You can install development version with pip install command. --When trying to plot an image with a WCS as projection that contains non linear Distortions it fails with a error. When I add as parameter to the call at line 326 of I get the good enough looking plot below: ! It would be nice if there was a way of getting that plot without having to hack the library code like that. <!-- What actually happened. --<!-- Was the output confusing or poorly described? --The call to plotting the grid fails with the following error (last few lines, can provide more if necessary): <!-- Ideally a code example could be provided so we can run it ourselves. --<!-- If you are pasting code, use triple backticks ( from import WCS, Sip import numpy as np import as plt wcs = WCS(naxis=2) a = [[ 0.+00, 0.+00, 6.-07, -1.-10], [ 0.+00, 9.-06, -1.-07, 0.+00], [ 7.-06, 2.-09, 0.+00, 0.+00], [-1.-07, 0.+00, 0.+00, 0.+00]] b = [[ 0.+00, 0.+00, 1.-05, -1.-07], [ 0.+00, 5.-06, -1.-09, 0.+00], [ 1.-05, -1.-07, 0.+00, 0.+00], [ 3.-09, 0.+00, 0.+00, 0.+00]] crpix = [1221., 994.]


Question: return world[0] if self.world_n_dim == 1 else tuple(world)      def world_to_pixel_values(self, *world_arrays):        pixel = self.all_world2pix(*world_arrays, 0)        # avoid circular import        from astropy.wcs.wcs import NoConvergence        try:            pixel = self.all_world2pix(*world_arrays, 0)        except NoConvergence as e:            warnings.warn(str(e))            # use best_solution contained in the exception and format the same            # way as all_world2pix does (using _array_converter)            pixel = self._array_converter(lambda *args: e.best_solution,                                         'input', *world_arrays, 0)         return pixel[0] if self.pixel_n_dim == 1 else tuple(pixel)      @property

ap = bp = ((4, 4)) = Sip(a, b, ap, bp, crpix) plt.subplot(projection=wcs) (((1944, 2592))) (color='white', ls='solid') import platform; print(platform.platform()) Linux-5.11.10-arch1-1-x8664-with-glibc2.33 import sys; print("Python", sys.version) Python 3.9.2 (default, Feb 20 2021, 18:40:11) [GCC 10.2.0] import numpy; print("Numpy", numpy.version) Numpy 1.20.2 import astropy; print("astropy", astropy.version) astropy 4.3.dev690+g7811614f8 import scipy; print("Scipy", scipy.version) Scipy 1.6.1 import matplotlib; print("Matplotlib", matplotlib.version) Matplotlib 3.3.4 pixel = self.allworld2pix(worldarrays, 0) ~/work/develop/env/lib/python3.9/site- in worldtopixelvalues(self, worldarrays) 324 325 def worldtopixelvalues(self, worldarrays): --326 pixel = self.allworld2pix(worldarrays, 0) 327 return pixel[0] if self.pixelndim == 1 else tuple(pixel) 328 ~/work/develop/env/lib/python3.9/site- in wrapper(args, kwargs) 534 (message, warningtype, stacklevel=2) 535 --536 return function(args, kwargs) 537 538 return wrapper ~/work/develop/env/lib/python3.9/site- in allworld2pix(self, tolerance, maxiter, adaptive, detectdivergence, quiet, args, kwargs) 1886 raise ValueError("No basic WCS settings were created.") 1887 -1888 return self.arrayconverter( 1889 lambda args, kwargs: 1890 self.allworld2pix( ~/work/develop/env/lib/python3.9/site- in arrayconverter(self, func, sky, radecorder, args) 1335 "a 1-D array for each axis, followed by an origin.")


Question: return world[0] if self.world_n_dim == 1 else tuple(world)      def world_to_pixel_values(self, *world_arrays):        pixel = self.all_world2pix(*world_arrays, 0)        # avoid circular import        from astropy.wcs.wcs import NoConvergence        try:            pixel = self.all_world2pix(*world_arrays, 0)        except NoConvergence as e:            warnings.warn(str(e))            # use best_solution contained in the exception and format the same            # way as all_world2pix does (using _array_converter)            pixel = self._array_converter(lambda *args: e.best_solution,                                         'input', *world_arrays, 0)         return pixel[0] if self.pixel_n_dim == 1 else tuple(pixel)      @property

1336 -1337 return returnlistofarrays(axes, origin) 1338 1339 raise TypeError( ~/work/develop/env/lib/python3.9/site- in returnlistofarrays(axes, origin) 1289 if radecorder and sky == 'input': 1290 xy = self.denormalizesky(xy) -1291 output = func(xy, origin) 1292 if radecorder and sky == 'output': 1293 output = self.normalizesky(output) ~/work/develop/env/lib/python3.9/site- in <lambda(args, kwargs) 1888 return self.arrayconverter( 1889 lambda args, kwargs: -1890 self.allworld2pix( 1891 args, tolerance=tolerance, maxiter=maxiter, 1892 adaptive=adaptive, detectdivergence=detectdivergence, ~/work/develop/env/lib/python3.9/site- in allworld2pix(self, world, origin, tolerance, maxiter, adaptive, detectdivergence, quiet) 1869 slowconv=ind, divergent=None) 1870 else: -1871 raise NoConvergence( 1872 "'WCS.allworld2pix' failed to " 1873 "converge to the requested accuracy.\n" NoConvergence: 'WCS.all_world2pix' failed to converge to the requested accuracy. After 20 iterations, the solution is diverging at least for one input point. ) around your code snippet. --<!-- If necessary, sanitize your screen output to be pasted so you do not reveal secrets like tokens and passwords. --Here is the code to reproduce the problem: <!-- Even if you do not think this is necessary, it is useful information for the maintainers. Please run the following snippet and paste the output below: import platform; print(platform.platform()) import sys; print("Python", sys.version) import numpy; print("Numpy", numpy.version) import astropy; print("astropy", astropy.version) import scipy; print("Scipy", scipy.version) import matplotlib; print("Matplotlib", matplotlib.version) --


Question: def _propagate_divide(self, other_uncert, result_data, correlation):         return None <ins>    def represent_as(self, other_uncert):        """Convert this uncertainty to a different uncertainty type.        Parameters        ----------        other_uncert : `NDUncertainty` subclass            The `NDUncertainty` subclass to convert to.        Returns        -------        resulting_uncertainty : `NDUncertainty` instance            An instance of ``other_uncert`` subclass containing the uncertainty            converted to the new uncertainty type.        Raises        ------        TypeError            If either the initial or final subclasses do not support            conversion, a `TypeError` is raised.        """        as_variance = getattr(self, "_convert_to_variance", None)        if as_variance is None:            raise TypeError(                f"{type(self)} does not support conversion to another "                "uncertainty type."            )        from_variance = getattr(other_uncert, "_convert_from_variance", None)        if from_variance is None:            raise TypeError(                f"{other_uncert.__name__} does not support conversion from "                "another uncertainty type."            )        return from_variance(as_variance())</ins>  class UnknownUncertainty(NDUncertainty):     """This class implements any unknown uncertainty type.

Add helpers to convert between different types of uncertainties Currently there no easy way to convert from an arbitrary uncertainty class to a different uncertainty class. This would be useful to be able to pass NDData objects to external libraries/tools which assume, for example, that uncertainties will always stored as variances. Here's some really scrappy code I bunged together quickly for my purposes (probably buggy, I need to properly test it), but what are peoples opinions on what's the best API/design/framework for such a system?


Question: def _data_unit_to_uncertainty_unit(self, value):         return value <ins>    def _convert_to_variance(self):        new_array = None if self.array is None else self.array ** 2        new_unit = None if self.unit is None else self.unit ** 2        return VarianceUncertainty(new_array, unit=new_unit)    @classmethod    def _convert_from_variance(cls, var_uncert):        new_array = None if var_uncert.array is None else var_uncert.array ** (1 / 2)        new_unit = None if var_uncert.unit is None else var_uncert.unit ** (1 / 2)        return cls(new_array, unit=new_unit)</ins>  class VarianceUncertainty(_VariancePropagationMixin, NDUncertainty):     """


Question: def _data_unit_to_uncertainty_unit(self, value):         return value ** 2 <ins>    def _convert_to_variance(self):        return self    @classmethod    def _convert_from_variance(cls, var_uncert):        return var_uncert</ins>  def _inverse(x):     """Just a simple inverse for use in the InverseVariance"""


Question: def _data_unit_to_uncertainty_unit(self, value):         return 1 / value ** 2<ins>    def _convert_to_variance(self):        new_array = None if self.array is None else 1 / self.array        new_unit = None if self.unit is None else 1 / self.unit        return VarianceUncertainty(new_array, unit=new_unit)    @classmethod    def _convert_from_variance(cls, var_uncert):        new_array = None if var_uncert.array is None else 1 / var_uncert.array        new_unit = None if var_uncert.unit is None else 1 / var_uncert.unit        return cls(new_array, unit=new_unit)</ins>


Question: Blackbody temperature.      scale : float or `~astropy.units.Quantity` ['dimensionless']        Scale factor        Scale factor.  If dimensionless, input units will assumed        to be in Hz and output units in (erg / (cm ** 2 * s * Hz * sr).        If not dimensionless, must be equivalent to either        (erg / (cm ** 2 * s * Hz * sr) or erg / (cm ** 2 * s * AA * sr),        in which case the result will be returned in the requested units and        the scale will be stripped of units (with the float value applied).      Notes     -----

BlackBody bolometric flux is wrong if scale has units of dimensionlessunscaled The class has the wrong bolometric flux if argument is passed as a Quantity with units, but the correct bolometric flux if is simply a float. <!-- Provide a general description of the bug. --Expected output from sample code: Actual output from sample code: Sample code:


Question: scale = Parameter(default=1.0, min=0, description="Scale factor")      # We allow values without units to be passed when evaluating the model, and    # in this case the input x values are assumed to be frequencies in Hz.    # in this case the input x values are assumed to be frequencies in Hz or wavelengths    # in AA (depending on the choice of output units controlled by units on scale    # and stored in self._output_units during init).     _input_units_allow_dimensionless = True      # We enable the spectral equivalency by default for the spectral axis     input_units_equivalencies = {'x': u.spectral()}     # Store the native units returned by B_nu equation    _native_units = u.erg / (u.cm ** 2 * u.s * u.Hz * u.sr)    # Store the base native output units.  If scale is not dimensionless, it    # must be equivalent to one of these.  If equivalent to SLAM, then    # input_units will expect AA for 'x', otherwise Hz.    _native_output_units = {'SNU': u.erg / (u.cm ** 2 * u.s * u.Hz * u.sr),                            'SLAM': u.erg / (u.cm ** 2 * u.s * u.AA * u.sr)}    def __init__(self, *args, **kwargs):        scale = kwargs.get('scale', None)        # Support scale with non-dimensionless unit by stripping the unit and        # storing as self._output_units.        if hasattr(scale, 'unit') and not scale.unit.is_equivalent(u.dimensionless_unscaled):            output_units = scale.unit            if not output_units.is_equivalent(self._native_units, u.spectral_density(1*u.AA)):                raise ValueError(f"scale units not dimensionless or in surface brightness: {output_units}")            kwargs['scale'] = scale.value            self._output_units = output_units        else:            self._output_units = self._native_units        return super().__init__(*args, **kwargs)     def evaluate(self, x, temperature, scale):         """Evaluate the model.


Question: ----------         x : float, `~numpy.ndarray`, or `~astropy.units.Quantity` ['frequency']             Frequency at which to compute the blackbody. If no units are given,            this defaults to Hz.            this defaults to Hz (or AA if `scale` was initialized with units            equivalent to erg / (cm ** 2 * s * AA * sr)).          temperature : float, `~numpy.ndarray`, or `~astropy.units.Quantity`             Temperature of the blackbody. If no units are given, this defaults


Question: else:             in_temp = temperature         if not isinstance(x, u.Quantity):            # then we assume it has input_units which depends on the            # requested output units (either Hz or AA)            in_x = u.Quantity(x, self.input_units['x'])        else:            in_x = x         # Convert to units for calculations, also force double precision         with u.add_enabled_equivalencies(u.spectral() + u.temperature()):            freq = u.Quantity(x, u.Hz, dtype=np.float64)            freq = u.Quantity(in_x, u.Hz, dtype=np.float64)             temp = u.Quantity(in_temp, u.K)         # check the units of scale and setup the output units        bb_unit = u.erg / (u.cm ** 2 * u.s * u.Hz * u.sr)  # default unit        # use the scale that was used at initialization for determining the units to return        # to support returning the right units when fitting where units are stripped        if hasattr(self.scale, "unit") and self.scale.unit is not None:            # check that the units on scale are covertable to surface brightness units            if not self.scale.unit.is_equivalent(bb_unit, u.spectral_density(x)):                raise ValueError(                    f"scale units not surface brightness: {self.scale.unit}"                )            # use the scale passed to get the value for scaling            if hasattr(scale, "unit"):                mult_scale = scale.value            else:                mult_scale = scale            bb_unit = self.scale.unit        else:            mult_scale = scale         # Check if input values are physically possible         if np.any(temp < 0):             raise ValueError(f"Temperature should be positive: {temp}")


Question: # Calculate blackbody flux         bb_nu = 2.0 * const.h * freq ** 3 / (const.c ** 2 * boltzm1) / u.sr         y = mult_scale * bb_nu.to(bb_unit, u.spectral_density(freq))        if self.scale.unit is not None:            # Will be dimensionless at this point, but may not be dimensionless_unscaled            if not hasattr(scale, 'unit'):                # during fitting, scale will be passed without units                # but we still need to convert from the input dimensionless                # to dimensionless unscaled                scale = scale * self.scale.unit            scale = scale.to(u.dimensionless_unscaled).value        # NOTE: scale is already stripped of any input units        y = scale * bb_nu.to(self._output_units, u.spectral_density(freq))          # If the temperature parameter has no unit, we should return a unitless         # value. This occurs for instance during fitting, since we drop the


Question: @property     def input_units(self):        # The input units are those of the 'x' value, which should always be        # Hz. Because we do this, and because input_units_allow_dimensionless        # is set to True, dimensionless values are assumed to be in Hz.        return {self.inputs[0]: u.Hz}        # The input units are those of the 'x' value, which will depend on the        # units compatible with the expected output units.        if self._output_units.is_equivalent(self._native_output_units['SNU']):            return {self.inputs[0]: u.Hz}        else:            # only other option is equivalent with SLAM            return {self.inputs[0]: u.AA}      def _parameter_units_for_data_units(self, inputs_unit, outputs_unit):         return {"temperature": u.K}


Question: @property     def bolometric_flux(self):         """Bolometric flux."""        if self.scale.unit is not None:            # Will be dimensionless at this point, but may not be dimensionless_unscaled            scale = self.scale.quantity.to(u.dimensionless_unscaled)        else:            scale = self.scale.value         # bolometric flux in the native units of the planck function         native_bolflux = (            self.scale.value * const.sigma_sb * self.temperature ** 4 / np.pi            scale * const.sigma_sb * self.temperature ** 4 / np.pi         )         # return in more "astro" units         return native_bolflux.to(u.erg / (u.cm ** 2 * u.s))


Question: def read_table_fits(input, hdu=None, astropy_native=False, memmap=False,                    character_as_bytes=True, unit_parse_strict='warn'):                    character_as_bytes=True, unit_parse_strict='warn',                    mask_invalid=True):     """     Read a Table object from an FITS file

Can Table masking be turned off? <!-- This comments are hidden when you submit the issue, so you do not need to remove them! --<!-- Please be sure to check out our contributing guidelines, . Please be sure to check out our code of conduct, . --<!-- Please have a search on our GitHub repository to see if a similar issue has already been posted. If a similar issue is closed, have a quick look to see if you are satisfied by the resolution. If not please go ahead and open an issue! --<!-- Provide a general description of the feature you would like. --<!-- If you want to, you can suggest a draft design or API. --<!-- This way we have a deeper discussion on the feature. --As of Astropy 5, when encounters values such as , it automatically creates a and the whole table becomes a . While this might be useful for individual end-users, it is very inconvenient for intermediate data in pipelines. Here's the scenario: data are being passed via files and . A downstream function needs to replace with valid values. Previously those values could be easily identified (e.g. and replaced. However, now additional work is need to look "underneath" the mask, extracting the actual values, replacing them, and then possibly creating a new, unmasked column, or even an entirely new table. Ideally, a keyword like would disable this behavior, for people who don't need this masking.


Question: fit the table in memory, you may be better off leaving memory mapping         off. However, if your table would not fit in memory, you should set this         to `True`.<ins>        When set to `True` then ``mask_invalid`` is set to `False` since the        masking would cause loading the full data array.</ins>     character_as_bytes : bool, optional         If `True`, string columns are stored as Numpy byte arrays (dtype ``S``)         and are converted on-the-fly to unicode strings when accessing


Question: :class:`~astropy.units.core.UnrecognizedUnit`.         Values are the ones allowed by the ``parse_strict`` argument of         :class:`~astropy.units.core.Unit`: ``raise``, ``warn`` and ``silent``.<ins>    mask_invalid : bool, optional        By default the code masks NaNs in float columns and empty strings in        string columns. Set this parameter to `False` to avoid the performance        penalty of doing this masking step. The masking is always deactivated        when using ``memmap=True`` (see above).</ins>      """


Question: else: <ins>        if memmap:            # using memmap is not compatible with masking invalid value by            # default so we deactivate the masking            mask_invalid = False</ins>         hdulist = fits_open(input, character_as_bytes=character_as_bytes,                             memmap=memmap)


Question: hdulist, hdu=hdu,                 astropy_native=astropy_native,                 unit_parse_strict=unit_parse_strict,<ins>                mask_invalid=mask_invalid,</ins>             )         finally:             hdulist.close()


Question: # Return a MaskedColumn even if no elements are masked so             # we roundtrip better.             masked = True        elif issubclass(coltype, np.inexact):        elif mask_invalid and issubclass(coltype, np.inexact):             mask = np.isnan(data[col.name])        elif issubclass(coltype, np.character):        elif mask_invalid and issubclass(coltype, np.character):             mask = col.array == b''          if masked or np.any(mask):


Question: This is required when the object is used as a mixin column within a table,     but can be used as a general way to store meta information.     """    attrs_from_parent = BaseColumnInfo.attr_names    attr_names = BaseColumnInfo.attr_names | {'groups'}    _attrs_no_copy = BaseColumnInfo._attrs_no_copy | {'groups'}    attrs_from_parent = attr_names     _supports_indexing = True      def new_like(self, cols, length, metadata_conflicts='warn', name=None):diff --git a/astropy/table/groups.py b/astropy/table/groups.py-- a/astropy/table/groups.py++ b/astropy/table/groups.py

SkyCoord in Table breaks aggregate on groupby When putting a column of s in a , does not work on : fails with This happens irregardless of the aggregation function. Aggregation works, only fails to aggregate columns where operation does not make sense. and


Question: class ColumnGroups(BaseGroups):     def __init__(self, parent_column, indices=None, keys=None):         self.parent_column = parent_column  # parent Column        self.parent_table = parent_column.parent_table        self.parent_table = parent_column.info.parent_table         self._indices = indices         self._keys = keys


Question: return self._keys      def aggregate(self, func):        from .column import MaskedColumn        from .column import MaskedColumn, Column        from astropy.utils.compat import NUMPY_LT_1_20          i0s, i1s = self.indices[:-1], self.indices[1:]         par_col = self.parent_column


Question: mean_case = func is np.mean         try:             if not masked and (reduceat or sum_case or mean_case):<ins>                # For numpy < 1.20 there is a bug where reduceat will fail to                # raise an exception for mixin columns that do not support the                # operation. For details see:                # https://github.com/astropy/astropy/pull/12825#issuecomment-1082412447                # Instead we try the function directly with a 2-element version                # of the column                if NUMPY_LT_1_20 and not isinstance(par_col, Column) and len(par_col) > 0:                    func(par_col[[0, 0]])</ins>                 if mean_case:                     vals = np.add.reduceat(par_col, i0s) / np.diff(self.indices)                 else:


Question: vals = func.reduceat(par_col, i0s)             else:                 vals = np.array([func(par_col[i0: i1]) for i0, i1 in zip(i0s, i1s)])            out = par_col.__class__(vals)         except Exception as err:            raise TypeError("Cannot aggregate column '{}' with type '{}'"                            .format(par_col.info.name,                                    par_col.info.dtype)) from err        out = par_col.__class__(data=vals,                                name=par_col.info.name,                                description=par_col.info.description,                                unit=par_col.info.unit,                                format=par_col.info.format,                                meta=par_col.info.meta)            raise TypeError("Cannot aggregate column '{}' with type '{}': {}"                            .format(par_col.info.name, par_col.info.dtype, err)) from err        out_info = out.info        for attr in ('name', 'unit', 'format', 'description', 'meta'):            try:                setattr(out_info, attr, getattr(par_col.info, attr))            except AttributeError:                pass         return out      def filter(self, func):


Question: new_col = col.take(i0s)             else:                 try:                    new_col = col.groups.aggregate(func)                    new_col = col.info.groups.aggregate(func)                 except TypeError as err:                     warnings.warn(str(err), AstropyUserWarning)                     continuediff --git a/astropy/utils/data_info.py b/astropy/utils/data_info.py-- a/astropy/utils/data_info.py++ b/astropy/utils/data_info.py


Question: Note that this class is defined here so that mixins can use it     without importing the table package.     """    attr_names = DataInfo.attr_names.union(['parent_table', 'indices'])    attr_names = DataInfo.attr_names | {'parent_table', 'indices'}     _attrs_no_copy = set(['parent_table', 'indices'])      # Context for serialization.  This can be set temporarily via


Question: self._attrs['name'] = name <ins>    @property    def groups(self):        # This implementation for mixin columns essentially matches the Column        # property definition.  `groups` is a read-only property here and        # depends on the parent table of the column having `groups`. This will        # allow aggregating mixins as long as they support those operations.        from astropy.table import groups        return self._attrs.setdefault('groups', groups.ColumnGroups(self._parent))</ins>  class ParentDtypeInfo(MixinInfo):     """Mixin that gets info.dtype from parent"""


Question: match = re.match(ecsv_header_re, lines[0].strip(), re.VERBOSE)         if not match:             raise core.InconsistentTableError(no_header_msg)        # ecsv_version could be constructed here, but it is not currently used.        # Construct ecsv_version for backwards compatibility workarounds.        self.ecsv_version = tuple(int(v or 0) for v in match.groups())          try:             header = meta.get_header_from_yaml(lines)

No longer able to read BinnedTimeSeries with datetime column saved as ECSV after upgrading from 4.2.1 -5.0+ <!-- This comments are hidden when you submit the issue, so you do not need to remove them! --<!-- Please be sure to check out our contributing guidelines, . Please be sure to check out our code of conduct, . --<!-- Please have a search on our GitHub repository to see if a similar issue has already been posted. If a similar issue is closed, have a quick look to see if you are satisfied by the resolution. If not please go ahead and open an issue! --<!-- Please check that the development version still produces the same bug. You can install development version with pip install command. --<!-- Provide a general description of the bug. --Hi, merged in PR breaks my ability to read an ECSV file created using Astropy v 4.2.1, BinnedTimeSeries class's write method, which has a datetime64 column. Downgrading astropy back to 4.2.1 fixes the issue because the strict type checking in line 177 of is not there. Is there a reason why this strict type checking was to ECSV? Is there a way to preserve reading and writing of ECSV files created with BinnedTimeSeries across versions? I am happy to make a PR on this if the strict type checking is allowed to be scaled back or we can add datetime64 as an allowed type. <!-- What did you expect to happen. --The file is read into a object from ecsv file without error. <!-- What actually happened. --<!-- Was the output confusing or poorly described? --ValueError is produced and the file is not read because does not accept the datetime64 column. <!-- Ideally a code example could be provided so we can run it ourselves.


Question: match = re.match(ecsv_header_re, lines[0].strip(), re.VERBOSE)         if not match:             raise core.InconsistentTableError(no_header_msg)        # ecsv_version could be constructed here, but it is not currently used.        # Construct ecsv_version for backwards compatibility workarounds.        self.ecsv_version = tuple(int(v or 0) for v in match.groups())          try:             header = meta.get_header_from_yaml(lines)

--<!-- If you are pasting code, use triple backticks ( ValueError Traceback (most recent call last) Input In [3], in <module---49 tsrbin = ('', format='') File ~/Apps/miniconda3/envs/py310latest/lib/python3.10/site-, in (self, filename, timebinstartcolumn, timebinendcolumn, timebinsizecolumn, timebinsizeunit, timeformat, timescale, format, args, kwargs) 230 """ 231 Read and parse a file and returns a . 232 (...) 279 280 """ 282 try: 283 284 # First we try the readers defined for the BinnedTimeSeries class --285 return super().read(filename, format=format, args, kwargs) 287 except TypeError: 288 289 # Otherwise we fall back to the default Table readers 291 if timebinstartcolumn is None: File ~/Apps/miniconda3/envs/py310latest/lib/python3.10/site-, in (self, args, kwargs) 59 units = ('units', None) 60 descriptions = ('descriptions', None) ---62 out = (cls, args, kwargs) 64 # For some readers (e.g., ), the returned class is not 65 # guaranteed to be the same as the desired output . If so, 66 # try coercing to desired class without copying ( 67 # would normally do a copy). The normal case here is swapping 68 # Table <=QTable. 69 if cls is not File ~/Apps/miniconda3/envs/py310latest/lib/python3.10/site-, in (self, cls, format, cache, args, kwargs) 195 format = self.getvalidformat( 196 'read', cls, path, fileobj, args, kwargs) 198 reader = self.getreader(format, cls) --199 data = reader(args, kwargs) 201 if not isinstance(data, cls): 202 # User has read with a subclass where only the parent class is 203 # registered. This returns the parent class, so try coercing 204 # to desired subclass. 205 try: File ~/Apps/miniconda3/envs/py310latest/lib/python3.10/site-, in ioread(format, filename, kwargs) 16 format = (r'^ascii.


Question: match = re.match(ecsv_header_re, lines[0].strip(), re.VERBOSE)         if not match:             raise core.InconsistentTableError(no_header_msg)        # ecsv_version could be constructed here, but it is not currently used.        # Construct ecsv_version for backwards compatibility workarounds.        self.ecsv_version = tuple(int(v or 0) for v in match.groups())          try:             header = meta.get_header_from_yaml(lines)

', '', format) 17 kwargs['format'] = format ---18 return read(filename, kwargs) File ~/Apps/miniconda3/envs/py310latest/lib/python3.10/site-, in read(table, guess, kwargs) 374 else: 375 reader = getreader(newkwargs) --376 dat = (table) 377 ({'kwargs': copy.deepcopy(newkwargs), 378 'Reader': , 379 'status': 'Success with specified Reader class ' 380 '(no guessing)'}) 382 # Static analysis (pyright) indicates might be left undefined, so just 383 # to be sure define it at the beginning and check here. File ~/Apps/miniconda3/envs/py310latest/lib/python3.10/site-, in (self, table) 1340 (, ) 1342 # Get the table column definitions -1343 () 1345 # Make sure columns are valid 1346 (, self.strictnames, self.guessing) File ~/Apps/miniconda3/envs/py310latest/lib/python3.10/site-, in EcsvHeader.getcols(self, lines) 175 = headercols[]['datatype'] 176 if not in ECSVDATATYPES: --177 raise ValueError(f'datatype {!r} of column {!r} ' 178 f'is not in allowed values {ECSVDATATYPES}') 180 # Subtype is written like "int64[2,null]" and we want to split this 181 # out to "int64" and [2, None]. 182 subtype = col.subtype ValueError: datatype 'datetime64' of column 'timebinstart' is not in allowed values ('bool', 'int8', 'int16', 'int32', 'int64', 'uint8', 'uint16', 'uint32', 'uint64', 'float16', 'float32', 'float64', 'float128', 'string') <!-- Even if you do not think this is necessary, it is useful information for the maintainers.


Question: match = re.match(ecsv_header_re, lines[0].strip(), re.VERBOSE)         if not match:             raise core.InconsistentTableError(no_header_msg)        # ecsv_version could be constructed here, but it is not currently used.        # Construct ecsv_version for backwards compatibility workarounds.        self.ecsv_version = tuple(int(v or 0) for v in match.groups())          try:             header = meta.get_header_from_yaml(lines)

Please run the following snippet and paste the output below: import platform; print(platform.platform()) import sys; print("Python", sys.version) import numpy; print("Numpy", numpy.version) import erfa; print("pyerfa", erfa.version) import astropy; print("astropy", astropy.version) import scipy; print("Scipy", scipy.version) import matplotlib; print("Matplotlib", matplotlib.version) --(For the version that does not work) Python 3.10.2 (main, Feb 1 2022, 19:28:35) [GCC 9.4.0] Numpy 1.22.2 pyerfa 2.0.0.1 astropy 5.0.1 Scipy 1.8.0 Matplotlib 3.5.1 (For the version that does work) Python 3.7.11 (default, Jul 27 2021, 14:32:16) [GCC 7.5.0] Numpy 1.20.3 pyerfa 2.0.0.1 astropy 4.2.1 Scipy 1.7.0 Matplotlib 3.4.2


Question: setattr(col, attr, header_cols[col.name][attr])              col.dtype = header_cols[col.name]['datatype']            if col.dtype not in ECSV_DATATYPES:            # Require col dtype to be a valid ECSV datatype. However, older versions            # of astropy writing ECSV version 0.9 and earlier had inadvertently allowed            # numpy datatypes like datetime64 or object or python str, which are not in the ECSV standard.            # For back-compatibility with those existing older files, allow reading with no error.            if col.dtype not in ECSV_DATATYPES and self.ecsv_version > (0, 9, 0):                 raise ValueError(f'datatype {col.dtype!r} of column {col.name!r} '                                  f'is not in allowed values {ECSV_DATATYPES}')


Question: setattr(col, attr, header_cols[col.name][attr])              col.dtype = header_cols[col.name]['datatype']            if col.dtype not in ECSV_DATATYPES:            # Require col dtype to be a valid ECSV datatype. However, older versions            # of astropy writing ECSV version 0.9 and earlier had inadvertently allowed            # numpy datatypes like datetime64 or object or python str, which are not in the ECSV standard.            # For back-compatibility with those existing older files, allow reading with no error.            if col.dtype not in ECSV_DATATYPES and self.ecsv_version > (0, 9, 0):                 raise ValueError(f'datatype {col.dtype!r} of column {col.name!r} '                                  f'is not in allowed values {ECSV_DATATYPES}')


Question: setattr(col, attr, header_cols[col.name][attr])              col.dtype = header_cols[col.name]['datatype']            if col.dtype not in ECSV_DATATYPES:            # Require col dtype to be a valid ECSV datatype. However, older versions            # of astropy writing ECSV version 0.9 and earlier had inadvertently allowed            # numpy datatypes like datetime64 or object or python str, which are not in the ECSV standard.            # For back-compatibility with those existing older files, allow reading with no error.            if col.dtype not in ECSV_DATATYPES and self.ecsv_version > (0, 9, 0):                 raise ValueError(f'datatype {col.dtype!r} of column {col.name!r} '                                  f'is not in allowed values {ECSV_DATATYPES}')


Question: setattr(col, attr, header_cols[col.name][attr])              col.dtype = header_cols[col.name]['datatype']            if col.dtype not in ECSV_DATATYPES:            # Require col dtype to be a valid ECSV datatype. However, older versions            # of astropy writing ECSV version 0.9 and earlier had inadvertently allowed            # numpy datatypes like datetime64 or object or python str, which are not in the ECSV standard.            # For back-compatibility with those existing older files, allow reading with no error.            if col.dtype not in ECSV_DATATYPES and self.ecsv_version > (0, 9, 0):                 raise ValueError(f'datatype {col.dtype!r} of column {col.name!r} '                                  f'is not in allowed values {ECSV_DATATYPES}')


Question: # LOCAL from astropy import config as _config<ins>from astropy.utils.compat import NUMPY_LT_1_20, NUMPY_LT_1_22</ins> from astropy.utils.compat.misc import override__dir__ from astropy.utils.data_info import ParentDtypeInfo from astropy.utils.exceptions import AstropyDeprecationWarning, AstropyWarning

The keyword argument of is not supported for instances. <!-- This comments are hidden when you submit the issue, so you do not need to remove them! --<!-- Please be sure to check out our contributing guidelines, . Please be sure to check out our code of conduct, . --<!-- Please have a search on our GitHub repository to see if a similar issue has already been posted. If a similar issue is closed, have a quick look to see if you are satisfied by the resolution. If not please go ahead and open an issue! --<!-- Provide a general description of the feature you would like. --<!-- If you want to, you can suggest a draft design or API. --<!-- This way we have a deeper discussion on the feature. --Apologies if there is a duplicate somewhere, I scoured all the issues for this problem and I couldn't find it mentioned yet. The keyword argument was to and all the other -based functions in version 1.20.0 of numpy, but it doesn't seem to work yet with . Does anyone know if there is some limitation in that is preventing this feature from being implemented? If not, I could put some time towards updating to support this feature. <!-- Add any other context or screenshots about the feature request here. --<!-- This part is optional. --


Question: def trace(self, offset=0, axis1=0, axis2=1, dtype=None, out=None):         return self._wrap_function(np.trace, offset, axis1, axis2, dtype,                                    out=out)    def var(self, axis=None, dtype=None, out=None, ddof=0, keepdims=False):        return self._wrap_function(np.var, axis, dtype,                                   out=out, ddof=ddof, keepdims=keepdims,                                   unit=self.unit**2)    def std(self, axis=None, dtype=None, out=None, ddof=0, keepdims=False):        return self._wrap_function(np.std, axis, dtype, out=out, ddof=ddof,                                   keepdims=keepdims)    def mean(self, axis=None, dtype=None, out=None, keepdims=False):        return self._wrap_function(np.mean, axis, dtype, out=out,                                   keepdims=keepdims)    if NUMPY_LT_1_20:        def var(self, axis=None, dtype=None, out=None, ddof=0, keepdims=False):            return self._wrap_function(np.var, axis, dtype,                                       out=out, ddof=ddof, keepdims=keepdims,                                       unit=self.unit**2)    else:        def var(self, axis=None, dtype=None, out=None, ddof=0, keepdims=False, *, where=True):            return self._wrap_function(np.var, axis, dtype,                                       out=out, ddof=ddof, keepdims=keepdims, where=where,                                       unit=self.unit**2)    if NUMPY_LT_1_20:        def std(self, axis=None, dtype=None, out=None, ddof=0, keepdims=False):            return self._wrap_function(np.std, axis, dtype, out=out, ddof=ddof,                                       keepdims=keepdims)    else:        def std(self, axis=None, dtype=None, out=None, ddof=0, keepdims=False, *, where=True):            return self._wrap_function(np.std, axis, dtype, out=out, ddof=ddof,                                       keepdims=keepdims, where=where)    if NUMPY_LT_1_20:        def mean(self, axis=None, dtype=None, out=None, keepdims=False):            return self._wrap_function(np.mean, axis, dtype, out=out,                                       keepdims=keepdims)    else:        def mean(self, axis=None, dtype=None, out=None, keepdims=False, *, where=True):            return self._wrap_function(np.mean, axis, dtype, out=out,                                       keepdims=keepdims, where=where)      def round(self, decimals=0, out=None):         return self._wrap_function(np.round, decimals, out=out)


Question: def ediff1d(self, to_end=None, to_begin=None):         return self._wrap_function(np.ediff1d, to_end, to_begin)     def nansum(self, axis=None, out=None, keepdims=False):        return self._wrap_function(np.nansum, axis,                                   out=out, keepdims=keepdims)    if NUMPY_LT_1_22:        def nansum(self, axis=None, out=None, keepdims=False):            return self._wrap_function(np.nansum, axis,                                       out=out, keepdims=keepdims)    else:        def nansum(self, axis=None, out=None, keepdims=False, *, initial=None, where=True):            return self._wrap_function(np.nansum, axis,                                       out=out, keepdims=keepdims, initial=initial, where=where)      def insert(self, obj, values, axis=None):         """diff --git a/astropy/utils/masked/core.py b/astropy/utils/masked/core.py-- a/astropy/utils/masked/core.py++ b/astropy/utils/masked/core.py


Question: np.minimum(out, dmax, out=out, where=True if mmax is None else ~mmax)         return masked_out     def mean(self, axis=None, dtype=None, out=None, keepdims=False):    def mean(self, axis=None, dtype=None, out=None, keepdims=False, *, where=True):         # Implementation based on that in numpy/core/_methods.py         # Cast bool, unsigned int, and int to float64 by default,         # and do float16 at higher precision.


Question: dtype = np.dtype('f4')                 is_float16_result = out is None         where = ~self.mask & where         result = self.sum(axis=axis, dtype=dtype, out=out,                          keepdims=keepdims, where=~self.mask)        n = np.add.reduce(~self.mask, axis=axis, keepdims=keepdims)                          keepdims=keepdims, where=where)        n = np.add.reduce(where, axis=axis, keepdims=keepdims)         result /= n         if is_float16_result:             result = result.astype(self.dtype)         return result     def var(self, axis=None, dtype=None, out=None, ddof=0, keepdims=False):    def var(self, axis=None, dtype=None, out=None, ddof=0, keepdims=False, *, where=True):        where_final = ~self.mask & where         # Simplified implementation based on that in numpy/core/_methods.py        n = np.add.reduce(~self.mask, axis=axis, keepdims=keepdims)[...]        n = np.add.reduce(where_final, axis=axis, keepdims=keepdims)[...]          # Cast bool, unsigned int, and int to float64 by default.         if dtype is None and issubclass(self.dtype.type,                                         (np.integer, np.bool_)):             dtype = np.dtype('f8')        mean = self.mean(axis=axis, dtype=dtype, keepdims=True)        mean = self.mean(axis=axis, dtype=dtype, keepdims=True, where=where)          x = self - mean         x *= x.conjugate()  # Conjugate just returns x if not complex.          result = x.sum(axis=axis, dtype=dtype, out=out,                       keepdims=keepdims, where=~x.mask)                       keepdims=keepdims, where=where_final)         n -= ddof         n = np.maximum(n, 0, out=n)         result /= n         result._mask |= (n == 0)         return result     def std(self, axis=None, dtype=None, out=None, ddof=0, keepdims=False):    def std(self, axis=None, dtype=None, out=None, ddof=0, keepdims=False, *, where=True):         result = self.var(axis=axis, dtype=dtype, out=out, ddof=ddof,                          keepdims=keepdims)                          keepdims=keepdims, where=where)         return np.sqrt(result, out=result)      def __bool__(self):


Question: result = super().__bool__()         return result and not self.mask     def any(self, axis=None, out=None, keepdims=False):    def any(self, axis=None, out=None, keepdims=False, *, where=True):         return np.logical_or.reduce(self, axis=axis, out=out,                                    keepdims=keepdims, where=~self.mask)                                    keepdims=keepdims, where=~self.mask & where)     def all(self, axis=None, out=None, keepdims=False):    def all(self, axis=None, out=None, keepdims=False, *, where=True):         return np.logical_and.reduce(self, axis=axis, out=out,                                     keepdims=keepdims, where=~self.mask)                                     keepdims=keepdims, where=~self.mask & where)      # Following overrides needed since somehow the ndarray implementation     # does not actually call these.


Question: cright = _coord_matrix(right, 'right', noutp)     else:         cright = np.zeros((noutp, right.shape[1]))        cright[-right.shape[0]:, -right.shape[1]:] = 1        cright[-right.shape[0]:, -right.shape[1]:] = right      return np.hstack([cleft, cright])

Modeling's does not compute separability correctly for nested CompoundModels Consider the following model: It's separability matrix as you might expect is a diagonal: If I make the model more complex: The output matrix is again, as expected, the outputs and inputs to the linear models are separable and independent of each other. If however, I nest these compound models: Suddenly the inputs and outputs are no longer separable? This feels like a bug to me, but I might be missing something?


Question: self._uncertainty = value      def to_hdu(self, hdu_mask='MASK', hdu_uncertainty='UNCERT',               hdu_flags=None, wcs_relax=True, key_uncertainty_type='UTYPE'):               hdu_flags=None, wcs_relax=True,               key_uncertainty_type='UTYPE', as_image_hdu=False):         """Creates an HDUList object from a CCDData object.          Parameters

Convert CCDData to ImageHDU As far as I can tell, currently there's no way to directly convert a object to an object. If we write it to a file using it will always create a file where the first HDU is a that contains the , followed by optionally some s that contain mask or uncertainty. If we instead use , it will return an equivalent to the file it writes with , that is, the is stored in the first element of the , which is always a . This is somewhat unexpected given that you can already do it the other way around (that is, convert a object to a object): The problem is that if we then want to use this as an extension to another FITS file, there's no obvious way to get an which would allow us to do that. As far as I can tell, there's also no trivial way to convert a to a . We could manually create a new by copying the data from the , as well as its relevant cards and so on... but this seems unnecessarily complicated. I propose the following interfaces: This seems somewhat similar to the situation with and . In that case, we can also specify an parameter when reading: From here we can use:


Question: .. versionadded:: 3.1 <ins>        as_image_hdu : bool            If this option is `True`, the first item of the returned            `~astropy.io.fits.HDUList` is a `~astropy.io.fits.ImageHDU`, instead            of the default `~astropy.io.fits.PrimaryHDU`.</ins>         Raises         ------         ValueError


Question: # not header.             wcs_header = self.wcs.to_header(relax=wcs_relax)             header.extend(wcs_header, useblanks=False, update=True)        hdus = [fits.PrimaryHDU(self.data, header)]        if as_image_hdu:            hdus = [fits.ImageHDU(self.data, header)]        else:            hdus = [fits.PrimaryHDU(self.data, header)]          if hdu_mask and self.mask is not None:             # Always assuming that the mask is a np.ndarray (check that it has


Question: def fits_ccddata_writer(         ccd_data, filename, hdu_mask='MASK', hdu_uncertainty='UNCERT',        hdu_flags=None, key_uncertainty_type='UTYPE', **kwd):        hdu_flags=None, key_uncertainty_type='UTYPE', as_image_hdu=False,        **kwd):     """     Write CCDData object to FITS file.


Question: .. versionadded:: 3.1 <ins>    as_image_hdu : bool        If this option is `True`, the first item of the returned        `~astropy.io.fits.HDUList` is a `~astropy.io.fits.ImageHDU`, instead of        the default `~astropy.io.fits.PrimaryHDU`.</ins>     kwd :         All additional keywords are passed to :py:mod:`astropy.io.fits`


Question: """     hdu = ccd_data.to_hdu(         hdu_mask=hdu_mask, hdu_uncertainty=hdu_uncertainty,        key_uncertainty_type=key_uncertainty_type, hdu_flags=hdu_flags)        key_uncertainty_type=key_uncertainty_type, hdu_flags=hdu_flags,        as_image_hdu=as_image_hdu)    if as_image_hdu:        hdu.insert(0, fits.PrimaryHDU())     hdu.writeto(filename, **kwd)


Question: for key, value in bounding_box.items():             self[key] = value <ins>    @property    def _available_input_index(self):        model_input_index = [self._get_index(_input) for _input in self._model.inputs]        return [_input for _input in model_input_index if _input not in self._ignored]</ins>     def _validate_sequence(self, bounding_box, order: str = None):         """Validate passing tuple of tuples representation (or related) and setting them."""         order = self._get_order(order)

Incorrect ignored usage in <!-- This comments are hidden when you submit the issue, so you do not need to remove them! --<!-- Please be sure to check out our contributing guidelines, . Please be sure to check out our code of conduct, . --<!-- Please have a search on our GitHub repository to see if a similar issue has already been posted. If a similar issue is closed, have a quick look to see if you are satisfied by the resolution. If not please go ahead and open an issue! --<!-- Please check that the development version still produces the same bug. You can install development version with pip install command. --<!-- Provide a general description of the bug. --Providing inputs to does not always work as expected. Running the following code: Produces: This is incorrect. It instead should produce: Somehow the status of the input is being accounted for during the validation which occurs during the construction of the bounding box; however, it is getting "lost" somehow resulting in the weird behavior we see above. Oddly enough ignoring does not have an issue. E.G. this code: Produces: as expected. This is present in both astropy 5.03 and astropy develop


Question: bounding_box = bounding_box[::-1]          for index, value in enumerate(bounding_box):            self[index] = value            self[self._available_input_index[index]] = value      @property     def _n_inputs(self) -> int:


Question: def _validate(self, bounding_box, order: str = None):         """Validate and set any representation"""         if self._n_inputs == 1 and not isinstance(bounding_box, dict):            self[0] = bounding_box            self[self._available_input_index[0]] = bounding_box         else:             self._validate_iterable(bounding_box, order)


Question: order = bounding_box.order             if _preserve_ignore:                 ignored = bounding_box.ignored            bounding_box = bounding_box.intervals            bounding_box = bounding_box.named_intervals          new = cls({}, model, ignored=ignored, order=order)         new._validate(bounding_box)


Question: _required_columns_relax = False      def _check_required_columns(self):<ins>        def as_scalar_or_list_str(obj):            if not hasattr(obj, "__len__"):                return f"'{obj}'"            elif len(obj) == 1:                return f"'{obj[0]}'"            else:                return str(obj)</ins>          if not self._required_columns_enabled:             return

TimeSeries: misleading exception when required column check fails. <!-- This comments are hidden when you submit the issue, so you do not need to remove them! --<!-- Please be sure to check out our contributing guidelines, . Please be sure to check out our code of conduct, . --<!-- Please have a search on our GitHub repository to see if a similar issue has already been posted. If a similar issue is closed, have a quick look to see if you are satisfied by the resolution. If not please go ahead and open an issue! --<!-- Please check that the development version still produces the same bug. You can install development version with pip install command. --<!-- Provide a general description of the bug. --For a object that has additional required columns (in addition to ), when codes mistakenly try to remove a required column, the exception it produces is misleading. <!-- What did you expect to happen. --An exception that informs the users required columns are missing. The actual exception message is confusing: <!-- Ideally a code example could be provided so we can run it ourselves. --<!-- If you are pasting code, use triple backticks (python from import Time from astropy.timeseries import TimeSeries time=Time((, ), format='jd') ts = TimeSeries(time=time, data = {"flux": [99.9, 99.8, 99.7]}) ts.requiredcolumns = ["time", "flux"] ts.remove_column("flux") Windows-10-10.0.-SP0 Python 3.9.10 (main, Feb 1 2022, 21:21:54) [MSC v.1929 64 bit (AMD64)] Numpy 1.22.3 pyerfa 2.0.0.1 astropy 5.0.3 Scipy 1.8.0 Matplotlib 3.5.1


Question: elif self.colnames[:len(required_columns)] != required_columns:                 raise ValueError("{} object is invalid - expected '{}' "                                 "as the first column{} but found '{}'"                                 .format(self.__class__.__name__, required_columns[0], plural, self.colnames[0]))                raise ValueError("{} object is invalid - expected {} "                                 "as the first column{} but found {}"                                 .format(self.__class__.__name__, as_scalar_or_list_str(required_columns),                                            plural, as_scalar_or_list_str(self.colnames[:len(required_columns)])))              if (self._required_columns_relax                     and self._required_columns == self.colnames[:len(self._required_columns)]):


Question: @precision.setter     def precision(self, val):         del self.cache        if not isinstance(val, int) or val < 0 or val > 9:            raise ValueError('precision attribute must be an int between '                             '0 and 9')         self._time.precision = val      @propertydiff --git a/astropy/time/formats.py b/astropy/time/formats.py-- a/astropy/time/formats.py++ b/astropy/time/formats.py

Time from not precise Hello, I encounter difficulties with Time. I'm working on a package to perform photometry and occultation. For this last case, data need times values accurately estimated. Of course, data coming from different camera will will have different time format in the header. to manage this without passing long time to build a time parser, i decided to use Time object which do exactly what i need. The problem is, i dont arrive to make accurate conversion between different format using Time. let's do an exemple: now let's do reverse as you can see i don't fall back on the same value and the difference is quite high. I would like to fall back on the original one. thank you in advance


Question: def jd2_filled(self):         return np.nan_to_num(self.jd2) if self.masked else self.jd2 <ins>    @property    def precision(self):        return self._precision    @precision.setter    def precision(self, val):        #Verify precision is 0-9 (inclusive)        if not isinstance(val, int) or val < 0 or val > 9:            raise ValueError('precision attribute must be an int between '                             '0 and 9')        self._precision = val</ins>     @lazyproperty     def cache(self):         """


Question: """Output table as a dict of column objects keyed on column name.  The     table data are stored as plain python lists within the column objects.     """    # User-defined converters which gets set in ascii.ui if a `converter` kwarg    # is supplied.     converters = {}     # Derived classes must define default_converters and __call__      @staticmethod

Document reading True/False in ASCII table as bool not str <!-- This comments are hidden when you submit the issue, so you do not need to remove them! --<!-- Please be sure to check out our contributing guidelines, . Please be sure to check out our code of conduct, . --<!-- Please have a search on our GitHub repository to see if a similar issue has already been posted. If a similar issue is closed, have a quick look to see if you are satisfied by the resolution. If not please go ahead and open an issue! --<!-- Provide a general description of the feature you would like. --<!-- If you want to, you can suggest a draft design or API. --<!-- This way we have a deeper discussion on the feature. -- showed a use case for having an ASCII table column consisting of only "True" and "False" be read as instead of (current behavior). That issue discusses reasons to maintain the current behavior, but there are simple workarounds discussed there that should be brought out to the narrative docs as examples for users. I'd suggest the following as a recommendation for users: This new information could go in the existing section on in the read documentation. <!-- Add any other context or screenshots about the feature request here. --<!-- This part is optional. -- Control dtype with (converters API needs better doc or refactoring) I cannot find a way to control the dtype of the output table when reading a file into a . Consider the following MWE, with 3 numerical columns, while one of them would preferably be kept as a string: Reading in the same with and then converting to a Table works, but it should ideally be supported directly.


Question: """Validate the format for the type converters and then copy those         which are valid converters for this column (i.e. converter type is         a subclass of col.type)"""        # Allow specifying a single converter instead of a list of converters.        # The input `converters` must be a ``type`` value that can init np.dtype.        try:            # Don't allow list-like things that dtype accepts            assert type(converters) is type            converters = [numpy.dtype(converters)]        except (AssertionError, TypeError):            pass         converters_out = []         try:             for converter in converters:                converter_func, converter_type = converter                try:                    converter_func, converter_type = converter                except TypeError as err:                    if str(err).startswith('cannot unpack'):                        converter_func, converter_type = convert_numpy(converter)                    else:                        raise                 if not issubclass(converter_type, NoType):                    raise ValueError()                    raise ValueError('converter_type must be a subclass of NoType')                 if issubclass(converter_type, col.type):                     converters_out.append((converter_func, converter_type))         except (ValueError, TypeError):        except (ValueError, TypeError) as err:             raise ValueError('Error: invalid format for converters, see '                             'documentation\n{}'.format(converters))                             f'documentation\n{converters}: {err}')         return converters_out      def _convert_vals(self, cols):diff --git a/astropy/io/ascii/docs.py b/astropy/io/ascii/docs.py-- a/astropy/io/ascii/docs.py++ b/astropy/io/ascii/docs.py


Question: Line index for the end of data not counting comment or blank lines.         This value can be negative to count from the end.     converters : dict        Dictionary of converters. Keys in the dictionary are columns names,        values are converter functions. In addition to single column names        you can use wildcards via `fnmatch` to select multiple columns.        Dictionary of converters to specify output column dtypes. Each key in        the dictionary is a column name or else a name matching pattern        including wildcards. The value is either a data type such as ``int`` or        ``np.float32``; a list of such types which is tried in order until a        successful conversion is achieved; or a list of converter tuples (see        the `~astropy.io.ascii.convert_numpy` function for details).     data_Splitter : `~astropy.io.ascii.BaseSplitter`         Splitter class to split data columns     header_Splitter : `~astropy.io.ascii.BaseSplitter`


Question: """  # Import to register with the I/O machineryfrom . import cosmology, ecsv, mapping, model, row, table, yamlfrom . import cosmology, ecsv, html, mapping, model, row, table, yaml  # noqa: F401diff --git a/astropy/cosmology/io/html.py b/astropy/cosmology/io/html.pynew file mode 100644-- /dev/null++ b/astropy/cosmology/io/html.py

Register format with nice mathjax Cosmology can now read and write to files. It would be nice to register with a method for exporting a Cosmology to a HTML table. There are good examples of IO with Cosmology at and documentation at I'm thinking the (..., format='html'). Edit: also, the mathjax representation of each parameter can be stored on the corresponding Parameter object, like how units have the argument in .


Question:
<ins>import astropy.cosmology.units as cu
import astropy.units as u
from astropy.cosmology.connect import readwrite_registry
from astropy.cosmology.core import Cosmology
from astropy.cosmology.parameter import Parameter
from astropy.table import QTable

from .table import from_table, to_table

# Format look-up for conversion, {original_name: new_name}
# TODO! move this information into the Parameters themselves
_FORMAT_TABLE = {
    "H0": "$$H_{0}$$",
    "Om0": "$$\\Omega_{m,0}$$",
    "Ode0": "$$\\Omega_{\\Lambda,0}$$",
    "Tcmb0": "$$T_{0}$$",
    "Neff": "$$N_{eff}$$",
    "m_nu": "$$m_{nu}$$",
    "Ob0": "$$\\Omega_{b,0}$$",
    "w0": "$$w_{0}$$",
    "wa": "$$w_{a}$$",
    "wz": "$$w_{z}$$",
    "wp": "$$w_{p}$$",
    "zp": "$$z_{p}$$",
}

def read_html_table(filename, index=None, *, move_to_meta=False, cosmology=None, latex_names=True, **kwargs):
    """Read a |Cosmology| from an HTML file.

    Parameters
    ----------
    filename : path-like or file-like
        From where to read the Cosmology.
    index : int or str or None, optional
        Needed to select the row in tables with multiple rows. ``index`` can be
        an integer for the row number or, if the table is indexed by a column,
        the value of that column. If the table is not indexed and ``index`` is a
        string, the "name" column is used as the indexing column.

    move_to_meta : bool, optional keyword-only
        Whether to move keyword arguments that are not in the Cosmology class'
        signature to the Cosmology's metadata. This will only be applied if the
        Cosmology does NOT have a keyword-only argument (e.g. ``**kwargs``).
        Arguments moved to the metadata will be merged with existing metadata,
        preferring specified metadata in the case of a merge conflict (e.g. for
        ``Cosmology(meta={'key':10}, key=42)``, the ``Cosmology.meta`` will be
        ``{'key': 10}``).
    cosmology : str or |Cosmology| class or None, optional keyword-only
        The cosmology class (or string name thereof) to use when constructing
        the cosmology instance. The class also provides default parameter
        values, filling in any non-mandatory arguments missing in 'table'.
    latex_names : bool, optional keyword-only
        Whether the |Table| (might) have latex column names for the parameters
        that need to be mapped to the correct parameter name -- e.g. $$H_{0}$$
        to 'H0'. This is `True` by default, but can be turned off (set to
        `False`) if there is a known name conflict (e.g. both an 'H0' and
        '$$H_{0}$$' column) as this will raise an error. In this case, the
        correct name ('H0') is preferred.
    **kwargs : Any
        Passed to :attr:`astropy.table.QTable.read`. ``format`` is set to
        'ascii.html', regardless of input.

    Returns
    -------
    |Cosmology| subclass instance

    Raises
    ------
    ValueError
        If the keyword argument 'format' is given and is not "ascii.html".
    """
    # Check that the format is 'ascii.html' (or not specified)
    format = kwargs.pop("format", "ascii.html")
    if format != "ascii.html":
        raise ValueError(f"format must be 'ascii.html', not {format}")

    # Reading is handled by `QTable`.
    with u.add_enabled_units(cu):  # (cosmology units not turned on by default)
        table = QTable.read(filename, format="ascii.html", **kwargs)

    # Need to map the table's column names to Cosmology inputs (parameter
    # names).
    # TODO! move the `latex_names` into `from_table`
    if latex_names:
        table_columns = set(table.colnames)
        for name, latex in _FORMAT_TABLE.items():
            if latex in table_columns:
                table.rename_column(latex, name)

    # Build the cosmology from table, using the private backend.
    return from_table(table, index=index, move_to_meta=move_to_meta, cosmology=cosmology)

def write_html_table(cosmology, file, *, overwrite=False, cls=QTable, latex_names=False, **kwargs):
    r"""Serialize the |Cosmology| into a HTML table.

    Parameters
    ----------
    cosmology : |Cosmology| subclass instance file : path-like or file-like
        Location to save the serialized cosmology.
    file : path-like or file-like
        Where to write the html table.

    overwrite : bool, optional keyword-only
        Whether to overwrite the file, if it exists.
    cls : |Table| class, optional keyword-only
        Astropy |Table| (sub)class to use when writing. Default is |QTable|
        class.
    latex_names : bool, optional keyword-only
        Whether to format the parameters (column) names to latex -- e.g. 'H0' to
        $$H_{0}$$.
    **kwargs : Any
        Passed to ``cls.write``.

    Raises
    ------
    TypeError
        If the optional keyword-argument 'cls' is not a subclass of |Table|.
    ValueError
        If the keyword argument 'format' is given and is not "ascii.html".

    Notes
    -----
    A HTML file containing a Cosmology HTML table should have scripts enabling
    MathJax.

    ::
        <script
        src="https://polyfill.io/v3/polyfill.min.js?features=es6"></script>
        <script type="text/javascript" id="MathJax-script" async
            src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml.js">
        </script>
    """
    # Check that the format is 'ascii.html' (or not specified)
    format = kwargs.pop("format", "ascii.html")
    if format != "ascii.html":
        raise ValueError(f"format must be 'ascii.html', not {format}")

    # Set cosmology_in_meta as false for now since there is no metadata being kept
    table = to_table(cosmology, cls=cls, cosmology_in_meta=False)

    cosmo_cls = type(cosmology)
    for name, col in table.columns.items():
        param = getattr(cosmo_cls, name, None)
        if not isinstance(param, Parameter) or param.unit in (None, u.one):
            continue
        # Replace column with unitless version
        table.replace_column(name, (col << param.unit).value, copy=False)

    # TODO! move the `latex_names` into `to_table`
    if latex_names:
        new_names = [_FORMAT_TABLE.get(k, k) for k in cosmology.__parameters__]
        table.rename_columns(cosmology.__parameters__, new_names)

    # Write HTML, using table I/O
    table.write(file, overwrite=overwrite, format="ascii.html", **kwargs)

def html_identify(origin, filepath, fileobj, *args, **kwargs):
    """Identify if an object uses the HTML Table format.

    Parameters
    ----------
    origin : Any
        Not used.
    filepath : str or Any
        From where to read the Cosmology.
    fileobj : Any
        Not used.
    *args : Any
        Not used.
    **kwargs : Any
        Not used.

    Returns
    -------
    bool
        If the filepath is a string ending with '.html'.
    """
    return isinstance(filepath, str) and filepath.endswith(".html")

# ===================================================================
# Register

readwrite_registry.register_reader("ascii.html", Cosmology, read_html_table)
readwrite_registry.register_writer("ascii.html", Cosmology, write_html_table)
readwrite_registry.register_identifier("ascii.html", Cosmology, html_identify)</ins>


Question: # Import TimeFromEpoch to avoid breaking code that followed the old example of # making a custom timescale in the documentation. from .formats import TimeFromEpoch  # noqa<ins>from .time_helper.function_helpers import CUSTOM_FUNCTIONS, UNSUPPORTED_FUNCTIONS</ins>  from astropy.extern import _strptime

Add arrayfunc for <!-- This comments are hidden when you submit the pull request, so you do not need to remove them! --<!-- Please be sure to check out our contributing guidelines, . Please be sure to check out our code of conduct, . --<!-- If you are new or need to be re-acquainted with Astropy contributing workflow, please see . There is even a practical example at . --<!-- Astropy coding style guidelines can be found here: Our testing infrastructure enforces to follow a subset of the PEP8 to be followed. You can check locally whether your changes have followed these by running the following command: tox -e codestyle --<!-- Please just have a quick search on GitHub to see if a similar pull request has already been posted. We have old closed pull requests that might provide useful code or ideas that directly tie in with your pull request. --<!-- We have several automatic features that run when a pull request is open. They can appear daunting but do not worry because maintainers will help you navigate them, if necessary. --<!-- Provide a general description of what your pull request does. Complete the following sentence and add relevant details as you see fit. --<!-- In addition please ensure that the pull request title is descriptive and allows maintainers to infer the applicable subpackage(s). --<!-- READ THIS FOR MANUAL BACKPORT FROM A MAINTAINER: Apply "skip-basebranch-check" label before you open the PR! --xref This provides some numpy array functions for objects. Most notably, one can now do the following without an errror(!): This still needs: [ ] Tests [ ] What's new [ ] API docs??? but opening now for feedback and a full CI run. <!-- If the pull request closes any open issues you can add this. If you replace <Issue Numberwith a number, GitHub will automatically link it. If this pull request is unrelated to any issues, please remove the following line. --<!-- This section is to be filled by package maintainer(s) who will review this pull request. --This checklist is meant to remind the package maintainer(s) who will review this pull request of some common things to look for. This list is not exhaustive. [x] Do the proposed changes actually accomplish desired goals? ? ? ? . [ ] Did the CI pass?


Question: # Import TimeFromEpoch to avoid breaking code that followed the old example of # making a custom timescale in the documentation. from .formats import TimeFromEpoch  # noqa<ins>from .time_helper.function_helpers import CUSTOM_FUNCTIONS, UNSUPPORTED_FUNCTIONS</ins>  from astropy.extern import _strptime

If no, are the failures related? If you need to run daily and weekly cron jobs as part of the PR, please apply the label. [ ] Is a change log needed? If yes, did the change log check pass? If no, add the label. If this is a manual backport, use the label unless special changelog handling is necessary. [ ] Is a milestone set? Milestone must be set but check might be missing; do not let the green checkmark fool you. [ ] At the time of adding the milestone, if the milestone set requires a backport to release branch(es), apply the appropriate label(s) before merge.


Question: def __radd__(self, other):         return self.__add__(other)     def __array_function__(self, function, types, args, kwargs):        """        Wrap numpy functions.        Parameters        ----------        function : callable            Numpy function to wrap        types : iterable of classes            Classes that provide an ``__array_function__`` override. Can            in principle be used to interact with other classes. Below,            mostly passed on to `~numpy.ndarray`, which can only interact            with subclasses.        args : tuple            Positional arguments provided in the function call.        kwargs : dict            Keyword arguments provided in the function call.        """        if function in CUSTOM_FUNCTIONS:            f = CUSTOM_FUNCTIONS[function]            return f(*args, **kwargs)        elif function in UNSUPPORTED_FUNCTIONS:            return NotImplemented        else:            return super().__array_function__(function, types, args, kwargs)     def to_datetime(self, timezone=None):         # TODO: this could likely go through to_value, as long as that         # had an **kwargs part that was just passed on to _time.diff --git a/astropy/time/time_helper/__init__.py b/astropy/time/time_helper/__init__.pynew file mode 100644-- /dev/null++ b/astropy/time/time_helper/__init__.py


Question: def __radd__(self, other):         return self.__add__(other)     def __array_function__(self, function, types, args, kwargs):        """        Wrap numpy functions.        Parameters        ----------        function : callable            Numpy function to wrap        types : iterable of classes            Classes that provide an ``__array_function__`` override. Can            in principle be used to interact with other classes. Below,            mostly passed on to `~numpy.ndarray`, which can only interact            with subclasses.        args : tuple            Positional arguments provided in the function call.        kwargs : dict            Keyword arguments provided in the function call.        """        if function in CUSTOM_FUNCTIONS:            f = CUSTOM_FUNCTIONS[function]            return f(*args, **kwargs)        elif function in UNSUPPORTED_FUNCTIONS:            return NotImplemented        else:            return super().__array_function__(function, types, args, kwargs)     def to_datetime(self, timezone=None):         # TODO: this could likely go through to_value, as long as that         # had an **kwargs part that was just passed on to _time.diff --git a/astropy/time/time_helper/__init__.py b/astropy/time/time_helper/__init__.pynew file mode 100644-- /dev/null++ b/astropy/time/time_helper/__init__.py


Question: """Helper functions for Time."""from . import function_helpersdiff --git a/astropy/time/time_helper/function_helpers.py b/astropy/time/time_helper/function_helpers.pynew file mode 100644-- /dev/null++ b/astropy/time/time_helper/function_helpers.py


Question: """Helper functions for Time."""from . import function_helpersdiff --git a/astropy/time/time_helper/function_helpers.py b/astropy/time/time_helper/function_helpers.pynew file mode 100644-- /dev/null++ b/astropy/time/time_helper/function_helpers.py


Question: <ins>"""Helpers for overriding numpy functions in`~astropy.time.Time.__array_function__`."""import numpy as npfrom astropy.units.quantity_helper.function_helpers import FunctionAssigner# TODO: Fill this in with functions that don't make sense for timesUNSUPPORTED_FUNCTIONS = {}# Functions that return the final result of the numpy functionCUSTOM_FUNCTIONS = {}custom_functions = FunctionAssigner(CUSTOM_FUNCTIONS)@custom_functions(helps={np.linspace})def linspace(tstart, tstop, *args, **kwargs):    from astropy.time import Time    if isinstance(tstart, Time):        if not isinstance(tstop, Time):            return NotImplemented    if kwargs.get('retstep'):        offsets, step = np.linspace(np.zeros(tstart.shape), np.ones(tstop.shape), *args, **kwargs)        tdelta = tstop - tstart        return tstart + tdelta * offsets, tdelta * step    else:        offsets = np.linspace(np.zeros(tstart.shape), np.ones(tstop.shape), *args, **kwargs)        return tstart + (tstop - tstart) * offsets</ins>


Question: <ins>"""Helpers for overriding numpy functions in`~astropy.time.Time.__array_function__`."""import numpy as npfrom astropy.units.quantity_helper.function_helpers import FunctionAssigner# TODO: Fill this in with functions that don't make sense for timesUNSUPPORTED_FUNCTIONS = {}# Functions that return the final result of the numpy functionCUSTOM_FUNCTIONS = {}custom_functions = FunctionAssigner(CUSTOM_FUNCTIONS)@custom_functions(helps={np.linspace})def linspace(tstart, tstop, *args, **kwargs):    from astropy.time import Time    if isinstance(tstart, Time):        if not isinstance(tstop, Time):            return NotImplemented    if kwargs.get('retstep'):        offsets, step = np.linspace(np.zeros(tstart.shape), np.ones(tstop.shape), *args, **kwargs)        tdelta = tstop - tstart        return tstart + tdelta * offsets, tdelta * step    else:        offsets = np.linspace(np.zeros(tstart.shape), np.ones(tstop.shape), *args, **kwargs)        return tstart + (tstop - tstart) * offsets</ins>


Question: IllegalMinuteWarning, IllegalMinuteError,                      IllegalSecondWarning, IllegalSecondError) from astropy.utils import format_exception, parsing<ins>from astropy.utils.decorators import deprecated</ins> from astropy import units as u

Angle bug for (d, m, s) tuple input (deprecate dmstodegrees) does not handle the sign correctly for a tuple input if : <!-- Provide a general description of the bug. --fix for the issue (Angle bug for (d, m, s) tuple input (deprecate dmstodegrees)) fix for the issue Two solutions are proposed. code for solution 1 is presented in this pull request.


Question: return np.floor(sign * d), sign * np.floor(m), sign * s  @deprecated("dms_to_degrees (or creating an Angle with a tuple) has ambiguous "            "behavior when the degree value is 0",            alternative="another way of creating angles instead (e.g. a less "                         "ambiguous string like '-0d1m2.3s'") def dms_to_degrees(d, m, s=None):     """     Convert degrees, arcminute, arcsecond to a float degrees value.     """     _check_minute_range(m)     _check_second_range(s)


Question: return sign * (d + m / 60. + s / 3600.)  @deprecated("hms_to_hours (or creating an Angle with a tuple) has ambiguous "            "behavior when the hour value is 0",            alternative="another way of creating angles instead (e.g. a less "                         "ambiguous string like '-0h1m2.3s'") def hms_to_hours(h, m, s=None):     """     Convert hour, minute, second to a float hour value.diff --git a/astropy/coordinates/angles.py b/astropy/coordinates/angles.py-- a/astropy/coordinates/angles.py++ b/astropy/coordinates/angles.py


Question: <Angle 1.04166667 hourangle>       >>> Angle('-1:2.5', unit=u.deg)       <Angle -1.04166667 deg><del>      >>> Angle((10, 11, 12), unit='hourangle')  # (h, m, s)      <Angle 10.18666667 hourangle>      >>> Angle((-1, 2, 3), unit=u.deg)  # (d, m, s)      <Angle -1.03416667 deg></del>       >>> Angle(10.2345 * u.deg)       <Angle 10.2345 deg>       >>> Angle(Angle(10.2345 * u.deg))


Question: angle_unit = unit                  if isinstance(angle, tuple):                    angle = cls._tuple_to_float(angle, angle_unit)                    if angle_unit == u.hourangle:                        form._check_hour_range(angle[0])                    form._check_minute_range(angle[1])                    a = np.abs(angle[0]) + angle[1] / 60.                    if len(angle) == 3:                        form._check_second_range(angle[2])                        a += angle[2] / 3600.                    angle = np.copysign(a, angle[0])                  if angle_unit is not unit:                     # Possible conversion to `unit` will be done below.


Question: # untrusted code by only importing known astropy classes.     cls_full_name = obj_attrs.pop('__class__', None)     if cls_full_name is None:        cls = SerializedColumn    elif cls_full_name not in __construct_mixin_classes:        # We're dealing with a SerializedColumn holding columns, stored in        # obj_attrs. For this case, info holds the name (and nothing else).        mixin = SerializedColumn(obj_attrs)        mixin.info.name = info['name']        return mixin    if cls_full_name not in __construct_mixin_classes:         raise ValueError(f'unsupported class for construct {cls_full_name}')    else:        mod_name, _, cls_name = cls_full_name.rpartition('.')        module = import_module(mod_name)        cls = getattr(module, cls_name)     mod_name, _, cls_name = cls_full_name.rpartition('.')    module = import_module(mod_name)    cls = getattr(module, cls_name)     for attr, value in info.items():         if attr in cls.info.attrs_from_parent:             obj_attrs[attr] = value

Structured column serialization round-trip fails with field name of "name" <!-- This comments are hidden when you submit the issue, so you do not need to remove them! --<!-- Please be sure to check out our contributing guidelines, . Please be sure to check out our code of conduct, . --<!-- Please have a search on our GitHub repository to see if a similar issue has already been posted. If a similar issue is closed, have a quick look to see if you are satisfied by the resolution. If not please go ahead and open an issue! --<!-- Please check that the development version still produces the same bug. You can install development version with pip install command. --<!-- Provide a general description of the bug. --A structured column with a field name of cannot be round-tripped through ECSV. Along with this suggests a tweak to the serialization format is needed. Perhaps: cc: <!-- What did you expect to happen. --It should work! <!-- Ideally a code example could be provided so we can run it ourselves.


Question: # untrusted code by only importing known astropy classes.     cls_full_name = obj_attrs.pop('__class__', None)     if cls_full_name is None:        cls = SerializedColumn    elif cls_full_name not in __construct_mixin_classes:        # We're dealing with a SerializedColumn holding columns, stored in        # obj_attrs. For this case, info holds the name (and nothing else).        mixin = SerializedColumn(obj_attrs)        mixin.info.name = info['name']        return mixin    if cls_full_name not in __construct_mixin_classes:         raise ValueError(f'unsupported class for construct {cls_full_name}')    else:        mod_name, _, cls_name = cls_full_name.rpartition('.')        module = import_module(mod_name)        cls = getattr(module, cls_name)     mod_name, _, cls_name = cls_full_name.rpartition('.')    module = import_module(mod_name)    cls = getattr(module, cls_name)     for attr, value in info.items():         if attr in cls.info.attrs_from_parent:             obj_attrs[attr] = value

--<!-- If you are pasting code, use triple backticks (python import io import numpy as np from import Table, Column dtype = ([('z', 'f8'), ('name', 'f8'), ('y', 'i4')]) t = Table() t['c'] = Column([(1, 2, 3), (4, 5, 6)], dtype=dtype) out = io.StringIO() t.write(out, format='') print(out.getvalue()) t2 = (out.getvalue(), format='') c.z c.name c.y 0 2.0 3 0 5.0 6 Traceback (most recent call last): File in <modulet2 = (out.getvalue(), format='') File in call out = (cls, args, kwargs) File in read data = reader(args, kwargs) File in ioread return read(filename, **kwargs) File in read dat = (table) File in read table = self.outputter(, ) File in call out = serialize.constructmixinsfromcolumns(out) File in constructmixinsfromcolumns constructmixinfromcolumns(newname, objattrs, out) File in constructmixinfromcolumns dataattrsmap[val['name']] = name TypeError: unhashable type: 'SerializedColumn' macOS-10.16-x8664-i386-64bit Python 3.8.12 (default, Oct 12 2021, 06:23:56) [Clang 10.0.0 ] Numpy 1.22.2 pyerfa 2.0.0.1 astropy 5.1.dev956+g1d10de9d45. Scipy 1.8.0 Matplotlib 3.5.1


Question: data_attrs_map = {}     for name, val in obj_attrs.items():         if isinstance(val, SerializedColumn):            if 'name' in val:            # A SerializedColumn can just link to a serialized column using a name            # (e.g., time.jd1), or itself be a mixin (e.g., coord.obstime).  Note            # that in principle a mixin could have include a column called 'name',            # hence we check whether the value is actually a string (see gh-13232).            if 'name' in val and isinstance(val['name'], str):                 data_attrs_map[val['name']] = name             else:                 out_name = f'{new_name}.{name}'


Question: data_attrs_map = {}     for name, val in obj_attrs.items():         if isinstance(val, SerializedColumn):            if 'name' in val:            # A SerializedColumn can just link to a serialized column using a name            # (e.g., time.jd1), or itself be a mixin (e.g., coord.obstime).  Note            # that in principle a mixin could have include a column called 'name',            # hence we check whether the value is actually a string (see gh-13232).            if 'name' in val and isinstance(val['name'], str):                 data_attrs_map[val['name']] = name             else:                 out_name = f'{new_name}.{name}'


Question: for name in data_attrs_map.values():         del obj_attrs[name]     # Get the index where to add new column    idx = min(out.colnames.index(name) for name in data_attrs_map)    # The order of data_attrs_map may not match the actual order, as it is set    # by the yaml description.  So, sort names by position in the serialized table.    # Keep the index of the first column, so we can insert the new one there later.    names = sorted(data_attrs_map, key=out.colnames.index)    idx = out.colnames.index(names[0])      # Name is the column name in the table (e.g. "coord.ra") and     # data_attr is the object attribute name  (e.g. "ra").  A different     # example would be a formatted time object that would have (e.g.)     # "time_col" and "value", respectively.    for name, data_attr in data_attrs_map.items():        obj_attrs[data_attr] = out[name]    for name in names:        obj_attrs[data_attrs_map[name]] = out[name]         del out[name]      info = obj_attrs.pop('__info__', {})    if len(data_attrs_map) == 1:    if len(names) == 1:         # col is the first and only serialized column; in that case, use info         # stored on the column. First step is to get that first column which         # has been moved from `out` to `obj_attrs` above.        data_attr = next(iter(data_attrs_map.values()))        col = obj_attrs[data_attr]        col = obj_attrs[data_attrs_map[name]]          # Now copy the relevant attributes         for attr, nontrivial in (('unit', lambda x: x not in (None, '')),


Question: for name in data_attrs_map.values():         del obj_attrs[name]     # Get the index where to add new column    idx = min(out.colnames.index(name) for name in data_attrs_map)    # The order of data_attrs_map may not match the actual order, as it is set    # by the yaml description.  So, sort names by position in the serialized table.    # Keep the index of the first column, so we can insert the new one there later.    names = sorted(data_attrs_map, key=out.colnames.index)    idx = out.colnames.index(names[0])      # Name is the column name in the table (e.g. "coord.ra") and     # data_attr is the object attribute name  (e.g. "ra").  A different     # example would be a formatted time object that would have (e.g.)     # "time_col" and "value", respectively.    for name, data_attr in data_attrs_map.items():        obj_attrs[data_attr] = out[name]    for name in names:        obj_attrs[data_attrs_map[name]] = out[name]         del out[name]      info = obj_attrs.pop('__info__', {})    if len(data_attrs_map) == 1:    if len(names) == 1:         # col is the first and only serialized column; in that case, use info         # stored on the column. First step is to get that first column which         # has been moved from `out` to `obj_attrs` above.        data_attr = next(iter(data_attrs_map.values()))        col = obj_attrs[data_attr]        col = obj_attrs[data_attrs_map[name]]          # Now copy the relevant attributes         for attr, nontrivial in (('unit', lambda x: x not in (None, '')),


Question: f'{fully_qualified_name} '                                 'did not return a valid mixin column') <del>        # Structured ndarray gets viewed as a mixin unless already a valid        # mixin class        if (not isinstance(data, Column) and not data_is_mixin                and isinstance(data, np.ndarray) and len(data.dtype) > 1):            data = data.view(NdarrayMixin)            data_is_mixin = True</del>         # Get the final column name using precedence.  Some objects may not         # have an info attribute. Also avoid creating info as a side effect.         if not name:

Consider removing auto-transform of structured column into NdarrayMixin <!-- This comments are hidden when you submit the issue, so you do not need to remove them! --<!-- Please be sure to check out our contributing guidelines, . Please be sure to check out our code of conduct, . --<!-- Please have a search on our GitHub repository to see if a similar issue has already been posted. If a similar issue is closed, have a quick look to see if you are satisfied by the resolution. If not please go ahead and open an issue! --<!-- Provide a general description of the feature you would like. --<!-- If you want to, you can suggest a draft design or API. --<!-- This way we have a deeper discussion on the feature. --Currently if you add a structured to a Table, it gets turned into an (via the code below). While this mostly works, I am not sure this is necessary or desirable any more after . Basically the original rational for was that structured dtype didn't quite work, in particular for serialization. So we pushed that out to a mixin class which would signal to unified I/O that it might not be supported. Proposal: Add a FutureWarning here telling the user to wrap in and that in the future (5.2) the structured array will be as a . Change the behavior in 5.2 by removing this clause. This is not critical for 5.1 but if we have the opportunity due to other (critical) bugfixes it might be nice to save 6 months in the change process. cc:


Question: dtype_bytes_or_chars(arr.dtype)]      arr_common = np.array([arr[0] for arr in arrs])    return arr_common.dtype.str    return arr_common.dtype.str if arr_common.dtype.names is None else arr_common.dtype.descr   class MergeStrategyMeta(type):

vstack'ing structured array tables fails with casting error <!-- This comments are hidden when you submit the issue, so you do not need to remove them! --<!-- Please be sure to check out our contributing guidelines, . Please be sure to check out our code of conduct, . --<!-- Please have a search on our GitHub repository to see if a similar issue has already been posted. If a similar issue is closed, have a quick look to see if you are satisfied by the resolution. If not please go ahead and open an issue! --<!-- Please check that the development version still produces the same bug. You can install development version with pip install command. --<!-- Provide a general description of the bug. --Using on tables containing columns backed by numpy structured arrays fails. <!-- Ideally a code example could be provided so we can run it ourselves. --<!-- If you are pasting code, use triple backticks (python a=Table([dict(field1='test',field2=(1.,0.5,1.5))]) b=Table([dict(field1='foo')]) ((a,b)) # works a=Table([dict(field1='test',field2=(1.,0.5,1.5))],dtype=[str,[('val','f4'),('min','f4'),('max','f4')]]) ((a,b)) # fails Traceback (most recent call last): Input In [45] in <cell line: ((a,b)) File in vstack out = vstack(tables, jointype, colnamemap, metadataconflicts) File in vstack col[idx0:idx1] = array[name] File in setitem [index] = value TypeError: Cannot cast array data from dtype([('val', '<f4'), ('min', '<f4'), ('max', '<f4')]) to dtype('V12') according to the rule 'unsafe' macOS-12.3.1-x86_64-i386-64bit Python 3.10.4 (main, Apr 26 2022, 19:42:59) [Clang 13.1.6 (clang-1316.0.21.2)] Numpy 1.22.3 pyerfa 2.0.0.1 astropy 5.2.dev92+gf0e2129aa Scipy 1.7.3 Matplotlib 3.5.2


Question: from . import icrs_cirs_transforms from . import cirs_observed_transforms from . import icrs_observed_transformsfrom . import itrs_observed_transforms from . import intermediate_rotation_transforms from . import ecliptic_transforms diff --git a/astropy/coordinates/builtin_frames/intermediate_rotation_transforms.py b/astropy/coordinates/builtin_frames/intermediate_rotation_transforms.py-- a/astropy/coordinates/builtin_frames/intermediate_rotation_transforms.py++ b/astropy/coordinates/builtin_frames/intermediate_rotation_transforms.py

A direct approach to ITRS to Observed transformations that stays within the ITRS. <!-- This comments are hidden when you submit the issue, so you do not need to remove them! --<!-- Please be sure to check out our contributing guidelines, . Please be sure to check out our code of conduct, . --<!-- Please have a search on our GitHub repository to see if a similar issue has already been posted. If a similar issue is closed, have a quick look to see if you are satisfied by the resolution. If not please go ahead and open an issue! --<!-- Provide a general description of the feature you would like. --<!-- If you want to, you can suggest a draft design or API. --<!-- This way we have a deeper discussion on the feature. --We have experienced recurring issues raised by folks that want to observe satellites and such (airplanes?, mountains?, neighboring buildings?) regarding the apparent inaccuracy of the ITRS to AltAz transform. I tire of explaining the problem of geocentric versus topocentric aberration and proposing the entirely nonintuitive solution laid out in . So, for the latest such issue (), I came up with a more direct approach. This approach stays entirely within the ITRS and merely converts between ITRS, AltAz, and HADec coordinates. I have put together the makings of a pull request that follows this approach for transforms between these frames (i.e. ITRS<-AltAz, ITRS<-HADec). One feature of this approach is that it treats the ITRS position as time invariant. It makes no sense to be doing an ITRS-ITRS transform for differing between the input and output frame, so the of the output frame is simply adopted. Even if it ends up being in the case of an or output frame where that is the default. This is because the current ITRS-ITRS transform refers the ITRS coordinates to the SSB rather than the rotating ITRF. Since ITRS positions tend to be nearby, any transform from one time to another leaves the poor ITRS position lost in the wake of the Earth's orbit around the SSB, perhaps millions of kilometers from where it is intended to be. Would folks be receptive to this approach? If so, I will submit my pull request.


Question: from . import icrs_cirs_transforms from . import cirs_observed_transforms from . import icrs_observed_transformsfrom . import itrs_observed_transforms from . import intermediate_rotation_transforms from . import ecliptic_transforms diff --git a/astropy/coordinates/builtin_frames/intermediate_rotation_transforms.py b/astropy/coordinates/builtin_frames/intermediate_rotation_transforms.py-- a/astropy/coordinates/builtin_frames/intermediate_rotation_transforms.py++ b/astropy/coordinates/builtin_frames/intermediate_rotation_transforms.py

<!-- Add any other context or screenshots about the feature request here. --<!-- This part is optional. --Here is the basic concept, which is tested and working. I have yet to add refraction, but I can do so if it is deemed important to do so:


Question: sp = erfa.sp00(*get_jd12(time, 'tt'))     pmmat = erfa.pom00(xp, yp, sp)     # now determine the greenwich apparent siderial time for the input obstime    # now determine the greenwich apparent sidereal time for the input obstime     # we use the 2006A model for consistency with RBPN matrix use in GCRS <-> TETE     ujd1, ujd2 = get_jd12(time, 'ut1')     jd1, jd2 = get_jd12(time, 'tt')


Question: sp = erfa.sp00(*get_jd12(time, 'tt'))     pmmat = erfa.pom00(xp, yp, sp)     # now determine the greenwich apparent siderial time for the input obstime    # now determine the greenwich apparent sidereal time for the input obstime     # we use the 2006A model for consistency with RBPN matrix use in GCRS <-> TETE     ujd1, ujd2 = get_jd12(time, 'ut1')     jd1, jd2 = get_jd12(time, 'tt')


Question: @frame_transform_graph.transform(FunctionTransformWithFiniteDifference, TETE, ITRS) def tete_to_itrs(tete_coo, itrs_frame):    # first get us to TETE at the target obstime, and geocentric position    # first get us to TETE at the target obstime, and location (no-op if same)     tete_coo2 = tete_coo.transform_to(TETE(obstime=itrs_frame.obstime,                                           location=EARTH_CENTER))                                           location=itrs_frame.location))      # now get the pmatrix     pmat = tete_to_itrs_mat(itrs_frame.obstime)


Question: @frame_transform_graph.transform(FunctionTransformWithFiniteDifference, TETE, ITRS) def tete_to_itrs(tete_coo, itrs_frame):    # first get us to TETE at the target obstime, and geocentric position    # first get us to TETE at the target obstime, and location (no-op if same)     tete_coo2 = tete_coo.transform_to(TETE(obstime=itrs_frame.obstime,                                           location=EARTH_CENTER))                                           location=itrs_frame.location))      # now get the pmatrix     pmat = tete_to_itrs_mat(itrs_frame.obstime)


Question: # compute the pmatrix, and then multiply by its transpose     pmat = tete_to_itrs_mat(itrs_coo.obstime)     newrepr = itrs_coo.cartesian.transform(matrix_transpose(pmat))    tete = TETE(newrepr, obstime=itrs_coo.obstime)    tete = TETE(newrepr, obstime=itrs_coo.obstime, location=itrs_coo.location)     # now do any needed offsets (no-op if same obstime)    # now do any needed offsets (no-op if same obstime and location)     return tete.transform_to(tete_frame)


Question: # compute the pmatrix, and then multiply by its transpose     pmat = tete_to_itrs_mat(itrs_coo.obstime)     newrepr = itrs_coo.cartesian.transform(matrix_transpose(pmat))    tete = TETE(newrepr, obstime=itrs_coo.obstime)    tete = TETE(newrepr, obstime=itrs_coo.obstime, location=itrs_coo.location)     # now do any needed offsets (no-op if same obstime)    # now do any needed offsets (no-op if same obstime and location)     return tete.transform_to(tete_frame)