From 3016cf650dd5c38aef098109f3e7a36858b876c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Tue, 26 Aug 2025 11:03:27 +0200 Subject: [PATCH] Geometry Nodes: implement file path callback for import nodes Add geometry file import nodes support to the for-each-path logic. This will make `bpy.data.file_path_map()` report the input files for OBJ, PLY, etc. import nodes (and any other node that has a string property of subtype `PROP_FILEPATH`). Currently this only supports static file paths, so where the file path is set as the input socket's default value. When the path is determined via any noodle, this is ignored and the default value is reported anyway. This is necessary for the new version of Blender Asset Tracer, which in turn is needed to resolve studio/flamenco#104423. Pull Request: https://projects.blender.org/blender/blender/pulls/144874 --- source/blender/blenkernel/intern/node.cc | 20 +++++++ .../blend_scene/geonodes_import_obj.blend | 3 + tests/python/CMakeLists.txt | 7 +++ tests/python/bl_geonode_file_reporting.py | 55 +++++++++++++++++++ 4 files changed, 85 insertions(+) create mode 100644 tests/files/io_tests/blend_scene/geonodes_import_obj.blend create mode 100644 tests/python/bl_geonode_file_reporting.py diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc index d9b37a7b517..e80789b7d0b 100644 --- a/source/blender/blenkernel/intern/node.cc +++ b/source/blender/blenkernel/intern/node.cc @@ -434,6 +434,26 @@ static void node_foreach_path(ID *id, BPathForeachPathData *bpath_data) } break; } + case NTREE_GEOMETRY: { + for (bNode *node : ntree->all_nodes()) { + for (bNodeSocket *socket : node->input_sockets()) { + /* Find file path input sockets. */ + if (socket->type != SOCK_STRING) { + continue; + } + bNodeSocketValueString *socket_value = static_cast( + socket->default_value); + if (socket_value->value[0] == '\0' || socket_value->subtype != PROP_FILEPATH) { + continue; + } + + /* Process the file path. */ + BKE_bpath_foreach_path_fixed_process( + bpath_data, socket_value->value, sizeof(socket_value->value)); + } + } + break; + } default: break; } diff --git a/tests/files/io_tests/blend_scene/geonodes_import_obj.blend b/tests/files/io_tests/blend_scene/geonodes_import_obj.blend new file mode 100644 index 00000000000..094cb72cfa2 --- /dev/null +++ b/tests/files/io_tests/blend_scene/geonodes_import_obj.blend @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a850ae13bc06f403c15fff8c9b04c70f5d1d77c49a6c1d1adcfeab89bbb99ca6 +size 95132 diff --git a/tests/python/CMakeLists.txt b/tests/python/CMakeLists.txt index fec4dc24f92..2ef6f469812 100644 --- a/tests/python/CMakeLists.txt +++ b/tests/python/CMakeLists.txt @@ -424,6 +424,13 @@ add_blender_test( --python ${CMAKE_CURRENT_LIST_DIR}/bl_geometry_attributes.py ) +add_blender_test( + geonode_file_reporting + --python ${CMAKE_CURRENT_LIST_DIR}/bl_geonode_file_reporting.py + -- + --testdir "${TEST_SRC_DIR}/io_tests" +) + # ------------------------------------------------------------------------------ # MODIFIERS TESTS # ------------------------------------------------------------------------------ diff --git a/tests/python/bl_geonode_file_reporting.py b/tests/python/bl_geonode_file_reporting.py new file mode 100644 index 00000000000..fa5545eeda4 --- /dev/null +++ b/tests/python/bl_geonode_file_reporting.py @@ -0,0 +1,55 @@ +# SPDX-FileCopyrightText: 2024 Blender Authors +# +# SPDX-License-Identifier: Apache-2.0 + +# blender -b -P tests/python/bl_geonode_file_reporting.py -- --verbose --testdir tests/files/io_tests +import unittest +from pathlib import Path + +import bpy + + +class TestFileImportNodes(unittest.TestCase): + """Test that the imported OBJ file is reported via bpy.data.file_path_map().""" + + testdir: Path + + @classmethod + def setUpClass(cls) -> None: + cls.testdir = args.testdir + + def test_obj_import_node(self): + blend_path = self.testdir / "blend_scene/geonodes_import_obj.blend" + + bpy.ops.wm.open_mainfile(filepath=str(blend_path)) + + node_tree = bpy.data.node_groups['Import OBJ'] + file_path_map: dict[bpy.types.ID, set[str]] = bpy.data.file_path_map() + + # Go through Path(...) to ensure platform-native slashes. + relative_path = f"//{Path('../obj/all_tris.obj')!s}" + + self.assertIn(node_tree, file_path_map) + self.assertEqual({relative_path}, file_path_map[node_tree], + "The path to the OBJ file should be reported, as relative path") + + +def main(): + global args + import argparse + import sys + + if '--' in sys.argv: + argv = [sys.argv[0]] + sys.argv[sys.argv.index('--') + 1:] + else: + argv = sys.argv + + parser = argparse.ArgumentParser() + parser.add_argument('--testdir', required=True, type=Path) + args, remaining = parser.parse_known_args(argv) + + unittest.main(argv=remaining, verbosity=0) + + +if __name__ == "__main__": + main()