import functools import inspect import logging import re import unicodedata from hashlib import md5 from typing import TYPE_CHECKING, Any, Dict, Iterable, Union from warnings import warn from anyascii import anyascii from django.apps import apps from django.conf import settings from django.conf.locale import LANG_INFO from django.core.cache import cache from django.core.cache.utils import make_template_fragment_key from django.core.exceptions import ImproperlyConfigured, SuspiciousOperation from django.core.signals import setting_changed from django.db.models import Model from django.db.models.base import ModelBase from django.dispatch import receiver from django.http import HttpRequest from django.test import RequestFactory from django.utils.encoding import force_str from django.utils.text import capfirst, slugify from django.utils.translation import check_for_language, get_supported_language_variant from django.utils.translation import gettext_lazy as _ from wagtail.utils.deprecation import RemovedInWagtail70Warning if TYPE_CHECKING: from wagtail.models import Site logger = logging.getLogger(__name__) WAGTAIL_APPEND_SLASH = getattr(settings, "WAGTAIL_APPEND_SLASH", True) def camelcase_to_underscore(str): # https://djangosnippets.org/snippets/585/ return ( re.sub("(((?<=[a-z])[A-Z])|([A-Z](?![A-Z]|$)))", "_\\1", str).lower().strip("_") ) def string_to_ascii(value): """ Convert a string to ascii. """ return str(anyascii(value)) def get_model_string(model): """ Returns a string that can be used to identify the specified model. The format is: `app_label.ModelName` This an be reversed with the `resolve_model_string` function """ return model._meta.app_label + "." + model.__name__ def resolve_model_string(model_string, default_app=None): """ Resolve an 'app_label.model_name' string into an actual model class. If a model class is passed in, just return that. Raises a LookupError if a model can not be found, or ValueError if passed something that is neither a model or a string. """ if isinstance(model_string, str): try: app_label, model_name = model_string.split(".") except ValueError: if default_app is not None: # If we can't split, assume a model in current app app_label = default_app model_name = model_string else: raise ValueError( "Can not resolve {!r} into a model. Model names " "should be in the form app_label.model_name".format(model_string), model_string, ) return apps.get_model(app_label, model_name) elif isinstance(model_string, type): return model_string else: raise ValueError(f"Can not resolve {model_string!r} into a model", model_string) SCRIPT_RE = re.compile(r"<(-*)/script>") def escape_script(text): """ Escape `` tags in 'text' so that it can be placed within a `