Squashed 'utils_v2/' content from commit 88e444a

git-subtree-dir: utils_v2
git-subtree-split: 88e444ac57ca6c090736645616d8a8a2d2af367b
This commit is contained in:
2025-11-14 16:53:30 +05:30
commit a1c1853ca5
226 changed files with 151722 additions and 0 deletions
View File
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1278
View File
File diff suppressed because it is too large Load Diff
+164
View File
@@ -0,0 +1,164 @@
"""
AUTHOR:
Khushal P Soonderji
DATE:
Thursday, 12th Sept., 2024
OBJECTIVE:
To maintain all status codes in one place.
REFERENCES:
N/A
DOWNLOADS:
N/A
"""
# *****************************************************************************************************************
# ***** ****
# *** IMPORT ***
# ***** ****
# *****************************************************************************************************************
from enum import Enum, unique
# *****************************************************************************************************************
# ***** ****
# *** MACROS / ONE-TIME INIT ***
# ***** ****
# *****************************************************************************************************************
@unique
class HttpCodes(Enum):
"""
Commonly used standard HTTP status codes.
Can be sent after an API Call is processed.
Refer to: https://http.dev/status
NOTE: THIS LIST IS NOT EXHAUSTIVE!
"""
# 1XX - Informational:
CONTINUE = 100 # .............. https://http.dev/102
SWITCHING_PROTOCOLS = 101 # ... https://http.dev/101
PROCESSING = 102 # ............ https://http.dev/102
EARLY_HINTS = 103 # ........... https://http.dev/103
# 2XX - Success:
SUCCESS = 200 # .................. https://http.dev/200
CREATED = 201 # .................. https://http.dev/201
ACCEPTED = 202 # ................. https://http.dev/202
NON_AUTHORITATIVE_INFO = 203 # ... https://http.dev/203
NO_CONTENT = 204 # ............... https://http.dev/204
RESET_CONTENT = 205 # ............ https://http.dev/205
PARTIAL_CONTENT = 206 # .......... https://http.dev/206
MULTI_STATUS = 207 # ............. https://http.dev/207
ALREADY_REPORTED = 208 # ......... https://http.dev/208
THIS_IS_FINE = 218 # ............. https://http.dev/218
IM_USED = 226 # .................. https://http.dev/226
# 3XX - Redirection:
MULTIPLE_CHOICES = 300 # ..... https://http.dev/300
MOVED_PERMANENTLY = 301 # .... https://http.dev/301
MOVED_TEMPORARILY = 302 # .... https://http.dev/302
SEE_OTHER = 303 # ............ https://http.dev/303
NOT_MODIFIED = 304 # ......... https://http.dev/304
USE_PROXY = 305 # ............ https://http.dev/305
SWITCH_PROXY = 306 # ......... https://http.dev/306
TEMPORARY_REDIRECT = 307 # ... https://http.dev/307
PERMANENT_REDIRECT = 308 # ... https://http.dev/308
# 4XX - Client Errors:
BAD_REQUEST = 400 # ..................... https://http.dev/401
UNAUTHORIZED = 401 # .................... https://http.dev/401
PAYMENT_REQUIRED = 402 # ................ https://http.dev/402
FORBIDDEN = 403 # ....................... https://http.dev/403
NOT_FOUND = 404 # ....................... https://http.dev/404
METHOD_NOT_ALLOWED = 405 # .............. https://http.dev/405
NOT_ACCEPTABLE = 406 # .................. https://http.dev/406
PROXY_AUTH_REQUIRED = 407 # ............. https://http.dev/407
REQUEST_TIMEOUT = 408 # ................. https://http.dev/408
CONFLICT = 409 # ........................ https://http.dev/409
GONE = 410 # ............................ https://http.dev/410
LENGTH_REQUIRED = 411 # ................. https://http.dev/411
PRECONDITION_FAILED = 412 # ............. https://http.dev/412
PAYLOAD_TOO_LARGE = 413 # ............... https://http.dev/413
URI_TOO_LONG = 414 # .................... https://http.dev/414
UNSUPPORTED_MEDIA_TYPE = 415 # .......... https://http.dev/415
PAGE_EXPIRED = 419 # .................... https://http.dev/419
TOO_MANY_REQUESTS = 429 # ............... https://http.dev/429
UNAVAILABLE_FOR_LEGAL_REASONS = 451 # ... https://http.dev/451
INVALID_TOKEN = 498 # ................... https://http.dev/498
CLIENT_CLOSED_REQUEST = 499 # ........... https://http.dev/499
# 5XX - Server Errors:
INTERNAL_SERVER_ERROR = 500 # ........... https://http.dev/500
NOT_IMPLEMENTED = 501 # ................. https://http.dev/501
BAD_GATEWAY = 502 # ..................... https://http.dev/502
SERVICE_UNAVAILABLE = 503 # ............. https://http.dev/503
GATEWAY_TIMEOUT = 504 # ................. https://http.dev/504
HTTP_VERSION_NOT_SUPPORTED = 505 # ...... https://http.dev/505
VARIANT_ALSO_NEGOTIATES = 506 # ......... https://http.dev/506
INSUFFICIENT_STORAGE = 507 # ............ https://http.dev/507
LOOP_DETECTED = 508 # ................... https://http.dev/508
BANDWIDTH_LIMIT_EXCEEDED = 509 # ........ https://http.dev/509
WEB_SERVER_DOWN = 521 # ................. https://http.dev/521
ORIGIN_IS_UNREACHABLE = 523 # ........... https://http.dev/523
SERVICE_IS_OVERLOADED = 529 # ........... https://http.dev/529
NETWORK_READ_TIMEOUT_ERROR = 598 # ...... https://http.dev/598
NETWORK_CONNECT_TIMEOUT_ERROR = 599 # ... https://http.dev/599
# ---------------------------------------------------------------------------------------------------------------------
@unique
class StatusCodes(Enum):
"""
To be used internally within the context of your service. Customize these to match your service.
The format is: (SUCCESS_INDICATOR, INTERNAL_NUMERIC_CODE, HTTP_CODE)
Example: (True, 1, 200)
"""
# Legacy Codes:
OK = (True, 1, HttpCodes.SUCCESS.value)
FAILED = (False, 0, HttpCodes.INTERNAL_SERVER_ERROR.value)
PARTIAL_SUCCESS = (True, 2, HttpCodes.PARTIAL_CONTENT.value)
PARTIAL_FAILURE = (False, 3, HttpCodes.PARTIAL_CONTENT.value)
# Authentication Codes:
LOGGED_IN_SUCCESSFULLY = (True, 200, HttpCodes.SUCCESS.value)
LOGIN_FAILED = (False, 201, HttpCodes.UNAUTHORIZED.value)
INVALID_SESSION_TOKEN = (False, 202, HttpCodes.UNAUTHORIZED.value)
AUTHENTICATION_DETAILS_INCOMPLETE = (False, 203, HttpCodes.BAD_REQUEST.value)
# Authorization Codes:
AUTHORIZED_SUCCESSFULLY = (True, 300, HttpCodes.SUCCESS.value)
NOT_ALLOWED = (False, 301, HttpCodes.FORBIDDEN.value)
AUTHORIZATION_DETAILS_INCOMPLETE = (False, 302, HttpCodes.BAD_REQUEST.value)
AUTHORIZATION_FAILED = (False, 303, HttpCodes.UNAUTHORIZED.value)
# General failures:
DOWN_FOR_MAINTENANCE = (False, 800, HttpCodes.SERVICE_UNAVAILABLE.value)
UNKNOWN_ERROR = (False, 801, HttpCodes.INTERNAL_SERVER_ERROR.value)
DATA_INCOMPLETE = (False, 802, HttpCodes.BAD_REQUEST.value)
HEADERS_INCOMPLETE = (False, 803, HttpCodes.BAD_REQUEST.value)
FILES_MISSING = (False, 804, HttpCodes.BAD_REQUEST.value)
CLIENT_CLOSED_REQUEST = (False, 805, HttpCodes.CLIENT_CLOSED_REQUEST.value)
# Validation failure:
DATA_VALIDATION_FAILURE = (False, 900, HttpCodes.BAD_REQUEST.value)
RATE_LIMIT_EXCEEDED = (False, 901, HttpCodes.TOO_MANY_REQUESTS.value)
+143
View File
@@ -0,0 +1,143 @@
"""
AUTHOR:
Khushal P Soonderji
DATE:
Thursday, 12th Sept., 2024
OBJECTIVE:
To have a structure to the response sent from the API calls.
REFERENCES:
N/A
DOWNLOADS:
N/A
"""
# *****************************************************************************************************************
# ***** ****
# *** IMPORT ***
# ***** ****
# *****************************************************************************************************************
# System-level activities:
import os
import distro
import socket
import platform
# For data-modelling:
from pydantic import BaseModel, Field
from typing import Any, Optional, List, Literal
# To work with date and time:
import datetime
# *****************************************************************************************************************
# ***** ****
# *** MACROS / ONE-TIME INIT ***
# ***** ****
# *****************************************************************************************************************
# Info for logging that will stay constant during runtime:
SERVER_HOSTNAME = str(socket.gethostname()) # ... Gives the machine's name.
SERVER_LOGIN = str(os.getlogin()) # ............. Gives the user that is logged in.
PLATFORM_INFO = platform.uname()
HOST_OS = f"{platform.system() or 'N/A'} ({distro.name(True) or 'N/A'})"
HOST_CPU = f"{PLATFORM_INFO.processor} ({PLATFORM_INFO.machine})"
# *****************************************************************************************************************
# ***** ****
# *** VARIABLES ***
# ***** ****
# *****************************************************************************************************************
# --- Nothing Yet
# *****************************************************************************************************************
# ***** ****
# *** CLASSES ***
# ***** ****
# *****************************************************************************************************************
class APILogModel(BaseModel):
# To identify the machine the code is running on.
# DO NOT MODIFY THESE:
hostname: str = SERVER_HOSTNAME
login: str = SERVER_LOGIN
platform: str = f"{PLATFORM_INFO.system} (v{PLATFORM_INFO.version}, release {PLATFORM_INFO.release}) on {PLATFORM_INFO.machine}"
os: str = HOST_OS
cpu: str = HOST_CPU
# Can modify these:
pid: Optional[Any] = None
ppid: Optional[Any] = None
# To identify the project and actions:
project: Optional[str] = None
log: str
operation: str
apiVer: Optional[str] = None
logId: Optional[str] = None
logChain: Optional[str] = None
# Timing metrics:
ts: datetime.datetime
tat: float
cpuTime: float
# To understand the request that came in:
sessionInfo: Optional[Any] = None
method: Optional[str] = None
url: Optional[str] = None
route: Optional[str] = None
headers: Optional[Any] = None
data: Optional[Any] = None
files: Optional[Any] = None
# To understand the output that went out:
exception: Optional[Any] = None
response: Optional[Any] = None
httpCode: Optional[int] = None
# *****************************************************************************************************************
# ***** ****
# *** FUNCTIONS ***
# ***** ****
# *****************************************************************************************************************
# --- Nothing Yet
# *****************************************************************************************************************
# ***** ****
# *** MAIN PROGRAM ***
# ***** ****
# *****************************************************************************************************************
if __name__ == "__main__":
my_log = APILogModel(
log = "internal"
)
print(my_log)
+142
View File
@@ -0,0 +1,142 @@
"""
AUTHOR:
Khushal P Soonderji
DATE:
Thursday, 12th Sept., 2024
OBJECTIVE:
To have a structure to the response sent from the API calls.
REFERENCES:
N/A
DOWNLOADS:
N/A
"""
# *****************************************************************************************************************
# ***** ****
# *** IMPORT ***
# ***** ****
# *****************************************************************************************************************
# For data-modelling:
from pydantic import BaseModel
from typing import Any, Optional, List
# My utils:
from utils_v2.api.codes import StatusCodes, HttpCodes
# *****************************************************************************************************************
# ***** ****
# *** MACROS / ONE-TIME INIT ***
# ***** ****
# *****************************************************************************************************************
# --- Nothing Yet
# *****************************************************************************************************************
# ***** ****
# *** VARIABLES ***
# ***** ****
# *****************************************************************************************************************
# --- Nothing Yet
# *****************************************************************************************************************
# ***** ****
# *** CLASSES ***
# ***** ****
# *****************************************************************************************************************
class ResponseModel(BaseModel):
"""
A model for how the response should be when developing API endpoints.
"""
# The fields that you want in your response:
status_code: StatusCodes
message: Optional[str | List] = None
data: Optional[Any] = None
seconds: Optional[float | int] = None
log_id: Optional[str] = None
http_code: Optional[HttpCodes] = None
api_version: Optional[str] = None
@property
def success(self) -> bool:
"""
A quick wy to check if the response indicates a successful outcome.
"""
return True if self.status_code.value[0] else False
def for_quart(self):
"""
Call this when you are using either Flask or Quart as your framework.
:return: The output as expected by Flask and Quart.
"""
# Figure out the HTTP code:
response_http_code = self.http_code.value if self.http_code is not None else self.status_code.value[2]
# Construct the basic structure:
response_dict = {
"status": 1 if self.status_code.value[0] else 0,
"code": response_http_code,
"message": self.message or self.status_code.name.replace("_", " ").lower(),
"data": self.data,
"apiVer": self.api_version
}
# Now add the additional fields:
if self.seconds is not None: response_dict["seconds"] = self.seconds
if self.log_id is not None: response_dict["logId"] = self.log_id
# Done here:
return response_dict, response_http_code
# *****************************************************************************************************************
# ***** ****
# *** FUNCTIONS ***
# ***** ****
# *****************************************************************************************************************
# --- Nothing Yet
# *****************************************************************************************************************
# ***** ****
# *** MAIN PROGRAM ***
# ***** ****
# *****************************************************************************************************************
if __name__ == "__main__":
my_response = ResponseModel(
status_code = StatusCodes.RATE_LIMIT_EXCEEDED
)
my_response.log_id = "abc123"
print(my_response.for_quart())