Skip to content

Commit

Permalink
v0.8.1: bugfix for using subtomogram averages in the list of shapes f…
Browse files Browse the repository at this point in the history
…or a segment
  • Loading branch information
Paul K. Korir, PhD committed Sep 26, 2023
1 parent 9894de9 commit 923c81c
Show file tree
Hide file tree
Showing 7 changed files with 65 additions and 27 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
@@ -1,5 +1,9 @@
#Changes by release

## [0.8.1] - 2023-09-26

* bugfix for using `SubtomogramAverage` class in `SFFShapePrimitiveList` class

## [0.8.0] - 2023-09-25

* added `SFFSubtomogramAverage` class
Expand Down
2 changes: 1 addition & 1 deletion sfftkrw/conf.py
@@ -1,2 +1,2 @@
SFFTKRW_VERSION = 'v0.8.0'
SFFTKRW_VERSION = 'v0.8.1'
SFFTKRW_ENTRY_POINT = 'sff'
11 changes: 8 additions & 3 deletions sfftkrw/schema/adapter_v0_8_0_dev1.py
Expand Up @@ -1709,6 +1709,7 @@ class SFFShapePrimitiveList(SFFListType):
(_sff.cuboid, SFFCuboid),
(_sff.cylinder, SFFCylinder),
(_sff.ellipsoid, SFFEllipsoid),
(_sff.three_d_volume_type, SFFSubtomogramAverage),
]

def _shape_count(self, shape_type):
Expand All @@ -1734,9 +1735,9 @@ def num_cones(self):
"""The number of cones in this container"""
return self._shape_count(_sff.cone)

# @property
# def num_subtomogram_averages(self):
# return self._shape_count(sff.subtomogramAverage)
@property
def num_subtomogram_averages(self):
return self._shape_count(_sff.three_d_volume_type)

def as_json(self, args=None):
slist = list()
Expand All @@ -1757,6 +1758,8 @@ def from_json(cls, data, args=None):
obj.append(SFFCylinder.from_json(shape, args=args))
elif shape[u'shape'] == u'ellipsoid':
obj.append(SFFEllipsoid.from_json(shape, args=args))
elif shape[u'shape'] == u'subtomogram_average':
obj.append(SFFSubtomogramAverage.from_json(shape, args=args))
else:
raise SFFTypeError(u"cannot convert shape '{}'".format(data[u'shape']))
else:
Expand Down Expand Up @@ -1785,6 +1788,8 @@ def from_hff(cls, parent_group, name=u'shape_primitive_list', args=None):
obj.append(SFFCylinder.from_hff(subgroup, args=args))
elif _decode(subgroup[u'shape'][()], 'utf-8') == u'ellipsoid':
obj.append(SFFEllipsoid.from_hff(subgroup, args=args))
elif _decode(subgroup['shape'][()], 'utf-8') == 'subtomogram_average':
obj.append(SFFSubtomogramAverage.from_hff(subgroup, args=args))
else:
raise SFFTypeError(u"cannot convert shape '{}'".format(subgroup[u'shape'][()]))
else:
Expand Down
6 changes: 3 additions & 3 deletions sfftkrw/unittests/test_adapter_v0_7_0_dev0.py
Expand Up @@ -2882,7 +2882,7 @@ def test_create_from_gds_type(self):
s = adapter.SFFSegment.from_gds_type(_s)
self.assertRegex(
_str(s),
r"""SFFSegment\(id=None, parentID=\d+, biologicalAnnotation=None, colour=None, """ \
r"""SFFSegment\(id=None, parentID=\d+, biologicalAnnotation=None, colour=None, """
r"""threeDVolume=None, meshList=SFFMeshList\(\[\]\), shapePrimitiveList=SFFShapePrimitiveList\(\[\]\)\)"""
)
# change ID
Expand All @@ -2892,7 +2892,7 @@ def test_create_from_gds_type(self):
self.assertEqual(s.id, _id)
self.assertRegex(
_str(s),
r"""SFFSegment\(id={}, parentID=\d+, biologicalAnnotation=None, colour=None, """ \
r"""SFFSegment\(id={}, parentID=\d+, biologicalAnnotation=None, colour=None, """
r"""threeDVolume=None, meshList=SFFMeshList\(\[\]\), shapePrimitiveList=SFFShapePrimitiveList\(\[\]\)\)""".format(
_id)
)
Expand All @@ -2904,7 +2904,7 @@ def test_create_from_gds_type(self):
self.assertEqual(s.parent_id, _parent_id)
self.assertRegex(
_str(s),
r"""SFFSegment\(id={}, parentID={}, biologicalAnnotation=None, colour=None, """ \
r"""SFFSegment\(id={}, parentID={}, biologicalAnnotation=None, colour=None, """
r"""threeDVolume=None, meshList=SFFMeshList\(\[\]\), shapePrimitiveList=SFFShapePrimitiveList\(\[\]\)\)""".format(
None,
_parent_id
Expand Down
46 changes: 38 additions & 8 deletions sfftkrw/unittests/test_adapter_v0_8_0_dev1.py
Expand Up @@ -3393,7 +3393,14 @@ def get_sff_shapes(counts=_random_integers(count=4, start=2, stop=10)):
z=_random_float(10),
)
]
return cones, cuboids, cylinders, ellipsoids
subtomogram_averages = [
adapter.SFFSubtomogramAverage(
lattice_id=_random_integer(),
value=_random_float(10),
transform_id=_random_integer(),
)
]
return cones, cuboids, cylinders, ellipsoids, subtomogram_averages

@staticmethod
def get_gds_shapes(counts=_random_integers(count=4, start=2, stop=10)):
Expand All @@ -3420,46 +3427,57 @@ def get_gds_shapes(counts=_random_integers(count=4, start=2, stop=10)):
z=_random_float(10),
)
]
return cones, cuboids, cylinders, ellipsoids
subtomogram_averages = [
emdb_sff.three_d_volume_type(
lattice_id=_random_integer(),
value=_random_float(10),
transform_id=_random_integer(),
)
]
return cones, cuboids, cylinders, ellipsoids, subtomogram_averages

def test_default(self):
"""Test default settings"""
S = adapter.SFFShapePrimitiveList()
cones, cuboids, cylinders, ellipsoids = TestSFFShapePrimitiveList.get_sff_shapes()
cones, cuboids, cylinders, ellipsoids, subtomogram_averages = TestSFFShapePrimitiveList.get_sff_shapes()
[S.append(c) for c in cones]
[S.append(c) for c in cuboids]
[S.append(c) for c in cylinders]
[S.append(c) for c in ellipsoids]
[S.append(c) for c in subtomogram_averages]
self.assertRegex(
_str(S),
r"""SFFShapePrimitiveList\(\[.*\]\)"""
)
total_shapes = len(cones) + len(cuboids) + len(cylinders) + len(ellipsoids)
total_shapes = len(cones) + len(cuboids) + len(cylinders) + len(ellipsoids) + len(subtomogram_averages)
self.assertEqual(len(S), total_shapes)
self.assertEqual(list(S.get_ids()), list(_xrange(total_shapes)))
s_id = random.choice(list(_xrange(total_shapes)))
s = S.get_by_id(s_id)
self.assertIsInstance(s, (adapter.SFFCone, adapter.SFFCuboid, adapter.SFFCylinder, adapter.SFFEllipsoid))
self.assertIsInstance(s, (
adapter.SFFCone, adapter.SFFCuboid, adapter.SFFCylinder, adapter.SFFEllipsoid, adapter.SFFSubtomogramAverage))

def test_create_from_gds_type(self):
"""Test that we can create from gds_type"""
_S = emdb_sff.shape_primitive_listType()
cones, cuboids, cylinders, ellipsoids = TestSFFShapePrimitiveList.get_gds_shapes()
cones, cuboids, cylinders, ellipsoids, subtomogram_averages = TestSFFShapePrimitiveList.get_gds_shapes()
[_S.add_shape_primitive(c) for c in cones]
[_S.add_shape_primitive(c) for c in cuboids]
[_S.add_shape_primitive(c) for c in cylinders]
[_S.add_shape_primitive(c) for c in ellipsoids]
[_S.add_shape_primitive(c) for c in subtomogram_averages]
S = adapter.SFFShapePrimitiveList.from_gds_type(_S)
self.assertRegex(
_str(S),
r"""SFFShapePrimitiveList\(\[.*\]\)"""
)
total_shapes = len(cones) + len(cuboids) + len(cylinders) + len(ellipsoids)
total_shapes = len(cones) + len(cuboids) + len(cylinders) + len(ellipsoids) + len(subtomogram_averages)
self.assertEqual(len(S), total_shapes)
self.assertEqual(list(S.get_ids()), list())
s_id = random.choice(list(_xrange(total_shapes)))
s = S[s_id]
self.assertIsInstance(s, (adapter.SFFCone, adapter.SFFCuboid, adapter.SFFCylinder, adapter.SFFEllipsoid))
self.assertIsInstance(s, (
adapter.SFFCone, adapter.SFFCuboid, adapter.SFFCylinder, adapter.SFFEllipsoid, adapter.SFFSubtomogramAverage))

def test_json(self):
"""Interconvert to JSON"""
Expand Down Expand Up @@ -3532,6 +3550,15 @@ def test_hff(self):
transform_id=transform_id,
)
) for _ in _xrange(no_ellipsoids)]
no_subtomogram_averages = _random_integer(start=2, stop=10)
transform_id = _random_integer()
[S.append(
adapter.SFFSubtomogramAverage(
lattice_id=_random_integer(),
value=_random_float(10),
transform_id=transform_id,
)
) for _ in _xrange(no_subtomogram_averages)]
with h5py.File(self.test_hdf5_fn, u'w') as h:
group = h.create_group(u'container')
group = S.as_hff(group)
Expand All @@ -3549,6 +3576,9 @@ def test_hff(self):
self.assertEqual(s.x, group[u'shape_primitive_list/{}/x'.format(i)][()])
self.assertEqual(s.y, group[u'shape_primitive_list/{}/y'.format(i)][()])
self.assertEqual(s.z, group[u'shape_primitive_list/{}/z'.format(i)][()])
elif isinstance(s, (adapter.SFFSubtomogramAverage,)):
self.assertEqual(s.lattice_id, group[f'shape_primitive_list/{i}/lattice_id'][()])
self.assertEqual(s.value, group[f'shape_primitive_list/{i}/value'][()])
self.assertEqual(s.transform_id, group[u'shape_primitive_list/{}/transform_id'.format(i)][()])
with h5py.File(self.test_hdf5_fn, u'r') as h:
S2 = adapter.SFFShapePrimitiveList.from_hff(h[u'container'])
Expand Down
15 changes: 7 additions & 8 deletions sfftkrw/unittests/test_base.py
Expand Up @@ -13,13 +13,13 @@
import numpy
from random_words import RandomWords, LoremIpsum

rw = RandomWords()
li = LoremIpsum()

from . import _random_integer, Py23FixTestCase, _random_float, _random_floats
from .. import EMDB_SFF_VERSION
from ..core import _xrange, _str
from ..schema import base # , emdb_sff
from ..schema import base

rw = RandomWords()
li = LoremIpsum()

# dynamically import the latest schema generateDS API
emdb_sff_name = 'sfftkrw.schema.v{schema_version}'.format(
Expand Down Expand Up @@ -65,7 +65,7 @@ class _SomeEntity(base.SFFType):
"""Empty entity"""

with self.assertRaisesRegex(ValueError, r'.*gds_type.*'):
_s = _SomeEntity()
_SomeEntity()

def test_create_from_gds_type(self):
"""Test creating an `SFFType` subclass object from a `gds_type' object"""
Expand All @@ -90,7 +90,7 @@ def test_create_from_gds_type_raises_error(self):
as the one provided"""
_r = emdb_sff.biological_annotationType()
with self.assertRaisesRegex(base.SFFTypeError, r".*is not object of type.*"):
r = adapter.SFFRGBA.from_gds_type(_r)
adapter.SFFRGBA.from_gds_type(_r)

def test_ref_attr(self):
"""Test the `gds_tag_name` attribute"""
Expand Down Expand Up @@ -413,7 +413,7 @@ class _Cone(_Shape):
ref = "cone"

with self.assertRaisesRegex(AttributeError, r".*superclass does not have an 'update_counter' classmethod"):
_cone = _Cone()
_Cone()

def test_errors(self):
"""Test that we get the right exceptions"""
Expand Down Expand Up @@ -646,7 +646,6 @@ def test_copy(self):
self.assertNotEqual(id(C), id(D))
# shapes
Sh = adapter.SFFShapePrimitiveList()
_no_shapes = 3
Sh.append(adapter.SFFCone())
Sh.append(adapter.SFFCuboid())
Sh.append(adapter.SFFCylinder())
Expand Down
8 changes: 4 additions & 4 deletions sfftkrw/unittests/test_core.py
Expand Up @@ -9,14 +9,14 @@

from random_words import RandomWords, LoremIpsum

rw = RandomWords()
li = LoremIpsum()

from . import TEST_DATA_PATH, _random_integer, Py23FixTestCase
from ..core import print_tools
from ..core import utils
from ..core.parser import parse_args, tool_list

rw = RandomWords()
li = LoremIpsum()

__author__ = "Paul K. Korir, PhD"
__email__ = "pkorir@ebi.ac.uk, paul.korir@gmail.com"
__date__ = "2017-05-15"
Expand Down Expand Up @@ -63,7 +63,7 @@ def test_print_date_default(self):
data = self.temp_file.readlines()[0]
_words = data.split(' ')
self.assertIn(_words[0], self._weekdays) # the first part is a date
self.assertEqual(_words[-1][-1], '\n') #  the last letter is a newline
self.assertEqual(_words[-1][-1], '\n') # the last letter is a newline

def test_print_date_non_basestring(self):
"""Test exception when print_string is not a basestring subclass"""
Expand Down

0 comments on commit 923c81c

Please sign in to comment.