diff --git a/.travis.yml b/.travis.yml index 1a36a61a..25071bc1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,47 +1,41 @@ language: python +# This only controls the version of Python used to run tox, the +# versions used for the tests are handled by tox itself. Python 3.5 +# is only installed if we explicitly request it, so we have to use +# it as the base, so that it's available to tox. Python 2.7 and 3.4 +# are available in the Travis images by default. See: +# https://github.com/travis-ci/travis-ci/issues/4794#issuecomment-143758799 +python: "3.5" sudo: false env: - TOX_ENV=py27-flake8 - - TOX_ENV=py26-django1.5-drf2.3 - - TOX_ENV=py26-django1.6-drf3.1 - - TOX_ENV=py27-django1.5-drf2.3 - - TOX_ENV=py27-django1.5-drf2.4 - - TOX_ENV=py27-django1.5-drf3.0 - - TOX_ENV=py27-django1.5-drf3.1 - - TOX_ENV=py27-django1.6-drf2.3 - - TOX_ENV=py27-django1.6-drf2.4 - - TOX_ENV=py27-django1.6-drf3.0 - - TOX_ENV=py27-django1.6-drf3.1 - - TOX_ENV=py27-django1.7-drf2.3 - - TOX_ENV=py27-django1.7-drf2.4 - - TOX_ENV=py27-django1.7-drf3.0 - - TOX_ENV=py27-django1.7-drf3.1 - TOX_ENV=py27-django1.8-drf2.3 - TOX_ENV=py27-django1.8-drf2.4 - TOX_ENV=py27-django1.8-drf3.0 - TOX_ENV=py27-django1.8-drf3.1 - - TOX_ENV=py33-django1.5-drf2.3 + - TOX_ENV=py27-django1.8-drf3.2 + - TOX_ENV=py27-django1.8-drf3.3 + - TOX_ENV=py27-django1.9-drf3.3 - TOX_ENV=py33-django1.8-drf3.1 - - TOX_ENV=py34-django1.5-drf2.3 - - TOX_ENV=py34-django1.5-drf2.4 - - TOX_ENV=py34-django1.5-drf3.0 - - TOX_ENV=py34-django1.5-drf3.1 - - TOX_ENV=py34-django1.6-drf2.3 - - TOX_ENV=py34-django1.6-drf2.4 - - TOX_ENV=py34-django1.6-drf3.0 - - TOX_ENV=py34-django1.6-drf3.1 - - TOX_ENV=py34-django1.7-drf2.3 - - TOX_ENV=py34-django1.7-drf2.4 - - TOX_ENV=py34-django1.7-drf3.0 - - TOX_ENV=py34-django1.7-drf3.1 + - TOX_ENV=py33-django1.8-drf3.2 + - TOX_ENV=py33-django1.8-drf3.3 - TOX_ENV=py34-django1.8-drf2.3 - TOX_ENV=py34-django1.8-drf2.4 - TOX_ENV=py34-django1.8-drf3.0 - TOX_ENV=py34-django1.8-drf3.1 + - TOX_ENV=py34-django1.8-drf3.2 + - TOX_ENV=py34-django1.8-drf3.3 + - TOX_ENV=py34-django1.9-drf3.3 + - TOX_ENV=py35-django1.8-drf3.3 + - TOX_ENV=py35-django1.9-drf3.3 matrix: + allow_failures: + - env: TOX_ENV=py27-django1.9-drf3.3 + - env: TOX_ENV=py34-django1.9-drf3.3 + - env: TOX_ENV=py35-django1.9-drf3.3 fast_finish: true install: diff --git a/CHANGELOG.md b/CHANGELOG.md index 0d31f4da..afb39823 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,26 @@ # Change Log +## [Unreleased](https://github.com/marcgibbons/django-rest-swagger/tree/HEAD) + +[Full Changelog](https://github.com/marcgibbons/django-rest-swagger/compare/0.3.7...HEAD) + +**Closed issues:** + +- AssertionError: The `slug\_field` argument is required. [\#460](https://github.com/marcgibbons/django-rest-swagger/issues/460) +- Errors with Django 1.10 [\#452](https://github.com/marcgibbons/django-rest-swagger/issues/452) +- Opening the docs makes 2 requests for each endpoint [\#440](https://github.com/marcgibbons/django-rest-swagger/issues/440) +- Serializer Meta option read\_only\_fields is not respected [\#424](https://github.com/marcgibbons/django-rest-swagger/issues/424) +- django1.9 can not work in web browser [\#405](https://github.com/marcgibbons/django-rest-swagger/issues/405) + +**Merged pull requests:** + +- Fix child field instantiation with missing arguments [\#459](https://github.com/marcgibbons/django-rest-swagger/pull/459) ([daluege](https://github.com/daluege)) +- Fixed support for Django 1.10 [\#456](https://github.com/marcgibbons/django-rest-swagger/pull/456) ([tarkatronic](https://github.com/tarkatronic)) +- Update testing matrix [\#451](https://github.com/marcgibbons/django-rest-swagger/pull/451) ([edmorley](https://github.com/edmorley)) +- Respect serializer.Meta.read\_only\_fields in introspector [\#450](https://github.com/marcgibbons/django-rest-swagger/pull/450) ([maroux](https://github.com/maroux)) +- Convert readthedocs link for their .org -\> .io migration for hosted projects [\#449](https://github.com/marcgibbons/django-rest-swagger/pull/449) ([adamchainz](https://github.com/adamchainz)) +- Primitive list fields 413 [\#444](https://github.com/marcgibbons/django-rest-swagger/pull/444) ([Bakuutin](https://github.com/Bakuutin)) + ## [0.3.7](https://github.com/marcgibbons/django-rest-swagger/tree/0.3.7) (2016-05-18) [Full Changelog](https://github.com/marcgibbons/django-rest-swagger/compare/0.3.6...0.3.7) diff --git a/README.md b/README.md index f94ad26f..f0923a41 100644 --- a/README.md +++ b/README.md @@ -41,8 +41,8 @@ This project is built on the [Django REST Framework Docs](https://github.com/mar for more information, see the [documentation][docs]. ## Requirements -* Python (2.6.5+, 2.7, 3.2, 3.3, 3.4) -* Django (1.5.5+, 1.6, 1.7, 1.8) +* Python (2.7, 3.3, 3.4, 3.5) +* Django (1.8) * Django REST framework (2.3.8+) * PyYAML (3.10+) diff --git a/rest_framework_swagger/__init__.py b/rest_framework_swagger/__init__.py index 80593c98..42692b62 100644 --- a/rest_framework_swagger/__init__.py +++ b/rest_framework_swagger/__init__.py @@ -1,4 +1,4 @@ -VERSION = '0.3.7' +VERSION = '0.3.8' DEFAULT_SWAGGER_SETTINGS = { 'exclude_url_names': [], diff --git a/rest_framework_swagger/docgenerator.py b/rest_framework_swagger/docgenerator.py index cd8dda11..f83174b0 100644 --- a/rest_framework_swagger/docgenerator.py +++ b/rest_framework_swagger/docgenerator.py @@ -271,12 +271,14 @@ def _find_field_serializers(self, serializers, found_serializers=set()): def get_thing(field, key): if rest_framework.VERSION >= '3.0.0': from rest_framework.serializers import ListSerializer - if isinstance(field, ListSerializer): + if isinstance(field, ListSerializer) and isinstance(field.child, BaseSerializer): return key(field.child) return key(field) serializers_set = set() for serializer in serializers: + if not hasattr(serializer, 'get_fields'): + continue fields = serializer().get_fields() for name, field in fields.items(): if isinstance(field, BaseSerializer): @@ -296,7 +298,9 @@ def _get_serializer_fields(self, serializer): if serializer is None: return - if hasattr(serializer, '__call__'): + if not hasattr(serializer, 'get_fields'): + fields = {} + elif callable(serializer): fields = serializer().get_fields() else: fields = serializer.get_fields() @@ -379,12 +383,19 @@ def _get_serializer_fields(self, serializer): if isinstance(field, BaseSerializer) or has_many: if isinstance(field, BaseSerializer): - field_serializer = IntrospectorHelper.get_serializer_name(field) + if (rest_framework.VERSION >= '3.0.0' and + isinstance(field, ListSerializer) and + not isinstance(field.child, BaseSerializer)): + + data_type, data_format = get_data_type(field.child) + field_serializer = None + else: + field_serializer = IntrospectorHelper.get_serializer_name(field) - if getattr(field, 'write_only', False): - field_serializer = "Write{}".format(field_serializer) + if getattr(field, 'write_only', False): + field_serializer = "Write{}".format(field_serializer) - f['type'] = field_serializer + f['type'] = field_serializer else: field_serializer = None data_type = 'string' diff --git a/rest_framework_swagger/introspectors.py b/rest_framework_swagger/introspectors.py index b65ae83d..fb84598a 100644 --- a/rest_framework_swagger/introspectors.py +++ b/rest_framework_swagger/introspectors.py @@ -430,16 +430,18 @@ def build_form_parameters(self): Builds form parameters from the serializer class """ data = [] - serializer = self.get_request_serializer_class() + serializer_class = self.get_request_serializer_class() - if serializer is None: + if serializer_class is None: return data - fields = serializer().get_fields() + serializer = serializer_class() + fields = serializer.get_fields() + read_only_fields = getattr(getattr(serializer, 'Meta', None), 'read_only_fields', []) for name, field in fields.items(): - if getattr(field, 'read_only', False): + if getattr(field, 'read_only', False) or name in read_only_fields: continue data_type, data_format = get_data_type(field) or ('string', 'string') diff --git a/rest_framework_swagger/templates/rest_framework_swagger/base.html b/rest_framework_swagger/templates/rest_framework_swagger/base.html index d43fc09b..b4d89509 100644 --- a/rest_framework_swagger/templates/rest_framework_swagger/base.html +++ b/rest_framework_swagger/templates/rest_framework_swagger/base.html @@ -47,7 +47,7 @@
diff --git a/rest_framework_swagger/tests.py b/rest_framework_swagger/tests.py index cbe985eb..875dfc55 100644 --- a/rest_framework_swagger/tests.py +++ b/rest_framework_swagger/tests.py @@ -1432,6 +1432,10 @@ class MySerializer(serializers.Serializer): content = serializers.CharField( max_length=200, min_length=10, default="Vandalay Industries") a_read_only_field = serializers.BooleanField(read_only=True) + another_read_only_field = serializers.BooleanField() + + class Meta: + read_only_fields = ('a_read_only_field', 'another_read_only_field') class MyAPIView(ListCreateAPIView): serializer_class = MySerializer diff --git a/rest_framework_swagger/views.py b/rest_framework_swagger/views.py index 57150fa0..48cde540 100644 --- a/rest_framework_swagger/views.py +++ b/rest_framework_swagger/views.py @@ -5,7 +5,8 @@ from django.views.generic import View from django.utils.safestring import mark_safe from django.utils.encoding import smart_text -from django.shortcuts import render_to_response, RequestContext +from django.shortcuts import render_to_response +from django.template import RequestContext from django.core.exceptions import PermissionDenied from .compat import import_string diff --git a/setup.py b/setup.py index 99a6177d..3873113f 100644 --- a/setup.py +++ b/setup.py @@ -32,24 +32,17 @@ pip install django-rest-swagger Project @ https://github.com/marcgibbons/django-rest-swagger -Docs @ http://django-rest-swagger.readthedocs.org/ +Docs @ https://django-rest-swagger.readthedocs.io/ """ # allow setup.py to be run from any path os.chdir(os.path.normpath(os.path.join(os.path.abspath(__file__), os.pardir))) install_requires = [ - 'Django>=1.5', + 'Django>=1.8', 'djangorestframework>=2.3.8', 'PyYAML>=3.10', ] -import platform - -version = platform.python_version_tuple() -if version < ('2','7'): - install_requires.append('importlib>=1.0.1') - install_requires.append('ordereddict>=1.1') - setup( name='django-rest-swagger', version=VERSION, @@ -68,18 +61,19 @@ author_email='marc_gibbons@rogers.com', maintainer='Ellery Newcomer', maintainer_email='ellery-newcomer@utulsa.edu', - url='http://github.com/marcgibbons/django-rest-swagger', + url='https://github.com/marcgibbons/django-rest-swagger', classifiers=[ 'Environment :: Web Environment', 'Framework :: Django', 'Intended Audience :: Developers', 'License :: OSI Approved :: BSD License', 'Operating System :: OS Independent', - 'Programming Language :: Python :: 2.6', + 'Programming Language :: Python :: 2', 'Programming Language :: Python :: 2.7', - 'Programming Language :: Python :: 3.2', + 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.3', 'Programming Language :: Python :: 3.4', + 'Programming Language :: Python :: 3.5', 'Topic :: Internet :: WWW/HTTP', 'Topic :: Internet :: WWW/HTTP :: Dynamic Content', ], diff --git a/tox.ini b/tox.ini index 3e032980..941bb24a 100644 --- a/tox.ini +++ b/tox.ini @@ -1,31 +1,29 @@ [tox] envlist = py27-flake8, - py26-django{1.5,1.6}-drf{2.3,2.4,3.0,3.1}, - {py27,py32,py33,py34}-django{1.5,1.6,1.7,1.8}-drf{2.3,2.4,3.0,3.1} + {py27,py33,py34}-django1.8-drf{2.3,2.4,3.0,3.1,3.2,3.3}, + # Django 1.9+ requires Python 2.7/3.4+ and django-rest-framework 3.3+. + {py27,py34}-django1.9-drf3.3, + {py35}-django{1.8,1.9}-drf3.3 [testenv] commands = ./runtests.py --stop deps = - django1.5: Django==1.5.11 - django1.6: Django==1.6.11 - django1.7: Django==1.7.8 - django1.8: Django==1.8.2 - drf2.3: djangorestframework==2.3.8 - drf2.4: djangorestframework==2.4.5 - drf3.0: djangorestframework==3.0.5 - drf3.1: djangorestframework==3.1.3 - {py27,py32,py33,py34}-django{1.5,1.6,1.7,1.8}-drf{2.3,2.4}: PyYAML==3.10 - {py27,py32,py33,py34}-django{1.5,1.6,1.7,1.8}-drf{2.3,2.4,3.0,3.1}: Markdown==2.5.1 - py26: Markdown==2.1.1 - py26: importlib==1.0.1 - py26: ordereddict==1.1 - py26: unittest2==1.1.0 + django1.8: Django>=1.8,<1.9 + django1.9: Django>=1.9,<1.10 + drf2.3: djangorestframework>=2.3,<2.4 + drf2.4: djangorestframework>=2.4,<2.5 + drf3.0: djangorestframework>=3.0,<3.1 + drf3.1: djangorestframework>=3.1,<3.2 + drf3.2: djangorestframework>=3.2,<3.3 + drf3.3: djangorestframework>=3.3,<3.4 + {py27,py33,py34}-django{1.8}-drf{2.3,2.4}: PyYAML==3.10 py27: functools32==3.2.3-2 docutils==0.11 argparse==1.2.1 argh==0.23.2 nose==1.3.0 + Markdown==2.5.1 mock==1.0.1 django-nose==1.4 coverage==3.6