mirror of
				https://github.com/encode/django-rest-framework.git
				synced 2025-11-04 01:47:59 +03:00 
			
		
		
		
	Merge pull request #2446 from tomchristie/django-18-alpha
Support 1.8-alpha.
This commit is contained in:
		
						commit
						d1fe3f6548
					
				| 
						 | 
					@ -33,10 +33,6 @@ env:
 | 
				
			||||||
matrix:
 | 
					matrix:
 | 
				
			||||||
  fast_finish: true
 | 
					  fast_finish: true
 | 
				
			||||||
  allow_failures:
 | 
					  allow_failures:
 | 
				
			||||||
    - env: TOX_ENV=py34-django18alpha
 | 
					 | 
				
			||||||
    - env: TOX_ENV=py33-django18alpha
 | 
					 | 
				
			||||||
    - env: TOX_ENV=py32-django18alpha
 | 
					 | 
				
			||||||
    - env: TOX_ENV=py27-django18alpha
 | 
					 | 
				
			||||||
    - env: TOX_ENV=py34-djangomaster
 | 
					    - env: TOX_ENV=py34-djangomaster
 | 
				
			||||||
    - env: TOX_ENV=py33-djangomaster
 | 
					    - env: TOX_ENV=py33-djangomaster
 | 
				
			||||||
    - env: TOX_ENV=py32-djangomaster
 | 
					    - env: TOX_ENV=py32-djangomaster
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										1
									
								
								env/pip-selfcheck.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								env/pip-selfcheck.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1 @@
 | 
				
			||||||
 | 
					{"last_check":"2015-01-23T11:37:11Z","pypi_version":"6.0.6"}
 | 
				
			||||||
| 
						 | 
					@ -298,7 +298,7 @@ class FileUploadParser(BaseParser):
 | 
				
			||||||
            if 'filename*' in filename_parm:
 | 
					            if 'filename*' in filename_parm:
 | 
				
			||||||
                return self.get_encoded_filename(filename_parm)
 | 
					                return self.get_encoded_filename(filename_parm)
 | 
				
			||||||
            return force_text(filename_parm['filename'])
 | 
					            return force_text(filename_parm['filename'])
 | 
				
			||||||
        except (AttributeError, KeyError):
 | 
					        except (AttributeError, KeyError, ValueError):
 | 
				
			||||||
            pass
 | 
					            pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_encoded_filename(self, filename_parm):
 | 
					    def get_encoded_filename(self, filename_parm):
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -81,10 +81,13 @@ class Response(SimpleTemplateResponse):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __getstate__(self):
 | 
					    def __getstate__(self):
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        Remove attributes from the response that shouldn't be cached
 | 
					        Remove attributes from the response that shouldn't be cached.
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        state = super(Response, self).__getstate__()
 | 
					        state = super(Response, self).__getstate__()
 | 
				
			||||||
        for key in ('accepted_renderer', 'renderer_context', 'data'):
 | 
					        for key in (
 | 
				
			||||||
 | 
					            'accepted_renderer', 'renderer_context', 'resolver_match',
 | 
				
			||||||
 | 
					            'client', 'request', 'wsgi_request', '_closable_objects'
 | 
				
			||||||
 | 
					        ):
 | 
				
			||||||
            if key in state:
 | 
					            if key in state:
 | 
				
			||||||
                del state[key]
 | 
					                del state[key]
 | 
				
			||||||
        return state
 | 
					        return state
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -121,12 +121,17 @@ def _get_reverse_relationships(opts):
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    Returns an `OrderedDict` of field names to `RelationInfo`.
 | 
					    Returns an `OrderedDict` of field names to `RelationInfo`.
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
 | 
					    # Note that we have a hack here to handle internal API differences for
 | 
				
			||||||
 | 
					    # this internal API across Django 1.7 -> Django 1.8.
 | 
				
			||||||
 | 
					    # See: https://code.djangoproject.com/ticket/24208
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    reverse_relations = OrderedDict()
 | 
					    reverse_relations = OrderedDict()
 | 
				
			||||||
    for relation in opts.get_all_related_objects():
 | 
					    for relation in opts.get_all_related_objects():
 | 
				
			||||||
        accessor_name = relation.get_accessor_name()
 | 
					        accessor_name = relation.get_accessor_name()
 | 
				
			||||||
 | 
					        related = getattr(relation, 'related_model', relation.model)
 | 
				
			||||||
        reverse_relations[accessor_name] = RelationInfo(
 | 
					        reverse_relations[accessor_name] = RelationInfo(
 | 
				
			||||||
            model_field=None,
 | 
					            model_field=None,
 | 
				
			||||||
            related=relation.model,
 | 
					            related=related,
 | 
				
			||||||
            to_many=relation.field.rel.multiple,
 | 
					            to_many=relation.field.rel.multiple,
 | 
				
			||||||
            has_through_model=False
 | 
					            has_through_model=False
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
| 
						 | 
					@ -134,9 +139,10 @@ def _get_reverse_relationships(opts):
 | 
				
			||||||
    # Deal with reverse many-to-many relationships.
 | 
					    # Deal with reverse many-to-many relationships.
 | 
				
			||||||
    for relation in opts.get_all_related_many_to_many_objects():
 | 
					    for relation in opts.get_all_related_many_to_many_objects():
 | 
				
			||||||
        accessor_name = relation.get_accessor_name()
 | 
					        accessor_name = relation.get_accessor_name()
 | 
				
			||||||
 | 
					        related = getattr(relation, 'related_model', relation.model)
 | 
				
			||||||
        reverse_relations[accessor_name] = RelationInfo(
 | 
					        reverse_relations[accessor_name] = RelationInfo(
 | 
				
			||||||
            model_field=None,
 | 
					            model_field=None,
 | 
				
			||||||
            related=relation.model,
 | 
					            related=related,
 | 
				
			||||||
            to_many=True,
 | 
					            to_many=True,
 | 
				
			||||||
            has_through_model=(
 | 
					            has_through_model=(
 | 
				
			||||||
                (getattr(relation.field.rel, 'through', None) is not None)
 | 
					                (getattr(relation.field.rel, 'through', None) is not None)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -467,6 +467,7 @@ class DjangoFilterOrderingTests(TestCase):
 | 
				
			||||||
        for d in data:
 | 
					        for d in data:
 | 
				
			||||||
            DjangoFilterOrderingModel.objects.create(**d)
 | 
					            DjangoFilterOrderingModel.objects.create(**d)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @unittest.skipUnless(django_filters, 'django-filter not installed')
 | 
				
			||||||
    def test_default_ordering(self):
 | 
					    def test_default_ordering(self):
 | 
				
			||||||
        class DjangoFilterOrderingView(generics.ListAPIView):
 | 
					        class DjangoFilterOrderingView(generics.ListAPIView):
 | 
				
			||||||
            serializer_class = DjangoFilterOrderingSerializer
 | 
					            serializer_class = DjangoFilterOrderingSerializer
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -56,7 +56,13 @@ class TemplateHTMLRendererTests(TestCase):
 | 
				
			||||||
                return Template("example: {{ object }}")
 | 
					                return Template("example: {{ object }}")
 | 
				
			||||||
            raise TemplateDoesNotExist(template_name)
 | 
					            raise TemplateDoesNotExist(template_name)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        def select_template(template_name_list, dirs=None, using=None):
 | 
				
			||||||
 | 
					            if template_name_list == ['example.html']:
 | 
				
			||||||
 | 
					                return Template("example: {{ object }}")
 | 
				
			||||||
 | 
					            raise TemplateDoesNotExist(template_name_list[0])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        django.template.loader.get_template = get_template
 | 
					        django.template.loader.get_template = get_template
 | 
				
			||||||
 | 
					        django.template.loader.select_template = select_template
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def tearDown(self):
 | 
					    def tearDown(self):
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -161,7 +161,9 @@ class TestFileUploadParser(TestCase):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.__replace_content_disposition('inline; filename=fallback.txt; filename*=utf-8--ÀĥƦ.txt')
 | 
					        self.__replace_content_disposition('inline; filename=fallback.txt; filename*=utf-8--ÀĥƦ.txt')
 | 
				
			||||||
        filename = parser.get_filename(self.stream, None, self.parser_context)
 | 
					        filename = parser.get_filename(self.stream, None, self.parser_context)
 | 
				
			||||||
        self.assertEqual(filename, 'fallback.txt')
 | 
					        # Malformed. Either None or 'fallback.txt' will be acceptable.
 | 
				
			||||||
 | 
					        # See also https://code.djangoproject.com/ticket/24209
 | 
				
			||||||
 | 
					        self.assertIn(filename, ('fallback.txt', None))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __replace_content_disposition(self, disposition):
 | 
					    def __replace_content_disposition(self, disposition):
 | 
				
			||||||
        self.parser_context['request'].META['HTTP_CONTENT_DISPOSITION'] = disposition
 | 
					        self.parser_context['request'].META['HTTP_CONTENT_DISPOSITION'] = disposition
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -22,7 +22,6 @@ from rest_framework.test import APIRequestFactory
 | 
				
			||||||
from collections import MutableMapping
 | 
					from collections import MutableMapping
 | 
				
			||||||
import datetime
 | 
					import datetime
 | 
				
			||||||
import json
 | 
					import json
 | 
				
			||||||
import pickle
 | 
					 | 
				
			||||||
import re
 | 
					import re
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -618,84 +617,24 @@ class CacheRenderTest(TestCase):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    urls = 'tests.test_renderers'
 | 
					    urls = 'tests.test_renderers'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    cache_key = 'just_a_cache_key'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @classmethod
 | 
					 | 
				
			||||||
    def _get_pickling_errors(cls, obj, seen=None):
 | 
					 | 
				
			||||||
        """ Return any errors that would be raised if `obj' is pickled
 | 
					 | 
				
			||||||
        Courtesy of koffie @ http://stackoverflow.com/a/7218986/109897
 | 
					 | 
				
			||||||
        """
 | 
					 | 
				
			||||||
        if seen is None:
 | 
					 | 
				
			||||||
            seen = []
 | 
					 | 
				
			||||||
        try:
 | 
					 | 
				
			||||||
            state = obj.__getstate__()
 | 
					 | 
				
			||||||
        except AttributeError:
 | 
					 | 
				
			||||||
            return
 | 
					 | 
				
			||||||
        if state is None:
 | 
					 | 
				
			||||||
            return
 | 
					 | 
				
			||||||
        if isinstance(state, tuple):
 | 
					 | 
				
			||||||
            if not isinstance(state[0], dict):
 | 
					 | 
				
			||||||
                state = state[1]
 | 
					 | 
				
			||||||
            else:
 | 
					 | 
				
			||||||
                state = state[0].update(state[1])
 | 
					 | 
				
			||||||
        result = {}
 | 
					 | 
				
			||||||
        for i in state:
 | 
					 | 
				
			||||||
            try:
 | 
					 | 
				
			||||||
                pickle.dumps(state[i], protocol=2)
 | 
					 | 
				
			||||||
            except pickle.PicklingError:
 | 
					 | 
				
			||||||
                if not state[i] in seen:
 | 
					 | 
				
			||||||
                    seen.append(state[i])
 | 
					 | 
				
			||||||
                    result[i] = cls._get_pickling_errors(state[i], seen)
 | 
					 | 
				
			||||||
        return result
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def http_resp(self, http_method, url):
 | 
					 | 
				
			||||||
        """
 | 
					 | 
				
			||||||
        Simple wrapper for Client http requests
 | 
					 | 
				
			||||||
        Removes the `client' and `request' attributes from as they are
 | 
					 | 
				
			||||||
        added by django.test.client.Client and not part of caching
 | 
					 | 
				
			||||||
        responses outside of tests.
 | 
					 | 
				
			||||||
        """
 | 
					 | 
				
			||||||
        method = getattr(self.client, http_method)
 | 
					 | 
				
			||||||
        resp = method(url)
 | 
					 | 
				
			||||||
        resp._closable_objects = []
 | 
					 | 
				
			||||||
        del resp.client, resp.request
 | 
					 | 
				
			||||||
        try:
 | 
					 | 
				
			||||||
            del resp.wsgi_request
 | 
					 | 
				
			||||||
        except AttributeError:
 | 
					 | 
				
			||||||
            pass
 | 
					 | 
				
			||||||
        return resp
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def test_obj_pickling(self):
 | 
					 | 
				
			||||||
        """
 | 
					 | 
				
			||||||
        Test that responses are properly pickled
 | 
					 | 
				
			||||||
        """
 | 
					 | 
				
			||||||
        resp = self.http_resp('get', '/cache')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # Make sure that no pickling errors occurred
 | 
					 | 
				
			||||||
        self.assertEqual(self._get_pickling_errors(resp), {})
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # Unfortunately LocMem backend doesn't raise PickleErrors but returns
 | 
					 | 
				
			||||||
        # None instead.
 | 
					 | 
				
			||||||
        cache.set(self.cache_key, resp)
 | 
					 | 
				
			||||||
        self.assertTrue(cache.get(self.cache_key) is not None)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def test_head_caching(self):
 | 
					    def test_head_caching(self):
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        Test caching of HEAD requests
 | 
					        Test caching of HEAD requests
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        resp = self.http_resp('head', '/cache')
 | 
					        response = self.client.head('/cache')
 | 
				
			||||||
        cache.set(self.cache_key, resp)
 | 
					        cache.set('key', response)
 | 
				
			||||||
 | 
					        cached_response = cache.get('key')
 | 
				
			||||||
        cached_resp = cache.get(self.cache_key)
 | 
					        assert isinstance(cached_response, Response)
 | 
				
			||||||
        self.assertIsInstance(cached_resp, Response)
 | 
					        assert cached_response.content == response.content
 | 
				
			||||||
 | 
					        assert cached_response.status_code == response.status_code
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_get_caching(self):
 | 
					    def test_get_caching(self):
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        Test caching of GET requests
 | 
					        Test caching of GET requests
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        resp = self.http_resp('get', '/cache')
 | 
					        response = self.client.get('/cache')
 | 
				
			||||||
        cache.set(self.cache_key, resp)
 | 
					        cache.set('key', response)
 | 
				
			||||||
 | 
					        cached_response = cache.get('key')
 | 
				
			||||||
        cached_resp = cache.get(self.cache_key)
 | 
					        assert isinstance(cached_response, Response)
 | 
				
			||||||
        self.assertIsInstance(cached_resp, Response)
 | 
					        assert cached_response.content == response.content
 | 
				
			||||||
        self.assertEqual(cached_resp.content, resp.content)
 | 
					        assert cached_response.status_code == response.status_code
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										2
									
								
								tox.ini
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								tox.ini
									
									
									
									
									
								
							| 
						 | 
					@ -22,7 +22,7 @@ deps =
 | 
				
			||||||
       {py26,py27}-django{14,15}: django-oauth2-provider==0.2.3
 | 
					       {py26,py27}-django{14,15}: django-oauth2-provider==0.2.3
 | 
				
			||||||
       {py26,py27}-django16: django-oauth2-provider==0.2.4
 | 
					       {py26,py27}-django16: django-oauth2-provider==0.2.4
 | 
				
			||||||
       pytest-django==2.8.0
 | 
					       pytest-django==2.8.0
 | 
				
			||||||
       django-filter==0.7
 | 
					       {py26,py27,py32,py33,py34}-django{14,15,16,17}: django-filter==0.7
 | 
				
			||||||
       defusedxml==0.3
 | 
					       defusedxml==0.3
 | 
				
			||||||
       markdown>=2.1.0
 | 
					       markdown>=2.1.0
 | 
				
			||||||
       PyYAML>=3.10
 | 
					       PyYAML>=3.10
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user