From c2027ffa0a574e55d05e5b6549010d07075933fc Mon Sep 17 00:00:00 2001 From: MaxNumerique Date: Fri, 27 Feb 2026 13:58:40 +0100 Subject: [PATCH 1/5] feat(geodeObjectInheritance): Blueprint to return a inheritance relaated objects list from geode_object string --- .../routes/blueprint_routes.py | 49 +++++++++++++++++++ .../routes/schemas/__init__.py | 1 + .../schemas/geode_object_inheritance.json | 17 +++++++ .../schemas/geode_object_inheritance.py | 10 ++++ tests/test_routes.py | 36 ++++++++++++++ 5 files changed, 113 insertions(+) create mode 100644 src/opengeodeweb_back/routes/schemas/geode_object_inheritance.json create mode 100644 src/opengeodeweb_back/routes/schemas/geode_object_inheritance.py diff --git a/src/opengeodeweb_back/routes/blueprint_routes.py b/src/opengeodeweb_back/routes/blueprint_routes.py index b02299e0..c5a19731 100644 --- a/src/opengeodeweb_back/routes/blueprint_routes.py +++ b/src/opengeodeweb_back/routes/blueprint_routes.py @@ -608,3 +608,52 @@ def import_extension() -> flask.Response: }, 200, ) + + +@routes.route( + schemas_dict["geode_object_inheritance"]["route"], + methods=schemas_dict["geode_object_inheritance"]["methods"], +) +def geode_object_inheritance() -> flask.Response: + json_data = utils_functions.validate_request( + flask.request, schemas_dict["geode_object_inheritance"] + ) + params = schemas.GeodeObjectInheritance.from_dict(json_data) + geode_object_type = params.geode_object_type + target_class = geode_functions.geode_object_from_string(geode_object_type) + print(f"Inheritance for {geode_object_type} ({target_class.__name__})") + + def get_all_bases(geode_class: type) -> set[type]: + bases = set() + for base_class in geode_class.__bases__: + if base_class is not object: + bases.add(base_class) + bases.update(get_all_bases(base_class)) + return bases + + def get_all_subclasses(geode_class: type) -> set[type]: + subclasses = set() + for subclass_class in geode_class.__subclasses__(): + subclasses.add(subclass_class) + subclasses.update(get_all_subclasses(subclass_class)) + return subclasses + + # Extract all related Geode classes (parents and children) + bases = get_all_bases(target_class) + subclasses = get_all_subclasses(target_class) + print(f"Bases found: {[base_class.__name__ for base_class in bases]}") + print( + f"Subclasses found: {[subclass_class.__name__ for subclass_class in subclasses]}" + ) + + all_related_classes = bases | subclasses + all_related_classes.add(target_class) + + # Filter GeodeObjectType to only include registered related objects + geode_inheritances = [] + for geode_object_type_str, geode_class in geode_objects.items(): + if geode_class in all_related_classes: + geode_inheritances.append(geode_object_type_str) + + print(f"Geode Object inheritances: {geode_inheritances}") + return flask.make_response({"geode_inheritances": geode_inheritances}, 200) diff --git a/src/opengeodeweb_back/routes/schemas/__init__.py b/src/opengeodeweb_back/routes/schemas/__init__.py index 763f0a24..4de19b16 100644 --- a/src/opengeodeweb_back/routes/schemas/__init__.py +++ b/src/opengeodeweb_back/routes/schemas/__init__.py @@ -11,6 +11,7 @@ from .import_project import * from .import_extension import * from .geographic_coordinate_systems import * +from .geode_object_inheritance import * from .geode_objects_and_output_extensions import * from .export_project import * from .edge_attribute_names import * diff --git a/src/opengeodeweb_back/routes/schemas/geode_object_inheritance.json b/src/opengeodeweb_back/routes/schemas/geode_object_inheritance.json new file mode 100644 index 00000000..70f97d5d --- /dev/null +++ b/src/opengeodeweb_back/routes/schemas/geode_object_inheritance.json @@ -0,0 +1,17 @@ +{ + "route": "/geode_object_inheritance", + "methods": [ + "POST" + ], + "type": "object", + "properties": { + "geode_object_type": { + "type": "string", + "minLength": 1 + } + }, + "required": [ + "geode_object_type" + ], + "additionalProperties": false +} diff --git a/src/opengeodeweb_back/routes/schemas/geode_object_inheritance.py b/src/opengeodeweb_back/routes/schemas/geode_object_inheritance.py new file mode 100644 index 00000000..f634434b --- /dev/null +++ b/src/opengeodeweb_back/routes/schemas/geode_object_inheritance.py @@ -0,0 +1,10 @@ +from dataclasses_json import DataClassJsonMixin +from dataclasses import dataclass + + +@dataclass +class GeodeObjectInheritance(DataClassJsonMixin): + def __post_init__(self) -> None: + print(self, flush=True) + + geode_object_type: str diff --git a/tests/test_routes.py b/tests/test_routes.py index 215e16d7..703ba638 100644 --- a/tests/test_routes.py +++ b/tests/test_routes.py @@ -379,3 +379,39 @@ def test_database_uri_path(client: FlaskClient) -> None: assert app.config["SQLALCHEMY_DATABASE_URI"] == expected_uri assert os.path.exists(expected_db_path) + + +def test_geode_object_inheritance(client: FlaskClient) -> None: + route = "/opengeodeweb_back/geode_object_inheritance" + # Test BRep + response = client.post(route, json={"geode_object_type": "BRep"}) + assert response.status_code == 200 + geode_inheritances = response.get_json()["geode_inheritances"] + assert "BRep" in geode_inheritances + # Descendants + assert "StructuralModel" in geode_inheritances + assert "ImplicitStructuralModel" in geode_inheritances + + # Test CrossSection + response = client.post(route, json={"geode_object_type": "CrossSection"}) + assert response.status_code == 200 + geode_inheritances = response.get_json()["geode_inheritances"] + assert "CrossSection" in geode_inheritances + # Parent + assert "Section" in geode_inheritances + # Descendant + assert "ImplicitCrossSection" in geode_inheritances + + # Test PolyhedralSolid3D + response = client.post(route, json={"geode_object_type": "PolyhedralSolid3D"}) + assert response.status_code == 200 + geode_inheritances = response.get_json()["geode_inheritances"] + assert "PolyhedralSolid3D" in geode_inheritances + # Parent + assert "VertexSet" in geode_inheritances + + # Test all params + def get_full_data() -> test_utils.JsonData: + return {"geode_object_type": "BRep"} + + test_utils.test_route_wrong_params(client, route, get_full_data) From 14bd40754654b6dc35f9a092581137041782c352 Mon Sep 17 00:00:00 2001 From: MaxNumerique Date: Fri, 27 Feb 2026 13:59:44 +0100 Subject: [PATCH 2/5] prints --- src/opengeodeweb_back/routes/blueprint_routes.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/opengeodeweb_back/routes/blueprint_routes.py b/src/opengeodeweb_back/routes/blueprint_routes.py index c5a19731..fd39b41a 100644 --- a/src/opengeodeweb_back/routes/blueprint_routes.py +++ b/src/opengeodeweb_back/routes/blueprint_routes.py @@ -641,10 +641,8 @@ def get_all_subclasses(geode_class: type) -> set[type]: # Extract all related Geode classes (parents and children) bases = get_all_bases(target_class) subclasses = get_all_subclasses(target_class) - print(f"Bases found: {[base_class.__name__ for base_class in bases]}") - print( - f"Subclasses found: {[subclass_class.__name__ for subclass_class in subclasses]}" - ) + print(f"Bases: {[base_class.__name__ for base_class in bases]}") + print(f"Subclasses: {[subclass_class.__name__ for subclass_class in subclasses]}") all_related_classes = bases | subclasses all_related_classes.add(target_class) @@ -655,5 +653,5 @@ def get_all_subclasses(geode_class: type) -> set[type]: if geode_class in all_related_classes: geode_inheritances.append(geode_object_type_str) - print(f"Geode Object inheritances: {geode_inheritances}") + print(f"inheritances: {geode_inheritances}") return flask.make_response({"geode_inheritances": geode_inheritances}, 200) From 498228293801db3fd745cc7095e26b1aa1bea897 Mon Sep 17 00:00:00 2001 From: MaxNumerique <144453705+MaxNumerique@users.noreply.github.com> Date: Fri, 27 Feb 2026 13:01:02 +0000 Subject: [PATCH 3/5] Apply prepare changes --- opengeodeweb_back_schemas.json | 18 ++++++++++++++++++ requirements.txt | 1 - .../routes/schemas/__init__.py | 2 +- 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/opengeodeweb_back_schemas.json b/opengeodeweb_back_schemas.json index 9e09d762..a8a9bd9d 100644 --- a/opengeodeweb_back_schemas.json +++ b/opengeodeweb_back_schemas.json @@ -294,6 +294,24 @@ ], "additionalProperties": false }, + "geode_object_inheritance": { + "$id": "opengeodeweb_back/geode_object_inheritance", + "route": "/geode_object_inheritance", + "methods": [ + "POST" + ], + "type": "object", + "properties": { + "geode_object_type": { + "type": "string", + "minLength": 1 + } + }, + "required": [ + "geode_object_type" + ], + "additionalProperties": false + }, "export_project": { "$id": "opengeodeweb_back/export_project", "route": "/export_project", diff --git a/requirements.txt b/requirements.txt index bd1ed694..c8216d02 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/routes/schemas/__init__.py b/src/opengeodeweb_back/routes/schemas/__init__.py index 4de19b16..606f794f 100644 --- a/src/opengeodeweb_back/routes/schemas/__init__.py +++ b/src/opengeodeweb_back/routes/schemas/__init__.py @@ -11,8 +11,8 @@ from .import_project import * from .import_extension import * from .geographic_coordinate_systems import * -from .geode_object_inheritance import * from .geode_objects_and_output_extensions import * +from .geode_object_inheritance import * from .export_project import * from .edge_attribute_names import * from .cell_attribute_names import * From 6fa7b5d08f7a6d4775ef2e6a60a266dd22d9a332 Mon Sep 17 00:00:00 2001 From: MaxNumerique Date: Fri, 27 Feb 2026 14:32:53 +0100 Subject: [PATCH 4/5] returns [parents] and [children] --- .../routes/blueprint_routes.py | 33 +++++++++++-------- tests/test_routes.py | 31 ++++++++++------- 2 files changed, 39 insertions(+), 25 deletions(-) diff --git a/src/opengeodeweb_back/routes/blueprint_routes.py b/src/opengeodeweb_back/routes/blueprint_routes.py index fd39b41a..722e7f11 100644 --- a/src/opengeodeweb_back/routes/blueprint_routes.py +++ b/src/opengeodeweb_back/routes/blueprint_routes.py @@ -639,19 +639,24 @@ def get_all_subclasses(geode_class: type) -> set[type]: return subclasses # Extract all related Geode classes (parents and children) - bases = get_all_bases(target_class) - subclasses = get_all_subclasses(target_class) - print(f"Bases: {[base_class.__name__ for base_class in bases]}") - print(f"Subclasses: {[subclass_class.__name__ for subclass_class in subclasses]}") - - all_related_classes = bases | subclasses - all_related_classes.add(target_class) + base_classes = get_all_bases(target_class) + subclass_classes = get_all_subclasses(target_class) + print(f"Bases: {[base_class.__name__ for base_class in base_classes]}") + print( + f"Subclasses: {[subclass_class.__name__ for subclass_class in subclass_classes]}" + ) - # Filter GeodeObjectType to only include registered related objects - geode_inheritances = [] + # Filter GeodeObjectType to only include registered related objects, excluding target + parents = [] + children = [] for geode_object_type_str, geode_class in geode_objects.items(): - if geode_class in all_related_classes: - geode_inheritances.append(geode_object_type_str) - - print(f"inheritances: {geode_inheritances}") - return flask.make_response({"geode_inheritances": geode_inheritances}, 200) + if geode_class == target_class: + continue + if geode_class in base_classes: + parents.append(geode_object_type_str) + if geode_class in subclass_classes: + children.append(geode_object_type_str) + + print(f"parents: {parents}") + print(f"children: {children}") + return flask.make_response({"parents": parents, "children": children}, 200) diff --git a/tests/test_routes.py b/tests/test_routes.py index 703ba638..fad9b009 100644 --- a/tests/test_routes.py +++ b/tests/test_routes.py @@ -386,29 +386,38 @@ def test_geode_object_inheritance(client: FlaskClient) -> None: # Test BRep response = client.post(route, json={"geode_object_type": "BRep"}) assert response.status_code == 200 - geode_inheritances = response.get_json()["geode_inheritances"] - assert "BRep" in geode_inheritances + json_data = response.get_json() + parents = json_data["parents"] + children = json_data["children"] + assert "BRep" not in parents + assert "BRep" not in children # Descendants - assert "StructuralModel" in geode_inheritances - assert "ImplicitStructuralModel" in geode_inheritances + assert "StructuralModel" in children + assert "ImplicitStructuralModel" in children # Test CrossSection response = client.post(route, json={"geode_object_type": "CrossSection"}) assert response.status_code == 200 - geode_inheritances = response.get_json()["geode_inheritances"] - assert "CrossSection" in geode_inheritances + json_data = response.get_json() + parents = json_data["parents"] + children = json_data["children"] + assert "CrossSection" not in parents + assert "CrossSection" not in children # Parent - assert "Section" in geode_inheritances + assert "Section" in parents # Descendant - assert "ImplicitCrossSection" in geode_inheritances + assert "ImplicitCrossSection" in children # Test PolyhedralSolid3D response = client.post(route, json={"geode_object_type": "PolyhedralSolid3D"}) assert response.status_code == 200 - geode_inheritances = response.get_json()["geode_inheritances"] - assert "PolyhedralSolid3D" in geode_inheritances + json_data = response.get_json() + parents = json_data["parents"] + children = json_data["children"] + assert "PolyhedralSolid3D" not in parents + assert "PolyhedralSolid3D" not in children # Parent - assert "VertexSet" in geode_inheritances + assert "VertexSet" in parents # Test all params def get_full_data() -> test_utils.JsonData: From c9fb3b5d6129967a37d90a65e9cc4445e3d71f6b Mon Sep 17 00:00:00 2001 From: MaxNumerique Date: Fri, 27 Feb 2026 14:41:55 +0100 Subject: [PATCH 5/5] rm logs --- src/opengeodeweb_back/routes/blueprint_routes.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/opengeodeweb_back/routes/blueprint_routes.py b/src/opengeodeweb_back/routes/blueprint_routes.py index 722e7f11..f16345b3 100644 --- a/src/opengeodeweb_back/routes/blueprint_routes.py +++ b/src/opengeodeweb_back/routes/blueprint_routes.py @@ -621,7 +621,6 @@ def geode_object_inheritance() -> flask.Response: params = schemas.GeodeObjectInheritance.from_dict(json_data) geode_object_type = params.geode_object_type target_class = geode_functions.geode_object_from_string(geode_object_type) - print(f"Inheritance for {geode_object_type} ({target_class.__name__})") def get_all_bases(geode_class: type) -> set[type]: bases = set() @@ -641,10 +640,6 @@ def get_all_subclasses(geode_class: type) -> set[type]: # Extract all related Geode classes (parents and children) base_classes = get_all_bases(target_class) subclass_classes = get_all_subclasses(target_class) - print(f"Bases: {[base_class.__name__ for base_class in base_classes]}") - print( - f"Subclasses: {[subclass_class.__name__ for subclass_class in subclass_classes]}" - ) # Filter GeodeObjectType to only include registered related objects, excluding target parents = [] @@ -657,6 +652,4 @@ def get_all_subclasses(geode_class: type) -> set[type]: if geode_class in subclass_classes: children.append(geode_object_type_str) - print(f"parents: {parents}") - print(f"children: {children}") return flask.make_response({"parents": parents, "children": children}, 200)