diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 22c4bdb2..c8cca2d8 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -10,5 +10,6 @@ jobs: test: uses: Geode-solutions/actions/.github/workflows/py-test.yml@master with: + repos: ${{ vars.REPOS }} npm: true secrets: inherit diff --git a/.github/workflows/test_pr.yml b/.github/workflows/test_pr.yml index 43d7b730..464546fc 100644 --- a/.github/workflows/test_pr.yml +++ b/.github/workflows/test_pr.yml @@ -8,5 +8,6 @@ jobs: test: uses: Geode-solutions/actions/.github/workflows/py-test-pr.yml@master with: + repos: ${{ vars.REPOS }} npm: true secrets: inherit diff --git a/app.py b/app.py index bfa77814..3672fe02 100644 --- a/app.py +++ b/app.py @@ -10,7 +10,7 @@ from src.opengeodeweb_back.routes.models import blueprint_models from src.opengeodeweb_back.utils_functions import handle_exception from src.opengeodeweb_back import app_config -from src.opengeodeweb_back.database import initialize_database +from opengeodeweb_microservice.database.connection import init_database """ Global config """ @@ -58,6 +58,6 @@ def return_error(): # ''' Main ''' if __name__ == "__main__": - initialize_database(app) + init_database(app) print(f"Python is running in {FLASK_DEBUG} mode") app.run(debug=FLASK_DEBUG, host=DEFAULT_HOST, port=PORT, ssl_context=SSL) diff --git a/pyproject.toml b/pyproject.toml index f32a7ef6..1a5e40b9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,16 +7,14 @@ build-backend = "setuptools.build_meta" name = "OpenGeodeWeb-Back" version = "0.0.0" dynamic = ["dependencies"] -authors = [ - { name="Geode-solutions", email="team-web@geode-solutions.com" }, -] +authors = [{ name = "Geode-solutions", email = "team-web@geode-solutions.com" }] description = "OpenGeodeWeb-Back is an open source framework that proposes handy python functions and wrappers for the OpenGeode ecosystem" readme = "README.md" requires-python = ">=3.9, <3.13" classifiers = [ - "Programming Language :: Python :: 3", - "License :: OSI Approved :: MIT License", - "Operating System :: OS Independent", + "Programming Language :: Python :: 3", + "License :: OSI Approved :: MIT License", + "Operating System :: OS Independent", ] [project.urls] @@ -24,7 +22,7 @@ classifiers = [ "Bug Tracker" = "https://github.com/Geode-solutions/OpenGeodeWeb-Back/issues" [tool.setuptools.dynamic] -dependencies = {file = ["requirements.txt"]} +dependencies = { file = ["requirements.txt"] } [tool.setuptools.packages.find] where = ["src"] @@ -32,3 +30,4 @@ where = ["src"] [tool.setuptools.package-data] "opengeodeweb_back.routes.schemas" = ["*.json"] "opengeodeweb_back.routes.models.schemas" = ["*.json"] +opengeodeweb_microservice = ["py.typed"] diff --git a/requirements.in b/requirements.in index 5ad963ec..6054d3a7 100644 --- a/requirements.in +++ b/requirements.in @@ -8,4 +8,5 @@ fastjsonschema==2.16.2 Flask[async]==3.0.3 Flask-Cors==6.0.1 werkzeug==3.0.3 -Flask-SQLAlchemy==3.1.1 \ No newline at end of file +Flask-SQLAlchemy==3.1.1 +# OpenGeodeWeb-Microservice \ No newline at end of file diff --git a/src/opengeodeweb_back/app_config.py b/src/opengeodeweb_back/app_config.py index 9f60b76d..453a0eda 100644 --- a/src/opengeodeweb_back/app_config.py +++ b/src/opengeodeweb_back/app_config.py @@ -4,7 +4,9 @@ # Third party imports # Local application imports -from .database import DATABASE_FILENAME +from opengeodeweb_microservice.database.connection import get_database + +DATABASE_FILENAME = "project.db" class Config(object): diff --git a/src/opengeodeweb_back/data.py b/src/opengeodeweb_back/data.py deleted file mode 100644 index 76889e03..00000000 --- a/src/opengeodeweb_back/data.py +++ /dev/null @@ -1,45 +0,0 @@ -from sqlalchemy import String, JSON -from sqlalchemy.orm import Mapped, mapped_column -from .database import database, Base -import uuid - - -class Data(Base): - __tablename__ = "datas" - - id: Mapped[str] = mapped_column( - String, primary_key=True, default=lambda: str(uuid.uuid4()).replace("-", "") - ) - native_file_name: Mapped[str] = mapped_column(String, nullable=False) - viewable_file_name: Mapped[str] = mapped_column(String, nullable=False) - geode_object: Mapped[str] = mapped_column(String, nullable=False) - - light_viewable: Mapped[str | None] = mapped_column(String, nullable=True) - input_file: Mapped[str | None] = mapped_column(String, nullable=True) - additional_files: Mapped[list[str] | None] = mapped_column(JSON, nullable=True) - - @staticmethod - def create( - geode_object: str, - input_file: str | None = None, - additional_files: list[str] | None = None, - ) -> "Data": - input_file = input_file if input_file is not None else "" - additional_files = additional_files if additional_files is not None else [] - - data_entry = Data( - geode_object=geode_object, - input_file=input_file, - additional_files=additional_files, - native_file_name="", - viewable_file_name="", - light_viewable=None, - ) - - database.session.add(data_entry) - database.session.flush() - return data_entry - - @staticmethod - def get(data_id: str) -> "Data | None": - return database.session.get(Data, data_id) diff --git a/src/opengeodeweb_back/database.py b/src/opengeodeweb_back/database.py deleted file mode 100644 index d5e2f0f7..00000000 --- a/src/opengeodeweb_back/database.py +++ /dev/null @@ -1,19 +0,0 @@ -from flask import Flask -from flask_sqlalchemy import SQLAlchemy -from sqlalchemy.orm import DeclarativeBase - -DATABASE_FILENAME = "project.db" - - -class Base(DeclarativeBase): - pass - - -database = SQLAlchemy(model_class=Base) - - -def initialize_database(app: Flask) -> SQLAlchemy: - database.init_app(app) - with app.app_context(): - database.create_all() - return database diff --git a/src/opengeodeweb_back/geode_functions.py b/src/opengeodeweb_back/geode_functions.py index a85373f4..de58c47b 100644 --- a/src/opengeodeweb_back/geode_functions.py +++ b/src/opengeodeweb_back/geode_functions.py @@ -11,8 +11,8 @@ # Local application imports from .geode_objects import geode_objects_dict from . import utils_functions -from .data import Data -from .database import database +from opengeodeweb_microservice.database.data import Data +from opengeodeweb_microservice.database.connection import get_session def geode_object_value(geode_object: str): @@ -61,12 +61,12 @@ def load_data(data_id: str) -> Any: flask.abort(404, f"Data with id {data_id} not found") file_absolute_path = data_file_path(data_id, data_entry.native_file_name) + print("Loading file: ", file_absolute_path) + print("File exists: ", os.path.exists(file_absolute_path)) return load(data_entry.geode_object, file_absolute_path) def get_data_info(data_id: str) -> Data: - from .data import Data - data_entry = Data.get(data_id) if not data_entry: flask.abort(404, f"Data with id {data_id} not found") diff --git a/src/opengeodeweb_back/py.typed b/src/opengeodeweb_back/py.typed new file mode 100644 index 00000000..b648ac92 --- /dev/null +++ b/src/opengeodeweb_back/py.typed @@ -0,0 +1 @@ +partial diff --git a/src/opengeodeweb_back/utils_functions.py b/src/opengeodeweb_back/utils_functions.py index d27b1246..2830a325 100644 --- a/src/opengeodeweb_back/utils_functions.py +++ b/src/opengeodeweb_back/utils_functions.py @@ -16,8 +16,8 @@ # Local application imports from . import geode_functions -from .data import Data -from .database import database +from opengeodeweb_microservice.database.data import Data +from opengeodeweb_microservice.database.connection import get_session def increment_request_counter(current_app: flask.Flask) -> None: @@ -193,7 +193,9 @@ def save_all_viewables_and_return_info( data_entry.viewable_file_name = os.path.basename(saved_viewable_file_path) data_entry.light_viewable = os.path.basename(saved_light_viewable_file_path) - database.session.commit() + session = get_session() + if session: + session.commit() return { "native_file_name": data_entry.native_file_name, @@ -247,8 +249,14 @@ def generate_native_viewable_and_light_viewable_from_file( data = geode_functions.load(geode_object, copied_full_path) - database.session.delete(temp_data_entry) - database.session.flush() + # Remplacer : + # database.session.delete(temp_data_entry) + # database.session.flush() + # Par : + session = get_session() + if session: + session.delete(temp_data_entry) + session.flush() return save_all_viewables_and_return_info( geode_object, diff --git a/tests/conftest.py b/tests/conftest.py index 22203f27..e9b41626 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -8,7 +8,7 @@ # Local application imports from app import app -from src.opengeodeweb_back.database import initialize_database +from opengeodeweb_microservice.database.connection import init_database TEST_ID = "1" @@ -28,7 +28,10 @@ def copy_data(): print("Current working directory:", os.getcwd()) print("Directory contents:", os.listdir(".")) - initialize_database(app) + init_database(app) + # print(list(app.blueprints.keys())) + # for rule in app.url_map.iter_rules(): + # print(f"Route: {rule.rule} -> {rule.endpoint}") @pytest.fixture diff --git a/tests/test_models_routes.py b/tests/test_models_routes.py index 2bacdc27..687d6027 100644 --- a/tests/test_models_routes.py +++ b/tests/test_models_routes.py @@ -3,8 +3,8 @@ import flask from src.opengeodeweb_back import geode_functions -from src.opengeodeweb_back.data import Data -from src.opengeodeweb_back.database import database +from opengeodeweb_microservice.database.data import Data +from opengeodeweb_microservice.database.connection import get_session def test_model_mesh_components(client, test_id): @@ -33,22 +33,24 @@ def test_extract_brep_uuids(client, test_id): brep_filename = "cube.og_brep" with client.application.app_context(): - data_entry = Data.create(geode_object="BRep", input_file=brep_filename) + data_entry = Data.create( + geode_object="BRep", + input_file=brep_filename, + ) data_entry.native_file_name = brep_filename - database.session.commit() - - data_path = geode_functions.data_file_path(data_entry.id, brep_filename) - os.makedirs(os.path.dirname(data_path), exist_ok=True) - shutil.copy(f"./tests/data/{brep_filename}", data_path) - - json_data = {"id": data_entry.id} - response = client.post(route, json=json_data) - - assert response.status_code == 200 - uuid_dict = response.json["uuid_dict"] - assert isinstance(uuid_dict, dict) - expected_keys = {"Block", "Line", "Surface", "Corner"} - assert any(key in uuid_dict for key in expected_keys) - for key, value in uuid_dict.items(): - assert isinstance(value, list) - assert all(isinstance(v, str) for v in value) + session = get_session() + if session: + session.commit() + + src_path = os.path.join("tests", "data", brep_filename) + dest_path = os.path.join( + flask.current_app.config["DATA_FOLDER_PATH"], data_entry.id, brep_filename + ) + os.makedirs(os.path.dirname(dest_path), exist_ok=True) + shutil.copy2(src_path, dest_path) + + response = client.post(route, json={"id": data_entry.id}) + assert response.status_code == 200 + assert "uuid_dict" in response.json + uuid_dict = response.json["uuid_dict"] + assert isinstance(uuid_dict, dict) diff --git a/tests/test_routes.py b/tests/test_routes.py index 9acc5d21..a46984b5 100644 --- a/tests/test_routes.py +++ b/tests/test_routes.py @@ -6,9 +6,9 @@ from werkzeug.datastructures import FileStorage # Local application imports +from opengeodeweb_microservice.database.data import Data +from opengeodeweb_microservice.database.connection import get_session from src.opengeodeweb_back import geode_functions, test_utils -from src.opengeodeweb_back.data import Data -from src.opengeodeweb_back.database import database def test_allowed_files(client): @@ -173,17 +173,15 @@ def test_texture_coordinates(client, test_id): with client.application.app_context(): data = Data.create(geode_object="PolygonalSurface3D", input_file="hat.vtp") data.native_file_name = "hat.vtp" - database.session.commit() + session = get_session() + if session: + session.commit() - data_path = geode_functions.data_file_path(data.id, "hat.vtp") - print(data_path) + data_path = geode_functions.data_file_path(data.id, data.native_file_name) os.makedirs(os.path.dirname(data_path), exist_ok=True) shutil.copy("./tests/data/hat.vtp", data_path) - - response = client.post( - "/texture_coordinates", - json={"id": data.id}, - ) + assert os.path.exists(data_path), f"File not found at {data_path}" + response = client.post("/texture_coordinates", json={"id": data.id}) assert response.status_code == 200 texture_coordinates = response.json["texture_coordinates"] assert type(texture_coordinates) is list @@ -197,13 +195,14 @@ def test_vertex_attribute_names(client, test_id): with client.application.app_context(): data = Data.create(geode_object="PolygonalSurface3D", input_file="test.vtp") data.native_file_name = "test.vtp" - database.session.commit() + session = get_session() + if session: + session.commit() - data_path = geode_functions.data_file_path(data.id, "test.vtp") + data_path = geode_functions.data_file_path(data.id, data.native_file_name) os.makedirs(os.path.dirname(data_path), exist_ok=True) - if os.path.exists("./tests/data/hat.vtp"): - shutil.copy("./tests/data/hat.vtp", data_path) - + shutil.copy("./tests/data/test.vtp", data_path) + assert os.path.exists(data_path), f"File not found at {data_path}" response = client.post(route, json={"id": data.id}) assert response.status_code == 200 vertex_attribute_names = response.json["vertex_attribute_names"] @@ -218,12 +217,14 @@ def test_polygon_attribute_names(client, test_id): with client.application.app_context(): data = Data.create(geode_object="PolygonalSurface3D", input_file="test.vtp") data.native_file_name = "test.vtp" - database.session.commit() + session = get_session() + if session: + session.commit() - data_path = geode_functions.data_file_path(data.id, "test.vtp") + data_path = geode_functions.data_file_path(data.id, data.native_file_name) os.makedirs(os.path.dirname(data_path), exist_ok=True) - shutil.copy("./tests/data/test.vtp", data_path) - + shutil.copy("./tests/data/test.vtp", data_path) + assert os.path.exists(data_path), f"File not found at {data_path}" response = client.post(route, json={"id": data.id}) assert response.status_code == 200 polygon_attribute_names = response.json["polygon_attribute_names"] @@ -238,13 +239,16 @@ def test_polyhedron_attribute_names(client, test_id): with client.application.app_context(): data = Data.create(geode_object="PolyhedralSolid3D", input_file="test.vtu") data.native_file_name = "test.vtu" - database.session.commit() + session = get_session() + if session: + session.commit() - data_path = geode_functions.data_file_path(data.id, "test.vtu") + data_path = geode_functions.data_file_path(data.id, data.native_file_name) os.makedirs(os.path.dirname(data_path), exist_ok=True) shutil.copy("./tests/data/test.vtu", data_path) - + assert os.path.exists(data_path), f"File not found at {data_path}" response = client.post(route, json={"id": data.id}) + print(response.json) assert response.status_code == 200 polyhedron_attribute_names = response.json["polyhedron_attribute_names"] assert type(polyhedron_attribute_names) is list diff --git a/tests/test_utils_functions.py b/tests/test_utils_functions.py index 8f748bba..c7e8bce7 100644 --- a/tests/test_utils_functions.py +++ b/tests/test_utils_functions.py @@ -8,8 +8,8 @@ import uuid # Local application imports -from src.opengeodeweb_back.database import database -from src.opengeodeweb_back.data import Data +from opengeodeweb_microservice.database.data import Data +from opengeodeweb_microservice.database.connection import get_session from src.opengeodeweb_back import geode_functions, utils_functions @@ -143,7 +143,8 @@ def test_save_all_viewables_commits_to_db(client): db_entry_before = Data.get(data_id) assert db_entry_before is not None assert db_entry_before.native_file_name == result["native_file_name"] - database.session.rollback() + session = get_session() + session.rollback() db_entry_after = Data.get(data_id) assert ( db_entry_after is not None