def test_get__filter(): class FilterSwaggerAutoSchema(BasicSwaggerAutoSchema): filter_inspectors = [drf_yasg_json_api.inspectors.DjangoFilterInspector] class ProjectSerializer(serializers.ModelSerializer): class Meta: model = Project fields = ('id', 'name', 'archived', 'members') class ProjectViewSet(mixins.ListModelMixin, viewsets.GenericViewSet): queryset = Project.objects.all() serializer_class = ProjectSerializer renderer_classes = [renderers.JSONRenderer] parser_classes = [parsers.JSONParser] swagger_schema = FilterSwaggerAutoSchema filter_backends = (filters.QueryParameterValidationFilter, django_filters.DjangoFilterBackend) filterset_fields = { 'archived': ('exact',), } router = routers.DefaultRouter() router.register(r'projects', ProjectViewSet, **compatibility._basename_or_base_name('projects')) generator = OpenAPISchemaGenerator(info=openapi.Info(title="", default_version=""), patterns=router.urls) swagger = generator.get_schema(None, True) request_parameters_schema = swagger['paths']['/projects/']['get']['parameters'] assert request_parameters_schema[0]['name'] == 'filter[archived]'
def test_post__mark_as_required(): class ProjectSerializer(serializers.ModelSerializer): class Meta: model = Project fields = ('id', 'name', 'archived', 'members') extra_kwargs = { 'name': {'required': True}, 'archived': {'required': False}, 'members': {'required': True}, } class ProjectViewSet(mixins.CreateModelMixin, viewsets.GenericViewSet): queryset = Project.objects.all() serializer_class = ProjectSerializer renderer_classes = [renderers.JSONRenderer] parser_classes = [parsers.JSONParser] swagger_schema = BasicSwaggerAutoSchema router = routers.DefaultRouter() router.register(r'projects', ProjectViewSet, **compatibility._basename_or_base_name('projects')) generator = OpenAPISchemaGenerator(info=openapi.Info(title="", default_version=""), patterns=router.urls) swagger = generator.get_schema(None, True) request_body_schema = swagger['paths']['/projects/']['post']['parameters'][0]['schema']['properties'] assert set(request_body_schema['data']['required']) == {'type', 'attributes', 'relationships'} assert request_body_schema['data']['properties']['attributes']['required'] == ['name'] assert request_body_schema['data']['properties']['relationships']['required'] == ['members'] members_schema = request_body_schema['data']['properties']['relationships']['properties']['members'] assert members_schema['required'] == ['data'] assert set(members_schema['properties']['data']['items']['required']) == {'type', 'id'}
def test_id_based_on_pk(): class ProjectSerializer(serializers.ModelSerializer): class Meta: model = ProjectWithCustomID fields = ['name'] class ProjectViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet): queryset = ProjectWithCustomID.objects.all() serializer_class = ProjectSerializer renderer_classes = [renderers.JSONRenderer] parser_classes = [parsers.JSONParser] swagger_schema = base.BasicSwaggerAutoSchema router = routers.DefaultRouter() router.register(r'projects', ProjectViewSet, **compatibility._basename_or_base_name('projects')) generator = OpenAPISchemaGenerator(info=openapi.Info(title="", default_version=""), patterns=router.urls) swagger = generator.get_schema(request=None, public=True) response_schema = swagger['paths']['/projects/{custom_id}/']['get'][ 'responses']['200']['schema']['properties'] assert 'id' in response_schema['data']['properties'] assert response_schema['data']['properties']['id']['type'] == 'string' assert 'type' in response_schema['data']['properties'] assert 'attributes' in response_schema['data']['properties'] assert list(response_schema['data']['properties']['attributes'] ['properties'].keys()) == ['name']
def test_data_links_self(): class ProjectSerializer(serializers.ModelSerializer): obj_url = serializers.HyperlinkedIdentityField(view_name='any') class Meta: model = test_models.Project fields = ('id', 'obj_url') class ProjectViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet): queryset = test_models.Project.objects.all() serializer_class = ProjectSerializer renderer_classes = [renderers.JSONRenderer] parser_classes = [parsers.JSONParser] swagger_schema = base.BasicSwaggerAutoSchema router = routers.DefaultRouter() router.register(r'projects', ProjectViewSet, **compatibility._basename_or_base_name('projects')) generator = OpenAPISchemaGenerator(info=openapi.Info(title="", default_version=""), patterns=router.urls) swagger = generator.get_schema(request=None, public=True) response_schema = swagger['paths']['/projects/{id}/']['get']['responses'][ '200']['schema']['properties'] assert 'id' in response_schema['data']['properties'] assert 'type' in response_schema['data']['properties'] assert 'links' in response_schema['data']['properties'] assert list(response_schema['data']['properties']['links'] ['properties'].keys()) == ['self']
def test_post__strip_read_only_fields(): class ProjectSerializer(serializers.ModelSerializer): class Meta: model = Project fields = ('id', 'name', 'archived', 'members') read_only_fields = ['archived', 'members'] class ProjectViewSet(mixins.CreateModelMixin, viewsets.GenericViewSet): queryset = Project.objects.all() serializer_class = ProjectSerializer renderer_classes = [renderers.JSONRenderer] parser_classes = [parsers.JSONParser] swagger_schema = BasicSwaggerAutoSchema router = routers.DefaultRouter() router.register(r'projects', ProjectViewSet, **compatibility._basename_or_base_name('projects')) generator = OpenAPISchemaGenerator(info=openapi.Info(title="", default_version=""), patterns=router.urls) swagger = generator.get_schema(None, True) request_body_schema = swagger['paths']['/projects/']['post']['parameters'][0]['schema']['properties'] assert 'id' not in request_body_schema['data']['properties'] assert 'type' in request_body_schema['data']['properties'] assert 'attributes' in request_body_schema['data']['properties'] assert list(request_body_schema['data']['properties']['attributes']['properties'].keys()) == ['name'] assert 'relationships' not in request_body_schema['data']['properties']
def test_non_model_many__responses_override(): class ProjectSerializer(serializers.Serializer): id = serializers.IntegerField() name = serializers.CharField() class ProjectViewSet(viewsets.ViewSet): renderer_classes = [renderers.JSONRenderer] parser_classes = [parsers.JSONParser] swagger_schema = base.BasicSwaggerAutoSchema resource_name = 'projects' @swagger_auto_schema(responses={200: ProjectSerializer(many=True)}) def list(self, request): pass router = routers.DefaultRouter() router.register(r'projects', ProjectViewSet, **compatibility._basename_or_base_name('projects')) generator = OpenAPISchemaGenerator(info=openapi.Info(title="", default_version=""), patterns=router.urls) swagger = generator.get_schema(request=None, public=True) response_schema = swagger['paths']['/projects/']['get']['responses'][ '200']['schema']['properties'] assert 'items' in response_schema['data'] assert 'id' in response_schema['data']['items']['properties'] assert 'type' in response_schema['data']['items']['properties'] assert list(response_schema['data']['items']['properties']['attributes'] ['properties'].keys()) == ['name']
def test_fallback_to_rest_api(): class ProjectSerializer(serializers.ModelSerializer): class Meta: model = test_models.Project fields = ('id', 'name', 'archived', 'members') class ProjectViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet): queryset = test_models.Project.objects.all() serializer_class = ProjectSerializer swagger_schema = base.BasicSwaggerAutoSchema router = routers.DefaultRouter() router.register(r'projects', ProjectViewSet, **compatibility._basename_or_base_name('projects')) generator = OpenAPISchemaGenerator(info=openapi.Info(title="", default_version=""), patterns=router.urls) swagger = generator.get_schema(request=None, public=True) response_schema = swagger['paths']['/projects/{id}/']['get']['responses'][ '200']['schema']['properties'] assert list( response_schema.keys()) == ['id', 'name', 'archived', 'members']
def test_get(): class ProjectSerializer(serializers.ModelSerializer): class Meta: model = Project fields = ('id', 'name', 'archived', 'members') class ProjectViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet): queryset = Project.objects.all() serializer_class = ProjectSerializer renderer_classes = [renderers.JSONRenderer] parser_classes = [parsers.JSONParser] swagger_schema = BasicSwaggerAutoSchema router = routers.DefaultRouter() router.register(r'projects', ProjectViewSet, **compatibility._basename_or_base_name('projects')) generator = OpenAPISchemaGenerator(info=openapi.Info(title="", default_version=""), patterns=router.urls) swagger = generator.get_schema(None, True) response_schema = swagger['paths']['/projects/{id}/']['get']['responses']['200']['schema']['properties'] assert 'id' in response_schema['data']['properties'] assert response_schema['data']['properties']['id']['type'] == 'string' assert 'type' in response_schema['data']['properties'] assert response_schema['data']['properties']['type']['pattern'] == 'projects' assert 'attributes' in response_schema['data']['properties'] assert list(response_schema['data']['properties']['attributes']['properties'].keys()) == ['name', 'archived'] assert 'relationships' in response_schema['data']['properties'] assert list(response_schema['data']['properties']['relationships']['properties'].keys()) == ['members'] members_schema = response_schema['data']['properties']['relationships']['properties']['members']['properties'] assert members_schema['data']['items']['properties']['id']['type'] == 'string' assert members_schema['data']['items']['properties']['type']['pattern'] == 'members'
def test_force_related_resource(serializer_field, expect_array): """ Support off combinations of related resources fields – they do supply models or don't. """ class ProjectSerializer(serializers.ModelSerializer): member_relation = serializer_field class Meta: model = ProjectWithCustomIDAndExtraProperties fields = ['name', 'archived', 'member_relation'] def get_member(self): pass def get_members(self): pass class ProjectViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet): queryset = ProjectWithCustomID.objects.all() serializer_class = ProjectSerializer renderer_classes = [renderers.JSONRenderer] parser_classes = [parsers.JSONParser] swagger_schema = base.BasicSwaggerAutoSchema router = routers.DefaultRouter() router.register(r'projects', ProjectViewSet, **compatibility._basename_or_base_name('projects')) generator = OpenAPISchemaGenerator(info=openapi.Info(title="", default_version=""), patterns=router.urls) swagger = generator.get_schema(request=None, public=True) response_schema = swagger['paths']['/projects/{custom_id}/']['get'][ 'responses']['200']['schema']['properties'] assert 'id' in response_schema['data']['properties'] assert response_schema['data']['properties']['id']['type'] == "string" assert response_schema['data']['properties']['id']['format'] == "int32" assert 'type' in response_schema['data']['properties'] assert 'attributes' in response_schema['data']['properties'] assert list(response_schema['data']['properties']['attributes'] ['properties'].keys()) == ['name', 'archived'] assert 'relationships' in response_schema['data']['properties'] relation_schema = response_schema['data']['properties']['relationships'][ 'properties']['member-relation'] if expect_array: assert 'items' in relation_schema['properties']['data'] data_schema = relation_schema['properties']['data']['items'][ 'properties'] else: assert 'properties' in relation_schema['properties']['data'] data_schema = relation_schema['properties']['data']['properties'] assert data_schema['id']['type'] == 'string' assert data_schema['id']['format'] == 'int64'
def test_related_resource(read_only): """ Correctly select id from non default pk field for both model and related models """ class ProjectSerializer(serializers.ModelSerializer): class Meta: model = ProjectWithCustomID fields = ('custom_id', 'name', 'archived', 'members', 'owner_member') read_only_fields = ['members', 'owner_member'] if read_only else [] class ProjectViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet): queryset = ProjectWithCustomID.objects.all() serializer_class = ProjectSerializer renderer_classes = [renderers.JSONRenderer] parser_classes = [parsers.JSONParser] swagger_schema = base.BasicSwaggerAutoSchema router = routers.DefaultRouter() router.register(r'projects', ProjectViewSet, **compatibility._basename_or_base_name('projects')) generator = OpenAPISchemaGenerator(info=openapi.Info(title="", default_version=""), patterns=router.urls) swagger = generator.get_schema(request=None, public=True) response_schema = swagger['paths']['/projects/{custom_id}/']['get'][ 'responses']['200']['schema']['properties'] assert 'id' in response_schema['data']['properties'] assert response_schema['data']['properties']['id']['type'] == 'string' assert response_schema['data']['properties']['id']['format'] == 'int32' assert 'type' in response_schema['data']['properties'] assert 'attributes' in response_schema['data']['properties'] assert list(response_schema['data']['properties']['attributes'] ['properties'].keys()) == ['name', 'archived'] assert 'relationships' in response_schema['data']['properties'] relationships_schema = response_schema['data']['properties'][ 'relationships']['properties'] assert list(relationships_schema.keys()) == ['members', 'owner-member'] members_schema = relationships_schema['members']['properties'] assert members_schema['data']['items']['properties']['id'][ 'type'] == 'string' assert members_schema['data']['items']['properties']['id'][ 'format'] == 'int64' assert members_schema['data']['items']['properties']['type'][ 'pattern'] == 'member-with-custom-ids' owner_member_schema = relationships_schema['owner-member']['properties'] assert owner_member_schema['data']['properties']['id']['type'] == 'string' assert owner_member_schema['data']['properties']['id']['format'] == 'int64' assert owner_member_schema['data']['properties']['type'][ 'pattern'] == 'member-with-custom-ids'
def test_pagination(): class SwaggerAutoSchemaWithPagination(base.BasicSwaggerAutoSchema): paginator_inspectors = [ drf_yasg_json_api.inspectors.DjangoRestResponsePagination, drf_yasg.inspectors.DjangoRestResponsePagination, drf_yasg.inspectors.CoreAPICompatInspector, ] class ProjectSerializer(serializers.ModelSerializer): class Meta: model = test_models.Project fields = ('id', 'name', 'archived', 'members') class ProjectViewSet(mixins.ListModelMixin, viewsets.GenericViewSet): queryset = test_models.Project.objects.all() serializer_class = ProjectSerializer renderer_classes = [renderers.JSONRenderer] parser_classes = [parsers.JSONParser] swagger_schema = SwaggerAutoSchemaWithPagination pagination_class = pagination.JsonApiPageNumberPagination router = routers.DefaultRouter() router.register(r'projects', ProjectViewSet, **compatibility._basename_or_base_name('projects')) generator = OpenAPISchemaGenerator(info=openapi.Info(title="", default_version=""), patterns=router.urls) swagger = generator.get_schema(request=None, public=True) request_parameters_schema = swagger['paths']['/projects/']['get'][ 'parameters'] assert set( map(operator.itemgetter('name'), request_parameters_schema)) == {'page[number]', 'page[size]'} response_schema = swagger['paths']['/projects/']['get']['responses'][ '200']['schema']['properties'] assert 'id' in response_schema['data']['items']['properties'] assert 'type' in response_schema['data']['items']['properties'] assert 'attributes' in response_schema['data']['items']['properties'] assert 'relationships' in response_schema['data']['items']['properties'] assert 'links' in response_schema assert set(response_schema['links']['properties'].keys()) == { 'first', 'next', 'last', 'prev' } assert 'meta' in response_schema assert 'pagination' in response_schema['meta']['properties'] pagination_response_schema = response_schema['meta']['properties'][ 'pagination']['properties'] assert set(pagination_response_schema.keys()) == {'page', 'pages', 'count'}
def test_post__x_properties(): class XPropertiesSwaggerAutoSchema(drf_yasg_json_api.inspectors.SwaggerAutoSchema): field_inspectors = [ drf_yasg_json_api.inspectors.NamesFormatFilter, drf_yasg_json_api.inspectors.XPropertiesFilter, drf_yasg_json_api.inspectors.InlineSerializerInspector, drf_yasg_json_api.inspectors.IntegerIDFieldInspector, drf_yasg_json_api.inspectors.ManyRelatedFieldInspector, drf_yasg.inspectors.RelatedFieldInspector, drf_yasg.inspectors.SimpleFieldInspector, drf_yasg.inspectors.StringDefaultFieldInspector, ] class ProjectSerializer(serializers.ModelSerializer): class Meta: model = Project fields = ('id', 'name', 'archived', 'members') extra_kwargs = { 'name': {'read_only': True}, 'archived': {'read_only': True}, 'members': {'write_only': True}, } class ProjectViewSet(mixins.CreateModelMixin, viewsets.GenericViewSet): queryset = Project.objects.all() serializer_class = ProjectSerializer renderer_classes = [renderers.JSONRenderer] parser_classes = [parsers.JSONParser] swagger_schema = XPropertiesSwaggerAutoSchema router = routers.DefaultRouter() router.register(r'projects', ProjectViewSet, **compatibility._basename_or_base_name('projects')) generator = OpenAPISchemaGenerator(info=openapi.Info(title="", default_version=""), patterns=router.urls) swagger = generator.get_schema(None, True) request_body_schema = swagger['paths']['/projects/']['post']['parameters'][0]['schema']['properties'] # TODO: add support for marking whole data/relationships if all children write only # assert 'x-writeOnly' in request_body_schema['data']['properties']['relationships'] members_schema = request_body_schema['data']['properties']['relationships']['properties']['members']['properties'] assert 'x-writeOnly' in members_schema['data']['items']['properties']['id'] response_schema = swagger['paths']['/projects/']['post']['responses']['201']['schema']['properties'] # TODO: add support for marking whole attributes key read_only if all children read only # assert 'x-readOnly' in response_schema['data']['properties']['attributes'] assert 'readOnly' in response_schema['data']['properties']['attributes']['properties']['name'] assert 'readOnly' in response_schema['data']['properties']['attributes']['properties']['archived']
def test_deprecate_universal_inline_serializer(recwarn): import drf_yasg.inspectors import drf_yasg_json_api.inspectors class SwaggerAutoSchema(drf_yasg_json_api.inspectors.SwaggerAutoSchema): field_inspectors = [ drf_yasg_json_api.inspectors.NamesFormatFilter, drf_yasg_json_api.inspectors.InlineSerializerSmartInspector, drf_yasg_json_api.inspectors.IntegerIDFieldInspector, drf_yasg_json_api.inspectors. IntegerPrimaryKeyRelatedFieldInspector, drf_yasg_json_api.inspectors.ManyRelatedFieldInspector, drf_yasg.inspectors.RelatedFieldInspector, drf_yasg.inspectors.SimpleFieldInspector, drf_yasg.inspectors.StringDefaultFieldInspector, ] class ProjectSerializer(serializers.ModelSerializer): class Meta: model = test_models.Project fields = ('id', 'name', 'archived', 'members') class ProjectViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet): queryset = test_models.Project.objects.all() serializer_class = ProjectSerializer renderer_classes = [renderers.JSONRenderer] parser_classes = [parsers.JSONParser] swagger_schema = SwaggerAutoSchema router = routers.DefaultRouter() router.register(r'projects', ProjectViewSet, **compatibility._basename_or_base_name('projects')) generator = OpenAPISchemaGenerator(info=openapi.Info(title="", default_version=""), patterns=router.urls) swagger = generator.get_schema(request=None, public=True) response_schema = swagger['paths']['/projects/{id}/']['get']['responses'][ '200']['schema']['properties'] assert 'id' in response_schema['data']['properties'] assert 'type' in response_schema['data']['properties'] assert 'attributes' in response_schema['data']['properties'] recwarn.pop(DrfYasgJsonApiDeprecationWarning)
def test_strip_write_only(): class ProjectSerializer(serializers.ModelSerializer): class Meta: model = test_models.Project fields = ('id', 'name', 'archived', 'members') extra_kwargs = { 'name': { 'write_only': False }, 'archived': { 'write_only': True }, 'members': { 'write_only': True }, } class ProjectViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet): queryset = test_models.Project.objects.all() serializer_class = ProjectSerializer renderer_classes = [renderers.JSONRenderer] parser_classes = [parsers.JSONParser] swagger_schema = base.BasicSwaggerAutoSchema router = routers.DefaultRouter() router.register(r'projects', ProjectViewSet, **compatibility._basename_or_base_name('projects')) generator = OpenAPISchemaGenerator(info=openapi.Info(title="", default_version=""), patterns=router.urls) swagger = generator.get_schema(request=None, public=True) response_schema = swagger['paths']['/projects/{id}/']['get']['responses'][ '200']['schema']['properties'] assert 'id' in response_schema['data']['properties'] assert 'type' in response_schema['data']['properties'] assert list(response_schema['data']['properties']['attributes'] ['properties'].keys()) == ['name'] assert 'relationships' not in response_schema['data']['properties']
def test_get__included(): class MemberSerializer(serializers.ModelSerializer): # projects = serializers.ResourceRelatedField(many=True, read_only=True) class Meta: model = Member fields = ['first_name', 'last_name', 'projects'] class ProjectSerializer(serializers.ModelSerializer): class Meta: model = Project fields = ('id', 'name', 'archived', 'members') included_serializers = { 'members': MemberSerializer, } class ProjectViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet): queryset = Project.objects.all() serializer_class = ProjectSerializer renderer_classes = [renderers.JSONRenderer] parser_classes = [parsers.JSONParser] swagger_schema = BasicSwaggerAutoSchema router = routers.DefaultRouter() router.register(r'projects', ProjectViewSet, **compatibility._basename_or_base_name('projects')) generator = OpenAPISchemaGenerator(info=openapi.Info(title="", default_version=""), patterns=router.urls) swagger = generator.get_schema(None, True) response_schema = swagger['paths']['/projects/{id}/']['get']['responses']['200']['schema']['properties'] assert 'included' in response_schema assert 'members' in response_schema['included']['properties'] included_members_schema = response_schema['included']['properties']['members']['properties'] assert 'projects' in included_members_schema['relationships']['properties'] request_parameters_schema = swagger['paths']['/projects/{id}/']['get']['parameters'] assert request_parameters_schema[0]['name'] == 'include' assert request_parameters_schema[0]['description'].endswith(': members')
def test_included__recursive(): class ProjectViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet): queryset = test_models.Project.objects.all() serializer_class = IncludedRecursiveProjectSerializer renderer_classes = [renderers.JSONRenderer] parser_classes = [parsers.JSONParser] swagger_schema = base.BasicSwaggerAutoSchema router = routers.DefaultRouter() router.register(r'projects', ProjectViewSet, **compatibility._basename_or_base_name('projects')) generator = OpenAPISchemaGenerator(info=openapi.Info(title="", default_version=""), patterns=router.urls) swagger = generator.get_schema(request=None, public=True) response_schema = swagger['paths']['/projects/{id}/']['get']['responses'][ '200']['schema']['properties'] assert 'included' in response_schema assert 'members' in response_schema['included']['properties'] assert 'projects' in response_schema['included']['properties'] included_members_schema = response_schema['included']['properties'][ 'members']['properties'] assert 'projects' in included_members_schema['relationships']['properties'] included_projects_schema = response_schema['included']['properties'][ 'projects']['properties'] assert 'sub-projects' in included_projects_schema['relationships'][ 'properties'] assert 'members' in included_projects_schema['relationships']['properties'] request_parameters_schema = swagger['paths']['/projects/{id}/']['get'][ 'parameters'] assert request_parameters_schema[0]['name'] == 'include' assert request_parameters_schema[0]['description'].endswith( ': sub-projects [recursive], members, members.projects [recursive through: members.projects]' )
def test_included__string_path(): class ProjectSerializer(serializers.ModelSerializer): class Meta: model = test_models.Project fields = ('id', 'name', 'archived', 'members') included_serializers = { 'members': 'tests.test_schema.test_get_included.IncludedStringPathMemberSerializer', } class ProjectViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet): queryset = test_models.Project.objects.all() serializer_class = ProjectSerializer renderer_classes = [renderers.JSONRenderer] parser_classes = [parsers.JSONParser] swagger_schema = base.BasicSwaggerAutoSchema router = routers.DefaultRouter() router.register(r'projects', ProjectViewSet, **compatibility._basename_or_base_name('projects')) generator = OpenAPISchemaGenerator(info=openapi.Info(title="", default_version=""), patterns=router.urls) swagger = generator.get_schema(request=None, public=True) response_schema = swagger['paths']['/projects/{id}/']['get']['responses'][ '200']['schema']['properties'] assert 'included' in response_schema assert 'members' in response_schema['included']['properties'] request_parameters_schema = swagger['paths']['/projects/{id}/']['get'][ 'parameters'] assert request_parameters_schema[0]['name'] == 'include' assert request_parameters_schema[0]['description'].endswith(': members')