aboutsummaryrefslogtreecommitdiffstats
path: root/djangorestframework/utils/description.py
blob: 25bef80bd15dcd5614c3b765bc613f802b647243 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
"""
Get a descriptive name and description for a view.
"""
import re
from djangorestframework.resources import Resource, FormResource, ModelResource


# These a a bit Grungy, but they do the job.

def get_name(view):
    """
    Return a name for the view.
    
    If view has a name attribute, use that, otherwise use the view's class name, with 'CamelCaseNames' converted to 'Camel Case Names'.
    """

    # If we're looking up the name of a view callable, as found by reverse,
    # grok the class instance that we stored when as_view was called.
    if getattr(view, 'cls_instance', None):
        view = view.cls_instance

    # If this view has a resource that's been overridden, then use that resource for the name
    if getattr(view, 'resource', None) not in (None, Resource, FormResource, ModelResource):
        name = view.resource.__name__
        
        # Chomp of any non-descriptive trailing part of the resource class name
        if name.endswith('Resource') and name != 'Resource':
            name = name[:-len('Resource')]

        # If the view has a descriptive suffix, eg '*** List', '*** Instance'
        if getattr(view, '_suffix', None):
            name += view._suffix
 
    # Otherwise if it's a function view use the function's name
    elif getattr(view, '__name__', None) is not None:
        name = view.__name__

    # If it's a view class with no resource then grok the name from the class name
    elif getattr(view, '__class__', None) is not None:
        name = view.__class__.__name__

        # Chomp of any non-descriptive trailing part of the view class name
        if name.endswith('View') and name != 'View':
            name = name[:-len('View')]

    # I ain't got nuthin fo' ya
    else:
        return ''

    return re.sub('(((?<=[a-z])[A-Z])|([A-Z](?![A-Z]|$)))', ' \\1', name).strip()



def get_description(view):
    """
    Provide a description for the view.

    By default this is the view's docstring with nice unindention applied.
    """

    # If we're looking up the name of a view callable, as found by reverse,
    # grok the class instance that we stored when as_view was called.
    if getattr(view, 'cls_instance', None):
        view = view.cls_instance
        

    # If this view has a resource that's been overridden, then use the resource's doctring
    if getattr(view, 'resource', None) not in (None, Resource, FormResource, ModelResource):
        doc = view.resource.__doc__
    
    # Otherwise use the view doctring
    elif getattr(view, '__doc__', None):
        doc = view.__doc__

    # I ain't got nuthin fo' ya
    else:
        return ''

    if not doc:
        return ''

    whitespace_counts = [len(line) - len(line.lstrip(' ')) for line in doc.splitlines()[1:] if line.lstrip()]

    # unindent the docstring if needed 
    if whitespace_counts:
        whitespace_pattern = '^' + (' ' * min(whitespace_counts))
        return re.sub(re.compile(whitespace_pattern, re.MULTILINE), '', doc)

    # otherwise return it as-is
    return doc