diff --git a/lib/__init__.py b/lib/__init__.py
index a1bcc92..b328917 100644
--- a/lib/__init__.py
+++ b/lib/__init__.py
@@ -1,2 +1,10 @@
# lib/__init__.py
+import logging
from .api import app
+
+logging.basicConfig(
+ level=logging.INFO,
+ filename='app.log',
+ filemode='a',
+ format='%(asctime)s - %(levelname)s - %(message)s',
+)
diff --git a/lib/api.py b/lib/api.py
index f86f2b1..6896bed 100644
--- a/lib/api.py
+++ b/lib/api.py
@@ -1,7 +1,6 @@
"""
This is the main API file for the RocketPy API.
"""
-import logging
from fastapi import FastAPI, Request, status
from fastapi.exceptions import RequestValidationError
@@ -9,8 +8,11 @@
from fastapi.openapi.utils import get_openapi
from fastapi.responses import RedirectResponse, JSONResponse
+from lib import logging
from lib.routes import flight, environment, motor, rocket
+logger = logging.getLogger(__name__)
+
app = FastAPI(
swagger_ui_parameters={
"defaultModelsExpandDepth": 0,
@@ -35,7 +37,7 @@ def custom_openapi():
return app.openapi_schema
openapi_schema = get_openapi(
title="RocketPy Infinity-API",
- version="1.0.0 BETA",
+ version="1.1.0 BETA",
description=(
"
RocketPy Infinity-API is a RESTful Open API for RocketPy, a rocket flight simulator.
"
"
"
@@ -79,9 +81,11 @@ async def __perform_healthcheck():
# Errors
@app.exception_handler(RequestValidationError)
-async def validation_exception_handler(request: Request, exc: RequestValidationError):
+async def validation_exception_handler(
+ request: Request, exc: RequestValidationError
+):
exc_str = f"{exc}".replace("\n", " ").replace(" ", " ")
- logging.error(f"{request}: {exc_str}")
+ logger.error(f"{request}: {exc_str}")
content = {"status_code": 10422, "message": exc_str, "data": None}
return JSONResponse(
content=content, status_code=status.HTTP_422_UNPROCESSABLE_ENTITY
diff --git a/lib/controllers/__init__.py b/lib/controllers/__init__.py
new file mode 100644
index 0000000..87e5b46
--- /dev/null
+++ b/lib/controllers/__init__.py
@@ -0,0 +1,6 @@
+# lib/controllers/__init__.py
+
+
+def parse_error(e):
+ exc_str = f"{e}".replace("\n", " ").replace(" ", " ")
+ return exc_str
diff --git a/lib/controllers/environment.py b/lib/controllers/environment.py
index 90c4c6f..fc3b6f7 100644
--- a/lib/controllers/environment.py
+++ b/lib/controllers/environment.py
@@ -1,9 +1,11 @@
from typing import Union
import jsonpickle
-from rocketpy.environment.environment import Environment
+from rocketpy.environment.environment import Environment as RocketPyEnvironment
from fastapi import HTTPException, status
+from lib import logging
+from lib.controllers import parse_error
from lib.models.environment import Env
from lib.repositories.environment import EnvRepository
from lib.views.environment import (
@@ -16,20 +18,41 @@
EnvPickle,
)
+logger = logging.getLogger(__name__)
+
class EnvController:
"""
Controller for the Environment model.
Init Attributes:
- env (models.Env): Environment model object.
+ env: models.Env
Enables:
- - Create a rocketpy.Environment object from an Env model object.
+ - Simulation of RocketPyEnvironment from models.Env
+ - CRUD operations over modeols.Env on the database
"""
def __init__(self, env: Env):
- rocketpy_env = Environment(
+ self._env = env
+
+ @property
+ def env(self) -> Env:
+ return self._env
+
+ @env.setter
+ def env(self, env: Env):
+ self._env = env
+
+ @staticmethod
+ async 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,
@@ -38,165 +61,212 @@ def __init__(self, env: Env):
rocketpy_env.set_atmospheric_model(
type=env.atmospheric_model_type, file=env.atmospheric_model_file
)
- self.rocketpy_env = rocketpy_env
- self.env = env
+ return rocketpy_env
async def create_env(self) -> "Union[EnvCreated, HTTPException]":
"""
Create a env in the database.
Returns:
- EnvCreated: Environment id.
+ views.EnvCreated
"""
- env = EnvRepository(environment=self.env)
- successfully_created_env = await env.create_env()
- if not successfully_created_env:
+ try:
+ created_env = await EnvRepository(
+ environment=self.env
+ ).create_env()
+ except Exception as e:
+ exc_str = parse_error(e)
+ logger.error(f"controllers.environment.create_env: {exc_str}")
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
- detail="Failed to create environment",
+ detail=f"Failed to create environment: {e}",
+ ) from e
+ else:
+ return EnvCreated(env_id=created_env.env_id)
+ finally:
+ logger.info(
+ f"Call to controllers.environment.create_env completed; params: Env {hash(self.env)}"
)
- return EnvCreated(env_id=str(env.env_id))
-
@staticmethod
- async def get_env(env_id: int) -> "Union[Env, HTTPException]":
+ async def get_env_by_id(env_id: int) -> "Union[Env, HTTPException]":
"""
Get a env from the database.
Args:
- env_id (int): Environment id.
+ env_id: int
Returns:
- env model object
+ models.Env
Raises:
HTTP 404 Not Found: If the env is not found in the database.
"""
- successfully_read_env = await EnvRepository(env_id=env_id).get_env()
- if not successfully_read_env:
+ try:
+ read_env = await EnvRepository(env_id=env_id).get_env()
+ except Exception as e:
+ exc_str = parse_error(e)
+ logger.error(f"controllers.environment.get_env_by_id: {exc_str}")
+ raise HTTPException(
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
+ detail=f"Failed to read environment: {e}",
+ ) from e
+ else:
+ if read_env:
+ return read_env
raise HTTPException(
- status_code=status.HTTP_404_NOT_FOUND, detail="Environment not found"
+ status_code=status.HTTP_404_NOT_FOUND,
+ detail="Environment not found",
+ )
+ finally:
+ logger.info(
+ f"Call to controllers.environment.get_env_by_id completed; params: EnvID {env_id}"
)
- return successfully_read_env
-
- @staticmethod
- async def get_rocketpy_env(env_id: int) -> "Union[EnvPickle, HTTPException]":
+ @classmethod
+ async def get_rocketpy_env_as_jsonpickle(
+ cls,
+ env_id: int,
+ ) -> "Union[EnvPickle, HTTPException]":
"""
- Get a rocketpy env object encoded as jsonpickle string from the database.
+ Get rocketpy.Environmnet as jsonpickle string.
Args:
- env_id (int): env id.
+ env_id: int
Returns:
- str: jsonpickle string of the rocketpy env.
+ views.EnvPickle
Raises:
HTTP 404 Not Found: If the env is not found in the database.
"""
- successfully_read_env = await EnvRepository(env_id=env_id).get_env()
- if not successfully_read_env:
+ try:
+ read_env = await cls.get_env_by_id(env_id)
+ except HTTPException as e:
+ raise e from e
+ except Exception as e:
+ exc_str = parse_error(e)
+ logger.error(
+ f"controllers.environment.get_rocketpy_env_as_jsonpickle: {exc_str}"
+ )
raise HTTPException(
- status_code=status.HTTP_404_NOT_FOUND, detail="Environment not found"
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
+ detail=f"Failed to read environment: {e}",
+ ) from e
+ else:
+ rocketpy_env = await cls.get_rocketpy_env(read_env)
+ return EnvPickle(
+ jsonpickle_rocketpy_env=jsonpickle.encode(rocketpy_env)
+ )
+ finally:
+ logger.info(
+ f"Call to controllers.environment.get_rocketpy_env_as_jsonpickle completed; params: EnvID {env_id}"
)
- successfully_read_rocketpy_env = EnvController(
- successfully_read_env
- ).rocketpy_env
-
- return EnvPickle(
- jsonpickle_rocketpy_env=jsonpickle.encode(successfully_read_rocketpy_env)
- )
-
- async def update_env(self, env_id: int) -> "Union[EnvUpdated, HTTPException]":
+ async def update_env(
+ self, env_id: int
+ ) -> "Union[EnvUpdated, HTTPException]":
"""
Update a env in the database.
Args:
- env_id (int): env id.
+ env_id: int
Returns:
- EnvUpdated: env id and message.
+ views.EnvUpdated
Raises:
HTTP 404 Not Found: If the env is not found in the database.
"""
- successfully_read_env = await EnvRepository(env_id=env_id).get_env()
- if not successfully_read_env:
- raise HTTPException(
- status_code=status.HTTP_404_NOT_FOUND, detail="Environment not found"
- )
-
- successfully_updated_env = await EnvRepository(
- environment=self.env, env_id=env_id
- ).update_env()
- if not successfully_updated_env:
+ try:
+ await EnvController.get_env_by_id(env_id)
+ updated_env = await EnvRepository(
+ environment=self.env, env_id=env_id
+ ).update_env()
+ except HTTPException as e:
+ raise e from e
+ except Exception as e:
+ exc_str = parse_error(e)
+ logger.error(f"controllers.environment.update_env: {exc_str}")
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
- detail="Failed to update environment",
+ detail=f"Failed to update environment: {e}",
+ ) from e
+ else:
+ return EnvUpdated(new_env_id=updated_env.env_id)
+ finally:
+ logger.info(
+ f"Call to controllers.environment.update_env completed; params: EnvID {env_id}, Env {hash(self.env)}"
)
- return EnvUpdated(new_env_id=str(successfully_updated_env))
-
@staticmethod
- async def delete_env(env_id: int) -> "Union[EnvDeleted, HTTPException]":
+ async def delete_env(env_id: str) -> "Union[EnvDeleted, HTTPException]":
"""
Delete a env from the database.
Args:
- env_id (int): Environment id.
+ env_id: int
Returns:
- EnvDeleted: Environment id and message.
+ views.EnvDeleted
Raises:
HTTP 404 Not Found: If the env is not found in the database.
"""
- successfully_read_env = await EnvRepository(env_id=env_id).get_env()
- if not successfully_read_env:
- raise HTTPException(
- status_code=status.HTTP_404_NOT_FOUND, detail="Environment not found"
- )
-
- successfully_deleted_env = await EnvRepository(env_id=env_id).delete_env()
- if not successfully_deleted_env:
+ try:
+ await EnvRepository(env_id=env_id).delete_env()
+ except Exception as e:
+ exc_str = parse_error(e)
+ logger.error(f"controllers.environment.delete_env: {exc_str}")
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
- detail="Failed to delete environment",
+ detail=f"Failed to delete environment: {e}",
+ ) from e
+ else:
+ return EnvDeleted(deleted_env_id=env_id)
+ finally:
+ logger.info(
+ f"Call to controllers.environment.delete_env completed; params: EnvID {env_id}"
)
- return EnvDeleted(deleted_env_id=str(env_id))
-
- @staticmethod
- async def simulate(env_id: int) -> "Union[EnvSummary, HTTPException]":
+ @classmethod
+ async def simulate(cls, env_id: int) -> "Union[EnvSummary, HTTPException]":
"""
Simulate a rocket environment.
Args:
- env_id (int): Env id.
+ env_id: int.
Returns:
- Env summary view.
+ views.EnvSummary
Raises:
HTTP 404 Not Found: If the env does not exist in the database.
"""
- successfully_read_env = await EnvRepository(env_id=env_id).get_env()
- if not successfully_read_env:
- raise HTTPException(
- status_code=status.HTTP_404_NOT_FOUND, detail="Environment not found"
- )
-
try:
- env = EnvController(successfully_read_env).rocketpy_env
- env_simulation_numbers = EnvData.parse_obj(env.all_info_returned())
- env_simulation_plots = EnvPlots.parse_obj(env.all_plot_info_returned())
+ read_env = await cls.get_env_by_id(env_id)
+ rocketpy_env = await 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
)
- return env_summary
+ except HTTPException as e:
+ raise e from e
except Exception as e:
+ exc_str = parse_error(e)
+ logger.error(f"controllers.environment.simulate: {exc_str}")
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"Failed to simulate environment: {e}",
) from e
+ else:
+ return env_summary
+ finally:
+ logger.info(
+ f"Call to controllers.environment.simulate completed; params: EnvID {env_id}"
+ )
diff --git a/lib/controllers/flight.py b/lib/controllers/flight.py
index 0fd6eba..38d9ee8 100644
--- a/lib/controllers/flight.py
+++ b/lib/controllers/flight.py
@@ -51,7 +51,10 @@ class FlightController:
"""
def __init__(
- self, flight: Flight, rocket_option: RocketOptions, motor_kind: MotorKinds
+ self,
+ flight: Flight,
+ rocket_option: RocketOptions,
+ motor_kind: MotorKinds,
):
rocketpy_rocket = RocketController(
flight.rocket, rocket_option=rocket_option, motor_kind=motor_kind
@@ -110,7 +113,8 @@ async def get_flight(flight_id: int) -> "Union[Flight, HTTPException]":
).get_flight()
if not successfully_read_flight:
raise HTTPException(
- status_code=status.HTTP_404_NOT_FOUND, detail="Flight not found."
+ status_code=status.HTTP_404_NOT_FOUND,
+ detail="Flight not found.",
)
return successfully_read_flight
@@ -136,13 +140,18 @@ async def get_rocketpy_flight(
).get_flight()
if not successfully_read_flight:
raise HTTPException(
- status_code=status.HTTP_404_NOT_FOUND, detail="Flight not found."
+ status_code=status.HTTP_404_NOT_FOUND,
+ detail="Flight not found.",
)
successfully_read_rocketpy_flight = FlightController(
flight=successfully_read_flight,
- rocket_option=RocketOptions(successfully_read_flight.rocket._rocket_option),
- motor_kind=MotorKinds(successfully_read_flight.rocket.motor._motor_kind),
+ rocket_option=RocketOptions(
+ successfully_read_flight.rocket._rocket_option
+ ),
+ motor_kind=MotorKinds(
+ successfully_read_flight.rocket.motor._motor_kind
+ ),
).rocketpy_flight
return FlightPickle(
@@ -171,12 +180,15 @@ async def update_flight(
).get_flight()
if not successfully_read_flight:
raise HTTPException(
- status_code=status.HTTP_404_NOT_FOUND, detail="Flight not found."
+ status_code=status.HTTP_404_NOT_FOUND,
+ detail="Flight not found.",
)
successfully_updated_flight = await FlightRepository(
flight=self.flight, flight_id=flight_id
- ).update_flight(rocket_option=self.rocket_option, motor_kind=self.motor_kind)
+ ).update_flight(
+ rocket_option=self.rocket_option, motor_kind=self.motor_kind
+ )
if not successfully_updated_flight:
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
@@ -207,7 +219,8 @@ async def update_env(
).get_flight()
if not successfully_read_flight:
raise HTTPException(
- status_code=status.HTTP_404_NOT_FOUND, detail="Flight not found."
+ status_code=status.HTTP_404_NOT_FOUND,
+ detail="Flight not found.",
)
flight = successfully_read_flight.dict()
@@ -246,7 +259,8 @@ async def update_rocket(
).get_flight()
if not successfully_read_flight:
raise HTTPException(
- status_code=status.HTTP_404_NOT_FOUND, detail="Flight not found."
+ status_code=status.HTTP_404_NOT_FOUND,
+ detail="Flight not found.",
)
flight = successfully_read_flight.dict()
@@ -267,7 +281,9 @@ async def update_rocket(
return FlightUpdated(new_flight_id=str(successfully_updated_flight))
@staticmethod
- async def delete_flight(flight_id: int) -> "Union[FlightDeleted, HTTPException]":
+ async def delete_flight(
+ flight_id: int,
+ ) -> "Union[FlightDeleted, HTTPException]":
"""
Delete a flight from the database.
@@ -285,7 +301,8 @@ async def delete_flight(flight_id: int) -> "Union[FlightDeleted, HTTPException]"
).get_flight()
if not successfully_read_flight:
raise HTTPException(
- status_code=status.HTTP_404_NOT_FOUND, detail="Flight not found."
+ status_code=status.HTTP_404_NOT_FOUND,
+ detail="Flight not found.",
)
successfully_deleted_flight = await FlightRepository(
@@ -300,7 +317,9 @@ async def delete_flight(flight_id: int) -> "Union[FlightDeleted, HTTPException]"
return FlightDeleted(deleted_flight_id=str(flight_id))
@staticmethod
- async def simulate(flight_id: int) -> "Union[FlightSummary, HTTPException]":
+ async def simulate(
+ flight_id: int,
+ ) -> "Union[FlightSummary, HTTPException]":
"""
Simulate a rocket flight.
@@ -318,7 +337,8 @@ async def simulate(flight_id: int) -> "Union[FlightSummary, HTTPException]":
).get_flight()
if not successfully_read_flight:
raise HTTPException(
- status_code=status.HTTP_404_NOT_FOUND, detail="Flight not found."
+ status_code=status.HTTP_404_NOT_FOUND,
+ detail="Flight not found.",
)
try:
@@ -351,7 +371,9 @@ async def simulate(flight_id: int) -> "Union[FlightSummary, HTTPException]":
)
_numerical_integration_settings = NumericalIntegrationSettings(
- max_time="Maximum Allowed Flight Time: {:f} s".format(flight.max_time),
+ max_time="Maximum Allowed Flight Time: {:f} s".format(
+ flight.max_time
+ ),
max_time_step="Maximum Allowed Time Step: {:f} s".format(
flight.max_time_step
),
@@ -371,11 +393,15 @@ async def simulate(flight_id: int) -> "Union[FlightSummary, HTTPException]":
)
_launch_rail_conditions = LaunchRailConditions(
- rail_length="Launch Rail Length: {:.2f} m".format(flight.rail_length),
+ rail_length="Launch Rail Length: {:.2f} m".format(
+ flight.rail_length
+ ),
flight_inclination="Launch Rail Inclination: {:.2f}°".format(
flight.inclination
),
- flight_heading="Launch Rail Heading: {:.2f}°".format(flight.heading),
+ flight_heading="Launch Rail Heading: {:.2f}°".format(
+ flight.heading
+ ),
)
_surface_wind_conditions = SurfaceWindConditions(
@@ -413,17 +439,25 @@ async def simulate(flight_id: int) -> "Union[FlightSummary, HTTPException]":
flight.rocket.motor.burn_out_time
),
burnout_altitude="Altitude at burn out: {:.3f} m (AGL)".format(
- flight.z(flight.rocket.motor.burn_out_time) - flight.env.elevation
+ flight.z(flight.rocket.motor.burn_out_time)
+ - flight.env.elevation
),
burnout_rocket_velocity="Rocket velocity at burn out: {:.3f} m/s".format(
flight.speed(flight.rocket.motor.burn_out_time)
),
burnout_freestream_velocity="Freestream velocity at burn out: {:.3f} m/s".format(
(
- flight.stream_velocity_x(flight.rocket.motor.burn_out_time) ** 2
- + flight.stream_velocity_y(flight.rocket.motor.burn_out_time)
+ flight.stream_velocity_x(
+ flight.rocket.motor.burn_out_time
+ )
+ ** 2
+ + flight.stream_velocity_y(
+ flight.rocket.motor.burn_out_time
+ )
** 2
- + flight.stream_velocity_z(flight.rocket.motor.burn_out_time)
+ + flight.stream_velocity_z(
+ flight.rocket.motor.burn_out_time
+ )
** 2
)
** 0.5
@@ -457,14 +491,17 @@ async def simulate(flight_id: int) -> "Union[FlightSummary, HTTPException]":
flight.max_reynolds_number, flight.max_reynolds_number_time
),
maximum_dynamic_pressure="Maximum Dynamic Pressure: {:.3e} Pa at {:.2f} s".format(
- flight.max_dynamic_pressure, flight.max_dynamic_pressure_time
+ flight.max_dynamic_pressure,
+ flight.max_dynamic_pressure_time,
),
maximum_acceleration_during_motor_burn="Maximum Acceleration During Motor Burn: {:.3f} m/s² at {:.2f} s".format(
flight.max_acceleration, flight.max_acceleration_time
),
maximum_gs_during_motor_burn="Maximum Gs During Motor Burn: {:.3f} g at {:.2f} s".format(
flight.max_acceleration
- / flight.env.gravity(flight.z(flight.max_acceleration_time)),
+ / flight.env.gravity(
+ flight.z(flight.max_acceleration_time)
+ ),
flight.max_acceleration_time,
),
maximum_acceleration_after_motor_burn="Maximum Acceleration After Motor Burn: {:.3f} m/s² at {:.2f} s".format(
@@ -491,9 +528,15 @@ async def simulate(flight_id: int) -> "Union[FlightSummary, HTTPException]":
if len(flight.impact_state) != 0:
_impact_conditions = ImpactConditions(
- x_impact_position="X Impact: {:.3f} m".format(flight.x_impact),
- y_impact_position="Y Impact: {:.3f} m".format(flight.y_impact),
- time_of_impact="Time of Impact: {:.3f} s".format(flight.t_final),
+ x_impact_position="X Impact: {:.3f} m".format(
+ flight.x_impact
+ ),
+ y_impact_position="Y Impact: {:.3f} m".format(
+ flight.y_impact
+ ),
+ time_of_impact="Time of Impact: {:.3f} s".format(
+ flight.t_final
+ ),
impact_velocity="Velocity at Impact: {:.3f} m/s".format(
flight.impact_velocity
),
@@ -501,7 +544,9 @@ async def simulate(flight_id: int) -> "Union[FlightSummary, HTTPException]":
elif flight.terminate_on_apogee is False:
_impact_conditions = ImpactConditions(
time="Time: {:.3f} s".format(flight.solution[-1][0]),
- altitude="Altitude: {:.3f} m".format(flight.solution[-1][3]),
+ altitude="Altitude: {:.3f} m".format(
+ flight.solution[-1][3]
+ ),
)
if len(flight.parachute_events) == 0:
@@ -519,10 +564,14 @@ async def simulate(flight_id: int) -> "Union[FlightSummary, HTTPException]":
name = parachute.name.title()
events[name] = []
events[name].append(
- name + " Ejection Triggered at: {:.3f} s".format(trigger_time)
+ name
+ + " Ejection Triggered at: {:.3f} s".format(
+ trigger_time
+ )
)
events[name].append(
- name + " Parachute Inflated at: {:.3f} s".format(open_time)
+ name
+ + " Parachute Inflated at: {:.3f} s".format(open_time)
)
events[name].append(
name
diff --git a/lib/controllers/motor.py b/lib/controllers/motor.py
index a01eafb..eaa226c 100644
--- a/lib/controllers/motor.py
+++ b/lib/controllers/motor.py
@@ -116,16 +116,21 @@ async def get_motor(motor_id: int) -> "Union[Motor, HTTPException]":
Raises:
HTTP 404 Not Found: If the motor is not found in the database.
"""
- successfully_read_motor = await MotorRepository(motor_id=motor_id).get_motor()
+ successfully_read_motor = await MotorRepository(
+ motor_id=motor_id
+ ).get_motor()
if not successfully_read_motor:
raise HTTPException(
- status_code=status.HTTP_404_NOT_FOUND, detail="Motor not found."
+ status_code=status.HTTP_404_NOT_FOUND,
+ detail="Motor not found.",
)
return successfully_read_motor
@staticmethod
- async def get_rocketpy_motor(motor_id: int) -> "Union[MotorPickle, HTTPException]":
+ async def get_rocketpy_motor(
+ motor_id: int,
+ ) -> "Union[MotorPickle, HTTPException]":
"""
Get a rocketpy motor object encoded as jsonpickle string from the database.
@@ -138,10 +143,13 @@ async def get_rocketpy_motor(motor_id: int) -> "Union[MotorPickle, HTTPException
Raises:
HTTP 404 Not Found: If the motor is not found in the database.
"""
- successfully_read_motor = await MotorRepository(motor_id=motor_id).get_motor()
+ successfully_read_motor = await MotorRepository(
+ motor_id=motor_id
+ ).get_motor()
if not successfully_read_motor:
raise HTTPException(
- status_code=status.HTTP_404_NOT_FOUND, detail="Motor not found."
+ status_code=status.HTTP_404_NOT_FOUND,
+ detail="Motor not found.",
)
successfully_read_rocketpy_motor = MotorController(
@@ -155,7 +163,9 @@ async def get_rocketpy_motor(motor_id: int) -> "Union[MotorPickle, HTTPException
)
)
- async def update_motor(self, motor_id: int) -> "Union[MotorUpdated, HTTPException]":
+ async def update_motor(
+ self, motor_id: int
+ ) -> "Union[MotorUpdated, HTTPException]":
"""
Update a motor in the database.
@@ -168,10 +178,13 @@ async def update_motor(self, motor_id: int) -> "Union[MotorUpdated, HTTPExceptio
Raises:
HTTP 404 Not Found: If the motor is not found in the database.
"""
- successfully_read_motor = await MotorRepository(motor_id=motor_id).get_motor()
+ successfully_read_motor = await MotorRepository(
+ motor_id=motor_id
+ ).get_motor()
if not successfully_read_motor:
raise HTTPException(
- status_code=status.HTTP_404_NOT_FOUND, detail="Motor not found."
+ status_code=status.HTTP_404_NOT_FOUND,
+ detail="Motor not found.",
)
successfully_updated_motor = await MotorRepository(
@@ -186,7 +199,9 @@ async def update_motor(self, motor_id: int) -> "Union[MotorUpdated, HTTPExceptio
return MotorUpdated(new_motor_id=str(successfully_updated_motor))
@staticmethod
- async def delete_motor(motor_id: int) -> "Union[MotorDeleted, HTTPException]":
+ async def delete_motor(
+ motor_id: int,
+ ) -> "Union[MotorDeleted, HTTPException]":
"""
Delete a motor from the database.
@@ -199,10 +214,13 @@ async def delete_motor(motor_id: int) -> "Union[MotorDeleted, HTTPException]":
Raises:
HTTP 404 Not Found: If the motor is not found in the database.
"""
- successfully_read_motor = await MotorRepository(motor_id=motor_id).get_motor()
+ successfully_read_motor = await MotorRepository(
+ motor_id=motor_id
+ ).get_motor()
if not successfully_read_motor:
raise HTTPException(
- status_code=status.HTTP_404_NOT_FOUND, detail="Motor not found."
+ status_code=status.HTTP_404_NOT_FOUND,
+ detail="Motor not found.",
)
successfully_deleted_motor = await MotorRepository(
@@ -230,10 +248,13 @@ async def simulate(motor_id: int) -> "Union[MotorSummary, HTTPException]":
Raises:
HTTP 404 Not Found: If the motor does not exist in the database.
"""
- successfully_read_motor = await MotorRepository(motor_id=motor_id).get_motor()
+ successfully_read_motor = await MotorRepository(
+ motor_id=motor_id
+ ).get_motor()
if not successfully_read_motor:
raise HTTPException(
- status_code=status.HTTP_404_NOT_FOUND, detail="Motor not found."
+ status_code=status.HTTP_404_NOT_FOUND,
+ detail="Motor not found.",
)
try:
@@ -249,7 +270,9 @@ async def simulate(motor_id: int) -> "Union[MotorSummary, HTTPException]":
+ "{:.3f}".format(motor.propellant_initial_mass)
+ " kg",
average_propellant_exhaust_velocity="Average Propellant Exhaust Velocity: "
- + "{:.3f}".format(motor.exhaust_velocity.average(*motor.burn_time))
+ + "{:.3f}".format(
+ motor.exhaust_velocity.average(*motor.burn_time)
+ )
+ " m/s",
average_thrust="Average Thrust: "
+ "{:.3f}".format(motor.average_thrust)
diff --git a/lib/controllers/rocket.py b/lib/controllers/rocket.py
index 5aa08ae..c0e7210 100644
--- a/lib/controllers/rocket.py
+++ b/lib/controllers/rocket.py
@@ -10,7 +10,9 @@
from rocketpy.rocket.parachute import Parachute as RocketpyParachute
from rocketpy.rocket.rocket import Rocket as RocketpyRocket
from rocketpy.rocket.aero_surface import NoseCone as RocketpyNoseCone
-from rocketpy.rocket.aero_surface import TrapezoidalFins as RocketpyTrapezoidalFins
+from rocketpy.rocket.aero_surface import (
+ TrapezoidalFins as RocketpyTrapezoidalFins,
+)
from rocketpy.rocket.aero_surface import Tail as RocketpyTail
from lib.controllers.motor import MotorController
@@ -238,7 +240,9 @@ def check_trigger(expression: str) -> bool:
try:
for operand in lambda_node.body.values:
if not isinstance(operand, ast.Compare):
- print("Invalid expression structure (not a Compare).")
+ print(
+ "Invalid expression structure (not a Compare)."
+ )
return False
except AttributeError:
print("Invalid expression structure (not a Compare).")
@@ -247,10 +251,14 @@ def check_trigger(expression: str) -> bool:
# Restricting access to functions or attributes
for node in ast.walk(lambda_node):
if isinstance(node, ast.Call):
- print("Calling functions is not allowed in the expression.")
+ print(
+ "Calling functions is not allowed in the expression."
+ )
return False
if isinstance(node, ast.Attribute):
- print("Accessing attributes is not allowed in the expression.")
+ print(
+ "Accessing attributes is not allowed in the expression."
+ )
return False
return True
@@ -292,7 +300,8 @@ async def get_rocket(rocket_id: int) -> "Union[Rocket, HTTPException]":
).get_rocket()
if not successfully_read_rocket:
raise HTTPException(
- status_code=status.HTTP_404_NOT_FOUND, detail="Rocket not found."
+ status_code=status.HTTP_404_NOT_FOUND,
+ detail="Rocket not found.",
)
return successfully_read_rocket
@@ -318,12 +327,15 @@ async def get_rocketpy_rocket(
).get_rocket()
if not successfully_read_rocket:
raise HTTPException(
- status_code=status.HTTP_404_NOT_FOUND, detail="Rocket not found."
+ status_code=status.HTTP_404_NOT_FOUND,
+ detail="Rocket not found.",
)
successfully_read_rocketpy_rocket = RocketController(
rocket=successfully_read_rocket,
- rocket_option=RocketOptions(successfully_read_rocket._rocket_option),
+ rocket_option=RocketOptions(
+ successfully_read_rocket._rocket_option
+ ),
motor_kind=MotorKinds(successfully_read_rocket.motor._motor_kind),
).rocketpy_rocket
@@ -353,7 +365,8 @@ async def update_rocket(
).get_rocket()
if not successfully_read_rocket:
raise HTTPException(
- status_code=status.HTTP_404_NOT_FOUND, detail="Rocket not found."
+ status_code=status.HTTP_404_NOT_FOUND,
+ detail="Rocket not found.",
)
successfully_updated_rocket = await RocketRepository(
@@ -368,7 +381,9 @@ async def update_rocket(
return RocketUpdated(new_rocket_id=str(successfully_updated_rocket))
@staticmethod
- async def delete_rocket(rocket_id: int) -> "Union[RocketDeleted, HTTPException]":
+ async def delete_rocket(
+ rocket_id: int,
+ ) -> "Union[RocketDeleted, HTTPException]":
"""
Delete a rocket from the database.
@@ -386,7 +401,8 @@ async def delete_rocket(rocket_id: int) -> "Union[RocketDeleted, HTTPException]"
).get_rocket()
if not successfully_read_rocket:
raise HTTPException(
- status_code=status.HTTP_404_NOT_FOUND, detail="Rocket not found."
+ status_code=status.HTTP_404_NOT_FOUND,
+ detail="Rocket not found.",
)
successfully_deleted_rocket = await RocketRepository(
@@ -401,7 +417,9 @@ async def delete_rocket(rocket_id: int) -> "Union[RocketDeleted, HTTPException]"
return RocketDeleted(deleted_rocket_id=str(rocket_id))
@staticmethod
- async def simulate(rocket_id: int) -> "Union[RocketSummary, HTTPException]":
+ async def simulate(
+ rocket_id: int,
+ ) -> "Union[RocketSummary, HTTPException]":
"""
Simulate a rocket rocket.
@@ -419,14 +437,19 @@ async def simulate(rocket_id: int) -> "Union[RocketSummary, HTTPException]":
).get_rocket()
if not successfully_read_rocket:
raise HTTPException(
- status_code=status.HTTP_404_NOT_FOUND, detail="Rocket not found."
+ status_code=status.HTTP_404_NOT_FOUND,
+ detail="Rocket not found.",
)
try:
rocket = RocketController(
rocket=successfully_read_rocket,
- rocket_option=RocketOptions(successfully_read_rocket._rocket_option),
- motor_kind=MotorKinds(successfully_read_rocket.motor._motor_kind),
+ rocket_option=RocketOptions(
+ successfully_read_rocket._rocket_option
+ ),
+ motor_kind=MotorKinds(
+ successfully_read_rocket.motor._motor_kind
+ ),
).rocketpy_rocket
_inertia_details = InertiaDetails(
@@ -467,7 +490,10 @@ async def simulate(rocket_id: int) -> "Union[RocketSummary, HTTPException]":
+ " m2",
rocket_codm_nozzle_exit_distance="Rocket Center of Dry Mass - Nozzle Exit Distance: "
+ "{:.3f} m".format(
- abs(rocket.center_of_dry_mass_position - rocket.motor_position)
+ abs(
+ rocket.center_of_dry_mass_position
+ - rocket.motor_position
+ )
),
rocket_codm_center_of_propellant_mass="Rocket Center of Dry Mass - Center of Propellant Mass: "
+ "{:.3f} m".format(
@@ -478,7 +504,10 @@ async def simulate(rocket_id: int) -> "Union[RocketSummary, HTTPException]":
),
rocket_codm_loaded_center_of_mass="Rocket Center of Mass - Rocket Loaded Center of Mass: "
+ "{:.3f} m".format(
- abs(rocket.center_of_mass(0) - rocket.center_of_dry_mass_position)
+ abs(
+ rocket.center_of_mass(0)
+ - rocket.center_of_dry_mass_position
+ )
),
)
@@ -488,7 +517,9 @@ async def simulate(rocket_id: int) -> "Union[RocketSummary, HTTPException]":
_aerodynamics_lift_coefficient_derivatives[name] = []
_aerodynamics_lift_coefficient_derivatives[name].append(
name
- + " Lift Coefficient Derivative: {:.3f}".format(surface.clalpha(0))
+ + " Lift Coefficient Derivative: {:.3f}".format(
+ surface.clalpha(0)
+ )
+ "/rad"
)
@@ -498,20 +529,26 @@ async def simulate(rocket_id: int) -> "Union[RocketSummary, HTTPException]":
cpz = surface.cp[2]
_aerodynamics_center_of_pressure[name] = []
_aerodynamics_center_of_pressure[name].append(
- name + " Center of Pressure to CM: {:.3f}".format(cpz) + " m"
+ name
+ + " Center of Pressure to CM: {:.3f}".format(cpz)
+ + " m"
)
_rocket_aerodynamics_quantities = RocketAerodynamicsQuantities(
aerodynamics_lift_coefficient_derivatives=_aerodynamics_lift_coefficient_derivatives,
aerodynamics_center_of_pressure=_aerodynamics_center_of_pressure,
distance_cop_to_codm="Distance from Center of Pressure to Center of Dry Mass: "
- + "{:.3f}".format(rocket.center_of_mass(0) - rocket.cp_position)
+ + "{:.3f}".format(
+ rocket.center_of_mass(0) - rocket.cp_position
+ )
+ " m",
initial_static_margin="Initial Static Margin: "
+ "{:.3f}".format(rocket.static_margin(0))
+ " c",
final_static_margin="Final Static Margin: "
- + "{:.3f}".format(rocket.static_margin(rocket.motor.burn_out_time))
+ + "{:.3f}".format(
+ rocket.static_margin(rocket.motor.burn_out_time)
+ )
+ " c",
)
@@ -531,12 +568,12 @@ async def simulate(rocket_id: int) -> "Union[RocketSummary, HTTPException]":
_parachute_ejection_signal_trigger[chute.name] = (
"Ejection signal trigger: " + chute.trigger.__name__
)
- _parachute_ejection_system_refresh_rate[
- chute.name
- ] = "Ejection system refresh rate: {chute.sampling_rate:.3f} Hz"
- _parachute_lag[
- chute.name
- ] = "Time between ejection signal is triggered and the parachute is fully opened: {chute.lag:.1f} s\n"
+ _parachute_ejection_system_refresh_rate[chute.name] = (
+ "Ejection system refresh rate: {chute.sampling_rate:.3f} Hz"
+ )
+ _parachute_lag[chute.name] = (
+ "Time between ejection signal is triggered and the parachute is fully opened: {chute.lag:.1f} s\n"
+ )
_parachute_data = ParachuteData(
parachute_details=_parachute_details,
diff --git a/lib/models/environment.py b/lib/models/environment.py
index 0ce9afe..cd2b9ab 100644
--- a/lib/models/environment.py
+++ b/lib/models/environment.py
@@ -11,6 +11,6 @@ class Env(BaseModel, frozen=True):
# Opional parameters
atmospheric_model_type: Optional[str] = "standard_atmosphere"
atmospheric_model_file: Optional[str] = "GFS"
- date: Optional[datetime.datetime] = datetime.datetime.today() + datetime.timedelta(
- days=1
+ date: Optional[datetime.datetime] = (
+ datetime.datetime.today() + datetime.timedelta(days=1)
)
diff --git a/lib/models/motor.py b/lib/models/motor.py
index 4e83891..635ee51 100644
--- a/lib/models/motor.py
+++ b/lib/models/motor.py
@@ -35,7 +35,10 @@ class TankFluids(BaseModel, frozen=True):
class MotorTank(BaseModel, frozen=True):
# Required parameters
- geometry: "List[Tuple[Tuple[float,float],float]]" = [((0, 5), 1), ((5, 10), 2)]
+ geometry: "List[Tuple[Tuple[float,float],float]]" = [
+ ((0, 5), 1),
+ ((5, 10), 2),
+ ]
tank_kind: TankKinds = TankKinds.mass_flow
gas: TankFluids = TankFluids()
liquid: TankFluids = TankFluids()
@@ -69,10 +72,14 @@ def __init__(self, **kwargs):
match self.tank_kind:
case TankKinds.level:
- tank = LevelBasedTank(**tank_core, liquid_height=self.liquid_height)
+ tank = LevelBasedTank(
+ **tank_core, liquid_height=self.liquid_height
+ )
case TankKinds.mass:
tank = MassBasedTank(
- **tank_core, liquid_mass=self.liquid_mass, gas_mass=self.gas_mass
+ **tank_core,
+ liquid_mass=self.liquid_mass,
+ gas_mass=self.gas_mass,
)
case TankKinds.mass_flow:
tank = MassFlowRateBasedTank(
@@ -117,7 +124,9 @@ class Motor(BaseModel, frozen=True):
grain_separation: Optional[float] = 0.005
throat_radius: Optional[float] = 0.011
interpolation_method: Optional[str] = "linear"
- coordinate_system_orientation: Optional[str] = "nozzle_to_combustion_chamber"
+ coordinate_system_orientation: Optional[str] = (
+ "nozzle_to_combustion_chamber"
+ )
def __init__(self, motor_kind=MotorKinds.solid, **kwargs):
super().__init__(**kwargs)
diff --git a/lib/repositories/__init__.py b/lib/repositories/__init__.py
new file mode 100644
index 0000000..87e5b46
--- /dev/null
+++ b/lib/repositories/__init__.py
@@ -0,0 +1,6 @@
+# lib/controllers/__init__.py
+
+
+def parse_error(e):
+ exc_str = f"{e}".replace("\n", " ").replace(" ", " ")
+ return exc_str
diff --git a/lib/repositories/environment.py b/lib/repositories/environment.py
index 8632b65..1301498 100644
--- a/lib/repositories/environment.py
+++ b/lib/repositories/environment.py
@@ -1,101 +1,125 @@
from typing import Union
-from pymongo.results import InsertOneResult
-from pymongo.results import DeleteResult
+from lib import logging
+from lib.repositories import parse_error
from lib.models.environment import Env
from lib.repositories.repo import Repository
+logger = logging.getLogger(__name__)
+
class EnvRepository(Repository):
"""
- Environment repository
+ Enables database CRUD operations with models.Env
Init Attributes:
- environment: Env object
- env_id: Environment id
+ environment: models.Env
+ env_id: str
- Enables CRUD operations on environment objects
"""
def __init__(self, environment: Env = None, env_id: str = None):
super().__init__("environments")
- self.environment = environment
+ self._env = environment
if env_id:
- self.env_id = env_id
+ self._env_id = env_id
else:
- self.env_id = self.environment.__hash__()
+ self._env_id = str(hash(self._env))
- def __del__(self):
- super().__del__()
+ @property
+ def env(self) -> "Env":
+ return self._env
- async def create_env(self) -> "InsertOneResult":
- """
- Creates a environment in the database
+ @env.setter
+ def env(self, environment: "Env"):
+ self._env = environment
+
+ @property
+ def env_id(self) -> "str":
+ return self._env_id
- Args:
- rocketpy_env: rocketpy environment object
+ @env_id.setter
+ def env_id(self, env_id: "str"):
+ self._env_id = env_id
+
+ async def create_env(self):
+ """
+ Creates a non-existing models.Env in the database
Returns:
- InsertOneResult: result of the insert operation
+ self
"""
- if not await self.get_env():
- try:
- environment_to_dict = self.environment.dict()
- environment_to_dict["env_id"] = self.env_id
- return await self.collection.insert_one(environment_to_dict)
- except Exception as e:
- raise Exception(f"Error creating environment: {str(e)}") from e
- finally:
- self.__del__()
+ try:
+ environment_to_dict = self.env.dict()
+ environment_to_dict["env_id"] = self.env_id
+ await self.collection.insert_one(environment_to_dict)
+ except Exception as e:
+ exc_str = parse_error(e)
+ logger.error(f"repositories.environment.create_env: {exc_str}")
+ raise Exception(f"Error creating environment: {str(e)}") from e
else:
- return InsertOneResult(acknowledged=True, inserted_id=None)
+ return self
+ finally:
+ logger.info(
+ f"Call to repositories.environment.create_env completed; states: EnvID {self.env_id}"
+ )
- async def update_env(self) -> "Union[int, None]":
+ async def update_env(self):
"""
- Updates a environment in the database
+ Updates a models.Env in the database
Returns:
- int: environment id
+ self
"""
try:
- environment_to_dict = self.environment.dict()
- environment_to_dict["env_id"] = self.environment.__hash__()
-
+ environment_to_dict = self.env.dict()
+ environment_to_dict["env_id"] = str(hash(self.env))
await self.collection.update_one(
{"env_id": self.env_id}, {"$set": environment_to_dict}
)
-
self.env_id = environment_to_dict["env_id"]
- return self.env_id
except Exception as e:
+ exc_str = parse_error(e)
+ logger.error(f"repositories.environment.update_env: {exc_str}")
raise Exception(f"Error updating environment: {str(e)}") from e
+ else:
+ return self
finally:
- self.__del__()
+ logger.info(
+ f"Call to repositories.environment.update_env completed; states: Env {hash(self.env)}, EnvID {self.env_id}"
+ )
async def get_env(self) -> "Union[Env, None]":
"""
- Gets a environment from the database
+ Gets a models.Env from the database
Returns:
- models.Env: Model environment object
+ models.Env
"""
try:
- environment = await self.collection.find_one({"env_id": self.env_id})
- if environment is not None:
- return Env.parse_obj(environment)
- return None
+ read_env = await self.collection.find_one({"env_id": self.env_id})
except Exception as e:
+ logger.error(f"repositories.environment.get_env: {str(e)}")
raise Exception(f"Error getting environment: {str(e)}") from e
+ else:
+ return Env.parse_obj(read_env) if read_env else None
+ finally:
+ logger.info(
+ f"Call to repositories.environment.get_env completed; states: Env {hash(self.env)}, EnvID {self.env_id}"
+ )
- async def delete_env(self) -> "DeleteResult":
+ async def delete_env(self):
"""
- Deletes a environment from the database
+ Deletes a models.Env from the database
Returns:
- DeleteResult: result of the delete operation
+ None
"""
try:
- return await self.collection.delete_one({"env_id": self.env_id})
+ await self.collection.delete_one({"env_id": self.env_id})
except Exception as e:
+ logger.error(f"repositories.environment.delete_env: {str(e)}")
raise Exception(f"Error deleting environment: {str(e)}") from e
finally:
- self.__del__()
+ logger.info(
+ f"Call to repositories.environment.delete_env completed; states: Env {hash(self.env)}, EnvID {self.env_id}"
+ )
diff --git a/lib/repositories/flight.py b/lib/repositories/flight.py
index 6f3f47b..3a14bc6 100644
--- a/lib/repositories/flight.py
+++ b/lib/repositories/flight.py
@@ -87,7 +87,9 @@ async def get_flight(self) -> "Union[Flight, None]":
models.Flight: Model flight object
"""
try:
- flight = await self.collection.find_one({"flight_id": self.flight_id})
+ flight = await self.collection.find_one(
+ {"flight_id": self.flight_id}
+ )
if flight is not None:
return Flight.parse_obj(flight)
return None
@@ -102,7 +104,9 @@ async def delete_flight(self) -> "DeleteResult":
DeleteResult: result of the delete operation
"""
try:
- return await self.collection.delete_one({"flight_id": self.flight_id})
+ return await self.collection.delete_one(
+ {"flight_id": self.flight_id}
+ )
except Exception as e:
raise Exception(f"Error deleting flight: {str(e)}") from e
finally:
diff --git a/lib/repositories/motor.py b/lib/repositories/motor.py
index 95883f1..552b90a 100644
--- a/lib/repositories/motor.py
+++ b/lib/repositories/motor.py
@@ -27,7 +27,9 @@ def __init__(self, motor: Motor = None, motor_id: str = None) -> None:
def __del__(self):
super().__del__()
- async def create_motor(self, motor_kind: str = "solid") -> "InsertOneResult":
+ async def create_motor(
+ self, motor_kind: str = "solid"
+ ) -> "InsertOneResult":
"""
Creates a motor in the database
@@ -50,7 +52,9 @@ async def create_motor(self, motor_kind: str = "solid") -> "InsertOneResult":
else:
return InsertOneResult(acknowledged=True, inserted_id=None)
- async def update_motor(self, motor_kind: str = "solid") -> "Union[int, None]":
+ async def update_motor(
+ self, motor_kind: str = "solid"
+ ) -> "Union[int, None]":
"""
Updates a motor in the database
@@ -96,7 +100,9 @@ async def delete_motor(self) -> "DeleteResult":
DeleteResult: result of the delete operation
"""
try:
- return await self.collection.delete_one({"motor_id": self.motor_id})
+ return await self.collection.delete_one(
+ {"motor_id": self.motor_id}
+ )
except Exception as e:
raise Exception(f"Error deleting motor: {str(e)}") from e
finally:
diff --git a/lib/repositories/repo.py b/lib/repositories/repo.py
index 24401c4..cfebf67 100644
--- a/lib/repositories/repo.py
+++ b/lib/repositories/repo.py
@@ -24,6 +24,3 @@ def __init__(self, collection: str):
)
self.db = self.client.rocketpy
self.collection = self.db[collection]
-
- def __del__(self):
- self.client.close()
diff --git a/lib/repositories/rocket.py b/lib/repositories/rocket.py
index 2d64fce..39536f5 100644
--- a/lib/repositories/rocket.py
+++ b/lib/repositories/rocket.py
@@ -27,7 +27,9 @@ def __init__(self, rocket: Rocket = None, rocket_id: str = None):
def __del__(self):
super().__del__()
- async def create_rocket(self, rocket_option: str = "Calisto") -> "InsertOneResult":
+ async def create_rocket(
+ self, rocket_option: str = "Calisto"
+ ) -> "InsertOneResult":
"""
Creates a rocket in the database
@@ -50,7 +52,9 @@ async def create_rocket(self, rocket_option: str = "Calisto") -> "InsertOneResul
else:
return InsertOneResult(acknowledged=True, inserted_id=None)
- async def update_rocket(self, rocket_option: str = "Calisto") -> "Union[int, None]":
+ async def update_rocket(
+ self, rocket_option: str = "Calisto"
+ ) -> "Union[int, None]":
"""
Updates a rocket in the database
@@ -81,7 +85,9 @@ async def get_rocket(self) -> "Union[Rocket, None]":
models.Rocket: Model rocket object
"""
try:
- rocket = await self.collection.find_one({"rocket_id": self.rocket_id})
+ rocket = await self.collection.find_one(
+ {"rocket_id": self.rocket_id}
+ )
if rocket is not None:
return Rocket.parse_obj(rocket)
return None
@@ -96,7 +102,9 @@ async def delete_rocket(self) -> "DeleteResult":
DeleteResult: result of the delete operation
"""
try:
- return await self.collection.delete_one({"rocket_id": self.rocket_id})
+ return await self.collection.delete_one(
+ {"rocket_id": self.rocket_id}
+ )
except Exception as e:
raise Exception(f"Error deleting rocket: {str(e)}") from e
finally:
diff --git a/lib/routes/environment.py b/lib/routes/environment.py
index e2e8f0c..d3c8dec 100644
--- a/lib/routes/environment.py
+++ b/lib/routes/environment.py
@@ -1,6 +1,7 @@
"""
Environment routes
"""
+
from fastapi import APIRouter
from lib.views.environment import (
@@ -30,38 +31,38 @@ async def create_env(env: Env) -> "EnvCreated":
Creates a new environment
## Args
- ``` Env object as a JSON ```
+ ``` models.Env JSON ```
"""
return await EnvController(env).create_env()
@router.get("/{env_id}")
-async def read_env(env_id: int) -> "Env":
+async def read_env(env_id: str) -> "Env":
"""
Reads an environment
## Args
- ``` env_id: Environment ID hash ```
+ ``` env_id: str ```
"""
- return await EnvController.get_env(env_id)
+ return await EnvController.get_env_by_id(env_id)
@router.put("/{env_id}")
-async def update_env(env_id: int, env: Env) -> "EnvUpdated":
+async def update_env(env_id: str, env: Env) -> "EnvUpdated":
"""
Updates an environment
## Args
```
- env_id: Environment ID hash
- env: Env object as JSON
+ env_id: str
+ env: models.Env JSON
```
"""
return await EnvController(env).update_env(env_id)
@router.delete("/{env_id}")
-async def delete_env(env_id: int) -> "EnvDeleted":
+async def delete_env(env_id: str) -> "EnvDeleted":
"""
Deletes an environment
@@ -72,22 +73,22 @@ async def delete_env(env_id: int) -> "EnvDeleted":
@router.get("/rocketpy/{env_id}")
-async def read_rocketpy_env(env_id: int) -> "EnvPickle":
+async def read_rocketpy_env(env_id: str) -> "EnvPickle":
"""
- Reads a rocketpy environment
+ Loads rocketpy.environment as jsonpickle string
## Args
- ``` env_id: Environment ID hash ```
+ ``` env_id: str ```
"""
- return await EnvController.get_rocketpy_env(env_id)
+ return await EnvController.get_rocketpy_env_as_jsonpickle(env_id)
@router.get("/{env_id}/simulate")
-async def simulate_env(env_id: int) -> "EnvSummary":
+async def simulate_env(env_id: str) -> "EnvSummary":
"""
- Simulates an environment
+ Loads rocketpy.environment simulation
## Args
- ``` env_id: Env ID hash ```
+ ``` env_id: str ```
"""
return await EnvController.simulate(env_id)
diff --git a/lib/routes/flight.py b/lib/routes/flight.py
index 5e2962b..8283085 100644
--- a/lib/routes/flight.py
+++ b/lib/routes/flight.py
@@ -1,6 +1,7 @@
"""
Flight routes
"""
+
from fastapi import APIRouter
from lib.views.flight import (
@@ -37,7 +38,9 @@ async def create_flight(
## Args
``` Flight object as JSON ```
"""
- return await FlightController(flight, rocket_option, motor_kind).create_flight()
+ return await FlightController(
+ flight, rocket_option, motor_kind
+ ).create_flight()
@router.get("/{flight_id}")
@@ -78,7 +81,10 @@ async def update_flight_env(flight_id: int, env: Env) -> "FlightUpdated":
@router.put("/{flight_id}/rocket")
async def update_flight_rocket(
- flight_id: int, rocket: Rocket, rocket_option: RocketOptions, motor_kind: MotorKinds
+ flight_id: int,
+ rocket: Rocket,
+ rocket_option: RocketOptions,
+ motor_kind: MotorKinds,
) -> "FlightUpdated":
"""
Updates flight rocket.
@@ -96,7 +102,10 @@ async def update_flight_rocket(
@router.put("/{flight_id}")
async def update_flight(
- flight_id: int, flight: Flight, rocket_option: RocketOptions, motor_kind: MotorKinds
+ flight_id: int,
+ flight: Flight,
+ rocket_option: RocketOptions,
+ motor_kind: MotorKinds,
) -> "FlightUpdated":
"""
Updates Flight object
@@ -107,9 +116,9 @@ async def update_flight(
flight: Flight object as JSON
```
"""
- return await FlightController(flight, rocket_option, motor_kind).update_flight(
- flight_id
- )
+ return await FlightController(
+ flight, rocket_option, motor_kind
+ ).update_flight(flight_id)
@router.delete("/{flight_id}")
diff --git a/lib/routes/motor.py b/lib/routes/motor.py
index c29d90b..85ad263 100644
--- a/lib/routes/motor.py
+++ b/lib/routes/motor.py
@@ -1,6 +1,7 @@
"""
Motor routes
"""
+
from fastapi import APIRouter
from lib.views.motor import (
diff --git a/lib/routes/rocket.py b/lib/routes/rocket.py
index fded8cc..4681763 100644
--- a/lib/routes/rocket.py
+++ b/lib/routes/rocket.py
@@ -1,6 +1,7 @@
"""
Rocket routes
"""
+
from fastapi import APIRouter
from lib.views.rocket import (
@@ -35,7 +36,9 @@ async def create_rocket(
## Args
``` Rocket object as a JSON ```
"""
- return await RocketController(rocket, rocket_option, motor_kind).create_rocket()
+ return await RocketController(
+ rocket, rocket_option, motor_kind
+ ).create_rocket()
@router.get("/{rocket_id}")
@@ -51,7 +54,10 @@ async def read_rocket(rocket_id: int) -> Rocket:
@router.put("/{rocket_id}")
async def update_rocket(
- rocket_id: int, rocket: Rocket, rocket_option: RocketOptions, motor_kind: MotorKinds
+ rocket_id: int,
+ rocket: Rocket,
+ rocket_option: RocketOptions,
+ motor_kind: MotorKinds,
) -> "RocketUpdated":
"""
Updates a rocket
@@ -62,9 +68,9 @@ async def update_rocket(
rocket: Rocket object as JSON
```
"""
- return await RocketController(rocket, rocket_option, motor_kind).update_rocket(
- rocket_id
- )
+ return await RocketController(
+ rocket, rocket_option, motor_kind
+ ).update_rocket(rocket_id)
@router.delete("/{rocket_id}")
diff --git a/pyproject.toml b/pyproject.toml
new file mode 100644
index 0000000..1ba712f
--- /dev/null
+++ b/pyproject.toml
@@ -0,0 +1,51 @@
+[project]
+name = "Infinity-API"
+version = "1.1.0"
+description = "RESTFULL open API for rocketpy"
+dynamic = ["dependencies"]
+requires-python = ">=3.12"
+authors = [
+ {name = "Gabriel Barberini", email = "gabrielbarberinirc@gmail.com"}
+]
+maintainers = [
+ {name = "Aasit", email = "aasitvora1999@gmail.com"},
+ {name = "Luiz Mota", email = "luiz.mota1999@usp.br"}
+]
+readme = "README.md"
+keywords = ["rocketpy", "rocket flight", "simulation", "API"]
+classifiers = [
+ "Development Status :: Alpha",
+ "Programming Language :: Python"
+]
+
+[tool.setuptools.dynamic]
+dependencies = { file = ["requirements.txt"] }
+
+[project.urls]
+Homepage = "http://api.rocketpy.org/"
+Documentation = "http://api.rocketpy.org/docs"
+Repository = "https://github.com/RocketPy-Team/infinity-api"
+"Bug Tracker" = "https://github.com/RocketPy-Team/Infinity-API/issues"
+
+[tool.black]
+line-length = 79
+include = '\.py$'
+skip-string-normalization = true
+
+[tool.pylint]
+max-line-length = 79
+disable = """
+ line-too-long,
+ duplicate-code,
+ use-dict-literal,
+ missing-module-docstring,
+ missing-function-docstring,
+ missing-class-docstring,
+ too-few-public-methods,
+ too-many-public-methods,
+ too-many-instance-attributes,
+ logging-fstring-interpolation,
+ broad-exception-raised,
+ import-error,
+ protected-access
+"""
diff --git a/requirements.txt b/requirements.txt
index 7dd605c..be65cb7 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -6,4 +6,4 @@ pymongo
jsonpickle
gunicorn
uvicorn
-git+https://github.com/RocketPy-Team/RocketPy
+rocketpy
diff --git a/test/Infinity-API.postman_collection.json b/tests/Infinity-API.postman_collection.json
similarity index 100%
rename from test/Infinity-API.postman_collection.json
rename to tests/Infinity-API.postman_collection.json