diff --git a/.gitignore b/.gitignore
index a9134f20..96807427 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,5 @@
.pytest_cache
-./data
+/data
dist
venv
output
diff --git a/pytest.ini b/pytest.ini
new file mode 100644
index 00000000..b5a5096b
--- /dev/null
+++ b/pytest.ini
@@ -0,0 +1,2 @@
+[pytest]
+addopts = --ignore=src/opengeodeweb_back/
\ No newline at end of file
diff --git a/requirements.txt b/requirements.txt
index edae6731..eba5af2a 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -10,22 +10,22 @@ attrs==24.2.0
# via
# jsonschema
# referencing
-blinker==1.8.2
+blinker==1.9.0
# via flask
click==8.1.7
# via flask
-flask[async]==3.0.3
+flask[async]==3.1.0
# via
# -r requirements.in
# flask-cors
flask-cors==5.0.0
# via -r requirements.in
-geode-background==8.7.0
+geode-background==8.7.5
# via
# geode-explicit
# geode-implicit
# geode-simplex
-geode-common==33.0.9
+geode-common==33.1.3
# via
# -r requirements.in
# geode-background
@@ -35,26 +35,26 @@ geode-common==33.0.9
# geode-numerics
# geode-simplex
# geode-viewables
-geode-conversion==6.0.14
+geode-conversion==6.0.18
# via
# geode-explicit
# geode-implicit
-geode-explicit==6.1.14
+geode-explicit==6.1.17
# via
# -r requirements.in
# geode-implicit
-geode-implicit==3.3.2
+geode-implicit==3.3.5
# via -r requirements.in
-geode-numerics==5.1.8
+geode-numerics==5.2.0
# via
# -r requirements.in
# geode-implicit
# geode-simplex
-geode-simplex==8.2.15
+geode-simplex==8.2.18
# via
# -r requirements.in
# geode-implicit
-geode-viewables==3.0.6
+geode-viewables==3.0.8
# via -r requirements.in
itsdangerous==2.2.0
# via flask
@@ -68,7 +68,7 @@ markupsafe==3.0.2
# via
# jinja2
# werkzeug
-opengeode-core==15.6.3
+opengeode-core==15.6.7
# via
# -r requirements.in
# geode-background
@@ -83,23 +83,23 @@ opengeode-core==15.6.3
# opengeode-geosciencesio
# opengeode-inspector
# opengeode-io
-opengeode-geosciences==8.1.1
+opengeode-geosciences==8.2.0
# via
# -r requirements.in
# geode-implicit
# geode-viewables
# opengeode-geosciencesio
-opengeode-geosciencesio==5.2.3
+opengeode-geosciencesio==5.3.2
# via
# -r requirements.in
# geode-implicit
-opengeode-inspector==6.1.12
+opengeode-inspector==6.1.15
# via
# -r requirements.in
# geode-explicit
# geode-implicit
# geode-simplex
-opengeode-io==7.0.5
+opengeode-io==7.0.7
# via
# -r requirements.in
# geode-implicit
@@ -115,7 +115,7 @@ rpds-py==0.21.0
# referencing
typing-extensions==4.12.2
# via asgiref
-werkzeug==3.1.2
+werkzeug==3.1.3
# via
# -r requirements.in
# flask
diff --git a/src/opengeodeweb_back/geode_objects.py b/src/opengeodeweb_back/geode_objects.py
index dbef8a76..77d2ac30 100644
--- a/src/opengeodeweb_back/geode_objects.py
+++ b/src/opengeodeweb_back/geode_objects.py
@@ -1,3 +1,6 @@
+# Standard library imports
+
+# Third party imports
import opengeode as og
import opengeode_io as og_io
import opengeode_inspector as og_inspector
@@ -5,6 +8,8 @@
import opengeode_geosciencesio as og_gs_io
import geode_viewables as g_v
+# Local application imports
+
def geode_objects_dict():
return {
diff --git a/src/opengeodeweb_back/routes/blueprint_routes.py b/src/opengeodeweb_back/routes/blueprint_routes.py
index 3d4a2c6f..47bb4ab9 100644
--- a/src/opengeodeweb_back/routes/blueprint_routes.py
+++ b/src/opengeodeweb_back/routes/blueprint_routes.py
@@ -304,6 +304,68 @@ def create_point():
)
+with open(
+ os.path.join(schemas, "vertex_attribute_names.json"),
+ "r",
+) as file:
+ vertex_attribute_names_json = json.load(file)
+
+
+@routes.route(
+ vertex_attribute_names_json["route"],
+ methods=vertex_attribute_names_json["methods"],
+)
+def vertex_attribute_names():
+
+ UPLOAD_FOLDER = flask.current_app.config["UPLOAD_FOLDER"]
+ utils_functions.validate_request(flask.request, vertex_attribute_names_json)
+ file_absolute_path = os.path.join(
+ UPLOAD_FOLDER, werkzeug.utils.secure_filename(flask.request.json["filename"])
+ )
+ data = geode_functions.load(
+ flask.request.json["input_geode_object"], file_absolute_path
+ )
+ vertex_attribute_names = data.vertex_attribute_manager().attribute_names()
+
+ return flask.make_response(
+ {
+ "vertex_attribute_names": vertex_attribute_names,
+ },
+ 200,
+ )
+
+
+with open(
+ os.path.join(schemas, "polygon_attribute_names.json"),
+ "r",
+) as file:
+ polygon_attribute_names_json = json.load(file)
+
+
+@routes.route(
+ polygon_attribute_names_json["route"],
+ methods=polygon_attribute_names_json["methods"],
+)
+def polygon_attribute_names():
+
+ UPLOAD_FOLDER = flask.current_app.config["UPLOAD_FOLDER"]
+ utils_functions.validate_request(flask.request, vertex_attribute_names_json)
+ file_absolute_path = os.path.join(
+ UPLOAD_FOLDER, werkzeug.utils.secure_filename(flask.request.json["filename"])
+ )
+ data = geode_functions.load(
+ flask.request.json["input_geode_object"], file_absolute_path
+ )
+ polygon_attribute_names = data.polygon_attribute_manager().attribute_names()
+
+ return flask.make_response(
+ {
+ "polygon_attribute_names": polygon_attribute_names,
+ },
+ 200,
+ )
+
+
with open(
os.path.join(schemas, "ping.json"),
"r",
diff --git a/src/opengeodeweb_back/routes/schemas/polygon_attribute_names.json b/src/opengeodeweb_back/routes/schemas/polygon_attribute_names.json
new file mode 100644
index 00000000..6f1f8b2c
--- /dev/null
+++ b/src/opengeodeweb_back/routes/schemas/polygon_attribute_names.json
@@ -0,0 +1,15 @@
+{
+ "route": "/polygon_attribute_names",
+ "methods": ["POST"],
+ "type": "object",
+ "properties": {
+ "input_geode_object": {
+ "type": "string"
+ },
+ "filename": {
+ "type": "string"
+ }
+ },
+ "required": ["input_geode_object", "filename"],
+ "additionalProperties": false
+}
diff --git a/src/opengeodeweb_back/routes/schemas/vertex_attribute_names.json b/src/opengeodeweb_back/routes/schemas/vertex_attribute_names.json
new file mode 100644
index 00000000..963597af
--- /dev/null
+++ b/src/opengeodeweb_back/routes/schemas/vertex_attribute_names.json
@@ -0,0 +1,15 @@
+{
+ "route": "/vertex_attribute_names",
+ "methods": ["POST"],
+ "type": "object",
+ "properties": {
+ "input_geode_object": {
+ "type": "string"
+ },
+ "filename": {
+ "type": "string"
+ }
+ },
+ "required": ["input_geode_object", "filename"],
+ "additionalProperties": false
+}
diff --git a/src/opengeodeweb_back/test_utils.py b/src/opengeodeweb_back/test_utils.py
new file mode 100644
index 00000000..0d4c6176
--- /dev/null
+++ b/src/opengeodeweb_back/test_utils.py
@@ -0,0 +1,25 @@
+# Standard library imports
+
+# Third party imports
+
+# Local application imports
+
+
+def test_route_wrong_params(client, route, get_full_data):
+ for key, value in get_full_data().items():
+ json = get_full_data()
+ json.pop(key)
+ response = client.post(route, json=json)
+ assert response.status_code == 400
+ error_description = response.json["description"]
+ assert error_description == f"Validation error: '{key}' is a required property"
+
+ json = get_full_data()
+ json["dumb_key"] = "dumb_value"
+ response = client.post(route, json=json)
+ assert response.status_code == 400
+ error_description = response.json["description"]
+ assert (
+ error_description
+ == "Validation error: Additional properties are not allowed ('dumb_key' was unexpected)"
+ )
diff --git a/tests/conftest.py b/tests/conftest.py
index 5642ba2c..efe7e6c2 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -1,6 +1,11 @@
+# Standard library imports
+import time
+
+# Third party imports
import pytest
+
+# Local application imports
from app import app
-import time
@pytest.fixture
diff --git a/tests/polygon_attribute.vtp b/tests/polygon_attribute.vtp
new file mode 100644
index 00000000..09e313a5
--- /dev/null
+++ b/tests/polygon_attribute.vtp
@@ -0,0 +1,25 @@
+
+
+
+
+
+ -5.03873 -3.56819 -3.29213 -0.379219 0.386424 -1.97966 -0.310684 1.50807 1.80048 2.25409 2.56229 0.235826 -0.162775 -1.4339
+ 1.1 4.5 3 5 1.2 6 3 8 5 8.2 5 5.5 1.1 8.3 2 10 4 10 6 10 7 10 5.9 7.7 6.1 7 5.8 5.8
+ 32 33 36 37 42 34 38 39 40 41 43 44 45 35
+ 0.441452 1.06497 0 0.509268 1.09401 0 0.451134 1.22395 0 0.244789 1.03019 0 0.306431 0.898241 0 0.520398 0.854144 0 0.0558145 0.936744 0 0.17577 1.03026 0 0.179188 0.94981 0 0.242737 0.863881 0 0.312089 0.886676 0 0.328556 0.855054 0 nan nan nan 0.353402 0.897993 0
+
+
+ 1.1 4.5 0 3 5 0 1.2 6 0 3 8 0 5 8.2 0 5 5.5 0 1.1 8.3 0 2 10 0 4 10 0 6 10 0 7 10 0 5.9 7.7 0 6.1 7 0 5.8 5.8 0
+
+
+ 0 1 2 1 3 2 1 4 3 1 5 4 2 3 6 3 7 6 3 8 7 3 4 8 4 9 8 4 10 9 4 11 10 4 12 11 5 12 4 5 13 12
+ 4.29497e+09 1 4.29497e+09 2 4 0 3 7 1 4.29497e+09 12 2 1 5 4.29497e+09 6 4.29497e+09 4 7 4.29497e+09 5 2 8 6 9 4.29497e+09 7 10 4.29497e+09 8 11 4.29497e+09 9 12 4.29497e+09 10 13 11 3 4.29497e+09 4.29497e+09 12
+ -3.96635 -2.41318 -1.18699 -1.72048 -1.32735 0.272721 0.976443 0.602562 1.48033 1.73427 1.06151 0.153159 -0.585337 -1.19211
+
+
+ 0 1 2 1 3 2 1 4 3 1 5 4 2 3 6 3 7 6 3 8 7 3 4 8 4 9 8 4 10 9 4 11 10 4 12 11 5 12 4 5 13 12
+ 3 6 9 12 15 18 21 24 27 30 33 36 39 42
+
+
+
+
diff --git a/tests/test_geode_functions.py b/tests/test_geode_functions.py
index 2155acf2..ea0ecb64 100644
--- a/tests/test_geode_functions.py
+++ b/tests/test_geode_functions.py
@@ -1,5 +1,10 @@
+# Standard library imports
import os
import uuid
+
+# Third party imports
+
+# Local application imports
from src.opengeodeweb_back import geode_functions, geode_objects
diff --git a/tests/test_routes.py b/tests/test_routes.py
index 0320271f..138cd435 100644
--- a/tests/test_routes.py
+++ b/tests/test_routes.py
@@ -1,17 +1,28 @@
-import os
+# Standard library imports
import base64
+import os
+
+# Third party imports
from werkzeug.datastructures import FileStorage
+# Local application imports
+from src.opengeodeweb_back import test_utils
+
def test_allowed_files(client):
route = f"/allowed_files"
- response = client.post(route, json={"supported_feature": None})
+ get_full_data = lambda: {"supported_feature": "None"}
+ json = get_full_data()
+ response = client.post(route, json=json)
assert response.status_code == 200
extensions = response.json["extensions"]
assert type(extensions) is list
for extension in extensions:
assert type(extension) is str
+ # Test all params
+ test_utils.test_route_wrong_params(client, route, get_full_data)
+
def test_allowed_objects(client):
route = f"/allowed_objects"
@@ -30,13 +41,8 @@ def get_full_data():
for allowed_object in allowed_objects:
assert type(allowed_object) is str
- for key, value in get_full_data().items():
- json = get_full_data()
- json.pop(key)
- response = client.post(route, json=json)
- assert response.status_code == 400
- error_description = response.json["description"]
- assert error_description == f"Validation error: '{key}' is a required property"
+ # Test all params
+ test_utils.test_route_wrong_params(client, route, get_full_data)
def test_upload_file(client):
@@ -58,11 +64,7 @@ def get_full_data():
}
json = get_full_data()
- response = client.post(
- route,
- json=json,
- )
-
+ response = client.post(route, json=json)
assert response.status_code == 200
has_missing_files = response.json["has_missing_files"]
mandatory_files = response.json["mandatory_files"]
@@ -71,33 +73,23 @@ def get_full_data():
assert type(mandatory_files) is list
assert type(additional_files) is list
- for key, value in get_full_data().items():
- json = get_full_data()
- json.pop(key)
- response = client.post(route, json=json)
- assert response.status_code == 400
- error_description = response.json["description"]
- assert error_description == f"Validation error: '{key}' is a required property"
+ # Test all params
+ test_utils.test_route_wrong_params(client, route, get_full_data)
def test_geographic_coordinate_systems(client):
route = f"/geographic_coordinate_systems"
-
+ get_full_data = lambda: {"input_geode_object": "BRep"}
# Normal test with geode_object 'BRep'
- response = client.post(route, json={"input_geode_object": "BRep"})
+ response = client.post(route, json=get_full_data())
assert response.status_code == 200
crs_list = response.json["crs_list"]
assert type(crs_list) is list
for crs in crs_list:
assert type(crs) is dict
- # Test without geode_object
- response = client.post(route, json={})
- assert response.status_code == 400
- error_message = response.json["description"]
- assert (
- error_message == "Validation error: 'input_geode_object' is a required property"
- )
+ # Test all params
+ test_utils.test_route_wrong_params(client, route, get_full_data)
def test_inspect_file(client):
@@ -117,13 +109,8 @@ def get_full_data():
inspection_result = response.json["inspection_result"]
assert type(inspection_result) is dict
- for key, value in get_full_data().items():
- json = get_full_data()
- json.pop(key)
- response = client.post(route, json=json)
- assert response.status_code == 400
- error_description = response.json["description"]
- assert error_description == f"Validation error: '{key}' is a required property"
+ # Test all params
+ test_utils.test_route_wrong_params(client, route, get_full_data)
def test_geode_objects_and_output_extensions(client):
@@ -148,13 +135,8 @@ def get_full_data():
assert type(value) is dict
assert type(value["is_saveable"]) is bool
- # Test without input_geode_object
- response = client.post(route, json={})
- assert response.status_code == 400
- error_message = response.json["description"]
- assert (
- error_message == "Validation error: 'input_geode_object' is a required property"
- )
+ # Test all params
+ test_utils.test_route_wrong_params(client, route, get_full_data)
def test_save_viewable_file(client):
@@ -178,20 +160,66 @@ def get_full_data():
id = response.json["id"]
assert type(id) is str
- for key, value in get_full_data().items():
- json = get_full_data()
- json.pop(key)
- response = client.post(route, json=json)
- assert response.status_code == 400
- error_description = response.json["description"]
- assert error_description == f"Validation error: '{key}' is a required property"
+ # Test all params
+ test_utils.test_route_wrong_params(client, route, get_full_data)
-def test_create_point(client):
- route = f"/create_point"
+def test_vertex_attribute_names(client):
+ response = client.put(
+ f"/upload_file",
+ data={"file": FileStorage(open("./tests/vertex_attribute.vtp", "rb"))},
+ )
+ assert response.status_code == 201
+
+ route = f"/vertex_attribute_names"
+
+ def get_full_data():
+ return {
+ "input_geode_object": "PolygonalSurface3D",
+ "filename": "vertex_attribute.vtp",
+ }
+
+ # Normal test with filename 'vertex_attribute.vtp'
+ response = client.post(route, json=get_full_data())
+ assert response.status_code == 200
+ vertex_attribute_names = response.json["vertex_attribute_names"]
+ assert type(vertex_attribute_names) is list
+ for vertex_attribute_name in vertex_attribute_names:
+ assert type(vertex_attribute_name) is str
+
+ test_utils.test_route_wrong_params(client, route, get_full_data)
+
+
+def test_polygon_attribute_names(client):
+ response = client.put(
+ f"/upload_file",
+ data={"file": FileStorage(open("./tests/polygon_attribute.vtp", "rb"))},
+ )
+ assert response.status_code == 201
+
+ route = f"/polygon_attribute_names"
def get_full_data():
- return {"x": 1, "y": 2, "z": 3}
+ return {
+ "input_geode_object": "PolygonalSurface3D",
+ "filename": "polygon_attribute.vtp",
+ }
+
+ # Normal test with filename 'vertex_attribute.vtp'
+ response = client.post(route, json=get_full_data())
+ assert response.status_code == 200
+ polygon_attribute_names = response.json["polygon_attribute_names"]
+ assert type(polygon_attribute_names) is list
+ for polygon_attribute_name in polygon_attribute_names:
+ assert type(polygon_attribute_name) is str
+
+ # Test all params
+ test_utils.test_route_wrong_params(client, route, get_full_data)
+
+
+def test_create_point(client):
+ route = f"/create_point"
+ get_full_data = lambda: {"x": 1, "y": 2, "z": 3}
# Normal test with all keys
response = client.post(route, json=get_full_data())
@@ -201,10 +229,5 @@ def get_full_data():
id = response.json["id"]
assert type(id) is str
- for key, value in get_full_data().items():
- json = get_full_data()
- json.pop(key)
- response = client.post(route, json=json)
- assert response.status_code == 400
- error_description = response.json["description"]
- assert error_description == f"Validation error: '{key}' is a required property"
+ # Test all params
+ test_utils.test_route_wrong_params(client, route, get_full_data)
diff --git a/tests/test_utils_functions.py b/tests/test_utils_functions.py
index 8416539d..59fbfcc9 100644
--- a/tests/test_utils_functions.py
+++ b/tests/test_utils_functions.py
@@ -1,4 +1,9 @@
+# Standard library imports
+
+# Third party imports
import flask
+
+# Local application imports
from src.opengeodeweb_back import utils_functions
diff --git a/tests/vertex_attribute.vtp b/tests/vertex_attribute.vtp
new file mode 100644
index 00000000..dfe9f191
--- /dev/null
+++ b/tests/vertex_attribute.vtp
@@ -0,0 +1,25 @@
+
+
+
+
+
+ -4.81986 -4.24426 -3.08307 -2.67472 -3.78427 -1.72952 -3.51395 -1.54156 -3.26163 -1.37705 1.49282 0.476446 3.07847 1.81965 0.15148 -0.00219692 -2.03758 -1.21643 -0.392793 1.04446 -0.159125 -1.41509 -1.36066
+ 1.1 1.5 4.5 1.4 2.9 3 4.9 3.1 6.4 1.7 6.3 4 8.2 1.9 8.5 4 11 2 10.9 4 10.7 6.9 9.4 6 10.6 8.5 8 7.5 7 5.95 5.8 5.8 1.1 4.5 3 5 5 5.5 6.1 7 5.8 5.8 5.35 4.45 5.35 4.45
+ 0.212913 0.898437 0 0.17411 0.88882 0 0.188674 0.91656 0 0.129386 0.902004 0 0.0522603 0.892251 0 0.0913028 0.902984 0 0.0494319 0.925332 0 0.0790874 0.944317 0 0.0630148 0.926847 0 0.0606951 0.95661 0 0.0916888 0.990159 0 0.102275 0.986827 0 0.0910002 0.997784 0 0.149679 1.01122 0 0.129961 0.95844 0 nan nan nan 0.18944 0.925768 0 0.188704 0.925194 0 0.172618 0.985506 0 0.149488 0.967933 0 0.14023 0.965619 0 0.0974158 0.875532 0 nan nan nan
+ 50 51 55 56 52 57 53 58 54 59 62 61 47 46 60 35 32 33 34 45 35 63 63
+
+
+ 1.1 1.5 0 4.5 1.4 0 2.9 3 3 4.9 3.1 0 6.4 1.7 0 6.3 4 0 8.2 1.9 0 8.5 4 0 11 2 0 10.9 4 3 10.7 6.9 0 9.4 6 0 10.6 8.5 0 8 7.5 0 7 5.95 0 5.8 5.8 0 1.1 4.5 0 3 5 0 5 5.5 0 6.1 7 3 5.8 5.8 0 5.35 4.45 0 5.35 4.45 0
+
+
+ -4.04907 -3.33402 -3.56775 -2.7295 -3.00925 -2.26168 -2.77238 -2.06008 0.197405 1.68258 1.79152 -0.814056 0.815858 -0.304546 -1.03987 -0.579057 -3.3135 -2.11236 -2.32474 -1.42798 0.345606 1.0052 -1.10125 -1.93978 -1.47606 -0.585217
+ 4.29497e+09 1 16 2 18 0 4.29497e+09 3 1 4 23 2 4.29497e+09 5 3 6 14 4 4.29497e+09 7 5 4.29497e+09 11 6 4.29497e+09 9 11 4.29497e+09 10 8 9 4.29497e+09 12 7 8 13 13 10 21 11 12 14 5 13 15 14 20 22 0 17 4.29497e+09 16 18 4.29497e+09 1 19 17 24 4.29497e+09 18 15 21 4.29497e+09 12 4.29497e+09 20 4.29497e+09 23 15 4.29497e+09 3 22 4.29497e+09 25 19 4.29497e+09 4.29497e+09 24
+ 0 1 2 1 3 2 1 4 3 4 5 3 4 6 5 6 7 5 6 8 7 8 9 7 9 10 11 10 12 11 11 12 13 7 9 11 14 11 13 7 11 14 5 7 14 5 14 20 0 2 16 16 2 17 2 3 17 3 18 17 20 14 19 14 13 19 20 21 5 21 3 5 3 22 18 22 15 18
+
+
+ 0 1 2 1 3 2 1 4 3 4 5 3 4 6 5 6 7 5 6 8 7 8 9 7 9 10 11 10 12 11 11 12 13 7 9 11 14 11 13 7 11 14 5 7 14 5 14 20 0 2 16 16 2 17 2 3 17 3 18 17 20 14 19 14 13 19 20 21 5 21 3 5 3 22 18 22 15 18
+ 3 6 9 12 15 18 21 24 27 30 33 36 39 42 45 48 51 54 57 60 63 66 69 72 75 78
+
+
+
+