Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

2.1.0 Incompatibility with drf-yasg #124

Closed
johnthagen opened this issue Feb 22, 2021 · 2 comments · Fixed by #125
Closed

2.1.0 Incompatibility with drf-yasg #124

johnthagen opened this issue Feb 22, 2021 · 2 comments · Fixed by #125

Comments

@johnthagen
Copy link
Contributor

johnthagen commented Feb 22, 2021

After updated to django-enumfields==2.1.0 I am getting the following error in a unit test that tests generation of OpenAPI schema using drf-yasg2.

The enum being used is:

from django.contrib.postgres.fields import ArrayField

@unique
class Tag(Enum):
    Upper = "upper"
    Lower = "lower"

class MyModel(models.Model):
    tags = ArrayField(EnumField(Tag), blank=True, null=True)
    ...

Relevant verisions:

Django==3.1.6
drf-yasg==1.20.0
django-enumfields==2.1.0
Traceback
Traceback (most recent call last):
  File "/venv/lib/python3.9/site-packages/django/core/handlers/exception.py", line 47, in inner
    response = get_response(request)
  File "/venv/lib/python3.9/site-packages/django/core/handlers/base.py", line 181, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/venv/lib/python3.9/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view
    return view_func(*args, **kwargs)
  File "/venv/lib/python3.9/site-packages/django/views/generic/base.py", line 70, in view
    return self.dispatch(request, *args, **kwargs)
  File "/venv/lib/python3.9/site-packages/rest_framework/views.py", line 509, in dispatch
    response = self.handle_exception(exc)
  File "/venv/lib/python3.9/site-packages/rest_framework/views.py", line 469, in handle_exception
    self.raise_uncaught_exception(exc)
  File "/venv/lib/python3.9/site-packages/rest_framework/views.py", line 480, in raise_uncaught_exception
    raise exc
  File "/venv/lib/python3.9/site-packages/rest_framework/views.py", line 506, in dispatch
    response = handler(request, *args, **kwargs)
  File "/venv/lib/python3.9/site-packages/drf_yasg/views.py", line 94, in get
    schema = generator.get_schema(request, self.public)
  File "/venv/lib/python3.9/site-packages/drf_yasg/generators.py", line 246, in get_schema
    paths, prefix = self.get_paths(endpoints, components, request, public)
  File "/venv/lib/python3.9/site-packages/drf_yasg/generators.py", line 404, in get_paths
    operation = self.get_operation(view, path, prefix, method, components, request)
  File "/venv/lib/python3.9/site-packages/drf_yasg/generators.py", line 446, in get_operation
    operation = view_inspector.get_operation(operation_keys)
  File "/venv/lib/python3.9/site-packages/drf_yasg/inspectors/view.py", line 45, in get_operation
    responses = self.get_responses()
  File "/venv/lib/python3.9/site-packages/drf_yasg/inspectors/view.py", line 180, in get_responses
    response_serializers = self.get_response_serializers()
  File "/venv/lib/python3.9/site-packages/drf_yasg/inspectors/view.py", line 235, in get_response_serializers
    responses = self.get_default_responses()
  File "/venv/lib/python3.9/site-packages/drf_yasg/inspectors/view.py", line 211, in get_default_responses
    default_schema = self.serializer_to_schema(default_schema) or ''
  File "/venv/lib/python3.9/site-packages/drf_yasg/inspectors/base.py", line 437, in serializer_to_schema
    return self.probe_inspectors(
  File "/venv/lib/python3.9/site-packages/drf_yasg/inspectors/base.py", line 110, in probe_inspectors
    result = method(obj, **kwargs)
  File "/venv/lib/python3.9/site-packages/drf_yasg/inspectors/field.py", line 33, in get_schema
    return self.probe_field_inspectors(serializer, openapi.Schema, self.use_definitions)
  File "/venv/lib/python3.9/site-packages/drf_yasg/inspectors/base.py", line 228, in probe_field_inspectors
    return self.probe_inspectors(
  File "/venv/lib/python3.9/site-packages/drf_yasg/inspectors/base.py", line 110, in probe_inspectors
    result = method(obj, **kwargs)
  File "/venv/lib/python3.9/site-packages/drf_yasg/inspectors/field.py", line 124, in field_to_swagger_object
    actual_schema = definitions.setdefault(ref_name, make_schema_definition)
  File "/venv/lib/python3.9/site-packages/drf_yasg/openapi.py", line 688, in setdefault
    ret = maker()
  File "/venv/lib/python3.9/site-packages/drf_yasg/inspectors/field.py", line 100, in make_schema_definition
    child_schema = self.probe_field_inspectors(
  File "/venv/lib/python3.9/site-packages/drf_yasg/inspectors/base.py", line 228, in probe_field_inspectors
    return self.probe_inspectors(
  File "/venv/lib/python3.9/site-packages/drf_yasg/inspectors/base.py", line 110, in probe_inspectors
    result = method(obj, **kwargs)
  File "/venv/lib/python3.9/site-packages/drf_yasg/inspectors/field.py", line 77, in field_to_swagger_object
    child_schema = self.probe_field_inspectors(field.child, ChildSwaggerType, use_references)
  File "/venv/lib/python3.9/site-packages/drf_yasg/inspectors/base.py", line 228, in probe_field_inspectors
    return self.probe_inspectors(
  File "/venv/lib/python3.9/site-packages/drf_yasg/inspectors/base.py", line 110, in probe_inspectors
    result = method(obj, **kwargs)
  File "/venv/lib/python3.9/site-packages/drf_yasg/inspectors/field.py", line 640, in field_to_swagger_object
    choice = field_value_to_representation(field, choice)
  File "/venv/lib/python3.9/site-packages/drf_yasg/utils.py", line 461, in field_value_to_representation
    value = field.to_representation(value)
  File "/venv/lib/python3.9/site-packages/enumfields/drf/fields.py", line 22, in to_representation
    assert isinstance(instance, self.enum), instance
AssertionError: upper

rest_api/tests/test_views/test_api/test_swagger.py:8 (test_swagger)
client = <rest_framework.test.APIClient object at 0x11b307580>
django_user_model = <class 'django.contrib.auth.models.User'>

    def test_swagger(client: APIClient, django_user_model: Model) -> None:
        """Ensure the OpenAPI specification is generated without error."""
        create_and_login(client, django_user_model)
>       resp = client.get(f"{swagger_json_url}")

test_swagger.py:12: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../../venv/lib/python3.9/site-packages/rest_framework/test.py:288: in get
    response = super().get(path, data=data, **extra)
../../../../venv/lib/python3.9/site-packages/rest_framework/test.py:205: in get
    return self.generic('GET', path, **r)
../../../../venv/lib/python3.9/site-packages/rest_framework/test.py:233: in generic
    return super().generic(
../../../../venv/lib/python3.9/site-packages/django/test/client.py:470: in generic
    return self.request(**r)
../../../../venv/lib/python3.9/site-packages/rest_framework/test.py:285: in request
    return super().request(**kwargs)
../../../../venv/lib/python3.9/site-packages/rest_framework/test.py:237: in request
    request = super().request(**kwargs)
../../../../venv/lib/python3.9/site-packages/django/test/client.py:716: in request
    self.check_exception(response)
../../../../venv/lib/python3.9/site-packages/django/test/client.py:577: in check_exception
    raise exc_value
../../../../venv/lib/python3.9/site-packages/django/core/handlers/exception.py:47: in inner
    response = get_response(request)
../../../../venv/lib/python3.9/site-packages/django/core/handlers/base.py:181: in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
../../../../venv/lib/python3.9/site-packages/django/views/decorators/csrf.py:54: in wrapped_view
    return view_func(*args, **kwargs)
../../../../venv/lib/python3.9/site-packages/django/views/generic/base.py:70: in view
    return self.dispatch(request, *args, **kwargs)
../../../../venv/lib/python3.9/site-packages/rest_framework/views.py:509: in dispatch
    response = self.handle_exception(exc)
../../../../venv/lib/python3.9/site-packages/rest_framework/views.py:469: in handle_exception
    self.raise_uncaught_exception(exc)
../../../../venv/lib/python3.9/site-packages/rest_framework/views.py:480: in raise_uncaught_exception
    raise exc
../../../../venv/lib/python3.9/site-packages/rest_framework/views.py:506: in dispatch
    response = handler(request, *args, **kwargs)
../../../../venv/lib/python3.9/site-packages/drf_yasg/views.py:94: in get
    schema = generator.get_schema(request, self.public)
../../../../venv/lib/python3.9/site-packages/drf_yasg/generators.py:246: in get_schema
    paths, prefix = self.get_paths(endpoints, components, request, public)
../../../../venv/lib/python3.9/site-packages/drf_yasg/generators.py:404: in get_paths
    operation = self.get_operation(view, path, prefix, method, components, request)
../../../../venv/lib/python3.9/site-packages/drf_yasg/generators.py:446: in get_operation
    operation = view_inspector.get_operation(operation_keys)
../../../../venv/lib/python3.9/site-packages/drf_yasg/inspectors/view.py:45: in get_operation
    responses = self.get_responses()
../../../../venv/lib/python3.9/site-packages/drf_yasg/inspectors/view.py:180: in get_responses
    response_serializers = self.get_response_serializers()
../../../../venv/lib/python3.9/site-packages/drf_yasg/inspectors/view.py:235: in get_response_serializers
    responses = self.get_default_responses()
../../../../venv/lib/python3.9/site-packages/drf_yasg/inspectors/view.py:211: in get_default_responses
    default_schema = self.serializer_to_schema(default_schema) or ''
../../../../venv/lib/python3.9/site-packages/drf_yasg/inspectors/base.py:437: in serializer_to_schema
    return self.probe_inspectors(
../../../../venv/lib/python3.9/site-packages/drf_yasg/inspectors/base.py:110: in probe_inspectors
    result = method(obj, **kwargs)
../../../../venv/lib/python3.9/site-packages/drf_yasg/inspectors/field.py:33: in get_schema
    return self.probe_field_inspectors(serializer, openapi.Schema, self.use_definitions)
../../../../venv/lib/python3.9/site-packages/drf_yasg/inspectors/base.py:228: in probe_field_inspectors
    return self.probe_inspectors(
../../../../venv/lib/python3.9/site-packages/drf_yasg/inspectors/base.py:110: in probe_inspectors
    result = method(obj, **kwargs)
../../../../venv/lib/python3.9/site-packages/drf_yasg/inspectors/field.py:124: in field_to_swagger_object
    actual_schema = definitions.setdefault(ref_name, make_schema_definition)
../../../../venv/lib/python3.9/site-packages/drf_yasg/openapi.py:688: in setdefault
    ret = maker()
../../../../venv/lib/python3.9/site-packages/drf_yasg/inspectors/field.py:100: in make_schema_definition
    child_schema = self.probe_field_inspectors(
../../../../venv/lib/python3.9/site-packages/drf_yasg/inspectors/base.py:228: in probe_field_inspectors
    return self.probe_inspectors(
../../../../venv/lib/python3.9/site-packages/drf_yasg/inspectors/base.py:110: in probe_inspectors
    result = method(obj, **kwargs)
../../../../venv/lib/python3.9/site-packages/drf_yasg/inspectors/field.py:77: in field_to_swagger_object
    child_schema = self.probe_field_inspectors(field.child, ChildSwaggerType, use_references)
../../../../venv/lib/python3.9/site-packages/drf_yasg/inspectors/base.py:228: in probe_field_inspectors
    return self.probe_inspectors(
../../../../venv/lib/python3.9/site-packages/drf_yasg/inspectors/base.py:110: in probe_inspectors
    result = method(obj, **kwargs)
../../../../venv/lib/python3.9/site-packages/drf_yasg/inspectors/field.py:640: in field_to_swagger_object
    choice = field_value_to_representation(field, choice)
../../../../venv/lib/python3.9/site-packages/drf_yasg/utils.py:461: in field_value_to_representation
    value = field.to_representation(value)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = EnumField(choices=[(<Tag.Upper: 'upper'>, 'Upper'), (<Tag.Lower: 'lower'>, 'Lower')], enum=<enum 'Tag'>, label='Tags')
instance = 'upper'

    def to_representation(self, instance):
>       assert isinstance(instance, self.enum), instance
E       AssertionError: upper

../../../../venv/lib/python3.9/site-packages/enumfields/drf/fields.py:22: AssertionError

Stepping through in the debugger, it looks like to_representation() is being passed a str instance which is tripping this assertion.

The unit test is roughly:

def test_swagger(client: APIClient) -> None:
    """Ensure the OpenAPI specification is generated without error."""
    resp = client.get("/rest/api/swagger.json")
    assert resp.status_code == HTTP_200_OK
@johnthagen
Copy link
Contributor Author

johnthagen commented Feb 22, 2021

I believe the breaking commit is this: 0eabdb4

Specifically when this code was removed:

            if not isinstance(instance, self.enum):
                instance = self.enum(instance)  # Try to cast it

@johnthagen
Copy link
Contributor Author

Pinging @gsakkis for thoughts as they were the one to remove this code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant