Coverage for /var/srv/projects/api.amasfac.comuna18.com/tmp/venv/lib/python3.9/site-packages/rest_framework/schemas/inspectors.py: 45%

61 statements  

« prev     ^ index     » next       coverage.py v6.4.4, created at 2023-07-17 14:22 -0600

1""" 

2inspectors.py # Per-endpoint view introspection 

3 

4See schemas.__init__.py for package overview. 

5""" 

6import re 

7from weakref import WeakKeyDictionary 

8 

9from django.utils.encoding import smart_str 

10 

11from rest_framework.settings import api_settings 

12from rest_framework.utils import formatting 

13 

14 

15class ViewInspector: 

16 """ 

17 Descriptor class on APIView. 

18 

19 Provide subclass for per-view schema generation 

20 """ 

21 

22 # Used in _get_description_section() 

23 header_regex = re.compile('^[a-zA-Z][0-9A-Za-z_]*:') 

24 

25 def __init__(self): 

26 self.instance_schemas = WeakKeyDictionary() 

27 

28 def __get__(self, instance, owner): 

29 """ 

30 Enables `ViewInspector` as a Python _Descriptor_. 

31 

32 This is how `view.schema` knows about `view`. 

33 

34 `__get__` is called when the descriptor is accessed on the owner. 

35 (That will be when view.schema is called in our case.) 

36 

37 `owner` is always the owner class. (An APIView, or subclass for us.) 

38 `instance` is the view instance or `None` if accessed from the class, 

39 rather than an instance. 

40 

41 See: https://docs.python.org/3/howto/descriptor.html for info on 

42 descriptor usage. 

43 """ 

44 if instance in self.instance_schemas: 44 ↛ 45line 44 didn't jump to line 45, because the condition on line 44 was never true

45 return self.instance_schemas[instance] 

46 

47 self.view = instance 

48 return self 

49 

50 def __set__(self, instance, other): 

51 self.instance_schemas[instance] = other 

52 if other is not None: 

53 other.view = instance 

54 

55 @property 

56 def view(self): 

57 """View property.""" 

58 assert self._view is not None, ( 

59 "Schema generation REQUIRES a view instance. (Hint: you accessed " 

60 "`schema` from the view class rather than an instance.)" 

61 ) 

62 return self._view 

63 

64 @view.setter 

65 def view(self, value): 

66 self._view = value 

67 

68 @view.deleter 

69 def view(self): 

70 self._view = None 

71 

72 def get_description(self, path, method): 

73 """ 

74 Determine a path description. 

75 

76 This will be based on the method docstring if one exists, 

77 or else the class docstring. 

78 """ 

79 view = self.view 

80 

81 method_name = getattr(view, 'action', method.lower()) 

82 method_docstring = getattr(view, method_name, None).__doc__ 

83 if method_docstring: 

84 # An explicit docstring on the method or action. 

85 return self._get_description_section(view, method.lower(), formatting.dedent(smart_str(method_docstring))) 

86 else: 

87 return self._get_description_section(view, getattr(view, 'action', method.lower()), 

88 view.get_view_description()) 

89 

90 def _get_description_section(self, view, header, description): 

91 lines = [line for line in description.splitlines()] 

92 current_section = '' 

93 sections = {'': ''} 

94 

95 for line in lines: 

96 if self.header_regex.match(line): 

97 current_section, separator, lead = line.partition(':') 

98 sections[current_section] = lead.strip() 

99 else: 

100 sections[current_section] += '\n' + line 

101 

102 # TODO: SCHEMA_COERCE_METHOD_NAMES appears here and in `SchemaGenerator.get_keys` 

103 coerce_method_names = api_settings.SCHEMA_COERCE_METHOD_NAMES 

104 if header in sections: 

105 return sections[header].strip() 

106 if header in coerce_method_names: 

107 if coerce_method_names[header] in sections: 

108 return sections[coerce_method_names[header]].strip() 

109 return sections[''].strip() 

110 

111 

112class DefaultSchema(ViewInspector): 

113 """Allows overriding AutoSchema using DEFAULT_SCHEMA_CLASS setting""" 

114 def __get__(self, instance, owner): 

115 result = super().__get__(instance, owner) 

116 if not isinstance(result, DefaultSchema): 116 ↛ 117line 116 didn't jump to line 117, because the condition on line 116 was never true

117 return result 

118 

119 inspector_class = api_settings.DEFAULT_SCHEMA_CLASS 

120 assert issubclass(inspector_class, ViewInspector), ( 

121 "DEFAULT_SCHEMA_CLASS must be set to a ViewInspector (usually an AutoSchema) subclass" 

122 ) 

123 inspector = inspector_class() 

124 inspector.view = instance 

125 return inspector