Skip to content

Commit

Permalink
add docstring and typing on helper e util
Browse files Browse the repository at this point in the history
  • Loading branch information
ebertti committed Aug 27, 2024
1 parent b303719 commit bf2c6ae
Show file tree
Hide file tree
Showing 2 changed files with 102 additions and 17 deletions.
94 changes: 80 additions & 14 deletions easy/helper.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
from __future__ import annotations
from typing import Callable, Union, Any

import django

EASY_CACHE_TEMPLATE_METHOD = 'easy.{}.{}.{}'
EASY_CACHE_TEMPLATE_OBJ = 'easy.{}.{}'


Model: django.db.models.Model

class Nothing(object):
def __str__(self):
return 'Error'
Expand All @@ -12,17 +17,39 @@ def __unicode__(self):
return u'Error'


def deep_getattribute(obj, attr):
def deep_getattribute(obj: object, attr: str) -> object:
"""
Retrieves the value of a nested attribute from an object.
Args:
obj (object): The object to retrieve the attribute from.
attr (str): The attribute to retrieve, in the form of a dot-separated string.
Returns:
object: The value of the attribute, or a Nothing instance if the attribute does not exist.
"""
attrs = attr.split(".")
for i in attrs:
obj = getattr(obj, i, Nothing())
return obj

def get_django_filter(django_filter, load='django'):
def get_django_filter(django_filter: str, load: str = 'django') -> Callable:
"""
Retrieves a Django filter method from the specified templatetag library.
Args:
django_filter (str): The name of the Django filter method.
load (str, optional): The name of the templatetag library to load. Defaults to 'django'.
Returns:
Callable: The Django filter method.
Raises:
Exception: If the specified Django filter or templatetag library does not exist.
"""
if django.VERSION < (1, 9):
from django.template.base import get_library
if load and not load == 'django':
if load and load != 'django':
library = get_library(load)
else:
library_path = 'django.template.defaultfilters'
Expand All @@ -37,30 +64,41 @@ def get_django_filter(django_filter, load='django'):
from django.template.backends.django import get_installed_libraries
from django.template.library import import_library
libraries = get_installed_libraries()
if load and not load == 'django':
if load and load != 'django':
library_path = libraries.get(load)
if not library_path:
raise Exception('templatetag "{}" is not registered'.format(load))
raise Exception(f'templatetag "{load}" is not registered')
else:
library_path = 'django.template.defaultfilters'

library = import_library(library_path)
filter_method = library.filters.get(django_filter)
if not filter_method:
raise Exception('filter "{}" not exist on {} templatetag package'.format(
django_filter, load
))
raise Exception(f'filter "{django_filter}" not exist on {load} templatetag package')

return filter_method


def call_or_get(obj, attr, default=None):
def call_or_get(obj: object, attr: Union[str, Callable[[object], Any]], default: Any = None) -> Any:
"""
Calls the given attribute if it is a callable, otherwise retrieves its value.
Args:
obj (object): The object to call the attribute on.
attr (Union[str, Callable[[object], Any]]): The attribute to call or retrieve.
default (Any, optional): The default value to return if the attribute's value is None or an instance of Nothing.
Returns:
Any: The result of calling the attribute if it is a callable, otherwise its value. If the attribute's value is None or an instance of Nothing, returns the default value if it is provided, otherwise returns None.
"""
ret = Nothing()
if hasattr(attr, '__call__'):

if callable(attr):
ret = attr(obj)

if isinstance(ret, Nothing):
value = deep_getattribute(obj, attr)
if hasattr(value, '__call__'):
if callable(value):
ret = value()
else:
ret = value
Expand All @@ -71,14 +109,33 @@ def call_or_get(obj, attr, default=None):
return ret


def get_model_name(model):
def get_model_name(model: Model) -> str:
"""
Retrieves the name of a Django model.
Args:
model (Model): The Django model object.
Returns:
str: The name of the model.
"""
if django.VERSION < (1, 6):
return model._meta.module_name
else:
return model._meta.model_name


def cache_method_key(model, method_name):
def cache_method_key(model: Model, method_name: str) -> str:
"""
Generates a cache key for a method of a model instance.
Args:
model (Model): The model instance.
method_name (str): The name of the method.
Returns:
str: The cache key.
"""
return EASY_CACHE_TEMPLATE_METHOD.format(
model._meta.app_label,
get_model_name(model),
Expand All @@ -87,7 +144,16 @@ def cache_method_key(model, method_name):
)


def cache_object_key(model):
def cache_object_key(model: Model) -> str:
"""
Generates a cache key for a model instance.
Args:
model (Model): The model instance.
Returns:
str: The cache key.
"""
return EASY_CACHE_TEMPLATE_OBJ.format(
model._meta.app_label,
get_model_name(model),
Expand Down
25 changes: 22 additions & 3 deletions easy/util.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,30 @@
from typing import Optional

from django.shortcuts import redirect
from django.contrib import messages


def action_response(request, message=None, level=messages.INFO, keep_querystring=True):
redirect_url = '.'
def action_response(
request: "HttpRequest",
message: Optional[str] = None,
level: int = messages.INFO,
keep_querystring: bool = True,
) -> "HttpResponseRedirect":
"""
Redirects the user to the current page with an optional message.
Args:
request: The current request.
message: The message to display to the user.
level: The level of the message.
keep_querystring: Whether to keep the query string in the redirect URL.
Returns:
An HttpResponseRedirect object.
"""
redirect_url = "."
if keep_querystring and request.GET:
redirect_url = './?' + request.GET.urlencode()
redirect_url = "./?" + request.GET.urlencode()
if message:
messages.add_message(request, level, message, fail_silently=True)
return redirect(redirect_url)

0 comments on commit bf2c6ae

Please sign in to comment.