Repository: obspy/obspy

Issue:
Empty EventDescription results with text values of "None"
Running on current obspy master on Ubuntu 16, python 3.7

Empty `EventDescription` objects prevents a catalog from being saved to disk via quakeml and still evaluating to equal.

```python
import io
import obspy.core.event as ev
from obspy import read_events

# create a catalog  with an empty event description
empty_description = ev.EventDescription()
cat1 = read_events()
cat1[0].event_descriptions.append(empty_description)

# serialize the catalog using quakeml and re-read
bio = io.BytesIO()
cat1.write(bio, 'quakeml')
bio.seek(0)
cat2 = read_events(bio)

# the two catalog are not equal
assert cat1 == cat2 

# because one event_description has text of 'None' and the other of None
assert cat1[0].event_descriptions[-1].text == cat2[0].event_descriptions[-1].text
```


Discussion:

Resolving patch:
diff --git a/obspy/io/quakeml/core.py b/obspy/io/quakeml/core.py
--- a/obspy/io/quakeml/core.py
+++ b/obspy/io/quakeml/core.py
@@ -1759,7 +1759,7 @@ def _serialize(self, catalog, pretty_print=True):
             # event descriptions
             for description in event.event_descriptions:
                 el = etree.Element('description')
-                self._str(description.text, el, 'text', True)
+                self._str(description.text, el, 'text')
                 self._str(description.type, el, 'type')
                 self._extra(description, el)
                 event_el.append(el)


Test patch:
diff --git a/obspy/io/quakeml/tests/test_quakeml.py b/obspy/io/quakeml/tests/test_quakeml.py
--- a/obspy/io/quakeml/tests/test_quakeml.py
+++ b/obspy/io/quakeml/tests/test_quakeml.py
@@ -13,7 +13,8 @@
 
 from obspy.core.event import (Catalog, Event, FocalMechanism, Magnitude,
                               MomentTensor, Origin, Pick, ResourceIdentifier,
-                              Tensor, WaveformStreamID, read_events)
+                              Tensor, WaveformStreamID, read_events,
+                              EventDescription)
 from obspy.core.utcdatetime import UTCDateTime
 from obspy.core.util import AttribDict
 from obspy.core.util.base import NamedTemporaryFile
@@ -1107,6 +1108,27 @@ def test_reading_invalid_enums(self):
         # It should of course not be set.
         self.assertIsNone(cat[0].origins[0].depth_type)
 
+    def test_issue_2339(self):
+        """
+        Make sure an empty EventDescription object does not prevent a catalog
+        from being saved to disk and re-read, while still being equal.
+        """
+        # create a catalog  with an empty event description
+        empty_description = EventDescription()
+        cat1 = Catalog(events=[read_events()[0]])
+        cat1[0].event_descriptions.append(empty_description)
+        # serialize the catalog using quakeml and re-read
+        bio = io.BytesIO()
+        cat1.write(bio, 'quakeml')
+        bio.seek(0)
+        cat2 = read_events(bio)
+        # the text of the empty EventDescription instances should be equal
+        text1 = cat1[0].event_descriptions[-1].text
+        text2 = cat2[0].event_descriptions[-1].text
+        self.assertEqual(text1, text2)
+        # the two catalogs should be equal
+        self.assertEqual(cat1, cat2)
+
 
 def suite():
     return unittest.makeSuite(QuakeMLTestCase, 'test')