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