Repository: astropy/astropy

Issue:
Table's subclass break with serialization
With the serialization of astropy objects to FITS (#6912), I just noticed that it breaks the use of our `Table` subclass. When writing and reading back a FITS file with this subclass, `io.registry.read` now fails because the reader return a `QTable`, for which my class is not a subclass.
I don't see a way to disable the serialization, or to not use it while reading. Any idea @taldcroft ?

Discussion:
astropy-bot[bot]: Hi there @saimn :wave: - thanks for the pull request! I'm just a friendly :robot: that checks for issues related to the changelog and making sure that this pull request is milestoned and labeled correctly. This is mainly intended for the maintainers, so if you are not a maintainer you can ignore this, and a maintainer will let you know if any action is required on your part :smiley:.

Everything looks good from my point of view! :+1:

*If there are any issues with this message, please report them [here](https://github.com/astropy/astropy-bot/issues).*

Patch:
diff --git a/CHANGES.rst b/CHANGES.rst
index a29607457c..6e2947a749 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -291,6 +291,8 @@ astropy.io.misc
 astropy.io.registry
 ^^^^^^^^^^^^^^^^^^^
 
+- Fix reading files with serialized metadata when using a Table subclass. [#7213]
+
 astropy.io.votable
 ^^^^^^^^^^^^^^^^^^
 
diff --git a/astropy/io/registry.py b/astropy/io/registry.py
index b332f83fe0..cca3fd0cb4 100644
--- a/astropy/io/registry.py
+++ b/astropy/io/registry.py
@@ -517,18 +517,14 @@ def read(cls, *args, format=None, **kwargs):
         data = reader(*args, **kwargs)
 
         if not isinstance(data, cls):
-            if issubclass(cls, data.__class__):
-                # User has read with a subclass where only the parent class is
-                # registered.  This returns the parent class, so try coercing
-                # to desired subclass.
-                try:
-                    data = cls(data)
-                except Exception:
-                    raise TypeError('could not convert reader output to {0} '
-                                    'class.'.format(cls.__name__))
-            else:
-                raise TypeError("reader should return a {0} instance"
-                                "".format(cls.__name__))
+            # User has read with a subclass where only the parent class is
+            # registered.  This returns the parent class, so try coercing
+            # to desired subclass.
+            try:
+                data = cls(data)
+            except Exception:
+                raise TypeError('could not convert reader output to {0} '
+                                'class.'.format(cls.__name__))
     finally:
         if ctx is not None:
             ctx.__exit__(*sys.exc_info())


Test patch:
diff --git a/astropy/io/tests/test_registry.py b/astropy/io/tests/test_registry.py
index a0da127a7b..91ffc623a5 100644
--- a/astropy/io/tests/test_registry.py
+++ b/astropy/io/tests/test_registry.py
@@ -1,7 +1,5 @@
 # Licensed under a 3-clause BSD style license - see LICENSE.rst
 
-
-
 import os
 from copy import copy
 from io import StringIO
@@ -12,11 +10,18 @@ import numpy as np
 from ..registry import _readers, _writers, _identifiers
 from .. import registry as io_registry
 from ...table import Table
+from ... import units as u
 
 _READERS_ORIGINAL = copy(_readers)
 _WRITERS_ORIGINAL = copy(_writers)
 _IDENTIFIERS_ORIGINAL = copy(_identifiers)
 
+try:
+    import yaml  # pylint: disable=W0611
+    HAS_YAML = True
+except ImportError:
+    HAS_YAML = False
+
 
 class TestData:
     read = classmethod(io_registry.read)
@@ -317,13 +322,6 @@ def test_read_valid_return():
     assert isinstance(t, TestData)
 
 
-def test_read_invalid_return():
-    io_registry.register_reader('test', TestData, lambda: 'spam')
-    with pytest.raises(TypeError) as exc:
-        TestData.read(format='test')
-    assert str(exc.value) == "reader should return a TestData instance"
-
-
 def test_non_existing_unknown_ext():
     """Raise the correct error when attempting to read a non-existing
     file with an unknown extension."""
@@ -410,3 +408,30 @@ class TestSubclass:
         mt = MyTable([[1], [2]], names=['a', 'b'])
         mt.write(buffer, format='ascii')
         assert buffer.getvalue() == os.linesep.join(['a b', '1 2', ''])
+
+    def test_read_table_subclass_with_columns_attributes(self, tmpdir):
+        """Regression test for https://github.com/astropy/astropy/issues/7181
+        """
+
+        class MTable(Table):
+            pass
+
+        mt = MTable([[1, 2.5]], names=['a'])
+        mt['a'].unit = u.m
+        mt['a'].format = '.4f'
+        mt['a'].description = 'hello'
+
+        testfile = str(tmpdir.join('junk.fits'))
+        mt.write(testfile, overwrite=True)
+
+        t = MTable.read(testfile)
+        assert np.all(mt == t)
+        assert mt.colnames == t.colnames
+        assert type(t) is MTable
+        assert t['a'].unit == u.m
+        if HAS_YAML:
+            assert t['a'].format == '.4f'
+            assert t['a'].description == 'hello'
+        else:
+            assert t['a'].format is None
+            assert t['a'].description is None