From 74e332e2acc9fb537240cc5af216cddc5791c357 Mon Sep 17 00:00:00 2001 From: zrgt Date: Tue, 5 May 2026 15:24:18 +0200 Subject: [PATCH 1/3] fix: LocalFileIdentifiableStore.__len__ count only .json files --- sdk/basyx/aas/backend/local_file.py | 2 +- sdk/test/backend/test_local_file.py | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/sdk/basyx/aas/backend/local_file.py b/sdk/basyx/aas/backend/local_file.py index 4008497a..8b718884 100644 --- a/sdk/basyx/aas/backend/local_file.py +++ b/sdk/basyx/aas/backend/local_file.py @@ -150,7 +150,7 @@ def __len__(self) -> int: :return: The number of objects (determined from the number of documents) """ logger.debug("Fetching number of documents from database ...") - return len(os.listdir(self.directory_path)) + return sum(1 for f in os.listdir(self.directory_path) if f.endswith(".json")) def __iter__(self) -> Iterator[model.Identifiable]: """ diff --git a/sdk/test/backend/test_local_file.py b/sdk/test/backend/test_local_file.py index adcbfcc7..abc94b7c 100644 --- a/sdk/test/backend/test_local_file.py +++ b/sdk/test/backend/test_local_file.py @@ -107,6 +107,19 @@ def test_key_errors(self) -> None: self.assertEqual("'No AAS object with id https://example.org/Test_Submodel exists in " "local file database'", str(cm.exception)) + def test_len_ignores_non_json_files(self) -> None: + example_data = create_full_example() + for item in example_data: + self.identifiable_store.add(item) + self.assertEqual(5, len(self.identifiable_store)) + + # Stray files must not be counted + stray = os.path.join(store_path, ".DS_Store") + with open(stray, "w") as f: + f.write("stray") + self.assertEqual(5, len(self.identifiable_store)) + os.remove(stray) + def test_reload_discard(self) -> None: # Load example submodel example_submodel = create_example_submodel() From 8feebf0251b6cd3cf676ead3f8812636e689584a Mon Sep 17 00:00:00 2001 From: zrgt Date: Tue, 5 May 2026 15:29:31 +0200 Subject: [PATCH 2/3] fix: LocalFileIdentifiableStore.__iter__ filter non-.json files and use removesuffix --- sdk/basyx/aas/backend/local_file.py | 3 ++- sdk/test/backend/test_local_file.py | 13 +++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/sdk/basyx/aas/backend/local_file.py b/sdk/basyx/aas/backend/local_file.py index 4008497a..a254c432 100644 --- a/sdk/basyx/aas/backend/local_file.py +++ b/sdk/basyx/aas/backend/local_file.py @@ -161,7 +161,8 @@ def __iter__(self) -> Iterator[model.Identifiable]: """ logger.debug("Iterating over objects in database ...") for name in os.listdir(self.directory_path): - yield self.get_identifiable_by_hash(name.rstrip(".json")) + if name.endswith(".json"): + yield self.get_identifiable_by_hash(name.removesuffix(".json")) @staticmethod def _transform_id(identifier: model.Identifier) -> str: diff --git a/sdk/test/backend/test_local_file.py b/sdk/test/backend/test_local_file.py index adcbfcc7..6ba1d692 100644 --- a/sdk/test/backend/test_local_file.py +++ b/sdk/test/backend/test_local_file.py @@ -107,6 +107,19 @@ def test_key_errors(self) -> None: self.assertEqual("'No AAS object with id https://example.org/Test_Submodel exists in " "local file database'", str(cm.exception)) + def test_iter_ignores_non_json_files(self) -> None: + example_data = create_full_example() + for item in example_data: + self.identifiable_store.add(item) + + # Stray files must not crash the iterator or be yielded + stray = os.path.join(store_path, ".DS_Store") + with open(stray, "w") as f: + f.write("stray") + items = list(self.identifiable_store) + self.assertEqual(5, len(items)) + os.remove(stray) + def test_reload_discard(self) -> None: # Load example submodel example_submodel = create_example_submodel() From effc30c4e332e91c705d891df482652b554c1a17 Mon Sep 17 00:00:00 2001 From: zrgt Date: Thu, 7 May 2026 18:11:36 +0200 Subject: [PATCH 3/3] fix: case-insensitive .json filter in __len__, strengthen test Use f.lower().endswith(".json") to handle .JSON filenames. Rename test to test_add_and_len_consistent: verify each add() increments len() by 1, then verify stray files are not counted. Addresses review feedback on #507 --- sdk/basyx/aas/backend/local_file.py | 2 +- sdk/test/backend/test_local_file.py | 13 +++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/sdk/basyx/aas/backend/local_file.py b/sdk/basyx/aas/backend/local_file.py index 8b718884..dfb4bd25 100644 --- a/sdk/basyx/aas/backend/local_file.py +++ b/sdk/basyx/aas/backend/local_file.py @@ -150,7 +150,7 @@ def __len__(self) -> int: :return: The number of objects (determined from the number of documents) """ logger.debug("Fetching number of documents from database ...") - return sum(1 for f in os.listdir(self.directory_path) if f.endswith(".json")) + return sum(1 for f in os.listdir(self.directory_path) if f.lower().endswith(".json")) def __iter__(self) -> Iterator[model.Identifiable]: """ diff --git a/sdk/test/backend/test_local_file.py b/sdk/test/backend/test_local_file.py index abc94b7c..645fa90e 100644 --- a/sdk/test/backend/test_local_file.py +++ b/sdk/test/backend/test_local_file.py @@ -107,17 +107,18 @@ def test_key_errors(self) -> None: self.assertEqual("'No AAS object with id https://example.org/Test_Submodel exists in " "local file database'", str(cm.exception)) - def test_len_ignores_non_json_files(self) -> None: - example_data = create_full_example() - for item in example_data: + def test_add_and_len_consistent(self) -> None: + # Each add() must increment len() by exactly 1 + example_data = list(create_full_example()) + for i, item in enumerate(example_data): self.identifiable_store.add(item) - self.assertEqual(5, len(self.identifiable_store)) + self.assertEqual(i + 1, len(self.identifiable_store)) - # Stray files must not be counted + # Stray non-json file must not be counted stray = os.path.join(store_path, ".DS_Store") with open(stray, "w") as f: f.write("stray") - self.assertEqual(5, len(self.identifiable_store)) + self.assertEqual(len(example_data), len(self.identifiable_store)) os.remove(stray) def test_reload_discard(self) -> None: