update
This commit is contained in:
@@ -1,11 +1,15 @@
|
||||
# coding=utf-8
|
||||
from pkg_resources import DistributionNotFound, get_distribution
|
||||
|
||||
__author__ = """Cristi V."""
|
||||
__email__ = 'cristi@cvjd.me'
|
||||
|
||||
try:
|
||||
__version__ = get_distribution(__name__).version
|
||||
except DistributionNotFound: # pragma: no cover
|
||||
# package is not installed
|
||||
pass
|
||||
from importlib.metadata import version
|
||||
__version__ = version(__name__)
|
||||
except ImportError: # Python < 3.8
|
||||
try:
|
||||
from pkg_resources import DistributionNotFound, get_distribution
|
||||
__version__ = get_distribution(__name__).version
|
||||
except DistributionNotFound: # pragma: no cover
|
||||
# package is not installed
|
||||
pass
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -41,6 +41,9 @@ SWAGGER_DEFAULTS = {
|
||||
'DEFAULT_API_URL': None,
|
||||
|
||||
'USE_SESSION_AUTH': True,
|
||||
'USE_COMPAT_RENDERERS': getattr(settings, 'SWAGGER_USE_COMPAT_RENDERERS', True),
|
||||
'CSRF_COOKIE_NAME': settings.CSRF_COOKIE_NAME,
|
||||
'CSRF_HEADER_NAME': settings.CSRF_HEADER_NAME,
|
||||
'SECURITY_DEFINITIONS': {
|
||||
'Basic': {
|
||||
'type': 'basic'
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -6,9 +6,7 @@ import uuid
|
||||
from contextlib import suppress
|
||||
from collections import OrderedDict
|
||||
from decimal import Decimal
|
||||
from inspect import signature as inspect_signature
|
||||
|
||||
import pkg_resources
|
||||
import typing
|
||||
from django.core import validators
|
||||
from django.db import models
|
||||
@@ -23,7 +21,20 @@ from ..utils import (
|
||||
decimal_as_float, field_value_to_representation, filter_none, get_serializer_class, get_serializer_ref_name
|
||||
)
|
||||
|
||||
drf_version = pkg_resources.get_distribution("djangorestframework").version
|
||||
try:
|
||||
from importlib import metadata
|
||||
drf_version = metadata.version("djangorestframework")
|
||||
except ImportError: # Python < 3.8
|
||||
import pkg_resources
|
||||
drf_version = pkg_resources.get_distribution("djangorestframework").version
|
||||
|
||||
try:
|
||||
from types import NoneType, UnionType
|
||||
|
||||
UNION_TYPES = (typing.Union, UnionType)
|
||||
except ImportError: # Python < 3.10
|
||||
NoneType = type(None)
|
||||
UNION_TYPES = (typing.Union,)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -189,7 +200,7 @@ def get_queryset_from_view(view, serializer=None):
|
||||
|
||||
if queryset is not None and serializer is not None:
|
||||
# make sure the view is actually using *this* serializer
|
||||
assert type(serializer) == call_view_method(view, 'get_serializer_class', 'serializer_class')
|
||||
assert type(serializer) is call_view_method(view, 'get_serializer_class', 'serializer_class')
|
||||
|
||||
return queryset
|
||||
except Exception: # pragma: no cover
|
||||
@@ -476,15 +487,6 @@ def decimal_return_type():
|
||||
return openapi.TYPE_STRING if rest_framework_settings.COERCE_DECIMAL_TO_STRING else openapi.TYPE_NUMBER
|
||||
|
||||
|
||||
def get_origin_type(hint_class):
|
||||
return getattr(hint_class, '__origin__', None) or hint_class
|
||||
|
||||
|
||||
def hint_class_issubclass(hint_class, check_class):
|
||||
origin_type = get_origin_type(hint_class)
|
||||
return inspect.isclass(origin_type) and issubclass(origin_type, check_class)
|
||||
|
||||
|
||||
hinting_type_info = [
|
||||
(bool, (openapi.TYPE_BOOLEAN, None)),
|
||||
(int, (openapi.TYPE_INTEGER, None)),
|
||||
@@ -501,11 +503,15 @@ hinting_type_info = [
|
||||
if hasattr(typing, 'get_args'):
|
||||
# python >=3.8
|
||||
typing_get_args = typing.get_args
|
||||
typing_get_origin = typing.get_origin
|
||||
else:
|
||||
# python <3.8
|
||||
def typing_get_args(tp):
|
||||
return getattr(tp, '__args__', ())
|
||||
|
||||
def typing_get_origin(tp):
|
||||
return getattr(tp, '__origin__', None)
|
||||
|
||||
|
||||
def inspect_collection_hint_class(hint_class):
|
||||
args = typing_get_args(hint_class)
|
||||
@@ -521,12 +527,6 @@ def inspect_collection_hint_class(hint_class):
|
||||
hinting_type_info.append(((typing.Sequence, typing.AbstractSet), inspect_collection_hint_class))
|
||||
|
||||
|
||||
def _get_union_types(hint_class):
|
||||
origin_type = get_origin_type(hint_class)
|
||||
if origin_type is typing.Union:
|
||||
return hint_class.__args__
|
||||
|
||||
|
||||
def get_basic_type_info_from_hint(hint_class):
|
||||
"""Given a class (eg from a SerializerMethodField's return type hint,
|
||||
return its basic type information - ``type``, ``format``, ``pattern``,
|
||||
@@ -536,12 +536,12 @@ def get_basic_type_info_from_hint(hint_class):
|
||||
:return: the extracted attributes as a dictionary, or ``None`` if the field type is not known
|
||||
:rtype: OrderedDict
|
||||
"""
|
||||
union_types = _get_union_types(hint_class)
|
||||
|
||||
if union_types:
|
||||
if typing_get_origin(hint_class) in UNION_TYPES:
|
||||
# Optional is implemented as Union[T, None]
|
||||
if len(union_types) == 2 and isinstance(None, union_types[1]):
|
||||
result = get_basic_type_info_from_hint(union_types[0])
|
||||
filtered_types = [t for t in typing_get_args(hint_class) if t is not NoneType]
|
||||
if len(filtered_types) == 1:
|
||||
result = get_basic_type_info_from_hint(filtered_types[0])
|
||||
if result:
|
||||
result['x-nullable'] = True
|
||||
|
||||
@@ -549,8 +549,15 @@ def get_basic_type_info_from_hint(hint_class):
|
||||
|
||||
return None
|
||||
|
||||
# resolve the origin class if the class is generic
|
||||
resolved_class = typing_get_origin(hint_class) or hint_class
|
||||
|
||||
# bail out early
|
||||
if not inspect.isclass(resolved_class):
|
||||
return None
|
||||
|
||||
for check_class, info in hinting_type_info:
|
||||
if hint_class_issubclass(hint_class, check_class):
|
||||
if issubclass(resolved_class, check_class):
|
||||
if callable(info):
|
||||
return info(hint_class)
|
||||
|
||||
@@ -613,17 +620,19 @@ class SerializerMethodFieldInspector(FieldInspector):
|
||||
return self.probe_field_inspectors(serializer, swagger_object_type, use_references, read_only=True)
|
||||
else:
|
||||
# look for Python 3.5+ style type hinting of the return value
|
||||
hint_class = inspect_signature(method).return_annotation
|
||||
hint_class = typing.get_type_hints(method).get('return')
|
||||
|
||||
if not inspect.isclass(hint_class) and hasattr(hint_class, '__args__'):
|
||||
hint_class = hint_class.__args__[0]
|
||||
if inspect.isclass(hint_class) and not issubclass(hint_class, inspect._empty):
|
||||
type_info = get_basic_type_info_from_hint(hint_class)
|
||||
# annotations such as typing.Optional have an __instancecheck__
|
||||
# hook and will not look like classes, but `issubclass` needs
|
||||
# a class as its first argument, so only in that case abort
|
||||
if inspect.isclass(hint_class) and issubclass(hint_class, inspect._empty):
|
||||
return NotHandled
|
||||
|
||||
if type_info is not None:
|
||||
SwaggerType, ChildSwaggerType = self._get_partial_types(field, swagger_object_type,
|
||||
use_references, **kwargs)
|
||||
return SwaggerType(**type_info)
|
||||
type_info = get_basic_type_info_from_hint(hint_class)
|
||||
if type_info is not None:
|
||||
SwaggerType, ChildSwaggerType = self._get_partial_types(field, swagger_object_type,
|
||||
use_references, **kwargs)
|
||||
return SwaggerType(**type_info)
|
||||
|
||||
return NotHandled
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -88,7 +88,7 @@ class SwaggerDict(OrderedDict):
|
||||
def __init__(self, **attrs):
|
||||
super(SwaggerDict, self).__init__()
|
||||
self._extras__ = attrs
|
||||
if type(self) == SwaggerDict:
|
||||
if type(self) is SwaggerDict:
|
||||
self._insert_extras__()
|
||||
|
||||
def __setattr__(self, key, value):
|
||||
@@ -516,7 +516,7 @@ class _Ref(SwaggerDict):
|
||||
:param bool ignore_unresolved: do not throw if the referenced object does not exist
|
||||
"""
|
||||
super(_Ref, self).__init__()
|
||||
assert not type(self) == _Ref, "do not instantiate _Ref directly"
|
||||
assert not type(self) is _Ref, "do not instantiate _Ref directly"
|
||||
ref_name = "#/{scope}/{name}".format(scope=scope, name=name)
|
||||
if not ignore_unresolved:
|
||||
obj = resolver.get(name, scope)
|
||||
|
||||
@@ -46,14 +46,14 @@ class OpenAPIRenderer(_SpecRenderer):
|
||||
class SwaggerJSONRenderer(_SpecRenderer):
|
||||
"""Renders the schema as a JSON document with the generic ``application/json`` mime type."""
|
||||
media_type = 'application/json'
|
||||
format = '.json'
|
||||
format = 'json'
|
||||
codec_class = OpenAPICodecJson
|
||||
|
||||
|
||||
class SwaggerYAMLRenderer(_SpecRenderer):
|
||||
"""Renders the schema as a YAML document."""
|
||||
media_type = 'application/yaml'
|
||||
format = '.yaml'
|
||||
format = 'yaml'
|
||||
codec_class = OpenAPICodecYaml
|
||||
|
||||
|
||||
@@ -153,6 +153,9 @@ class SwaggerUIRenderer(_UIRenderer):
|
||||
'refetchWithAuth': swagger_settings.REFETCH_SCHEMA_WITH_AUTH,
|
||||
'refetchOnLogout': swagger_settings.REFETCH_SCHEMA_ON_LOGOUT,
|
||||
'fetchSchemaWithQuery': swagger_settings.FETCH_SCHEMA_WITH_QUERY,
|
||||
'csrfCookie': swagger_settings.CSRF_COOKIE_NAME,
|
||||
# remove HTTP_ and convert underscores to dashes
|
||||
'csrfHeader': swagger_settings.CSRF_HEADER_NAME[5:].replace('_', '-'),
|
||||
}
|
||||
|
||||
data = filter_none(data)
|
||||
|
||||
@@ -36,11 +36,26 @@ var swaggerUiConfig = {
|
||||
],
|
||||
layout: "StandaloneLayout",
|
||||
filter: true,
|
||||
csrfCookie: 'csrftoken',
|
||||
csrfHeader: 'X-CSRFToken',
|
||||
requestInterceptor: function (request) {
|
||||
var headers = request.headers || {};
|
||||
var csrftoken = document.querySelector("[name=csrfmiddlewaretoken]");
|
||||
if (csrftoken) {
|
||||
headers["X-CSRFToken"] = csrftoken.value;
|
||||
csrftoken = csrftoken.value;
|
||||
} else {
|
||||
var cookies = document.cookie.split(/;\s+/);
|
||||
var name = swaggerUiConfig.csrfCookie;
|
||||
for (var i = 0; i < cookies.length; i++) {
|
||||
if (cookies[i].indexOf(name) === 0) {
|
||||
csrftoken = cookies[i].slice(cookies[i].indexOf('=') + 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (csrftoken) {
|
||||
headers[swaggerUiConfig.csrfHeader] = csrftoken;
|
||||
}
|
||||
|
||||
return request;
|
||||
|
||||
@@ -17,6 +17,15 @@ from rest_framework.views import APIView
|
||||
|
||||
from .app_settings import swagger_settings
|
||||
|
||||
try:
|
||||
import zoneinfo
|
||||
except ImportError:
|
||||
try:
|
||||
from backports import zoneinfo
|
||||
except ImportError:
|
||||
zoneinfo = None
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@@ -442,7 +451,7 @@ def force_real_str(s, encoding='utf-8', strings_only=False, errors='strict'):
|
||||
"""
|
||||
if s is not None:
|
||||
s = force_str(s, encoding, strings_only, errors)
|
||||
if type(s) != str:
|
||||
if type(s) is not str:
|
||||
s = '' + s
|
||||
|
||||
# Remove common indentation to get the correct Markdown rendering
|
||||
@@ -465,7 +474,10 @@ def field_value_to_representation(field, value):
|
||||
else:
|
||||
value = str(value)
|
||||
|
||||
if isinstance(value, pytz.BaseTzInfo):
|
||||
elif isinstance(value, pytz.BaseTzInfo):
|
||||
value = str(value)
|
||||
|
||||
elif zoneinfo is not None and isinstance(value, zoneinfo.ZoneInfo):
|
||||
value = str(value)
|
||||
|
||||
# JSON roundtrip ensures that the value is valid JSON;
|
||||
|
||||
@@ -13,7 +13,9 @@ from .app_settings import swagger_settings
|
||||
from .renderers import (
|
||||
ReDocOldRenderer,
|
||||
ReDocRenderer,
|
||||
SwaggerJSONRenderer,
|
||||
SwaggerUIRenderer,
|
||||
SwaggerYAMLRenderer,
|
||||
_SpecRenderer,
|
||||
)
|
||||
|
||||
@@ -77,6 +79,20 @@ def get_schema_view(info=None, url=None, patterns=None, urlconf=None, public=Fal
|
||||
validators = validators or []
|
||||
_spec_renderers = tuple(renderer.with_validators(validators) for renderer in SPEC_RENDERERS)
|
||||
|
||||
# optionally copy renderers with the validators that are configured above
|
||||
if swagger_settings.USE_COMPAT_RENDERERS:
|
||||
warnings.warn(
|
||||
"SwaggerJSONRenderer & SwaggerYAMLRenderer's `format` has changed to not include a `.` prefix, "
|
||||
"please silence this warning by setting `SWAGGER_USE_COMPAT_RENDERERS = False` "
|
||||
"in your Django settings and ensure your application works "
|
||||
"(check your URLCONF and swagger/redoc URLs).",
|
||||
DeprecationWarning)
|
||||
_spec_renderers += tuple(
|
||||
type(cls.__name__, (cls,), {'format': '.' + cls.format})
|
||||
for cls in _spec_renderers
|
||||
if issubclass(cls, (SwaggerJSONRenderer, SwaggerYAMLRenderer))
|
||||
)
|
||||
|
||||
class SchemaView(APIView):
|
||||
_ignore_model_permissions = True
|
||||
schema = None # exclude from schema
|
||||
|
||||
Reference in New Issue
Block a user