Repository: astropy/pyvo
Pull request #197 (2019-12-12 23:07:09)

Handle description of None when describing a TAP service's tables
This small PR is to address an issue we have found in describing available tables from a TAP service, when a description is not provided.

To test:
```
import pyvo as vo
irsa_services = vo.regsearch(servicetype='table', keywords=['irsa'])
irsa_tap = irsa_services[0]
irsa_tap.service.tables.describe()
```
The fix in the PR is to print `No description` instead of raising an exception.

cbanek: Since this is a user facing kind of thing, might want to add an entry to the CHANGELOG (although I'm also fine if we think this is below that bar, we can add the flag no-changelog-entry-needed)
codecov[bot]: # [Codecov](https://codecov.io/gh/astropy/pyvo/pull/197?src=pr&el=h1) Report
> Merging [#197](https://codecov.io/gh/astropy/pyvo/pull/197?src=pr&el=desc) into [master](https://codecov.io/gh/astropy/pyvo/commit/78e3d52c41c114d01a30579caa62f2af4ef61c53?src=pr&el=desc) will **decrease** coverage by `0.03%`.
> The diff coverage is `0%`.

[![Impacted file tree graph](https://codecov.io/gh/astropy/pyvo/pull/197/graphs/tree.svg?width=650&token=Mynyo9xoPZ&height=150&src=pr)](https://codecov.io/gh/astropy/pyvo/pull/197?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master     #197      +/-   ##
==========================================
- Coverage   70.81%   70.78%   -0.04%     
==========================================
  Files          37       37              
  Lines        3910     3912       +2     
==========================================
  Hits         2769     2769              
- Misses       1141     1143       +2
```


| [Impacted Files](https://codecov.io/gh/astropy/pyvo/pull/197?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [pyvo/io/vosi/vodataservice.py](https://codecov.io/gh/astropy/pyvo/pull/197/diff?src=pr&el=tree#diff-cHl2by9pby92b3NpL3ZvZGF0YXNlcnZpY2UucHk=) | `83.24% <0%> (-0.44%)` | :arrow_down: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/astropy/pyvo/pull/197?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/astropy/pyvo/pull/197?src=pr&el=footer). Last update [78e3d52...edb0d5b](https://codecov.io/gh/astropy/pyvo/pull/197?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

stargaser: I feel like I should add a test. Looks like I should make an analog of `tests/data/tables/multiple_table_descriptions.xml` that is `missing_table_description.xml` and then add a test using that file. Does that make sense?
stargaser: Cross-referencing NASA-NAVO/workshop-dev#5 where we noticed the problem addressed in this PR.
stargaser: Huh, looks like codecov/project increased by adding the test, but codecov/patch went down. I'm puzzled.

Patch:
diff --git a/CHANGES.rst b/CHANGES.rst
index 54eb7cd..a956cf8 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -3,6 +3,7 @@
 
 - Add default for UWS version. [#199]
 
+- Handle description of None when describing a TAP service's tables. [#197]
 
 1.0 (2019-09-20)
 ================
diff --git a/pyvo/io/vosi/vodataservice.py b/pyvo/io/vosi/vodataservice.py
index d9666c8..28b3bf5 100644
--- a/pyvo/io/vosi/vodataservice.py
+++ b/pyvo/io/vosi/vodataservice.py
@@ -311,7 +311,10 @@ class Table(Element):
 
     def describe(self):
         print(self.name)
-        print(indent(self.description))
+        if self.description is not None:
+            print(indent(self.description))
+        else:
+            print('No description')
 
         print()
 


Test patch:
diff --git a/pyvo/io/vosi/tests/data/tables/no_table_description.xml b/pyvo/io/vosi/tests/data/tables/no_table_description.xml
new file mode 100644
index 0000000..b8d4912
--- /dev/null
+++ b/pyvo/io/vosi/tests/data/tables/no_table_description.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href='/static/xsl/vosi.xsl' type='text/xsl'?>
+<vtm:tableset xmlns:vs="http://www.ivoa.net/xml/VODataService/v1.1" xmlns:vtm="http://www.ivoa.net/xml/VOSITables/v1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.ivoa.net/xml/VODataService/v1.1 http://vo.ari.uni-heidelberg.de/docs/schemata/VODataService-v1.1.xsd http://www.ivoa.net/xml/VOSITables/v1.0 http://vo.ari.uni-heidelberg.de/docs/schemata/VOSITables-v1.0.xsd">
+  <schema>
+    <name>test</name>
+    <table>
+      <name>description</name>
+    </table>
+  </schema>
+</vtm:tableset>
diff --git a/pyvo/io/vosi/tests/data/tables/single_table_description.xml b/pyvo/io/vosi/tests/data/tables/single_table_description.xml
new file mode 100644
index 0000000..027ad6a
--- /dev/null
+++ b/pyvo/io/vosi/tests/data/tables/single_table_description.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href='/static/xsl/vosi.xsl' type='text/xsl'?>
+<vtm:tableset xmlns:vs="http://www.ivoa.net/xml/VODataService/v1.1" xmlns:vtm="http://www.ivoa.net/xml/VOSITables/v1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.ivoa.net/xml/VODataService/v1.1 http://vo.ari.uni-heidelberg.de/docs/schemata/VODataService-v1.1.xsd http://www.ivoa.net/xml/VOSITables/v1.0 http://vo.ari.uni-heidelberg.de/docs/schemata/VOSITables-v1.0.xsd">
+  <schema>
+    <name>test</name>
+    <table>
+      <name>description</name>
+      <description>A test table with a single description</description>
+    </table>
+  </schema>
+</vtm:tableset>
diff --git a/pyvo/io/vosi/tests/test_tables.py b/pyvo/io/vosi/tests/test_tables.py
index 811e2ed..e9bb6ed 100644
--- a/pyvo/io/vosi/tests/test_tables.py
+++ b/pyvo/io/vosi/tests/test_tables.py
@@ -3,6 +3,8 @@
 """
 Tests for pyvo.io.vosi
 """
+import contextlib
+import io
 import pytest
 
 import pyvo.io.vosi as vosi
@@ -368,3 +370,32 @@ class TestTables:
             vosi.parse_tables(
                 get_pkg_data_filename(
                     "data/tables/wrong_arraysize.xml"))
+
+    def test_no_table_description(self):
+        """Test handling of describing tables with no description
+        """
+        tableset = vosi.parse_tables(
+                get_pkg_data_filename(
+                    "data/tables/no_table_description.xml"))
+        nodesc_table = tableset.get_first_table()
+        assert nodesc_table.description is None
+
+        with io.StringIO() as buf, contextlib.redirect_stdout(buf):
+            nodesc_table.describe()
+            output = buf.getvalue()
+        assert 'No description' in output
+
+    def test_single_table_description(self):
+        """Test describing a table with a single description
+        """
+        tableset = vosi.parse_tables(
+                get_pkg_data_filename(
+                    "data/tables/single_table_description.xml"))
+        onedesc_table = tableset.get_first_table()
+        describe_string = 'A test table with a single description'
+        assert describe_string in onedesc_table.description
+
+        with io.StringIO() as buf, contextlib.redirect_stdout(buf):
+            onedesc_table.describe()
+            output = buf.getvalue()
+        assert describe_string in output