We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
API Docs - Typo error on /virtualisation/interfaces/
<!--
    Before opening a new issue, please search through the existing issues to
    see if your topic has already been addressed. Note that you may need to
    remove the "is:open" filter from the search bar to include closed issues.

    Check the appropriate type for your issue below by placing an x between the
    brackets. For assistance with installation issues, or for any other issues
    other than those listed below, please raise your topic for discussion on
    our mailing list:

        https://groups.google.com/forum/#!forum/netbox-discuss

    Please note that issues which do not fall under any of the below categories
    will be closed. Due to an excessive backlog of feature requests, we are
    not currently accepting any proposals which extend NetBox's feature scope.

    Do not prepend any sort of tag to your issue's title. An administrator will
    review your issue and assign labels as appropriate.
--->
### Issue type
[ ] Feature request <!-- An enhancement of existing functionality -->
[ ] Bug report      <!-- Unexpected or erroneous behavior -->
[X] Documentation   <!-- A modification to the documentation -->

<!--
    Please describe the environment in which you are running NetBox. (Be sure
    to verify that you are running the latest stable release of NetBox before
    submitting a bug report.) If you are submitting a bug report and have made
    any changes to the code base, please first validate that your bug can be
    recreated while running an official release.
-->
### Environment
* Python version:  3.6.5
* NetBox version:  2.3.3

<!--
    BUG REPORTS must include:
        * A list of the steps needed for someone else to reproduce the bug
        * A description of the expected and observed behavior
        * Any relevant error messages (screenshots may also help)

    FEATURE REQUESTS must include:
        * A detailed description of the proposed functionality
        * A use case for the new feature
        * A rough description of any necessary changes to the database schema
        * Any relevant third-party libraries which would be needed
-->
### Description
Hello,

On the API documentation it seems there is a little error.

On `/virtualisation/interfaces/` endpoint, method `POST`, the field `device` is marked as mandatory, but the API only respond to the field `virtual_machine`.

The error message returned by the API is also misleading :
```
{
 "non_field_errors": [
   "An interface must belong to either a device or a virtual machine."
 ]
}
```

It seems the error is also present on `/virtualisation/interfaces/{id}` methods `PUT` and `PATCH`.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `netbox/utilities/custom_inspectors.py`
Content:
```
1 from drf_yasg import openapi
2 from drf_yasg.inspectors import FieldInspector, NotHandled, PaginatorInspector, FilterInspector, SwaggerAutoSchema
3 from rest_framework.fields import ChoiceField
4 from rest_framework.relations import ManyRelatedField
5 from taggit_serializer.serializers import TagListSerializerField
6 
7 from extras.api.customfields import CustomFieldsSerializer
8 from utilities.api import ChoiceField, SerializedPKRelatedField, WritableNestedSerializer
9 
10 
11 class NetBoxSwaggerAutoSchema(SwaggerAutoSchema):
12     def get_request_serializer(self):
13         serializer = super().get_request_serializer()
14 
15         if serializer is not None and self.method in self.implicit_body_methods:
16             properties = {}
17             for child_name, child in serializer.fields.items():
18                 if isinstance(child, (ChoiceField, WritableNestedSerializer)):
19                     properties[child_name] = None
20                 elif isinstance(child, ManyRelatedField) and isinstance(child.child_relation, SerializedPKRelatedField):
21                     properties[child_name] = None
22 
23             if properties:
24                 writable_class = type('Writable' + type(serializer).__name__, (type(serializer),), properties)
25                 serializer = writable_class()
26 
27         return serializer
28 
29 
30 class SerializedPKRelatedFieldInspector(FieldInspector):
31     def field_to_swagger_object(self, field, swagger_object_type, use_references, **kwargs):
32         SwaggerType, ChildSwaggerType = self._get_partial_types(field, swagger_object_type, use_references, **kwargs)
33         if isinstance(field, SerializedPKRelatedField):
34             return self.probe_field_inspectors(field.serializer(), ChildSwaggerType, use_references)
35 
36         return NotHandled
37 
38 
39 class TagListFieldInspector(FieldInspector):
40     def field_to_swagger_object(self, field, swagger_object_type, use_references, **kwargs):
41         SwaggerType, ChildSwaggerType = self._get_partial_types(field, swagger_object_type, use_references, **kwargs)
42         if isinstance(field, TagListSerializerField):
43             child_schema = self.probe_field_inspectors(field.child, ChildSwaggerType, use_references)
44             return SwaggerType(
45                 type=openapi.TYPE_ARRAY,
46                 items=child_schema,
47             )
48 
49         return NotHandled
50 
51 
52 class CustomChoiceFieldInspector(FieldInspector):
53     def field_to_swagger_object(self, field, swagger_object_type, use_references, **kwargs):
54         # this returns a callable which extracts title, description and other stuff
55         # https://drf-yasg.readthedocs.io/en/stable/_modules/drf_yasg/inspectors/base.html#FieldInspector._get_partial_types
56         SwaggerType, _ = self._get_partial_types(field, swagger_object_type, use_references, **kwargs)
57 
58         if isinstance(field, ChoiceField):
59             value_schema = openapi.Schema(type=openapi.TYPE_INTEGER)
60 
61             choices = list(field._choices.keys())
62             if set([None] + choices) == {None, True, False}:
63                 # DeviceType.subdevice_role, Device.face and InterfaceConnection.connection_status all need to be
64                 # differentiated since they each have subtly different values in their choice keys.
65                 # - subdevice_role and connection_status are booleans, although subdevice_role includes None
66                 # - face is an integer set {0, 1} which is easily confused with {False, True}
67                 schema_type = openapi.TYPE_INTEGER
68                 if all(type(x) == bool for x in [c for c in choices if c is not None]):
69                     schema_type = openapi.TYPE_BOOLEAN
70                 value_schema = openapi.Schema(type=schema_type)
71                 value_schema['x-nullable'] = True
72 
73             schema = SwaggerType(type=openapi.TYPE_OBJECT, required=["label", "value"], properties={
74                 "label": openapi.Schema(type=openapi.TYPE_STRING),
75                 "value": value_schema
76             })
77 
78             return schema
79 
80         elif isinstance(field, CustomFieldsSerializer):
81             schema = SwaggerType(type=openapi.TYPE_OBJECT)
82             return schema
83 
84         return NotHandled
85 
86 
87 class NullableBooleanFieldInspector(FieldInspector):
88     def process_result(self, result, method_name, obj, **kwargs):
89 
90         if isinstance(result, openapi.Schema) and isinstance(obj, ChoiceField) and result.type == 'boolean':
91             keys = obj.choices.keys()
92             if set(keys) == {None, True, False}:
93                 result['x-nullable'] = True
94                 result.type = 'boolean'
95 
96         return result
97 
98 
99 class IdInFilterInspector(FilterInspector):
100     def process_result(self, result, method_name, obj, **kwargs):
101         if isinstance(result, list):
102             params = [p for p in result if isinstance(p, openapi.Parameter) and p.name == 'id__in']
103             for p in params:
104                 p.type = 'string'
105 
106         return result
107 
108 
109 class NullablePaginatorInspector(PaginatorInspector):
110     def process_result(self, result, method_name, obj, **kwargs):
111         if method_name == 'get_paginated_response' and isinstance(result, openapi.Schema):
112             next = result.properties['next']
113             if isinstance(next, openapi.Schema):
114                 next['x-nullable'] = True
115             previous = result.properties['previous']
116             if isinstance(previous, openapi.Schema):
117                 previous['x-nullable'] = True
118 
119         return result
120
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/netbox/utilities/custom_inspectors.py b/netbox/utilities/custom_inspectors.py
--- a/netbox/utilities/custom_inspectors.py
+++ b/netbox/utilities/custom_inspectors.py
@@ -1,14 +1,24 @@
 from drf_yasg import openapi
 from drf_yasg.inspectors import FieldInspector, NotHandled, PaginatorInspector, FilterInspector, SwaggerAutoSchema
+from drf_yasg.utils import get_serializer_ref_name
 from rest_framework.fields import ChoiceField
 from rest_framework.relations import ManyRelatedField
 from taggit_serializer.serializers import TagListSerializerField
 
+from dcim.api.serializers import InterfaceSerializer as DCIMInterfaceSerializer
+from virtualization.api.serializers import InterfaceSerializer as VirtualMachineInterfaceSerializer
 from extras.api.customfields import CustomFieldsSerializer
 from utilities.api import ChoiceField, SerializedPKRelatedField, WritableNestedSerializer
 
 
+# this might be ugly, but it limits drf_yasg-specific code to this file
+DCIMInterfaceSerializer.Meta.ref_name = 'DCIMInterface'
+VirtualMachineInterfaceSerializer.Meta.ref_name = 'VirtualMachineInterface'
+
+
 class NetBoxSwaggerAutoSchema(SwaggerAutoSchema):
+    writable_serializers = {}
+
     def get_request_serializer(self):
         serializer = super().get_request_serializer()
 
@@ -21,7 +31,17 @@
                     properties[child_name] = None
 
             if properties:
-                writable_class = type('Writable' + type(serializer).__name__, (type(serializer),), properties)
+                if type(serializer) not in self.writable_serializers:
+                    writable_name = 'Writable' + type(serializer).__name__
+                    meta_class = getattr(type(serializer), 'Meta', None)
+                    if meta_class:
+                        ref_name = 'Writable' + get_serializer_ref_name(serializer)
+                        writable_meta = type('Meta', (meta_class,), {'ref_name': ref_name})
+                        properties['Meta'] = writable_meta
+
+                    self.writable_serializers[type(serializer)] = type(writable_name, (type(serializer),), properties)
+
+                writable_class = self.writable_serializers[type(serializer)]
                 serializer = writable_class()
 
         return serializer

{"golden_diff": "diff --git a/netbox/utilities/custom_inspectors.py b/netbox/utilities/custom_inspectors.py\n--- a/netbox/utilities/custom_inspectors.py\n+++ b/netbox/utilities/custom_inspectors.py\n@@ -1,14 +1,24 @@\n from drf_yasg import openapi\n from drf_yasg.inspectors import FieldInspector, NotHandled, PaginatorInspector, FilterInspector, SwaggerAutoSchema\n+from drf_yasg.utils import get_serializer_ref_name\n from rest_framework.fields import ChoiceField\n from rest_framework.relations import ManyRelatedField\n from taggit_serializer.serializers import TagListSerializerField\n \n+from dcim.api.serializers import InterfaceSerializer as DCIMInterfaceSerializer\n+from virtualization.api.serializers import InterfaceSerializer as VirtualMachineInterfaceSerializer\n from extras.api.customfields import CustomFieldsSerializer\n from utilities.api import ChoiceField, SerializedPKRelatedField, WritableNestedSerializer\n \n \n+# this might be ugly, but it limits drf_yasg-specific code to this file\n+DCIMInterfaceSerializer.Meta.ref_name = 'DCIMInterface'\n+VirtualMachineInterfaceSerializer.Meta.ref_name = 'VirtualMachineInterface'\n+\n+\n class NetBoxSwaggerAutoSchema(SwaggerAutoSchema):\n+    writable_serializers = {}\n+\n     def get_request_serializer(self):\n         serializer = super().get_request_serializer()\n \n@@ -21,7 +31,17 @@\n                     properties[child_name] = None\n \n             if properties:\n-                writable_class = type('Writable' + type(serializer).__name__, (type(serializer),), properties)\n+                if type(serializer) not in self.writable_serializers:\n+                    writable_name = 'Writable' + type(serializer).__name__\n+                    meta_class = getattr(type(serializer), 'Meta', None)\n+                    if meta_class:\n+                        ref_name = 'Writable' + get_serializer_ref_name(serializer)\n+                        writable_meta = type('Meta', (meta_class,), {'ref_name': ref_name})\n+                        properties['Meta'] = writable_meta\n+\n+                    self.writable_serializers[type(serializer)] = type(writable_name, (type(serializer),), properties)\n+\n+                writable_class = self.writable_serializers[type(serializer)]\n                 serializer = writable_class()\n \n         return serializer\n", "issue": "API Docs - Typo error on /virtualisation/interfaces/\n<!--\r\n    Before opening a new issue, please search through the existing issues to\r\n    see if your topic has already been addressed. Note that you may need to\r\n    remove the \"is:open\" filter from the search bar to include closed issues.\r\n\r\n    Check the appropriate type for your issue below by placing an x between the\r\n    brackets. For assistance with installation issues, or for any other issues\r\n    other than those listed below, please raise your topic for discussion on\r\n    our mailing list:\r\n\r\n        https://groups.google.com/forum/#!forum/netbox-discuss\r\n\r\n    Please note that issues which do not fall under any of the below categories\r\n    will be closed. Due to an excessive backlog of feature requests, we are\r\n    not currently accepting any proposals which extend NetBox's feature scope.\r\n\r\n    Do not prepend any sort of tag to your issue's title. An administrator will\r\n    review your issue and assign labels as appropriate.\r\n--->\r\n### Issue type\r\n[ ] Feature request <!-- An enhancement of existing functionality -->\r\n[ ] Bug report      <!-- Unexpected or erroneous behavior -->\r\n[X] Documentation   <!-- A modification to the documentation -->\r\n\r\n<!--\r\n    Please describe the environment in which you are running NetBox. (Be sure\r\n    to verify that you are running the latest stable release of NetBox before\r\n    submitting a bug report.) If you are submitting a bug report and have made\r\n    any changes to the code base, please first validate that your bug can be\r\n    recreated while running an official release.\r\n-->\r\n### Environment\r\n* Python version:  3.6.5\r\n* NetBox version:  2.3.3\r\n\r\n<!--\r\n    BUG REPORTS must include:\r\n        * A list of the steps needed for someone else to reproduce the bug\r\n        * A description of the expected and observed behavior\r\n        * Any relevant error messages (screenshots may also help)\r\n\r\n    FEATURE REQUESTS must include:\r\n        * A detailed description of the proposed functionality\r\n        * A use case for the new feature\r\n        * A rough description of any necessary changes to the database schema\r\n        * Any relevant third-party libraries which would be needed\r\n-->\r\n### Description\r\nHello,\r\n\r\nOn the API documentation it seems there is a little error.\r\n\r\nOn `/virtualisation/interfaces/` endpoint, method `POST`, the field `device` is marked as mandatory, but the API only respond to the field `virtual_machine`.\r\n\r\nThe error message returned by the API is also misleading :\r\n```\r\n{\r\n \"non_field_errors\": [\r\n   \"An interface must belong to either a device or a virtual machine.\"\r\n ]\r\n}\r\n```\r\n\r\nIt seems the error is also present on `/virtualisation/interfaces/{id}` methods `PUT` and `PATCH`.\n", "before_files": [{"content": "from drf_yasg import openapi\nfrom drf_yasg.inspectors import FieldInspector, NotHandled, PaginatorInspector, FilterInspector, SwaggerAutoSchema\nfrom rest_framework.fields import ChoiceField\nfrom rest_framework.relations import ManyRelatedField\nfrom taggit_serializer.serializers import TagListSerializerField\n\nfrom extras.api.customfields import CustomFieldsSerializer\nfrom utilities.api import ChoiceField, SerializedPKRelatedField, WritableNestedSerializer\n\n\nclass NetBoxSwaggerAutoSchema(SwaggerAutoSchema):\n    def get_request_serializer(self):\n        serializer = super().get_request_serializer()\n\n        if serializer is not None and self.method in self.implicit_body_methods:\n            properties = {}\n            for child_name, child in serializer.fields.items():\n                if isinstance(child, (ChoiceField, WritableNestedSerializer)):\n                    properties[child_name] = None\n                elif isinstance(child, ManyRelatedField) and isinstance(child.child_relation, SerializedPKRelatedField):\n                    properties[child_name] = None\n\n            if properties:\n                writable_class = type('Writable' + type(serializer).__name__, (type(serializer),), properties)\n                serializer = writable_class()\n\n        return serializer\n\n\nclass SerializedPKRelatedFieldInspector(FieldInspector):\n    def field_to_swagger_object(self, field, swagger_object_type, use_references, **kwargs):\n        SwaggerType, ChildSwaggerType = self._get_partial_types(field, swagger_object_type, use_references, **kwargs)\n        if isinstance(field, SerializedPKRelatedField):\n            return self.probe_field_inspectors(field.serializer(), ChildSwaggerType, use_references)\n\n        return NotHandled\n\n\nclass TagListFieldInspector(FieldInspector):\n    def field_to_swagger_object(self, field, swagger_object_type, use_references, **kwargs):\n        SwaggerType, ChildSwaggerType = self._get_partial_types(field, swagger_object_type, use_references, **kwargs)\n        if isinstance(field, TagListSerializerField):\n            child_schema = self.probe_field_inspectors(field.child, ChildSwaggerType, use_references)\n            return SwaggerType(\n                type=openapi.TYPE_ARRAY,\n                items=child_schema,\n            )\n\n        return NotHandled\n\n\nclass CustomChoiceFieldInspector(FieldInspector):\n    def field_to_swagger_object(self, field, swagger_object_type, use_references, **kwargs):\n        # this returns a callable which extracts title, description and other stuff\n        # https://drf-yasg.readthedocs.io/en/stable/_modules/drf_yasg/inspectors/base.html#FieldInspector._get_partial_types\n        SwaggerType, _ = self._get_partial_types(field, swagger_object_type, use_references, **kwargs)\n\n        if isinstance(field, ChoiceField):\n            value_schema = openapi.Schema(type=openapi.TYPE_INTEGER)\n\n            choices = list(field._choices.keys())\n            if set([None] + choices) == {None, True, False}:\n                # DeviceType.subdevice_role, Device.face and InterfaceConnection.connection_status all need to be\n                # differentiated since they each have subtly different values in their choice keys.\n                # - subdevice_role and connection_status are booleans, although subdevice_role includes None\n                # - face is an integer set {0, 1} which is easily confused with {False, True}\n                schema_type = openapi.TYPE_INTEGER\n                if all(type(x) == bool for x in [c for c in choices if c is not None]):\n                    schema_type = openapi.TYPE_BOOLEAN\n                value_schema = openapi.Schema(type=schema_type)\n                value_schema['x-nullable'] = True\n\n            schema = SwaggerType(type=openapi.TYPE_OBJECT, required=[\"label\", \"value\"], properties={\n                \"label\": openapi.Schema(type=openapi.TYPE_STRING),\n                \"value\": value_schema\n            })\n\n            return schema\n\n        elif isinstance(field, CustomFieldsSerializer):\n            schema = SwaggerType(type=openapi.TYPE_OBJECT)\n            return schema\n\n        return NotHandled\n\n\nclass NullableBooleanFieldInspector(FieldInspector):\n    def process_result(self, result, method_name, obj, **kwargs):\n\n        if isinstance(result, openapi.Schema) and isinstance(obj, ChoiceField) and result.type == 'boolean':\n            keys = obj.choices.keys()\n            if set(keys) == {None, True, False}:\n                result['x-nullable'] = True\n                result.type = 'boolean'\n\n        return result\n\n\nclass IdInFilterInspector(FilterInspector):\n    def process_result(self, result, method_name, obj, **kwargs):\n        if isinstance(result, list):\n            params = [p for p in result if isinstance(p, openapi.Parameter) and p.name == 'id__in']\n            for p in params:\n                p.type = 'string'\n\n        return result\n\n\nclass NullablePaginatorInspector(PaginatorInspector):\n    def process_result(self, result, method_name, obj, **kwargs):\n        if method_name == 'get_paginated_response' and isinstance(result, openapi.Schema):\n            next = result.properties['next']\n            if isinstance(next, openapi.Schema):\n                next['x-nullable'] = True\n            previous = result.properties['previous']\n            if isinstance(previous, openapi.Schema):\n                previous['x-nullable'] = True\n\n        return result\n", "path": "netbox/utilities/custom_inspectors.py"}], "after_files": [{"content": "from drf_yasg import openapi\nfrom drf_yasg.inspectors import FieldInspector, NotHandled, PaginatorInspector, FilterInspector, SwaggerAutoSchema\nfrom drf_yasg.utils import get_serializer_ref_name\nfrom rest_framework.fields import ChoiceField\nfrom rest_framework.relations import ManyRelatedField\nfrom taggit_serializer.serializers import TagListSerializerField\n\nfrom dcim.api.serializers import InterfaceSerializer as DCIMInterfaceSerializer\nfrom virtualization.api.serializers import InterfaceSerializer as VirtualMachineInterfaceSerializer\nfrom extras.api.customfields import CustomFieldsSerializer\nfrom utilities.api import ChoiceField, SerializedPKRelatedField, WritableNestedSerializer\n\n\n# this might be ugly, but it limits drf_yasg-specific code to this file\nDCIMInterfaceSerializer.Meta.ref_name = 'DCIMInterface'\nVirtualMachineInterfaceSerializer.Meta.ref_name = 'VirtualMachineInterface'\n\n\nclass NetBoxSwaggerAutoSchema(SwaggerAutoSchema):\n    writable_serializers = {}\n\n    def get_request_serializer(self):\n        serializer = super().get_request_serializer()\n\n        if serializer is not None and self.method in self.implicit_body_methods:\n            properties = {}\n            for child_name, child in serializer.fields.items():\n                if isinstance(child, (ChoiceField, WritableNestedSerializer)):\n                    properties[child_name] = None\n                elif isinstance(child, ManyRelatedField) and isinstance(child.child_relation, SerializedPKRelatedField):\n                    properties[child_name] = None\n\n            if properties:\n                if type(serializer) not in self.writable_serializers:\n                    writable_name = 'Writable' + type(serializer).__name__\n                    meta_class = getattr(type(serializer), 'Meta', None)\n                    if meta_class:\n                        ref_name = 'Writable' + get_serializer_ref_name(serializer)\n                        writable_meta = type('Meta', (meta_class,), {'ref_name': ref_name})\n                        properties['Meta'] = writable_meta\n\n                    self.writable_serializers[type(serializer)] = type(writable_name, (type(serializer),), properties)\n\n                writable_class = self.writable_serializers[type(serializer)]\n                serializer = writable_class()\n\n        return serializer\n\n\nclass SerializedPKRelatedFieldInspector(FieldInspector):\n    def field_to_swagger_object(self, field, swagger_object_type, use_references, **kwargs):\n        SwaggerType, ChildSwaggerType = self._get_partial_types(field, swagger_object_type, use_references, **kwargs)\n        if isinstance(field, SerializedPKRelatedField):\n            return self.probe_field_inspectors(field.serializer(), ChildSwaggerType, use_references)\n\n        return NotHandled\n\n\nclass TagListFieldInspector(FieldInspector):\n    def field_to_swagger_object(self, field, swagger_object_type, use_references, **kwargs):\n        SwaggerType, ChildSwaggerType = self._get_partial_types(field, swagger_object_type, use_references, **kwargs)\n        if isinstance(field, TagListSerializerField):\n            child_schema = self.probe_field_inspectors(field.child, ChildSwaggerType, use_references)\n            return SwaggerType(\n                type=openapi.TYPE_ARRAY,\n                items=child_schema,\n            )\n\n        return NotHandled\n\n\nclass CustomChoiceFieldInspector(FieldInspector):\n    def field_to_swagger_object(self, field, swagger_object_type, use_references, **kwargs):\n        # this returns a callable which extracts title, description and other stuff\n        # https://drf-yasg.readthedocs.io/en/stable/_modules/drf_yasg/inspectors/base.html#FieldInspector._get_partial_types\n        SwaggerType, _ = self._get_partial_types(field, swagger_object_type, use_references, **kwargs)\n\n        if isinstance(field, ChoiceField):\n            value_schema = openapi.Schema(type=openapi.TYPE_INTEGER)\n\n            choices = list(field._choices.keys())\n            if set([None] + choices) == {None, True, False}:\n                # DeviceType.subdevice_role, Device.face and InterfaceConnection.connection_status all need to be\n                # differentiated since they each have subtly different values in their choice keys.\n                # - subdevice_role and connection_status are booleans, although subdevice_role includes None\n                # - face is an integer set {0, 1} which is easily confused with {False, True}\n                schema_type = openapi.TYPE_INTEGER\n                if all(type(x) == bool for x in [c for c in choices if c is not None]):\n                    schema_type = openapi.TYPE_BOOLEAN\n                value_schema = openapi.Schema(type=schema_type)\n                value_schema['x-nullable'] = True\n\n            schema = SwaggerType(type=openapi.TYPE_OBJECT, required=[\"label\", \"value\"], properties={\n                \"label\": openapi.Schema(type=openapi.TYPE_STRING),\n                \"value\": value_schema\n            })\n\n            return schema\n\n        elif isinstance(field, CustomFieldsSerializer):\n            schema = SwaggerType(type=openapi.TYPE_OBJECT)\n            return schema\n\n        return NotHandled\n\n\nclass NullableBooleanFieldInspector(FieldInspector):\n    def process_result(self, result, method_name, obj, **kwargs):\n\n        if isinstance(result, openapi.Schema) and isinstance(obj, ChoiceField) and result.type == 'boolean':\n            keys = obj.choices.keys()\n            if set(keys) == {None, True, False}:\n                result['x-nullable'] = True\n                result.type = 'boolean'\n\n        return result\n\n\nclass IdInFilterInspector(FilterInspector):\n    def process_result(self, result, method_name, obj, **kwargs):\n        if isinstance(result, list):\n            params = [p for p in result if isinstance(p, openapi.Parameter) and p.name == 'id__in']\n            for p in params:\n                p.type = 'string'\n\n        return result\n\n\nclass NullablePaginatorInspector(PaginatorInspector):\n    def process_result(self, result, method_name, obj, **kwargs):\n        if method_name == 'get_paginated_response' and isinstance(result, openapi.Schema):\n            next = result.properties['next']\n            if isinstance(next, openapi.Schema):\n                next['x-nullable'] = True\n            previous = result.properties['previous']\n            if isinstance(previous, openapi.Schema):\n                previous['x-nullable'] = True\n\n        return result\n", "path": "netbox/utilities/custom_inspectors.py"}]}