Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

API Refactoring #20

Merged
merged 30 commits into from
May 31, 2024
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
b7e48ff
implements pyproject toml and change test filesystem
GabrielBarberini Apr 14, 2024
9eac5dc
enhances error log parsing
GabrielBarberini May 9, 2024
7798064
refactors controllers/flight
GabrielBarberini May 19, 2024
d252369
adjusts controllers.environment method signatures
GabrielBarberini May 19, 2024
c6198e0
sanitizes controllers.flight dependencies
GabrielBarberini May 19, 2024
1c26784
initiates controllers.motor refactoring
GabrielBarberini May 19, 2024
72b3321
refactors controllers.rocket
GabrielBarberini May 19, 2024
e9e392f
adapts rocket repository to comply with rocket controller
GabrielBarberini May 20, 2024
169a8c7
adapts rocket routes to comply with refactored rocket controller
GabrielBarberini May 20, 2024
c02b505
refactors repositories
GabrielBarberini May 20, 2024
873f96e
removes forward reference and improves logs wording
GabrielBarberini May 20, 2024
f2a89a9
refactors motor controller nad adapts adjacent controllers accordingly
GabrielBarberini May 21, 2024
1008c5a
renames engine files
GabrielBarberini May 21, 2024
e516fd6
refactors models
GabrielBarberini May 21, 2024
ff4859f
refactors repositories
GabrielBarberini May 21, 2024
ae9dbd2
refactors routes
GabrielBarberini May 21, 2024
803f0db
general refactoring
GabrielBarberini May 22, 2024
7f50464
addresses review comments
GabrielBarberini May 22, 2024
7879742
fixes missing importing
GabrielBarberini May 22, 2024
77efcc2
implements db context manager
GabrielBarberini May 24, 2024
dc40720
addresses review comments
GabrielBarberini May 24, 2024
288ad39
Update lib/repositories/rocket.py
GabrielBarberini May 24, 2024
7d615c7
updates repositories init
GabrielBarberini May 24, 2024
fc730e6
implements async context manager and threading lock
GabrielBarberini May 29, 2024
05aa6fd
fixes async issues
GabrielBarberini May 29, 2024
ff510c8
minor bug fixing
GabrielBarberini May 29, 2024
95a99fc
addresses pylint complains
GabrielBarberini May 29, 2024
fea731f
removes redundant event set and ensures thread lock on finalization
GabrielBarberini May 29, 2024
5b5fa81
removes useless collection setter
GabrielBarberini May 30, 2024
9ac550b
implements stdout log handler
GabrielBarberini May 30, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion lib/__init__.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
# 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',
)


def parse_error(error):
exc_type = type(error).__name__
exc_obj = f"{error}".replace("\n", " ").replace(" ", " ")
return f"{exc_type} exception: {exc_obj}"


from .api import app # noqa
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the reason for brining this line to the bottom of the file?

Suggested change
from .api import app # noqa
from .api import app # noqa

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To avoid circular imports. I use parse_error on api.py as well, and since importing app from it means the importing system will run over the whole file, it ended up breaking as parse_error was not ready yet.

7 changes: 3 additions & 4 deletions lib/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from fastapi.openapi.utils import get_openapi
from fastapi.responses import RedirectResponse, JSONResponse

from lib import logging
from lib import logging, parse_error
from lib.routes import flight, environment, motor, rocket

logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -84,9 +84,8 @@ async def __perform_healthcheck():
async def validation_exception_handler(
request: Request, exc: RequestValidationError
):
exc_str = f"{exc}".replace("\n", " ").replace(" ", " ")
exc_str = parse_error(exc)
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
content=exc_str, status_code=status.HTTP_422_UNPROCESSABLE_ENTITY
)
5 changes: 0 additions & 5 deletions lib/controllers/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1 @@
# lib/controllers/__init__.py


def parse_error(e):
exc_str = f"{e}".replace("\n", " ").replace(" ", " ")
return exc_str
91 changes: 44 additions & 47 deletions lib/controllers/environment.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@
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 import logging, parse_error
from lib.models.environment import Env
from lib.repositories.environment import EnvRepository
from lib.views.environment import (
Expand All @@ -30,7 +29,7 @@ class EnvController:

Enables:
- Simulation of RocketPyEnvironment from models.Env
- CRUD operations over modeols.Env on the database
- CRUD operations over models.Env on the database
"""

def __init__(self, env: Env):
Expand All @@ -45,7 +44,7 @@ def env(self, env: Env):
self._env = env

@staticmethod
async def get_rocketpy_env(env: Env) -> RocketPyEnvironment:
def get_rocketpy_env(env: Env) -> RocketPyEnvironment:
"""
Get the rocketpy env object.

Expand All @@ -63,38 +62,36 @@ async def get_rocketpy_env(env: Env) -> RocketPyEnvironment:
)
return rocketpy_env

async def create_env(self) -> "Union[EnvCreated, HTTPException]":
async def create_env(self) -> Union[EnvCreated, HTTPException]:
"""
Create a env in the database.

Returns:
views.EnvCreated
"""
try:
created_env = await EnvRepository(
environment=self.env
).create_env()
await EnvRepository.fetch_env(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=f"Failed to create environment: {e}",
detail=f"Failed to create environment: {exc_str}",
) from e
else:
return EnvCreated(env_id=created_env.env_id)
return EnvCreated(env_id=self.env.env_id)
finally:
logger.info(
f"Call to controllers.environment.create_env completed; params: Env {hash(self.env)}"
f"Call to controllers.environment.create_env completed for Env {hash(self.env)}"
)

@staticmethod
async def get_env_by_id(env_id: int) -> "Union[Env, HTTPException]":
async def get_env_by_id(env_id: str) -> Union[Env, HTTPException]:
"""
Get a env from the database.

Args:
env_id: int
env_id: str

Returns:
models.Env
Expand All @@ -103,13 +100,13 @@ async def get_env_by_id(env_id: int) -> "Union[Env, HTTPException]":
HTTP 404 Not Found: If the env is not found in the database.
"""
try:
read_env = await EnvRepository(env_id=env_id).get_env()
read_env = await EnvRepository().get_env_by_id(env_id)
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}",
detail=f"Failed to read environment: {exc_str}",
) from e
else:
if read_env:
Expand All @@ -120,19 +117,19 @@ async def get_env_by_id(env_id: int) -> "Union[Env, HTTPException]":
)
finally:
logger.info(
f"Call to controllers.environment.get_env_by_id completed; params: EnvID {env_id}"
f"Call to controllers.environment.get_env_by_id completed for Env {env_id}"
)

@classmethod
async def get_rocketpy_env_as_jsonpickle(
cls,
env_id: int,
) -> "Union[EnvPickle, HTTPException]":
env_id: str,
) -> Union[EnvPickle, HTTPException]:
"""
Get rocketpy.Environmnet as jsonpickle string.

Args:
env_id: int
env_id: str

Returns:
views.EnvPickle
Expand All @@ -142,6 +139,7 @@ async def get_rocketpy_env_as_jsonpickle(
"""
try:
read_env = await cls.get_env_by_id(env_id)
rocketpy_env = cls.get_rocketpy_env(read_env)
except HTTPException as e:
raise e from e
except Exception as e:
Expand All @@ -151,26 +149,25 @@ async def get_rocketpy_env_as_jsonpickle(
)
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"Failed to read environment: {e}",
detail=f"Failed to read environment: {exc_str}",
) 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}"
f"Call to controllers.environment.get_rocketpy_env_as_jsonpickle completed for Env {env_id}"
)

async def update_env(
self, env_id: int
) -> "Union[EnvUpdated, HTTPException]":
async def update_env_by_id(
self, env_id: str
) -> Union[EnvUpdated, HTTPException]:
"""
Update a env in the database.
Update a models.Env in the database.

Args:
env_id: int
env_id: str

Returns:
views.EnvUpdated
Expand All @@ -179,33 +176,31 @@ async def update_env(
HTTP 404 Not Found: If the env is not found in the database.
"""
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
env_repo = await EnvRepository.fetch_env(self.env).create_env()
await env_repo.delete_env_by_id(env_id)
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=f"Failed to update environment: {e}",
detail=f"Failed to update environment: {exc_str}",
) from e
else:
return EnvUpdated(new_env_id=updated_env.env_id)
return EnvUpdated(new_env_id=self.env.env_id)
finally:
logger.info(
f"Call to controllers.environment.update_env completed; params: EnvID {env_id}, Env {hash(self.env)}"
f"Call to controllers.environment.update_env completed for Env {env_id}; Env {hash(self.env)}"
)

@staticmethod
async def delete_env(env_id: str) -> "Union[EnvDeleted, HTTPException]":
async def delete_env_by_id(
env_id: str,
) -> Union[EnvDeleted, HTTPException]:
"""
Delete a env from the database.
Delete a models.Env from the database.

Args:
env_id: int
env_id: str

Returns:
views.EnvDeleted
Expand All @@ -214,28 +209,30 @@ async def delete_env(env_id: str) -> "Union[EnvDeleted, HTTPException]":
HTTP 404 Not Found: If the env is not found in the database.
"""
try:
await EnvRepository(env_id=env_id).delete_env()
await EnvRepository().delete_env_by_id(env_id)
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=f"Failed to delete environment: {e}",
detail=f"Failed to delete environment: {exc_str}",
) 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}"
f"Call to controllers.environment.delete_env completed for Env {env_id}"
)

@classmethod
async def simulate(cls, env_id: int) -> "Union[EnvSummary, HTTPException]":
async def simulate_env(
cls, env_id: str
) -> Union[EnvSummary, HTTPException]:
"""
Simulate a rocket environment.

Args:
env_id: int.
env_id: str.

Returns:
views.EnvSummary
Expand All @@ -245,7 +242,7 @@ async def simulate(cls, env_id: int) -> "Union[EnvSummary, HTTPException]":
"""
try:
read_env = await cls.get_env_by_id(env_id)
rocketpy_env = await cls.get_rocketpy_env(read_env)
rocketpy_env = cls.get_rocketpy_env(read_env)
env_simulation_numbers = EnvData.parse_obj(
rocketpy_env.all_info_returned()
)
Expand All @@ -262,11 +259,11 @@ async def simulate(cls, env_id: int) -> "Union[EnvSummary, HTTPException]":
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}",
detail=f"Failed to simulate environment: {exc_str}",
) from e
else:
return env_summary
finally:
logger.info(
f"Call to controllers.environment.simulate completed; params: EnvID {env_id}"
f"Call to controllers.environment.simulate completed for Env {env_id}"
)
Loading
Loading