diff --git a/rest_framework/settings.py b/rest_framework/settings.py index 0b2bdb62d..7d25e5131 100644 --- a/rest_framework/settings.py +++ b/rest_framework/settings.py @@ -70,8 +70,8 @@ DEFAULTS = { 'PAGINATE_BY_PARAM': None, # View configuration - 'VIEW_NAME_FUNCTION': 'rest_framework.utils.formatting.view_name', - 'VIEW_DESCRIPTION_FUNCTION': 'rest_framework.utils.formatting.view_description', + 'VIEW_NAME_FUNCTION': 'rest_framework.views.get_view_name', + 'VIEW_DESCRIPTION_FUNCTION': 'rest_framework.views.get_view_description', # Authentication 'UNAUTHENTICATED_USER': 'django.contrib.auth.models.AnonymousUser', diff --git a/rest_framework/utils/formatting.py b/rest_framework/utils/formatting.py index 89a89252e..4b59ba840 100644 --- a/rest_framework/utils/formatting.py +++ b/rest_framework/utils/formatting.py @@ -5,12 +5,13 @@ from __future__ import unicode_literals from django.utils.html import escape from django.utils.safestring import mark_safe -from rest_framework.compat import apply_markdown, smart_text -import re +from rest_framework.compat import apply_markdown from rest_framework.settings import api_settings +from textwrap import dedent +import re -def _remove_trailing_string(content, trailing): +def remove_trailing_string(content, trailing): """ Strip trailing component `trailing` from `content` if it exists. Used when generating names from view classes. @@ -20,10 +21,14 @@ def _remove_trailing_string(content, trailing): return content -def _remove_leading_indent(content): +def dedent(content): """ Remove leading indent from a block of text. Used when generating descriptions from docstrings. + + Note that python's `textwrap.dedent` doesn't quite cut it, + as it fails to dedent multiline docstrings that include + unindented text on the initial line. """ whitespace_counts = [len(line) - len(line.lstrip(' ')) for line in content.splitlines()[1:] if line.lstrip()] @@ -32,11 +37,10 @@ def _remove_leading_indent(content): if whitespace_counts: whitespace_pattern = '^' + (' ' * min(whitespace_counts)) content = re.sub(re.compile(whitespace_pattern, re.MULTILINE), '', content) - content = content.strip('\n') - return content + return content.strip() -def _camelcase_to_spaces(content): +def camelcase_to_spaces(content): """ Translate 'CamelCaseNames' to 'Camel Case Names'. Used when generating names from view classes. @@ -54,21 +58,3 @@ def markup_description(description): else: description = escape(description).replace('\n', '
') return mark_safe(description) - - -def view_name(instance, view, suffix=None): - name = view.__name__ - name = _remove_trailing_string(name, 'View') - name = _remove_trailing_string(name, 'ViewSet') - name = _camelcase_to_spaces(name) - if suffix: - name += ' ' + suffix - - return name - -def view_description(instance, view, html=False): - description = view.__doc__ or '' - description = _remove_leading_indent(smart_text(description)) - if html: - return markup_description(description) - return description \ No newline at end of file diff --git a/rest_framework/views.py b/rest_framework/views.py index 4553714a9..431e21f95 100644 --- a/rest_framework/views.py +++ b/rest_framework/views.py @@ -8,10 +8,29 @@ from django.http import Http404 from django.utils.datastructures import SortedDict from django.views.decorators.csrf import csrf_exempt from rest_framework import status, exceptions -from rest_framework.compat import View, HttpResponseBase +from rest_framework.compat import smart_text, HttpResponseBase, View from rest_framework.request import Request from rest_framework.response import Response from rest_framework.settings import api_settings +from rest_framework.utils import formatting + + +def get_view_name(instance, view, suffix=None): + name = view.__name__ + name = formatting.remove_trailing_string(name, 'View') + name = formatting.remove_trailing_string(name, 'ViewSet') + name = formatting.camelcase_to_spaces(name) + if suffix: + name += ' ' + suffix + + return name + +def get_view_description(instance, view, html=False): + description = view.__doc__ or '' + description = formatting.dedent(smart_text(description)) + if html: + return formatting.markup_description(description) + return description class APIView(View):