Improve RelatedField and callable default handling
- callable default values will now be properly called - PrimaryKeyRelatedField and SlugRelatedField will now return an appropriate type based on the relation model's Field - mock views now have a request object bound even when public is True
This commit is contained in:
+20
-9
@@ -3,6 +3,9 @@ import json
|
||||
import os
|
||||
|
||||
import pytest
|
||||
from django.contrib.auth.models import User
|
||||
from rest_framework.test import APIRequestFactory
|
||||
from rest_framework.views import APIView
|
||||
from ruamel import yaml
|
||||
|
||||
from drf_yasg import openapi, codecs
|
||||
@@ -10,11 +13,16 @@ from drf_yasg.generators import OpenAPISchemaGenerator
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def generator():
|
||||
return OpenAPISchemaGenerator(
|
||||
info=openapi.Info(title="Test generator", default_version="v1"),
|
||||
version="v2",
|
||||
)
|
||||
def mock_schema_request(db):
|
||||
from rest_framework.test import force_authenticate
|
||||
|
||||
factory = APIRequestFactory()
|
||||
user = User.objects.create_user(username='admin', is_staff=True, is_superuser=True)
|
||||
|
||||
request = factory.get('/swagger.json')
|
||||
force_authenticate(request, user=user)
|
||||
request = APIView().initialize_request(request)
|
||||
return request
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
@@ -28,13 +36,16 @@ def codec_yaml():
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def swagger(generator):
|
||||
return generator.get_schema(None, True)
|
||||
def swagger(mock_schema_request):
|
||||
generator = OpenAPISchemaGenerator(
|
||||
info=openapi.Info(title="Test generator", default_version="v1"),
|
||||
version="v2",
|
||||
)
|
||||
return generator.get_schema(mock_schema_request, True)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def swagger_dict(generator):
|
||||
swagger = generator.get_schema(None, True)
|
||||
def swagger_dict(swagger):
|
||||
json_bytes = codec_json().encode(swagger)
|
||||
return json.loads(json_bytes.decode('utf-8'))
|
||||
|
||||
|
||||
+29
-2
@@ -178,6 +178,7 @@ paths:
|
||||
description: slug model help_text
|
||||
required: true
|
||||
type: string
|
||||
format: slug
|
||||
pattern: '[a-z0-9]+(?:-[a-z0-9]+)'
|
||||
/articles/{slug}/image/:
|
||||
get:
|
||||
@@ -231,6 +232,7 @@ paths:
|
||||
description: slug model help_text
|
||||
required: true
|
||||
type: string
|
||||
format: slug
|
||||
pattern: '[a-z0-9]+(?:-[a-z0-9]+)'
|
||||
/plain/:
|
||||
get:
|
||||
@@ -355,12 +357,12 @@ paths:
|
||||
- name: username
|
||||
in: query
|
||||
description: this field is generated from a query_serializer
|
||||
required: true
|
||||
required: false
|
||||
type: string
|
||||
- name: is_staff
|
||||
in: query
|
||||
description: this one too!
|
||||
required: true
|
||||
required: false
|
||||
type: boolean
|
||||
responses:
|
||||
'200':
|
||||
@@ -464,6 +466,11 @@ definitions:
|
||||
title:
|
||||
description: title model help_text
|
||||
type: string
|
||||
author:
|
||||
description: The ID of the user that created this article; if none is provided,
|
||||
defaults to the currently logged in user.
|
||||
type: integer
|
||||
default: 1
|
||||
body:
|
||||
description: body serializer help_text
|
||||
type: string
|
||||
@@ -523,6 +530,12 @@ definitions:
|
||||
type: integer
|
||||
readOnly: true
|
||||
owner:
|
||||
description: The ID of the user that created this snippet; if none is provided,
|
||||
defaults to the currently logged in user.
|
||||
type: integer
|
||||
default: 1
|
||||
owner_as_string:
|
||||
description: The ID of the user that created this snippet.
|
||||
type: string
|
||||
readOnly: true
|
||||
title:
|
||||
@@ -1022,10 +1035,12 @@ definitions:
|
||||
difficulty_factor:
|
||||
description: this is here just to test FloatField
|
||||
type: number
|
||||
default: 6.9
|
||||
readOnly: true
|
||||
UserSerializerrr:
|
||||
required:
|
||||
- username
|
||||
- articles
|
||||
- snippets
|
||||
type: object
|
||||
properties:
|
||||
@@ -1039,6 +1054,11 @@ definitions:
|
||||
email:
|
||||
type: string
|
||||
format: email
|
||||
articles:
|
||||
type: array
|
||||
items:
|
||||
type: integer
|
||||
uniqueItems: true
|
||||
snippets:
|
||||
type: array
|
||||
items:
|
||||
@@ -1054,6 +1074,13 @@ definitions:
|
||||
type: string
|
||||
format: date
|
||||
readOnly: true
|
||||
article_slugs:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
readOnly: true
|
||||
uniqueItems: true
|
||||
readOnly: true
|
||||
securityDefinitions:
|
||||
basic:
|
||||
type: basic
|
||||
|
||||
@@ -2,7 +2,6 @@ from datadiff.tools import assert_equal
|
||||
|
||||
|
||||
def test_reference_schema(swagger_dict, reference_schema):
|
||||
# formatted better than pytest diff
|
||||
swagger_dict = dict(swagger_dict)
|
||||
reference_schema = dict(reference_schema)
|
||||
ignore = ['info', 'host', 'schemes', 'basePath', 'securityDefinitions']
|
||||
@@ -10,4 +9,5 @@ def test_reference_schema(swagger_dict, reference_schema):
|
||||
swagger_dict.pop(attr, None)
|
||||
reference_schema.pop(attr, None)
|
||||
|
||||
# formatted better than pytest diff
|
||||
assert_equal(swagger_dict, reference_schema)
|
||||
|
||||
@@ -7,16 +7,11 @@ from drf_yasg import openapi, codecs
|
||||
from drf_yasg.generators import OpenAPISchemaGenerator
|
||||
|
||||
|
||||
def test_schema_generates_without_errors(generator):
|
||||
generator.get_schema(None, True)
|
||||
|
||||
|
||||
def test_schema_is_valid(generator, codec_yaml):
|
||||
swagger = generator.get_schema(request=None, public=False)
|
||||
def test_schema_is_valid(swagger, codec_yaml):
|
||||
codec_yaml.encode(swagger)
|
||||
|
||||
|
||||
def test_invalid_schema_fails(codec_json):
|
||||
def test_invalid_schema_fails(codec_json, mock_schema_request):
|
||||
# noinspection PyTypeChecker
|
||||
bad_generator = OpenAPISchemaGenerator(
|
||||
info=openapi.Info(
|
||||
@@ -26,40 +21,37 @@ def test_invalid_schema_fails(codec_json):
|
||||
version="v2",
|
||||
)
|
||||
|
||||
swagger = bad_generator.get_schema(None, True)
|
||||
swagger = bad_generator.get_schema(mock_schema_request, True)
|
||||
with pytest.raises(codecs.SwaggerValidationError):
|
||||
codec_json.encode(swagger)
|
||||
|
||||
|
||||
def test_json_codec_roundtrip(codec_json, generator, validate_schema):
|
||||
swagger = generator.get_schema(None, True)
|
||||
def test_json_codec_roundtrip(codec_json, swagger, validate_schema):
|
||||
json_bytes = codec_json.encode(swagger)
|
||||
validate_schema(json.loads(json_bytes.decode('utf-8')))
|
||||
|
||||
|
||||
def test_yaml_codec_roundtrip(codec_yaml, generator, validate_schema):
|
||||
swagger = generator.get_schema(None, True)
|
||||
def test_yaml_codec_roundtrip(codec_yaml, swagger, validate_schema):
|
||||
yaml_bytes = codec_yaml.encode(swagger)
|
||||
assert b'omap' not in yaml_bytes # ensure no ugly !!omap is outputted
|
||||
assert b'&id' not in yaml_bytes and b'*id' not in yaml_bytes # ensure no YAML references are generated
|
||||
validate_schema(yaml.safe_load(yaml_bytes.decode('utf-8')))
|
||||
|
||||
|
||||
def test_yaml_and_json_match(codec_yaml, codec_json, generator):
|
||||
swagger = generator.get_schema(None, True)
|
||||
def test_yaml_and_json_match(codec_yaml, codec_json, swagger):
|
||||
yaml_schema = yaml.safe_load(codec_yaml.encode(swagger).decode('utf-8'))
|
||||
json_schema = json.loads(codec_json.encode(swagger).decode('utf-8'))
|
||||
assert yaml_schema == json_schema
|
||||
|
||||
|
||||
def test_basepath_only():
|
||||
def test_basepath_only(mock_schema_request):
|
||||
generator = OpenAPISchemaGenerator(
|
||||
info=openapi.Info(title="Test generator", default_version="v1"),
|
||||
version="v2",
|
||||
url='/basepath/',
|
||||
)
|
||||
|
||||
swagger = generator.get_schema(None, public=True)
|
||||
swagger = generator.get_schema(mock_schema_request, public=True)
|
||||
assert 'host' not in swagger
|
||||
assert 'schemes' not in swagger
|
||||
assert swagger['basePath'] == '/' # base path is not implemented for now
|
||||
|
||||
Reference in New Issue
Block a user