From 7982564eac59f47047e2f68876180e64010ea37e Mon Sep 17 00:00:00 2001 From: whitews Date: Sun, 27 Oct 2024 20:39:53 -0400 Subject: [PATCH] better error for invalid gate names '.' & '..' (closes #220) --- src/flowkit/_models/gating_strategy.py | 12 +++++++++++- tests/workspace_tests.py | 14 +++++++++++++- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/flowkit/_models/gating_strategy.py b/src/flowkit/_models/gating_strategy.py index 29812115..124e0d1c 100644 --- a/src/flowkit/_models/gating_strategy.py +++ b/src/flowkit/_models/gating_strategy.py @@ -71,11 +71,21 @@ def add_gate(self, gate, gate_path, sample_id=None): if not isinstance(gate_path, tuple): raise TypeError("gate_path must be a tuple not %s" % str(type(gate_path))) + # make string representation of parent path, used for anytree Resolver later + parent_abs_gate_path = "/" + "/".join(gate_path) + + # Verify gate name is not "." or ".." as these are incompatible w/ the + # current version of anytree (see open issue https://github.com/c0fec0de/anytree/issues/269) + if gate.gate_name in ['.', '..']: + raise GateTreeError( + "Gate name '%s' is incompatible with FlowKit. Gate was found in path: %s" % + (gate.gate_name, parent_abs_gate_path) + ) + # We need the parent gate (via its node) for 2 reasons: # 1) To verify the parent exists when creating a new node # 2) Verify the parent is NOT a QuadrantGate, as only # Quadrants of a QuadrantGate can be a parent. - parent_abs_gate_path = "/" + "/".join(gate_path) try: parent_node = self.resolver.get(self._gate_tree, parent_abs_gate_path) except anytree.ResolverError: diff --git a/tests/workspace_tests.py b/tests/workspace_tests.py index 7d6b52fb..c1e26db1 100644 --- a/tests/workspace_tests.py +++ b/tests/workspace_tests.py @@ -11,7 +11,7 @@ # noinspection PyProtectedMember from flowkit._models.transforms._base_transform import Transform from flowkit._models.gating_results import GatingResults -from flowkit.exceptions import GateReferenceError +from flowkit.exceptions import GateReferenceError, GateTreeError from tests.test_config import test_samples_8c_full_set @@ -426,6 +426,18 @@ def test_parse_wsp_with_ellipse(self): self.assertIsInstance(gate_indices, np.ndarray) self.assertEqual(np.sum(gate_indices), 7023) + def test_parse_wsp_with_invalid_gate_name(self): + wsp_path = "data/8_color_data_set/8_color_ICS_dot_gate_name.wsp" + + self.assertRaisesRegex( + GateTreeError, + r"Gate name '\.' is incompatible with FlowKit\. " + r"Gate was found in path: \/root\/Time\/Singlets\/aAmine-\/CD3\+\/CD4\+", + Workspace, + wsp_path, + ignore_missing_files=True + ) + def test_parse_wsp_with_boolean_gates(self): wsp_path = "data/8_color_data_set/8_color_ICS_boolean_gate_testing.wsp" fcs_path = "data/8_color_data_set/fcs_files/101_DEN084Y5_15_E01_008_clean.fcs"