From 55af6cc497f9d7cf64de0eedc796d8b13bbf9c90 Mon Sep 17 00:00:00 2001 From: MaxNumerique Date: Wed, 25 Feb 2026 14:31:21 +0100 Subject: [PATCH 1/6] fix(FileSystem): using native instead of input_file & additional_files --- .../routes/blueprint_routes.py | 29 +++++++------------ src/opengeodeweb_back/utils_functions.py | 19 +++++------- tests/test_routes.py | 6 ---- tests/test_utils_functions.py | 18 ++---------- 4 files changed, 20 insertions(+), 52 deletions(-) diff --git a/src/opengeodeweb_back/routes/blueprint_routes.py b/src/opengeodeweb_back/routes/blueprint_routes.py index 156f690b..5bd89167 100644 --- a/src/opengeodeweb_back/routes/blueprint_routes.py +++ b/src/opengeodeweb_back/routes/blueprint_routes.py @@ -425,7 +425,7 @@ def export_project() -> flask.Response: export_vease_path = os.path.join(project_folder, filename) with get_session() as session: - rows = session.query(Data.id, Data.input_file, Data.additional_files).all() + rows = session.query(Data.id, Data.native_file).all() with zipfile.ZipFile( export_vease_path, "w", compression=zipfile.ZIP_DEFLATED @@ -434,21 +434,12 @@ def export_project() -> flask.Response: if os.path.isfile(database_root_path): zip_file.write(database_root_path, "project.db") - for data_id, input_file, additional_files in rows: + for data_id, native_file in rows: base_dir = os.path.join(project_folder, data_id) - input_path = os.path.join(base_dir, str(input_file)) - if os.path.isfile(input_path): - zip_file.write(input_path, os.path.join(data_id, str(input_file))) - - for relative_path in ( - additional_files if isinstance(additional_files, list) else [] - ): - additional_path = os.path.join(base_dir, relative_path) - if os.path.isfile(additional_path): - zip_file.write( - additional_path, os.path.join(data_id, relative_path) - ) + native_path = os.path.join(base_dir, str(native_file)) + if os.path.isfile(native_path): + zip_file.write(native_path, os.path.join(data_id, str(native_file))) zip_file.writestr("snapshot.json", flask.json.dumps(params.snapshot)) @@ -523,17 +514,17 @@ def import_project() -> flask.Response: if os.path.isfile(vpath): continue - input_file = str(data.input_file or "") - if not input_file: + native_file = str(data.native_file or "") + if not native_file: continue - input_full = geode_functions.data_file_path(data.id, input_file) - if not os.path.isfile(input_full): + native_full = geode_functions.data_file_path(data.id, native_file) + if not os.path.isfile(native_full): continue geode_object = geode_functions.geode_object_from_string( data.geode_object - ).load(input_full) + ).load(native_full) utils_functions.save_all_viewables_and_return_info( geode_object, data, data_path ) diff --git a/src/opengeodeweb_back/utils_functions.py b/src/opengeodeweb_back/utils_functions.py index 6341911f..5f2231e8 100644 --- a/src/opengeodeweb_back/utils_functions.py +++ b/src/opengeodeweb_back/utils_functions.py @@ -188,6 +188,7 @@ def save_all_viewables_and_return_info( geode_object: GeodeObject, data: Data, data_path: str, + native_filename: str | None = None, ) -> dict[str, str | list[str]]: with ThreadPoolExecutor() as executor: native_files, viewable_path, light_path = executor.map( @@ -196,7 +197,10 @@ def save_all_viewables_and_return_info( ( geode_object.save, os.path.join( - data_path, "native." + geode_object.native_extension() + data_path, + native_filename + if native_filename is not None + else "native." + geode_object.native_extension(), ), ), (geode_object.save_viewable, os.path.join(data_path, "viewable")), @@ -212,9 +216,6 @@ def save_all_viewables_and_return_info( data.viewable_file = os.path.basename(viewable_path) data.light_viewable_file = os.path.basename(light_path) - if not data.input_file: - data.input_file = data.native_file - assert data.native_file is not None assert data.viewable_file is not None assert data.light_viewable_file is not None @@ -226,8 +227,6 @@ def save_all_viewables_and_return_info( "viewer_type": data.viewer_object, "binary_light_viewable": binary_light_viewable.decode("utf-8"), "geode_object_type": data.geode_object, - "input_file": data.input_file or "", - "additional_files": data.additional_files or [], } @@ -251,15 +250,13 @@ def generate_native_viewable_and_light_viewable_from_file( geode_object=geode_object_type, viewer_object=generic_geode_object.viewer_type(), viewer_elements_type=generic_geode_object.viewer_elements_type(), - input_file=input_file, ) data_path = create_data_folder_from_id(data.id) full_input_filename = geode_functions.upload_file_path(input_file) - copied_full_path = os.path.join( - data_path, werkzeug.utils.secure_filename(input_file) - ) + secure_input_file = werkzeug.utils.secure_filename(input_file) + copied_full_path = os.path.join(data_path, secure_input_file) shutil.copy2(full_input_filename, copied_full_path) additional_files_copied: list[str] = [] @@ -278,9 +275,9 @@ def generate_native_viewable_and_light_viewable_from_file( additional_files_copied.append(additional_file.filename) geode_object = generic_geode_object.load(copied_full_path) - data.additional_files = additional_files_copied return save_all_viewables_and_return_info( geode_object, data, data_path, + native_filename=secure_input_file, ) diff --git a/tests/test_routes.py b/tests/test_routes.py index 48656774..215e16d7 100644 --- a/tests/test_routes.py +++ b/tests/test_routes.py @@ -205,7 +205,6 @@ def test_texture_coordinates(client: FlaskClient, test_id: str) -> None: geode_object=GeodePolygonalSurface3D.geode_object_type(), viewer_object=GeodePolygonalSurface3D.viewer_type(), viewer_elements_type=GeodePolygonalSurface3D.viewer_elements_type(), - input_file=file, ) data.native_file = file session = get_session() @@ -234,7 +233,6 @@ def test_vertex_attribute_names(client: FlaskClient, test_id: str) -> None: geode_object=GeodePolygonalSurface3D.geode_object_type(), viewer_object=GeodePolygonalSurface3D.viewer_type(), viewer_elements_type=GeodePolygonalSurface3D.viewer_elements_type(), - input_file=file, ) data.native_file = file session = get_session() @@ -263,7 +261,6 @@ def test_cell_attribute_names(client: FlaskClient, test_id: str) -> None: geode_object=GeodeRegularGrid2D.geode_object_type(), viewer_object=GeodeRegularGrid2D.viewer_type(), viewer_elements_type=GeodeRegularGrid2D.viewer_elements_type(), - input_file=file, ) data.native_file = file session = get_session() @@ -292,7 +289,6 @@ def test_polygon_attribute_names(client: FlaskClient, test_id: str) -> None: geode_object=GeodePolygonalSurface3D.geode_object_type(), viewer_object=GeodePolygonalSurface3D.viewer_type(), viewer_elements_type=GeodePolygonalSurface3D.viewer_elements_type(), - input_file=file, ) data.native_file = file session = get_session() @@ -321,7 +317,6 @@ def test_polyhedron_attribute_names(client: FlaskClient, test_id: str) -> None: geode_object=GeodePolyhedralSolid3D.geode_object_type(), viewer_object=GeodePolyhedralSolid3D.viewer_type(), viewer_elements_type=GeodePolyhedralSolid3D.viewer_elements_type(), - input_file=file, ) data.native_file = file session = get_session() @@ -354,7 +349,6 @@ def test_edge_attribute_names(client: FlaskClient, test_id: str) -> None: geode_object=GeodeEdgedCurve3D.geode_object_type(), viewer_object=GeodeEdgedCurve3D.viewer_type(), viewer_elements_type=GeodeEdgedCurve3D.viewer_elements_type(), - input_file=file, ) data.native_file = file session = get_session() diff --git a/tests/test_utils_functions.py b/tests/test_utils_functions.py index 792f3367..40318c10 100644 --- a/tests/test_utils_functions.py +++ b/tests/test_utils_functions.py @@ -105,15 +105,11 @@ def test_save_all_viewables_and_return_info(client: FlaskClient) -> None: assert os.path.exists(expected_db_path) geode_object = GeodeBRep.load(os.path.join(data_dir, "test.og_brep")) - input_file = "test.og_brep" - additional_files = ["additional_file.txt"] data_entry = Data.create( geode_object=geode_object.geode_object_type(), viewer_object=geode_object.viewer_type(), viewer_elements_type=geode_object.viewer_elements_type(), - input_file=input_file, - additional_files=additional_files, ) data_path = utils_functions.create_data_folder_from_id(data_entry.id) @@ -124,7 +120,7 @@ def test_save_all_viewables_and_return_info(client: FlaskClient) -> None: assert isinstance(result, dict) native_file = result["native_file"] assert isinstance(native_file, str) - assert native_file.startswith("native.") + assert native_file == "native.og_brep" viewable_file = result["viewable_file"] assert isinstance(viewable_file, str) assert viewable_file.endswith(".vtm") @@ -134,15 +130,12 @@ def test_save_all_viewables_and_return_info(client: FlaskClient) -> None: assert isinstance(result["viewer_type"], str) assert isinstance(result["binary_light_viewable"], str) assert result["geode_object_type"] == geode_object.geode_object_type() - assert result["input_file"] == input_file db_entry = Data.get(result["id"]) assert db_entry is not None assert db_entry.native_file == result["native_file"] assert db_entry.viewable_file == result["viewable_file"] assert db_entry.geode_object == geode_object.geode_object_type() - assert db_entry.input_file == input_file - assert db_entry.additional_files == additional_files expected_data_path = os.path.join(app.config["DATA_FOLDER_PATH"], result["id"]) assert os.path.exists(expected_data_path) @@ -152,13 +145,10 @@ def test_save_all_viewables_commits_to_db(client: FlaskClient) -> None: app = client.application with app.app_context(): geode_object = GeodeBRep.load(os.path.join(data_dir, "test.og_brep")) - input_file = "test.og_brep" data_entry = Data.create( geode_object=geode_object.geode_object_type(), viewer_object=geode_object.viewer_type(), viewer_elements_type=geode_object.viewer_elements_type(), - input_file=input_file, - additional_files=[], ) data_path = utils_functions.create_data_folder_from_id(data_entry.id) @@ -196,11 +186,8 @@ def test_generate_native_viewable_and_light_viewable_from_object( assert isinstance(result["binary_light_viewable"], str) assert result["binary_light_viewable"].startswith('') - assert result["input_file"] == result["native_file"] - data = Data.get(result["id"]) assert data is not None - assert data.input_file == data.native_file assert data.light_viewable_file is not None assert data.light_viewable_file.endswith(".vtp") @@ -221,14 +208,13 @@ def test_generate_native_viewable_and_light_viewable_from_file( assert isinstance(result, dict) assert isinstance(result["native_file"], str) - assert result["native_file"].startswith("native.") + assert result["native_file"] == "test.og_brep" assert isinstance(result["viewable_file"], str) assert result["viewable_file"].endswith(".vtm") assert isinstance(result["id"], str) assert re.match(r"[0-9a-f]{32}", result["id"]) assert isinstance(result["viewer_type"], str) assert isinstance(result["binary_light_viewable"], str) - assert isinstance(result["input_file"], str) def test_send_file_multiple_returns_zip(client: FlaskClient, tmp_path: Path) -> None: From 69cc920248ba8b4ddf23fe88c73958352a77f294 Mon Sep 17 00:00:00 2001 From: MaxNumerique <144453705+MaxNumerique@users.noreply.github.com> Date: Wed, 25 Feb 2026 13:40:23 +0000 Subject: [PATCH 2/6] Apply prepare changes --- requirements.txt | 1 - src/opengeodeweb_back/utils_functions.py | 8 +++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/requirements.txt b/requirements.txt index 15e1ad30..158e1f59 100644 --- a/requirements.txt +++ b/requirements.txt @@ -60,4 +60,3 @@ werkzeug==3.1.2 # flask # flask-cors -opengeodeweb-microservice==1.*,>=1.0.14 diff --git a/src/opengeodeweb_back/utils_functions.py b/src/opengeodeweb_back/utils_functions.py index 5f2231e8..a14636eb 100644 --- a/src/opengeodeweb_back/utils_functions.py +++ b/src/opengeodeweb_back/utils_functions.py @@ -198,9 +198,11 @@ def save_all_viewables_and_return_info( geode_object.save, os.path.join( data_path, - native_filename - if native_filename is not None - else "native." + geode_object.native_extension(), + ( + native_filename + if native_filename is not None + else "native." + geode_object.native_extension() + ), ), ), (geode_object.save_viewable, os.path.join(data_path, "viewable")), From d0e7ae432e2905a487a0321b0a7097042806c0e9 Mon Sep 17 00:00:00 2001 From: MaxNumerique Date: Wed, 25 Feb 2026 14:52:27 +0100 Subject: [PATCH 3/6] update test with new persistance workflow --- tests/test_models_routes.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/tests/test_models_routes.py b/tests/test_models_routes.py index d6fbf7f9..c80666f0 100644 --- a/tests/test_models_routes.py +++ b/tests/test_models_routes.py @@ -62,18 +62,14 @@ def test_export_project_route(client: FlaskClient, tmp_path: Path) -> None: geode_object="BRep", viewer_object="BRep", viewer_elements_type="default", - input_file="test_native.txt", native_file="test_native.txt", - additional_files=[], ) data2 = Data( id="test_data_2", geode_object="Section", viewer_object="Section", viewer_elements_type="default", - input_file="test_input.txt", native_file="test_native2.txt", - additional_files=[], ) session.add(data1) session.add(data2) @@ -86,8 +82,8 @@ def test_export_project_route(client: FlaskClient, tmp_path: Path) -> None: data2_dir = os.path.join(project_folder, "test_data_2") os.makedirs(data2_dir, exist_ok=True) - with open(os.path.join(data2_dir, "test_input.txt"), "w") as f: - f.write("input file content") + with open(os.path.join(data2_dir, "test_native2.txt"), "w") as f: + f.write("native file content") response = client.post(route, json={"snapshot": snapshot, "filename": filename}) assert response.status_code == 200 @@ -105,7 +101,7 @@ def test_export_project_route(client: FlaskClient, tmp_path: Path) -> None: assert parsed == snapshot assert "project.db" in names assert "test_data_1/test_native.txt" in names - assert "test_data_2/test_input.txt" in names + assert "test_data_2/test_native2.txt" in names response.close() @@ -132,7 +128,7 @@ def test_import_project_route(client: FlaskClient, tmp_path: Path) -> None: conn = sqlite3.connect(str(temp_db)) conn.execute( "CREATE TABLE datas (id TEXT PRIMARY KEY, geode_object TEXT, viewer_object TEXT, viewer_elements_type TEXT, native_file TEXT, " - "viewable_file TEXT, light_viewable_file TEXT, input_file TEXT, additional_files TEXT)" + "viewable_file TEXT, light_viewable_file TEXT)" ) conn.commit() conn.close() From 681e1693f1f9fa8aed79dbfd581bacef9d306091 Mon Sep 17 00:00:00 2001 From: MaxNumerique Date: Wed, 25 Feb 2026 15:04:23 +0100 Subject: [PATCH 4/6] native. instead of filename. for native file --- src/opengeodeweb_back/utils_functions.py | 19 ++++++------------- tests/test_models_routes.py | 12 ++++++------ tests/test_utils_functions.py | 2 +- 3 files changed, 13 insertions(+), 20 deletions(-) diff --git a/src/opengeodeweb_back/utils_functions.py b/src/opengeodeweb_back/utils_functions.py index a14636eb..eb67b335 100644 --- a/src/opengeodeweb_back/utils_functions.py +++ b/src/opengeodeweb_back/utils_functions.py @@ -188,7 +188,6 @@ def save_all_viewables_and_return_info( geode_object: GeodeObject, data: Data, data_path: str, - native_filename: str | None = None, ) -> dict[str, str | list[str]]: with ThreadPoolExecutor() as executor: native_files, viewable_path, light_path = executor.map( @@ -197,12 +196,7 @@ def save_all_viewables_and_return_info( ( geode_object.save, os.path.join( - data_path, - ( - native_filename - if native_filename is not None - else "native." + geode_object.native_extension() - ), + data_path, "native." + geode_object.native_extension() ), ), (geode_object.save_viewable, os.path.join(data_path, "viewable")), @@ -276,10 +270,9 @@ def generate_native_viewable_and_light_viewable_from_file( shutil.copy2(source_path, dest_path) additional_files_copied.append(additional_file.filename) + data.name = input_file geode_object = generic_geode_object.load(copied_full_path) - return save_all_viewables_and_return_info( - geode_object, - data, - data_path, - native_filename=secure_input_file, - ) + result = save_all_viewables_and_return_info(geode_object, data, data_path) + if os.path.exists(copied_full_path): + os.remove(copied_full_path) + return result diff --git a/tests/test_models_routes.py b/tests/test_models_routes.py index c80666f0..85152dbf 100644 --- a/tests/test_models_routes.py +++ b/tests/test_models_routes.py @@ -62,14 +62,14 @@ def test_export_project_route(client: FlaskClient, tmp_path: Path) -> None: geode_object="BRep", viewer_object="BRep", viewer_elements_type="default", - native_file="test_native.txt", + native_file="native.txt", ) data2 = Data( id="test_data_2", geode_object="Section", viewer_object="Section", viewer_elements_type="default", - native_file="test_native2.txt", + native_file="native.txt", ) session.add(data1) session.add(data2) @@ -77,12 +77,12 @@ def test_export_project_route(client: FlaskClient, tmp_path: Path) -> None: data1_dir = os.path.join(project_folder, "test_data_1") os.makedirs(data1_dir, exist_ok=True) - with open(os.path.join(data1_dir, "test_native.txt"), "w") as f: + with open(os.path.join(data1_dir, "native.txt"), "w") as f: f.write("native file content") data2_dir = os.path.join(project_folder, "test_data_2") os.makedirs(data2_dir, exist_ok=True) - with open(os.path.join(data2_dir, "test_native2.txt"), "w") as f: + with open(os.path.join(data2_dir, "native.txt"), "w") as f: f.write("native file content") response = client.post(route, json={"snapshot": snapshot, "filename": filename}) @@ -100,8 +100,8 @@ def test_export_project_route(client: FlaskClient, tmp_path: Path) -> None: parsed = json.loads(zip_file.read("snapshot.json").decode("utf-8")) assert parsed == snapshot assert "project.db" in names - assert "test_data_1/test_native.txt" in names - assert "test_data_2/test_native2.txt" in names + assert "test_data_1/native.txt" in names + assert "test_data_2/native.txt" in names response.close() diff --git a/tests/test_utils_functions.py b/tests/test_utils_functions.py index 40318c10..78b12659 100644 --- a/tests/test_utils_functions.py +++ b/tests/test_utils_functions.py @@ -208,7 +208,7 @@ def test_generate_native_viewable_and_light_viewable_from_file( assert isinstance(result, dict) assert isinstance(result["native_file"], str) - assert result["native_file"] == "test.og_brep" + assert result["native_file"] == "native.og_brep" assert isinstance(result["viewable_file"], str) assert result["viewable_file"].endswith(".vtm") assert isinstance(result["id"], str) From 37eeeeeca01f7d380daf2d3f041d6e05412b0265 Mon Sep 17 00:00:00 2001 From: MaxNumerique Date: Wed, 25 Feb 2026 15:17:30 +0100 Subject: [PATCH 5/6] rm name --- src/opengeodeweb_back/utils_functions.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/opengeodeweb_back/utils_functions.py b/src/opengeodeweb_back/utils_functions.py index eb67b335..d6d7e86f 100644 --- a/src/opengeodeweb_back/utils_functions.py +++ b/src/opengeodeweb_back/utils_functions.py @@ -270,7 +270,6 @@ def generate_native_viewable_and_light_viewable_from_file( shutil.copy2(source_path, dest_path) additional_files_copied.append(additional_file.filename) - data.name = input_file geode_object = generic_geode_object.load(copied_full_path) result = save_all_viewables_and_return_info(geode_object, data, data_path) if os.path.exists(copied_full_path): From 120d2bea2b2901b19e9d77ab11796924cdb4e2f5 Mon Sep 17 00:00:00 2001 From: MaxNumerique Date: Wed, 25 Feb 2026 15:46:10 +0100 Subject: [PATCH 6/6] rm copied path, additional_file, .. --- src/opengeodeweb_back/utils_functions.py | 29 +++--------------------- 1 file changed, 3 insertions(+), 26 deletions(-) diff --git a/src/opengeodeweb_back/utils_functions.py b/src/opengeodeweb_back/utils_functions.py index d6d7e86f..89bc0a2c 100644 --- a/src/opengeodeweb_back/utils_functions.py +++ b/src/opengeodeweb_back/utils_functions.py @@ -247,31 +247,8 @@ def generate_native_viewable_and_light_viewable_from_file( viewer_object=generic_geode_object.viewer_type(), viewer_elements_type=generic_geode_object.viewer_elements_type(), ) - data_path = create_data_folder_from_id(data.id) - full_input_filename = geode_functions.upload_file_path(input_file) - secure_input_file = werkzeug.utils.secure_filename(input_file) - copied_full_path = os.path.join(data_path, secure_input_file) - shutil.copy2(full_input_filename, copied_full_path) - - additional_files_copied: list[str] = [] - additional = generic_geode_object.additional_files(full_input_filename) - for additional_file in additional.mandatory_files + additional.optional_files: - if additional_file.is_missing: - continue - source_path = os.path.join( - os.path.dirname(full_input_filename), additional_file.filename - ) - if not os.path.exists(source_path): - continue - dest_path = os.path.join(data_path, additional_file.filename) - os.makedirs(os.path.dirname(dest_path), exist_ok=True) - shutil.copy2(source_path, dest_path) - additional_files_copied.append(additional_file.filename) - - geode_object = generic_geode_object.load(copied_full_path) - result = save_all_viewables_and_return_info(geode_object, data, data_path) - if os.path.exists(copied_full_path): - os.remove(copied_full_path) - return result + geode_object = generic_geode_object.load(full_input_filename) + geode_object.builder().set_name(input_file) + return save_all_viewables_and_return_info(geode_object, data, data_path)