Repository: astropy/astropy (Python)

Issue:
writing a basic ascii table from QTable is broken
```python
from astropy.table import QTable,Column
import astropy.units as u
q = QTable()
q['dt'] = [1,2,3]*u.s
q.write('foo.txt',format='ascii.no_header',delimiter=',',formats={'dt':'%.18f'})
```

The write call throws an exception with "Quantity object has no name member"

If I look in `_set_col_formats` in `io/ascii/core.py`
it says
```python
if col.info.name in self.formats:
   col.info.format = self.formats[col.name]
```

That second line probably should say "col.info.name" instead.  A similar change would need to be made in the fast writer

EDIT: Syntax highlighting


Discussion:
From your Slack message, you said this exact code used to work in Astropy 1.2.4? If not, please provide the snippet that worked in Astropy 1.2.4. Thanks.
Thanks for the report!

Looking into this more, looks like `col.name` works with `Table` but not `QTable`. However, `col.info.name` works with both.

@taldcroft or @mhvk , what is the proper patch here? Should `QTable` support `col.name` or do we change usage to `col.info.name`?
On Thu, May 09, 2019 at 07:21:56AM -0700, P. L. Lim wrote:
>    From your Slack message, you said this exact code used to work in Astropy
>    1.2.4? If not, please provide the snippet that worked in Astropy 1.2.4.
>    Thanks.

Yes, that exact code worked on 1.2.4

Jeff

-- 
"The man who does not read good books has no advantage over 
 the man who cannot read them."
 -- not Mark Twain, maybe a southen librarian in 1910

Changing to `col.info.name` is the correct patch.  Going through the `info` attribute is the generalized version that works for both mixins (e.g. Quantity) and normal Columns.
@mcbeth , do you want to go ahead and submit a PR with the suggested patch?

http://docs.astropy.org/en/stable/development/workflow/development_workflow.html
I can also probably make a quick fix if @mcbeth does not have time.
First come, first serve! We are open-source and open-development after all. :wink: 
My main hesitation would be that I haven't dug through the fast writer far enough to figure out how to make the same change there.  I guarantee that @taldcroft will be quicker.



Patch:
diff --git a/CHANGES.rst b/CHANGES.rst
index 86e34d5a3c01..3dc79416e8fb 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -698,6 +698,10 @@ astropy.extern
 astropy.io.ascii
 ^^^^^^^^^^^^^^^^
 
+- Fixed a bug where an exception was raised when writing a table which includes
+  mixin columns (e.g. a Quantity column) and the output format was specified
+  using the ``formats`` keyword. [#8681]
+
 astropy.io.misc
 ^^^^^^^^^^^^^^^
 
diff --git a/astropy/io/ascii/core.py b/astropy/io/ascii/core.py
index 1ef6539d8023..359ece4a4d73 100644
--- a/astropy/io/ascii/core.py
+++ b/astropy/io/ascii/core.py
@@ -835,7 +835,7 @@ def _set_col_formats(self):
         """
         for col in self.cols:
             if col.info.name in self.formats:
-                col.info.format = self.formats[col.name]
+                col.info.format = self.formats[col.info.name]
 
 
 def convert_numpy(numpy_type):


Test patch:
diff --git a/astropy/io/ascii/tests/test_write.py b/astropy/io/ascii/tests/test_write.py
index ea545160e04b..72e8fb9d7225 100644
--- a/astropy/io/ascii/tests/test_write.py
+++ b/astropy/io/ascii/tests/test_write.py
@@ -15,7 +15,7 @@
 from astropy.table.table_helpers import simple_table
 from astropy.tests.helper import catch_warnings
 from astropy.utils.exceptions import AstropyWarning, AstropyDeprecationWarning
-from astropy import units
+from astropy import units as u
 
 from .common import setup_function, teardown_function
 
@@ -582,8 +582,8 @@ def test_latex_units():
     ascii.write(t, out, format='aastex', latexdict=latexdict)
     assert out.getvalue() == expected
     # use unit attribute instead
-    t['NUV exp.time'].unit = units.s
-    t['date'].unit = units.yr
+    t['NUV exp.time'].unit = u.s
+    t['date'].unit = u.yr
     out = StringIO()
     ascii.write(t, out, format='aastex', latexdict=ascii.latexdicts['AA'])
     assert out.getvalue() == expected.replace(
@@ -768,3 +768,16 @@ def test_write_newlines(fast_writer, tmpdir):
         content = f.read()
 
     assert content == os.linesep.join(['col', 'a', 'b', 'c']) + os.linesep
+
+@pytest.mark.parametrize("fast_writer", [True, False])
+def test_write_formatted_mixin(fast_writer):
+    """
+    Test fix for #8680 where writing a QTable with a quantity mixin generates
+    an exception if a format is specified.
+    """
+    out = StringIO()
+    t = table.QTable([[1, 2], [1, 2] * u.m], names=['a', 'b'])
+    ascii.write(t, out, fast_writer=fast_writer, formats={'a': '%02d', 'b': '%.2f'})
+    assert out.getvalue().splitlines() == ['a b',
+                                           '01 1.00',
+                                           '02 2.00']