From cd3fd36d0e5fa7e2d4907a7f74cd45641a8ddd03 Mon Sep 17 00:00:00 2001 From: Asif Saifuddin Auvi Date: Sun, 27 Nov 2016 23:55:09 +0600 Subject: [PATCH 01/46] converted generic relations assert to pytest style --- tests/test_relations_generic.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_relations_generic.py b/tests/test_relations_generic.py index babc2269c..a3798b0a3 100644 --- a/tests/test_relations_generic.py +++ b/tests/test_relations_generic.py @@ -75,7 +75,7 @@ class TestGenericRelations(TestCase): 'tags': ['django', 'python'], 'url': 'https://www.djangoproject.com/' } - self.assertEqual(serializer.data, expected) + assert serializer.data == expected def test_generic_fk(self): """ @@ -105,4 +105,4 @@ class TestGenericRelations(TestCase): 'tagged_item': 'Note: Remember the milk' } ] - self.assertEqual(serializer.data, expected) + assert serializer.data == expected From 42d6098c74e3c8536458f4d423bedb652da16db7 Mon Sep 17 00:00:00 2001 From: Asif Saifuddin Auvi Date: Mon, 28 Nov 2016 15:43:48 +0600 Subject: [PATCH 02/46] converted primary key relations test asserts to pytest (#4709) --- tests/test_relations_pk.py | 118 ++++++++++++++++++------------------- 1 file changed, 59 insertions(+), 59 deletions(-) diff --git a/tests/test_relations_pk.py b/tests/test_relations_pk.py index 7a3d45927..ea02f2577 100644 --- a/tests/test_relations_pk.py +++ b/tests/test_relations_pk.py @@ -84,7 +84,7 @@ class PKManyToManyTests(TestCase): {'id': 3, 'name': 'source-3', 'targets': [1, 2, 3]} ] with self.assertNumQueries(4): - self.assertEqual(serializer.data, expected) + assert serializer.data == expected def test_many_to_many_retrieve_prefetch_related(self): queryset = ManyToManySource.objects.all().prefetch_related('targets') @@ -101,15 +101,15 @@ class PKManyToManyTests(TestCase): {'id': 3, 'name': 'target-3', 'sources': [3]} ] with self.assertNumQueries(4): - self.assertEqual(serializer.data, expected) + assert serializer.data == expected def test_many_to_many_update(self): data = {'id': 1, 'name': 'source-1', 'targets': [1, 2, 3]} instance = ManyToManySource.objects.get(pk=1) serializer = ManyToManySourceSerializer(instance, data=data) - self.assertTrue(serializer.is_valid()) + assert serializer.is_valid() serializer.save() - self.assertEqual(serializer.data, data) + assert serializer.data == data # Ensure source 1 is updated, and everything else is as expected queryset = ManyToManySource.objects.all() @@ -119,15 +119,15 @@ class PKManyToManyTests(TestCase): {'id': 2, 'name': 'source-2', 'targets': [1, 2]}, {'id': 3, 'name': 'source-3', 'targets': [1, 2, 3]} ] - self.assertEqual(serializer.data, expected) + assert serializer.data == expected def test_reverse_many_to_many_update(self): data = {'id': 1, 'name': 'target-1', 'sources': [1]} instance = ManyToManyTarget.objects.get(pk=1) serializer = ManyToManyTargetSerializer(instance, data=data) - self.assertTrue(serializer.is_valid()) + assert serializer.is_valid() serializer.save() - self.assertEqual(serializer.data, data) + assert serializer.data == data # Ensure target 1 is updated, and everything else is as expected queryset = ManyToManyTarget.objects.all() @@ -137,15 +137,15 @@ class PKManyToManyTests(TestCase): {'id': 2, 'name': 'target-2', 'sources': [2, 3]}, {'id': 3, 'name': 'target-3', 'sources': [3]} ] - self.assertEqual(serializer.data, expected) + assert serializer.data == expected def test_many_to_many_create(self): data = {'id': 4, 'name': 'source-4', 'targets': [1, 3]} serializer = ManyToManySourceSerializer(data=data) - self.assertTrue(serializer.is_valid()) + assert serializer.is_valid() obj = serializer.save() - self.assertEqual(serializer.data, data) - self.assertEqual(obj.name, 'source-4') + assert serializer.data == data + assert obj.name == 'source-4' # Ensure source 4 is added, and everything else is as expected queryset = ManyToManySource.objects.all() @@ -156,7 +156,7 @@ class PKManyToManyTests(TestCase): {'id': 3, 'name': 'source-3', 'targets': [1, 2, 3]}, {'id': 4, 'name': 'source-4', 'targets': [1, 3]}, ] - self.assertEqual(serializer.data, expected) + assert serializer.data == expected def test_many_to_many_unsaved(self): source = ManyToManySource(name='source-unsaved') @@ -166,15 +166,15 @@ class PKManyToManyTests(TestCase): expected = {'id': None, 'name': 'source-unsaved', 'targets': []} # no query if source hasn't been created yet with self.assertNumQueries(0): - self.assertEqual(serializer.data, expected) + assert serializer.data == expected def test_reverse_many_to_many_create(self): data = {'id': 4, 'name': 'target-4', 'sources': [1, 3]} serializer = ManyToManyTargetSerializer(data=data) - self.assertTrue(serializer.is_valid()) + assert serializer.is_valid() obj = serializer.save() - self.assertEqual(serializer.data, data) - self.assertEqual(obj.name, 'target-4') + assert serializer.data == data + assert obj.name == 'target-4' # Ensure target 4 is added, and everything else is as expected queryset = ManyToManyTarget.objects.all() @@ -185,7 +185,7 @@ class PKManyToManyTests(TestCase): {'id': 3, 'name': 'target-3', 'sources': [3]}, {'id': 4, 'name': 'target-4', 'sources': [1, 3]} ] - self.assertEqual(serializer.data, expected) + assert serializer.data == expected class PKForeignKeyTests(TestCase): @@ -207,7 +207,7 @@ class PKForeignKeyTests(TestCase): {'id': 3, 'name': 'source-3', 'target': 1} ] with self.assertNumQueries(1): - self.assertEqual(serializer.data, expected) + assert serializer.data == expected def test_reverse_foreign_key_retrieve(self): queryset = ForeignKeyTarget.objects.all() @@ -217,7 +217,7 @@ class PKForeignKeyTests(TestCase): {'id': 2, 'name': 'target-2', 'sources': []}, ] with self.assertNumQueries(3): - self.assertEqual(serializer.data, expected) + assert serializer.data == expected def test_reverse_foreign_key_retrieve_prefetch_related(self): queryset = ForeignKeyTarget.objects.all().prefetch_related('sources') @@ -229,9 +229,9 @@ class PKForeignKeyTests(TestCase): data = {'id': 1, 'name': 'source-1', 'target': 2} instance = ForeignKeySource.objects.get(pk=1) serializer = ForeignKeySourceSerializer(instance, data=data) - self.assertTrue(serializer.is_valid()) + assert serializer.is_valid() serializer.save() - self.assertEqual(serializer.data, data) + assert serializer.data == data # Ensure source 1 is updated, and everything else is as expected queryset = ForeignKeySource.objects.all() @@ -241,20 +241,20 @@ class PKForeignKeyTests(TestCase): {'id': 2, 'name': 'source-2', 'target': 1}, {'id': 3, 'name': 'source-3', 'target': 1} ] - self.assertEqual(serializer.data, expected) + assert serializer.data == expected def test_foreign_key_update_incorrect_type(self): data = {'id': 1, 'name': 'source-1', 'target': 'foo'} instance = ForeignKeySource.objects.get(pk=1) serializer = ForeignKeySourceSerializer(instance, data=data) - self.assertFalse(serializer.is_valid()) - self.assertEqual(serializer.errors, {'target': ['Incorrect type. Expected pk value, received %s.' % six.text_type.__name__]}) + assert not serializer.is_valid() + assert serializer.errors == {'target': ['Incorrect type. Expected pk value, received %s.' % six.text_type.__name__]} def test_reverse_foreign_key_update(self): data = {'id': 2, 'name': 'target-2', 'sources': [1, 3]} instance = ForeignKeyTarget.objects.get(pk=2) serializer = ForeignKeyTargetSerializer(instance, data=data) - self.assertTrue(serializer.is_valid()) + assert serializer.is_valid() # We shouldn't have saved anything to the db yet since save # hasn't been called. queryset = ForeignKeyTarget.objects.all() @@ -263,10 +263,10 @@ class PKForeignKeyTests(TestCase): {'id': 1, 'name': 'target-1', 'sources': [1, 2, 3]}, {'id': 2, 'name': 'target-2', 'sources': []}, ] - self.assertEqual(new_serializer.data, expected) + assert new_serializer.data == expected serializer.save() - self.assertEqual(serializer.data, data) + assert serializer.data == data # Ensure target 2 is update, and everything else is as expected queryset = ForeignKeyTarget.objects.all() @@ -275,15 +275,15 @@ class PKForeignKeyTests(TestCase): {'id': 1, 'name': 'target-1', 'sources': [2]}, {'id': 2, 'name': 'target-2', 'sources': [1, 3]}, ] - self.assertEqual(serializer.data, expected) + assert serializer.data == expected def test_foreign_key_create(self): data = {'id': 4, 'name': 'source-4', 'target': 2} serializer = ForeignKeySourceSerializer(data=data) - self.assertTrue(serializer.is_valid()) + assert serializer.is_valid() obj = serializer.save() - self.assertEqual(serializer.data, data) - self.assertEqual(obj.name, 'source-4') + assert serializer.data == data + assert obj.name == 'source-4' # Ensure source 4 is added, and everything else is as expected queryset = ForeignKeySource.objects.all() @@ -294,15 +294,15 @@ class PKForeignKeyTests(TestCase): {'id': 3, 'name': 'source-3', 'target': 1}, {'id': 4, 'name': 'source-4', 'target': 2}, ] - self.assertEqual(serializer.data, expected) + assert serializer.data == expected def test_reverse_foreign_key_create(self): data = {'id': 3, 'name': 'target-3', 'sources': [1, 3]} serializer = ForeignKeyTargetSerializer(data=data) - self.assertTrue(serializer.is_valid()) + assert serializer.is_valid() obj = serializer.save() - self.assertEqual(serializer.data, data) - self.assertEqual(obj.name, 'target-3') + assert serializer.data == data + assert obj.name == 'target-3' # Ensure target 3 is added, and everything else is as expected queryset = ForeignKeyTarget.objects.all() @@ -312,14 +312,14 @@ class PKForeignKeyTests(TestCase): {'id': 2, 'name': 'target-2', 'sources': []}, {'id': 3, 'name': 'target-3', 'sources': [1, 3]}, ] - self.assertEqual(serializer.data, expected) + assert serializer.data == expected def test_foreign_key_update_with_invalid_null(self): data = {'id': 1, 'name': 'source-1', 'target': None} instance = ForeignKeySource.objects.get(pk=1) serializer = ForeignKeySourceSerializer(instance, data=data) - self.assertFalse(serializer.is_valid()) - self.assertEqual(serializer.errors, {'target': ['This field may not be null.']}) + assert not serializer.is_valid() + assert serializer.errors == {'target': ['This field may not be null.']} def test_foreign_key_with_unsaved(self): source = ForeignKeySource(name='source-unsaved') @@ -329,7 +329,7 @@ class PKForeignKeyTests(TestCase): # no query if source hasn't been created yet with self.assertNumQueries(0): - self.assertEqual(serializer.data, expected) + assert serializer.data == expected def test_foreign_key_with_empty(self): """ @@ -338,7 +338,7 @@ class PKForeignKeyTests(TestCase): https://github.com/tomchristie/django-rest-framework/issues/1072 """ serializer = NullableForeignKeySourceSerializer() - self.assertEqual(serializer.data['target'], None) + assert serializer.data['target'] is None def test_foreign_key_not_required(self): """ @@ -350,7 +350,7 @@ class PKForeignKeyTests(TestCase): extra_kwargs = {'target': {'required': False}} serializer = ModelSerializer(data={'name': 'test'}) serializer.is_valid(raise_exception=True) - self.assertNotIn('target', serializer.validated_data) + assert 'target' not in serializer.validated_data class PKNullableForeignKeyTests(TestCase): @@ -371,15 +371,15 @@ class PKNullableForeignKeyTests(TestCase): {'id': 2, 'name': 'source-2', 'target': 1}, {'id': 3, 'name': 'source-3', 'target': None}, ] - self.assertEqual(serializer.data, expected) + assert serializer.data == expected def test_foreign_key_create_with_valid_null(self): data = {'id': 4, 'name': 'source-4', 'target': None} serializer = NullableForeignKeySourceSerializer(data=data) - self.assertTrue(serializer.is_valid()) + assert serializer.is_valid() obj = serializer.save() - self.assertEqual(serializer.data, data) - self.assertEqual(obj.name, 'source-4') + assert serializer.data == data + assert obj.name == 'source-4' # Ensure source 4 is created, and everything else is as expected queryset = NullableForeignKeySource.objects.all() @@ -390,7 +390,7 @@ class PKNullableForeignKeyTests(TestCase): {'id': 3, 'name': 'source-3', 'target': None}, {'id': 4, 'name': 'source-4', 'target': None} ] - self.assertEqual(serializer.data, expected) + assert serializer.data == expected def test_foreign_key_create_with_valid_emptystring(self): """ @@ -400,10 +400,10 @@ class PKNullableForeignKeyTests(TestCase): data = {'id': 4, 'name': 'source-4', 'target': ''} expected_data = {'id': 4, 'name': 'source-4', 'target': None} serializer = NullableForeignKeySourceSerializer(data=data) - self.assertTrue(serializer.is_valid()) + assert serializer.is_valid() obj = serializer.save() - self.assertEqual(serializer.data, expected_data) - self.assertEqual(obj.name, 'source-4') + assert serializer.data == expected_data + assert obj.name == 'source-4' # Ensure source 4 is created, and everything else is as expected queryset = NullableForeignKeySource.objects.all() @@ -414,15 +414,15 @@ class PKNullableForeignKeyTests(TestCase): {'id': 3, 'name': 'source-3', 'target': None}, {'id': 4, 'name': 'source-4', 'target': None} ] - self.assertEqual(serializer.data, expected) + assert serializer.data == expected def test_foreign_key_update_with_valid_null(self): data = {'id': 1, 'name': 'source-1', 'target': None} instance = NullableForeignKeySource.objects.get(pk=1) serializer = NullableForeignKeySourceSerializer(instance, data=data) - self.assertTrue(serializer.is_valid()) + assert serializer.is_valid() serializer.save() - self.assertEqual(serializer.data, data) + assert serializer.data == data # Ensure source 1 is updated, and everything else is as expected queryset = NullableForeignKeySource.objects.all() @@ -432,7 +432,7 @@ class PKNullableForeignKeyTests(TestCase): {'id': 2, 'name': 'source-2', 'target': 1}, {'id': 3, 'name': 'source-3', 'target': None} ] - self.assertEqual(serializer.data, expected) + assert serializer.data == expected def test_foreign_key_update_with_valid_emptystring(self): """ @@ -443,9 +443,9 @@ class PKNullableForeignKeyTests(TestCase): expected_data = {'id': 1, 'name': 'source-1', 'target': None} instance = NullableForeignKeySource.objects.get(pk=1) serializer = NullableForeignKeySourceSerializer(instance, data=data) - self.assertTrue(serializer.is_valid()) + assert serializer.is_valid() serializer.save() - self.assertEqual(serializer.data, expected_data) + assert serializer.data == expected_data # Ensure source 1 is updated, and everything else is as expected queryset = NullableForeignKeySource.objects.all() @@ -455,18 +455,18 @@ class PKNullableForeignKeyTests(TestCase): {'id': 2, 'name': 'source-2', 'target': 1}, {'id': 3, 'name': 'source-3', 'target': None} ] - self.assertEqual(serializer.data, expected) + assert serializer.data == expected def test_null_uuid_foreign_key_serializes_as_none(self): source = NullableUUIDForeignKeySource(name='Source') serializer = NullableUUIDForeignKeySourceSerializer(source) data = serializer.data - self.assertEqual(data["target"], None) + assert data["target"] is None def test_nullable_uuid_foreign_key_is_valid_when_none(self): data = {"name": "Source", "target": None} serializer = NullableUUIDForeignKeySourceSerializer(data=data) - self.assertTrue(serializer.is_valid(), serializer.errors) + assert serializer.is_valid(), serializer.errors class PKNullableOneToOneTests(TestCase): @@ -485,4 +485,4 @@ class PKNullableOneToOneTests(TestCase): {'id': 1, 'name': 'target-1', 'nullable_source': None}, {'id': 2, 'name': 'target-2', 'nullable_source': 1}, ] - self.assertEqual(serializer.data, expected) + assert serializer.data == expected From 9f4c9691f47c534338cdaa4d8a22efc201c8fb62 Mon Sep 17 00:00:00 2001 From: Asif Saifuddin Auvi Date: Mon, 28 Nov 2016 20:31:27 +0600 Subject: [PATCH 03/46] converted filters tests asserts to pytest style (#4711) --- tests/test_filters.py | 300 +++++++++++++++++------------------------- 1 file changed, 124 insertions(+), 176 deletions(-) diff --git a/tests/test_filters.py b/tests/test_filters.py index 12fb85895..0cc326239 100644 --- a/tests/test_filters.py +++ b/tests/test_filters.py @@ -155,8 +155,8 @@ class IntegrationTestFiltering(CommonFilteringTestCase): request = factory.get('/') response = view(request).render() - self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(response.data, self.data) + assert response.status_code == status.HTTP_200_OK + assert response.data == self.data self.assertTrue(issubclass(w[-1].category, PendingDeprecationWarning)) self.assertIn("'rest_framework.filters.DjangoFilterBackend' is pending deprecation.", str(w[-1].message)) @@ -175,9 +175,9 @@ class IntegrationTestFiltering(CommonFilteringTestCase): request = factory.get('/') response = view(request).render() - self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(response.data, self.data) - self.assertEqual(len(w), 0) + assert response.status_code == status.HTTP_200_OK + assert response.data == self.data + assert len(w) == 0 @unittest.skipUnless(django_filters, 'django-filter not installed') def test_get_filtered_fields_root_view(self): @@ -189,24 +189,24 @@ class IntegrationTestFiltering(CommonFilteringTestCase): # Basic test with no filter. request = factory.get('/') response = view(request).render() - self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(response.data, self.data) + assert response.status_code == status.HTTP_200_OK + assert response.data == self.data # Tests that the decimal filter works. search_decimal = Decimal('2.25') request = factory.get('/', {'decimal': '%s' % search_decimal}) response = view(request).render() - self.assertEqual(response.status_code, status.HTTP_200_OK) + assert response.status_code == status.HTTP_200_OK expected_data = [f for f in self.data if Decimal(f['decimal']) == search_decimal] - self.assertEqual(response.data, expected_data) + assert response.data == expected_data # Tests that the date filter works. search_date = datetime.date(2012, 9, 22) request = factory.get('/', {'date': '%s' % search_date}) # search_date str: '2012-09-22' response = view(request).render() - self.assertEqual(response.status_code, status.HTTP_200_OK) + assert response.status_code == status.HTTP_200_OK expected_data = [f for f in self.data if parse_date(f['date']) == search_date] - self.assertEqual(response.data, expected_data) + assert response.data == expected_data @unittest.skipUnless(django_filters, 'django-filter not installed') def test_filter_with_queryset(self): @@ -219,9 +219,9 @@ class IntegrationTestFiltering(CommonFilteringTestCase): search_decimal = Decimal('2.25') request = factory.get('/', {'decimal': '%s' % search_decimal}) response = view(request).render() - self.assertEqual(response.status_code, status.HTTP_200_OK) + assert response.status_code == status.HTTP_200_OK expected_data = [f for f in self.data if Decimal(f['decimal']) == search_decimal] - self.assertEqual(response.data, expected_data) + assert response.data == expected_data @unittest.skipUnless(django_filters, 'django-filter not installed') def test_filter_with_get_queryset_only(self): @@ -245,32 +245,32 @@ class IntegrationTestFiltering(CommonFilteringTestCase): # Basic test with no filter. request = factory.get('/') response = view(request).render() - self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(response.data, self.data) + assert response.status_code == status.HTTP_200_OK + assert response.data == self.data # Tests that the decimal filter set with 'lt' in the filter class works. search_decimal = Decimal('4.25') request = factory.get('/', {'decimal': '%s' % search_decimal}) response = view(request).render() - self.assertEqual(response.status_code, status.HTTP_200_OK) + assert response.status_code == status.HTTP_200_OK expected_data = [f for f in self.data if Decimal(f['decimal']) < search_decimal] - self.assertEqual(response.data, expected_data) + assert response.data == expected_data # Tests that the date filter set with 'gt' in the filter class works. search_date = datetime.date(2012, 10, 2) request = factory.get('/', {'date': '%s' % search_date}) # search_date str: '2012-10-02' response = view(request).render() - self.assertEqual(response.status_code, status.HTTP_200_OK) + assert response.status_code == status.HTTP_200_OK expected_data = [f for f in self.data if parse_date(f['date']) > search_date] - self.assertEqual(response.data, expected_data) + assert response.data == expected_data # Tests that the text filter set with 'icontains' in the filter class works. search_text = 'ff' request = factory.get('/', {'text': '%s' % search_text}) response = view(request).render() - self.assertEqual(response.status_code, status.HTTP_200_OK) + assert response.status_code == status.HTTP_200_OK expected_data = [f for f in self.data if search_text in f['text'].lower()] - self.assertEqual(response.data, expected_data) + assert response.data == expected_data # Tests that multiple filters works. search_decimal = Decimal('5.25') @@ -280,10 +280,10 @@ class IntegrationTestFiltering(CommonFilteringTestCase): 'date': '%s' % (search_date,) }) response = view(request).render() - self.assertEqual(response.status_code, status.HTTP_200_OK) + assert response.status_code == status.HTTP_200_OK expected_data = [f for f in self.data if parse_date(f['date']) > search_date and Decimal(f['decimal']) < search_decimal] - self.assertEqual(response.data, expected_data) + assert response.data == expected_data @unittest.skipUnless(django_filters, 'django-filter not installed') def test_incorrectly_configured_filter(self): @@ -304,8 +304,8 @@ class IntegrationTestFiltering(CommonFilteringTestCase): request = factory.get('/?text=aaa') response = view(request).render() - self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(len(response.data), 1) + assert response.status_code == status.HTTP_200_OK + assert len(response.data) == 1 @unittest.skipUnless(django_filters, 'django-filter not installed') def test_base_model_filter_with_proxy(self): @@ -316,8 +316,8 @@ class IntegrationTestFiltering(CommonFilteringTestCase): request = factory.get('/?text=aaa') response = view(request).render() - self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(len(response.data), 1) + assert response.status_code == status.HTTP_200_OK + assert len(response.data) == 1 @unittest.skipUnless(django_filters, 'django-filter not installed') def test_unknown_filter(self): @@ -329,7 +329,7 @@ class IntegrationTestFiltering(CommonFilteringTestCase): search_integer = 10 request = factory.get('/', {'integer': '%s' % search_integer}) response = view(request).render() - self.assertEqual(response.status_code, status.HTTP_200_OK) + assert response.status_code == status.HTTP_200_OK @override_settings(ROOT_URLCONF='tests.test_filters') @@ -351,8 +351,8 @@ class IntegrationTestDetailFiltering(CommonFilteringTestCase): # Basic test with no filter. response = self.client.get(self._get_url(item)) - self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(response.data, data) + assert response.status_code == status.HTTP_200_OK + assert response.data == data # Tests that the decimal filter set that should fail. search_decimal = Decimal('4.25') @@ -360,7 +360,7 @@ class IntegrationTestDetailFiltering(CommonFilteringTestCase): response = self.client.get( '{url}'.format(url=self._get_url(high_item)), {'decimal': '{param}'.format(param=search_decimal)}) - self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) + assert response.status_code == status.HTTP_404_NOT_FOUND # Tests that the decimal filter set that should succeed. search_decimal = Decimal('4.25') @@ -369,8 +369,8 @@ class IntegrationTestDetailFiltering(CommonFilteringTestCase): response = self.client.get( '{url}'.format(url=self._get_url(low_item)), {'decimal': '{param}'.format(param=search_decimal)}) - self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(response.data, low_item_data) + assert response.status_code == status.HTTP_200_OK + assert response.data == low_item_data # Tests that multiple filters works. search_decimal = Decimal('5.25') @@ -382,8 +382,8 @@ class IntegrationTestDetailFiltering(CommonFilteringTestCase): 'decimal': '{decimal}'.format(decimal=search_decimal), 'date': '{date}'.format(date=search_date) }) - self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(response.data, valid_item_data) + assert response.status_code == status.HTTP_200_OK + assert response.data == valid_item_data class SearchFilterModel(models.Model): @@ -424,13 +424,10 @@ class SearchFilterTests(TestCase): view = SearchListView.as_view() request = factory.get('/', {'search': 'b'}) response = view(request) - self.assertEqual( - response.data, - [ - {'id': 1, 'title': 'z', 'text': 'abc'}, - {'id': 2, 'title': 'zz', 'text': 'bcd'} - ] - ) + assert response.data == [ + {'id': 1, 'title': 'z', 'text': 'abc'}, + {'id': 2, 'title': 'zz', 'text': 'bcd'} + ] def test_exact_search(self): class SearchListView(generics.ListAPIView): @@ -442,12 +439,9 @@ class SearchFilterTests(TestCase): view = SearchListView.as_view() request = factory.get('/', {'search': 'zzz'}) response = view(request) - self.assertEqual( - response.data, - [ - {'id': 3, 'title': 'zzz', 'text': 'cde'} - ] - ) + assert response.data == [ + {'id': 3, 'title': 'zzz', 'text': 'cde'} + ] def test_startswith_search(self): class SearchListView(generics.ListAPIView): @@ -459,12 +453,9 @@ class SearchFilterTests(TestCase): view = SearchListView.as_view() request = factory.get('/', {'search': 'b'}) response = view(request) - self.assertEqual( - response.data, - [ - {'id': 2, 'title': 'zz', 'text': 'bcd'} - ] - ) + assert response.data == [ + {'id': 2, 'title': 'zz', 'text': 'bcd'} + ] def test_regexp_search(self): class SearchListView(generics.ListAPIView): @@ -476,12 +467,9 @@ class SearchFilterTests(TestCase): view = SearchListView.as_view() request = factory.get('/', {'search': 'z{2} ^b'}) response = view(request) - self.assertEqual( - response.data, - [ - {'id': 2, 'title': 'zz', 'text': 'bcd'} - ] - ) + assert response.data == [ + {'id': 2, 'title': 'zz', 'text': 'bcd'} + ] def test_search_with_nonstandard_search_param(self): with override_settings(REST_FRAMEWORK={'SEARCH_PARAM': 'query'}): @@ -496,13 +484,10 @@ class SearchFilterTests(TestCase): view = SearchListView.as_view() request = factory.get('/', {'query': 'b'}) response = view(request) - self.assertEqual( - response.data, - [ - {'id': 1, 'title': 'z', 'text': 'abc'}, - {'id': 2, 'title': 'zz', 'text': 'bcd'} - ] - ) + assert response.data == [ + {'id': 1, 'title': 'z', 'text': 'abc'}, + {'id': 2, 'title': 'zz', 'text': 'bcd'} + ] reload_module(filters) @@ -528,15 +513,13 @@ class SearchFilterFkTests(TestCase): filter_ = filters.SearchFilter() prefixes = [''] + list(filter_.lookup_prefixes) for prefix in prefixes: - self.assertFalse( - filter_.must_call_distinct( - SearchFilterModelFk._meta, ["%stitle" % prefix] - ) + assert not filter_.must_call_distinct( + SearchFilterModelFk._meta, + ["%stitle" % prefix] ) - self.assertFalse( - filter_.must_call_distinct( - SearchFilterModelFk._meta, ["%stitle" % prefix, "%sattribute__label" % prefix] - ) + assert not filter_.must_call_distinct( + SearchFilterModelFk._meta, + ["%stitle" % prefix, "%sattribute__label" % prefix] ) def test_must_call_distinct_restores_meta_for_each_field(self): @@ -545,10 +528,9 @@ class SearchFilterFkTests(TestCase): filter_ = filters.SearchFilter() prefixes = [''] + list(filter_.lookup_prefixes) for prefix in prefixes: - self.assertFalse( - filter_.must_call_distinct( - SearchFilterModelFk._meta, ["%sattribute__label" % prefix, "%stitle" % prefix] - ) + assert not filter_.must_call_distinct( + SearchFilterModelFk._meta, + ["%sattribute__label" % prefix, "%stitle" % prefix] ) @@ -596,21 +578,20 @@ class SearchFilterM2MTests(TestCase): view = SearchListView.as_view() request = factory.get('/', {'search': 'zz'}) response = view(request) - self.assertEqual(len(response.data), 1) + assert len(response.data) == 1 def test_must_call_distinct(self): filter_ = filters.SearchFilter() prefixes = [''] + list(filter_.lookup_prefixes) for prefix in prefixes: - self.assertFalse( - filter_.must_call_distinct( - SearchFilterModelM2M._meta, ["%stitle" % prefix] - ) + assert not filter_.must_call_distinct( + SearchFilterModelM2M._meta, + ["%stitle" % prefix] ) - self.assertTrue( - filter_.must_call_distinct( - SearchFilterModelM2M._meta, ["%stitle" % prefix, "%sattributes__label" % prefix] - ) + + assert filter_.must_call_distinct( + SearchFilterModelM2M._meta, + ["%stitle" % prefix, "%sattributes__label" % prefix] ) @@ -672,14 +653,11 @@ class DjangoFilterOrderingTests(TestCase): request = factory.get('/') response = view(request) - self.assertEqual( - response.data, - [ - {'id': 3, 'date': '2014-10-08', 'text': 'cde'}, - {'id': 2, 'date': '2013-10-08', 'text': 'bcd'}, - {'id': 1, 'date': '2012-10-08', 'text': 'abc'} - ] - ) + assert response.data == [ + {'id': 3, 'date': '2014-10-08', 'text': 'cde'}, + {'id': 2, 'date': '2013-10-08', 'text': 'bcd'}, + {'id': 1, 'date': '2012-10-08', 'text': 'abc'} + ] class OrderingFilterTests(TestCase): @@ -713,14 +691,11 @@ class OrderingFilterTests(TestCase): view = OrderingListView.as_view() request = factory.get('/', {'ordering': 'text'}) response = view(request) - self.assertEqual( - response.data, - [ - {'id': 1, 'title': 'zyx', 'text': 'abc'}, - {'id': 2, 'title': 'yxw', 'text': 'bcd'}, - {'id': 3, 'title': 'xwv', 'text': 'cde'}, - ] - ) + assert response.data == [ + {'id': 1, 'title': 'zyx', 'text': 'abc'}, + {'id': 2, 'title': 'yxw', 'text': 'bcd'}, + {'id': 3, 'title': 'xwv', 'text': 'cde'}, + ] def test_reverse_ordering(self): class OrderingListView(generics.ListAPIView): @@ -733,14 +708,11 @@ class OrderingFilterTests(TestCase): view = OrderingListView.as_view() request = factory.get('/', {'ordering': '-text'}) response = view(request) - self.assertEqual( - response.data, - [ - {'id': 3, 'title': 'xwv', 'text': 'cde'}, - {'id': 2, 'title': 'yxw', 'text': 'bcd'}, - {'id': 1, 'title': 'zyx', 'text': 'abc'}, - ] - ) + assert response.data == [ + {'id': 3, 'title': 'xwv', 'text': 'cde'}, + {'id': 2, 'title': 'yxw', 'text': 'bcd'}, + {'id': 1, 'title': 'zyx', 'text': 'abc'}, + ] def test_incorrectfield_ordering(self): class OrderingListView(generics.ListAPIView): @@ -753,14 +725,11 @@ class OrderingFilterTests(TestCase): view = OrderingListView.as_view() request = factory.get('/', {'ordering': 'foobar'}) response = view(request) - self.assertEqual( - response.data, - [ - {'id': 3, 'title': 'xwv', 'text': 'cde'}, - {'id': 2, 'title': 'yxw', 'text': 'bcd'}, - {'id': 1, 'title': 'zyx', 'text': 'abc'}, - ] - ) + assert response.data == [ + {'id': 3, 'title': 'xwv', 'text': 'cde'}, + {'id': 2, 'title': 'yxw', 'text': 'bcd'}, + {'id': 1, 'title': 'zyx', 'text': 'abc'}, + ] def test_default_ordering(self): class OrderingListView(generics.ListAPIView): @@ -773,14 +742,11 @@ class OrderingFilterTests(TestCase): view = OrderingListView.as_view() request = factory.get('') response = view(request) - self.assertEqual( - response.data, - [ - {'id': 3, 'title': 'xwv', 'text': 'cde'}, - {'id': 2, 'title': 'yxw', 'text': 'bcd'}, - {'id': 1, 'title': 'zyx', 'text': 'abc'}, - ] - ) + assert response.data == [ + {'id': 3, 'title': 'xwv', 'text': 'cde'}, + {'id': 2, 'title': 'yxw', 'text': 'bcd'}, + {'id': 1, 'title': 'zyx', 'text': 'abc'}, + ] def test_default_ordering_using_string(self): class OrderingListView(generics.ListAPIView): @@ -793,14 +759,11 @@ class OrderingFilterTests(TestCase): view = OrderingListView.as_view() request = factory.get('') response = view(request) - self.assertEqual( - response.data, - [ - {'id': 3, 'title': 'xwv', 'text': 'cde'}, - {'id': 2, 'title': 'yxw', 'text': 'bcd'}, - {'id': 1, 'title': 'zyx', 'text': 'abc'}, - ] - ) + assert response.data == [ + {'id': 3, 'title': 'xwv', 'text': 'cde'}, + {'id': 2, 'title': 'yxw', 'text': 'bcd'}, + {'id': 1, 'title': 'zyx', 'text': 'abc'}, + ] def test_ordering_by_aggregate_field(self): # create some related models to aggregate order by @@ -824,14 +787,11 @@ class OrderingFilterTests(TestCase): view = OrderingListView.as_view() request = factory.get('/', {'ordering': 'relateds__count'}) response = view(request) - self.assertEqual( - response.data, - [ - {'id': 1, 'title': 'zyx', 'text': 'abc'}, - {'id': 3, 'title': 'xwv', 'text': 'cde'}, - {'id': 2, 'title': 'yxw', 'text': 'bcd'}, - ] - ) + assert response.data == [ + {'id': 1, 'title': 'zyx', 'text': 'abc'}, + {'id': 3, 'title': 'xwv', 'text': 'cde'}, + {'id': 2, 'title': 'yxw', 'text': 'bcd'}, + ] def test_ordering_with_nonstandard_ordering_param(self): with override_settings(REST_FRAMEWORK={'ORDERING_PARAM': 'order'}): @@ -847,14 +807,11 @@ class OrderingFilterTests(TestCase): view = OrderingListView.as_view() request = factory.get('/', {'order': 'text'}) response = view(request) - self.assertEqual( - response.data, - [ - {'id': 1, 'title': 'zyx', 'text': 'abc'}, - {'id': 2, 'title': 'yxw', 'text': 'bcd'}, - {'id': 3, 'title': 'xwv', 'text': 'cde'}, - ] - ) + assert response.data == [ + {'id': 1, 'title': 'zyx', 'text': 'abc'}, + {'id': 2, 'title': 'yxw', 'text': 'bcd'}, + {'id': 3, 'title': 'xwv', 'text': 'cde'}, + ] reload_module(filters) @@ -884,14 +841,11 @@ class OrderingFilterTests(TestCase): view = OrderingListView.as_view() request = factory.get('/', {'ordering': 'text'}) response = view(request) - self.assertEqual( - response.data, - [ - {'id': 1, 'title': 'zyx', 'text': 'abc'}, - {'id': 2, 'title': 'yxw', 'text': 'bcd'}, - {'id': 3, 'title': 'xwv', 'text': 'cde'}, - ] - ) + assert response.data == [ + {'id': 1, 'title': 'zyx', 'text': 'abc'}, + {'id': 2, 'title': 'yxw', 'text': 'bcd'}, + {'id': 3, 'title': 'xwv', 'text': 'cde'}, + ] def test_ordering_with_improper_configuration(self): class OrderingListView(generics.ListAPIView): @@ -967,14 +921,11 @@ class SensitiveOrderingFilterTests(TestCase): username_field = 'username' # Note: Inverse username ordering correctly applied. - self.assertEqual( - response.data, - [ - {'id': 3, username_field: 'userC'}, - {'id': 2, username_field: 'userB'}, - {'id': 1, username_field: 'userA'}, - ] - ) + assert response.data == [ + {'id': 3, username_field: 'userC'}, + {'id': 2, username_field: 'userB'}, + {'id': 1, username_field: 'userA'}, + ] def test_cannot_order_by_non_serializer_fields(self): for serializer_cls in [ @@ -997,11 +948,8 @@ class SensitiveOrderingFilterTests(TestCase): username_field = 'username' # Note: The passwords are not in order. Default ordering is used. - self.assertEqual( - response.data, - [ - {'id': 1, username_field: 'userA'}, # PassB - {'id': 2, username_field: 'userB'}, # PassC - {'id': 3, username_field: 'userC'}, # PassA - ] - ) + assert response.data == [ + {'id': 1, username_field: 'userA'}, # PassB + {'id': 2, username_field: 'userB'}, # PassC + {'id': 3, username_field: 'userC'}, # PassA + ] From 649876674933c7c05225e8f33a278ce4210df598 Mon Sep 17 00:00:00 2001 From: Ryan P Kilby Date: Tue, 29 Nov 2016 04:49:18 -0500 Subject: [PATCH 04/46] Fix django deprecation warnings (#4712) --- tests/test_model_serializer.py | 4 ++-- tests/test_prefetch_related.py | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/test_model_serializer.py b/tests/test_model_serializer.py index 06848302f..b839f56ca 100644 --- a/tests/test_model_serializer.py +++ b/tests/test_model_serializer.py @@ -94,7 +94,7 @@ class Issue3674ParentModel(models.Model): class Issue3674ChildModel(models.Model): - parent = models.ForeignKey(Issue3674ParentModel, related_name='children') + parent = models.ForeignKey(Issue3674ParentModel, related_name='children', on_delete=models.CASCADE) value = models.CharField(primary_key=True, max_length=64) @@ -1013,7 +1013,7 @@ class Issue3674Test(TestCase): title = models.CharField(max_length=64) class TestChildModel(models.Model): - parent = models.ForeignKey(TestParentModel, related_name='children') + parent = models.ForeignKey(TestParentModel, related_name='children', on_delete=models.CASCADE) value = models.CharField(primary_key=True, max_length=64) class TestChildModelSerializer(serializers.ModelSerializer): diff --git a/tests/test_prefetch_related.py b/tests/test_prefetch_related.py index a9fa238ea..750173b38 100644 --- a/tests/test_prefetch_related.py +++ b/tests/test_prefetch_related.py @@ -2,6 +2,7 @@ from django.contrib.auth.models import Group, User from django.test import TestCase from rest_framework import generics, serializers +from rest_framework.compat import set_many from rest_framework.test import APIRequestFactory factory = APIRequestFactory() @@ -22,7 +23,7 @@ class TestPrefetchRelatedUpdates(TestCase): def setUp(self): self.user = User.objects.create(username='tom', email='tom@example.com') self.groups = [Group.objects.create(name='a'), Group.objects.create(name='b')] - self.user.groups = self.groups + set_many(self.user, 'groups', self.groups) self.user.save() def test_prefetch_related_updates(self): From 1e0988686cda1f9c150e239b945c1d9a0ea9b19c Mon Sep 17 00:00:00 2001 From: Xavier Ordoquy Date: Tue, 29 Nov 2016 13:27:00 +0100 Subject: [PATCH 05/46] Update the Python doc links to use https and point to Python 3 (#4713) --- docs/api-guide/fields.md | 2 +- docs/api-guide/settings.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/api-guide/fields.md b/docs/api-guide/fields.md index 17168b721..3dcc9d0a5 100644 --- a/docs/api-guide/fields.md +++ b/docs/api-guide/fields.md @@ -669,7 +669,7 @@ The [django-rest-framework-hstore][django-rest-framework-hstore] package provide [html-and-forms]: ../topics/html-and-forms.md [FILE_UPLOAD_HANDLERS]: https://docs.djangoproject.com/en/dev/ref/settings/#std:setting-FILE_UPLOAD_HANDLERS [ecma262]: http://ecma-international.org/ecma-262/5.1/#sec-15.9.1.15 -[strftime]: http://docs.python.org/2/library/datetime.html#strftime-and-strptime-behavior +[strftime]: https://docs.python.org/3/library/datetime.html#strftime-and-strptime-behavior [django-widgets]: https://docs.djangoproject.com/en/dev/ref/forms/widgets/ [iso8601]: http://www.w3.org/TR/NOTE-datetime [drf-compound-fields]: https://drf-compound-fields.readthedocs.io diff --git a/docs/api-guide/settings.md b/docs/api-guide/settings.md index 58ceeeeb4..a1ea12d6e 100644 --- a/docs/api-guide/settings.md +++ b/docs/api-guide/settings.md @@ -456,7 +456,7 @@ An integer of 0 or more, that may be used to specify the number of application p Default: `None` -[cite]: http://www.python.org/dev/peps/pep-0020/ +[cite]: https://www.python.org/dev/peps/pep-0020/ [rfc4627]: http://www.ietf.org/rfc/rfc4627.txt [heroku-minified-json]: https://github.com/interagent/http-api-design#keep-json-minified-in-all-responses -[strftime]: http://docs.python.org/2/library/time.html#time.strftime +[strftime]: https://docs.python.org/3/library/time.html#time.strftime From aed8387e05a7a665439044d90b7fac5d1fd61225 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Larra=C3=ADn?= Date: Tue, 29 Nov 2016 12:35:43 -0300 Subject: [PATCH 06/46] docs: Fix description of `DecimalField`'s `max_digits` (#4714) As of PR #4377, `max_digits=None` is allowed for `DecimalField`. --- docs/api-guide/fields.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api-guide/fields.md b/docs/api-guide/fields.md index 3dcc9d0a5..6b6ae612d 100644 --- a/docs/api-guide/fields.md +++ b/docs/api-guide/fields.md @@ -261,7 +261,7 @@ Corresponds to `django.db.models.fields.DecimalField`. **Signature**: `DecimalField(max_digits, decimal_places, coerce_to_string=None, max_value=None, min_value=None)` -- `max_digits` The maximum number of digits allowed in the number. Note that this number must be greater than or equal to decimal_places. +- `max_digits` The maximum number of digits allowed in the number. It must be either `None` or an integer greater than or equal to `decimal_places`. - `decimal_places` The number of decimal places to store with the number. - `coerce_to_string` Set to `True` if string values should be returned for the representation, or `False` if `Decimal` objects should be returned. Defaults to the same value as the `COERCE_DECIMAL_TO_STRING` settings key, which will be `True` unless overridden. If `Decimal` objects are returned by the serializer, then the final output format will be determined by the renderer. Note that setting `localize` will force the value to `True`. - `max_value` Validate that the number provided is no greater than this value. From 27641e07b5b56ea6fcd4676419e8fd99c58e9c66 Mon Sep 17 00:00:00 2001 From: Asif Saifuddin Auvi Date: Wed, 30 Nov 2016 01:13:21 +0600 Subject: [PATCH 07/46] converted test asserts of generics-test to pytest --- tests/test_generics.py | 102 ++++++++++++++++++++--------------------- 1 file changed, 51 insertions(+), 51 deletions(-) diff --git a/tests/test_generics.py b/tests/test_generics.py index 247237584..2c3679c46 100644 --- a/tests/test_generics.py +++ b/tests/test_generics.py @@ -98,8 +98,8 @@ class TestRootView(TestCase): request = factory.get('/') with self.assertNumQueries(1): response = self.view(request).render() - self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(response.data, self.data) + assert response.status_code == status.HTTP_200_OK + assert response.data == self.data def test_post_root_view(self): """ @@ -109,10 +109,10 @@ class TestRootView(TestCase): request = factory.post('/', data, format='json') with self.assertNumQueries(1): response = self.view(request).render() - self.assertEqual(response.status_code, status.HTTP_201_CREATED) - self.assertEqual(response.data, {'id': 4, 'text': 'foobar'}) + assert response.status_code == status.HTTP_201_CREATED + assert response.data == {'id': 4, 'text': 'foobar'} created = self.objects.get(id=4) - self.assertEqual(created.text, 'foobar') + assert created.text == 'foobar' def test_put_root_view(self): """ @@ -122,8 +122,8 @@ class TestRootView(TestCase): request = factory.put('/', data, format='json') with self.assertNumQueries(0): response = self.view(request).render() - self.assertEqual(response.status_code, status.HTTP_405_METHOD_NOT_ALLOWED) - self.assertEqual(response.data, {"detail": 'Method "PUT" not allowed.'}) + assert response.status_code == status.HTTP_405_METHOD_NOT_ALLOWED + assert response.data == {"detail": 'Method "PUT" not allowed.'} def test_delete_root_view(self): """ @@ -132,8 +132,8 @@ class TestRootView(TestCase): request = factory.delete('/') with self.assertNumQueries(0): response = self.view(request).render() - self.assertEqual(response.status_code, status.HTTP_405_METHOD_NOT_ALLOWED) - self.assertEqual(response.data, {"detail": 'Method "DELETE" not allowed.'}) + assert response.status_code == status.HTTP_405_METHOD_NOT_ALLOWED + assert response.data == {"detail": 'Method "DELETE" not allowed.'} def test_post_cannot_set_id(self): """ @@ -143,10 +143,10 @@ class TestRootView(TestCase): request = factory.post('/', data, format='json') with self.assertNumQueries(1): response = self.view(request).render() - self.assertEqual(response.status_code, status.HTTP_201_CREATED) - self.assertEqual(response.data, {'id': 4, 'text': 'foobar'}) + assert response.status_code == status.HTTP_201_CREATED + assert response.data == {'id': 4, 'text': 'foobar'} created = self.objects.get(id=4) - self.assertEqual(created.text, 'foobar') + assert created.text == 'foobar' def test_post_error_root_view(self): """ @@ -156,7 +156,7 @@ class TestRootView(TestCase): request = factory.post('/', data, HTTP_ACCEPT='text/html') response = self.view(request).render() expected_error = 'Ensure this field has no more than 100 characters.' - self.assertIn(expected_error, response.rendered_content.decode('utf-8')) + assert expected_error in response.rendered_content.decode('utf-8') EXPECTED_QUERIES_FOR_PUT = 2 @@ -185,8 +185,8 @@ class TestInstanceView(TestCase): request = factory.get('/1') with self.assertNumQueries(1): response = self.view(request, pk=1).render() - self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(response.data, self.data[0]) + assert response.status_code == status.HTTP_200_OK + assert response.data == self.data[0] def test_post_instance_view(self): """ @@ -196,8 +196,8 @@ class TestInstanceView(TestCase): request = factory.post('/', data, format='json') with self.assertNumQueries(0): response = self.view(request).render() - self.assertEqual(response.status_code, status.HTTP_405_METHOD_NOT_ALLOWED) - self.assertEqual(response.data, {"detail": 'Method "POST" not allowed.'}) + assert response.status_code == status.HTTP_405_METHOD_NOT_ALLOWED + assert response.data == {"detail": 'Method "POST" not allowed.'} def test_put_instance_view(self): """ @@ -207,10 +207,10 @@ class TestInstanceView(TestCase): request = factory.put('/1', data, format='json') with self.assertNumQueries(EXPECTED_QUERIES_FOR_PUT): response = self.view(request, pk='1').render() - self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(dict(response.data), {'id': 1, 'text': 'foobar'}) + assert response.status_code == status.HTTP_200_OK + assert dict(response.data) == {'id': 1, 'text': 'foobar'} updated = self.objects.get(id=1) - self.assertEqual(updated.text, 'foobar') + assert updated.text == 'foobar' def test_patch_instance_view(self): """ @@ -221,10 +221,10 @@ class TestInstanceView(TestCase): with self.assertNumQueries(EXPECTED_QUERIES_FOR_PUT): response = self.view(request, pk=1).render() - self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(response.data, {'id': 1, 'text': 'foobar'}) + assert response.status_code == status.HTTP_200_OK + assert response.data == {'id': 1, 'text': 'foobar'} updated = self.objects.get(id=1) - self.assertEqual(updated.text, 'foobar') + assert updated.text == 'foobar' def test_delete_instance_view(self): """ @@ -233,10 +233,10 @@ class TestInstanceView(TestCase): request = factory.delete('/1') with self.assertNumQueries(2): response = self.view(request, pk=1).render() - self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) - self.assertEqual(response.content, six.b('')) + assert response.status_code == status.HTTP_204_NO_CONTENT + assert response.content == six.b('') ids = [obj.id for obj in self.objects.all()] - self.assertEqual(ids, [2, 3]) + assert ids == [2, 3] def test_get_instance_view_incorrect_arg(self): """ @@ -246,7 +246,7 @@ class TestInstanceView(TestCase): request = factory.get('/a') with self.assertNumQueries(0): response = self.view(request, pk='a').render() - self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) + assert response.status_code == status.HTTP_404_NOT_FOUND def test_put_cannot_set_id(self): """ @@ -256,10 +256,10 @@ class TestInstanceView(TestCase): request = factory.put('/1', data, format='json') with self.assertNumQueries(EXPECTED_QUERIES_FOR_PUT): response = self.view(request, pk=1).render() - self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(response.data, {'id': 1, 'text': 'foobar'}) + assert response.status_code == status.HTTP_200_OK + assert response.data == {'id': 1, 'text': 'foobar'} updated = self.objects.get(id=1) - self.assertEqual(updated.text, 'foobar') + assert updated.text == 'foobar' def test_put_to_deleted_instance(self): """ @@ -271,7 +271,7 @@ class TestInstanceView(TestCase): request = factory.put('/1', data, format='json') with self.assertNumQueries(1): response = self.view(request, pk=1).render() - self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) + assert response.status_code == status.HTTP_404_NOT_FOUND def test_put_to_filtered_out_instance(self): """ @@ -282,7 +282,7 @@ class TestInstanceView(TestCase): filtered_out_pk = BasicModel.objects.filter(text='filtered out')[0].pk request = factory.put('/{0}'.format(filtered_out_pk), data, format='json') response = self.view(request, pk=filtered_out_pk).render() - self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) + assert response.status_code == status.HTTP_404_NOT_FOUND def test_patch_cannot_create_an_object(self): """ @@ -292,8 +292,8 @@ class TestInstanceView(TestCase): request = factory.patch('/999', data, format='json') with self.assertNumQueries(1): response = self.view(request, pk=999).render() - self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) - self.assertFalse(self.objects.filter(id=999).exists()) + assert response.status_code == status.HTTP_404_NOT_FOUND + assert not self.objects.filter(id=999).exists() def test_put_error_instance_view(self): """ @@ -303,7 +303,7 @@ class TestInstanceView(TestCase): request = factory.put('/', data, HTTP_ACCEPT='text/html') response = self.view(request, pk=1).render() expected_error = 'Ensure this field has no more than 100 characters.' - self.assertIn(expected_error, response.rendered_content.decode('utf-8')) + assert expected_error in response.rendered_content.decode('utf-8') class TestFKInstanceView(TestCase): @@ -363,8 +363,8 @@ class TestOverriddenGetObject(TestCase): request = factory.get('/1') with self.assertNumQueries(1): response = self.view(request, pk=1).render() - self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(response.data, self.data[0]) + assert response.status_code == status.HTTP_200_OK + assert response.data == self.data[0] # Regression test for #285 @@ -394,9 +394,9 @@ class TestCreateModelWithAutoNowAddField(TestCase): data = {'email': 'foobar@example.com', 'content': 'foobar'} request = factory.post('/', data, format='json') response = self.view(request).render() - self.assertEqual(response.status_code, status.HTTP_201_CREATED) + assert response.status_code == status.HTTP_201_CREATED created = self.objects.get(id=1) - self.assertEqual(created.content, 'foobar') + assert created.content == 'foobar' # Test for particularly ugly regression with m2m in browsable API @@ -432,7 +432,7 @@ class TestM2MBrowsableAPI(TestCase): request = factory.get('/', HTTP_ACCEPT='text/html') view = ExampleView().as_view() response = view(request).render() - self.assertEqual(response.status_code, status.HTTP_200_OK) + assert response.status_code == status.HTTP_200_OK class InclusiveFilterBackend(object): @@ -489,9 +489,9 @@ class TestFilterBackendAppliedToViews(TestCase): root_view = RootView.as_view(filter_backends=(InclusiveFilterBackend,)) request = factory.get('/') response = root_view(request).render() - self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(len(response.data), 1) - self.assertEqual(response.data, [{'id': 1, 'text': 'foo'}]) + assert response.status_code == status.HTTP_200_OK + assert len(response.data) == 1 + assert response.data == [{'id': 1, 'text': 'foo'}] def test_get_root_view_filters_out_all_models_with_exclusive_filter_backend(self): """ @@ -500,8 +500,8 @@ class TestFilterBackendAppliedToViews(TestCase): root_view = RootView.as_view(filter_backends=(ExclusiveFilterBackend,)) request = factory.get('/') response = root_view(request).render() - self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(response.data, []) + assert response.status_code == status.HTTP_200_OK + assert response.data == [] def test_get_instance_view_filters_out_name_with_filter_backend(self): """ @@ -510,8 +510,8 @@ class TestFilterBackendAppliedToViews(TestCase): instance_view = InstanceView.as_view(filter_backends=(ExclusiveFilterBackend,)) request = factory.get('/1') response = instance_view(request, pk=1).render() - self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) - self.assertEqual(response.data, {'detail': 'Not found.'}) + assert response.status_code == status.HTTP_404_NOT_FOUND + assert response.data == {'detail': 'Not found.'} def test_get_instance_view_will_return_single_object_when_filter_does_not_exclude_it(self): """ @@ -520,8 +520,8 @@ class TestFilterBackendAppliedToViews(TestCase): instance_view = InstanceView.as_view(filter_backends=(InclusiveFilterBackend,)) request = factory.get('/1') response = instance_view(request, pk=1).render() - self.assertEqual(response.status_code, status.HTTP_200_OK) - self.assertEqual(response.data, {'id': 1, 'text': 'foo'}) + assert response.status_code == status.HTTP_200_OK + assert response.data == {'id': 1, 'text': 'foo'} def test_dynamic_serializer_form_in_browsable_api(self): """ @@ -530,8 +530,8 @@ class TestFilterBackendAppliedToViews(TestCase): view = DynamicSerializerView.as_view() request = factory.get('/') response = view(request).render() - self.assertContains(response, 'field_b') - self.assertNotContains(response, 'field_a') + assert 'field_b' in response + assert 'field_a' not in response class TestGuardedQueryset(TestCase): From 4a0829d6ec58b8b2fd12c36a34cdcc319def2695 Mon Sep 17 00:00:00 2001 From: Asif Saifuddin Auvi Date: Wed, 30 Nov 2016 02:08:37 +0600 Subject: [PATCH 08/46] attempt to fix test --- tests/test_generics.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_generics.py b/tests/test_generics.py index 2c3679c46..67191d329 100644 --- a/tests/test_generics.py +++ b/tests/test_generics.py @@ -530,7 +530,7 @@ class TestFilterBackendAppliedToViews(TestCase): view = DynamicSerializerView.as_view() request = factory.get('/') response = view(request).render() - assert 'field_b' in response + assert response is 'field_b' assert 'field_a' not in response From a5c8a8c2265c6462208c2defc0b943bc51ace6df Mon Sep 17 00:00:00 2001 From: Jeff Fein-Worton Date: Tue, 29 Nov 2016 18:00:10 -0800 Subject: [PATCH 09/46] typo --- docs/api-guide/permissions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api-guide/permissions.md b/docs/api-guide/permissions.md index 7cdb59531..f2d2fcaae 100644 --- a/docs/api-guide/permissions.md +++ b/docs/api-guide/permissions.md @@ -164,7 +164,7 @@ As with `DjangoModelPermissions`, this permission must only be applied to views Note that `DjangoObjectPermissions` **does not** require the `django-guardian` package, and should support other object-level backends equally well. -As with `DjangoModelPermissions` you can use custom model permissions by overriding `DjangoModelPermissions` and setting the `.perms_map` property. Refer to the source code for details. +As with `DjangoModelPermissions` you can use custom model permissions by overriding `DjangoObjectPermissions` and setting the `.perms_map` property. Refer to the source code for details. --- From a5bb9825f3b238d89fdb5d8754d057116fff56a9 Mon Sep 17 00:00:00 2001 From: Asif Saifuddin Auvi Date: Wed, 30 Nov 2016 09:56:22 +0600 Subject: [PATCH 10/46] attempt to fix test again --- tests/test_generics.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_generics.py b/tests/test_generics.py index 67191d329..2c3679c46 100644 --- a/tests/test_generics.py +++ b/tests/test_generics.py @@ -530,7 +530,7 @@ class TestFilterBackendAppliedToViews(TestCase): view = DynamicSerializerView.as_view() request = factory.get('/') response = view(request).render() - assert response is 'field_b' + assert 'field_b' in response assert 'field_a' not in response From f5a900a404a85163ba36ec34034d0bacd626b010 Mon Sep 17 00:00:00 2001 From: Asif Saifuddin Auvi Date: Wed, 30 Nov 2016 10:01:37 +0600 Subject: [PATCH 11/46] some reverts to fix test --- tests/test_generics.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_generics.py b/tests/test_generics.py index 2c3679c46..aa3951154 100644 --- a/tests/test_generics.py +++ b/tests/test_generics.py @@ -530,8 +530,8 @@ class TestFilterBackendAppliedToViews(TestCase): view = DynamicSerializerView.as_view() request = factory.get('/') response = view(request).render() - assert 'field_b' in response - assert 'field_a' not in response + self.assertContains(response, 'field_b') + self.assertNotContains(response, 'field_a') class TestGuardedQueryset(TestCase): From 10b5f36fec92871e1d96c85a008324683a32f6b5 Mon Sep 17 00:00:00 2001 From: Asif Saifuddin Auvi Date: Wed, 30 Nov 2016 12:35:34 +0600 Subject: [PATCH 12/46] added fixes --- tests/test_generics.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/test_generics.py b/tests/test_generics.py index aa3951154..c24cda006 100644 --- a/tests/test_generics.py +++ b/tests/test_generics.py @@ -530,8 +530,9 @@ class TestFilterBackendAppliedToViews(TestCase): view = DynamicSerializerView.as_view() request = factory.get('/') response = view(request).render() - self.assertContains(response, 'field_b') - self.assertNotContains(response, 'field_a') + content = response.content.decode('utf8') + assert 'field_b' in content + assert 'field_a' not in content class TestGuardedQueryset(TestCase): From e03d88ced7f2b22f96f50c2a885264147b242b4a Mon Sep 17 00:00:00 2001 From: Asif Saifuddin Auvi Date: Wed, 30 Nov 2016 15:48:33 +0600 Subject: [PATCH 13/46] more pytest style assert (#4719) --- tests/test_validation.py | 38 +++++++++++++++++++--------------- tests/test_validation_error.py | 16 +++++++------- 2 files changed, 29 insertions(+), 25 deletions(-) diff --git a/tests/test_validation.py b/tests/test_validation.py index bc950dd22..8ff4aaf38 100644 --- a/tests/test_validation.py +++ b/tests/test_validation.py @@ -60,11 +60,11 @@ class TestNestedValidationError(TestCase): } }) - self.assertEqual(serializers.as_serializer_error(e), { + assert serializers.as_serializer_error(e) == { 'nested': { 'field': ['error'], } - }) + } class TestPreSaveValidationExclusionsSerializer(TestCase): @@ -75,20 +75,20 @@ class TestPreSaveValidationExclusionsSerializer(TestCase): # We've set `required=False` on the serializer, but the model # does not have `blank=True`, so this serializer should not validate. serializer = ShouldValidateModelSerializer(data={'renamed': ''}) - self.assertEqual(serializer.is_valid(), False) - self.assertIn('renamed', serializer.errors) - self.assertNotIn('should_validate_field', serializer.errors) + assert serializer.is_valid() is False + assert 'renamed' in serializer.errors + assert 'should_validate_field' not in serializer.errors class TestCustomValidationMethods(TestCase): def test_custom_validation_method_is_executed(self): serializer = ShouldValidateModelSerializer(data={'renamed': 'fo'}) - self.assertFalse(serializer.is_valid()) - self.assertIn('renamed', serializer.errors) + assert not serializer.is_valid() + assert 'renamed' in serializer.errors def test_custom_validation_method_passing(self): serializer = ShouldValidateModelSerializer(data={'renamed': 'foo'}) - self.assertTrue(serializer.is_valid()) + assert serializer.is_valid() class ValidationSerializer(serializers.Serializer): @@ -108,12 +108,12 @@ class TestAvoidValidation(TestCase): """ def test_serializer_errors_has_only_invalid_data_error(self): serializer = ValidationSerializer(data='invalid data') - self.assertFalse(serializer.is_valid()) - self.assertDictEqual(serializer.errors, { + assert not serializer.is_valid() + assert serializer.errors == { 'non_field_errors': [ 'Invalid data. Expected a dictionary, but got %s.' % type('').__name__ ] - }) + } # regression tests for issue: 1493 @@ -137,27 +137,31 @@ class TestMaxValueValidatorValidation(TestCase): def test_max_value_validation_serializer_success(self): serializer = ValidationMaxValueValidatorModelSerializer(data={'number_value': 99}) - self.assertTrue(serializer.is_valid()) + assert serializer.is_valid() def test_max_value_validation_serializer_fails(self): serializer = ValidationMaxValueValidatorModelSerializer(data={'number_value': 101}) - self.assertFalse(serializer.is_valid()) - self.assertDictEqual({'number_value': ['Ensure this value is less than or equal to 100.']}, serializer.errors) + assert not serializer.is_valid() + assert serializer.errors == { + 'number_value': [ + 'Ensure this value is less than or equal to 100.' + ] + } def test_max_value_validation_success(self): obj = ValidationMaxValueValidatorModel.objects.create(number_value=100) request = factory.patch('/{0}'.format(obj.pk), {'number_value': 98}, format='json') view = UpdateMaxValueValidationModel().as_view() response = view(request, pk=obj.pk).render() - self.assertEqual(response.status_code, status.HTTP_200_OK) + assert response.status_code == status.HTTP_200_OK def test_max_value_validation_fail(self): obj = ValidationMaxValueValidatorModel.objects.create(number_value=100) request = factory.patch('/{0}'.format(obj.pk), {'number_value': 101}, format='json') view = UpdateMaxValueValidationModel().as_view() response = view(request, pk=obj.pk).render() - self.assertEqual(response.content, b'{"number_value":["Ensure this value is less than or equal to 100."]}') - self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + assert response.content == b'{"number_value":["Ensure this value is less than or equal to 100."]}' + assert response.status_code == status.HTTP_400_BAD_REQUEST # regression tests for issue: 1533 diff --git a/tests/test_validation_error.py b/tests/test_validation_error.py index 8e371a349..562fe37e6 100644 --- a/tests/test_validation_error.py +++ b/tests/test_validation_error.py @@ -54,16 +54,16 @@ class TestValidationErrorWithFullDetails(TestCase): request = factory.get('/', content_type='application/json') response = view(request) - self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) - self.assertEqual(response.data, self.expected_response_data) + assert response.status_code == status.HTTP_400_BAD_REQUEST + assert response.data == self.expected_response_data def test_function_based_view_exception_handler(self): view = error_view request = factory.get('/', content_type='application/json') response = view(request) - self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) - self.assertEqual(response.data, self.expected_response_data) + assert response.status_code == status.HTTP_400_BAD_REQUEST + assert response.data == self.expected_response_data class TestValidationErrorWithCodes(TestCase): @@ -89,13 +89,13 @@ class TestValidationErrorWithCodes(TestCase): request = factory.get('/', content_type='application/json') response = view(request) - self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) - self.assertEqual(response.data, self.expected_response_data) + assert response.status_code == status.HTTP_400_BAD_REQUEST + assert response.data == self.expected_response_data def test_function_based_view_exception_handler(self): view = error_view request = factory.get('/', content_type='application/json') response = view(request) - self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) - self.assertEqual(response.data, self.expected_response_data) + assert response.status_code == status.HTTP_400_BAD_REQUEST + assert response.data == self.expected_response_data From 504f4b44c6dc96e1c1dd2cece3e9d3ac1052011d Mon Sep 17 00:00:00 2001 From: Asif Saifuddin Auvi Date: Wed, 30 Nov 2016 16:17:30 +0600 Subject: [PATCH 14/46] converted asserts of atomic requests test to pytest --- tests/test_atomic_requests.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/tests/test_atomic_requests.py b/tests/test_atomic_requests.py index 09d7f2fb1..9085bfc89 100644 --- a/tests/test_atomic_requests.py +++ b/tests/test_atomic_requests.py @@ -67,8 +67,8 @@ class DBTransactionTests(TestCase): with self.assertNumQueries(1): response = self.view(request) - self.assertFalse(transaction.get_rollback()) - self.assertEqual(response.status_code, status.HTTP_200_OK) + assert not transaction.get_rollback() + assert response.status_code == status.HTTP_200_OK assert BasicModel.objects.count() == 1 @@ -98,7 +98,7 @@ class DBTransactionErrorTests(TestCase): # 3 - release savepoint with transaction.atomic(): self.assertRaises(Exception, self.view, request) - self.assertFalse(transaction.get_rollback()) + assert not transaction.get_rollback() assert BasicModel.objects.count() == 1 @@ -128,9 +128,8 @@ class DBTransactionAPIExceptionTests(TestCase): # 4 - release savepoint (django>=1.8 only) with transaction.atomic(): response = self.view(request) - self.assertTrue(transaction.get_rollback()) - self.assertEqual(response.status_code, - status.HTTP_500_INTERNAL_SERVER_ERROR) + assert transaction.get_rollback() + assert response.status_code == status.HTTP_500_INTERNAL_SERVER_ERROR assert BasicModel.objects.count() == 0 @@ -151,5 +150,4 @@ class NonAtomicDBTransactionAPIExceptionTests(TransactionTestCase): # without checking connection.in_atomic_block view raises 500 # due attempt to rollback without transaction - self.assertEqual(response.status_code, - status.HTTP_404_NOT_FOUND) + assert response.status_code == status.HTTP_404_NOT_FOUND From a9b6c974852c7b5c6fb95c586fdab9fbe29e73f7 Mon Sep 17 00:00:00 2001 From: Asif Saifuddin Auvi Date: Wed, 30 Nov 2016 16:24:48 +0600 Subject: [PATCH 15/46] converted asserts of decorators test to pytest --- tests/test_decorators.py | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/tests/test_decorators.py b/tests/test_decorators.py index 46e4a6ad7..b187e5fd6 100644 --- a/tests/test_decorators.py +++ b/tests/test_decorators.py @@ -56,11 +56,11 @@ class DecoratorTestCase(TestCase): request = self.factory.get('/') response = view(request) - self.assertEqual(response.status_code, status.HTTP_200_OK) + assert response.status_code == status.HTTP_200_OK request = self.factory.post('/') response = view(request) - self.assertEqual(response.status_code, status.HTTP_405_METHOD_NOT_ALLOWED) + assert response.status_code == status.HTTP_405_METHOD_NOT_ALLOWED def test_calling_put_method(self): @@ -70,11 +70,11 @@ class DecoratorTestCase(TestCase): request = self.factory.put('/') response = view(request) - self.assertEqual(response.status_code, status.HTTP_200_OK) + assert response.status_code == status.HTTP_200_OK request = self.factory.post('/') response = view(request) - self.assertEqual(response.status_code, status.HTTP_405_METHOD_NOT_ALLOWED) + assert response.status_code == status.HTTP_405_METHOD_NOT_ALLOWED def test_calling_patch_method(self): @@ -84,11 +84,11 @@ class DecoratorTestCase(TestCase): request = self.factory.patch('/') response = view(request) - self.assertEqual(response.status_code, status.HTTP_200_OK) + assert response.status_code == status.HTTP_200_OK request = self.factory.post('/') response = view(request) - self.assertEqual(response.status_code, status.HTTP_405_METHOD_NOT_ALLOWED) + assert response.status_code == status.HTTP_405_METHOD_NOT_ALLOWED def test_renderer_classes(self): @@ -99,16 +99,15 @@ class DecoratorTestCase(TestCase): request = self.factory.get('/') response = view(request) - self.assertTrue(isinstance(response.accepted_renderer, JSONRenderer)) + assert isinstance(response.accepted_renderer, JSONRenderer) def test_parser_classes(self): @api_view(['GET']) @parser_classes([JSONParser]) def view(request): - self.assertEqual(len(request.parsers), 1) - self.assertTrue(isinstance(request.parsers[0], - JSONParser)) + assert len(request.parsers) == 1 + assert isinstance(request.parsers[0], JSONParser) return Response({}) request = self.factory.get('/') @@ -119,9 +118,8 @@ class DecoratorTestCase(TestCase): @api_view(['GET']) @authentication_classes([BasicAuthentication]) def view(request): - self.assertEqual(len(request.authenticators), 1) - self.assertTrue(isinstance(request.authenticators[0], - BasicAuthentication)) + assert len(request.authenticators) == 1 + assert isinstance(request.authenticators[0], BasicAuthentication) return Response({}) request = self.factory.get('/') @@ -136,7 +134,7 @@ class DecoratorTestCase(TestCase): request = self.factory.get('/') response = view(request) - self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) + assert response.status_code == status.HTTP_403_FORBIDDEN def test_throttle_classes(self): class OncePerDayUserThrottle(UserRateThrottle): @@ -149,7 +147,7 @@ class DecoratorTestCase(TestCase): request = self.factory.get('/') response = view(request) - self.assertEqual(response.status_code, status.HTTP_200_OK) + assert response.status_code == status.HTTP_200_OK response = view(request) - self.assertEqual(response.status_code, status.HTTP_429_TOO_MANY_REQUESTS) + assert response.status_code == status.HTTP_429_TOO_MANY_REQUESTS From 9a3f8d9a9c63fc14a4e13738407f2b262de6649a Mon Sep 17 00:00:00 2001 From: Asif Saifuddin Auvi Date: Wed, 30 Nov 2016 16:42:43 +0600 Subject: [PATCH 16/46] converted asserts of descriptions test to pytest --- tests/test_description.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/test_description.py b/tests/test_description.py index fcb88287b..08d8bddec 100644 --- a/tests/test_description.py +++ b/tests/test_description.py @@ -60,7 +60,7 @@ class TestViewNamesAndDescriptions(TestCase): """ class MockView(APIView): pass - self.assertEqual(MockView().get_view_name(), 'Mock') + assert MockView().get_view_name() == 'Mock' def test_view_description_uses_docstring(self): """Ensure view descriptions are based on the docstring.""" @@ -80,7 +80,7 @@ class TestViewNamesAndDescriptions(TestCase): # hash style header #""" - self.assertEqual(MockView().get_view_description(), DESCRIPTION) + assert MockView().get_view_description() == DESCRIPTION def test_view_description_can_be_empty(self): """ @@ -89,7 +89,7 @@ class TestViewNamesAndDescriptions(TestCase): """ class MockView(APIView): pass - self.assertEqual(MockView().get_view_description(), '') + assert MockView().get_view_description() == '' def test_view_description_can_be_promise(self): """ @@ -111,7 +111,7 @@ class TestViewNamesAndDescriptions(TestCase): class MockView(APIView): __doc__ = MockLazyStr("a gettext string") - self.assertEqual(MockView().get_view_description(), 'a gettext string') + assert MockView().get_view_description() == 'a gettext string' def test_markdown(self): """ @@ -120,7 +120,7 @@ class TestViewNamesAndDescriptions(TestCase): if apply_markdown: gte_21_match = apply_markdown(DESCRIPTION) == MARKED_DOWN_gte_21 lt_21_match = apply_markdown(DESCRIPTION) == MARKED_DOWN_lt_21 - self.assertTrue(gte_21_match or lt_21_match) + assert gte_21_match or lt_21_match def test_dedent_tabs(): From 7e8b01dbd2e780b1204d8c362dcb40d31d1b27d5 Mon Sep 17 00:00:00 2001 From: Asif Saifuddin Auvi Date: Wed, 30 Nov 2016 16:45:48 +0600 Subject: [PATCH 17/46] converted asserts of encoders test to pytest --- tests/test_encoders.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/test_encoders.py b/tests/test_encoders.py index d6f681932..687141476 100644 --- a/tests/test_encoders.py +++ b/tests/test_encoders.py @@ -20,21 +20,21 @@ class JSONEncoderTests(TestCase): Tests encoding a decimal """ d = Decimal(3.14) - self.assertEqual(d, float(d)) + assert d == float(d) def test_encode_datetime(self): """ Tests encoding a datetime object """ current_time = datetime.now() - self.assertEqual(self.encoder.default(current_time), current_time.isoformat()) + assert self.encoder.default(current_time) == current_time.isoformat() def test_encode_time(self): """ Tests encoding a timezone """ current_time = datetime.now().time() - self.assertEqual(self.encoder.default(current_time), current_time.isoformat()[:12]) + assert self.encoder.default(current_time) == current_time.isoformat()[:12] def test_encode_time_tz(self): """ @@ -64,18 +64,18 @@ class JSONEncoderTests(TestCase): Tests encoding a date object """ current_date = date.today() - self.assertEqual(self.encoder.default(current_date), current_date.isoformat()) + assert self.encoder.default(current_date) == current_date.isoformat() def test_encode_timedelta(self): """ Tests encoding a timedelta object """ delta = timedelta(hours=1) - self.assertEqual(self.encoder.default(delta), str(delta.total_seconds())) + assert self.encoder.default(delta) == str(delta.total_seconds()) def test_encode_uuid(self): """ Tests encoding a UUID object """ unique_id = uuid4() - self.assertEqual(self.encoder.default(unique_id), str(unique_id)) + assert self.encoder.default(unique_id) == str(unique_id) From 1a741bb2a2759d9b20afc6160b5c7d58ec5ff382 Mon Sep 17 00:00:00 2001 From: Asif Saifuddin Auvi Date: Wed, 30 Nov 2016 17:12:01 +0600 Subject: [PATCH 18/46] converted asserts of exceptions test to pytest (#4723) --- tests/test_exceptions.py | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/tests/test_exceptions.py b/tests/test_exceptions.py index f1d172211..8b5628ef2 100644 --- a/tests/test_exceptions.py +++ b/tests/test_exceptions.py @@ -16,28 +16,22 @@ class ExceptionTestCase(TestCase): example = "string" lazy_example = _(example) - self.assertEqual( - _get_error_details(lazy_example), - example - ) + assert _get_error_details(lazy_example) == example + assert isinstance( _get_error_details(lazy_example), ErrorDetail ) - self.assertEqual( - _get_error_details({'nested': lazy_example})['nested'], - example - ) + assert _get_error_details({'nested': lazy_example})['nested'] == example + assert isinstance( _get_error_details({'nested': lazy_example})['nested'], ErrorDetail ) - self.assertEqual( - _get_error_details([[lazy_example]])[0][0], - example - ) + assert _get_error_details([[lazy_example]])[0][0] == example + assert isinstance( _get_error_details([[lazy_example]])[0][0], ErrorDetail From 4f6c326a9955e70e64eb83499015bba10175468a Mon Sep 17 00:00:00 2001 From: Asif Saifuddin Auvi Date: Wed, 30 Nov 2016 18:52:32 +0600 Subject: [PATCH 19/46] converted remaining unittes asserts of fields test to pytest (#4724) --- tests/test_fields.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/test_fields.py b/tests/test_fields.py index 92030e3ca..069ba879d 100644 --- a/tests/test_fields.py +++ b/tests/test_fields.py @@ -1014,16 +1014,16 @@ class TestLocalizedDecimalField(TestCase): @override_settings(USE_L10N=True, LANGUAGE_CODE='pl') def test_to_internal_value(self): field = serializers.DecimalField(max_digits=2, decimal_places=1, localize=True) - self.assertEqual(field.to_internal_value('1,1'), Decimal('1.1')) + assert field.to_internal_value('1,1') == Decimal('1.1') @override_settings(USE_L10N=True, LANGUAGE_CODE='pl') def test_to_representation(self): field = serializers.DecimalField(max_digits=2, decimal_places=1, localize=True) - self.assertEqual(field.to_representation(Decimal('1.1')), '1,1') + assert field.to_representation(Decimal('1.1')) == '1,1' def test_localize_forces_coerce_to_string(self): field = serializers.DecimalField(max_digits=2, decimal_places=1, coerce_to_string=False, localize=True) - self.assertTrue(isinstance(field.to_representation(Decimal('1.1')), six.string_types)) + assert isinstance(field.to_representation(Decimal('1.1')), six.string_types) class TestQuantizedValueForDecimal(TestCase): @@ -1031,19 +1031,19 @@ class TestQuantizedValueForDecimal(TestCase): field = serializers.DecimalField(max_digits=4, decimal_places=2) value = field.to_internal_value(12).as_tuple() expected_digit_tuple = (0, (1, 2, 0, 0), -2) - self.assertEqual(value, expected_digit_tuple) + assert value == expected_digit_tuple def test_string_quantized_value_for_decimal(self): field = serializers.DecimalField(max_digits=4, decimal_places=2) value = field.to_internal_value('12').as_tuple() expected_digit_tuple = (0, (1, 2, 0, 0), -2) - self.assertEqual(value, expected_digit_tuple) + assert value == expected_digit_tuple def test_part_precision_string_quantized_value_for_decimal(self): field = serializers.DecimalField(max_digits=4, decimal_places=2) value = field.to_internal_value('12.0').as_tuple() expected_digit_tuple = (0, (1, 2, 0, 0), -2) - self.assertEqual(value, expected_digit_tuple) + assert value == expected_digit_tuple class TestNoDecimalPlaces(FieldValues): From 22578525eff075e329e8840c42c358d59105a0d3 Mon Sep 17 00:00:00 2001 From: Xavier Ordoquy Date: Wed, 30 Nov 2016 13:58:34 +0100 Subject: [PATCH 20/46] Documentation update (#4717) --- docs/api-guide/authentication.md | 2 +- docs/api-guide/fields.md | 6 +++--- docs/api-guide/filtering.md | 4 ++-- docs/api-guide/generic-views.md | 2 +- docs/api-guide/pagination.md | 2 +- docs/api-guide/parsers.md | 2 +- docs/api-guide/permissions.md | 4 ++-- docs/api-guide/relations.md | 6 +++--- docs/api-guide/renderers.md | 4 ++-- docs/api-guide/responses.md | 2 +- docs/api-guide/reverse.md | 4 ++-- docs/api-guide/schemas.md | 4 ++-- docs/api-guide/serializers.md | 2 +- docs/api-guide/testing.md | 4 ++-- docs/api-guide/throttling.md | 4 ++-- docs/api-guide/validators.md | 2 +- docs/topics/2.2-announcement.md | 8 ++++---- docs/topics/2.4-announcement.md | 2 +- docs/topics/3.0-announcement.md | 4 ++-- docs/topics/ajax-csrf-cors.md | 2 +- docs/topics/release-notes.md | 2 +- 21 files changed, 36 insertions(+), 36 deletions(-) diff --git a/docs/api-guide/authentication.md b/docs/api-guide/authentication.md index bf3a31eb7..4a01188f3 100644 --- a/docs/api-guide/authentication.md +++ b/docs/api-guide/authentication.md @@ -363,7 +363,7 @@ HTTP Signature (currently a [IETF draft][http-signature-ietf-draft]) provides a [oauth]: http://oauth.net/2/ [permission]: permissions.md [throttling]: throttling.md -[csrf-ajax]: https://docs.djangoproject.com/en/dev/ref/csrf/#ajax +[csrf-ajax]: https://docs.djangoproject.com/en/stable/ref/csrf/#ajax [mod_wsgi_official]: http://code.google.com/p/modwsgi/wiki/ConfigurationDirectives#WSGIPassAuthorization [django-oauth-toolkit-getting-started]: https://django-oauth-toolkit.readthedocs.io/en/latest/rest-framework/getting_started.html [django-rest-framework-oauth]: http://jpadilla.github.io/django-rest-framework-oauth/ diff --git a/docs/api-guide/fields.md b/docs/api-guide/fields.md index 6b6ae612d..b527b016b 100644 --- a/docs/api-guide/fields.md +++ b/docs/api-guide/fields.md @@ -665,12 +665,12 @@ The [django-rest-framework-gis][django-rest-framework-gis] package provides geog The [django-rest-framework-hstore][django-rest-framework-hstore] package provides an `HStoreField` to support [django-hstore][django-hstore] `DictionaryField` model field. -[cite]: https://docs.djangoproject.com/en/dev/ref/forms/api/#django.forms.Form.cleaned_data +[cite]: https://docs.djangoproject.com/en/stable/ref/forms/api/#django.forms.Form.cleaned_data [html-and-forms]: ../topics/html-and-forms.md -[FILE_UPLOAD_HANDLERS]: https://docs.djangoproject.com/en/dev/ref/settings/#std:setting-FILE_UPLOAD_HANDLERS +[FILE_UPLOAD_HANDLERS]: https://docs.djangoproject.com/en/stable/ref/settings/#std:setting-FILE_UPLOAD_HANDLERS [ecma262]: http://ecma-international.org/ecma-262/5.1/#sec-15.9.1.15 [strftime]: https://docs.python.org/3/library/datetime.html#strftime-and-strptime-behavior -[django-widgets]: https://docs.djangoproject.com/en/dev/ref/forms/widgets/ +[django-widgets]: https://docs.djangoproject.com/en/stable/ref/forms/widgets/ [iso8601]: http://www.w3.org/TR/NOTE-datetime [drf-compound-fields]: https://drf-compound-fields.readthedocs.io [drf-extra-fields]: https://github.com/Hipo/drf-extra-fields diff --git a/docs/api-guide/filtering.md b/docs/api-guide/filtering.md index 3f212ced3..8a23a2ea3 100644 --- a/docs/api-guide/filtering.md +++ b/docs/api-guide/filtering.md @@ -455,14 +455,14 @@ The [djangorestframework-word-filter][django-rest-framework-word-search-filter] [drf-url-filter][drf-url-filter] is a simple Django app to apply filters on drf `ModelViewSet`'s `Queryset` in a clean, simple and configurable way. It also supports validations on incoming query params and their values. A beautiful python package `Voluptuous` is being used for validations on the incoming query parameters. The best part about voluptuous is you can define your own validations as per your query params requirements. -[cite]: https://docs.djangoproject.com/en/dev/topics/db/queries/#retrieving-specific-objects-with-filters +[cite]: https://docs.djangoproject.com/en/stable/topics/db/queries/#retrieving-specific-objects-with-filters [django-filter]: https://github.com/alex/django-filter [django-filter-docs]: https://django-filter.readthedocs.io/en/latest/index.html [guardian]: https://django-guardian.readthedocs.io/ [view-permissions]: https://django-guardian.readthedocs.io/en/latest/userguide/assign.html [view-permissions-blogpost]: http://blog.nyaruka.com/adding-a-view-permission-to-django-models [nullbooleanselect]: https://github.com/django/django/blob/master/django/forms/widgets.py -[search-django-admin]: https://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.search_fields +[search-django-admin]: https://docs.djangoproject.com/en/stable/ref/contrib/admin/#django.contrib.admin.ModelAdmin.search_fields [django-rest-framework-filters]: https://github.com/philipn/django-rest-framework-filters [django-rest-framework-word-search-filter]: https://github.com/trollknurr/django-rest-framework-word-search-filter [django-url-filter]: https://github.com/miki725/django-url-filter diff --git a/docs/api-guide/generic-views.md b/docs/api-guide/generic-views.md index c368d0b46..606a3787a 100644 --- a/docs/api-guide/generic-views.md +++ b/docs/api-guide/generic-views.md @@ -382,7 +382,7 @@ The [django-rest-framework-bulk package][django-rest-framework-bulk] implements [Django Rest Multiple Models][django-rest-multiple-models] provides a generic view (and mixin) for sending multiple serialized models and/or querysets via a single API request. -[cite]: https://docs.djangoproject.com/en/dev/ref/class-based-views/#base-vs-generic-views +[cite]: https://docs.djangoproject.com/en/stable/ref/class-based-views/#base-vs-generic-views [GenericAPIView]: #genericapiview [ListModelMixin]: #listmodelmixin [CreateModelMixin]: #createmodelmixin diff --git a/docs/api-guide/pagination.md b/docs/api-guide/pagination.md index f82614eca..bc7a5602d 100644 --- a/docs/api-guide/pagination.md +++ b/docs/api-guide/pagination.md @@ -325,7 +325,7 @@ The [`DRF-extensions` package][drf-extensions] includes a [`PaginateByMaxMixin` The [`drf-proxy-pagination` package][drf-proxy-pagination] includes a `ProxyPagination` class which allows to choose pagination class with a query parameter. -[cite]: https://docs.djangoproject.com/en/dev/topics/pagination/ +[cite]: https://docs.djangoproject.com/en/stable/topics/pagination/ [github-link-pagination]: https://developer.github.com/guides/traversing-with-pagination/ [link-header]: ../img/link-header-pagination.png [drf-extensions]: http://chibisov.github.io/drf-extensions/docs/ diff --git a/docs/api-guide/parsers.md b/docs/api-guide/parsers.md index ef2859fe1..7bf932d06 100644 --- a/docs/api-guide/parsers.md +++ b/docs/api-guide/parsers.md @@ -224,7 +224,7 @@ Modify your REST framework settings. [jquery-ajax]: http://api.jquery.com/jQuery.ajax/ [cite]: https://groups.google.com/d/topic/django-developers/dxI4qVzrBY4/discussion -[upload-handlers]: https://docs.djangoproject.com/en/dev/topics/http/file-uploads/#upload-handlers +[upload-handlers]: https://docs.djangoproject.com/en/stable/topics/http/file-uploads/#upload-handlers [rest-framework-yaml]: http://jpadilla.github.io/django-rest-framework-yaml/ [rest-framework-xml]: http://jpadilla.github.io/django-rest-framework-xml/ [yaml]: http://www.yaml.org/ diff --git a/docs/api-guide/permissions.md b/docs/api-guide/permissions.md index f2d2fcaae..be2981327 100644 --- a/docs/api-guide/permissions.md +++ b/docs/api-guide/permissions.md @@ -269,8 +269,8 @@ The [Django Rest Framework Roles][django-rest-framework-roles] package makes it [authentication]: authentication.md [throttling]: throttling.md [filtering]: filtering.md -[contribauth]: https://docs.djangoproject.com/en/dev/topics/auth/customizing/#custom-permissions -[objectpermissions]: https://docs.djangoproject.com/en/dev/topics/auth/customizing/#handling-object-permissions +[contribauth]: https://docs.djangoproject.com/en/stable/topics/auth/customizing/#custom-permissions +[objectpermissions]: https://docs.djangoproject.com/en/stable/topics/auth/customizing/#handling-object-permissions [guardian]: https://github.com/lukaszb/django-guardian [get_objects_for_user]: http://pythonhosted.org/django-guardian/api/guardian.shortcuts.html#get-objects-for-user [2.2-announcement]: ../topics/2.2-announcement.md diff --git a/docs/api-guide/relations.md b/docs/api-guide/relations.md index aabe49412..662fd4809 100644 --- a/docs/api-guide/relations.md +++ b/docs/api-guide/relations.md @@ -505,7 +505,7 @@ For example, given the following model for a tag, which has a generic relationsh """ Tags arbitrary model instances using a generic relation. - See: https://docs.djangoproject.com/en/dev/ref/contrib/contenttypes/ + See: https://docs.djangoproject.com/en/stable/ref/contrib/contenttypes/ """ tag_name = models.SlugField() content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE) @@ -593,9 +593,9 @@ The [drf-nested-routers package][drf-nested-routers] provides routers and relati The [rest-framework-generic-relations][drf-nested-relations] library provides read/write serialization for generic foreign keys. [cite]: http://lwn.net/Articles/193245/ -[reverse-relationships]: https://docs.djangoproject.com/en/dev/topics/db/queries/#following-relationships-backward +[reverse-relationships]: https://docs.djangoproject.com/en/stable/topics/db/queries/#following-relationships-backward [routers]: http://www.django-rest-framework.org/api-guide/routers#defaultrouter -[generic-relations]: https://docs.djangoproject.com/en/dev/ref/contrib/contenttypes/#id1 +[generic-relations]: https://docs.djangoproject.com/en/stable/ref/contrib/contenttypes/#id1 [2.2-announcement]: ../topics/2.2-announcement.md [drf-nested-routers]: https://github.com/alanjds/drf-nested-routers [drf-nested-relations]: https://github.com/Ian-Foote/rest-framework-generic-relations diff --git a/docs/api-guide/renderers.md b/docs/api-guide/renderers.md index a95778350..648eafdde 100644 --- a/docs/api-guide/renderers.md +++ b/docs/api-guide/renderers.md @@ -476,7 +476,7 @@ Comma-separated values are a plain-text tabular data format, that can be easily [Rest Framework Latex] provides a renderer that outputs PDFs using Laulatex. It is maintained by [Pebble (S/F Software)][mypebble]. -[cite]: https://docs.djangoproject.com/en/dev/ref/template-response/#the-rendering-process +[cite]: https://docs.djangoproject.com/en/stable/stable/template-response/#the-rendering-process [conneg]: content-negotiation.md [html-and-forms]: ../topics/html-and-forms.md [browser-accept-headers]: http://www.gethifi.com/blog/browser-rest-http-accept-headers @@ -485,7 +485,7 @@ Comma-separated values are a plain-text tabular data format, that can be easily [quote]: http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven [application/vnd.github+json]: http://developer.github.com/v3/media/ [application/vnd.collection+json]: http://www.amundsen.com/media-types/collection/ -[django-error-views]: https://docs.djangoproject.com/en/dev/topics/http/views/#customizing-error-views +[django-error-views]: https://docs.djangoproject.com/en/stable/topics/http/views/#customizing-error-views [rest-framework-jsonp]: http://jpadilla.github.io/django-rest-framework-jsonp/ [cors]: http://www.w3.org/TR/cors/ [cors-docs]: http://www.django-rest-framework.org/topics/ajax-csrf-cors/ diff --git a/docs/api-guide/responses.md b/docs/api-guide/responses.md index 97f312710..8ee14eefa 100644 --- a/docs/api-guide/responses.md +++ b/docs/api-guide/responses.md @@ -91,5 +91,5 @@ As with any other `TemplateResponse`, this method is called to render the serial You won't typically need to call `.render()` yourself, as it's handled by Django's standard response cycle. -[cite]: https://docs.djangoproject.com/en/dev/ref/template-response/ +[cite]: https://docs.djangoproject.com/en/stable/stable/template-response/ [statuscodes]: status-codes.md diff --git a/docs/api-guide/reverse.md b/docs/api-guide/reverse.md index 35d88e2db..ee0b2054f 100644 --- a/docs/api-guide/reverse.md +++ b/docs/api-guide/reverse.md @@ -51,5 +51,5 @@ As with the `reverse` function, you should **include the request as a keyword ar api_root = reverse_lazy('api-root', request=request) [cite]: http://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm#sec_5_1_5 -[reverse]: https://docs.djangoproject.com/en/dev/topics/http/urls/#reverse -[reverse-lazy]: https://docs.djangoproject.com/en/dev/topics/http/urls/#reverse-lazy +[reverse]: https://docs.djangoproject.com/en/stable/topics/http/urls/#reverse +[reverse-lazy]: https://docs.djangoproject.com/en/stable/topics/http/urls/#reverse-lazy diff --git a/docs/api-guide/schemas.md b/docs/api-guide/schemas.md index 7da619034..c89c100fe 100644 --- a/docs/api-guide/schemas.md +++ b/docs/api-guide/schemas.md @@ -541,5 +541,5 @@ A short description of the meaning and intended usage of the input field. [open-api]: https://openapis.org/ [json-hyperschema]: http://json-schema.org/latest/json-schema-hypermedia.html [api-blueprint]: https://apiblueprint.org/ -[static-files]: https://docs.djangoproject.com/en/dev/howto/static-files/ -[named-arguments]: https://docs.djangoproject.com/en/dev/topics/http/urls/#named-groups +[static-files]: https://docs.djangoproject.com/en/stable/howto/static-files/ +[named-arguments]: https://docs.djangoproject.com/en/stable/topics/http/urls/#named-groups diff --git a/docs/api-guide/serializers.md b/docs/api-guide/serializers.md index 290e32f4f..d36812f3f 100644 --- a/docs/api-guide/serializers.md +++ b/docs/api-guide/serializers.md @@ -1118,7 +1118,7 @@ The [html-json-forms][html-json-forms] package provides an algorithm and seriali [cite]: https://groups.google.com/d/topic/django-users/sVFaOfQi4wY/discussion [relations]: relations.md -[model-managers]: https://docs.djangoproject.com/en/dev/topics/db/managers/ +[model-managers]: https://docs.djangoproject.com/en/stable/topics/db/managers/ [encapsulation-blogpost]: http://www.dabapps.com/blog/django-models-and-encapsulation/ [django-rest-marshmallow]: http://tomchristie.github.io/django-rest-marshmallow/ [marshmallow]: https://marshmallow.readthedocs.io/en/latest/ diff --git a/docs/api-guide/testing.md b/docs/api-guide/testing.md index de79a1e2f..410f6d78a 100644 --- a/docs/api-guide/testing.md +++ b/docs/api-guide/testing.md @@ -373,6 +373,6 @@ For example, to add support for using `format='html'` in test requests, you migh } [cite]: http://jacobian.org/writing/django-apps-with-buildout/#s-create-a-test-wrapper -[client]: https://docs.djangoproject.com/en/dev/topics/testing/tools/#the-test-client -[requestfactory]: https://docs.djangoproject.com/en/dev/topics/testing/advanced/#django.test.client.RequestFactory +[client]: https://docs.djangoproject.com/en/stable/topics/testing/tools/#the-test-client +[requestfactory]: https://docs.djangoproject.com/en/stable/topics/testing/advanced/#django.test.client.RequestFactory [configuration]: #configuration diff --git a/docs/api-guide/throttling.md b/docs/api-guide/throttling.md index da4d5f725..2a6337e81 100644 --- a/docs/api-guide/throttling.md +++ b/docs/api-guide/throttling.md @@ -193,5 +193,5 @@ The following is an example of a rate throttle, that will randomly throttle 1 in [cite]: https://dev.twitter.com/docs/error-codes-responses [permissions]: permissions.md [identifing-clients]: http://oxpedia.org/wiki/index.php?title=AppSuite:Grizzly#Multiple_Proxies_in_front_of_the_cluster -[cache-setting]: https://docs.djangoproject.com/en/dev/ref/settings/#caches -[cache-docs]: https://docs.djangoproject.com/en/dev/topics/cache/#setting-up-the-cache +[cache-setting]: https://docs.djangoproject.com/en/stable/stable/settings/#caches +[cache-docs]: https://docs.djangoproject.com/en/stable/topics/cache/#setting-up-the-cache diff --git a/docs/api-guide/validators.md b/docs/api-guide/validators.md index e041e9072..0e58c6fff 100644 --- a/docs/api-guide/validators.md +++ b/docs/api-guide/validators.md @@ -300,4 +300,4 @@ In some advanced cases you might want a validator to be passed the serializer fi # In `__call__` we can then use that information to modify the validation behavior. self.is_update = serializer_field.parent.instance is not None -[cite]: https://docs.djangoproject.com/en/dev/ref/validators/ +[cite]: https://docs.djangoproject.com/en/stable/ref/validators/ diff --git a/docs/topics/2.2-announcement.md b/docs/topics/2.2-announcement.md index e6220f427..ca4ed2efa 100644 --- a/docs/topics/2.2-announcement.md +++ b/docs/topics/2.2-announcement.md @@ -147,10 +147,10 @@ When using a serializer with a `HyperlinkedRelatedField` or `HyperlinkedIdentity From version 2.2 onwards, serializers with hyperlinked relationships *always* require a `'request'` key to be supplied in the context dictionary. The implicit behavior will continue to function, but its use will raise a `PendingDeprecationWarning`. [xordoquy]: https://github.com/xordoquy -[django-python-3]: https://docs.djangoproject.com/en/dev/faq/install/#can-i-use-django-with-python-3 -[porting-python-3]: https://docs.djangoproject.com/en/dev/topics/python3/ -[python-compat]: https://docs.djangoproject.com/en/dev/releases/1.5/#python-compatibility -[django-deprecation-policy]: https://docs.djangoproject.com/en/dev/internals/release-process/#internal-release-deprecation-policy +[django-python-3]: https://docs.djangoproject.com/en/stable/faq/install/#can-i-use-django-with-python-3 +[porting-python-3]: https://docs.djangoproject.com/en/stable/topics/python3/ +[python-compat]: https://docs.djangoproject.com/en/stable/releases/1.5/#python-compatibility +[django-deprecation-policy]: https://docs.djangoproject.com/en/stable/internals/release-process/#internal-release-deprecation-policy [credits]: http://www.django-rest-framework.org/topics/credits [mailing-list]: https://groups.google.com/forum/?fromgroups#!forum/django-rest-framework [django-rest-framework-docs]: https://github.com/marcgibbons/django-rest-framework-docs diff --git a/docs/topics/2.4-announcement.md b/docs/topics/2.4-announcement.md index 3009daa49..96f68c865 100644 --- a/docs/topics/2.4-announcement.md +++ b/docs/topics/2.4-announcement.md @@ -162,7 +162,7 @@ The next planned release will be 3.0, featuring an improved and simplified seria Once again, many thanks to all the generous [backers and sponsors][kickstarter-sponsors] who've helped make this possible! -[lts-releases]: https://docs.djangoproject.com/en/dev/internals/release-process/#long-term-support-lts-releases +[lts-releases]: https://docs.djangoproject.com/en/stable/internals/release-process/#long-term-support-lts-releases [2-4-release-notes]: release-notes#240 [view-name-and-description-settings]: ../api-guide/settings#view-names-and-descriptions [client-ip-identification]: ../api-guide/throttling#how-clients-are-identified diff --git a/docs/topics/3.0-announcement.md b/docs/topics/3.0-announcement.md index e6cbf7238..25ab4fd5b 100644 --- a/docs/topics/3.0-announcement.md +++ b/docs/topics/3.0-announcement.md @@ -870,7 +870,7 @@ The `COMPACT_JSON` setting has been added, and can be used to revert this behavi #### File fields as URLs -The `FileField` and `ImageField` classes are now represented as URLs by default. You should ensure you set Django's [standard `MEDIA_URL` setting](https://docs.djangoproject.com/en/dev/ref/settings/#std:setting-MEDIA_URL) appropriately, and ensure your application [serves the uploaded files](https://docs.djangoproject.com/en/dev/howto/static-files/#serving-uploaded-files-in-development). +The `FileField` and `ImageField` classes are now represented as URLs by default. You should ensure you set Django's [standard `MEDIA_URL` setting](https://docs.djangoproject.com/en/stable/ref/settings/#std:setting-MEDIA_URL) appropriately, and ensure your application [serves the uploaded files](https://docs.djangoproject.com/en/stable/howto/static-files/#serving-uploaded-files-in-development). You can revert this behavior, and display filenames in the representation by using the `UPLOADED_FILES_USE_URL` settings key: @@ -962,4 +962,4 @@ You can follow development on the GitHub site, where we use [milestones to indic [kickstarter]: http://kickstarter.com/projects/tomchristie/django-rest-framework-3 [sponsors]: http://www.django-rest-framework.org/topics/kickstarter-announcement/#sponsors [mixins.py]: https://github.com/tomchristie/django-rest-framework/blob/master/rest_framework/mixins.py -[django-localization]: https://docs.djangoproject.com/en/dev/topics/i18n/translation/#localization-how-to-create-language-files +[django-localization]: https://docs.djangoproject.com/en/stable/topics/i18n/translation/#localization-how-to-create-language-files diff --git a/docs/topics/ajax-csrf-cors.md b/docs/topics/ajax-csrf-cors.md index ad88810da..4960e0881 100644 --- a/docs/topics/ajax-csrf-cors.md +++ b/docs/topics/ajax-csrf-cors.md @@ -35,7 +35,7 @@ The best way to deal with CORS in REST framework is to add the required response [cite]: http://www.codinghorror.com/blog/2008/10/preventing-csrf-and-xsrf-attacks.html [csrf]: https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF) -[csrf-ajax]: https://docs.djangoproject.com/en/dev/ref/csrf/#ajax +[csrf-ajax]: https://docs.djangoproject.com/en/stable/ref/csrf/#ajax [cors]: http://www.w3.org/TR/cors/ [ottoyiu]: https://github.com/ottoyiu/ [django-cors-headers]: https://github.com/ottoyiu/django-cors-headers/ diff --git a/docs/topics/release-notes.md b/docs/topics/release-notes.md index e5683360b..5628bcaec 100644 --- a/docs/topics/release-notes.md +++ b/docs/topics/release-notes.md @@ -598,7 +598,7 @@ For older release notes, [please see the version 2.x documentation][old-release- [cite]: http://www.catb.org/~esr/writings/cathedral-bazaar/cathedral-bazaar/ar01s04.html [deprecation-policy]: #deprecation-policy -[django-deprecation-policy]: https://docs.djangoproject.com/en/dev/internals/release-process/#internal-release-deprecation-policy +[django-deprecation-policy]: https://docs.djangoproject.com/en/stable/internals/release-process/#internal-release-deprecation-policy [defusedxml-announce]: http://blog.python.org/2013/02/announcing-defusedxml-fixes-for-xml.html [743]: https://github.com/tomchristie/django-rest-framework/pull/743 [staticfiles14]: https://docs.djangoproject.com/en/1.4/howto/static-files/#with-a-template-tag From 16f5d42cbc3e966ab2d4d8dc00163942f2769e43 Mon Sep 17 00:00:00 2001 From: Carlton Gibson Date: Thu, 1 Dec 2016 10:11:25 +0100 Subject: [PATCH 21/46] Add additional link to HTML & Forms topic page (#4726) Just makes the topic page easier to find. Closes #1673 --- docs/api-guide/renderers.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/api-guide/renderers.md b/docs/api-guide/renderers.md index 648eafdde..236504850 100644 --- a/docs/api-guide/renderers.md +++ b/docs/api-guide/renderers.md @@ -123,6 +123,8 @@ You can use `TemplateHTMLRenderer` either to return regular HTML pages using RES If you're building websites that use `TemplateHTMLRenderer` along with other renderer classes, you should consider listing `TemplateHTMLRenderer` as the first class in the `renderer_classes` list, so that it will be prioritised first even for browsers that send poorly formed `ACCEPT:` headers. +See the [_HTML & Forms_ Topic Page][html-and-forms] for further examples of `TemplateHTMLRenderer` usage. + **.media_type**: `text/html` **.format**: `'.html'` From 932d04a4beb79afa7a52bfec7f66bb6ccfe53814 Mon Sep 17 00:00:00 2001 From: Asif Saifuddin Auvi Date: Thu, 1 Dec 2016 22:17:36 +0600 Subject: [PATCH 22/46] Browsable API tests asserts to pytest (#4725) --- tests/browsable_api/test_browsable_api.py | 18 ++++++++++++------ .../browsable_api/test_browsable_nested_api.py | 8 ++++---- tests/browsable_api/test_form_rendering.py | 4 ++-- 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/tests/browsable_api/test_browsable_api.py b/tests/browsable_api/test_browsable_api.py index 3d49c353b..684d7ae14 100644 --- a/tests/browsable_api/test_browsable_api.py +++ b/tests/browsable_api/test_browsable_api.py @@ -26,16 +26,19 @@ class DropdownWithAuthTests(TestCase): def test_name_shown_when_logged_in(self): self.client.login(username=self.username, password=self.password) response = self.client.get('/') - self.assertContains(response, 'john') + content = response.content.decode('utf8') + assert 'john' in content def test_logout_shown_when_logged_in(self): self.client.login(username=self.username, password=self.password) response = self.client.get('/') - self.assertContains(response, '>Log out<') + content = response.content.decode('utf8') + assert '>Log out<' in content def test_login_shown_when_logged_out(self): response = self.client.get('/') - self.assertContains(response, '>Log in<') + content = response.content.decode('utf8') + assert '>Log in<' in content @override_settings(ROOT_URLCONF='tests.browsable_api.no_auth_urls') @@ -58,13 +61,16 @@ class NoDropdownWithoutAuthTests(TestCase): def test_name_shown_when_logged_in(self): self.client.login(username=self.username, password=self.password) response = self.client.get('/') - self.assertContains(response, 'john') + content = response.content.decode('utf8') + assert 'john' in content def test_dropdown_not_shown_when_logged_in(self): self.client.login(username=self.username, password=self.password) response = self.client.get('/') - self.assertNotContains(response, '