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
« prev ^ index » next coverage.py v6.4.4, created at 2023-07-17 14:22 -0600
1"""
2inspectors.py # Per-endpoint view introspection
4See schemas.__init__.py for package overview.
5"""
6import re
7from weakref import WeakKeyDictionary
9from django.utils.encoding import smart_str
11from rest_framework.settings import api_settings
12from rest_framework.utils import formatting
15class ViewInspector:
16 """
17 Descriptor class on APIView.
19 Provide subclass for per-view schema generation
20 """
22 # Used in _get_description_section()
23 header_regex = re.compile('^[a-zA-Z][0-9A-Za-z_]*:')
25 def __init__(self):
26 self.instance_schemas = WeakKeyDictionary()
28 def __get__(self, instance, owner):
29 """
30 Enables `ViewInspector` as a Python _Descriptor_.
32 This is how `view.schema` knows about `view`.
34 `__get__` is called when the descriptor is accessed on the owner.
35 (That will be when view.schema is called in our case.)
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.
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]
47 self.view = instance
48 return self
50 def __set__(self, instance, other):
51 self.instance_schemas[instance] = other
52 if other is not None:
53 other.view = instance
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
64 @view.setter
65 def view(self, value):
66 self._view = value
68 @view.deleter
69 def view(self):
70 self._view = None
72 def get_description(self, path, method):
73 """
74 Determine a path description.
76 This will be based on the method docstring if one exists,
77 or else the class docstring.
78 """
79 view = self.view
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())
90 def _get_description_section(self, view, header, description):
91 lines = [line for line in description.splitlines()]
92 current_section = ''
93 sections = {'': ''}
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
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()
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
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