diff --git a/lib/__init__.py b/lib/__init__.py index 2f27218..0dbaa09 100644 --- a/lib/__init__.py +++ b/lib/__init__.py @@ -23,3 +23,6 @@ def parse_error(error): exc_type = type(error).__name__ exc_obj = f"{error}".replace("\n", " ").replace(" ", " ") return f"{exc_type} exception: {exc_obj}" + + +from lib.api import app diff --git a/lib/controllers/environment.py b/lib/controllers/environment.py index 45d5f2a..2696970 100644 --- a/lib/controllers/environment.py +++ b/lib/controllers/environment.py @@ -1,17 +1,15 @@ from typing import Union import jsonpickle -from rocketpy.environment.environment import Environment as RocketPyEnvironment from fastapi import HTTPException, status from pymongo.errors import PyMongoError from lib import logger, parse_error from lib.models.environment import Env +from lib.services.environment import EnvironmentService from lib.repositories.environment import EnvRepository from lib.views.environment import ( EnvSummary, - EnvData, - EnvPlots, EnvCreated, EnvDeleted, EnvUpdated, @@ -27,7 +25,7 @@ class EnvController: env: models.Env Enables: - - Simulation of RocketPyEnvironment from models.Env + - Simulation of a RocketPy Environment from models.Env - CRUD operations over models.Env on the database """ @@ -42,25 +40,6 @@ def env(self) -> Env: def env(self, env: Env): self._env = env - @staticmethod - def get_rocketpy_env(env: Env) -> RocketPyEnvironment: - """ - Get the rocketpy env object. - - Returns: - RocketPyEnvironment - """ - rocketpy_env = RocketPyEnvironment( - latitude=env.latitude, - longitude=env.longitude, - elevation=env.elevation, - date=env.date, - ) - rocketpy_env.set_atmospheric_model( - type=env.atmospheric_model_type, file=env.atmospheric_model_file - ) - return rocketpy_env - async def create_env(self) -> Union[EnvCreated, HTTPException]: """ Create a env in the database. @@ -152,7 +131,7 @@ async def get_rocketpy_env_as_jsonpickle( """ try: read_env = await cls.get_env_by_id(env_id) - rocketpy_env = cls.get_rocketpy_env(read_env) + rocketpy_env = EnvironmentService.from_env_model(read_env) except HTTPException as e: raise e from e except Exception as e: @@ -261,24 +240,15 @@ async def simulate_env( env_id: str. Returns: - views.EnvSummary + EnvSummary Raises: HTTP 404 Not Found: If the env does not exist in the database. """ try: read_env = await cls.get_env_by_id(env_id) - rocketpy_env = cls.get_rocketpy_env(read_env) - - env_simulation_numbers = EnvData.parse_obj( - rocketpy_env.all_info_returned() - ) - env_simulation_plots = EnvPlots.parse_obj( - rocketpy_env.all_plot_info_returned() - ) - env_summary = EnvSummary( - env_data=env_simulation_numbers, env_plots=env_simulation_plots - ) + rocketpy_env = EnvironmentService.from_env_model(read_env) + env_summary = rocketpy_env.get_env_summary() except HTTPException as e: raise e from e except Exception as e: diff --git a/lib/repositories/repo.py b/lib/repositories/repo.py index 44c2c0c..79f8849 100644 --- a/lib/repositories/repo.py +++ b/lib/repositories/repo.py @@ -43,7 +43,7 @@ def _on_init_done(self, future): future.result() except Exception as e: logger.error("Initialization failed: %s", e, exc_info=True) - self._initialized_event.set() # Ensure the event is set even on failure + self._initialized_event.set() raise e @retry(stop=stop_after_attempt(3), wait=wait_fixed(2)) @@ -54,7 +54,7 @@ async def _async_init(self): self._initialized_event.set() async def __aenter__(self): - await self._initialized_event.wait() # Ensure initialization is complete + await self._initialized_event.wait() return self async def __aexit__(self, exc_type, exc_value, traceback): @@ -94,31 +94,34 @@ async def _cleanup_instance(self): self._instances.pop(self.__class__, None) @retry(stop=stop_after_attempt(3), wait=wait_fixed(2)) - @property - def connection_string(self): + def _get_connection_string(self): with self._thread_lock: if not getattr(self, '_initialized', False): - raise RuntimeError( - "Repository not initialized or has been finalized" - ) + raise RepositoryNotInitializedException() return self._connection_string - @retry(stop=stop_after_attempt(3), wait=wait_fixed(2)) @property - def client(self): + def connection_string(self): + return self._get_connection_string() + + @retry(stop=stop_after_attempt(3), wait=wait_fixed(2)) + def _get_client(self): with self._thread_lock: if not getattr(self, '_initialized', False): - raise RuntimeError( - "Repository not initialized or has been finalized" - ) + raise RepositoryNotInitializedException() return self._client - @retry(stop=stop_after_attempt(3), wait=wait_fixed(2)) @property - def collection(self): + def client(self): + return self._get_client() + + @retry(stop=stop_after_attempt(3), wait=wait_fixed(2)) + def _get_collection(self): with self._thread_lock: if not getattr(self, '_initialized', False): - raise RuntimeError( - "Repository not initialized or has been finalized" - ) + raise RepositoryNotInitializedException() return self._collection + + @property + def collection(self): + return self._get_collection() diff --git a/lib/services/environment.py b/lib/services/environment.py new file mode 100644 index 0000000..e641a43 --- /dev/null +++ b/lib/services/environment.py @@ -0,0 +1,39 @@ +from typing import Self +from rocketpy.environment.environment import Environment as RocketPyEnvironment +from rocketpy.utilities import get_instance_attributes +from lib.models.environment import Env +from lib.views.environment import EnvSummary + + +class EnvironmentService(RocketPyEnvironment): + + @classmethod + def from_env_model(cls, env: Env) -> Self: + """ + Get the rocketpy env object. + + Returns: + RocketPyEnvironment + """ + rocketpy_env = cls( + latitude=env.latitude, + longitude=env.longitude, + elevation=env.elevation, + date=env.date, + ) + rocketpy_env.set_atmospheric_model( + type=env.atmospheric_model_type, file=env.atmospheric_model_file + ) + return rocketpy_env + + def get_env_summary(self) -> EnvSummary: + """ + Get the summary of the environment. + + Returns: + EnvSummary + """ + + attributes = get_instance_attributes(self) + env_summary = EnvSummary(**attributes) + return env_summary diff --git a/lib/views/environment.py b/lib/views/environment.py index b0f4757..15157db 100644 --- a/lib/views/environment.py +++ b/lib/views/environment.py @@ -2,39 +2,49 @@ from pydantic import BaseModel -class EnvData(BaseModel): - # TODO: review grav type - # grav: "Any" - elevation: int - model_type: str - model_type_max_expected_height: int - wind_speed: float - wind_direction: float - wind_heading: float - surface_pressure: float - surface_temperature: float - surface_air_density: float - surface_speed_of_sound: float - launch_date: str - lat: float - lon: float - - -class EnvPlots(BaseModel): - grid: "List[float]" - wind_speed: "List[float]" - wind_direction: "List[float]" - speed_of_sound: "List[float]" - density: "List[float]" - wind_vel_x: "List[float]" - wind_vel_y: "List[float]" - pressure: "List[float]" - temperature: "List[float]" - - class EnvSummary(BaseModel): - env_data: EnvData - env_plots: EnvPlots + latitude: float + longitude: float + elevation: float + # date: str #datetime + atmospheric_model_type: str + air_gas_constant: float + standard_g: float + earth_radius: float + datum: str + timezone: str + # ellipsoid: str # function + initial_utm_zone: int + initial_utm_letter: str + initial_north: float + initial_east: float + initial_hemisphere: str + initial_ew: str + # local_date: str #datetime + # datetime_date: str #datetime + max_expected_height: int + # barometric_height: str # function + # barometric_height_ISA: str # function + # pressure: str # function + # pressure_ISA: str # function + # temperature: str # function + # temperature_ISA: str # function + # density: str # function + # speed_of_sound: str # function + # dynamic_viscosity: str # function + # gravity: str # function + # somigliana_gravity: str # function + # wind_speed: str # function + # wind_direction: str # function + # wind_heading: str # function + # wind_velocity_x: str # function + # wind_velocity_y: str # function + # calculate_earth_radius: str # function + # decimal_degrees_to_arc_seconds: str # function + # geodesic_to_utm: str # function + # utm_to_geodesic: str # function + # prints: str # function + # plots: str # function class EnvCreated(BaseModel):