summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--django/core/mail.py22
-rw-r--r--django/core/validators.py10
-rw-r--r--django/db/backends/postgresql/base.py5
-rw-r--r--django/db/backends/postgresql_psycopg2/base.py5
-rw-r--r--django/utils/datastructures.py2
-rw-r--r--docs/authentication.txt4
-rw-r--r--docs/email.txt6
-rw-r--r--docs/forms.txt4
-rw-r--r--extras/django_bash_completion26
-rw-r--r--tests/regressiontests/humanize/__init__.py0
-rw-r--r--tests/regressiontests/humanize/models.py0
-rw-r--r--tests/regressiontests/humanize/tests.py52
12 files changed, 116 insertions, 20 deletions
diff --git a/django/core/mail.py b/django/core/mail.py
index cc99659adb..b9966c2af0 100644
--- a/django/core/mail.py
+++ b/django/core/mail.py
@@ -3,7 +3,8 @@
from django.conf import settings
from email.MIMEText import MIMEText
from email.Header import Header
-import smtplib, rfc822
+from email.Utils import formatdate
+import smtplib
import socket
import time
import random
@@ -33,21 +34,34 @@ class SafeMIMEText(MIMEText):
val = Header(val, settings.DEFAULT_CHARSET)
MIMEText.__setitem__(self, name, val)
-def send_mail(subject, message, from_email, recipient_list, fail_silently=False, auth_user=settings.EMAIL_HOST_USER, auth_password=settings.EMAIL_HOST_PASSWORD):
+def send_mail(subject, message, from_email, recipient_list, fail_silently=False, auth_user=None, auth_password=None):
"""
Easy wrapper for sending a single message to a recipient list. All members
of the recipient list will see the other recipients in the 'To' field.
+
+ If auth_user is None, the EMAIL_HOST_USER setting is used.
+ If auth_password is None, the EMAIL_HOST_PASSWORD setting is used.
"""
+ if auth_user is None:
+ auth_user = settings.EMAIL_HOST_USER
+ if auth_password is None:
+ auth_password = settings.EMAIL_HOST_PASSWORD
return send_mass_mail([[subject, message, from_email, recipient_list]], fail_silently, auth_user, auth_password)
-def send_mass_mail(datatuple, fail_silently=False, auth_user=settings.EMAIL_HOST_USER, auth_password=settings.EMAIL_HOST_PASSWORD):
+def send_mass_mail(datatuple, fail_silently=False, auth_user=None, auth_password=None):
"""
Given a datatuple of (subject, message, from_email, recipient_list), sends
each message to each recipient list. Returns the number of e-mails sent.
If from_email is None, the DEFAULT_FROM_EMAIL setting is used.
If auth_user and auth_password are set, they're used to log in.
+ If auth_user is None, the EMAIL_HOST_USER setting is used.
+ If auth_password is None, the EMAIL_HOST_PASSWORD setting is used.
"""
+ if auth_user is None:
+ auth_user = settings.EMAIL_HOST_USER
+ if auth_password is None:
+ auth_password = settings.EMAIL_HOST_PASSWORD
try:
server = smtplib.SMTP(settings.EMAIL_HOST, settings.EMAIL_PORT)
if auth_user and auth_password:
@@ -65,7 +79,7 @@ def send_mass_mail(datatuple, fail_silently=False, auth_user=settings.EMAIL_HOST
msg['Subject'] = subject
msg['From'] = from_email
msg['To'] = ', '.join(recipient_list)
- msg['Date'] = rfc822.formatdate()
+ msg['Date'] = formatdate()
try:
random_bits = str(random.getrandbits(64))
except AttributeError: # Python 2.3 doesn't have random.getrandbits().
diff --git a/django/core/validators.py b/django/core/validators.py
index a2f3dc3bc3..ebfbd3961e 100644
--- a/django/core/validators.py
+++ b/django/core/validators.py
@@ -312,11 +312,12 @@ class RequiredIfOtherFieldGiven(RequiredIfOtherFieldsGiven):
RequiredIfOtherFieldsGiven.__init__(self, [other_field_name], error_message)
class RequiredIfOtherFieldEquals(object):
- def __init__(self, other_field, other_value, error_message=None):
+ def __init__(self, other_field, other_value, error_message=None, other_label=None):
self.other_field = other_field
self.other_value = other_value
+ other_label = other_label or other_value
self.error_message = error_message or lazy_inter(gettext_lazy("This field must be given if %(field)s is %(value)s"), {
- 'field': other_field, 'value': other_value})
+ 'field': other_field, 'value': other_label})
self.always_test = True
def __call__(self, field_data, all_data):
@@ -324,11 +325,12 @@ class RequiredIfOtherFieldEquals(object):
raise ValidationError(self.error_message)
class RequiredIfOtherFieldDoesNotEqual(object):
- def __init__(self, other_field, other_value, error_message=None):
+ def __init__(self, other_field, other_value, other_label=None, error_message=None):
self.other_field = other_field
self.other_value = other_value
+ other_label = other_label or other_value
self.error_message = error_message or lazy_inter(gettext_lazy("This field must be given if %(field)s is not %(value)s"), {
- 'field': other_field, 'value': other_value})
+ 'field': other_field, 'value': other_label})
self.always_test = True
def __call__(self, field_data, all_data):
diff --git a/django/db/backends/postgresql/base.py b/django/db/backends/postgresql/base.py
index 054f74a0d3..2342539a6f 100644
--- a/django/db/backends/postgresql/base.py
+++ b/django/db/backends/postgresql/base.py
@@ -60,7 +60,9 @@ class DatabaseWrapper(local):
def cursor(self):
from django.conf import settings
+ set_tz = False
if self.connection is None:
+ set_tz = True
if settings.DATABASE_NAME == '':
from django.core.exceptions import ImproperlyConfigured
raise ImproperlyConfigured, "You need to specify DATABASE_NAME in your Django settings file."
@@ -76,7 +78,8 @@ class DatabaseWrapper(local):
self.connection = Database.connect(conn_string, **self.options)
self.connection.set_isolation_level(1) # make transactions transparent to all cursors
cursor = self.connection.cursor()
- cursor.execute("SET TIME ZONE %s", [settings.TIME_ZONE])
+ if set_tz:
+ cursor.execute("SET TIME ZONE %s", [settings.TIME_ZONE])
cursor = UnicodeCursorWrapper(cursor, settings.DEFAULT_CHARSET)
if settings.DEBUG:
return util.CursorDebugWrapper(cursor, self)
diff --git a/django/db/backends/postgresql_psycopg2/base.py b/django/db/backends/postgresql_psycopg2/base.py
index 04322332dc..cfddb96bee 100644
--- a/django/db/backends/postgresql_psycopg2/base.py
+++ b/django/db/backends/postgresql_psycopg2/base.py
@@ -28,7 +28,9 @@ class DatabaseWrapper(local):
def cursor(self):
from django.conf import settings
+ set_tz = False
if self.connection is None:
+ set_tz = True
if settings.DATABASE_NAME == '':
from django.core.exceptions import ImproperlyConfigured
raise ImproperlyConfigured, "You need to specify DATABASE_NAME in your Django settings file."
@@ -45,7 +47,8 @@ class DatabaseWrapper(local):
self.connection.set_isolation_level(1) # make transactions transparent to all cursors
cursor = self.connection.cursor()
cursor.tzinfo_factory = None
- cursor.execute("SET TIME ZONE %s", [settings.TIME_ZONE])
+ if set_tz:
+ cursor.execute("SET TIME ZONE %s", [settings.TIME_ZONE])
if settings.DEBUG:
return util.CursorDebugWrapper(cursor, self)
return cursor
diff --git a/django/utils/datastructures.py b/django/utils/datastructures.py
index 9bec7a5df7..c20da05144 100644
--- a/django/utils/datastructures.py
+++ b/django/utils/datastructures.py
@@ -17,7 +17,7 @@ class MergeDict(object):
def __contains__(self, key):
return self.has_key(key)
- def get(self, key, default):
+ def get(self, key, default=None):
try:
return self[key]
except KeyError:
diff --git a/docs/authentication.txt b/docs/authentication.txt
index ef30879ae0..a7c28fc7a8 100644
--- a/docs/authentication.txt
+++ b/docs/authentication.txt
@@ -813,13 +813,13 @@ The ``authenticate`` method takes credentials as keyword arguments. Most of
the time, it'll just look like this::
class MyBackend:
- def authenticate(username=None, password=None):
+ def authenticate(self, username=None, password=None):
# Check the username/password and return a User.
But it could also authenticate a token, like so::
class MyBackend:
- def authenticate(token=None):
+ def authenticate(self, token=None):
# Check the token and return a User.
Either way, ``authenticate`` should check the credentials it gets, and it
diff --git a/docs/email.txt b/docs/email.txt
index 1edce88cef..1f4ce4ef42 100644
--- a/docs/email.txt
+++ b/docs/email.txt
@@ -34,8 +34,8 @@ The simplest way to send e-mail is using the function
``django.core.mail.send_mail()``. Here's its definition::
send_mail(subject, message, from_email, recipient_list,
- fail_silently=False, auth_user=EMAIL_HOST_USER,
- auth_password=EMAIL_HOST_PASSWORD)
+ fail_silently=False, auth_user=None,
+ auth_password=None)
The ``subject``, ``message``, ``from_email`` and ``recipient_list`` parameters
are required.
@@ -65,7 +65,7 @@ send_mass_mail()
Here's the definition::
send_mass_mail(datatuple, fail_silently=False,
- auth_user=EMAIL_HOST_USER, auth_password=EMAIL_HOST_PASSWORD):
+ auth_user=None, auth_password=None):
``datatuple`` is a tuple in which each element is in this format::
diff --git a/docs/forms.txt b/docs/forms.txt
index fc10e3f17a..8c40eeb997 100644
--- a/docs/forms.txt
+++ b/docs/forms.txt
@@ -608,6 +608,10 @@ fails. If no message is passed in, a default message is used.
order). If the given field does (or does not have, in the latter case) the
given value, then the current field being validated is required.
+ An optional ``other_label`` argument can be passed which, if given, is used
+ in error messages instead of the value. This allows more user friendly error
+ messages if the value itself is not descriptive enough.
+
Note that because validators are called before any ``do_html2python()``
functions, the value being compared against is a string. So
``RequiredIfOtherFieldEquals('choice', '1')`` is correct, whilst
diff --git a/extras/django_bash_completion b/extras/django_bash_completion
index 829756c371..79efc5b3b1 100644
--- a/extras/django_bash_completion
+++ b/extras/django_bash_completion
@@ -79,10 +79,28 @@ _django_completion()
adminindex|install|reset| \
sql|sqlall|sqlclear|sqlindexes| \
sqlinitialdata|sqlreset|sqlsequencereset)
- # App completion isn't yet implemented, but here's where that
- # would go.
- # COMPREPLY=( $(compgen -W "auth core" -- ${cur}) )
- COMPREPLY=()
+ # App completion
+ settings=""
+ # If settings.py in the PWD, use that
+ if [ -e settings.py ] ; then
+ settings="$PWD/settings.py"
+ else
+ # Use the ENV variable if it is set
+ if [ $DJANGO_SETTINGS_MODULE ] ; then
+ settings=$DJANGO_SETTINGS_MODULE
+ fi
+ fi
+ # Couldn't find settings so return nothing
+ if [ -z $settings ] ; then
+ COMPREPLY=()
+ # Otherwise inspect settings.py file
+ else
+ apps=`sed -n "/INSTALLED_APPS = (/,/)/p" $settings | \
+ grep -v "django.contrib" |
+ sed -n "s/^[ ]*'\(.*\.\)*\(.*\)'.*$/\2 /pg" | \
+ tr -d "\n"`
+ COMPREPLY=( $(compgen -W "${apps}" -- ${cur}) )
+ fi
return 0
;;
diff --git a/tests/regressiontests/humanize/__init__.py b/tests/regressiontests/humanize/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/regressiontests/humanize/__init__.py
diff --git a/tests/regressiontests/humanize/models.py b/tests/regressiontests/humanize/models.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/regressiontests/humanize/models.py
diff --git a/tests/regressiontests/humanize/tests.py b/tests/regressiontests/humanize/tests.py
new file mode 100644
index 0000000000..e342d7ded8
--- /dev/null
+++ b/tests/regressiontests/humanize/tests.py
@@ -0,0 +1,52 @@
+import unittest
+from django.template import Template, Context, add_to_builtins
+
+add_to_builtins('django.contrib.humanize.templatetags.humanize')
+
+class HumanizeTests(unittest.TestCase):
+
+ def humanize_tester(self, test_list, result_list, method):
+ # Using max below ensures we go through both lists
+ # However, if the lists are not equal length, this raises an exception
+ for index in xrange(len(max(test_list,result_list))):
+ test_content = test_list[index]
+ t = Template('{{ test_content|%s }}' % method)
+ rendered = t.render(Context(locals())).strip()
+ self.assertEqual(rendered, result_list[index],
+ msg="""%s test failed, produced %s,
+should've produced %s""" % (method, rendered, result_list[index]))
+
+ def test_ordinal(self):
+ test_list = ('1','2','3','4','11','12',
+ '13','101','102','103','111',
+ 'something else')
+ result_list = ('1st', '2nd', '3rd', '4th', '11th',
+ '12th', '13th', '101st', '102nd', '103rd',
+ '111th', 'something else')
+
+ self.humanize_tester(test_list, result_list, 'ordinal')
+
+ def test_intcomma(self):
+ test_list = ('100','1000','10123','10311','1000000')
+ result_list = ('100', '1,000', '10,123', '10,311', '1,000,000')
+
+ self.humanize_tester(test_list, result_list, 'intcomma')
+
+ def test_intword(self):
+ test_list = ('100', '1000000', '1200000', '1290000',
+ '1000000000','2000000000','6000000000000')
+ result_list = ('100', '1.0 million', '1.2 million', '1.3 million',
+ '1.0 billion', '2.0 billion', '6.0 trillion')
+
+ self.humanize_tester(test_list, result_list, 'intword')
+
+ def test_apnumber(self):
+ test_list = [str(x) for x in xrange(1,11)]
+ result_list = ('one', 'two', 'three', 'four', 'five', 'six',
+ 'seven', 'eight', 'nine', '10')
+
+ self.humanize_tester(test_list, result_list, 'apnumber')
+
+if __name__ == '__main__':
+ unittest.main()
+