From 2624f4ea563e8139c7f19a20d9b723d39b1e6ac1 Mon Sep 17 00:00:00 2001 From: Brian Rosner Date: Mon, 14 Jul 2008 05:04:57 +0000 Subject: [PATCH] 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 --- AUTHORS | 2 +- django/conf/locale/it/LC_MESSAGES/django.mo | Bin 66449 -> 66524 bytes django/conf/locale/it/LC_MESSAGES/django.po | 267 +++++++++--------- django/core/files/uploadedfile.py | 2 +- django/core/management/__init__.py | 29 ++ django/core/management/commands/syncdb.py | 14 +- django/db/models/fields/__init__.py | 15 +- django/db/models/query.py | 13 +- django/db/models/sql/query.py | 9 +- django/http/multipartparser.py | 55 ++-- django/newforms/fields.py | 2 + django/utils/itercompat.py | 5 + docs/contributing.txt | 5 + docs/db-api.txt | 12 + docs/testing.txt | 8 +- docs/tutorial01.txt | 5 +- tests/modeltests/basic/models.py | 8 +- tests/modeltests/model_forms/models.py | 2 +- tests/modeltests/or_lookups/models.py | 5 + tests/modeltests/test_client/models.py | 8 +- tests/modeltests/test_client/urls.py | 1 + tests/modeltests/test_client/views.py | 6 + .../management/commands/app_command.py | 5 + .../management/commands/base_command.py | 11 + .../management/commands/label_command.py | 5 + .../management/commands/noargs_command.py | 5 + tests/regressiontests/admin_scripts/tests.py | 185 +++++++++--- tests/regressiontests/defaultfilters/tests.py | 6 + tests/regressiontests/file_uploads/tests.py | 2 +- .../model_inheritance_regress/models.py | 6 + tests/regressiontests/queries/models.py | 15 + tests/regressiontests/utils/datastructures.py | 13 +- tests/regressiontests/utils/itercompat.py | 15 + tests/regressiontests/utils/tests.py | 2 + 34 files changed, 503 insertions(+), 240 deletions(-) create mode 100644 tests/regressiontests/utils/itercompat.py 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 ant9000@netwise.it - Florian Apolloner + Florian Apolloner arien David Ascher Jökull Sólberg Auðunsson diff --git a/django/conf/locale/it/LC_MESSAGES/django.mo b/django/conf/locale/it/LC_MESSAGES/django.mo index 683680bb7dc982c20f77c4c41d9e1fc78d225959..e96764a0a85ec3cd622fc777fd5e4bdc7ce3f353 100644 GIT binary patch delta 21082 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 delta 21013 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 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 \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 change " "password form." @@ -1173,19 +1181,19 @@ msgstr "" "Usare '[algo]$[salt]$[hexdigest]' oppure la maschera " "di cambio password." -#: 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." - ) + 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]) - self._position = value - - 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 = """BlinkMalcolm Gladwell""" 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 ' 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=, 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=, options=[('pythonpath', None), ('settings', None), ('traceback', None)]") self.assertOutput(out, "EXECUTE:AppCommand app=, 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_中文_Orl\u00e9ans.jpg'), 'w+b') + file3 = open(os.path.join(tdir, u'test_中文_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]) +[, ] + +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):