diff --git a/emannotationschemas/__init__.py b/emannotationschemas/__init__.py index 82975d4..d27d345 100644 --- a/emannotationschemas/__init__.py +++ b/emannotationschemas/__init__.py @@ -4,6 +4,7 @@ from emannotationschemas.schemas.synapse import BuhmannSynapseSchema from emannotationschemas.schemas.synapse import BuhmannEcksteinSynapseSchema from emannotationschemas.schemas.synapse import NoCleftSynapse +from emannotationschemas.schemas.synapse import SynapseWithNeuron from emannotationschemas.schemas.bouton_shape import BoutonShape from emannotationschemas.schemas.presynaptic_bouton_type import PresynapticBoutonType from emannotationschemas.schemas.base import ReferenceAnnotation, ReferenceTagAnnotation @@ -102,6 +103,7 @@ "bound_tag_bool": BoundBoolAnnotation, "bound_tag_bool_valid": BoundBoolWithValid, "bound_tag_valid": BoundTagWithValid, + "synapse_with_neuron": SynapseWithNeuron, } def get_types(): diff --git a/emannotationschemas/schemas/synapse.py b/emannotationschemas/schemas/synapse.py index 47b2e77..377b1ac 100644 --- a/emannotationschemas/schemas/synapse.py +++ b/emannotationschemas/schemas/synapse.py @@ -88,3 +88,32 @@ class ValidSynapse(ReferenceAnnotation): required=True, description="Valid annotation for synapses", ) + +class SynapseWithNeuron(SynapseSchema): + pre_neuron_pt = mm.fields.Nested( + BoundSpatialPoint, + required=True, + description="a point of the sample voxel of the neuron where the presynaptic compartment of the synapse is located", + order=3, + ) + post_neuron_pt = mm.fields.Nested( + BoundSpatialPoint, + required=True, + description="a point of the sample voxel of the neuron where the postsynaptic compartment of the synapse is located", + order=4, + ) + + @mm.post_load + def check_root_id(self, data, **kwargs): + pre_neuron_id = data["pre_neuron_pt"].get("root_id", None) + post_neuron_id = data["post_neuron_pt"].get("root_id", None) + # when the root_id is present + # we should set the valid flag depending up on this rule + # when the root_id is not present + # (i.e. when posting new annotations with no root_id's in mind) + # then the valid flag should be not present + if pre_neuron_id is not None: + data["valid"] = False if pre_neuron_id == post_neuron_id else True + else: + data.pop("valid", None) + return data \ No newline at end of file diff --git a/requirements_service.txt b/requirements_service.txt index 6bf3334..cf65558 100644 --- a/requirements_service.txt +++ b/requirements_service.txt @@ -5,4 +5,5 @@ flask-admin==1.6.1 flask-restx==1.3.0 flask-accepts==0.18.4 Werkzeug <= 2.1.2 -pandas==2.0.3 \ No newline at end of file +pandas==2.0.3 +cryptography>=42.0.5 \ No newline at end of file diff --git a/tests/test_synapse_schema.py b/tests/test_synapse_schema.py index 6d9dab7..43691fe 100644 --- a/tests/test_synapse_schema.py +++ b/tests/test_synapse_schema.py @@ -9,6 +9,7 @@ NoCleftSynapse, PlasticSynapse, SynapseSchema, + SynapseWithNeuron, ) good_base_synapse = { @@ -80,6 +81,13 @@ "plasticity": 1, } +good_synapse_with_neuron = { + "pre_pt": {"position": [31, 31, 0]}, + "ctr_pt": {"position": [32, 32, 0]}, + "post_pt": {"position": [33, 33, 0]}, + "pre_neuron_pt": {"position": [34, 34, 0]}, + "post_neuron_pt": {"position": [35, 35, 0]}, +} # class PlasticSynapse(SynapseSchema): # plasticity = mm.fields.Int(required=True, # validate=mm.validate.OneOf([0, 1, 2, 3, 4]), @@ -203,3 +211,19 @@ def test_synapse_invalid(): schema = SynapseSchema() with pytest.raises(mm.ValidationError): result = schema.load(supervoxel_rootId_invalid_synapse) + +def test_synapse_with_neuron(): + schema = SynapseWithNeuron() + result = schema.load(good_synapse_with_neuron) + assert result["pre_pt"]["position"] == [31, 31, 0] + assert result["pre_neuron_pt"]["position"] == [34, 34, 0] + assert result["post_neuron_pt"]["position"] == [35, 35, 0] + + +def test_synapse_with_neuron_postgis(): + schema = SynapseWithNeuron(context={"postgis": True}) + result = schema.load(good_synapse_with_neuron) + d = flatten_dict(result) + assert d["pre_pt_position"] == "POINTZ(31 31 0)" + assert d["pre_neuron_pt_position"] == "POINTZ(34 34 0)" + assert d["post_neuron_pt_position"] == "POINTZ(35 35 0)" \ No newline at end of file