def parse(self, request, public): """ Iterate endpoints generating per method path operations. """ result = {} self._initialise_endpoints() for path, path_regex, method, view in self._get_paths_and_endpoints( None if public else request): if not self.has_view_permissions(path, method, view): continue # mocked request to allow certain operations in get_queryset and get_serializer[_class] # without exceptions being raised due to no request. if not request: request = spectacular_settings.GET_MOCK_REQUEST( method, path, view, request) view.request = request if view.versioning_class and not is_versioning_supported( view.versioning_class): warn( f'using unsupported versioning class "{view.versioning_class}". view will be ' f'processed as unversioned view.') elif view.versioning_class: version = ( self.api_version # generator was explicitly versioned or getattr(request, 'version', None) # incoming request was versioned or view.versioning_class.default_version # fallback ) if not version: continue path = modify_for_versioning(self.inspector.patterns, method, path, view, version) if not operation_matches_version(view, version): continue assert isinstance(view.schema, AutoSchema), ( 'Incompatible AutoSchema used on View. Is DRF\'s DEFAULT_SCHEMA_CLASS ' 'pointing to "drf_spectacular.openapi.AutoSchema" or any other drf-spectacular ' 'compatible AutoSchema?') operation = view.schema.get_operation(path, path_regex, method, self.registry) # operation was manually removed via @extend_schema if not operation: continue # Normalise path for any provided mount url. if path.startswith('/'): path = path[1:] path = urljoin(self.url or '/', path) if spectacular_settings.CAMELIZE_NAMES: path, operation = camelize_operation(path, operation) result.setdefault(path, {}) result[path][method.lower()] = operation return result
def parse(self, request, public): """ Iterate endpoints generating per method path operations. """ result = {} self._initialise_endpoints() for path, path_regex, method, view in self._get_paths_and_endpoints( None if public else request): if not self.has_view_permissions(path, method, view): continue if view.versioning_class and not is_versioning_supported( view.versioning_class): warn( f'using unsupported versioning class "{view.versioning_class}". view will be ' f'processed as unversioned view.') elif view.versioning_class: version = ( self.api_version # generator was explicitly versioned or getattr(request, 'version', None) # incoming request was versioned or view.versioning_class.default_version # fallback ) path = modify_for_versioning(self.inspector.patterns, method, path, view, version) if not version or not operation_matches_version(view, version): continue # beware that every access to schema yields a fresh object (descriptor pattern) operation = view.schema.get_operation(path, path_regex, method, self.registry) # operation was manually removed via @extend_schema if not operation: continue # Normalise path for any provided mount url. if path.startswith('/'): path = path[1:] path = urljoin(self.url or '/', path) result.setdefault(path, {}) result[path][method.lower()] = operation return result
def parse(self, input_request, public): """ Iterate endpoints generating per method path operations. """ result = {} self._initialise_endpoints() endpoints = self._get_paths_and_endpoints( None if public else input_request) if spectacular_settings.SCHEMA_PATH_PREFIX is None: # estimate common path prefix if none was given. only use it if we encountered more # than one view to prevent emission of erroneous and unnecessary fallback names. non_trivial_prefix = len( set([view.__class__ for _, _, _, view in endpoints])) > 1 if non_trivial_prefix: path_prefix = os.path.commonpath( [path for path, _, _, _ in endpoints]) else: path_prefix = '/' else: path_prefix = spectacular_settings.SCHEMA_PATH_PREFIX if not path_prefix.startswith('^'): path_prefix = '^' + path_prefix # make sure regex only matches from the start for path, path_regex, method, view in endpoints: if not self.has_view_permissions(path, method, view): continue if input_request: request = input_request else: # mocked request to allow certain operations in get_queryset and get_serializer[_class] # without exceptions being raised due to no request. request = spectacular_settings.GET_MOCK_REQUEST( method, path, view, input_request) view.request = request if view.versioning_class and not is_versioning_supported( view.versioning_class): warn( f'using unsupported versioning class "{view.versioning_class}". view will be ' f'processed as unversioned view.') elif view.versioning_class: version = ( self.api_version # generator was explicitly versioned or getattr(request, 'version', None) # incoming request was versioned or view.versioning_class.default_version # fallback ) if not version: continue path = modify_for_versioning(self.inspector.patterns, method, path, view, version) if not operation_matches_version(view, version): continue assert isinstance(view.schema, AutoSchema), ( f'Incompatible AutoSchema used on View {view.__class__}. Is DRF\'s ' f'DEFAULT_SCHEMA_CLASS pointing to "drf_spectacular.openapi.AutoSchema" ' f'or any other drf-spectacular compatible AutoSchema?') with add_trace_message(getattr(view, '__class__', view).__name__): operation = view.schema.get_operation(path, path_regex, path_prefix, method, self.registry) # operation was manually removed via @extend_schema if not operation: continue if spectacular_settings.SCHEMA_PATH_PREFIX_TRIM: path = re.sub(pattern=path_prefix, repl='', string=path, flags=re.IGNORECASE) if not path.startswith('/'): path = '/' + path if spectacular_settings.CAMELIZE_NAMES: path, operation = camelize_operation(path, operation) result.setdefault(path, {}) result[path][method.lower()] = operation return result