Skip to content

Commit

Permalink
🔧 Enhance the Project Dependencies to be fully migrated to UV (#711)
Browse files Browse the repository at this point in the history
  • Loading branch information
yezz123 authored Dec 21, 2024
2 parents c9d49f3 + f352b6f commit 7afa246
Show file tree
Hide file tree
Showing 34 changed files with 828 additions and 1,962 deletions.
10 changes: 5 additions & 5 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ jobs:
uv-venv: ".venv"

- name: Install Dependencies
run: uv sync
run: uv sync --group lint --all-extras

- name: Typecheck with mypy
run: bash scripts/mypy.sh
Expand Down Expand Up @@ -61,7 +61,7 @@ jobs:
uv-venv: ".venv"

- name: Install Dependencies
run: uv sync
run: uv sync --group test --all-extras

- name: Freeze Dependencies
run: uv pip freeze
Expand All @@ -75,7 +75,7 @@ jobs:
uses: codecov/codecov-action@v5
with:
token: ${{ secrets.CODECOV_TOKEN }}
file: ./coverage.xml
files: ./coverage.xml

tests-pydantic-v1:

Expand Down Expand Up @@ -106,7 +106,7 @@ jobs:
uv-venv: ".venv"

- name: Install Dependencies
run: uv sync
run: uv sync --group test --all-extras

- name: Install pydantic v1
run: uv pip install pydantic==1.10.17
Expand All @@ -123,7 +123,7 @@ jobs:
uses: codecov/codecov-action@v5
with:
token: ${{ secrets.CODECOV_TOKEN }}
file: ./coverage.xml
files: ./coverage.xml

test-extra:

Expand Down
27 changes: 12 additions & 15 deletions authx/_internal/_callback.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@


class _CallbackHandler(Generic[T]):
"""
Base class for callback handlers in AuthX.
"""Base class for callback handlers in AuthX.
Args:
Generic (T): Model type
Expand Down Expand Up @@ -41,56 +40,54 @@ def __init__(self, model: Optional[T] = None) -> None:

@property
def is_model_callback_set(self) -> bool:
"""Check if callback is set for model instance"""
"""Check if callback is set for model instance."""
return self.callback_get_model_instance is not None

@property
def is_token_callback_set(self) -> bool:
"""Check if callback is set for token"""
"""Check if callback is set for token."""
return self.callback_is_token_in_blocklist is not None

def _check_model_callback_is_set(self, ignore_errors: bool = False) -> bool:
"""Check if callback is set for model instance and raise exception if not set"""
"""Check if callback is set for model instance and raise exception if not set."""
if self.is_model_callback_set:
return True
if not ignore_errors:
raise self._callback_model_set_exception
return False

def _check_token_callback_is_set(self, ignore_errors: bool = False) -> bool:
"""Check if callback is set for token and raise exception if not set"""
"""Check if callback is set for token and raise exception if not set."""
if self.is_token_callback_set:
return True
if not ignore_errors:
raise self._callback_token_set_exception
return False

def set_callback_get_model_instance(self, callback: ModelCallback[T]) -> None:
"""Set callback for model instance"""
"""Set callback for model instance."""
self.callback_get_model_instance = callback

def set_callback_token_blocklist(self, callback: TokenCallback) -> None:
"""Set callback for token"""
"""Set callback for token."""
self.callback_is_token_in_blocklist = callback

def set_subject_getter(self, callback: ModelCallback[T]) -> None:
"""Set the callback to run for subject retrieval and serialization"""
"""Set the callback to run for subject retrieval and serialization."""
self.set_callback_get_model_instance(callback)

def set_token_blocklist(self, callback: TokenCallback) -> None:
"""Set the callback to run for validation of revoked tokens"""
"""Set the callback to run for validation of revoked tokens."""
self.set_callback_token_blocklist(callback)

def _get_current_subject(self, uid: str, **kwargs: ParamSpecKwargs) -> Optional[T]:
"""Get current model instance from callback"""
"""Get current model instance from callback."""
self._check_model_callback_is_set()
callback: Optional[ModelCallback[T]] = self.callback_get_model_instance
return callback(uid, **kwargs) if callback is not None else None # type: ignore

def is_token_in_blocklist(
self, token: Optional[str], **kwargs: ParamSpecKwargs
) -> bool:
"""Check if token is in blocklist"""
def is_token_in_blocklist(self, token: Optional[str], **kwargs: ParamSpecKwargs) -> bool:
"""Check if token is in blocklist."""
if self._check_token_callback_is_set(ignore_errors=True):
callback: Optional[TokenCallback] = self.callback_is_token_in_blocklist
if callback is not None and token is not None:
Expand Down
18 changes: 7 additions & 11 deletions authx/_internal/_error.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Optional, Type
from typing import Optional

from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
Expand All @@ -7,7 +7,7 @@


class _ErrorHandler:
"""Base Handler for FastAPI handling AuthX exceptions"""
"""Base Handler for FastAPI handling AuthX exceptions."""

MSG_TokenError = "Token Error"
MSG_MissingTokenError = "Missing JWT in request"
Expand All @@ -28,7 +28,7 @@ async def _error_handler(
status_code: int,
message: Optional[str],
) -> JSONResponse:
"""Generate the async function to be decorated by `FastAPI.exception_handler` decorator
"""Generate the async function to be decorated by `FastAPI.exception_handler` decorator.
Args:
request (Request): The request object.
Expand All @@ -55,13 +55,11 @@ async def _error_handler(
def _set_app_exception_handler(
self,
app: FastAPI,
exception: Type[exceptions.AuthXException],
exception: type[exceptions.AuthXException],
status_code: int,
message: Optional[str],
) -> None:
async def exception_handler_wrapper(
request: Request, exc: exceptions.AuthXException
) -> JSONResponse:
async def exception_handler_wrapper(request: Request, exc: exceptions.AuthXException) -> JSONResponse:
return await self._error_handler(request, exc, status_code, message)

# Add the exception handler to the FastAPI application
Expand All @@ -70,14 +68,12 @@ async def exception_handler_wrapper(
app.exception_handler(exception)(exception_handler_wrapper)

def handle_errors(self, app: FastAPI) -> None:
"""Add the `FastAPI.exception_handlers` relative to AuthX exceptions
"""Add the `FastAPI.exception_handlers` relative to AuthX exceptions.
Args:
app (FastAPI): the FastAPI application to handle errors for
"""
self._set_app_exception_handler(
app, exception=exceptions.JWTDecodeError, status_code=422, message=None
)
self._set_app_exception_handler(app, exception=exceptions.JWTDecodeError, status_code=422, message=None)
self._set_app_exception_handler(
app,
exception=exceptions.MissingTokenError,
Expand Down
8 changes: 2 additions & 6 deletions authx/_internal/_logger.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,7 @@ def set_log_level(level: str) -> logging.Logger:
return log


def log_debug(
msg: str, loc: Optional[str] = None, method: Optional[str] = None
) -> None:
def log_debug(msg: str, loc: Optional[str] = None, method: Optional[str] = None) -> None:
log.debug(msg=_build_log_msg(msg=msg, loc=loc, method=method))


Expand All @@ -35,9 +33,7 @@ def log_error(
log.error(f"{traceback.format_exc()}")


def _build_log_msg(
msg: str, loc: Optional[str] = None, method: Optional[str] = None
) -> str:
def _build_log_msg(msg: str, loc: Optional[str] = None, method: Optional[str] = None) -> str:
log_str = f"{msg}"
if loc:
log_str = f"[{loc}] {log_str}"
Expand Down
11 changes: 5 additions & 6 deletions authx/_internal/_memory.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import time
from typing import Any, Dict, Optional
from typing import Any, Optional


class MemoryIO:
raw_memory_store: Dict[str, Dict[str, Any]]
raw_memory_store: dict[str, dict[str, Any]]

"""
MemoryIO is a class that implements the IO interface for the session store.
Expand All @@ -12,8 +12,7 @@ class MemoryIO:
"""

def __init__(self) -> None:
"""
Initialize an instance of MemoryIO.
"""Initialize an instance of MemoryIO.
Creates a dictionary to store the session data.
"""
Expand All @@ -25,15 +24,15 @@ async def has_session_id(self, session_id: str) -> bool:
async def has_no_session_id(self, session_id: str) -> bool:
return session_id not in self.raw_memory_store

async def create_store(self, session_id: str) -> Dict[str, Any]:
async def create_store(self, session_id: str) -> dict[str, Any]:
self.raw_memory_store[session_id] = {
"created_at": int(time.time()),
"store": {},
}
await self.save_store(session_id)
return self.raw_memory_store.get(session_id, {}).get("store", {})

async def get_store(self, session_id: str) -> Optional[Dict[str, Any]]:
async def get_store(self, session_id: str) -> Optional[dict[str, Any]]:
if self.raw_memory_store.get(session_id):
return self.raw_memory_store.get(session_id, {}).get("store")
else:
Expand Down
14 changes: 5 additions & 9 deletions authx/_internal/_signature.py
Original file line number Diff line number Diff line change
@@ -1,26 +1,22 @@
from typing import Any, Dict, Optional, Tuple
from typing import Any, Optional

from itsdangerous import BadTimeSignature, SignatureExpired, URLSafeTimedSerializer

CASUAL_UT = False


class SignatureSerializer:
"""
A class that implements a URL-safe timed serializer.
"""
"""A class that implements a URL-safe timed serializer."""

def __init__(self, secret_key: str, expired_in: int = 0) -> None:
"""
Initialize the serializer with a secret key and an optional expiration time.
"""
"""Initialize the serializer with a secret key and an optional expiration time."""
self.ser = URLSafeTimedSerializer(secret_key)
self.expired_in = expired_in

def encode(self, dict_obj: Dict[str, Any]) -> str:
def encode(self, dict_obj: dict[str, Any]) -> str:
return self.ser.dumps(dict_obj)

def decode(self, token: str) -> Tuple[Optional[Dict[str, Any]], Optional[str]]:
def decode(self, token: str) -> tuple[Optional[dict[str, Any]], Optional[str]]:
if token is None:
return None, "NoTokenSpecified"
try:
Expand Down
28 changes: 7 additions & 21 deletions authx/_internal/_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,7 @@ def to_UTC(event_timestamp: Union[datetime, str], tz: BaseTzInfo = utc) -> datet
return dt.astimezone(tz)


def to_UTC_without_tz(
event_timestamp: str, format: str = "%Y-%m-%d %H:%M:%S.%f"
) -> str:
def to_UTC_without_tz(event_timestamp: str, format: str = "%Y-%m-%d %H:%M:%S.%f") -> str:
dt = datetime.strptime(event_timestamp, format)
dt = dt.replace(tzinfo=tz.utc)
return dt.astimezone(tz.utc).strftime(format)
Expand All @@ -69,27 +67,19 @@ def end_of_day(dt: datetime) -> datetime:
return dt


def minutes_ago(
dt: datetime, days: int = 0, hours: int = 0, minutes: int = 1, seconds: int = 0
) -> datetime:
def minutes_ago(dt: datetime, days: int = 0, hours: int = 0, minutes: int = 1, seconds: int = 0) -> datetime:
return dt - timedelta(days=days, hours=hours, minutes=minutes, seconds=seconds)


def minutes_after(
dt: datetime, days: int = 0, hours: int = 0, minutes: int = 1, seconds: int = 0
) -> datetime:
def minutes_after(dt: datetime, days: int = 0, hours: int = 0, minutes: int = 1, seconds: int = 0) -> datetime:
return dt + timedelta(days=days, hours=hours, minutes=minutes, seconds=seconds)


def hours_ago(
dt: datetime, days: int = 0, hours: int = 1, minutes: int = 0, seconds: int = 0
) -> datetime:
def hours_ago(dt: datetime, days: int = 0, hours: int = 1, minutes: int = 0, seconds: int = 0) -> datetime:
return dt - timedelta(days=days, hours=hours, minutes=minutes, seconds=seconds)


def days_ago(
dt: datetime, days: int = 1, hours: int = 0, minutes: int = 0, seconds: int = 0
) -> datetime:
def days_ago(dt: datetime, days: int = 1, hours: int = 0, minutes: int = 0, seconds: int = 0) -> datetime:
past = dt - timedelta(days=days, hours=hours, minutes=minutes, seconds=seconds)
if dt.tzinfo:
past = past.replace(tzinfo=dt.tzinfo)
Expand All @@ -111,9 +101,7 @@ def years_ago(dt: datetime, years: int = 1) -> datetime:
return past


def days_after(
dt: datetime, days: int = 1, hours: int = 0, minutes: int = 0, seconds: int = 0
) -> datetime:
def days_after(dt: datetime, days: int = 1, hours: int = 0, minutes: int = 0, seconds: int = 0) -> datetime:
future = dt + timedelta(days=days, hours=hours, minutes=minutes, seconds=seconds)
if dt.tzinfo:
future = future.replace(tzinfo=dt.tzinfo)
Expand Down Expand Up @@ -141,9 +129,7 @@ def tz_now(tz: BaseTzInfo = utc) -> datetime:
return dt.replace(tzinfo=tz)


def tz_from_iso(
dt: str, to_tz: BaseTzInfo = utc, format: str = "%Y-%m-%dT%H:%M:%S.%f%z"
) -> datetime:
def tz_from_iso(dt: str, to_tz: BaseTzInfo = utc, format: str = "%Y-%m-%dT%H:%M:%S.%f%z") -> datetime:
date_time = datetime.strptime(dt, format)
return date_time.astimezone(to_tz)

Expand Down
Loading

0 comments on commit 7afa246

Please sign in to comment.