From cd1ca26702005c51dbcbeea593650b939cb2d3eb Mon Sep 17 00:00:00 2001
From: Brendon Crawford
Date: Wed, 3 Apr 2013 19:42:31 -0700
Subject: [PATCH 001/105] Adds generators support for email backends that do
not support it.
---
django/core/mail/backends/console.py | 4 +++-
django/core/mail/backends/dummy.py | 2 +-
django/core/mail/backends/locmem.py | 4 +++-
3 files changed, 7 insertions(+), 3 deletions(-)
diff --git a/django/core/mail/backends/console.py b/django/core/mail/backends/console.py
index ea0cb5d9ad..389e06b37f 100644
--- a/django/core/mail/backends/console.py
+++ b/django/core/mail/backends/console.py
@@ -16,6 +16,7 @@ class EmailBackend(BaseEmailBackend):
"""Write all messages to the stream in a thread-safe way."""
if not email_messages:
return
+ msg_count = 0
with self._lock:
try:
stream_created = self.open()
@@ -24,9 +25,10 @@ class EmailBackend(BaseEmailBackend):
self.stream.write('-' * 79)
self.stream.write('\n')
self.stream.flush() # flush after each message
+ msg_count += 1
if stream_created:
self.close()
except:
if not self.fail_silently:
raise
- return len(email_messages)
+ return msg_count
diff --git a/django/core/mail/backends/dummy.py b/django/core/mail/backends/dummy.py
index 273aa0d88e..7ae4878f13 100644
--- a/django/core/mail/backends/dummy.py
+++ b/django/core/mail/backends/dummy.py
@@ -6,4 +6,4 @@ from django.core.mail.backends.base import BaseEmailBackend
class EmailBackend(BaseEmailBackend):
def send_messages(self, email_messages):
- return len(email_messages)
+ return len(list(email_messages))
diff --git a/django/core/mail/backends/locmem.py b/django/core/mail/backends/locmem.py
index 6826d09ee5..8e893af358 100644
--- a/django/core/mail/backends/locmem.py
+++ b/django/core/mail/backends/locmem.py
@@ -20,7 +20,9 @@ class EmailBackend(BaseEmailBackend):
def send_messages(self, messages):
"""Redirect messages to the dummy outbox"""
+ msg_count = 0
for message in messages: # .message() triggers header validation
message.message()
+ msg_count += 1
mail.outbox.extend(messages)
- return len(messages)
+ return msg_count
From 8160e6341d160607f7898ea4a9c389e84d547763 Mon Sep 17 00:00:00 2001
From: Ben Firshman
Date: Tue, 2 Jul 2013 17:52:54 +0100
Subject: [PATCH 002/105] Fix "semicolon" in docs
---
docs/topics/forms/index.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/topics/forms/index.txt b/docs/topics/forms/index.txt
index 7d5a0ed411..66461c80db 100644
--- a/docs/topics/forms/index.txt
+++ b/docs/topics/forms/index.txt
@@ -321,7 +321,7 @@ attributes, which can be useful in your templates:
.. versionchanged:: 1.6
This includes the form's :attr:`~django.forms.Form.label_suffix`. For
- example, the default ``label_suffix`` is a semicolon::
+ example, the default ``label_suffix`` is a colon::
From 3632d289dedc2e83cde1976e5a4cd00b08c799ee Mon Sep 17 00:00:00 2001
From: Tim Graham
Date: Tue, 2 Jul 2013 14:14:56 -0400
Subject: [PATCH 003/105] A couple more semicolon -> colon fixes; refs #18134.
---
docs/ref/forms/api.txt | 2 +-
docs/releases/1.6.txt | 8 ++++----
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/docs/ref/forms/api.txt b/docs/ref/forms/api.txt
index 3c17827800..aa19719a68 100644
--- a/docs/ref/forms/api.txt
+++ b/docs/ref/forms/api.txt
@@ -661,7 +661,7 @@ additional attributes for the ``
{% endif %}
- {% if inline_admin_form.has_auto_field %}{{ inline_admin_form.pk_field.field }}{% endif %}
+ {% if inline_admin_form.needs_explicit_pk_field %}{{ inline_admin_form.pk_field.field }}{% endif %}
{{ inline_admin_form.fk_field.field }}
{% spaceless %}
{% for fieldset in inline_admin_form %}
diff --git a/tests/admin_inlines/admin.py b/tests/admin_inlines/admin.py
index 2f88248ca4..62f9e04e5b 100644
--- a/tests/admin_inlines/admin.py
+++ b/tests/admin_inlines/admin.py
@@ -12,8 +12,26 @@ class BookInline(admin.TabularInline):
model = Author.books.through
+class NonAutoPKBookTabularInline(admin.TabularInline):
+ model = NonAutoPKBook
+
+
+class NonAutoPKBookStackedInline(admin.StackedInline):
+ model = NonAutoPKBook
+
+
+class EditablePKBookTabularInline(admin.TabularInline):
+ model = EditablePKBook
+
+
+class EditablePKBookStackedInline(admin.StackedInline):
+ model = EditablePKBook
+
+
class AuthorAdmin(admin.ModelAdmin):
- inlines = [BookInline]
+ inlines = [BookInline,
+ NonAutoPKBookTabularInline, NonAutoPKBookStackedInline,
+ EditablePKBookTabularInline, EditablePKBookStackedInline]
class InnerInline(admin.StackedInline):
diff --git a/tests/admin_inlines/models.py b/tests/admin_inlines/models.py
index d4ba0ab6bc..dde5cf79e3 100644
--- a/tests/admin_inlines/models.py
+++ b/tests/admin_inlines/models.py
@@ -3,6 +3,7 @@ Testing of admin inline formsets.
"""
from __future__ import unicode_literals
+import random
from django.db import models
from django.contrib.contenttypes.models import ContentType
@@ -48,6 +49,25 @@ class Author(models.Model):
books = models.ManyToManyField(Book)
+class NonAutoPKBook(models.Model):
+ rand_pk = models.IntegerField(primary_key=True, editable=False)
+ author = models.ForeignKey(Author)
+ title = models.CharField(max_length=50)
+
+ def save(self, *args, **kwargs):
+ while not self.rand_pk:
+ test_pk = random.randint(1, 99999)
+ if not NonAutoPKBook.objects.filter(rand_pk=test_pk).exists():
+ self.rand_pk = test_pk
+ super(NonAutoPKBook, self).save(*args, **kwargs)
+
+
+class EditablePKBook(models.Model):
+ manual_pk = models.IntegerField(primary_key=True)
+ author = models.ForeignKey(Author)
+ title = models.CharField(max_length=50)
+
+
class Holder(models.Model):
dummy = models.IntegerField()
diff --git a/tests/admin_inlines/tests.py b/tests/admin_inlines/tests.py
index 41dc0e32de..465b224d4f 100644
--- a/tests/admin_inlines/tests.py
+++ b/tests/admin_inlines/tests.py
@@ -211,6 +211,24 @@ class TestInline(TestCase):
self.assertContains(response, max_forms_input % 2)
self.assertContains(response, total_forms_hidden)
+ def test_inline_nonauto_noneditable_pk(self):
+ response = self.client.get('/admin/admin_inlines/author/add/')
+ self.assertContains(response,
+ '',
+ html=True)
+ self.assertContains(response,
+ '',
+ html=True)
+
+ def test_inline_editable_pk(self):
+ response = self.client.get('/admin/admin_inlines/author/add/')
+ self.assertContains(response,
+ '',
+ html=True, count=1)
+ self.assertContains(response,
+ '',
+ html=True, count=1)
+
@override_settings(PASSWORD_HASHERS=('django.contrib.auth.hashers.SHA1PasswordHasher',))
class TestInlineMedia(TestCase):
From 11b7b9ad0040cbe78d17514373475ee41179d3fa Mon Sep 17 00:00:00 2001
From: Claude Paroz
Date: Sat, 20 Jul 2013 18:00:23 +0200
Subject: [PATCH 101/105] Fixed an email validation regression
Thanks Vincent Wagelaar for the report.
---
django/core/validators.py | 2 +-
tests/validators/tests.py | 1 +
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/django/core/validators.py b/django/core/validators.py
index 200d28fe02..aa417ed099 100644
--- a/django/core/validators.py
+++ b/django/core/validators.py
@@ -87,7 +87,7 @@ class EmailValidator(object):
r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-\011\013\014\016-\177])*"$)', # quoted-string
re.IGNORECASE)
domain_regex = re.compile(
- r'(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}\.?$)' # domain
+ r'(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+(?:[A-Z]{2,6}|[A-Z0-9-]{2,})\.?$' # domain
# literal form, ipv4 address (SMTP 4.1.3)
r'|^\[(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}\]$',
re.IGNORECASE)
diff --git a/tests/validators/tests.py b/tests/validators/tests.py
index ec3e2dc8c1..9be49d7726 100644
--- a/tests/validators/tests.py
+++ b/tests/validators/tests.py
@@ -46,6 +46,7 @@ TEST_DATA = (
(validate_email, 'example@-invalid.com', ValidationError),
(validate_email, 'example@inv-.alid-.com', ValidationError),
(validate_email, 'example@inv-.-alid.com', ValidationError),
+ (validate_email, 'test@example.com\n\n tags required with Google Maps JavaScript."
- return format_html('%s\n ', self.api_script, mark_safe(self.js))
+ return format_html('{0}\n ',
+ self.api_script, mark_safe(self.js))
@property
def style(self):
diff --git a/django/contrib/gis/tests/geoadmin/tests.py b/django/contrib/gis/tests/geoadmin/tests.py
index c34964a2da..df4158bb31 100644
--- a/django/contrib/gis/tests/geoadmin/tests.py
+++ b/django/contrib/gis/tests/geoadmin/tests.py
@@ -2,9 +2,10 @@ from __future__ import absolute_import
from unittest import skipUnless
-from django.test import TestCase
from django.contrib.gis.geos import HAS_GEOS
from django.contrib.gis.tests.utils import HAS_SPATIAL_DB
+from django.test import TestCase
+from django.test.utils import override_settings
if HAS_GEOS and HAS_SPATIAL_DB:
from django.contrib.gis import admin
@@ -12,6 +13,8 @@ if HAS_GEOS and HAS_SPATIAL_DB:
from .models import City
+GOOGLE_MAPS_API_KEY = 'XXXX'
+
@skipUnless(HAS_GEOS and HAS_SPATIAL_DB, "Geos and spatial db are required.")
class GeoAdminTest(TestCase):
@@ -39,7 +42,9 @@ class GeoAdminTest(TestCase):
result)
def test_olwidget_has_changed(self):
- """ Check that changes are accurately noticed by OpenLayersWidget. """
+ """
+ Check that changes are accurately noticed by OpenLayersWidget.
+ """
geoadmin = admin.site._registry[City]
form = geoadmin.get_changelist_form(None)()
has_changed = form.fields['point']._has_changed
@@ -55,3 +60,15 @@ class GeoAdminTest(TestCase):
self.assertFalse(has_changed(initial, data_same))
self.assertFalse(has_changed(initial, data_almost_same))
self.assertTrue(has_changed(initial, data_changed))
+
+ @override_settings(GOOGLE_MAPS_API_KEY=GOOGLE_MAPS_API_KEY)
+ def test_google_map_scripts(self):
+ """
+ Testing GoogleMap.scripts() output. See #20773.
+ """
+ from django.contrib.gis.maps.google.gmap import GoogleMap
+
+ google_map = GoogleMap()
+ scripts = google_map.scripts
+ self.assertIn(GOOGLE_MAPS_API_KEY, scripts)
+ self.assertIn("new GMap2", scripts)
From 8e9865241600a2ee0541b30902b4b0c828d2e60b Mon Sep 17 00:00:00 2001
From: Tyler Garner
Date: Mon, 22 Jul 2013 10:32:09 -0400
Subject: [PATCH 105/105] Fixed small grammatical error in docstring.
---
django/contrib/gis/db/models/query.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/django/contrib/gis/db/models/query.py b/django/contrib/gis/db/models/query.py
index c1e360de27..be955524af 100644
--- a/django/contrib/gis/db/models/query.py
+++ b/django/contrib/gis/db/models/query.py
@@ -136,7 +136,7 @@ class GeoQuerySet(QuerySet):
Returns a GeoJSON representation of the geomtry field in a `geojson`
attribute on each element of the GeoQuerySet.
- The `crs` and `bbox` keywords may be set to True if the users wants
+ The `crs` and `bbox` keywords may be set to True if the user wants
the coordinate reference system and the bounding box to be included
in the GeoJSON representation of the geometry.
"""