Skip to content

Commit

Permalink
Change struct_id and struct_name to optional (#795)
Browse files Browse the repository at this point in the history
* Removed Required from struct_id and struct_name attributes

* Fixed wrong update

* Add mutual exclusive function

* Add unit test

* Add relevant cases to unit test

* Update unit test with specific test functions

* Fix tests functions

* update to black 24

---------

Co-authored-by: Robin De Schepper <robin.deschepper93@gmail.com>
  • Loading branch information
filimarc and Helveg committed Feb 13, 2024
1 parent b04d5e4 commit 3ff5268
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 3 deletions.
2 changes: 2 additions & 0 deletions bsb/config/_make.py
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,8 @@ def __post_new__(self, _parent=None, _key=None, **kwargs):
for attr in attrs.values():
name = attr.attr_name
if attr.key and attr.attr_name not in kwargs:
# If this is a "key" attribute, and the user didn't overwrite it,
# set the attribute to the config key
setattr(self, name, self._config_key)
attr.flag_pristine(self)
elif (value := values[name]) is None:
Expand Down
5 changes: 3 additions & 2 deletions bsb/topology/partition.py
Original file line number Diff line number Diff line change
Expand Up @@ -492,13 +492,14 @@ class AllenStructure(NrrdVoxels, classmap_entry="allen"):
"""

struct_id: int = config.attr(
type=int, required=types.mut_excl("struct_id", "struct_name", required=True)
type=int, required=types.mut_excl("struct_id", "struct_name", required=False)
)
"""Id of the region to filter within the annotation volume according to the AMBRH.
If struct_id is set, then struct_name should not be set."""
struct_name: str = config.attr(
type=types.str(strip=True, lower=True),
required=types.mut_excl("struct_id", "struct_name", required=True),
required=types.mut_excl("struct_id", "struct_name", required=False),
key=True,
)
"""Name or acronym of the region to filter within the annotation volume according to the AMBRH.
If struct_name is set, then struct_id should not be set."""
Expand Down
48 changes: 48 additions & 0 deletions tests/test_configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -1203,6 +1203,54 @@ class Test:
d = Test(c="test.nrrd", _parent=TestRoot())
self.assertRaises(FileNotFoundError, d.c.load_object)

def test_mutexcl_required(self):
"""test the types.mut_excl function"""

@config.node
class TestClass:
a = config.attr(required=types.mut_excl("a", "b"))
b = config.attr(required=types.mut_excl("a", "b"))

TestClass(a="1")
TestClass(b="6")
with self.assertRaises(RequirementError):
TestClass(a="5", b="6")
with self.assertRaises(RequirementError):
TestClass()

def test_mutexcl_optional(self):
"""test the types.mut_excl function with optional values"""

@config.node
class TestClass:
a = config.attr(required=types.mut_excl("a", "b", required=False))
b = config.attr(required=types.mut_excl("a", "b", required=False))

TestClass()

def test_mutexcl_maxval(self):
"""test the max variable"""

@config.node
class TestClass:
a = config.attr(required=types.mut_excl("a", "b", max=2))
b = config.attr(required=types.mut_excl("a", "b", max=2))

TestClass(a="1", b="6")

def test_mutexcl_threecase(self):
"""test the types.mut_excl function with three arguments"""

@config.node
class TestClass:
a = config.attr(required=types.mut_excl("a", "b", "c", max=2))
b = config.attr(required=types.mut_excl("a", "b", "c", max=2))
c = config.attr(required=types.mut_excl("a", "b", "c", max=2))

TestClass(a="1", c="3")
with self.assertRaises(RequirementError):
TestClass(a="1", b="6", c="3")


@config.dynamic(
type=types.in_classmap(),
Expand Down
10 changes: 9 additions & 1 deletion tests/test_topology.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,6 @@ def test_partition_chunking(self):
class TestAllenVoxels(unittest.TestCase):
def test_val(self):
cfg = Configuration.default(
regions=dict(br=dict(children=["a"])),
partitions=dict(a=dict(type="allen", struct_name="VAL")),
)
part = cfg.partitions.a
Expand All @@ -91,6 +90,15 @@ def test_val(self):
with self.assertRaises(LayoutError, msg=not_impl):
transform(0)

def test_optional_struct_key(self):
"""Test only if AllenStructure correctly assign default struct_name, the actual function is tested in test_val()"""
cfg = Configuration.default(
partitions=dict(val=dict(type="allen")),
)
part = cfg.partitions.val
vs = part.voxelset
self.assertEqual(52314, len(vs), "VAL is that many voxels")

def test_mask_nrrd(self):
cfg = Configuration.default(
regions=dict(br=dict(children=["a"])),
Expand Down

0 comments on commit 3ff5268

Please sign in to comment.