Skip to content

Commit

Permalink
Decouple Morphology constructor from io
Browse files Browse the repository at this point in the history
  • Loading branch information
eleftherioszisis committed Apr 25, 2024
1 parent 985a4dd commit f5f92d2
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 35 deletions.
9 changes: 3 additions & 6 deletions neurom/core/morphology.py
Original file line number Diff line number Diff line change
Expand Up @@ -538,18 +538,15 @@ def __repr__(self):
class Morphology:
"""Class representing a simple morphology."""

def __init__(self, filename, name=None, process_subtrees=False):
def __init__(self, morphio_morph, name=None, process_subtrees=False):
"""Morphology constructor.
Args:
filename (str|Path): a filename or morphio.{mut}.Morphology object
morphio_morph (morphio.Morphology|morphio.mut.Morphology): a morphio object
name (str): an optional morphology name
process_subtrees (bool): enable mixed tree processing if set to True
"""
self._morphio_morph = morphio.mut.Morphology(filename)

if isinstance(filename, (str, Path, morphio.Morphology)):
self._morphio_morph = self._morphio_morph.as_immutable()
self._morphio_morph = morphio_morph

self.name = name if name else 'Morphology'
self.soma = make_soma(self._morphio_morph.soma)
Expand Down
29 changes: 19 additions & 10 deletions neurom/io/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ def _get_file(stream, extension):
return temp_file


def load_morphology(morph, reader=None, process_subtrees=False):
def load_morphology(morph, reader=None, mutable=None, process_subtrees=False):
"""Build section trees from a morphology or a h5, swc or asc file.
Args:
Expand Down Expand Up @@ -157,15 +157,24 @@ def load_morphology(morph, reader=None, process_subtrees=False):
)'''), reader='asc')
"""
if isinstance(morph, Morphology):
return Morphology(morph.to_morphio(), process_subtrees=process_subtrees)

if isinstance(morph, (morphio.Morphology, morphio.mut.Morphology)):
return Morphology(morph, process_subtrees=process_subtrees)

if reader:
return Morphology(_get_file(morph, reader), process_subtrees=process_subtrees)

return Morphology(morph, Path(morph).name, process_subtrees=process_subtrees)
name = morph.name
morphio_morph = morph.to_morphio()
elif isinstance(morph, (morphio.Morphology, morphio.mut.Morphology)):
name = "Morphology"
morphio_morph = morph
else:
filepath = _get_file(morph, reader) if reader else morph
name = os.path.basename(filepath)
morphio_morph = morphio.Morphology(filepath)

# None does not modify existing mutability
if mutable is not None:
if mutable and isinstance(morphio_morph, morphio.Morphology):
morphio_morph = morphio_morph.as_mutable()
elif not mutable and isinstance(morphio_morph, morphio.mut.Morphology):
morphio_morph = morphio_morph.as_immutable()

return Morphology(morphio_morph, name=name, process_subtrees=process_subtrees)


def load_morphologies(
Expand Down
19 changes: 0 additions & 19 deletions tests/core/test_neuron.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,6 @@ def test_load_morphology_from_other_morphologies():
]

assert_array_equal(nm.load_morphology(nm.load_morphology(filename)).points, expected_points)

assert_array_equal(nm.load_morphology(Morphology(filename)).points, expected_points)

assert_array_equal(nm.load_morphology(morphio.Morphology(filename)).points, expected_points)


Expand Down Expand Up @@ -140,19 +137,3 @@ def test_str():
n = nm.load_morphology(SWC_PATH / 'simple.swc')
assert 'Morphology' in str(n)
assert 'Section' in str(n.neurites[0].root_node)


def test_mut_nonmut_constructor():
path = SWC_PATH / 'simple.swc'

m = Morphology(path)
assert isinstance(m.to_morphio(), morphio.Morphology)

m = Morphology(str(path))
assert isinstance(m.to_morphio(), morphio.Morphology)

m = Morphology(morphio.Morphology(path))
assert isinstance(m.to_morphio(), morphio.Morphology)

m = Morphology(morphio.mut.Morphology(path))
assert isinstance(m.to_morphio(), morphio.mut.Morphology)
59 changes: 59 additions & 0 deletions tests/io/test_io_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
from pathlib import Path

import numpy as np
import morphio
from morphio import (
MissingParentError,
RawDataError,
Expand Down Expand Up @@ -183,6 +184,64 @@ def test_load_morphology():
utils.load_morphology(StringIO(morphology_str), reader='swc')


def test_load_morphology__conversions():

morphology_str = u""" 1 1 0 0 0 1. -1
2 3 0 0 0 1. 1
3 3 0 5 0 1. 2
4 3 -5 5 0 0. 3
5 3 6 5 0 0. 3
6 2 0 0 0 1. 1
7 2 0 -4 0 1. 6
8 2 6 -4 0 0. 7
9 2 -5 -4 0 0. 7
"""
filepath = FILENAMES[0]
morphio_mut = morphio.mut.Morphology(filepath)
morphio_immut = morphio_mut.as_immutable()

# default readonly
morph = utils.load_morphology(filepath)
assert isinstance(morph.to_morphio(), morphio.Morphology)

# should be same with mutable=False
morph = utils.load_morphology(filepath, mutable=False)
assert isinstance(morph.to_morphio(), morphio.Morphology)

morph = utils.load_morphology(filepath, mutable=True)
assert isinstance(morph.to_morphio(), morphio.mut.Morphology)

# default mutable=None maintains mutability
morph = utils.load_morphology(morphio_mut)
assert isinstance(morph.to_morphio(), morphio.mut.Morphology)

morph = utils.load_morphology(morphio_mut, mutable=False)
assert isinstance(morph.to_morphio(), morphio.Morphology)

morph = utils.load_morphology(morphio_mut, mutable=True)
assert isinstance(morph.to_morphio(), morphio.mut.Morphology)

# default mutable=None maintains mutability
morph = utils.load_morphology(morphio_immut)
assert isinstance(morph.to_morphio(), morphio.Morphology)

morph = utils.load_morphology(morphio_immut, mutable=False)
assert isinstance(morph.to_morphio(), morphio.Morphology)

morph = utils.load_morphology(morphio_immut, mutable=True)
assert isinstance(morph.to_morphio(), morphio.mut.Morphology)

# default mutable=None is readaonly
morph = utils.load_morphology(morphology_str, reader="swc")
assert isinstance(morph.to_morphio(), morphio.Morphology)

morph = utils.load_morphology(morphology_str, mutable=False, reader="swc")
assert isinstance(morph.to_morphio(), morphio.Morphology)

morph = utils.load_morphology(morphology_str, mutable=True, reader="swc")
assert isinstance(morph.to_morphio(), morphio.mut.Morphology)


def test_morphology_name():
for fn, nn in zip(FILENAMES, NRN_NAMES):
m = utils.load_morphology(fn)
Expand Down

0 comments on commit f5f92d2

Please sign in to comment.