Repository: BlueBrain/MorphIO (language: python)

Issue:
Attempting to write a soma without diameters segfaults for swc & asc
```python
from morphio.mut import Morphology
from morphio import PointLevel, SectionType
m = Morphology()
m.soma.points = [[0.0, 0.0, 0.0]]
m.write("test.asc")
m.write("test.swc")
```
Results in a segfault.

Using the hdf5 format, it handles the missing diameters and throws the appropriate error:
```python
WriterError: Vector length mismatch: 
Length soma points: 1
Length soma diameters: 0
Tip: Did you forget to fill vector: soma diameters ?
```


Discussion / hints:

Fix patch:
diff --git a/src/mut/writers.cpp b/src/mut/writers.cpp
index 3e3cd2241..d56b95688 100644
--- a/src/mut/writers.cpp
+++ b/src/mut/writers.cpp
@@ -62,6 +62,15 @@ bool _skipDuplicate(const std::shared_ptr<morphio::mut::Section>& section) {
     return section->diameters().front() == section->parent()->diameters().back();
 }
 
+static void checkSomaHasSameNumberPointsDiameters(const morphio::mut::Soma& soma) {
+    const size_t n_points = soma.points().size();
+    const size_t n_diameters = soma.diameters().size();
+
+    if (n_points != n_diameters) {
+        throw morphio::WriterError(morphio::readers::ErrorMessages().ERROR_VECTOR_LENGTH_MISMATCH(
+            "soma points", n_points, "soma diameters", n_diameters));
+    }
+}
 }  // anonymous namespace
 
 namespace morphio {
@@ -77,6 +86,8 @@ void swc(const Morphology& morphology, const std::string& filename) {
         return;
     }
 
+    checkSomaHasSameNumberPointsDiameters(*soma);
+
     if (hasPerimeterData(morphology)) {
         throw WriterError(readers::ErrorMessages().ERROR_PERIMETER_DATA_NOT_WRITABLE());
     }
@@ -183,6 +194,8 @@ void asc(const Morphology& morphology, const std::string& filename) {
         return;
     }
 
+    checkSomaHasSameNumberPointsDiameters(*soma);
+
     if (hasPerimeterData(morphology)) {
         throw WriterError(readers::ErrorMessages().ERROR_PERIMETER_DATA_NOT_WRITABLE());
     }
@@ -330,7 +343,8 @@ static void dendriticSpinePostSynapticDensityH5(HighFive::File& h5_file,
 
 
 void h5(const Morphology& morpho, const std::string& filename) {
-    const auto& somaPoints = morpho.soma()->points();
+    const auto& soma = morpho.soma();
+    const auto& somaPoints = soma->points();
     const auto numberOfSomaPoints = somaPoints.size();
 
     if (numberOfSomaPoints < 1) {
@@ -342,6 +356,7 @@ void h5(const Morphology& morpho, const std::string& filename) {
         printError(Warning::WRITE_NO_SOMA, readers::ErrorMessages().WARNING_WRITE_NO_SOMA());
     }
 
+    checkSomaHasSameNumberPointsDiameters(*soma);
 
     HighFive::File h5_file(filename,
                            HighFive::File::ReadWrite | HighFive::File::Create |
@@ -354,16 +369,7 @@ void h5(const Morphology& morpho, const std::string& filename) {
     std::vector<std::vector<int32_t>> raw_structure;
     std::vector<morphio::floatType> raw_perimeters;
 
-    const auto& somaDiameters = morpho.soma()->diameters();
-
-    const auto numberOfSomaDiameters = somaDiameters.size();
-
-
-    if (numberOfSomaPoints != numberOfSomaDiameters) {
-        throw WriterError(readers::ErrorMessages().ERROR_VECTOR_LENGTH_MISMATCH(
-            "soma points", numberOfSomaPoints, "soma diameters", numberOfSomaDiameters));
-    }
-
+    const auto& somaDiameters = soma->diameters();
 
     bool hasPerimeterData_ = hasPerimeterData(morpho);
 


Test patch:
diff --git a/tests/test_6_writers.py b/tests/test_6_writers.py
index 65cee939d..6ca8d51f7 100644
--- a/tests/test_6_writers.py
+++ b/tests/test_6_writers.py
@@ -204,6 +204,18 @@ def test_write_no_soma():
             assert_array_equal(read.root_sections[1].points, [[0, 1, 0], [0, 7, 0]])
 
 
+def test_write_soma__points_no_diameters():
+
+    morph = Morphology()
+    morph.soma.points = [[0., 0., 0.]]
+
+    with TemporaryDirectory("test_write_soma__points_no_diameters") as tmp_folder:
+
+        for ext in ["asc", "h5", "swc"]:
+            with pytest.raises(WriterError):
+                morph.write(Path(tmp_folder, f"tmp.{ext}"))
+
+
 def test_mitochondria():
     morpho = Morphology()
     morpho.soma.points = [[0, 0, 0], [1, 1, 1]]