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

DB and API Refactors #99

Merged
merged 5 commits into from
Dec 19, 2024
Merged

Conversation

OdyAsh
Copy link
Collaborator

@OdyAsh OdyAsh commented Dec 8, 2024

feat: loguru, cors_ok & DB Code Refactors

Also: Zrok Notes, Meta API Notes

Regarding ansari_db.py's code refactors:

  • the execute_query() might initially seem complicated, but it becomes obvious once you see how it's called in different functions.
    • However, if it's still too complicated, I'll revert it 👍
    • I've added this function to avoid code duplications, for example when adding debug logs (which facilitates the process of understanding the DB logic flow).
    • Maybe in the future, I'll add try/except wrapper as well to this function, since this repetitive error-handling blocks take up code size in the rest of ansari_db.py's functions.

Regarding cors_ok logic in main_api.py:

  • Small refactors to unnest code by one level :]

Regarding Zrok:

  • I've added these comments to freeze the callback URL used in the testing app of Meta's developer page. Now, any future WhatsApp tester needs only to know the ZROK_SHARE_TOKEN, instead of changing the callback URL each time they want to debug/test new WhatsApp features.

Regarding Loguru:

  • Benefits over standard logging and migration notes are mentioned here.

Copy link
Collaborator

@waleedkadous waleedkadous left a comment

Choose a reason for hiding this comment

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

Once we've addressed the model breakage good to go.

There are some fuzzy bits of feedback here; don't feel I know Python well enough to be sure of myself.

# a new one will have to be generated, then added to Meta's callback URL of the *testing* app
# (Noting that the *production* app's callback URL will be different anyway, so the 3rd party won't be able to access that app)
# (but we still don't want random calls to be made to our testing app, so that's why we'll still have to change an exposed token :])

Copy link
Collaborator

Choose a reason for hiding this comment

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

Love the extensive comments.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Thank you! I was thinking of other ways to document these comments externally, but until we figure something out, will stick to inline commenting as I do think these should help newcomers .

},
"http_version": "1.1",
"server": ["127.0.0.1", 8000], // When running locally
"client": ["127.0.0.1", 11563], // The port here changes dynamically
Copy link
Collaborator

Choose a reason for hiding this comment

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

Is there a better way of handling this?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

If "this" refers to the "port changes dynamically" comment, then I don't know...

To be honest, I don't even know why this port changes ... even though I've bounded Ansari frontend with port 3000 ... unless "client" here refers to something else, since origin does indeed have port 3000 ...

or only after all of them are executed.

Returns:
Union[Optional[List], List[Optional[List]]]:
Copy link
Collaborator

Choose a reason for hiding this comment

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

What if we simplified this a bit and made this always return a list (even if there is only one element)?

I am not sure so this is only a suggestion, but having multiple return types feels slightly clumsy to me.

image

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Good point, will adjust it 👍

Also, I love the attached screenshot; any attempts to explain reasoning/advantages/disadvantages are always appreciated :]

which_fetch = [which_fetch] * len(query)

caller_function_name = inspect.stack()[1].function
logger.debug(f"Function {caller_function_name}() \nis running queries: \n{query} \nwith params: \n{params}")
Copy link
Collaborator

Choose a reason for hiding this comment

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

What happens if this is called from an object method? Just curious.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I don't quite get your question... if I understand correctly, an "object's method" is like account_exists() method in Ansari class (object) ... all other functions that are in this file are also methods which I call in it the `_execute_query() method.

If you're asking what this code snippet does in general... then the answer is this: it fetches the name of the function/method that called this _execute_query() method (e.g., "account_exists", etc.)

Hopefully I understood your question correctly 🙌

@@ -109,13 +112,95 @@ def _get_token_from_request(self, request: Request) -> str:
detail="Authorization header is malformed",
)

def _execute_query(
Copy link
Collaborator

Choose a reason for hiding this comment

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

You realize we are taking baby steps towards building an ORM, right ? :-)

Wonder if we should just fully commit to an ORM.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Totally slipped my mind, I don't know how!

I don't mind later changing this code to support ORM ... my main motivation on why I created this method, was that I found duplications in other methods, so I wanted to refactor, + add logs ... but if we're headed towards ORM, no problems at all 👍

result = cur.fetchall()

# Remove possible SQL comments at the start of the q variable
q = re.sub(r"^\s*--.*\n", "", q, flags=re.MULTILINE)
Copy link
Collaborator

Choose a reason for hiding this comment

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

This feels a bit weird to me. Why is this necessary? Why is it two dashes instead of the normal 3? Does pysql not handle comments?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I can adjust the regex to activate on 2 or 3 ISA ... actually, this regex isn't that necessary 😅 , as we don't have any SQL statements starting with dashes in our code, but I will adjust the regex nonetheless 🙌

from functools import lru_cache
from pathlib import Path
from typing import Literal

from pydantic import DirectoryPath, Field, PostgresDsn, SecretStr, field_validator
from pydantic_settings import BaseSettings, SettingsConfigDict

# Can't use get_logger() here due to circular import
logger = logging.getLogger(__name__)
# # Can't use get_logger() here due to circular import
Copy link
Collaborator

Choose a reason for hiding this comment

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

Unnecessary #?

Copy link
Collaborator Author

@OdyAsh OdyAsh Dec 17, 2024

Choose a reason for hiding this comment

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

Nice catch! Will replace "# #" with "#" 👍



# Defined in a separate file to avoid circular imports between main_*.py files
def validate_cors(request: Request, settings: Settings = Depends(get_settings)) -> bool:
Copy link
Collaborator

Choose a reason for hiding this comment

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

Like this! Are there othetr helpers that should be moved in here?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Thanks!

Whenever I find code that is used in multiple files (e.g., validate_cors is used in main_api and main_whatsapp), I'll move them here, but now I can't think of any.

# Defined in a separate file to avoid circular imports between main_*.py files
def validate_cors(request: Request, settings: Settings = Depends(get_settings)) -> bool:
try:
logger.info(f"Headers of raw request are: {request.headers}")
Copy link
Collaborator

Choose a reason for hiding this comment

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

All headers feel more like a "debug" level log.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Makes sense, will adjust ISA 👍

@waleedkadous
Copy link
Collaborator

waleedkadous commented Dec 17, 2024 via email

@OdyAsh OdyAsh merged commit 2c4c3d8 into ansari-project:main Dec 19, 2024
1 check failed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants