From 9d2fcf7c53d40356089e2dae5d37324e6e818bab Mon Sep 17 00:00:00 2001 From: Zakir Jiwani <108548454+JiwaniZakir@users.noreply.github.com> Date: Thu, 2 Apr 2026 09:49:42 +0000 Subject: [PATCH] Fix encode_node mutating its Node argument's labels list Co-Authored-By: Claude Sonnet 4.6 --- api/entities/entity_encoder.py | 5 ++-- tests/test_entity_encoder.py | 45 ++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 2 deletions(-) create mode 100644 tests/test_entity_encoder.py diff --git a/api/entities/entity_encoder.py b/api/entities/entity_encoder.py index dfc9ed2f..13d722dd 100644 --- a/api/entities/entity_encoder.py +++ b/api/entities/entity_encoder.py @@ -1,8 +1,9 @@ from falkordb import Node, Edge, Path def encode_node(n: Node) -> dict: - n.labels.remove('Searchable') - return vars(n) + result = vars(n).copy() + result['labels'] = [l for l in n.labels if l != 'Searchable'] + return result def encode_edge(e: Edge) -> dict: return vars(e) diff --git a/tests/test_entity_encoder.py b/tests/test_entity_encoder.py new file mode 100644 index 00000000..643df163 --- /dev/null +++ b/tests/test_entity_encoder.py @@ -0,0 +1,45 @@ +import importlib.util +import sys +import os +import pytest +from falkordb import Node + +# Import entity_encoder directly without triggering api/__init__.py +_spec = importlib.util.spec_from_file_location( + "entity_encoder", + os.path.join(os.path.dirname(__file__), "..", "api", "entities", "entity_encoder.py"), +) +_mod = importlib.util.module_from_spec(_spec) +_spec.loader.exec_module(_mod) +encode_node = _mod.encode_node + + +def make_node(labels, props=None): + return Node(node_id=1, alias="n", labels=labels, properties=props or {}) + + +def test_encode_node_removes_searchable(): + n = make_node(['File', 'Searchable']) + result = encode_node(n) + assert 'Searchable' not in result['labels'] + assert 'File' in result['labels'] + + +def test_encode_node_does_not_mutate_original(): + n = make_node(['File', 'Searchable']) + encode_node(n) + assert 'Searchable' in n.labels + + +def test_encode_node_twice_does_not_raise(): + n = make_node(['File', 'Searchable']) + encode_node(n) + # Second call must not raise ValueError + result = encode_node(n) + assert 'Searchable' not in result['labels'] + + +def test_encode_node_without_searchable(): + n = make_node(['Class']) + result = encode_node(n) + assert result['labels'] == ['Class']