summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrian Rosner <brosner@gmail.com>2008-07-14 05:04:57 +0000
committerBrian Rosner <brosner@gmail.com>2008-07-14 05:04:57 +0000
commit2624f4ea563e8139c7f19a20d9b723d39b1e6ac1 (patch)
tree975193cb2d38ec3369e2688818d41e07660fb40a
parentf3cda0b77afb2a6e22520b4c9f1c6d111add6ac9 (diff)
newforms-admin: Merged from trunk up to [7917].
git-svn-id: http://code.djangoproject.com/svn/django/branches/newforms-admin@7922 bcc190cf-cafb-0310-a4f2-bffc1f526a37
-rw-r--r--AUTHORS2
-rw-r--r--django/conf/locale/it/LC_MESSAGES/django.mobin66449 -> 66524 bytes
-rw-r--r--django/conf/locale/it/LC_MESSAGES/django.po267
-rw-r--r--django/core/files/uploadedfile.py2
-rw-r--r--django/core/management/__init__.py29
-rw-r--r--django/core/management/commands/syncdb.py14
-rw-r--r--django/db/models/fields/__init__.py15
-rw-r--r--django/db/models/query.py13
-rw-r--r--django/db/models/sql/query.py9
-rw-r--r--django/http/multipartparser.py55
-rw-r--r--django/newforms/fields.py2
-rw-r--r--django/utils/itercompat.py5
-rw-r--r--docs/contributing.txt5
-rw-r--r--docs/db-api.txt12
-rw-r--r--docs/testing.txt8
-rw-r--r--docs/tutorial01.txt5
-rw-r--r--tests/modeltests/basic/models.py8
-rw-r--r--tests/modeltests/model_forms/models.py2
-rw-r--r--tests/modeltests/or_lookups/models.py5
-rw-r--r--tests/modeltests/test_client/models.py8
-rw-r--r--tests/modeltests/test_client/urls.py1
-rw-r--r--tests/modeltests/test_client/views.py6
-rw-r--r--tests/regressiontests/admin_scripts/management/commands/app_command.py5
-rw-r--r--tests/regressiontests/admin_scripts/management/commands/base_command.py11
-rw-r--r--tests/regressiontests/admin_scripts/management/commands/label_command.py5
-rw-r--r--tests/regressiontests/admin_scripts/management/commands/noargs_command.py5
-rw-r--r--tests/regressiontests/admin_scripts/tests.py185
-rw-r--r--tests/regressiontests/defaultfilters/tests.py6
-rw-r--r--tests/regressiontests/file_uploads/tests.py2
-rw-r--r--tests/regressiontests/model_inheritance_regress/models.py6
-rw-r--r--tests/regressiontests/queries/models.py15
-rw-r--r--tests/regressiontests/utils/datastructures.py13
-rw-r--r--tests/regressiontests/utils/itercompat.py15
-rw-r--r--tests/regressiontests/utils/tests.py2
34 files changed, 503 insertions, 240 deletions
diff --git a/AUTHORS b/AUTHORS
index 6f825aea9e..a0f25e1c12 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -52,7 +52,7 @@ answer newbie questions, and generally made Django that much better:
andy@jadedplanet.net
Fabrice Aneche <akh@nobugware.com>
ant9000@netwise.it
- Florian Apolloner
+ Florian Apolloner <florian@apolloner.eu>
arien <regexbot@gmail.com>
David Ascher <http://ascher.ca/>
Jökull Sólberg Auðunsson <jokullsolberg@gmail.com>
diff --git a/django/conf/locale/it/LC_MESSAGES/django.mo b/django/conf/locale/it/LC_MESSAGES/django.mo
index 683680bb7d..e96764a0a8 100644
--- a/django/conf/locale/it/LC_MESSAGES/django.mo
+++ b/django/conf/locale/it/LC_MESSAGES/django.mo
Binary files differ
diff --git a/django/conf/locale/it/LC_MESSAGES/django.po b/django/conf/locale/it/LC_MESSAGES/django.po
index a8f02e4967..4e87ad549d 100644
--- a/django/conf/locale/it/LC_MESSAGES/django.po
+++ b/django/conf/locale/it/LC_MESSAGES/django.po
@@ -6,8 +6,8 @@ msgid ""
msgstr ""
"Project-Id-Version: Django vSVN\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2008-06-02 18:40+0200\n"
-"PO-Revision-Date: 2008-05-18 19:13+0200\n"
+"POT-Creation-Date: 2008-07-12 20:30+0200\n"
+"PO-Revision-Date: 2008-07-12 20:45+0200\n"
"Last-Translator: Nicola Larosa <nico@tekNico.net>\n"
"Language-Team: Italiano\n"
"MIME-Version: 1.0\n"
@@ -16,191 +16,199 @@ msgstr ""
"X-Generator: KBabel 1.11.4\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-#: conf/global_settings.py:43
+#: conf/global_settings.py:44
msgid "Arabic"
msgstr "Arabo"
-#: conf/global_settings.py:44
+#: conf/global_settings.py:45
msgid "Bengali"
msgstr "Bengali"
-#: conf/global_settings.py:45
+#: conf/global_settings.py:46
msgid "Bulgarian"
msgstr "Bulgaro"
-#: conf/global_settings.py:46
+#: conf/global_settings.py:47
msgid "Catalan"
msgstr "Catalano"
-#: conf/global_settings.py:47
+#: conf/global_settings.py:48
msgid "Czech"
msgstr "Ceco"
-#: conf/global_settings.py:48
+#: conf/global_settings.py:49
msgid "Welsh"
msgstr "Gallese"
-#: conf/global_settings.py:49
+#: conf/global_settings.py:50
msgid "Danish"
msgstr "Danese"
-#: conf/global_settings.py:50
+#: conf/global_settings.py:51
msgid "German"
msgstr "Tedesco"
-#: conf/global_settings.py:51
+#: conf/global_settings.py:52
msgid "Greek"
msgstr "Greco"
-#: conf/global_settings.py:52
+#: conf/global_settings.py:53
msgid "English"
msgstr "Inglese"
-#: conf/global_settings.py:53
+#: conf/global_settings.py:54
msgid "Spanish"
msgstr "Spagnolo"
-#: conf/global_settings.py:54
+#: conf/global_settings.py:55
+msgid "Estonian"
+msgstr "Estone"
+
+#: conf/global_settings.py:56
msgid "Argentinean Spanish"
msgstr "Spagnolo argentino"
-#: conf/global_settings.py:55
+#: conf/global_settings.py:57
msgid "Basque"
msgstr "Basco"
-#: conf/global_settings.py:56
+#: conf/global_settings.py:58
msgid "Persian"
msgstr "Persiano"
-#: conf/global_settings.py:57
+#: conf/global_settings.py:59
msgid "Finnish"
msgstr "Finlandese"
-#: conf/global_settings.py:58
+#: conf/global_settings.py:60
msgid "French"
msgstr "Francese"
-#: conf/global_settings.py:59
+#: conf/global_settings.py:61
msgid "Irish"
msgstr "Irlandese"
-#: conf/global_settings.py:60
+#: conf/global_settings.py:62
msgid "Galician"
msgstr "Galiziano"
-#: conf/global_settings.py:61
+#: conf/global_settings.py:63
msgid "Hungarian"
msgstr "Ungherese"
-#: conf/global_settings.py:62
+#: conf/global_settings.py:64
msgid "Hebrew"
msgstr "Ebraico"
-#: conf/global_settings.py:63
+#: conf/global_settings.py:65
msgid "Croatian"
msgstr "Croato"
-#: conf/global_settings.py:64
+#: conf/global_settings.py:66
msgid "Icelandic"
msgstr "Islandese"
-#: conf/global_settings.py:65
+#: conf/global_settings.py:67
msgid "Italian"
msgstr "Italiano"
-#: conf/global_settings.py:66
+#: conf/global_settings.py:68
msgid "Japanese"
msgstr "Giapponese"
-#: conf/global_settings.py:67
+#: conf/global_settings.py:69
msgid "Georgian"
msgstr "Georgiano"
-#: conf/global_settings.py:68
+#: conf/global_settings.py:70
msgid "Korean"
msgstr "Coreano"
-#: conf/global_settings.py:69
+#: conf/global_settings.py:71
msgid "Khmer"
msgstr "Khmer"
-#: conf/global_settings.py:70
+#: conf/global_settings.py:72
msgid "Kannada"
msgstr "Kannada"
-#: conf/global_settings.py:71
+#: conf/global_settings.py:73
msgid "Latvian"
msgstr "Lettone"
-#: conf/global_settings.py:72
+#: conf/global_settings.py:74
+msgid "Lithuanian"
+msgstr "Lituano"
+
+#: conf/global_settings.py:75
msgid "Macedonian"
msgstr "Macedone"
-#: conf/global_settings.py:73
+#: conf/global_settings.py:76
msgid "Dutch"
msgstr "Olandese"
-#: conf/global_settings.py:74
+#: conf/global_settings.py:77
msgid "Norwegian"
msgstr "Norvegese"
-#: conf/global_settings.py:75
+#: conf/global_settings.py:78
msgid "Polish"
msgstr "Polacco"
-#: conf/global_settings.py:76
+#: conf/global_settings.py:79
msgid "Portugese"
msgstr "Portoghese"
-#: conf/global_settings.py:77
+#: conf/global_settings.py:80
msgid "Brazilian Portuguese"
msgstr "Brasiliano Portoghese"
-#: conf/global_settings.py:78
+#: conf/global_settings.py:81
msgid "Romanian"
msgstr "Rumeno"
-#: conf/global_settings.py:79
+#: conf/global_settings.py:82
msgid "Russian"
msgstr "Russo"
-#: conf/global_settings.py:80
+#: conf/global_settings.py:83
msgid "Slovak"
msgstr "Slovacco"
-#: conf/global_settings.py:81
+#: conf/global_settings.py:84
msgid "Slovenian"
msgstr "Sloveno"
-#: conf/global_settings.py:82
+#: conf/global_settings.py:85
msgid "Serbian"
msgstr "Serbo"
-#: conf/global_settings.py:83
+#: conf/global_settings.py:86
msgid "Swedish"
msgstr "Svedese"
-#: conf/global_settings.py:84
+#: conf/global_settings.py:87
msgid "Tamil"
msgstr "Tamil"
-#: conf/global_settings.py:85
+#: conf/global_settings.py:88
msgid "Telugu"
msgstr "Telugu"
-#: conf/global_settings.py:86
+#: conf/global_settings.py:89
msgid "Turkish"
msgstr "Turco"
-#: conf/global_settings.py:87
+#: conf/global_settings.py:90
msgid "Ukrainian"
msgstr "Ucraino"
-#: conf/global_settings.py:88
+#: conf/global_settings.py:91
msgid "Simplified Chinese"
msgstr "Cinese semplificato"
-#: conf/global_settings.py:89
+#: conf/global_settings.py:92
msgid "Traditional Chinese"
msgstr "Cinese tradizionale"
@@ -1133,15 +1141,15 @@ msgstr "permessi"
msgid "group"
msgstr "gruppo"
-#: contrib/auth/models.py:98 contrib/auth/models.py:141
+#: contrib/auth/models.py:98 contrib/auth/models.py:148
msgid "groups"
msgstr "gruppi"
-#: contrib/auth/models.py:131
+#: contrib/auth/models.py:138
msgid "username"
msgstr "nome utente"
-#: contrib/auth/models.py:131
+#: contrib/auth/models.py:138
msgid ""
"Required. 30 characters or fewer. Alphanumeric characters only (letters, "
"digits and underscores)."
@@ -1149,23 +1157,23 @@ msgstr ""
"Obbligatorio. 30 caratteri o meno. Solo caratteri alfanumerici (lettere, "
"cifre e sottolineati)."
-#: contrib/auth/models.py:132
+#: contrib/auth/models.py:139
msgid "first name"
msgstr "nome"
-#: contrib/auth/models.py:133
+#: contrib/auth/models.py:140
msgid "last name"
msgstr "cognome"
-#: contrib/auth/models.py:134
+#: contrib/auth/models.py:141
msgid "e-mail address"
msgstr "indirizzo e-mail"
-#: contrib/auth/models.py:135
+#: contrib/auth/models.py:142
msgid "password"
msgstr "password"
-#: contrib/auth/models.py:135
+#: contrib/auth/models.py:142
msgid ""
"Use '[algo]$[salt]$[hexdigest]' or use the <a href=\"password/\">change "
"password form</a>."
@@ -1173,19 +1181,19 @@ msgstr ""
"Usare '[algo]$[salt]$[hexdigest]' oppure la <a href=\"password/\">maschera "
"di cambio password</a>."
-#: contrib/auth/models.py:136
+#: contrib/auth/models.py:143
msgid "staff status"
msgstr "privilegi di staff"
-#: contrib/auth/models.py:136
+#: contrib/auth/models.py:143
msgid "Designates whether the user can log into this admin site."
msgstr "Indica se l'utente può accedere a questo sito di amministrazione."
-#: contrib/auth/models.py:137
+#: contrib/auth/models.py:144
msgid "active"
msgstr "attivo"
-#: contrib/auth/models.py:137
+#: contrib/auth/models.py:144
msgid ""
"Designates whether this user should be treated as active. Unselect this "
"instead of deleting accounts."
@@ -1193,11 +1201,11 @@ msgstr ""
"Indica se l'utente debba essere considerato attivo. Deselezionare "
"qui, piuttosto che cancellare gli account."
-#: contrib/auth/models.py:138
+#: contrib/auth/models.py:145
msgid "superuser status"
msgstr "privilegi di superutente"
-#: contrib/auth/models.py:138
+#: contrib/auth/models.py:145
msgid ""
"Designates that this user has all permissions without explicitly assigning "
"them."
@@ -1205,15 +1213,15 @@ msgstr ""
"Indica che l'utente ha tutti i privilegi, senza che siano stati assegnati "
"esplicitamente."
-#: contrib/auth/models.py:139
+#: contrib/auth/models.py:146
msgid "last login"
msgstr "ultimo accesso"
-#: contrib/auth/models.py:140
+#: contrib/auth/models.py:147
msgid "date joined"
msgstr "iscritto in data"
-#: contrib/auth/models.py:142
+#: contrib/auth/models.py:149
msgid ""
"In addition to the permissions manually assigned, this user will also get "
"all permissions granted to each group he/she is in."
@@ -1221,39 +1229,39 @@ msgstr ""
"In aggiunta ai privilegi assegnati manualmente, l'utente riceverà anche "
"tutti i privilegi assegnati ad ogni gruppo cui appartiene."
-#: contrib/auth/models.py:143
+#: contrib/auth/models.py:150
msgid "user permissions"
msgstr "privilegi utente"
-#: contrib/auth/models.py:147
+#: contrib/auth/models.py:154
msgid "user"
msgstr "utente"
-#: contrib/auth/models.py:148
+#: contrib/auth/models.py:155
msgid "users"
msgstr "utenti"
-#: contrib/auth/models.py:154
+#: contrib/auth/models.py:160
msgid "Personal info"
msgstr "Informazioni personali"
-#: contrib/auth/models.py:155
+#: contrib/auth/models.py:161
msgid "Permissions"
msgstr "Permessi"
-#: contrib/auth/models.py:156
+#: contrib/auth/models.py:162
msgid "Important dates"
msgstr "Date importanti"
-#: contrib/auth/models.py:157
+#: contrib/auth/models.py:163
msgid "Groups"
msgstr "Gruppi"
-#: contrib/auth/models.py:316
+#: contrib/auth/models.py:323
msgid "message"
msgstr "messaggio"
-#: contrib/auth/views.py:47
+#: contrib/auth/views.py:49
msgid "Logged out"
msgstr "Accesso annullato"
@@ -3523,23 +3531,23 @@ msgstr "redirezione"
msgid "redirects"
msgstr "redirezioni"
-#: contrib/sessions/models.py:41
+#: contrib/sessions/models.py:45
msgid "session key"
msgstr "chiave di sessione"
-#: contrib/sessions/models.py:42
+#: contrib/sessions/models.py:47
msgid "session data"
msgstr "dati di sessione"
-#: contrib/sessions/models.py:43
+#: contrib/sessions/models.py:48
msgid "expire date"
msgstr "data di scadenza"
-#: contrib/sessions/models.py:48
+#: contrib/sessions/models.py:53
msgid "session"
msgstr "sessione"
-#: contrib/sessions/models.py:49
+#: contrib/sessions/models.py:54
msgid "sessions"
msgstr "sessioni"
@@ -3607,7 +3615,7 @@ msgstr "Sono ammessi soltanto caratteri numerici."
msgid "This value can't be comprised solely of digits."
msgstr "Questo valore non può essere composto solo da cifre."
-#: core/validators.py:128 newforms/fields.py:152
+#: core/validators.py:128 newforms/fields.py:157
msgid "Enter a whole number."
msgstr "Inserire un numero intero."
@@ -3624,7 +3632,7 @@ msgstr "L'anno deve essere 1900 o successivo."
msgid "Invalid date: %s"
msgstr "Data non valida: %s"
-#: core/validators.py:156 db/models/fields/__init__.py:548
+#: core/validators.py:156 db/models/fields/__init__.py:554
msgid "Enter a valid date in YYYY-MM-DD format."
msgstr "Inserire una data valida in formato AAAA-MM-GG."
@@ -3632,20 +3640,19 @@ msgstr "Inserire una data valida in formato AAAA-MM-GG."
msgid "Enter a valid time in HH:MM format."
msgstr "Inserire un ora valida in formato OO:MM."
-#: core/validators.py:165 db/models/fields/__init__.py:625
+#: core/validators.py:165 db/models/fields/__init__.py:631
msgid "Enter a valid date/time in YYYY-MM-DD HH:MM format."
msgstr "Inserire una data/ora valida in formato AAAA-MM-GG OO:MM."
-#: core/validators.py:170 newforms/fields.py:403
+#: core/validators.py:170 newforms/fields.py:408
msgid "Enter a valid e-mail address."
msgstr "Inserire un indirizzo e-mail valido."
-#: core/validators.py:182 core/validators.py:474 newforms/fields.py:433
-#: oldforms/__init__.py:687
+#: core/validators.py:182 core/validators.py:474 newforms/fields.py:426
msgid "No file was submitted. Check the encoding type on the form."
msgstr "Non è stato inviato alcun file. Verificare il tipo di codifica della form."
-#: core/validators.py:193 newforms/fields.py:459
+#: core/validators.py:193 newforms/fields.py:468
msgid ""
"Upload a valid image. The file you uploaded was either not an image or a "
"corrupted image."
@@ -3876,38 +3883,38 @@ msgstr ""
msgid "%(object)s with this %(type)s already exists for the given %(field)s."
msgstr "Un %(object)s·con questo·%(type)s·esiste già per questo·%(field)s."
-#: db/models/fields/__init__.py:54
+#: db/models/fields/__init__.py:52
#, python-format
msgid "%(optname)s with this %(fieldname)s already exists."
msgstr "Un %(optname)s·con questo·%(fieldname)s·esiste già."
-#: db/models/fields/__init__.py:179 db/models/fields/__init__.py:348
-#: db/models/fields/__init__.py:780 db/models/fields/__init__.py:791
-#: newforms/fields.py:46 oldforms/__init__.py:374
+#: db/models/fields/__init__.py:182 db/models/fields/__init__.py:354
+#: db/models/fields/__init__.py:788 db/models/fields/__init__.py:799
+#: newforms/fields.py:51 oldforms/__init__.py:374
msgid "This field is required."
msgstr "Questo campo è obbligatorio."
-#: db/models/fields/__init__.py:448
+#: db/models/fields/__init__.py:454
msgid "This value must be an integer."
msgstr "Questo valore deve essere un intero."
-#: db/models/fields/__init__.py:487
+#: db/models/fields/__init__.py:493
msgid "This value must be either True or False."
msgstr "Questo valore deve essere True o False."
-#: db/models/fields/__init__.py:511
+#: db/models/fields/__init__.py:517
msgid "This field cannot be null."
msgstr "Questo campo non può essere nullo."
-#: db/models/fields/__init__.py:689
+#: db/models/fields/__init__.py:695
msgid "This value must be a decimal number."
msgstr "Questo valore deve essere un numero decimale."
-#: db/models/fields/__init__.py:800
+#: db/models/fields/__init__.py:808
msgid "Enter a valid filename."
msgstr "Inserire un nome di file valido."
-#: db/models/fields/__init__.py:981
+#: db/models/fields/__init__.py:999
msgid "This value must be either None, True or False."
msgstr "Questo valore deve essere None, True o False."
@@ -3916,118 +3923,118 @@ msgstr "Questo valore deve essere None, True o False."
msgid "Please enter a valid %s."
msgstr "Inserire un %s valido."
-#: db/models/fields/related.py:721
+#: db/models/fields/related.py:756
msgid "Separate multiple IDs with commas."
msgstr "Separare gli ID multipli con virgole."
-#: db/models/fields/related.py:723
+#: db/models/fields/related.py:758
msgid "Hold down \"Control\", or \"Command\" on a Mac, to select more than one."
msgstr ""
"Tenere premuto \"Control\", o \"Command\" su Mac, per selezionarne più di "
"uno."
-#: db/models/fields/related.py:770
+#: db/models/fields/related.py:805
#, python-format
msgid "Please enter valid %(self)s IDs. The value %(value)r is invalid."
msgid_plural "Please enter valid %(self)s IDs. The values %(value)r are invalid."
msgstr[0] "Inserire un ID valido per %(self)s. Il valore %(value)r non è valido."
msgstr[1] "Inserire ID validi per %(self)s. I valori %(value)r non sono validi."
-#: newforms/fields.py:47
+#: newforms/fields.py:52
msgid "Enter a valid value."
msgstr "Inserire un valore valido."
-#: newforms/fields.py:124
+#: newforms/fields.py:129
#, python-format
msgid "Ensure this value has at most %(max)d characters (it has %(length)d)."
msgstr ""
"Assicurarsi che questo valore non contenga più di %(max)d caratteri (ne ha %"
"(length)d)."
-#: newforms/fields.py:125
+#: newforms/fields.py:130
#, python-format
msgid "Ensure this value has at least %(min)d characters (it has %(length)d)."
msgstr ""
"Assicurarsi che questo valore contenga almeno %(min)d caratteri (ne ha %"
"(length)d)."
-#: newforms/fields.py:153 newforms/fields.py:182 newforms/fields.py:211
+#: newforms/fields.py:158 newforms/fields.py:187 newforms/fields.py:216
#, python-format
msgid "Ensure this value is less than or equal to %s."
msgstr "Assicurarsi che questo valore sia minore o uguale a %s."
-#: newforms/fields.py:154 newforms/fields.py:183 newforms/fields.py:212
+#: newforms/fields.py:159 newforms/fields.py:188 newforms/fields.py:217
#, python-format
msgid "Ensure this value is greater than or equal to %s."
msgstr "Assicurarsi che questo valore sia maggiore o uguale a %s."
-#: newforms/fields.py:181 newforms/fields.py:210
+#: newforms/fields.py:186 newforms/fields.py:215
msgid "Enter a number."
msgstr "Inserire un numero."
-#: newforms/fields.py:213
+#: newforms/fields.py:218
#, python-format
msgid "Ensure that there are no more than %s digits in total."
msgstr "Assicurarsi che non vi siano più di %s cifre in totale."
-#: newforms/fields.py:214
+#: newforms/fields.py:219
#, python-format
msgid "Ensure that there are no more than %s decimal places."
msgstr "Assicurarsi che non vi siano più di %s cifre decimali."
-#: newforms/fields.py:215
+#: newforms/fields.py:220
#, python-format
msgid "Ensure that there are no more than %s digits before the decimal point."
msgstr "Assicurarsi che non vi siano più di %s cifre prima della virgola."
-#: newforms/fields.py:263 newforms/fields.py:751
+#: newforms/fields.py:268 newforms/fields.py:779
msgid "Enter a valid date."
msgstr "Inserire una data valida."
-#: newforms/fields.py:296 newforms/fields.py:752
+#: newforms/fields.py:301 newforms/fields.py:780
msgid "Enter a valid time."
msgstr "Inserire un ora valida."
-#: newforms/fields.py:335
+#: newforms/fields.py:340
msgid "Enter a valid date/time."
msgstr "Inserire una coppia data/ora valida."
-#: newforms/fields.py:434
+#: newforms/fields.py:427
msgid "No file was submitted."
msgstr "Nessun file è stato inviato."
-#: newforms/fields.py:435 oldforms/__init__.py:689
+#: newforms/fields.py:428 oldforms/__init__.py:693
msgid "The submitted file is empty."
msgstr "Il file inviato è vuoto."
-#: newforms/fields.py:497
+#: newforms/fields.py:522
msgid "Enter a valid URL."
msgstr "Inserire una URL valida."
-#: newforms/fields.py:498
+#: newforms/fields.py:523
msgid "This URL appears to be a broken link."
msgstr "Questa URL non sembra funzionare."
-#: newforms/fields.py:560 newforms/models.py:299
+#: newforms/fields.py:588 newforms/models.py:306
msgid "Select a valid choice. That choice is not one of the available choices."
msgstr ""
"Scegliere un'opzione valida. La scelta effettuata non compare tra quelle "
"disponibili."
-#: newforms/fields.py:599
+#: newforms/fields.py:627
#, python-format
msgid "Select a valid choice. %(value)s is not one of the available choices."
msgstr "Scegliere un'opzione valida. '%(value)s non compare tra quelle disponibili."
-#: newforms/fields.py:600 newforms/fields.py:662 newforms/models.py:371
+#: newforms/fields.py:628 newforms/fields.py:690 newforms/models.py:373
msgid "Enter a list of values."
msgstr "Inserire una lista di valori."
-#: newforms/fields.py:780
+#: newforms/fields.py:808
msgid "Enter a valid IPv4 address."
msgstr "Inserire un indirizzo IPv4 valido."
-#: newforms/models.py:372
+#: newforms/models.py:374
#, python-format
msgid "Select a valid choice. %s is not one of the available choices."
msgstr "Scegliere un'opzione valida. '%s non compare tra quelle disponibili."
@@ -4048,15 +4055,15 @@ msgstr "Non sono ammessi a capo manuali qui."
msgid "Select a valid choice; '%(data)s' is not in %(choices)s."
msgstr "Scegliere un'opzione valida; '%(data)s' non presente in %(choices)s."
-#: oldforms/__init__.py:745
+#: oldforms/__init__.py:754
msgid "Enter a whole number between -32,768 and 32,767."
msgstr "Inserire un numero intero compreso tra -32.768 e 32.767 ."
-#: oldforms/__init__.py:755
+#: oldforms/__init__.py:764
msgid "Enter a positive number."
msgstr "Inserire un numero positivo."
-#: oldforms/__init__.py:765
+#: oldforms/__init__.py:774
msgid "Enter a whole number between 0 and 32,767."
msgstr "Inserire un numero intero compreso tra 0 e 32.767 ."
@@ -4290,7 +4297,7 @@ msgstr "Nov."
msgid "Dec."
msgstr "Dic."
-#: utils/text.py:127
+#: utils/text.py:128
msgid "or"
msgstr "o"
@@ -4344,23 +4351,23 @@ msgstr "%(number)d %(type)s"
msgid ", %(number)d %(type)s"
msgstr ", %(number)d %(type)s"
-#: utils/translation/trans_real.py:403
+#: utils/translation/trans_real.py:412
msgid "DATE_FORMAT"
msgstr "j F Y"
-#: utils/translation/trans_real.py:404
+#: utils/translation/trans_real.py:413
msgid "DATETIME_FORMAT"
msgstr "j F Y, H:i"
-#: utils/translation/trans_real.py:405
+#: utils/translation/trans_real.py:414
msgid "TIME_FORMAT"
msgstr "H:i"
-#: utils/translation/trans_real.py:421
+#: utils/translation/trans_real.py:430
msgid "YEAR_MONTH_FORMAT"
msgstr "Y F"
-#: utils/translation/trans_real.py:422
+#: utils/translation/trans_real.py:431
msgid "MONTH_DAY_FORMAT"
msgstr "F j"
diff --git a/django/core/files/uploadedfile.py b/django/core/files/uploadedfile.py
index 9287a1bec8..7f515f94d4 100644
--- a/django/core/files/uploadedfile.py
+++ b/django/core/files/uploadedfile.py
@@ -193,7 +193,7 @@ class TemporaryUploadedFile(UploadedFile):
"""
Returns the full path of this file.
"""
- return self.name
+ return self._file.name
# Most methods on this object get proxied to NamedTemporaryFile.
# We can't directly subclass because NamedTemporaryFile is actually a
diff --git a/django/core/management/__init__.py b/django/core/management/__init__.py
index 819b19a366..5e01ccbbe9 100644
--- a/django/core/management/__init__.py
+++ b/django/core/management/__init__.py
@@ -134,6 +134,35 @@ class LaxOptionParser(OptionParser):
"""
def error(self, msg):
pass
+
+ def _process_args(self, largs, rargs, values):
+ """
+ Overrides OptionParser._process_args to exclusively handle default
+ options and ignore args and other options.
+
+ This overrides the behavior of the super class, which stop parsing
+ at the first unrecognized option.
+ """
+ while rargs:
+ arg = rargs[0]
+ try:
+ if arg[0:2] == "--" and len(arg) > 2:
+ # process a single long option (possibly with value(s))
+ # the superclass code pops the arg off rargs
+ self._process_long_opt(rargs, values)
+ elif arg[:1] == "-" and len(arg) > 1:
+ # process a cluster of short options (possibly with
+ # value(s) for the last one only)
+ # the superclass code pops the arg off rargs
+ self._process_short_opts(rargs, values)
+ else:
+ # it's either a non-default option or an arg
+ # either way, add it to the args list so we can keep
+ # dealing with options
+ del rargs[0]
+ raise error
+ except:
+ largs.append(arg)
class ManagementUtility(object):
"""
diff --git a/django/core/management/commands/syncdb.py b/django/core/management/commands/syncdb.py
index 91e78c96e8..3792a312d7 100644
--- a/django/core/management/commands/syncdb.py
+++ b/django/core/management/commands/syncdb.py
@@ -41,10 +41,11 @@ class Command(NoArgsCommand):
# but raises an ImportError for some reason. The only way we
# can do this is to check the text of the exception. Note that
# we're a bit broad in how we check the text, because different
- # Python implementations may not use the same text. CPython
- # uses the text "No module named management".
+ # Python implementations may not use the same text.
+ # CPython uses the text "No module named management"
+ # PyPy uses "No module named myproject.myapp.management"
msg = exc.args[0]
- if not msg.startswith('No module named management') or 'management' not in msg:
+ if not msg.startswith('No module named') or 'management' not in msg:
raise
cursor = connection.cursor()
@@ -105,7 +106,10 @@ class Command(NoArgsCommand):
# Send the post_syncdb signal, so individual apps can do whatever they need
# to do at this point.
emit_post_sync_signal(created_models, verbosity, interactive)
-
+
+ # The connection may have been closed by a syncdb handler.
+ cursor = connection.cursor()
+
# Install custom SQL for the app (but only if this
# is a model we've just created)
for app in models.get_apps():
@@ -144,7 +148,7 @@ class Command(NoArgsCommand):
for sql in index_sql:
cursor.execute(sql)
except Exception, e:
- sys.stderr.write("Failed to install index for %s.%s model: %s" % \
+ sys.stderr.write("Failed to install index for %s.%s model: %s\n" % \
(app_name, model._meta.object_name, e))
transaction.rollback_unless_managed()
else:
diff --git a/django/db/models/fields/__init__.py b/django/db/models/fields/__init__.py
index eed2f89c52..cb20ae51e2 100644
--- a/django/db/models/fields/__init__.py
+++ b/django/db/models/fields/__init__.py
@@ -314,7 +314,7 @@ class Field(object):
params['validator_list'].append(getattr(manipulator, 'isUnique%sFor%s' % (self.name, self.unique_for_month)))
if self.unique_for_year:
params['validator_list'].append(getattr(manipulator, 'isUnique%sFor%s' % (self.name, self.unique_for_year)))
- if self.unique or (self.primary_key and not rel):
+ if self.unique and not rel:
params['validator_list'].append(curry(manipulator_validator_unique, self, opts, manipulator))
# Only add is_required=True if the field cannot be blank. Primary keys
@@ -539,7 +539,7 @@ class DateField(Field):
raise validators.ValidationError, _('Enter a valid date in YYYY-MM-DD format.')
def get_db_prep_lookup(self, lookup_type, value):
- if lookup_type == 'range':
+ if lookup_type in ('range', 'in'):
value = [smart_unicode(v) for v in value]
elif lookup_type in ('exact', 'gt', 'gte', 'lt', 'lte') and hasattr(value, 'strftime'):
value = value.strftime('%Y-%m-%d')
@@ -626,7 +626,7 @@ class DateTimeField(DateField):
return Field.get_db_prep_save(self, value)
def get_db_prep_lookup(self, lookup_type, value):
- if lookup_type == 'range':
+ if lookup_type in ('range', 'in'):
value = [smart_unicode(v) for v in value]
else:
value = smart_unicode(value)
@@ -705,7 +705,7 @@ class DecimalField(Field):
return super(DecimalField, self).get_db_prep_save(value)
def get_db_prep_lookup(self, lookup_type, value):
- if lookup_type == 'range':
+ if lookup_type in ('range', 'in'):
value = [self._format(v) for v in value]
else:
value = self._format(value)
@@ -820,12 +820,14 @@ class FileField(Field):
def save_file(self, new_data, new_object, original_object, change, rel, save=True):
upload_field_name = self.get_manipulator_field_names('')[0]
if new_data.get(upload_field_name, False):
- func = getattr(new_object, 'save_%s_file' % self.name)
if rel:
file = new_data[upload_field_name][0]
else:
file = new_data[upload_field_name]
+ if not file:
+ return
+
# Backwards-compatible support for files-as-dictionaries.
# We don't need to raise a warning because Model._save_FIELD_file will
# do so for us.
@@ -834,6 +836,7 @@ class FileField(Field):
except AttributeError:
file_name = file['filename']
+ func = getattr(new_object, 'save_%s_file' % self.name)
func(file_name, file, save)
def get_directory_name(self):
@@ -1086,7 +1089,7 @@ class TimeField(Field):
return smart_unicode(value)
else:
prep = smart_unicode
- if lookup_type == 'range':
+ if lookup_type in ('range', 'in'):
value = [prep(v) for v in value]
else:
value = prep(value)
diff --git a/django/db/models/query.py b/django/db/models/query.py
index 986846fc3a..b1921a8e4b 100644
--- a/django/db/models/query.py
+++ b/django/db/models/query.py
@@ -1,13 +1,17 @@
import warnings
+try:
+ set
+except NameError:
+ from sets import Set as set # Python 2.3 fallback
-from django.conf import settings
from django.db import connection, transaction, IntegrityError
-from django.db.models.fields import DateField, FieldDoesNotExist
+from django.db.models.fields import DateField
from django.db.models.query_utils import Q, select_related_descend
from django.db.models import signals, sql
from django.dispatch import dispatcher
from django.utils.datastructures import SortedDict
+
# Used to control how many objects are worked with at once in some cases (e.g.
# when deleting objects).
CHUNK_SIZE = 100
@@ -16,7 +20,12 @@ ITER_CHUNK_SIZE = CHUNK_SIZE
# Pull into this namespace for backwards compatibility.
EmptyResultSet = sql.EmptyResultSet
+
class CyclicDependency(Exception):
+ """
+ An error when dealing with a collection of objects that have a cyclic
+ dependency, i.e. when deleting multiple objects.
+ """
pass
diff --git a/django/db/models/sql/query.py b/django/db/models/sql/query.py
index 7944d0358f..f682c71d07 100644
--- a/django/db/models/sql/query.py
+++ b/django/db/models/sql/query.py
@@ -283,12 +283,11 @@ class Query(object):
if ordering:
result.append('ORDER BY %s' % ', '.join(ordering))
- # FIXME: Pull this out to make life easier for Oracle et al.
if with_limits:
- if self.high_mark:
+ if self.high_mark is not None:
result.append('LIMIT %d' % (self.high_mark - self.low_mark))
if self.low_mark:
- if not self.high_mark:
+ if self.high_mark is None:
val = self.connection.ops.no_limit_value()
if val:
result.append('LIMIT %d' % val)
@@ -1381,12 +1380,12 @@ class Query(object):
constraints. So low is added to the current low value and both will be
clamped to any existing high value.
"""
- if high:
+ if high is not None:
if self.high_mark:
self.high_mark = min(self.high_mark, self.low_mark + high)
else:
self.high_mark = self.low_mark + high
- if low:
+ if low is not None:
if self.high_mark:
self.low_mark = min(self.high_mark, self.low_mark + low)
else:
diff --git a/django/http/multipartparser.py b/django/http/multipartparser.py
index fc48aa9e7b..fa1ae11968 100644
--- a/django/http/multipartparser.py
+++ b/django/http/multipartparser.py
@@ -270,24 +270,9 @@ class LazyStream(object):
self._empty = False
self._leftover = ''
self.length = length
- self._position = 0
+ self.position = 0
self._remaining = length
-
- # These fields are to do sanity checking to make sure we don't
- # have infinite loops getting/ungetting from the stream. The
- # purpose overall is to raise an exception if we perform lots
- # of stream get/unget gymnastics without getting
- # anywhere. Naturally this is not sound, but most probably
- # would indicate a bug if the exception is raised.
-
- # largest position tell us how far this lazystream has ever
- # been advanced
- self._largest_position = 0
-
- # "modifications since" will start at zero and increment every
- # time the position is modified but a new largest position is
- # not achieved.
- self._modifications_since = 0
+ self._unget_history = []
def tell(self):
return self.position
@@ -329,6 +314,7 @@ class LazyStream(object):
self._leftover = ''
else:
output = self._producer.next()
+ self._unget_history = []
self.position += len(output)
return output
@@ -351,25 +337,30 @@ class LazyStream(object):
Future calls to read() will return those bytes first. The
stream position and thus tell() will be rewound.
"""
+ if not bytes:
+ return
+ self._update_unget_history(len(bytes))
self.position -= len(bytes)
self._leftover = ''.join([bytes, self._leftover])
- def _set_position(self, value):
- if value > self._largest_position:
- self._modifications_since = 0
- self._largest_position = value
- else:
- self._modifications_since += 1
- if self._modifications_since > 500:
- raise SuspiciousOperation(
- "The multipart parser got stuck, which shouldn't happen with"
- " normal uploaded files. Check for malicious upload activity;"
- " if there is none, report this to the Django developers."
- )
-
- self._position = value
+ def _update_unget_history(self, num_bytes):
+ """
+ Updates the unget history as a sanity check to see if we've pushed
+ back the same number of bytes in one chunk. If we keep ungetting the
+ same number of bytes many times (here, 50), we're mostly likely in an
+ infinite loop of some sort. This is usually caused by a
+ maliciously-malformed MIME request.
+ """
+ self._unget_history = [num_bytes] + self._unget_history[:49]
+ number_equal = len([current_number for current_number in self._unget_history
+ if current_number == num_bytes])
- position = property(lambda self: self._position, _set_position)
+ if number_equal > 40:
+ raise SuspiciousOperation(
+ "The multipart parser got stuck, which shouldn't happen with"
+ " normal uploaded files. Check for malicious upload activity;"
+ " if there is none, report this to the Django developers."
+ )
class ChunkIter(object):
"""
diff --git a/django/newforms/fields.py b/django/newforms/fields.py
index ad46d78859..bfff9fe8b0 100644
--- a/django/newforms/fields.py
+++ b/django/newforms/fields.py
@@ -507,6 +507,8 @@ class ImageField(FileField):
trial_image.verify()
except Exception: # Python Imaging Library doesn't recognize it as an image
raise ValidationError(self.error_messages['invalid_image'])
+ if hasattr(f, 'seek') and callable(f.seek):
+ f.seek(0)
return f
url_re = re.compile(
diff --git a/django/utils/itercompat.py b/django/utils/itercompat.py
index 3742d6c5d8..c166da35b8 100644
--- a/django/utils/itercompat.py
+++ b/django/utils/itercompat.py
@@ -67,3 +67,8 @@ def is_iterable(x):
else:
return True
+def sorted(in_value):
+ "A naive implementation of sorted"
+ out_value = in_value[:]
+ out_value.sort()
+ return out_value
diff --git a/docs/contributing.txt b/docs/contributing.txt
index 61b24f4705..f3bee14069 100644
--- a/docs/contributing.txt
+++ b/docs/contributing.txt
@@ -738,6 +738,11 @@ If you're using another backend:
deleted when the tests are finished. This means your user account needs
permission to execute ``CREATE DATABASE``.
+You will also need to ensure that your database uses UTF-8 as the default
+character set. If your database server doesn't use UTF-8 as a default charset,
+you will need to include a value for ``TEST_DATABASE_CHARSET`` in your settings
+file.
+
If you want to run the full suite of tests, you'll need to install a number of
dependencies:
diff --git a/docs/db-api.txt b/docs/db-api.txt
index 9a604bf320..5fdcd946bd 100644
--- a/docs/db-api.txt
+++ b/docs/db-api.txt
@@ -2212,6 +2212,18 @@ updated is that it can only access one database table, the model's main
table. So don't try to filter based on related fields or anything like that;
it won't work.
+Be aware that the ``update()`` method is converted directly to an SQL
+statement. It is a bulk operation for direct updates. It doesn't run any
+``save()`` methods on your models, or emit the ``pre_save`` or ``post_save``
+signals (which are a consequence of calling ``save()``). If you want to save
+every item in a ``QuerySet`` and make sure that the ``save()`` method is
+called on each instance, you don't need any special function to handle that.
+Just loop over them and call ``save()``:
+
+ for item in my_queryset:
+ item.save()
+
+
Extra instance methods
======================
diff --git a/docs/testing.txt b/docs/testing.txt
index 0b18545efb..bb091bfd6b 100644
--- a/docs/testing.txt
+++ b/docs/testing.txt
@@ -89,7 +89,7 @@ read Python's official documentation for the details.
For example, this function has a docstring that describes what it does::
def add_two(num):
- "Adds 2 to the given number and returns the result."
+ "Return the result of adding two to the provided number."
return num + 2
Because tests often make great documentation, putting tests directly in
@@ -600,8 +600,6 @@ Specifically, a ``Response`` object has the following attributes:
``context`` will be a list of ``Context``
objects, in the order in which they were rendered.
- ``headers`` The HTTP headers of the response. This is a dictionary.
-
``request`` The request data that stimulated the response.
``status_code`` The HTTP status of the response, as an integer. See
@@ -619,6 +617,10 @@ Specifically, a ``Response`` object has the following attributes:
which they were rendered.
=============== ==========================================================
+You can also use dictionary syntax on the response object to query the value
+of any settings in the HTTP headers. For example, you could determine the
+content type of a response using ``response['Content-Type']``.
+
.. _RFC2616: http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
.. _template inheritance: ../templates/#template-inheritance
diff --git a/docs/tutorial01.txt b/docs/tutorial01.txt
index 04863cc7fd..9e765b1a9b 100644
--- a/docs/tutorial01.txt
+++ b/docs/tutorial01.txt
@@ -146,7 +146,7 @@ database's connection parameters:
* ``DATABASE_ENGINE`` -- Either 'postgresql_psycopg2', 'mysql' or 'sqlite3'.
Other backends are `also available`_.
* ``DATABASE_NAME`` -- The name of your database, or the full (absolute)
- path to the database file if you're using SQLite.
+ path to the database file if you're using SQLite.
* ``DATABASE_USER`` -- Your database username (not used for SQLite).
* ``DATABASE_PASSWORD`` -- Your database password (not used for SQLite).
* ``DATABASE_HOST`` -- The host your database is on. Leave this as an
@@ -161,6 +161,9 @@ database's connection parameters:
this point. Do that with "``CREATE DATABASE database_name;``" within your
database's interactive prompt.
+ If you're using SQLite, you don't need to create anything beforehand - the
+ database file will be created automatically when it is needed.
+
While you're editing ``settings.py``, take note of the ``INSTALLED_APPS``
setting towards the bottom of the file. That variable holds the names of all
Django applications that are activated in this Django instance. Apps can be
diff --git a/tests/modeltests/basic/models.py b/tests/modeltests/basic/models.py
index c3ad38d661..835c5c90cf 100644
--- a/tests/modeltests/basic/models.py
+++ b/tests/modeltests/basic/models.py
@@ -4,12 +4,18 @@
This is a basic model with only two non-primary-key fields.
"""
-
+# Python 2.3 doesn't have set as a builtin
try:
set
except NameError:
from sets import Set as set
+# Python 2.3 doesn't have sorted()
+try:
+ sorted
+except NameError:
+ from django.utils.itercompat import sorted
+
from django.db import models
class Article(models.Model):
diff --git a/tests/modeltests/model_forms/models.py b/tests/modeltests/model_forms/models.py
index 289dcb42a6..6838f11d4e 100644
--- a/tests/modeltests/model_forms/models.py
+++ b/tests/modeltests/model_forms/models.py
@@ -900,7 +900,7 @@ u'...test3.txt'
... class Meta:
... model = ImageFile
->>> image_data = open(os.path.join(os.path.dirname(__file__), "test.png")).read()
+>>> image_data = open(os.path.join(os.path.dirname(__file__), "test.png"), 'rb').read()
>>> f = ImageFileForm(data={'description': u'An image'}, files={'image': SimpleUploadedFile('test.png', image_data)})
>>> f.is_valid()
diff --git a/tests/modeltests/or_lookups/models.py b/tests/modeltests/or_lookups/models.py
index 22bada07b1..6e56095d7c 100644
--- a/tests/modeltests/or_lookups/models.py
+++ b/tests/modeltests/or_lookups/models.py
@@ -8,6 +8,11 @@ Alternatively, use positional arguments, and pass one or more expressions of
clauses using the variable ``django.db.models.Q`` (or any object with an
add_to_query method).
"""
+# Python 2.3 doesn't have sorted()
+try:
+ sorted
+except NameError:
+ from django.utils.itercompat import sorted
from django.db import models
diff --git a/tests/modeltests/test_client/models.py b/tests/modeltests/test_client/models.py
index 1a6e1bdc18..3797bf2d52 100644
--- a/tests/modeltests/test_client/models.py
+++ b/tests/modeltests/test_client/models.py
@@ -70,7 +70,13 @@ class ClientTest(TestCase):
self.assertEqual(response.context['data'], '37')
self.assertEqual(response.template.name, 'POST Template')
self.failUnless('Data received' in response.content)
-
+
+ def test_response_headers(self):
+ "Check the value of HTTP headers returned in a response"
+ response = self.client.get("/test_client/header_view/")
+
+ self.assertEquals(response['X-DJANGO-TEST'], 'Slartibartfast')
+
def test_raw_post(self):
"POST raw data (with a content type) to a view"
test_doc = """<?xml version="1.0" encoding="utf-8"?><library><book><title>Blink</title><author>Malcolm Gladwell</author></book></library>"""
diff --git a/tests/modeltests/test_client/urls.py b/tests/modeltests/test_client/urls.py
index 09ee7eaf34..0e511d7360 100644
--- a/tests/modeltests/test_client/urls.py
+++ b/tests/modeltests/test_client/urls.py
@@ -5,6 +5,7 @@ import views
urlpatterns = patterns('',
(r'^get_view/$', views.get_view),
(r'^post_view/$', views.post_view),
+ (r'^header_view/$', views.view_with_header),
(r'^raw_post_view/$', views.raw_post_view),
(r'^redirect_view/$', views.redirect_view),
(r'^permanent_redirect_view/$', redirect_to, { 'url': '/test_client/get_view/' }),
diff --git a/tests/modeltests/test_client/views.py b/tests/modeltests/test_client/views.py
index 3f4a54c5bd..f4eab6462d 100644
--- a/tests/modeltests/test_client/views.py
+++ b/tests/modeltests/test_client/views.py
@@ -32,6 +32,12 @@ def post_view(request):
return HttpResponse(t.render(c))
+def view_with_header(request):
+ "A view that has a custom header"
+ response = HttpResponse()
+ response['X-DJANGO-TEST'] = 'Slartibartfast'
+ return response
+
def raw_post_view(request):
"""A view which expects raw XML to be posted and returns content extracted
from the XML"""
diff --git a/tests/regressiontests/admin_scripts/management/commands/app_command.py b/tests/regressiontests/admin_scripts/management/commands/app_command.py
index f72e912ac0..3d8c43755c 100644
--- a/tests/regressiontests/admin_scripts/management/commands/app_command.py
+++ b/tests/regressiontests/admin_scripts/management/commands/app_command.py
@@ -1,4 +1,9 @@
from django.core.management.base import AppCommand
+# Python 2.3 doesn't have sorted()
+try:
+ sorted
+except NameError:
+ from django.utils.itercompat import sorted
class Command(AppCommand):
help = 'Test Application-based commands'
diff --git a/tests/regressiontests/admin_scripts/management/commands/base_command.py b/tests/regressiontests/admin_scripts/management/commands/base_command.py
index 0187a23b29..536f40409a 100644
--- a/tests/regressiontests/admin_scripts/management/commands/base_command.py
+++ b/tests/regressiontests/admin_scripts/management/commands/base_command.py
@@ -1,6 +1,17 @@
from django.core.management.base import BaseCommand
+from optparse import make_option
+# Python 2.3 doesn't have sorted()
+try:
+ sorted
+except NameError:
+ from django.utils.itercompat import sorted
class Command(BaseCommand):
+ option_list = BaseCommand.option_list + (
+ make_option('--option_a','-a', action='store', dest='option_a', default='1'),
+ make_option('--option_b','-b', action='store', dest='option_b', default='2'),
+ make_option('--option_c','-c', action='store', dest='option_c', default='3'),
+ )
help = 'Test basic commands'
requires_model_validation = False
args = '[labels ...]'
diff --git a/tests/regressiontests/admin_scripts/management/commands/label_command.py b/tests/regressiontests/admin_scripts/management/commands/label_command.py
index 2b735c8e60..e749209d9c 100644
--- a/tests/regressiontests/admin_scripts/management/commands/label_command.py
+++ b/tests/regressiontests/admin_scripts/management/commands/label_command.py
@@ -1,4 +1,9 @@
from django.core.management.base import LabelCommand
+# Python 2.3 doesn't have sorted()
+try:
+ sorted
+except NameError:
+ from django.utils.itercompat import sorted
class Command(LabelCommand):
help = "Test Label-based commands"
diff --git a/tests/regressiontests/admin_scripts/management/commands/noargs_command.py b/tests/regressiontests/admin_scripts/management/commands/noargs_command.py
index 683eb7a62c..f0f418752a 100644
--- a/tests/regressiontests/admin_scripts/management/commands/noargs_command.py
+++ b/tests/regressiontests/admin_scripts/management/commands/noargs_command.py
@@ -1,4 +1,9 @@
from django.core.management.base import NoArgsCommand
+# Python 2.3 doesn't have sorted()
+try:
+ sorted
+except NameError:
+ from django.utils.itercompat import sorted
class Command(NoArgsCommand):
help = "Test No-args commands"
diff --git a/tests/regressiontests/admin_scripts/tests.py b/tests/regressiontests/admin_scripts/tests.py
index 441ce10d07..3ebcfbb6cd 100644
--- a/tests/regressiontests/admin_scripts/tests.py
+++ b/tests/regressiontests/admin_scripts/tests.py
@@ -7,7 +7,7 @@ import os
import unittest
import shutil
-from django import conf, bin
+from django import conf, bin, get_version
from django.conf import settings
class AdminScriptTestCase(unittest.TestCase):
@@ -29,7 +29,7 @@ class AdminScriptTestCase(unittest.TestCase):
settings_file.write("%s = '%s'\n" % (s, str(getattr(settings,s))))
if apps is None:
- apps = ['django.contrib.auth', 'django.contrib.contenttypes', 'regressiontests.admin_scripts']
+ apps = ['django.contrib.auth', 'django.contrib.contenttypes', 'admin_scripts']
if apps:
settings_file.write("INSTALLED_APPS = %s\n" % apps)
@@ -53,7 +53,7 @@ class AdminScriptTestCase(unittest.TestCase):
# Build the command line
cmd = 'python "%s"' % script
- cmd += ''.join(' %s' % arg for arg in args)
+ cmd += ''.join([' %s' % arg for arg in args])
# Remember the old environment
old_django_settings_module = os.environ.get('DJANGO_SETTINGS_MODULE', None)
@@ -66,8 +66,8 @@ class AdminScriptTestCase(unittest.TestCase):
elif 'DJANGO_SETTINGS_MODULE' in os.environ:
del os.environ['DJANGO_SETTINGS_MODULE']
- os.environ['PYTHONPATH'] = os.pathsep.join([project_dir,base_dir])
-
+ os.environ['PYTHONPATH'] = os.pathsep.join([test_dir,base_dir])
+
# Move to the test directory and run
os.chdir(test_dir)
stdin, stdout, stderr = os.popen3(cmd)
@@ -129,17 +129,17 @@ class DjangoAdminNoSettings(AdminScriptTestCase):
def test_builtin_with_bad_settings(self):
"no settings: django-admin builtin commands fail if settings file (from argument) doesn't exist"
- args = ['sqlall','--settings=regressiontests.bad_settings', 'admin_scripts']
+ args = ['sqlall','--settings=bad_settings', 'admin_scripts']
out, err = self.run_django_admin(args)
self.assertNoOutput(out)
- self.assertOutput(err, "Could not import settings 'regressiontests.bad_settings'")
+ self.assertOutput(err, "Could not import settings 'bad_settings'")
def test_builtin_with_bad_environment(self):
"no settings: django-admin builtin commands fail if settings file (from environment) doesn't exist"
args = ['sqlall','admin_scripts']
- out, err = self.run_django_admin(args,'regressiontests.bad_settings')
+ out, err = self.run_django_admin(args,'bad_settings')
self.assertNoOutput(out)
- self.assertOutput(err, "Could not import settings 'regressiontests.bad_settings'")
+ self.assertOutput(err, "Could not import settings 'bad_settings'")
class DjangoAdminDefaultSettings(AdminScriptTestCase):
@@ -161,7 +161,7 @@ class DjangoAdminDefaultSettings(AdminScriptTestCase):
def test_builtin_with_settings(self):
"default: django-admin builtin commands succeed if settings are provided as argument"
- args = ['sqlall','--settings=regressiontests.settings', 'admin_scripts']
+ args = ['sqlall','--settings=settings', 'admin_scripts']
out, err = self.run_django_admin(args)
self.assertNoOutput(err)
self.assertOutput(out, 'CREATE TABLE')
@@ -169,23 +169,23 @@ class DjangoAdminDefaultSettings(AdminScriptTestCase):
def test_builtin_with_environment(self):
"default: django-admin builtin commands succeed if settings are provided in the environment"
args = ['sqlall','admin_scripts']
- out, err = self.run_django_admin(args,'regressiontests.settings')
+ out, err = self.run_django_admin(args,'settings')
self.assertNoOutput(err)
self.assertOutput(out, 'CREATE TABLE')
def test_builtin_with_bad_settings(self):
"default: django-admin builtin commands fail if settings file (from argument) doesn't exist"
- args = ['sqlall','--settings=regressiontests.bad_settings', 'admin_scripts']
+ args = ['sqlall','--settings=bad_settings', 'admin_scripts']
out, err = self.run_django_admin(args)
self.assertNoOutput(out)
- self.assertOutput(err, "Could not import settings 'regressiontests.bad_settings'")
+ self.assertOutput(err, "Could not import settings 'bad_settings'")
def test_builtin_with_bad_environment(self):
"default: django-admin builtin commands fail if settings file (from environment) doesn't exist"
args = ['sqlall','admin_scripts']
- out, err = self.run_django_admin(args,'regressiontests.bad_settings')
+ out, err = self.run_django_admin(args,'bad_settings')
self.assertNoOutput(out)
- self.assertOutput(err, "Could not import settings 'regressiontests.bad_settings'")
+ self.assertOutput(err, "Could not import settings 'bad_settings'")
def test_custom_command(self):
"default: django-admin can't execute user commands"
@@ -196,7 +196,7 @@ class DjangoAdminDefaultSettings(AdminScriptTestCase):
def test_custom_command_with_settings(self):
"default: django-admin can't execute user commands, even if settings are provided as argument"
- args = ['noargs_command', '--settings=regressiontests.settings']
+ args = ['noargs_command', '--settings=settings']
out, err = self.run_django_admin(args)
self.assertNoOutput(out)
self.assertOutput(err, "Unknown command: 'noargs_command'")
@@ -204,7 +204,7 @@ class DjangoAdminDefaultSettings(AdminScriptTestCase):
def test_custom_command_with_environment(self):
"default: django-admin can't execute user commands, even if settings are provided in environment"
args = ['noargs_command']
- out, err = self.run_django_admin(args,'regressiontests.settings')
+ out, err = self.run_django_admin(args,'settings')
self.assertNoOutput(out)
self.assertOutput(err, "Unknown command: 'noargs_command'")
@@ -227,7 +227,7 @@ class DjangoAdminMinimalSettings(AdminScriptTestCase):
def test_builtin_with_settings(self):
"minimal: django-admin builtin commands fail if settings are provided as argument"
- args = ['sqlall','--settings=regressiontests.settings', 'admin_scripts']
+ args = ['sqlall','--settings=settings', 'admin_scripts']
out, err = self.run_django_admin(args)
self.assertNoOutput(out)
self.assertOutput(err, 'App with label admin_scripts could not be found')
@@ -235,23 +235,23 @@ class DjangoAdminMinimalSettings(AdminScriptTestCase):
def test_builtin_with_environment(self):
"minimal: django-admin builtin commands fail if settings are provided in the environment"
args = ['sqlall','admin_scripts']
- out, err = self.run_django_admin(args,'regressiontests.settings')
+ out, err = self.run_django_admin(args,'settings')
self.assertNoOutput(out)
self.assertOutput(err, 'App with label admin_scripts could not be found')
def test_builtin_with_bad_settings(self):
"minimal: django-admin builtin commands fail if settings file (from argument) doesn't exist"
- args = ['sqlall','--settings=regressiontests.bad_settings', 'admin_scripts']
+ args = ['sqlall','--settings=bad_settings', 'admin_scripts']
out, err = self.run_django_admin(args)
self.assertNoOutput(out)
- self.assertOutput(err, "Could not import settings 'regressiontests.bad_settings'")
+ self.assertOutput(err, "Could not import settings 'bad_settings'")
def test_builtin_with_bad_environment(self):
"minimal: django-admin builtin commands fail if settings file (from environment) doesn't exist"
args = ['sqlall','admin_scripts']
- out, err = self.run_django_admin(args,'regressiontests.bad_settings')
+ out, err = self.run_django_admin(args,'bad_settings')
self.assertNoOutput(out)
- self.assertOutput(err, "Could not import settings 'regressiontests.bad_settings'")
+ self.assertOutput(err, "Could not import settings 'bad_settings'")
def test_custom_command(self):
"minimal: django-admin can't execute user commands"
@@ -262,7 +262,7 @@ class DjangoAdminMinimalSettings(AdminScriptTestCase):
def test_custom_command_with_settings(self):
"minimal: django-admin can't execute user commands, even if settings are provided as argument"
- args = ['noargs_command', '--settings=regressiontests.settings']
+ args = ['noargs_command', '--settings=settings']
out, err = self.run_django_admin(args)
self.assertNoOutput(out)
self.assertOutput(err, "Unknown command: 'noargs_command'")
@@ -270,7 +270,7 @@ class DjangoAdminMinimalSettings(AdminScriptTestCase):
def test_custom_command_with_environment(self):
"minimal: django-admin can't execute user commands, even if settings are provided in environment"
args = ['noargs_command']
- out, err = self.run_django_admin(args,'regressiontests.settings')
+ out, err = self.run_django_admin(args,'settings')
self.assertNoOutput(out)
self.assertOutput(err, "Unknown command: 'noargs_command'")
@@ -293,7 +293,7 @@ class DjangoAdminAlternateSettings(AdminScriptTestCase):
def test_builtin_with_settings(self):
"alternate: django-admin builtin commands succeed if settings are provided as argument"
- args = ['sqlall','--settings=regressiontests.alternate_settings', 'admin_scripts']
+ args = ['sqlall','--settings=alternate_settings', 'admin_scripts']
out, err = self.run_django_admin(args)
self.assertNoOutput(err)
self.assertOutput(out, 'CREATE TABLE')
@@ -301,23 +301,23 @@ class DjangoAdminAlternateSettings(AdminScriptTestCase):
def test_builtin_with_environment(self):
"alternate: django-admin builtin commands succeed if settings are provided in the environment"
args = ['sqlall','admin_scripts']
- out, err = self.run_django_admin(args,'regressiontests.alternate_settings')
+ out, err = self.run_django_admin(args,'alternate_settings')
self.assertNoOutput(err)
self.assertOutput(out, 'CREATE TABLE')
def test_builtin_with_bad_settings(self):
"alternate: django-admin builtin commands fail if settings file (from argument) doesn't exist"
- args = ['sqlall','--settings=regressiontests.bad_settings', 'admin_scripts']
+ args = ['sqlall','--settings=bad_settings', 'admin_scripts']
out, err = self.run_django_admin(args)
self.assertNoOutput(out)
- self.assertOutput(err, "Could not import settings 'regressiontests.bad_settings'")
+ self.assertOutput(err, "Could not import settings 'bad_settings'")
def test_builtin_with_bad_environment(self):
"alternate: django-admin builtin commands fail if settings file (from environment) doesn't exist"
args = ['sqlall','admin_scripts']
- out, err = self.run_django_admin(args,'regressiontests.bad_settings')
+ out, err = self.run_django_admin(args,'bad_settings')
self.assertNoOutput(out)
- self.assertOutput(err, "Could not import settings 'regressiontests.bad_settings'")
+ self.assertOutput(err, "Could not import settings 'bad_settings'")
def test_custom_command(self):
"alternate: django-admin can't execute user commands"
@@ -328,7 +328,7 @@ class DjangoAdminAlternateSettings(AdminScriptTestCase):
def test_custom_command_with_settings(self):
"alternate: django-admin can't execute user commands, even if settings are provided as argument"
- args = ['noargs_command', '--settings=regressiontests.alternate_settings']
+ args = ['noargs_command', '--settings=alternate_settings']
out, err = self.run_django_admin(args)
self.assertNoOutput(out)
self.assertOutput(err, "Unknown command: 'noargs_command'")
@@ -336,7 +336,7 @@ class DjangoAdminAlternateSettings(AdminScriptTestCase):
def test_custom_command_with_environment(self):
"alternate: django-admin can't execute user commands, even if settings are provided in environment"
args = ['noargs_command']
- out, err = self.run_django_admin(args,'regressiontests.alternate_settings')
+ out, err = self.run_django_admin(args,'alternate_settings')
self.assertNoOutput(out)
self.assertOutput(err, "Unknown command: 'noargs_command'")
@@ -364,7 +364,7 @@ class DjangoAdminMultipleSettings(AdminScriptTestCase):
def test_builtin_with_settings(self):
"alternate: django-admin builtin commands succeed if settings are provided as argument"
- args = ['sqlall','--settings=regressiontests.alternate_settings', 'admin_scripts']
+ args = ['sqlall','--settings=alternate_settings', 'admin_scripts']
out, err = self.run_django_admin(args)
self.assertNoOutput(err)
self.assertOutput(out, 'CREATE TABLE')
@@ -372,22 +372,22 @@ class DjangoAdminMultipleSettings(AdminScriptTestCase):
def test_builtin_with_environment(self):
"alternate: django-admin builtin commands succeed if settings are provided in the environment"
args = ['sqlall','admin_scripts']
- out, err = self.run_django_admin(args,'regressiontests.alternate_settings')
+ out, err = self.run_django_admin(args,'alternate_settings')
self.assertNoOutput(err)
self.assertOutput(out, 'CREATE TABLE')
def test_builtin_with_bad_settings(self):
"alternate: django-admin builtin commands fail if settings file (from argument) doesn't exist"
- args = ['sqlall','--settings=regressiontests.bad_settings', 'admin_scripts']
+ args = ['sqlall','--settings=bad_settings', 'admin_scripts']
out, err = self.run_django_admin(args)
- self.assertOutput(err, "Could not import settings 'regressiontests.bad_settings'")
+ self.assertOutput(err, "Could not import settings 'bad_settings'")
def test_builtin_with_bad_environment(self):
"alternate: django-admin builtin commands fail if settings file (from environment) doesn't exist"
args = ['sqlall','admin_scripts']
- out, err = self.run_django_admin(args,'regressiontests.bad_settings')
+ out, err = self.run_django_admin(args,'bad_settings')
self.assertNoOutput(out)
- self.assertOutput(err, "Could not import settings 'regressiontests.bad_settings'")
+ self.assertOutput(err, "Could not import settings 'bad_settings'")
def test_custom_command(self):
"alternate: django-admin can't execute user commands"
@@ -398,7 +398,7 @@ class DjangoAdminMultipleSettings(AdminScriptTestCase):
def test_custom_command_with_settings(self):
"alternate: django-admin can't execute user commands, even if settings are provided as argument"
- args = ['noargs_command', '--settings=regressiontests.alternate_settings']
+ args = ['noargs_command', '--settings=alternate_settings']
out, err = self.run_django_admin(args)
self.assertNoOutput(out)
self.assertOutput(err, "Unknown command: 'noargs_command'")
@@ -406,7 +406,7 @@ class DjangoAdminMultipleSettings(AdminScriptTestCase):
def test_custom_command_with_environment(self):
"alternate: django-admin can't execute user commands, even if settings are provided in environment"
args = ['noargs_command']
- out, err = self.run_django_admin(args,'regressiontests.alternate_settings')
+ out, err = self.run_django_admin(args,'alternate_settings')
self.assertNoOutput(out)
self.assertOutput(err, "Unknown command: 'noargs_command'")
@@ -725,26 +725,62 @@ class CommandTypes(AdminScriptTestCase):
def tearDown(self):
self.remove_settings('settings.py')
+ def test_version(self):
+ "--version is handled as a special case"
+ args = ['--version']
+ out, err = self.run_manage(args)
+ self.assertNoOutput(err)
+ # Only check the first part of the version number
+ self.assertOutput(out, get_version().split('-')[0])
+
+ def test_help(self):
+ "--help is handled as a special case"
+ args = ['--help']
+ out, err = self.run_manage(args)
+ self.assertOutput(out, "Usage: manage.py [options]")
+ self.assertOutput(err, "Type 'manage.py help <subcommand>' for help on a specific subcommand.")
+
+ def test_specific_help(self):
+ "--help can be used on a specific command"
+ args = ['sqlall','--help']
+ out, err = self.run_manage(args)
+ self.assertNoOutput(err)
+ self.assertOutput(out, "Prints the CREATE TABLE, custom SQL and CREATE INDEX SQL statements for the given model module name(s).")
+
def test_base_command(self):
"User BaseCommands can execute when a label is provided"
args = ['base_command','testlabel']
out, err = self.run_manage(args)
self.assertNoOutput(err)
- self.assertOutput(out, "EXECUTE:BaseCommand labels=('testlabel',), options=[('pythonpath', None), ('settings', None), ('traceback', None)]")
+ self.assertOutput(out, "EXECUTE:BaseCommand labels=('testlabel',), options=[('option_a', '1'), ('option_b', '2'), ('option_c', '3'), ('pythonpath', None), ('settings', None), ('traceback', None)]")
def test_base_command_no_label(self):
"User BaseCommands can execute when no labels are provided"
args = ['base_command']
out, err = self.run_manage(args)
self.assertNoOutput(err)
- self.assertOutput(out, "EXECUTE:BaseCommand labels=(), options=[('pythonpath', None), ('settings', None), ('traceback', None)]")
+ self.assertOutput(out, "EXECUTE:BaseCommand labels=(), options=[('option_a', '1'), ('option_b', '2'), ('option_c', '3'), ('pythonpath', None), ('settings', None), ('traceback', None)]")
def test_base_command_multiple_label(self):
"User BaseCommands can execute when no labels are provided"
args = ['base_command','testlabel','anotherlabel']
out, err = self.run_manage(args)
self.assertNoOutput(err)
- self.assertOutput(out, "EXECUTE:BaseCommand labels=('testlabel', 'anotherlabel'), options=[('pythonpath', None), ('settings', None), ('traceback', None)]")
+ self.assertOutput(out, "EXECUTE:BaseCommand labels=('testlabel', 'anotherlabel'), options=[('option_a', '1'), ('option_b', '2'), ('option_c', '3'), ('pythonpath', None), ('settings', None), ('traceback', None)]")
+
+ def test_base_command_with_option(self):
+ "User BaseCommands can execute with options when a label is provided"
+ args = ['base_command','testlabel','--option_a=x']
+ out, err = self.run_manage(args)
+ self.assertNoOutput(err)
+ self.assertOutput(out, "EXECUTE:BaseCommand labels=('testlabel',), options=[('option_a', 'x'), ('option_b', '2'), ('option_c', '3'), ('pythonpath', None), ('settings', None), ('traceback', None)]")
+
+ def test_base_command_with_options(self):
+ "User BaseCommands can execute with multiple options when a label is provided"
+ args = ['base_command','testlabel','-a','x','--option_b=y']
+ out, err = self.run_manage(args)
+ self.assertNoOutput(err)
+ self.assertOutput(out, "EXECUTE:BaseCommand labels=('testlabel',), options=[('option_a', 'x'), ('option_b', 'y'), ('option_c', '3'), ('pythonpath', None), ('settings', None), ('traceback', None)]")
def test_noargs(self):
"NoArg Commands can be executed"
@@ -765,8 +801,9 @@ class CommandTypes(AdminScriptTestCase):
out, err = self.run_manage(args)
self.assertNoOutput(err)
self.assertOutput(out, "EXECUTE:AppCommand app=<module 'django.contrib.auth.models'")
- self.assertOutput(out, os.sep.join(['django','contrib','auth','models.pyc']) + "'>, options=[('pythonpath', None), ('settings', None), ('traceback', None)]")
-
+ self.assertOutput(out, os.sep.join(['django','contrib','auth','models.py']))
+ self.assertOutput(out, "'>, options=[('pythonpath', None), ('settings', None), ('traceback', None)]")
+
def test_app_command_no_apps(self):
"User AppCommands raise an error when no app name is provided"
args = ['app_command']
@@ -781,7 +818,8 @@ class CommandTypes(AdminScriptTestCase):
self.assertOutput(out, "EXECUTE:AppCommand app=<module 'django.contrib.auth.models'")
self.assertOutput(out, os.sep.join(['django','contrib','auth','models.pyc']) + "'>, options=[('pythonpath', None), ('settings', None), ('traceback', None)]")
self.assertOutput(out, "EXECUTE:AppCommand app=<module 'django.contrib.contenttypes.models'")
- self.assertOutput(out, os.sep.join(['django','contrib','contenttypes','models.pyc']) + "'>, options=[('pythonpath', None), ('settings', None), ('traceback', None)]")
+ self.assertOutput(out, os.sep.join(['django','contrib','contenttypes','models.py']))
+ self.assertOutput(out, "'>, options=[('pythonpath', None), ('settings', None), ('traceback', None)]")
def test_app_command_invalid_appname(self):
"User AppCommands can execute when a single app name is provided"
@@ -815,3 +853,56 @@ class CommandTypes(AdminScriptTestCase):
self.assertNoOutput(err)
self.assertOutput(out, "EXECUTE:LabelCommand label=testlabel, options=[('pythonpath', None), ('settings', None), ('traceback', None)]")
self.assertOutput(out, "EXECUTE:LabelCommand label=anotherlabel, options=[('pythonpath', None), ('settings', None), ('traceback', None)]")
+
+class ArgumentOrder(AdminScriptTestCase):
+ """Tests for 2-stage argument parsing scheme.
+
+ django-admin command arguments are parsed in 2 parts; the core arguments
+ (--settings, --traceback and --pythonpath) are parsed using a Lax parser.
+ This Lax parser ignores any unknown options. Then the full settings are
+ passed to the command parser, which extracts commands of interest to the
+ individual command.
+ """
+ def setUp(self):
+ self.write_settings('settings.py', apps=['django.contrib.auth','django.contrib.contenttypes'])
+ self.write_settings('alternate_settings.py')
+
+ def tearDown(self):
+ self.remove_settings('settings.py')
+ self.remove_settings('alternate_settings.py')
+
+ def test_setting_then_option(self):
+ "Options passed after settings are correctly handled"
+ args = ['base_command','testlabel','--settings=alternate_settings','--option_a=x']
+ out, err = self.run_manage(args)
+ self.assertNoOutput(err)
+ self.assertOutput(out, "EXECUTE:BaseCommand labels=('testlabel',), options=[('option_a', 'x'), ('option_b', '2'), ('option_c', '3'), ('pythonpath', None), ('settings', 'alternate_settings'), ('traceback', None)]")
+
+ def test_setting_then_short_option(self):
+ "Short options passed after settings are correctly handled"
+ args = ['base_command','testlabel','--settings=alternate_settings','--option_a=x']
+ out, err = self.run_manage(args)
+ self.assertNoOutput(err)
+ self.assertOutput(out, "EXECUTE:BaseCommand labels=('testlabel',), options=[('option_a', 'x'), ('option_b', '2'), ('option_c', '3'), ('pythonpath', None), ('settings', 'alternate_settings'), ('traceback', None)]")
+
+ def test_option_then_setting(self):
+ "Options passed before settings are correctly handled"
+ args = ['base_command','testlabel','--option_a=x','--settings=alternate_settings']
+ out, err = self.run_manage(args)
+ self.assertNoOutput(err)
+ self.assertOutput(out, "EXECUTE:BaseCommand labels=('testlabel',), options=[('option_a', 'x'), ('option_b', '2'), ('option_c', '3'), ('pythonpath', None), ('settings', 'alternate_settings'), ('traceback', None)]")
+
+ def test_short_option_then_setting(self):
+ "Short options passed before settings are correctly handled"
+ args = ['base_command','testlabel','-a','x','--settings=alternate_settings']
+ out, err = self.run_manage(args)
+ self.assertNoOutput(err)
+ self.assertOutput(out, "EXECUTE:BaseCommand labels=('testlabel',), options=[('option_a', 'x'), ('option_b', '2'), ('option_c', '3'), ('pythonpath', None), ('settings', 'alternate_settings'), ('traceback', None)]")
+
+ def test_option_then_setting_then_option(self):
+ "Options are correctly handled when they are passed before and after a setting"
+ args = ['base_command','testlabel','--option_a=x','--settings=alternate_settings','--option_b=y']
+ out, err = self.run_manage(args)
+ self.assertNoOutput(err)
+ self.assertOutput(out, "EXECUTE:BaseCommand labels=('testlabel',), options=[('option_a', 'x'), ('option_b', 'y'), ('option_c', '3'), ('pythonpath', None), ('settings', 'alternate_settings'), ('traceback', None)]")
+
diff --git a/tests/regressiontests/defaultfilters/tests.py b/tests/regressiontests/defaultfilters/tests.py
index b56c33a652..1b659a91f4 100644
--- a/tests/regressiontests/defaultfilters/tests.py
+++ b/tests/regressiontests/defaultfilters/tests.py
@@ -537,6 +537,12 @@ u'123'
from django.template.defaultfilters import *
import datetime
+# Python 2.3 doesn't have sorted()
+try:
+ sorted
+except NameError:
+ from django.utils.itercompat import sorted
+
if __name__ == '__main__':
import doctest
doctest.testmod()
diff --git a/tests/regressiontests/file_uploads/tests.py b/tests/regressiontests/file_uploads/tests.py
index 8a61966240..d2b581686f 100644
--- a/tests/regressiontests/file_uploads/tests.py
+++ b/tests/regressiontests/file_uploads/tests.py
@@ -25,7 +25,7 @@ class FileUploadTests(TestCase):
file2.seek(0)
# This file contains chinese symbols for a name.
- file3 = open(os.path.join(tdir, u'test_&#20013;&#25991;_Orl\u00e9ans.jpg'), 'w+b')
+ file3 = open(os.path.join(tdir, u'test_&#20013;&#25991;_Orl\u00e9ans.jpg'.encode('utf-8')), 'w+b')
file3.write('b' * (2 ** 10))
file3.seek(0)
diff --git a/tests/regressiontests/model_inheritance_regress/models.py b/tests/regressiontests/model_inheritance_regress/models.py
index 24d6186150..b78b493e15 100644
--- a/tests/regressiontests/model_inheritance_regress/models.py
+++ b/tests/regressiontests/model_inheritance_regress/models.py
@@ -6,6 +6,12 @@ import datetime
from django.db import models
+# Python 2.3 doesn't have sorted()
+try:
+ sorted
+except NameError:
+ from django.utils.itercompat import sorted
+
class Place(models.Model):
name = models.CharField(max_length=50)
address = models.CharField(max_length=80)
diff --git a/tests/regressiontests/queries/models.py b/tests/regressiontests/queries/models.py
index 566411e513..65d0d6ec65 100644
--- a/tests/regressiontests/queries/models.py
+++ b/tests/regressiontests/queries/models.py
@@ -8,6 +8,12 @@ import pickle
from django.db import models
from django.db.models.query import Q
+# Python 2.3 doesn't have sorted()
+try:
+ sorted
+except NameError:
+ from django.utils.itercompat import sorted
+
class Tag(models.Model):
name = models.CharField(max_length=10)
parent = models.ForeignKey('self', blank=True, null=True,
@@ -805,5 +811,14 @@ Bug #7371
>>> Related.objects.order_by('custom')
[]
+Bug #7448, #7707 -- Complex objects should be converted to strings before being
+used in lookups.
+>>> Item.objects.filter(created__in=[time1, time2])
+[<Item: one>, <Item: two>]
+
+Bug #7698 -- People like to slice with '0' as the high-water mark.
+>>> Item.objects.all()[0:0]
+[]
+
"""}
diff --git a/tests/regressiontests/utils/datastructures.py b/tests/regressiontests/utils/datastructures.py
index 52bf81a9e0..5d31d21318 100644
--- a/tests/regressiontests/utils/datastructures.py
+++ b/tests/regressiontests/utils/datastructures.py
@@ -44,8 +44,15 @@
>>> d.keys()
[2, 1]
>>> real_dict = dict(tuples)
->>> real_dict.values()
+>>> sorted(real_dict.values())
['one', 'second-two']
->>> d.values()
+>>> d.values() # Here the order of SortedDict values *is* what we are testing
['second-two', 'one']
-""" \ No newline at end of file
+"""
+
+# Python 2.3 doesn't have sorted()
+try:
+ sorted
+except NameError:
+ from django.utils.itercompat import sorted
+ \ No newline at end of file
diff --git a/tests/regressiontests/utils/itercompat.py b/tests/regressiontests/utils/itercompat.py
new file mode 100644
index 0000000000..ad79cffcd1
--- /dev/null
+++ b/tests/regressiontests/utils/itercompat.py
@@ -0,0 +1,15 @@
+"""
+# Tests of the utils itercompat library.
+
+>>> from django.utils.itercompat import sorted as compat_sorted
+
+# Check the replacement version of sorted
+>>> x = [5,1,4,2,3]
+>>> y = compat_sorted(x)
+>>> print y
+[1, 2, 3, 4, 5]
+
+>>> print x
+[5, 1, 4, 2, 3]
+
+""" \ No newline at end of file
diff --git a/tests/regressiontests/utils/tests.py b/tests/regressiontests/utils/tests.py
index 6fc645505b..cd4762e02f 100644
--- a/tests/regressiontests/utils/tests.py
+++ b/tests/regressiontests/utils/tests.py
@@ -8,12 +8,14 @@ from django.utils import html, checksums
import timesince
import datastructures
+import itercompat
from decorators import DecoratorFromMiddlewareTests
# Extra tests
__test__ = {
'timesince': timesince,
'datastructures': datastructures,
+ 'itercompat': itercompat,
}
class TestUtilsHtml(TestCase):