diff --git a/AUTHORS b/AUTHORS index bd7ef7770d..564cd0a139 100644 --- a/AUTHORS +++ b/AUTHORS @@ -42,6 +42,7 @@ people who have submitted patches, reported bugs, added translations, helped answer newbie questions, and generally made Django that much better: adurdin@gmail.com + alang@bright-green.com Daniel Alves Barbosa de Oliveira Vaz Andreas andy@jadedplanet.net @@ -150,6 +151,7 @@ answer newbie questions, and generally made Django that much better: Manuzhai Petar Marić Nuno Mariz + marijn@metronomo.cl mark@junklight.com Yasushi Masuda mattycakes@gmail.com @@ -163,6 +165,7 @@ answer newbie questions, and generally made Django that much better: Robin Munn Robert Myers Nebojša Dorđević + Gopal Narayanan Fraser Nevett Sam Newman Neal Norwitz @@ -185,9 +188,11 @@ answer newbie questions, and generally made Django that much better: Brian Ray remco@diji.biz rhettg@gmail.com + Henrique Romano Armin Ronacher Oliver Rutherfurd Ivan Sagalaev (Maniac) + Vinay Sajip David Schein scott@staplefish.com serbaut@gmail.com @@ -211,6 +216,7 @@ answer newbie questions, and generally made Django that much better: torne-django@wolfpuppy.org.uk Karen Tracey Makoto Tsuyuki + tt@gurgle.no Amit Upadhyay Geert Vanderkelen viestards.lists@gmail.com diff --git a/django/bin/make-messages.py b/django/bin/make-messages.py index 2a0cbe41be..3e5acb70cb 100755 --- a/django/bin/make-messages.py +++ b/django/bin/make-messages.py @@ -81,7 +81,7 @@ def make_messages(): src = pythonize_re.sub('\n#', src) open(os.path.join(dirpath, '%s.py' % file), "wb").write(src) thefile = '%s.py' % file - cmd = 'xgettext %s -d %s -L Perl --keyword=gettext_noop --keyword=gettext_lazy --keyword=ngettext_lazy --from-code UTF-8 -o - "%s"' % ( + cmd = 'xgettext %s -d %s -L Perl --keyword=gettext_noop --keyword=gettext_lazy --keyword=ngettext_lazy:1,2 --from-code UTF-8 -o - "%s"' % ( os.path.exists(potfile) and '--omit-header' or '', domain, os.path.join(dirpath, thefile)) (stdin, stdout, stderr) = os.popen3(cmd, 'b') msgs = stdout.read() @@ -103,7 +103,7 @@ def make_messages(): open(os.path.join(dirpath, '%s.py' % file), "wb").write(templatize(src)) thefile = '%s.py' % file if verbose: sys.stdout.write('processing file %s in %s\n' % (file, dirpath)) - cmd = 'xgettext %s -d %s -L Python --keyword=gettext_noop --keyword=gettext_lazy --keyword=ngettext_lazy --keyword=ugettext_noop --keyword=ugettext_lazy --keyword=ungettext_lazy:1,2 --from-code UTF-8 -o - "%s"' % ( + cmd = 'xgettext %s -d %s -L Python --keyword=gettext_noop --keyword=gettext_lazy --keyword=ngettext_lazy:1,2 --keyword=ugettext_noop --keyword=ugettext_lazy --keyword=ungettext_lazy:1,2 --from-code UTF-8 -o - "%s"' % ( os.path.exists(potfile) and '--omit-header' or '', domain, os.path.join(dirpath, thefile)) (stdin, stdout, stderr) = os.popen3(cmd, 'b') msgs = stdout.read() diff --git a/django/bin/profiling/gather_profile_stats.py b/django/bin/profiling/gather_profile_stats.py index 852f16229d..c0844930e9 100644 --- a/django/bin/profiling/gather_profile_stats.py +++ b/django/bin/profiling/gather_profile_stats.py @@ -22,7 +22,7 @@ def gather_stats(p): else: continue print "Processing %s" % f - if profiles.has_key(path): + if path in profiles: profiles[path].add(prof) else: profiles[path] = prof diff --git a/django/conf/locale/el/LC_MESSAGES/django.mo b/django/conf/locale/el/LC_MESSAGES/django.mo index 4a7d8e41f0..a048d87976 100644 Binary files a/django/conf/locale/el/LC_MESSAGES/django.mo and b/django/conf/locale/el/LC_MESSAGES/django.mo differ diff --git a/django/conf/locale/el/LC_MESSAGES/django.po b/django/conf/locale/el/LC_MESSAGES/django.po index 06099eb9da..d041a275e5 100644 --- a/django/conf/locale/el/LC_MESSAGES/django.po +++ b/django/conf/locale/el/LC_MESSAGES/django.po @@ -10,7 +10,7 @@ msgstr "" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2006-05-16 10:13+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: panos laganakos \n" +"Last-Translator: Orestis Markou \n" "Language-Team: Greek\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" @@ -164,9 +164,9 @@ msgid "" "\n" "%(text)s" msgstr "" -"Αυτο το σχόλιο σημειώθηκε απο %(χρήστη)ες\n" +"Αυτο το σχόλιο σημειώθηκε απο %(user)s\n" "\n" -"%(κείμενο)α" +"%(text)s" #: contrib/comments/models.py:265 msgid "flag date" diff --git a/django/conf/locale/no/LC_MESSAGES/django.mo b/django/conf/locale/no/LC_MESSAGES/django.mo index 1dc12ae50e..7048e3079d 100644 Binary files a/django/conf/locale/no/LC_MESSAGES/django.mo and b/django/conf/locale/no/LC_MESSAGES/django.mo differ diff --git a/django/conf/locale/no/LC_MESSAGES/django.po b/django/conf/locale/no/LC_MESSAGES/django.po index 85b7d49d09..ea388cfd81 100644 --- a/django/conf/locale/no/LC_MESSAGES/django.po +++ b/django/conf/locale/no/LC_MESSAGES/django.po @@ -1,4 +1,4 @@ -# SOME DESCRIPTIVE TITLE. +# translation of django.po to # Copyright (C) 2005 and beyond # This file is distributed under the same license as the PACKAGE package. # Espen Grindhaug , Nov 2005. @@ -6,74 +6,73 @@ # msgid "" msgstr "" -"Project-Id-Version: PACKAGE VERSION\n" +"Project-Id-Version: django\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2006-05-16 10:12+0200\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: Espen Grndhaug \n" -"Language-Team: Norwegian\n" +"PO-Revision-Date: 2007-04-27 06:48+0200\n" +"Last-Translator: \n" +"Language-Team: \n" "MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" +"Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"X-Generator: KBabel 1.11.4\n" #: contrib/comments/models.py:67 contrib/comments/models.py:166 -#, fuzzy msgid "object ID" -msgstr "Vis objekt ID" +msgstr "objekt ID" #: contrib/comments/models.py:68 msgid "headline" -msgstr "" +msgstr "overskrift" #: contrib/comments/models.py:69 contrib/comments/models.py:90 #: contrib/comments/models.py:167 -#, fuzzy msgid "comment" -msgstr "innhold" +msgstr "kommentar" #: contrib/comments/models.py:70 msgid "rating #1" -msgstr "" +msgstr "rangering #1 " #: contrib/comments/models.py:71 msgid "rating #2" -msgstr "" +msgstr "rangering #2" #: contrib/comments/models.py:72 msgid "rating #3" -msgstr "" +msgstr "rangering #3" #: contrib/comments/models.py:73 msgid "rating #4" -msgstr "" +msgstr "rangering #4" #: contrib/comments/models.py:74 msgid "rating #5" -msgstr "" +msgstr "rangering #5" #: contrib/comments/models.py:75 msgid "rating #6" -msgstr "" +msgstr "rangering #6" #: contrib/comments/models.py:76 msgid "rating #7" -msgstr "" +msgstr "rangering #7" #: contrib/comments/models.py:77 msgid "rating #8" -msgstr "" +msgstr "rangering #8" #: contrib/comments/models.py:82 msgid "is valid rating" -msgstr "" +msgstr "er gyldig rangering" #: contrib/comments/models.py:83 contrib/comments/models.py:169 msgid "date/time submitted" -msgstr "" +msgstr "dato/tid for innsendelse" #: contrib/comments/models.py:84 contrib/comments/models.py:170 msgid "is public" -msgstr "" +msgstr "er tilgjengelig for alle" #: contrib/comments/models.py:85 contrib/admin/views/doc.py:289 msgid "IP address" @@ -81,23 +80,21 @@ msgstr "IP adresse" #: contrib/comments/models.py:86 msgid "is removed" -msgstr "" +msgstr "er fjernet" #: contrib/comments/models.py:86 msgid "" "Check this box if the comment is inappropriate. A \"This comment has been " "removed\" message will be displayed instead." -msgstr "" +msgstr "Aktiver denne avkryssningsboksen hvis kommentaren er upasende. Beskjeden \"Denne kommentaren er blitt fjernet\" vil bli vist istedet." #: contrib/comments/models.py:91 -#, fuzzy msgid "comments" -msgstr "innhold" +msgstr "kommentarer" #: contrib/comments/models.py:131 contrib/comments/models.py:207 -#, fuzzy msgid "Content object" -msgstr "innholds type" +msgstr "innholdsobjekt" #: contrib/comments/models.py:159 #, python-format @@ -108,101 +105,97 @@ msgid "" "\n" "http://%(domain)s%(url)s" msgstr "" +"Sendt av %(user)s på %(date)s\n" +"\n" +"%(comment)s\n" +"\n" +"http://%(domain)s%(url)s" #: contrib/comments/models.py:168 -#, fuzzy msgid "person's name" -msgstr "fornavn" +msgstr "personens navn" #: contrib/comments/models.py:171 -#, fuzzy msgid "ip address" msgstr "IP adresse" #: contrib/comments/models.py:173 msgid "approved by staff" -msgstr "" +msgstr "godkjent av moderator" #: contrib/comments/models.py:176 -#, fuzzy msgid "free comment" -msgstr "tillat kommentarer" +msgstr "åpen kommentar" #: contrib/comments/models.py:177 -#, fuzzy msgid "free comments" -msgstr "tillat kommentarer" +msgstr "åpne kommentarer" #: contrib/comments/models.py:233 msgid "score" -msgstr "" +msgstr "poeng" #: contrib/comments/models.py:234 -#, fuzzy msgid "score date" -msgstr "utløpsdato" +msgstr "poeng dato" #: contrib/comments/models.py:237 msgid "karma score" -msgstr "" +msgstr "karma poeng" #: contrib/comments/models.py:238 msgid "karma scores" -msgstr "" +msgstr "karma poeng" #: contrib/comments/models.py:242 #, python-format msgid "%(score)d rating by %(user)s" -msgstr "" +msgstr "%(score)d rangering av %(user)s" #: contrib/comments/models.py:258 -#, fuzzy, python-format +#, python-format msgid "" "This comment was flagged by %(user)s:\n" "\n" "%(text)s" msgstr "" -"Denne kommentaren er skrevet med lite omtanke:\n" +"Denne kommentaren er flagget av %(user)s:\n" "\n" "%(text)s" #: contrib/comments/models.py:265 -#, fuzzy msgid "flag date" -msgstr "flatside" +msgstr "flagg dato" #: contrib/comments/models.py:268 -#, fuzzy msgid "user flag" -msgstr "Bruker" +msgstr "brukerflag" #: contrib/comments/models.py:269 -#, fuzzy msgid "user flags" -msgstr "Brukere" +msgstr "brukerflag" #: contrib/comments/models.py:273 #, python-format msgid "Flag by %r" -msgstr "" +msgstr "Flagg med %r" #: contrib/comments/models.py:278 -#, fuzzy msgid "deletion date" -msgstr "sesjon data" +msgstr "fjernet dato" #: contrib/comments/models.py:280 msgid "moderator deletion" -msgstr "" +msgstr "fjernet av moderator" #: contrib/comments/models.py:281 msgid "moderator deletions" -msgstr "" +msgstr "fjernet av moderator" #: contrib/comments/models.py:285 #, python-format msgid "Moderator deletion by %r" -msgstr "" +msgstr "Fjernet av moderator med %r" #: contrib/comments/views/karma.py:19 msgid "Anonymous users cannot vote" @@ -214,16 +207,14 @@ msgstr "Ikke gyldig kommentar ID" #: contrib/comments/views/karma.py:25 msgid "No voting for yourself" -msgstr "Du kan ikke stemme selv" +msgstr "Du kan ikke stemme på deg selv" #: contrib/comments/views/comments.py:28 -#, fuzzy -msgid "" -"This rating is required because you've entered at least one other rating." -msgstr "Denne bla bla.." +msgid "This rating is required because you've entered at least one other rating." +msgstr "Denne rangeringen er påkrevd fordi du har rangert en eller flere ting fra før " #: contrib/comments/views/comments.py:112 -#, fuzzy, python-format +#, python-format msgid "" "This comment was posted by a user who has posted fewer than %(count)s " "comment:\n" @@ -246,13 +237,13 @@ msgstr[1] "" "%(text)s" #: contrib/comments/views/comments.py:117 -#, fuzzy, python-format +#, python-format msgid "" "This comment was posted by a sketchy user:\n" "\n" "%(text)s" msgstr "" -"Denne kommentaren er skrevet med lite omtanke:\n" +"Denne kommentaren er skrevet av en upålitelig bruker:\n" "\n" "%(text)s" @@ -281,8 +272,7 @@ msgstr "Skjemaet hadde en ugyldig verdi - objekt IDen var ugyldig" #: contrib/comments/views/comments.py:257 #: contrib/comments/views/comments.py:321 msgid "The comment form didn't provide either 'preview' or 'post'" -msgstr "" -"Kommentar skjemaet returnerte ikke et 'forhåndsvisning' eller 'post' objekt" +msgstr "Kommentar skjemaet returnerte ikke et 'forhåndsvisning' eller 'post' objekt" #: contrib/comments/templates/comments/form.html:6 #: contrib/comments/templates/comments/form.html:8 @@ -296,9 +286,8 @@ msgid "Password:" msgstr "Passord:" #: contrib/comments/templates/comments/form.html:6 -#, fuzzy msgid "Forgotten your password?" -msgstr "Endre passord" +msgstr "Har du glemt passordet ditt ?" #: contrib/comments/templates/comments/form.html:8 #: contrib/admin/templates/admin/object_history.html:3 @@ -323,38 +312,35 @@ msgstr "Log ut" #: contrib/comments/templates/comments/form.html:12 msgid "Ratings" -msgstr "" +msgstr "Rangeringer" #: contrib/comments/templates/comments/form.html:12 #: contrib/comments/templates/comments/form.html:23 msgid "Required" -msgstr "" +msgstr "Påkrevd" #: contrib/comments/templates/comments/form.html:12 #: contrib/comments/templates/comments/form.html:23 msgid "Optional" -msgstr "" +msgstr "Valgfri" #: contrib/comments/templates/comments/form.html:23 msgid "Post a photo" -msgstr "" +msgstr "Send et foto" #: contrib/comments/templates/comments/form.html:27 #: contrib/comments/templates/comments/freeform.html:5 -#, fuzzy msgid "Comment:" -msgstr "tillat kommentarer" +msgstr "Kommentar:" #: contrib/comments/templates/comments/form.html:32 #: contrib/comments/templates/comments/freeform.html:9 -#, fuzzy msgid "Preview comment" -msgstr "tillat kommentarer" +msgstr "Forhåndvis kommentar" #: contrib/comments/templates/comments/freeform.html:4 -#, fuzzy msgid "Your name:" -msgstr "brukernavn" +msgstr "Ditt navn:" #: contrib/admin/filterspecs.py:40 #, python-format @@ -416,7 +402,7 @@ msgstr "objekt repr" #: contrib/admin/models.py:21 msgid "action flag" -msgstr "handlings flagg" +msgstr "handlingsflagg" #: contrib/admin/models.py:22 msgid "change message" @@ -424,11 +410,11 @@ msgstr "endre melding" #: contrib/admin/models.py:25 msgid "log entry" -msgstr "logg notis" +msgstr "logg post" #: contrib/admin/models.py:26 msgid "log entries" -msgstr "logg innlegg" +msgstr "logg poster" #: contrib/admin/templatetags/admin_list.py:228 msgid "All dates" @@ -440,8 +426,8 @@ msgid "" "Please enter a correct username and password. Note that both fields are case-" "sensitive." msgstr "" -"Vær snill å angi korrekt brukernavn og passord. La merke til at små og " -"store bokstaver er betraktet ulik." +"Vennligst angi korrekt brukernavn og passord. Merk at små og " +"store bokstaver er betraktet ulikt." #: contrib/admin/views/decorators.py:23 #: contrib/admin/templates/admin/login.html:25 @@ -452,18 +438,15 @@ msgstr "Logg inn" msgid "" "Please log in again, because your session has expired. Don't worry: Your " "submission has been saved." -msgstr "" -"Du må logge inn igjen, fordi sesjonen din har gått ut på dato, men ikke ikke " -"bekjymr deg informasjonen du sendte ble lagret." +msgstr "Du må logge inn igjen, fordi økten din har gått ut, men innlegget ditt ble lagret." #: contrib/admin/views/decorators.py:68 msgid "" "Looks like your browser isn't configured to accept cookies. Please enable " "cookies, reload this page, and try again." msgstr "" -"Det ser ut som om nettleseren din ikke vill ta i mot informasjonskapsler " -"('cookies'). Vennligst omkonfigurer nettleseren din, last siden på ny og " -"prøv igjen." +"Det ser ut som om nettleseren din ikke støtter informasjonskapsler " +"('cookies'). Vennligst konfigurer nettleseren din, og prøv igjen." #: contrib/admin/views/decorators.py:82 msgid "Usernames cannot contain the '@' character." @@ -500,7 +483,7 @@ msgstr "Ny %s" #: contrib/admin/views/main.py:336 #, python-format msgid "Added %s." -msgstr "Lagt til %s" +msgstr "La til %s" #: contrib/admin/views/main.py:336 contrib/admin/views/main.py:338 #: contrib/admin/views/main.py:340 @@ -528,8 +511,7 @@ msgstr "%(name)s \"%(obj)s\" ble endret." #: contrib/admin/views/main.py:354 #, python-format -msgid "" -"The %(name)s \"%(obj)s\" was added successfully. You may edit it again below." +msgid "The %(name)s \"%(obj)s\" was added successfully. You may edit it again below." msgstr "%(name)s \"%(obj)s\" ble endret. Du kan endre det igjen under." #: contrib/admin/views/main.py:392 @@ -742,8 +724,8 @@ msgid "" "There's been an error. It's been reported to the site administrators via e-" "mail and should be fixed shortly. Thanks for your patience." msgstr "" -"Det har vært en feil. Feilen er blitt rapportert til administrator via e-" -"mail, og vill bli fikset snart. Takk for din tålmodighet." +"Det har oppstått en feil. Feilen er blitt rapportert til administrator via e-" +"post, og vil bli fikset snart. Takk for din tålmodighet." #: contrib/admin/templates/admin/404.html:4 #: contrib/admin/templates/admin/404.html:8 @@ -909,7 +891,7 @@ msgstr "Tilbakestill mitt passord" #: contrib/admin/templates/registration/logged_out.html:8 msgid "Thanks for spending some quality time with the Web site today." -msgstr "Takk for å bruke tid på internett siden i dag." +msgstr "Takk for at du valgte å bruke kvalitetstid på nettstedet idag." #: contrib/admin/templates/registration/logged_out.html:10 msgid "Log in again" @@ -954,8 +936,7 @@ msgstr "Endre passord" #: contrib/admin/templates/registration/password_reset_email.html:2 msgid "You're receiving this e-mail because you requested a password reset" -msgstr "" -"Du har mottatt denne e-posten fordi du ba om å tilbakestille passordet ditt" +msgstr "Du har mottatt denne e-posten fordi du ba om å tilbakestille passordet ditt" #: contrib/admin/templates/registration/password_reset_email.html:3 #, python-format @@ -1002,6 +983,12 @@ msgid "" "as \"internal\" (talk to your system administrator if you aren't sure if\n" "your computer is \"internal\").

\n" msgstr "" +"\n" +"

For å installere bokmerker, dra linken til verktøylinja\n" +"for bokmerker, eller høyreklikk og legg til i bokmerker. Nå kan du du velge\n" +"bokmerket fra hvilken som helst side på nettstedet. Noen av disse\n" +"bokmerkene krever at datamaskinen du bruker er markert som \"intern\"\n" +"(kontakt din systemadministrator hvis du er usikker på om maskinen din er \"intern\").

\n" #: contrib/admin/templates/admin_doc/bookmarklets.html:19 msgid "Documentation for this page" @@ -1033,8 +1020,7 @@ msgstr "Endre dette objektet (åpnes i dette vinduet)" #: contrib/admin/templates/admin_doc/bookmarklets.html:26 msgid "Jumps to the admin page for pages that represent a single object." -msgstr "" -"Hopp til administrasjonsiden for sidene som representerer et enkelt objekt." +msgstr "Hopp til administrasjonsiden for sidene som representerer et enkelt objekt." #: contrib/admin/templates/admin_doc/bookmarklets.html:28 msgid "Edit this object (new window)" @@ -1069,7 +1055,7 @@ msgid "" "This should be an absolute path, excluding the domain name. Example: '/" "events/search/'." msgstr "" -"Denne burde vær en fullstendig sti, uten domene navnet. Foreksempel: '/" +"Dette burde vært en fullstendig sti, uten domene navnet. Foreksempel: '/" "nyheter/les/" #: contrib/redirects/models.py:9 @@ -1081,7 +1067,7 @@ msgid "" "This can be either an absolute path (as above) or a full URL starting with " "'http://'." msgstr "" -"Denne kan enten være en fullstendig sti (som over), eller en hel " +"Dette kan enten være en fullstendig sti (som over), eller en hel " "internettadresse som starter med 'http://'" #: contrib/redirects/models.py:12 @@ -1093,10 +1079,8 @@ msgid "redirects" msgstr "omadresserelser" #: contrib/flatpages/models.py:8 -msgid "" -"Example: '/about/contact/'. Make sure to have leading and trailing slashes." -msgstr "" -"Eksempel: '/om/kontakt/'. Vær sikker på at du har en skråstrek forran og bak." +msgid "Example: '/about/contact/'. Make sure to have leading and trailing slashes." +msgstr "Eksempel: '/om/kontakt/'. Vær sikker på at du har en skråstrek forran og bak." #: contrib/flatpages/models.py:9 msgid "title" @@ -1186,7 +1170,7 @@ msgstr "passord" #: contrib/auth/models.py:59 msgid "Use '[algo]$[salt]$[hexdigest]'" -msgstr "" +msgstr "Bruk '[algo]$[salt]$[hexdigest]'" #: contrib/auth/models.py:60 msgid "staff status" @@ -1256,7 +1240,7 @@ msgstr "Melding" msgid "" "Your Web browser doesn't appear to have cookies enabled. Cookies are " "required for logging in." -msgstr "" +msgstr "Din nettleser ser ikkeut til å støtte informasjonskapsler (cookies). Informasjonskapsler er påkrevd for å logge inn." #: contrib/contenttypes/models.py:25 msgid "python model class name" @@ -1698,8 +1682,7 @@ msgstr "Internettadressen %s peker ikke til et godkjent bilde." #: core/validators.py:159 #, python-format msgid "Phone numbers must be in XXX-XXX-XXXX format. \"%s\" is invalid." -msgstr "" -"Telefon nummeret må være i XXX-XXX-XXXX format. \"%s\" er ikke godkjent." +msgstr "Telefon nummeret må være i XXX-XXX-XXXX format. \"%s\" er ikke godkjent." #: core/validators.py:167 #, python-format @@ -1784,30 +1767,26 @@ msgstr "Vennligst skriv inn et godkjent desimal tall." #: core/validators.py:349 #, python-format msgid "Please enter a valid decimal number with at most %s total digit." -msgid_plural "" -"Please enter a valid decimal number with at most %s total digits." +msgid_plural "Please enter a valid decimal number with at most %s total digits." msgstr[0] "Skriv inn et desimal tall med maksimum %s total antall tall." msgstr[1] "Skriv inn et desimal tall med maksimum %s total antall tall." #: core/validators.py:352 #, python-format msgid "Please enter a valid decimal number with at most %s decimal place." -msgid_plural "" -"Please enter a valid decimal number with at most %s decimal places." +msgid_plural "Please enter a valid decimal number with at most %s decimal places." msgstr[0] "Skriv inn et desimal tall med maksimum %s tall bak komma. " msgstr[1] "Skriv inn et desimal tall med maksimum %s tall bak komma. " #: core/validators.py:362 #, python-format msgid "Make sure your uploaded file is at least %s bytes big." -msgstr "" -"Vær sikker på at fila du prøver å laste opp er minimum %s bytes stor." +msgstr "Vær sikker på at fila du prøver å laste opp er minimum %s bytes stor." #: core/validators.py:363 #, python-format msgid "Make sure your uploaded file is at most %s bytes big." -msgstr "" -"Vær sikker på at fila du prøver å laste opp er maksimum %s bytes stor." +msgstr "Vær sikker på at fila du prøver å laste opp er maksimum %s bytes stor." #: core/validators.py:376 msgid "The format for this field is wrong." @@ -1824,8 +1803,7 @@ msgstr "Klarte ikke å motta noe fra %s." #: core/validators.py:429 #, python-format -msgid "" -"The URL %(url)s returned the invalid Content-Type header '%(contenttype)s'." +msgid "The URL %(url)s returned the invalid Content-Type header '%(contenttype)s'." msgstr "" "Internettadressen %(url)s returnerte en ikke godkjent Content-Type '%" "(contenttype)s'." @@ -1926,16 +1904,13 @@ msgid "Separate multiple IDs with commas." msgstr "Separer Id-ene med kommaer." #: db/models/fields/related.py:581 -msgid "" -"Hold down \"Control\", or \"Command\" on a Mac, to select more than one." -msgstr "" -"Hold nede \"Control\", eller \"Command\" på en Mac, for å velge mere enn en." +msgid "Hold down \"Control\", or \"Command\" on a Mac, to select more than one." +msgstr "Hold nede \"Control\", eller \"Command\" på en Mac, for å velge mere enn en." #: db/models/fields/related.py:625 #, 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." +msgid_plural "Please enter valid %(self)s IDs. The values %(value)r are invalid." msgstr[0] "Skriv inn gyldige %(self)s ID-er. Verdien %(value)r er ikke gyldig." msgstr[1] "Skriv inn gyldige %(self)s ID-er. Verdiene %(value)r er ikke gyldige." diff --git a/django/conf/locale/no/LC_MESSAGES/djangojs.mo b/django/conf/locale/no/LC_MESSAGES/djangojs.mo index 4b23aba4e0..da2854f72e 100644 Binary files a/django/conf/locale/no/LC_MESSAGES/djangojs.mo and b/django/conf/locale/no/LC_MESSAGES/djangojs.mo differ diff --git a/django/conf/locale/no/LC_MESSAGES/djangojs.po b/django/conf/locale/no/LC_MESSAGES/djangojs.po index c6087646e0..ab3d3b965d 100644 --- a/django/conf/locale/no/LC_MESSAGES/djangojs.po +++ b/django/conf/locale/no/LC_MESSAGES/djangojs.po @@ -1,19 +1,20 @@ -# SOME DESCRIPTIVE TITLE. +# translation of djangojs.po to # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # Espen Grindhaug , 2006. # msgid "" msgstr "" -"Project-Id-Version: PACKAGE VERSION\n" +"Project-Id-Version: djangojs\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2005-12-09 11:51+0100\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: Espen Grindhaug \n" -"Language-Team: no\n" +"PO-Revision-Date: 2007-04-27 06:51+0200\n" +"Last-Translator: \n" +"Language-Team: \n" "MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" +"Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"X-Generator: KBabel 1.11.4\n" #: contrib/admin/media/js/SelectFilter2.js:33 #, perl-format @@ -21,7 +22,6 @@ msgid "Available %s" msgstr "%s er tilgjengelige" #: contrib/admin/media/js/SelectFilter2.js:41 -#, fuzzy msgid "Choose all" msgstr "Velg alle" @@ -116,3 +116,4 @@ msgstr "I går" #: contrib/admin/media/js/admin/DateTimeShortcuts.js:164 msgid "Tomorrow" msgstr "I morgen" + diff --git a/django/conf/urls/defaults.py b/django/conf/urls/defaults.py index 49bc176ef3..13a74331d6 100644 --- a/django/conf/urls/defaults.py +++ b/django/conf/urls/defaults.py @@ -11,9 +11,10 @@ def patterns(prefix, *args): pattern_list = [] for t in args: if isinstance(t, (list, tuple)): - pattern_list.append(url(prefix=prefix, *t)) - else: - pattern_list.append(t) + t = url(prefix=prefix, *t) + elif isinstance(t, RegexURLPattern): + t.add_prefix(prefix) + pattern_list.append(t) return pattern_list def url(regex, view, kwargs=None, name=None, prefix=''): diff --git a/django/contrib/admin/templatetags/admin_modify.py b/django/contrib/admin/templatetags/admin_modify.py index e708b876bd..f9cad005d5 100644 --- a/django/contrib/admin/templatetags/admin_modify.py +++ b/django/contrib/admin/templatetags/admin_modify.py @@ -74,7 +74,7 @@ class FieldWidgetNode(template.Node): self.bound_field_var = bound_field_var def get_nodelist(cls, klass): - if not cls.nodelists.has_key(klass): + if klass not in cls.nodelists: try: field_class_name = klass.__name__ template_name = "widget/%s.html" % class_name_to_underscored(field_class_name) diff --git a/django/contrib/admin/views/auth.py b/django/contrib/admin/views/auth.py index bea1f8533c..c6ad0c3a95 100644 --- a/django/contrib/admin/views/auth.py +++ b/django/contrib/admin/views/auth.py @@ -17,7 +17,7 @@ def user_add_stage(request): if not errors: new_user = manipulator.save(new_data) msg = _('The %(name)s "%(obj)s" was added successfully.') % {'name': 'user', 'obj': new_user} - if request.POST.has_key("_addanother"): + if "_addanother" in request.POST: request.user.message_set.create(message=msg) return HttpResponseRedirect(request.path) else: @@ -29,7 +29,7 @@ def user_add_stage(request): return render_to_response('admin/auth/user/add_form.html', { 'title': _('Add user'), 'form': form, - 'is_popup': request.REQUEST.has_key('_popup'), + 'is_popup': '_popup' in request.REQUEST, 'add': True, 'change': False, 'has_delete_permission': False, @@ -63,7 +63,7 @@ def user_change_password(request, id): return render_to_response('admin/auth/user/change_password.html', { 'title': _('Change password: %s') % escape(user.username), 'form': form, - 'is_popup': request.REQUEST.has_key('_popup'), + 'is_popup': '_popup' in request.REQUEST, 'add': True, 'change': False, 'has_delete_permission': False, diff --git a/django/contrib/admin/views/decorators.py b/django/contrib/admin/views/decorators.py index bdd8257b2e..5389ca4dff 100644 --- a/django/contrib/admin/views/decorators.py +++ b/django/contrib/admin/views/decorators.py @@ -12,7 +12,7 @@ LOGIN_FORM_KEY = 'this_is_the_login_form' def _display_login_form(request, error_message=''): request.session.set_test_cookie() - if request.POST and request.POST.has_key('post_data'): + if request.POST and 'post_data' in request.POST: # User has failed login BUT has previously saved post data. post_data = request.POST['post_data'] elif request.POST: @@ -48,7 +48,7 @@ def staff_member_required(view_func): def _checklogin(request, *args, **kwargs): if request.user.is_authenticated() and request.user.is_staff: # The user is valid. Continue to the admin page. - if request.POST.has_key('post_data'): + if 'post_data' in request.POST: # User must have re-authenticated through a different window # or tab. request.POST = _decode_post_data(request.POST['post_data']) @@ -57,7 +57,7 @@ def staff_member_required(view_func): assert hasattr(request, 'session'), "The Django admin requires session middleware to be installed. Edit your MIDDLEWARE_CLASSES setting to insert 'django.contrib.sessions.middleware.SessionMiddleware'." # If this isn't already the login page, display it. - if not request.POST.has_key(LOGIN_FORM_KEY): + if LOGIN_FORM_KEY not in request.POST: if request.POST: message = _("Please log in again, because your session has expired. Don't worry: Your submission has been saved.") else: @@ -90,9 +90,9 @@ def staff_member_required(view_func): if user.is_active and user.is_staff: login(request, user) # TODO: set last_login with an event. - if request.POST.has_key('post_data'): + if 'post_data' in request.POST: post_data = _decode_post_data(request.POST['post_data']) - if post_data and not post_data.has_key(LOGIN_FORM_KEY): + if post_data and LOGIN_FORM_KEY not in post_data: # overwrite request.POST with the saved post_data, and continue request.POST = post_data request.user = user diff --git a/django/contrib/admin/views/main.py b/django/contrib/admin/views/main.py index 0e962adf18..5edc1fc19d 100644 --- a/django/contrib/admin/views/main.py +++ b/django/contrib/admin/views/main.py @@ -257,17 +257,17 @@ def add_stage(request, app_label, model_name, show_delete=False, form_url='', po msg = _('The %(name)s "%(obj)s" was added successfully.') % {'name': opts.verbose_name, 'obj': new_object} # Here, we distinguish between different save types by checking for # the presence of keys in request.POST. - if request.POST.has_key("_continue"): + if "_continue" in request.POST: request.user.message_set.create(message=msg + ' ' + _("You may edit it again below.")) - if request.POST.has_key("_popup"): + if "_popup" in request.POST: post_url_continue += "?_popup=1" return HttpResponseRedirect(post_url_continue % pk_value) - if request.POST.has_key("_popup"): + if "_popup" in request.POST: if type(pk_value) is str: # Quote if string, so JavaScript doesn't think it's a variable. pk_value = '"%s"' % pk_value.replace('"', '\\"') return HttpResponse('' % \ (pk_value, str(new_object).replace('"', '\\"'))) - elif request.POST.has_key("_addanother"): + elif "_addanother" in request.POST: request.user.message_set.create(message=msg + ' ' + (_("You may add another %s below.") % opts.verbose_name)) return HttpResponseRedirect(request.path) else: @@ -288,7 +288,7 @@ def add_stage(request, app_label, model_name, show_delete=False, form_url='', po c = template.RequestContext(request, { 'title': _('Add %s') % opts.verbose_name, 'form': form, - 'is_popup': request.REQUEST.has_key('_popup'), + 'is_popup': '_popup' in request.REQUEST, 'show_delete': show_delete, }) @@ -308,7 +308,7 @@ def change_stage(request, app_label, model_name, object_id): if not request.user.has_perm(app_label + '.' + opts.get_change_permission()): raise PermissionDenied - if request.POST and request.POST.has_key("_saveasnew"): + if request.POST and "_saveasnew" in request.POST: return add_stage(request, app_label, model_name, form_url='../../add/') try: @@ -343,16 +343,16 @@ def change_stage(request, app_label, model_name, object_id): LogEntry.objects.log_action(request.user.id, ContentType.objects.get_for_model(model).id, pk_value, str(new_object), CHANGE, change_message) msg = _('The %(name)s "%(obj)s" was changed successfully.') % {'name': opts.verbose_name, 'obj': new_object} - if request.POST.has_key("_continue"): + if "_continue" in request.POST: request.user.message_set.create(message=msg + ' ' + _("You may edit it again below.")) - if request.REQUEST.has_key('_popup'): + if '_popup' in request.REQUEST: return HttpResponseRedirect(request.path + "?_popup=1") else: return HttpResponseRedirect(request.path) - elif request.POST.has_key("_saveasnew"): + elif "_saveasnew" in request.POST: request.user.message_set.create(message=_('The %(name)s "%(obj)s" was added successfully. You may edit it again below.') % {'name': opts.verbose_name, 'obj': new_object}) return HttpResponseRedirect("../%s/" % pk_value) - elif request.POST.has_key("_addanother"): + elif "_addanother" in request.POST: request.user.message_set.create(message=msg + ' ' + (_("You may add another %s below.") % opts.verbose_name)) return HttpResponseRedirect("../add/") else: @@ -392,7 +392,7 @@ def change_stage(request, app_label, model_name, object_id): 'form': form, 'object_id': object_id, 'original': manipulator.original_object, - 'is_popup': request.REQUEST.has_key('_popup'), + 'is_popup': '_popup' in request.REQUEST, }) return render_change_form(model, manipulator, c, change=True) change_stage = staff_member_required(never_cache(change_stage)) @@ -558,12 +558,12 @@ class ChangeList(object): self.page_num = int(request.GET.get(PAGE_VAR, 0)) except ValueError: self.page_num = 0 - self.show_all = request.GET.has_key(ALL_VAR) - self.is_popup = request.GET.has_key(IS_POPUP_VAR) + self.show_all = ALL_VAR in request.GET + self.is_popup = IS_POPUP_VAR in request.GET self.params = dict(request.GET.items()) - if self.params.has_key(PAGE_VAR): + if PAGE_VAR in self.params: del self.params[PAGE_VAR] - if self.params.has_key(ERROR_FLAG): + if ERROR_FLAG in self.params: del self.params[ERROR_FLAG] self.order_field, self.order_type = self.get_ordering() @@ -594,7 +594,7 @@ class ChangeList(object): if k.startswith(r): del p[k] for k, v in new_params.items(): - if p.has_key(k) and v is None: + if k in p and v is None: del p[k] elif v is not None: p[k] = v @@ -656,7 +656,7 @@ class ChangeList(object): order_field, order_type = ordering[0][1:], 'desc' else: order_field, order_type = ordering[0], 'asc' - if params.has_key(ORDER_VAR): + if ORDER_VAR in params: try: field_name = lookup_opts.admin.list_display[int(params[ORDER_VAR])] try: @@ -674,7 +674,7 @@ class ChangeList(object): order_field = f.name except (IndexError, ValueError): pass # Invalid ordering specified. Just use the default. - if params.has_key(ORDER_TYPE_VAR) and params[ORDER_TYPE_VAR] in ('asc', 'desc'): + if ORDER_TYPE_VAR in params and params[ORDER_TYPE_VAR] in ('asc', 'desc'): order_type = params[ORDER_TYPE_VAR] return order_field, order_type @@ -682,7 +682,7 @@ class ChangeList(object): qs = self.manager.get_query_set() lookup_params = self.params.copy() # a dictionary of the query string for i in (ALL_VAR, ORDER_VAR, ORDER_TYPE_VAR, SEARCH_VAR, IS_POPUP_VAR): - if lookup_params.has_key(i): + if i in lookup_params: del lookup_params[i] # Apply lookup parameters from the query string. diff --git a/django/contrib/comments/templatetags/comments.py b/django/contrib/comments/templatetags/comments.py index 80d4bf24ab..5c02c16f95 100644 --- a/django/contrib/comments/templatetags/comments.py +++ b/django/contrib/comments/templatetags/comments.py @@ -116,7 +116,7 @@ class CommentListNode(template.Node): comment_list = get_list_function(**kwargs).order_by(self.ordering + 'submit_date').select_related() if not self.free: - if context.has_key('user') and context['user'].is_authenticated(): + if 'user' in context and context['user'].is_authenticated(): user_id = context['user'].id context['user_can_moderate_comments'] = Comment.objects.user_is_moderator(context['user']) else: diff --git a/django/contrib/comments/views/comments.py b/django/contrib/comments/views/comments.py index 12330afe41..73a9b2c480 100644 --- a/django/contrib/comments/views/comments.py +++ b/django/contrib/comments/views/comments.py @@ -217,10 +217,10 @@ def post_comment(request): errors = manipulator.get_validation_errors(new_data) # If user gave correct username/password and wasn't already logged in, log them in # so they don't have to enter a username/password again. - if manipulator.get_user() and not manipulator.get_user().is_authenticated() and new_data.has_key('password') and manipulator.get_user().check_password(new_data['password']): + if manipulator.get_user() and not manipulator.get_user().is_authenticated() and 'password' in new_data and manipulator.get_user().check_password(new_data['password']): from django.contrib.auth import login login(request, manipulator.get_user()) - if errors or request.POST.has_key('preview'): + if errors or 'preview' in request.POST: class CommentFormWrapper(oldforms.FormWrapper): def __init__(self, manipulator, new_data, errors, rating_choices): oldforms.FormWrapper.__init__(self, manipulator, new_data, errors) @@ -244,7 +244,7 @@ def post_comment(request): 'rating_range': rating_range, 'rating_choices': rating_choices, }, context_instance=RequestContext(request)) - elif request.POST.has_key('post'): + elif 'post' in request.POST: # If the IP is banned, mail the admins, do NOT save the comment, and # serve up the "Thanks for posting" page as if the comment WAS posted. if request.META['REMOTE_ADDR'] in settings.BANNED_IPS: @@ -298,7 +298,7 @@ def post_free_comment(request): new_data['is_public'] = IS_PUBLIC in option_list manipulator = PublicFreeCommentManipulator() errors = manipulator.get_validation_errors(new_data) - if errors or request.POST.has_key('preview'): + if errors or 'preview' in request.POST: comment = errors and '' or manipulator.get_comment(new_data) return render_to_response('comments/free_preview.html', { 'comment': comment, @@ -307,7 +307,7 @@ def post_free_comment(request): 'target': target, 'hash': security_hash, }, context_instance=RequestContext(request)) - elif request.POST.has_key('post'): + elif 'post' in request.POST: # If the IP is banned, mail the admins, do NOT save the comment, and # serve up the "Thanks for posting" page as if the comment WAS posted. if request.META['REMOTE_ADDR'] in settings.BANNED_IPS: @@ -330,7 +330,7 @@ def comment_was_posted(request): The object the comment was posted on """ obj = None - if request.GET.has_key('c'): + if 'c' in request.GET: content_type_id, object_id = request.GET['c'].split(':') try: content_type = ContentType.objects.get(pk=content_type_id) diff --git a/django/contrib/localflavor/br/forms.py b/django/contrib/localflavor/br/forms.py index 29ad4df53d..3487787643 100644 --- a/django/contrib/localflavor/br/forms.py +++ b/django/contrib/localflavor/br/forms.py @@ -4,7 +4,7 @@ BR-specific Form helpers """ from django.newforms import ValidationError -from django.newforms.fields import Field, RegexField, Select, EMPTY_VALUES +from django.newforms.fields import Field, RegexField, CharField, Select, EMPTY_VALUES from django.utils.encoding import smart_unicode from django.utils.translation import gettext import re @@ -15,7 +15,7 @@ class BRZipCodeField(RegexField): def __init__(self, *args, **kwargs): super(BRZipCodeField, self).__init__(r'^\d{5}-\d{3}$', max_length=None, min_length=None, - error_message=gettext(u'Enter a zip code in the format XXXXX-XXX.'), + error_message=gettext('Enter a zip code in the format XXXXX-XXX.'), *args, **kwargs) class BRPhoneNumberField(Field): @@ -31,9 +31,89 @@ class BRPhoneNumberField(Field): class BRStateSelect(Select): """ - A Select widget that uses a list of brazilian states/territories + A Select widget that uses a list of Brazilian states/territories as its choices. """ def __init__(self, attrs=None): from br_states import STATE_CHOICES # relative import super(BRStateSelect, self).__init__(attrs, choices=STATE_CHOICES) + + +def DV_maker(v): + if v >= 2: + return 11 - v + return 0 + +class BRCPFField(CharField): + """ + This field validate a CPF number or a CPF string. A CPF number is + compounded by XXX.XXX.XXX-VD. The two last digits are check digits. + + More information: + http://en.wikipedia.org/wiki/Cadastro_de_Pessoas_F%C3%ADsicas + """ + def __init__(self, *args, **kwargs): + super(BRCPFField, self).__init__(max_length=14, min_length=11, *args, **kwargs) + + def clean(self, value): + """ + Value can be either a string in the format XXX.XXX.XXX-XX or an + 11-digit number. + """ + value = super(BRCPFField, self).clean(value) + if value in EMPTY_VALUES: + return u'' + orig_value = value[:] + if not value.isdigit(): + value = re.sub("[-\.]", "", value) + try: + int(value) + except ValueError: + raise ValidationError(gettext("This field requires only numbers.")) + if len(value) != 11: + raise ValidationError(gettext("This field requires at most 11 digits or 14 characters.")) + orig_dv = value[-2:] + + new_1dv = sum([i * int(value[idx]) for idx, i in enumerate(range(10, 1, -1))]) + new_1dv = DV_maker(new_1dv % 11) + value = value[:-2] + str(new_1dv) + value[-1] + new_2dv = sum([i * int(value[idx]) for idx, i in enumerate(range(11, 1, -1))]) + new_2dv = DV_maker(new_2dv % 11) + value = value[:-1] + str(new_2dv) + if value[-2:] != orig_dv: + raise ValidationError(gettext("Invalid CPF number.")) + + return orig_value + +class BRCNPJField(Field): + def clean(self, value): + """ + Value can be either a string in the format XX.XXX.XXX/XXXX-XX or a + group of 14 characters. + """ + value = super(BRCNPJField, self).clean(value) + if value in EMPTY_VALUES: + return u'' + orig_value = value[:] + if not value.isdigit(): + value = re.sub("[-/\.]", "", value) + try: + int(value) + except ValueError: + raise ValidationError("This field requires only numbers.") + if len(value) != 14: + raise ValidationError( + gettext("This field requires at least 14 digits")) + orig_dv = value[-2:] + + new_1dv = sum([i * int(value[idx]) for idx, i in enumerate(range(5, 1, -1) + range(9, 1, -1))]) + new_1dv = DV_maker(new_1dv % 11) + value = value[:-2] + str(new_1dv) + value[-1] + new_2dv = sum([i * int(value[idx]) for idx, i in enumerate(range(6, 1, -1) + range(9, 1, -1))]) + new_2dv = DV_maker(new_2dv % 11) + value = value[:-1] + str(new_2dv) + if value[-2:] != orig_dv: + raise ValidationError(gettext("Invalid CNPJ number.")) + + return orig_value + diff --git a/django/contrib/localflavor/cl/__init__.py b/django/contrib/localflavor/cl/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/django/contrib/localflavor/cl/forms.py b/django/contrib/localflavor/cl/forms.py new file mode 100644 index 0000000000..87c8093407 --- /dev/null +++ b/django/contrib/localflavor/cl/forms.py @@ -0,0 +1,78 @@ +""" +Chile specific form helpers. +""" + +from django.newforms import ValidationError +from django.newforms.fields import RegexField, EMPTY_VALUES +from django.utils.translation import gettext + +class CLRutField(RegexField): + """ + Chilean "Rol Unico Tributario" (RUT) field. This is the Chilean national + identification number. + + Samples for testing are available from + https://palena.sii.cl/cvc/dte/ee_empresas_emisoras.html + """ + def __init__(self, *args, **kwargs): + if 'strict' in kwargs: + del kwargs['strict'] + super(CLRutField, self).__init__(r'^(\d{1,2}\.)?\d{3}\.\d{3}-[\dkK]$', + error_message=gettext('Enter valid a Chilean RUT. The format is XX.XXX.XXX-X.'), + *args, **kwargs) + else: + # In non-strict mode, accept RUTs that validate but do not exist in + # the real world. + super(CLRutField, self).__init__(r'^[\d\.]{1,11}-?[\dkK]$', error_message=gettext(u'Enter valid a Chilean RUT'), *args, **kwargs) + + def clean(self, value): + """ + Check and clean the Chilean RUT. + """ + super(CLRutField, self).clean(value) + if value in EMPTY_VALUES: + return u'' + rut, verificador = self._canonify(value) + if self._algorithm(rut) == verificador: + return self._format(rut, verificador) + else: + raise ValidationError(u'The Chilean RUT is not valid.') + + def _algorithm(self, rut): + """ + Takes RUT in pure canonical form, calculates the verifier digit. + """ + suma = 0 + multi = 2 + for r in rut[::-1]: + suma += int(r) * multi + multi += 1 + if multi == 8: + multi = 2 + return '0123456789K0'[11 - suma % 11] + + def _canonify(self, rut): + """ + Turns the RUT into one normalized format. Returns a (rut, verifier) + tuple. + """ + rut = str(rut).replace(' ', '').replace('.', '').replace('-', '') + return rut[:-1], rut[-1] + + def _format(self, code, verifier=None): + """ + Formats the RUT from canonical form to the common string representation. + If verifier=None, then the last digit in 'code' is the verifier. + """ + if verifier is None: + verifier = code[-1] + code = code[:-1] + while len(code) > 3 and '.' not in code[:3]: + pos = code.find('.') + if pos == -1: + new_dot = -3 + else: + new_dot = pos - 3 + code = code[:new_dot] + '.' + code[new_dot:] + return '%s-%s' % (code, verifier) + diff --git a/django/contrib/localflavor/is_/forms.py b/django/contrib/localflavor/is_/forms.py index 3ee2d76937..d052acf579 100644 --- a/django/contrib/localflavor/is_/forms.py +++ b/django/contrib/localflavor/is_/forms.py @@ -1,12 +1,12 @@ """ Iceland specific form helpers. """ + from django.newforms import ValidationError from django.newforms.fields import RegexField, EMPTY_VALUES from django.newforms.widgets import Select from django.utils.translation import gettext - class ISIdNumberField(RegexField): """ Icelandic identification number (kennitala). This is a number every citizen @@ -15,7 +15,6 @@ class ISIdNumberField(RegexField): def __init__(self, *args, **kwargs): error_msg = gettext(u'Enter a valid Icelandic identification number. The format is XXXXXX-XXXX.') kwargs['min_length'],kwargs['max_length'] = 10,11 - super(ISIdNumberField, self).__init__(r'^\d{6}(-| )?\d{4}$', error_message=error_msg, *args, **kwargs) def clean(self, value): @@ -30,7 +29,6 @@ class ISIdNumberField(RegexField): else: raise ValidationError(gettext(u'The Icelandic identification number is not valid.')) - def _canonify(self, value): """ Returns the value as only digits. @@ -52,7 +50,6 @@ class ISIdNumberField(RegexField): """ return value[:6]+'-'+value[6:] - class ISPhoneNumberField(RegexField): """ Icelandic phone number. Seven digits with an optional hyphen or space after @@ -70,7 +67,6 @@ class ISPhoneNumberField(RegexField): return value.replace('-', '').replace(' ', '') - class ISPostalCodeSelect(Select): """ A Select widget that uses a list of Icelandic postal codes as its choices. diff --git a/django/contrib/sitemaps/views.py b/django/contrib/sitemaps/views.py index 576e3d0bb8..d615c8e661 100644 --- a/django/contrib/sitemaps/views.py +++ b/django/contrib/sitemaps/views.py @@ -16,7 +16,7 @@ def index(request, sitemaps): def sitemap(request, sitemaps, section=None): maps, urls = [], [] if section is not None: - if not sitemaps.has_key(section): + if section not in sitemaps: raise Http404("No sitemap available for section: %r" % section) maps.append(sitemaps[section]) else: diff --git a/django/core/cache/backends/simple.py b/django/core/cache/backends/simple.py index 175944a75a..3fcad8c7ad 100644 --- a/django/core/cache/backends/simple.py +++ b/django/core/cache/backends/simple.py @@ -52,7 +52,7 @@ class CacheClass(BaseCache): pass def has_key(self, key): - return self._cache.has_key(key) + return key in self._cache def _cull(self): if self._cull_frequency == 0: diff --git a/django/core/handlers/modpython.py b/django/core/handlers/modpython.py index 5fc41a048b..6370cab47c 100644 --- a/django/core/handlers/modpython.py +++ b/django/core/handlers/modpython.py @@ -42,11 +42,11 @@ class ModPythonRequest(http.HttpRequest): def is_secure(self): # Note: modpython 3.2.10+ has req.is_https(), but we need to support previous versions - return self._req.subprocess_env.has_key('HTTPS') and self._req.subprocess_env['HTTPS'] == 'on' + return 'HTTPS' in self._req.subprocess_env and self._req.subprocess_env['HTTPS'] == 'on' def _load_post_and_files(self): "Populates self._post and self._files" - if self._req.headers_in.has_key('content-type') and self._req.headers_in['content-type'].startswith('multipart'): + if 'content-type' in self._req.headers_in and self._req.headers_in['content-type'].startswith('multipart'): self._post, self._files = http.parse_file_upload(self._req.headers_in, self.raw_post_data) else: self._post, self._files = http.QueryDict(self.raw_post_data), datastructures.MultiValueDict() diff --git a/django/core/handlers/wsgi.py b/django/core/handlers/wsgi.py index 71cfecd9a0..4320b69627 100644 --- a/django/core/handlers/wsgi.py +++ b/django/core/handlers/wsgi.py @@ -103,7 +103,7 @@ class WSGIRequest(http.HttpRequest): return '%s%s' % (self.path, self.environ.get('QUERY_STRING', '') and ('?' + self.environ.get('QUERY_STRING', '')) or '') def is_secure(self): - return self.environ.has_key('HTTPS') and self.environ['HTTPS'] == 'on' + return 'HTTPS' in self.environ and self.environ['HTTPS'] == 'on' def _load_post_and_files(self): # Populates self._post and self._files diff --git a/django/core/management.py b/django/core/management.py index f55fb57dd6..85592553e6 100644 --- a/django/core/management.py +++ b/django/core/management.py @@ -168,6 +168,8 @@ def _get_sql_model_create(model, known_models=set()): for f in opts.fields: if isinstance(f, (models.ForeignKey, models.OneToOneField)): rel_field = f.rel.get_related_field() + while isinstance(rel_field, (models.ForeignKey, models.OneToOneField)): + rel_field = rel_field.rel.get_related_field() data_type = get_rel_data_type(rel_field) else: rel_field = f @@ -314,7 +316,7 @@ def get_sql_delete(app): # Drop the table now output.append('%s %s;' % (style.SQL_KEYWORD('DROP TABLE'), style.SQL_TABLE(backend.quote_name(model._meta.db_table)))) - if backend.supports_constraints and references_to_delete.has_key(model): + if backend.supports_constraints and model in references_to_delete: for rel_class, f in references_to_delete[model]: table = rel_class._meta.db_table col = f.column @@ -843,7 +845,7 @@ def inspectdb(): att_name += '_field' comment_notes.append('Field renamed because it was a Python reserved word.') - if relations.has_key(i): + if i in relations: rel_to = relations[i][1] == table_name and "'self'" or table2model(relations[i][1]) field_type = 'ForeignKey(%s' % rel_to if att_name.endswith('_id'): @@ -1318,6 +1320,8 @@ def load_data(fixture_labels, verbosity=1): from django.conf import settings import sys + disable_termcolors() + # Keep a count of the installed objects and fixtures count = [0,0] models = set() @@ -1550,7 +1554,7 @@ def execute_from_command_line(action_mapping=DEFAULT_ACTION_MAPPING, argv=None): action = args[0] except IndexError: parser.print_usage_and_exit() - if not action_mapping.has_key(action): + if action not in action_mapping: print_error("Your action, %r, was invalid." % action, argv[0]) # Switch to English, because django-admin.py creates database content diff --git a/django/core/servers/basehttp.py b/django/core/servers/basehttp.py index a16b8b675a..80a0bf6a91 100644 --- a/django/core/servers/basehttp.py +++ b/django/core/servers/basehttp.py @@ -208,15 +208,15 @@ def guess_scheme(environ): else: return 'http' -_hoppish = { +_hop_headers = { 'connection':1, 'keep-alive':1, 'proxy-authenticate':1, 'proxy-authorization':1, 'te':1, 'trailers':1, 'transfer-encoding':1, 'upgrade':1 -}.has_key +} def is_hop_by_hop(header_name): """Return true if 'header_name' is an HTTP/1.1 "Hop-by-Hop" header""" - return _hoppish(header_name.lower()) + return header_name.lower() in _hop_headers class ServerHandler(object): """Manage the invocation of a WSGI application""" @@ -334,7 +334,7 @@ class ServerHandler(object): Subclasses can extend this to add other defaults. """ - if not self.headers.has_key('Content-Length'): + if 'Content-Length' not in self.headers: self.set_content_length() def start_response(self, status, headers,exc_info=None): @@ -368,11 +368,11 @@ class ServerHandler(object): if self.origin_server: if self.client_is_modern(): self._write('HTTP/%s %s\r\n' % (self.http_version,self.status)) - if not self.headers.has_key('Date'): + if 'Date' not in self.headers: self._write( 'Date: %s\r\n' % time.asctime(time.gmtime(time.time())) ) - if self.server_software and not self.headers.has_key('Server'): + if self.server_software and 'Server' not in self.headers: self._write('Server: %s\r\n' % self.server_software) else: self._write('Status: %s\r\n' % self.status) diff --git a/django/core/urlresolvers.py b/django/core/urlresolvers.py index c4cbccabcf..38b3263da1 100644 --- a/django/core/urlresolvers.py +++ b/django/core/urlresolvers.py @@ -102,6 +102,14 @@ class RegexURLPattern(object): self.default_args = default_args or {} self.name = name + def add_prefix(self, prefix): + """ + Adds the prefix string to a string-based callback. + """ + if not prefix or not hasattr(self, '_callback_str'): + return + self._callback_str = prefix + '.' + self._callback_str + def resolve(self, path): match = self.regex.search(path) if match: diff --git a/django/core/validators.py b/django/core/validators.py index bf1aa87c4c..b9c9f7fa08 100644 --- a/django/core/validators.py +++ b/django/core/validators.py @@ -284,7 +284,7 @@ class ValidateIfOtherFieldEquals(object): self.always_test = True def __call__(self, field_data, all_data): - if all_data.has_key(self.other_field) and all_data[self.other_field] == self.other_value: + if self.other_field in all_data and all_data[self.other_field] == self.other_value: for v in self.validator_list: v(field_data, all_data) @@ -322,7 +322,7 @@ class RequiredIfOtherFieldEquals(object): self.always_test = True def __call__(self, field_data, all_data): - if all_data.has_key(self.other_field) and all_data[self.other_field] == self.other_value and not field_data: + if self.other_field in all_data and all_data[self.other_field] == self.other_value and not field_data: raise ValidationError(self.error_message) class RequiredIfOtherFieldDoesNotEqual(object): @@ -335,7 +335,7 @@ class RequiredIfOtherFieldDoesNotEqual(object): self.always_test = True def __call__(self, field_data, all_data): - if all_data.has_key(self.other_field) and all_data[self.other_field] != self.other_value and not field_data: + if self.other_field in all_data and all_data[self.other_field] != self.other_value and not field_data: raise ValidationError(self.error_message) class IsLessThanOtherField(object): diff --git a/django/db/backends/mysql_old/base.py b/django/db/backends/mysql_old/base.py index 673808f994..497c8fdc77 100644 --- a/django/db/backends/mysql_old/base.py +++ b/django/db/backends/mysql_old/base.py @@ -53,7 +53,7 @@ class MysqlDebugWrapper: raise Database.Warning, "%s: %s" % (w, self.cursor.fetchall()) def __getattr__(self, attr): - if self.__dict__.has_key(attr): + if attr in self.__dict__: return self.__dict__[attr] else: return getattr(self.cursor, attr) diff --git a/django/db/backends/postgresql/base.py b/django/db/backends/postgresql/base.py index ecbdd51a39..867ddd0148 100644 --- a/django/db/backends/postgresql/base.py +++ b/django/db/backends/postgresql/base.py @@ -48,7 +48,7 @@ class UnicodeCursorWrapper(object): return self.cursor.executemany(sql, new_param_list) def __getattr__(self, attr): - if self.__dict__.has_key(attr): + if attr in self.__dict__: return self.__dict__[attr] else: return getattr(self.cursor, attr) diff --git a/django/db/backends/util.py b/django/db/backends/util.py index d8f86fef4f..d14a337ca2 100644 --- a/django/db/backends/util.py +++ b/django/db/backends/util.py @@ -33,7 +33,7 @@ class CursorDebugWrapper(object): }) def __getattr__(self, attr): - if self.__dict__.has_key(attr): + if attr in self.__dict__: return self.__dict__[attr] else: return getattr(self.cursor, attr) diff --git a/django/db/models/fields/__init__.py b/django/db/models/fields/__init__.py index 3da3ad70c3..77cac7745c 100644 --- a/django/db/models/fields/__init__.py +++ b/django/db/models/fields/__init__.py @@ -341,11 +341,13 @@ class Field(object): return self._choices choices = property(_get_choices) - def formfield(self, **kwargs): + def formfield(self, form_class=forms.CharField, **kwargs): "Returns a django.newforms.Field instance for this database Field." defaults = {'required': not self.blank, 'label': capfirst(self.verbose_name), 'help_text': self.help_text} + if self.choices: + defaults['widget'] = forms.Select(choices=self.get_choices()) defaults.update(kwargs) - return forms.CharField(**defaults) + return form_class(**defaults) def value_from_object(self, obj): "Returns the value of this field in the given model instance." @@ -405,9 +407,9 @@ class BooleanField(Field): return [oldforms.CheckboxField] def formfield(self, **kwargs): - defaults = {'required': not self.blank, 'label': capfirst(self.verbose_name), 'help_text': self.help_text} + defaults = {'form_class': forms.BooleanField} defaults.update(kwargs) - return forms.BooleanField(**defaults) + return super(BooleanField, self).formfield(**defaults) class CharField(Field): def get_manipulator_field_objs(self): @@ -424,9 +426,9 @@ class CharField(Field): return str(value) def formfield(self, **kwargs): - defaults = {'max_length': self.maxlength, 'required': not self.blank, 'label': capfirst(self.verbose_name), 'help_text': self.help_text} + defaults = {'max_length': self.maxlength} defaults.update(kwargs) - return forms.CharField(**defaults) + return super(CharField, self).formfield(**defaults) # TODO: Maybe move this into contrib, because it's specialized. class CommaSeparatedIntegerField(CharField): @@ -502,9 +504,9 @@ class DateField(Field): return {self.attname: (val is not None and val.strftime("%Y-%m-%d") or '')} def formfield(self, **kwargs): - defaults = {'required': not self.blank, 'label': capfirst(self.verbose_name), 'help_text': self.help_text} + defaults = {'form_class': forms.DateField} defaults.update(kwargs) - return forms.DateField(**defaults) + return super(DateField, self).formfield(**defaults) class DateTimeField(DateField): def to_python(self, value): @@ -567,9 +569,9 @@ class DateTimeField(DateField): time_field: (val is not None and val.strftime("%H:%M:%S") or '')} def formfield(self, **kwargs): - defaults = {'required': not self.blank, 'label': capfirst(self.verbose_name), 'help_text': self.help_text} + defaults = {'form_class': forms.DateTimeField} defaults.update(kwargs) - return forms.DateTimeField(**defaults) + return super(DateTimeField, self).formfield(**defaults) class EmailField(CharField): def __init__(self, *args, **kwargs): @@ -586,9 +588,9 @@ class EmailField(CharField): validators.isValidEmail(field_data, all_data) def formfield(self, **kwargs): - defaults = {'required': not self.blank, 'label': capfirst(self.verbose_name), 'help_text': self.help_text} + defaults = {'form_class': forms.EmailField} defaults.update(kwargs) - return forms.EmailField(**defaults) + return super(EmailField, self).formfield(**defaults) class FileField(Field): def __init__(self, verbose_name=None, name=None, upload_to='', **kwargs): @@ -723,9 +725,9 @@ class IntegerField(Field): return [oldforms.IntegerField] def formfield(self, **kwargs): - defaults = {'required': not self.blank, 'label': capfirst(self.verbose_name), 'help_text': self.help_text} + defaults = {'form_class': forms.IntegerField} defaults.update(kwargs) - return forms.IntegerField(**defaults) + return super(IntegerField, self).formfield(**defaults) class IPAddressField(Field): def __init__(self, *args, **kwargs): @@ -762,9 +764,9 @@ class PhoneNumberField(IntegerField): def formfield(self, **kwargs): from django.contrib.localflavor.us.forms import USPhoneNumberField - defaults = {'required': not self.blank, 'label': capfirst(self.verbose_name), 'help_text': self.help_text} + defaults = {'form_class': USPhoneNumberField} defaults.update(kwargs) - return USPhoneNumberField(**defaults) + return super(PhoneNumberField, self).formfield(**defaults) class PositiveIntegerField(IntegerField): def get_manipulator_field_objs(self): @@ -779,7 +781,7 @@ class SlugField(Field): kwargs['maxlength'] = kwargs.get('maxlength', 50) kwargs.setdefault('validator_list', []).append(validators.isSlug) # Set db_index=True unless it's been set manually. - if not kwargs.has_key('db_index'): + if 'db_index' not in kwargs: kwargs['db_index'] = True Field.__init__(self, *args, **kwargs) @@ -795,9 +797,9 @@ class TextField(Field): return [oldforms.LargeTextField] def formfield(self, **kwargs): - defaults = {'required': not self.blank, 'widget': forms.Textarea, 'label': capfirst(self.verbose_name), 'help_text': self.help_text} + defaults = {'widget': forms.Textarea} defaults.update(kwargs) - return forms.CharField(**defaults) + return super(TextField, self).formfield(**defaults) class TimeField(Field): empty_strings_allowed = False @@ -840,9 +842,9 @@ class TimeField(Field): return {self.attname: (val is not None and val.strftime("%H:%M:%S") or '')} def formfield(self, **kwargs): - defaults = {'required': not self.blank, 'label': capfirst(self.verbose_name), 'help_text': self.help_text} + defaults = {'form_class': forms.TimeField} defaults.update(kwargs) - return forms.TimeField(**defaults) + return super(TimeField, self).formfield(**defaults) class URLField(CharField): def __init__(self, verbose_name=None, name=None, verify_exists=True, **kwargs): @@ -859,9 +861,9 @@ class URLField(CharField): return "CharField" def formfield(self, **kwargs): - defaults = {'required': not self.blank, 'verify_exists': self.verify_exists, 'label': capfirst(self.verbose_name), 'help_text': self.help_text} + defaults = {'form_class': forms.URLField, 'verify_exists': self.verify_exists} defaults.update(kwargs) - return forms.URLField(**defaults) + return super(URLField, self).formfield(**defaults) class USStateField(Field): def get_manipulator_field_objs(self): diff --git a/django/db/models/fields/generic.py b/django/db/models/fields/generic.py index 480ee689c9..f995ab2044 100644 --- a/django/db/models/fields/generic.py +++ b/django/db/models/fields/generic.py @@ -37,7 +37,7 @@ class GenericForeignKey(object): def instance_pre_init(self, signal, sender, args, kwargs): # Handle initalizing an object with the generic FK instaed of # content-type/object-id fields. - if kwargs.has_key(self.name): + if self.name in kwargs: value = kwargs.pop(self.name) kwargs[self.ct_field] = self.get_content_type(value) kwargs[self.fk_field] = value._get_pk_val() diff --git a/django/db/models/fields/related.py b/django/db/models/fields/related.py index fad9c164c1..0739d0461a 100644 --- a/django/db/models/fields/related.py +++ b/django/db/models/fields/related.py @@ -474,7 +474,7 @@ class ForeignKey(RelatedField, Field): to_field = to_field or to._meta.pk.name kwargs['verbose_name'] = kwargs.get('verbose_name', '') - if kwargs.has_key('edit_inline_type'): + if 'edit_inline_type' in kwargs: import warnings warnings.warn("edit_inline_type is deprecated. Use edit_inline instead.") kwargs['edit_inline'] = kwargs.pop('edit_inline_type') @@ -553,9 +553,9 @@ class ForeignKey(RelatedField, Field): setattr(cls, related.get_accessor_name(), ForeignRelatedObjectsDescriptor(related)) def formfield(self, **kwargs): - defaults = {'queryset': self.rel.to._default_manager.all(), 'required': not self.blank, 'label': capfirst(self.verbose_name), 'help_text': self.help_text} + defaults = {'form_class': forms.ModelChoiceField, 'queryset': self.rel.to._default_manager.all()} defaults.update(kwargs) - return forms.ModelChoiceField(**defaults) + return super(ForeignKey, self).formfield(**defaults) class OneToOneField(RelatedField, IntegerField): def __init__(self, to, to_field=None, **kwargs): @@ -567,7 +567,7 @@ class OneToOneField(RelatedField, IntegerField): to_field = to_field or to._meta.pk.name kwargs['verbose_name'] = kwargs.get('verbose_name', '') - if kwargs.has_key('edit_inline_type'): + if 'edit_inline_type' in kwargs: import warnings warnings.warn("edit_inline_type is deprecated. Use edit_inline instead.") kwargs['edit_inline'] = kwargs.pop('edit_inline_type') @@ -619,9 +619,9 @@ class OneToOneField(RelatedField, IntegerField): cls._meta.one_to_one_field = self def formfield(self, **kwargs): - defaults = {'queryset': self.rel.to._default_manager.all(), 'required': not self.blank, 'label': capfirst(self.verbose_name), 'help_text': self.help_text} + defaults = {'form_class': forms.ModelChoiceField, 'queryset': self.rel.to._default_manager.all()} defaults.update(kwargs) - return forms.ModelChoiceField(**defaults) + return super(OneToOneField, self).formfield(**defaults) class ManyToManyField(RelatedField, Field): def __init__(self, to, **kwargs): @@ -738,13 +738,13 @@ class ManyToManyField(RelatedField, Field): return getattr(obj, self.attname).all() def formfield(self, **kwargs): + defaults = {'form_class': forms.ModelMultipleChoiceField, 'queryset': self.rel.to._default_manager.all()} + defaults.update(kwargs) # If initial is passed in, it's a list of related objects, but the # MultipleChoiceField takes a list of IDs. - if kwargs.get('initial') is not None: - kwargs['initial'] = [i._get_pk_val() for i in kwargs['initial']] - defaults = {'queryset' : self.rel.to._default_manager.all(), 'required': not self.blank, 'label': capfirst(self.verbose_name), 'help_text': self.help_text} - defaults.update(kwargs) - return forms.ModelMultipleChoiceField(**defaults) + if defaults.get('initial') is not None: + defaults['initial'] = [i._get_pk_val() for i in defaults['initial']] + return super(ManyToManyField, self).formfield(**defaults) class ManyToOneRel(object): def __init__(self, to, field_name, num_in_admin=3, min_num_in_admin=None, diff --git a/django/db/models/loading.py b/django/db/models/loading.py index f4aff2438b..224f5e8451 100644 --- a/django/db/models/loading.py +++ b/django/db/models/loading.py @@ -103,7 +103,7 @@ def register_models(app_label, *models): # in the _app_models dictionary model_name = model._meta.object_name.lower() model_dict = _app_models.setdefault(app_label, {}) - if model_dict.has_key(model_name): + if model_name in model_dict: # The same model may be imported via different paths (e.g. # appname.models and project.appname.models). We use the source # filename as a means to detect identity. diff --git a/django/db/models/options.py b/django/db/models/options.py index 51cf0a019b..dd6c586ddd 100644 --- a/django/db/models/options.py +++ b/django/db/models/options.py @@ -140,7 +140,7 @@ class Options(object): def get_follow(self, override=None): follow = {} for f in self.fields + self.many_to_many + self.get_all_related_objects(): - if override and override.has_key(f.name): + if override and f.name in override: child_override = override[f.name] else: child_override = None @@ -182,7 +182,7 @@ class Options(object): # TODO: follow if not hasattr(self, '_field_types'): self._field_types = {} - if not self._field_types.has_key(field_type): + if field_type not in self._field_types: try: # First check self.fields. for f in self.fields: diff --git a/django/db/transaction.py b/django/db/transaction.py index 4a0658e1c3..bb90713525 100644 --- a/django/db/transaction.py +++ b/django/db/transaction.py @@ -46,12 +46,12 @@ def enter_transaction_management(): when no current block is running). """ thread_ident = thread.get_ident() - if state.has_key(thread_ident) and state[thread_ident]: + if thread_ident in state and state[thread_ident]: state[thread_ident].append(state[thread_ident][-1]) else: state[thread_ident] = [] state[thread_ident].append(settings.TRANSACTIONS_MANAGED) - if not dirty.has_key(thread_ident): + if thread_ident not in dirty: dirty[thread_ident] = False def leave_transaction_management(): @@ -61,7 +61,7 @@ def leave_transaction_management(): those from outside. (Commits are on connection level.) """ thread_ident = thread.get_ident() - if state.has_key(thread_ident) and state[thread_ident]: + if thread_ident in state and state[thread_ident]: del state[thread_ident][-1] else: raise TransactionManagementError("This code isn't under transaction management") @@ -84,7 +84,7 @@ def set_dirty(): changes waiting for commit. """ thread_ident = thread.get_ident() - if dirty.has_key(thread_ident): + if thread_ident in dirty: dirty[thread_ident] = True else: raise TransactionManagementError("This code isn't under transaction management") @@ -96,7 +96,7 @@ def set_clean(): should happen. """ thread_ident = thread.get_ident() - if dirty.has_key(thread_ident): + if thread_ident in dirty: dirty[thread_ident] = False else: raise TransactionManagementError("This code isn't under transaction management") @@ -106,7 +106,7 @@ def is_managed(): Checks whether the transaction manager is in manual or in auto state. """ thread_ident = thread.get_ident() - if state.has_key(thread_ident): + if thread_ident in state: if state[thread_ident]: return state[thread_ident][-1] return settings.TRANSACTIONS_MANAGED diff --git a/django/http/__init__.py b/django/http/__init__.py index ed2c128a16..a0c51ff0da 100644 --- a/django/http/__init__.py +++ b/django/http/__init__.py @@ -29,12 +29,12 @@ class HttpRequest(object): def __getitem__(self, key): for d in (self.POST, self.GET): - if d.has_key(key): + if key in d: return d[key] raise KeyError, "%s not found in either POST or GET" % key def has_key(self, key): - return self.GET.has_key(key) or self.POST.has_key(key) + return key in self.GET or key in self.POST def get_full_path(self): return '' @@ -57,7 +57,7 @@ def parse_file_upload(header_dict, post_data): # name_dict is something like {'name': 'file', 'filename': 'test.txt'} for file uploads # or {'name': 'blah'} for POST fields # We assume all uploaded files have a 'filename' set. - if name_dict.has_key('filename'): + if 'filename' in name_dict: assert type([]) != type(submessage.get_payload()), "Nested MIME messages are not supported" if not name_dict['filename'].strip(): continue @@ -66,7 +66,7 @@ def parse_file_upload(header_dict, post_data): filename = name_dict['filename'][name_dict['filename'].rfind("\\")+1:] FILES.appendlist(name_dict['name'], { 'filename': filename, - 'content-type': (submessage.has_key('Content-Type') and submessage['Content-Type'] or None), + 'content-type': 'Content-Type' in submessage and submessage['Content-Type'] or None, 'content': submessage.get_payload(), }) else: diff --git a/django/middleware/common.py b/django/middleware/common.py index 9891b1efad..2c72c9a583 100644 --- a/django/middleware/common.py +++ b/django/middleware/common.py @@ -25,7 +25,7 @@ class CommonMiddleware(object): """ # Check for denied User-Agents - if request.META.has_key('HTTP_USER_AGENT'): + if 'HTTP_USER_AGENT' in request.META: for user_agent_regex in settings.DISALLOWED_USER_AGENTS: if user_agent_regex.search(request.META['HTTP_USER_AGENT']): return http.HttpResponseForbidden('

Forbidden

') diff --git a/django/newforms/fields.py b/django/newforms/fields.py index 0b805144f3..b9a210db8c 100644 --- a/django/newforms/fields.py +++ b/django/newforms/fields.py @@ -457,7 +457,7 @@ class MultiValueField(Field): for i, field in enumerate(self.fields): try: field_value = value[i] - except KeyError: + except IndexError: field_value = None if self.required and field_value in EMPTY_VALUES: raise ValidationError(ugettext(u'This field is required.')) diff --git a/django/newforms/forms.py b/django/newforms/forms.py index 1f37da91ff..9fafd20787 100644 --- a/django/newforms/forms.py +++ b/django/newforms/forms.py @@ -122,7 +122,14 @@ class BaseForm(StrAndUnicode): else: if errors_on_separate_row and bf_errors: output.append(error_row % bf_errors) - label = bf.label and bf.label_tag(escape(bf.label + ':')) or '' + if bf.label: + label = escape(bf.label) + # Only add a colon if the label does not end in punctuation. + if label[-1] not in ':?.!': + label += ':' + label = bf.label_tag(label) or '' + else: + label = '' if field.help_text: help_text = help_text_html % field.help_text else: @@ -244,7 +251,7 @@ class BoundField(StrAndUnicode): def as_widget(self, widget, attrs=None): attrs = attrs or {} auto_id = self.auto_id - if auto_id and not attrs.has_key('id') and not widget.attrs.has_key('id'): + if auto_id and 'id' not in attrs and 'id' not in widget.attrs: attrs['id'] = auto_id if not self.form.is_bound: data = self.form.initial.get(self.name, self.field.initial) diff --git a/django/newforms/widgets.py b/django/newforms/widgets.py index d50b1921ea..dd71ebc455 100644 --- a/django/newforms/widgets.py +++ b/django/newforms/widgets.py @@ -230,7 +230,7 @@ class RadioInput(StrAndUnicode): return self.value == self.choice_value def tag(self): - if self.attrs.has_key('id'): + if 'id' in self.attrs: self.attrs['id'] = '%s_%s' % (self.attrs['id'], self.index) final_attrs = dict(self.attrs, type='radio', name=self.name, value=self.choice_value) if self.is_checked(): @@ -276,7 +276,7 @@ class RadioSelect(Select): class CheckboxSelectMultiple(SelectMultiple): def render(self, name, value, attrs=None, choices=()): if value is None: value = [] - has_id = attrs and attrs.has_key('id') + has_id = attrs and 'id' in attrs final_attrs = self.build_attrs(attrs, name=name) output = [u'
    '] str_values = set([smart_unicode(v) for v in value]) # Normalize to strings. @@ -347,7 +347,7 @@ class MultiWidget(Widget): id_for_label = classmethod(id_for_label) def value_from_datadict(self, data, name): - return [data.get(name + '_%s' % i) for i in range(len(self.widgets))] + return [widget.value_from_datadict(data, name + '_%s' % i) for i, widget in enumerate(self.widgets)] def format_output(self, rendered_widgets): return u''.join(rendered_widgets) diff --git a/django/oldforms/__init__.py b/django/oldforms/__init__.py index 053286ee35..439bffa568 100644 --- a/django/oldforms/__init__.py +++ b/django/oldforms/__init__.py @@ -341,7 +341,7 @@ class FormField(object): def convert_post_data(self, new_data): name = self.get_member_name() - if new_data.has_key(self.field_name): + if self.field_name in new_data: d = new_data.getlist(self.field_name) try: converted_data = [self.__class__.html2python(data) for data in d] diff --git a/django/template/__init__.py b/django/template/__init__.py index 4f0fddaf14..7f1231e83f 100644 --- a/django/template/__init__.py +++ b/django/template/__init__.py @@ -201,18 +201,27 @@ class Lexer(object): def tokenize(self): "Return a list of tokens from a given template_string" - # remove all empty strings, because the regex has a tendency to add them - bits = filter(None, tag_re.split(self.template_string)) - return map(self.create_token, bits) + in_tag = False + result = [] + for bit in tag_re.split(self.template_string): + if bit: + result.append(self.create_token(bit, in_tag)) + in_tag = not in_tag + return result - def create_token(self,token_string): - "Convert the given token string into a new Token object and return it" - if token_string.startswith(VARIABLE_TAG_START): - token = Token(TOKEN_VAR, token_string[len(VARIABLE_TAG_START):-len(VARIABLE_TAG_END)].strip()) - elif token_string.startswith(BLOCK_TAG_START): - token = Token(TOKEN_BLOCK, token_string[len(BLOCK_TAG_START):-len(BLOCK_TAG_END)].strip()) - elif token_string.startswith(COMMENT_TAG_START): - token = Token(TOKEN_COMMENT, '') + def create_token(self, token_string, in_tag): + """ + Convert the given token string into a new Token object and return it. + If in_tag is True, we are processing something that matched a tag, + otherwise it should be treated as a literal string. + """ + if in_tag: + if token_string.startswith(VARIABLE_TAG_START): + token = Token(TOKEN_VAR, token_string[len(VARIABLE_TAG_START):-len(VARIABLE_TAG_END)].strip()) + elif token_string.startswith(BLOCK_TAG_START): + token = Token(TOKEN_BLOCK, token_string[len(BLOCK_TAG_START):-len(BLOCK_TAG_END)].strip()) + elif token_string.startswith(COMMENT_TAG_START): + token = Token(TOKEN_COMMENT, '') else: token = Token(TOKEN_TEXT, token_string) return token @@ -223,22 +232,22 @@ class DebugLexer(Lexer): def tokenize(self): "Return a list of tokens from a given template_string" - token_tups, upto = [], 0 + result, upto = [], 0 for match in tag_re.finditer(self.template_string): start, end = match.span() if start > upto: - token_tups.append( (self.template_string[upto:start], (upto, start)) ) + result.append(self.create_token(self.template_string[upto:start], (upto, start), False)) upto = start - token_tups.append( (self.template_string[start:end], (start,end)) ) + result.append(self.create_token(self.template_string[start:end], (start, end), True)) upto = end last_bit = self.template_string[upto:] if last_bit: - token_tups.append( (last_bit, (upto, upto + len(last_bit))) ) - return [self.create_token(tok, (self.origin, loc)) for tok, loc in token_tups] + result.append(self.create_token(last_bit, (upto, upto + len(last_bit)), False)) + return result - def create_token(self, token_string, source): - token = super(DebugLexer, self).create_token(token_string) - token.source = source + def create_token(self, token_string, source, in_tag): + token = super(DebugLexer, self).create_token(token_string, in_tag) + token.source = self.origin, source return token class Parser(object): @@ -346,7 +355,7 @@ class Parser(object): return FilterExpression(token, self) def find_filter(self, filter_name): - if self.filters.has_key(filter_name): + if filter_name in self.filters: return self.filters[filter_name] else: raise TemplateSyntaxError, "Invalid filter: '%s'" % filter_name diff --git a/django/template/context.py b/django/template/context.py index 25397b0e1a..59650b05fe 100644 --- a/django/template/context.py +++ b/django/template/context.py @@ -35,7 +35,7 @@ class Context(object): def __getitem__(self, key): "Get a variable's value, starting at the current context and going upward" for d in self.dicts: - if d.has_key(key): + if key in d: return d[key] raise KeyError(key) @@ -45,7 +45,7 @@ class Context(object): def has_key(self, key): for d in self.dicts: - if d.has_key(key): + if key in d: return True return False @@ -54,7 +54,7 @@ class Context(object): def get(self, key, otherwise=None): for d in self.dicts: - if d.has_key(key): + if key in d: return d[key] return otherwise diff --git a/django/template/defaulttags.py b/django/template/defaulttags.py index 623afc477a..f2453dff4a 100644 --- a/django/template/defaulttags.py +++ b/django/template/defaulttags.py @@ -88,7 +88,7 @@ class ForNode(Node): def render(self, context): nodelist = NodeList() - if context.has_key('forloop'): + if 'forloop' in context: parentloop = context['forloop'] else: parentloop = {} @@ -134,7 +134,7 @@ class IfChangedNode(Node): self._varlist = varlist def render(self, context): - if context.has_key('forloop') and context['forloop']['first']: + if 'forloop' in context and context['forloop']['first']: self._last_seen = None try: if self._varlist: @@ -433,7 +433,7 @@ def cycle(parser, token): name = args[1] if not hasattr(parser, '_namedCycleNodes'): raise TemplateSyntaxError("No named cycles in template: '%s' is not defined" % name) - if not parser._namedCycleNodes.has_key(name): + if name not in parser._namedCycleNodes: raise TemplateSyntaxError("Named cycle '%s' does not exist" % name) return parser._namedCycleNodes[name] @@ -912,7 +912,7 @@ def templatetag(parser, token): if len(bits) != 2: raise TemplateSyntaxError, "'templatetag' statement takes one argument" tag = bits[1] - if not TemplateTagNode.mapping.has_key(tag): + if tag not in TemplateTagNode.mapping: raise TemplateSyntaxError, "Invalid templatetag argument: '%s'. Must be one of: %s" % \ (tag, TemplateTagNode.mapping.keys()) return TemplateTagNode(tag) diff --git a/django/utils/datastructures.py b/django/utils/datastructures.py index cca30b462d..60bc0051a2 100644 --- a/django/utils/datastructures.py +++ b/django/utils/datastructures.py @@ -42,7 +42,7 @@ class MergeDict(object): def has_key(self, key): for dict in self.dicts: - if dict.has_key(key): + if key in dict: return True return False diff --git a/django/utils/functional.py b/django/utils/functional.py index e3c0a3c76b..0c31c1f375 100644 --- a/django/utils/functional.py +++ b/django/utils/functional.py @@ -42,7 +42,7 @@ def lazy(func, *resultclasses): res = self.__func(*self.__args, **self.__kw) return self.__dispatch[type(res)][funcname](res, *args, **kw) - if not self.__dispatch.has_key(klass): + if klass not in self.__dispatch: self.__dispatch[klass] = {} self.__dispatch[klass][funcname] = func return __wrapper__ diff --git a/django/utils/translation/trans_real.py b/django/utils/translation/trans_real.py index 2878d9ad0a..2b8e8fa448 100644 --- a/django/utils/translation/trans_real.py +++ b/django/utils/translation/trans_real.py @@ -200,7 +200,7 @@ def deactivate(): will resolve against the default translation object, again. """ global _active - if _active.has_key(currentThread()): + if currentThread() in _active: del _active[currentThread()] def get_language(): diff --git a/django/views/i18n.py b/django/views/i18n.py index 0a19cfe986..0fec6b6c6f 100644 --- a/django/views/i18n.py +++ b/django/views/i18n.py @@ -97,7 +97,7 @@ def javascript_catalog(request, domain='djangojs', packages=None): deliver your JavaScript source from Django templates. """ if request.GET: - if request.GET.has_key('language'): + if 'language' in request.GET: if check_for_language(request.GET['language']): activate(request.GET['language']) if packages is None: @@ -136,7 +136,7 @@ def javascript_catalog(request, domain='djangojs', packages=None): t.update(catalog._catalog) src = [LibHead] plural = None - if t.has_key(''): + if '' in t: for l in t[''].split('\n'): if l.startswith('Plural-Forms:'): plural = l.split(':',1)[1].strip() @@ -155,7 +155,7 @@ def javascript_catalog(request, domain='djangojs', packages=None): if type(k) in (str, unicode): csrc.append("catalog['%s'] = '%s';\n" % (javascript_quote(k), javascript_quote(v))) elif type(k) == tuple: - if not pdict.has_key(k[0]): + if k[0] not in pdict: pdict[k[0]] = k[1] else: pdict[k[0]] = max(k[1], pdict[k[0]]) diff --git a/docs/authentication.txt b/docs/authentication.txt index 14ca581877..091a30a895 100644 --- a/docs/authentication.txt +++ b/docs/authentication.txt @@ -208,7 +208,8 @@ Hashtype is either ``sha1`` (default), ``md5`` or ``crypt`` -- the algorithm used to perform a one-way hash of the password. Salt is a random string used to salt the raw password to create the hash. Note that the ``crypt`` method is only supported on platforms that have the standard Python ``crypt`` module -available. +available, and ``crypt`` support is only available in the Django development +version. For example:: diff --git a/docs/db-api.txt b/docs/db-api.txt index d2aa6b8bb3..9d2f09daf3 100644 --- a/docs/db-api.txt +++ b/docs/db-api.txt @@ -112,7 +112,7 @@ the previous record in the database:: b4 = Blog(id=3, name='Not Cheddar', tagline='Anything but cheese.') b4.save() # Overrides the previous blog with ID=3! -See _`How Django knows to UPDATE vs. INSERT`, below, for the reason this +See `How Django knows to UPDATE vs. INSERT`_, below, for the reason this happens. Explicitly specifying auto-primary-key values is mostly useful for bulk-saving @@ -714,7 +714,7 @@ QuerySet methods that do not return QuerySets The following ``QuerySet`` methods evaluate the ``QuerySet`` and return something *other than* a ``QuerySet``. -These methods do not use a cache (see _`Caching and QuerySets` below). Rather, +These methods do not use a cache (see `Caching and QuerySets`_ below). Rather, they query the database each time they're called. ``get(**kwargs)`` @@ -906,8 +906,8 @@ The database API supports the following lookup types: exact ~~~~~ -Exact match. If the value provided for comparison is ``None``, it will -be interpreted as an SQL ``NULL`` (See isnull_ for more details). +Exact match. If the value provided for comparison is ``None``, it will +be interpreted as an SQL ``NULL`` (See isnull_ for more details). Examples:: diff --git a/docs/email.txt b/docs/email.txt index 1f4ce4ef42..8ebdaa8136 100644 --- a/docs/email.txt +++ b/docs/email.txt @@ -19,13 +19,22 @@ In two lines:: send_mail('Subject here', 'Here is the message.', 'from@example.com', ['to@example.com'], fail_silently=False) - + +Mail will be sent using the SMTP host and port specified in the `EMAIL_HOST`_ +and `EMAIL_PORT`_ settings. The `EMAIL_HOST_USER`_ and `EMAIL_HOST_PASSWORD`_ +settings, if set, will be used to authenticate to the SMTP server. + .. note:: The character set of email sent with ``django.core.mail`` will be set to the value of your `DEFAULT_CHARSET setting`_. - -.. _DEFAULT_CHARSET setting: ../settings/#DEFAULT_CHARSET + +.. _DEFAULT_CHARSET setting: ../settings/#default-charset +.. _EMAIL_HOST: ../settings/#email-host +.. _EMAIL_PORT: ../settings/#email-port +.. _EMAIL_HOST_USER: ../settings/#email-host-user +.. _EMAIL_HOST_PASSWORD: ../settings/#email-host-password + send_mail() =========== diff --git a/docs/forms.txt b/docs/forms.txt index 144b70f13b..329e84a1b1 100644 --- a/docs/forms.txt +++ b/docs/forms.txt @@ -517,7 +517,7 @@ to put punctuation at the end of your validation messages. When are validators called? --------------------------- -After a form has been submitted, Django validates each field in turn. First, +After a form has been submitted, Django validates each field in turn. First, if the field is required, Django checks that it is present and non-empty. Then, if that test passes *and the form submission contained data* for that field, all the validators for that field are called in turn. The emphasized portion in the @@ -615,15 +615,19 @@ fails. If no message is passed in, a default message is used. ``other_value``, then the validators in ``validator_list`` are all run against the current field. +``RequiredIfOtherFieldGiven`` + Takes a field name of the current field is only required if the other + field has a value. + +``RequiredIfOtherFieldsGiven`` + Similar to ``RequiredIfOtherFieldGiven``, except that it takes a list of + field names and if any one of the supplied fields has a value provided, + the current field being validated is required. + ``RequiredIfOtherFieldNotGiven`` Takes the name of the other field and this field is only required if the other field has no value. -``RequiredIfOtherFieldsNotGiven`` - Similar to ``RequiredIfOtherFieldNotGiven``, except that it takes a list - of field names and if any one of the supplied fields does not have a value - provided, the field being validated is required. - ``RequiredIfOtherFieldEquals`` and ``RequiredIfOtherFieldDoesNotEqual`` Each of these validator classes takes a field name and a value (in that order). If the given field does (or does not have, in the latter case) the @@ -650,8 +654,8 @@ fails. If no message is passed in, a default message is used. ``NumberIsInRange`` Takes two boundary numbers, ``lower`` and ``upper``, and checks that the field is greater than ``lower`` (if given) and less than ``upper`` (if - given). - + given). + Both checks are inclusive. That is, ``NumberIsInRange(10, 20)`` will allow values of both 10 and 20. This validator only checks numeric values (e.g., float and integer values). diff --git a/docs/install.txt b/docs/install.txt index 4650fd746b..112a92d2f5 100644 --- a/docs/install.txt +++ b/docs/install.txt @@ -45,16 +45,16 @@ Get your database running ========================= If you plan to use Django's database API functionality, you'll need to -make sure a database server is running. Django works with PostgreSQL_ -(recommended), MySQL_ and SQLite_. +make sure a database server is running. Django works with PostgreSQL_, +MySQL_ and SQLite_. Additionally, you'll need to make sure your Python database bindings are installed. -* If you're using PostgreSQL, you'll need the psycopg_ package (version 2 is - recommended with ``postgresql_psycopg2`` backend, version 1.1 works also with the - ``postgresql``` backend). - +* If you're using PostgreSQL, you'll need the psycopg_ package. Django supports + both version 1 and 2. (When you configure Django's database layer, specify + either ``postgresql`` [for version 1] or ``postgresql_psycopg2`` [for version 2].) + If you're on Windows, check out the unofficial `compiled Windows version`_. * If you're using MySQL, you'll need MySQLdb_, version 1.2.1p2 or higher. diff --git a/docs/settings.txt b/docs/settings.txt index 4bdf1c4006..39179248de 100644 --- a/docs/settings.txt +++ b/docs/settings.txt @@ -395,8 +395,10 @@ EMAIL_HOST_PASSWORD Default: ``''`` (Empty string) -Username to use for the SMTP server defined in ``EMAIL_HOST``. If empty, -Django won't attempt authentication. +Password to use for the SMTP server defined in ``EMAIL_HOST``. This setting is +used in conjunction with ``EMAIL_HOST_USER`` when authenticating to the SMTP +server. If either of these settings is empty, Django won't attempt +authenticaion. See also ``EMAIL_HOST_USER``. @@ -570,9 +572,23 @@ strings for translation, but the translation won't happen at runtime -- so you'll have to remember to wrap the languages in the *real* ``gettext()`` in any code that uses ``LANGUAGES`` at runtime. +LOGIN_REDIRECT_URL +------------------ + +**New in Django development version** + +Default: ``'/accounts/profile/'`` + +The URL where requests are redirected after login when the +``contrib.auth.login`` view gets no ``next`` parameter. + +This is used by the `@login_required`_ decorator, for example. + LOGIN_URL --------- +**New in Django development version** + Default: ``'/accounts/login/'`` The URL where requests are redirected for login, specially when using the @@ -581,6 +597,8 @@ The URL where requests are redirected for login, specially when using the LOGOUT_URL ---------- +**New in Django development version** + Default: ``'/accounts/logout/'`` LOGIN_URL counterpart. @@ -643,16 +661,6 @@ locales have different formats. For example, U.S. English would say See `allowed date format strings`_. See also DATE_FORMAT, DATETIME_FORMAT, TIME_FORMAT and YEAR_MONTH_FORMAT. -LOGIN_REDIRECT_URL ------------------- - -Default: ``'/accounts/profile/'`` - -The URL where requests are redirected after login when the -``contrib.auth.login`` view gets no ``next`` parameter. - -This is used by the `@login_required`_ decorator, for example. - PREPEND_WWW ----------- diff --git a/tests/modeltests/model_forms/models.py b/tests/modeltests/model_forms/models.py index 14ec96940f..6855be0580 100644 --- a/tests/modeltests/model_forms/models.py +++ b/tests/modeltests/model_forms/models.py @@ -24,6 +24,12 @@ a commit=True parameter. from django.db import models +ARTICLE_STATUS = ( + (1, 'Draft'), + (2, 'Pending'), + (3, 'Live'), +) + class Category(models.Model): name = models.CharField(maxlength=20) url = models.CharField('The URL', maxlength=40) @@ -44,6 +50,7 @@ class Article(models.Model): writer = models.ForeignKey(Writer) article = models.TextField() categories = models.ManyToManyField(Category, blank=True) + status = models.IntegerField(choices=ARTICLE_STATUS, blank=True, null=True) def save(self): import datetime @@ -147,8 +154,8 @@ Create a couple of Writers. >>> w = Writer(name='Bob Woodward') >>> w.save() -ManyToManyFields are represented by a MultipleChoiceField, and ForeignKeys are -represented by a ChoiceField. +ManyToManyFields are represented by a MultipleChoiceField, ForeignKeys and any +fields with the 'choices' attribute are represented by a ChoiceField. >>> ArticleForm = form_for_model(Article) >>> f = ArticleForm(auto_id=False) >>> print f @@ -160,6 +167,12 @@ represented by a ChoiceField. Article: +Status: Categories:
  • Article:
  • +
  • Status:
  • Categories:
  • Article:
  • +
  • Status:
  • Categories:
  • Article:
  • +
  • Status:
  • Categories:
  • Article:
  • +
  • Status:
  • Categories: \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n' + +## CLRutField ############################################################# + +CLRutField is a Field that checks the validity of the Chilean +personal identification number (RUT). It has two modes relaxed (default) and +strict. + +>>> from django.contrib.localflavor.cl.forms import CLRutField +>>> rut = CLRutField() + +>>> rut.clean('11-6') +'11-6' +>>> rut.clean('116') +'11-6' + +# valid format, bad verifier. +>>> rut.clean('11.111.111-0') +Traceback (most recent call last): +... +ValidationError: [u'The Chilean RUT is not valid.'] +>>> rut.clean('111') +Traceback (most recent call last): +... +ValidationError: [u'The Chilean RUT is not valid.'] + +>>> rut.clean('767484100') +'76.748.410-0' +>>> rut.clean('78.412.790-7') +'78.412.790-7' +>>> rut.clean('8.334.6043') +'8.334.604-3' +>>> rut.clean('76793310-K') +'76.793.310-K' + +Strict RUT usage (does not allow imposible values) +>>> rut = CLRutField(strict=True) + +>>> rut.clean('11-6') +Traceback (most recent call last): +... +ValidationError: [u'Enter valid a Chilean RUT. The format is XX.XXX.XXX-X.'] + +# valid format, bad verifier. +>>> rut.clean('11.111.111-0') +Traceback (most recent call last): +... +ValidationError: [u'The Chilean RUT is not valid.'] + +# Correct input, invalid format. +>>> rut.clean('767484100') +Traceback (most recent call last): +... +ValidationError: [u'Enter valid a Chilean RUT. The format is XX.XXX.XXX-X.'] +>>> rut.clean('78.412.790-7') +'78.412.790-7' +>>> rut.clean('8.334.6043') +Traceback (most recent call last): +... +ValidationError: [u'Enter valid a Chilean RUT. The format is XX.XXX.XXX-X.'] +>>> rut.clean('76793310-K') +Traceback (most recent call last): +... +ValidationError: [u'Enter valid a Chilean RUT. The format is XX.XXX.XXX-X.'] + """ diff --git a/tests/regressiontests/forms/tests.py b/tests/regressiontests/forms/tests.py index 8f8b3c828a..0d3a65277c 100644 --- a/tests/regressiontests/forms/tests.py +++ b/tests/regressiontests/forms/tests.py @@ -5,6 +5,7 @@ from regressions import regression_tests form_tests = r""" >>> from django.newforms import * >>> import datetime +>>> import time >>> import re ########### @@ -2600,6 +2601,27 @@ underscores converted to spaces, and the initial letter capitalized.
  • Password1:
  • Password (again):
  • +Labels for as_* methods will only end in a colon if they don't end in other +punctuation already. +>>> class Questions(Form): +... q1 = CharField(label='The first question') +... q2 = CharField(label='What is your name?') +... q3 = CharField(label='The answer to life is:') +... q4 = CharField(label='Answer this question!') +... q5 = CharField(label='The last question. Period.') +>>> print Questions(auto_id=False).as_p() +

    The first question:

    +

    What is your name?

    +

    The answer to life is:

    +

    Answer this question!

    +

    The last question. Period.

    +>>> print Questions().as_p() +

    +

    +

    +

    +

    + A label can be a Unicode object or a bytestring with special characters. >>> class UserRegistration(Form): ... username = CharField(max_length=10, label='ŠĐĆŽćžšđ') @@ -3297,6 +3319,94 @@ True +# MultiWidget and MultiValueField ############################################# +# MultiWidgets are widgets composed of other widgets. They are usually +# combined with MultiValueFields - a field that is composed of other fields. +# MulitWidgets can themselved be composed of other MultiWidgets. +# SplitDateTimeWidget is one example of a MultiWidget. + +>>> class ComplexMultiWidget(MultiWidget): +... def __init__(self, attrs=None): +... widgets = ( +... TextInput(), +... SelectMultiple(choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), +... SplitDateTimeWidget(), +... ) +... super(ComplexMultiWidget, self).__init__(widgets, attrs) +... +... def decompress(self, value): +... if value: +... data = value.split(',') +... return [data[0], data[1], datetime.datetime(*time.strptime(data[2], "%Y-%m-%d %H:%M:%S")[0:6])] +... return [None, None, None] +... def format_output(self, rendered_widgets): +... return u'\n'.join(rendered_widgets) +>>> w = ComplexMultiWidget() +>>> print w.render('name', 'some text,JP,2007-04-25 06:24:00') + + + + +>>> class ComplexField(MultiValueField): +... def __init__(self, required=True, widget=None, label=None, initial=None): +... fields = ( +... CharField(), +... MultipleChoiceField(choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), +... SplitDateTimeField() +... ) +... super(ComplexField, self).__init__(fields, required, widget, label, initial) +... +... def compress(self, data_list): +... if data_list: +... return '%s,%s,%s' % (data_list[0],''.join(data_list[1]),data_list[2]) +... return None + +>>> f = ComplexField(widget=w) +>>> f.clean(['some text', ['J','P'], ['2007-04-25','6:24:00']]) +u'some text,JP,2007-04-25 06:24:00' +>>> f.clean(['some text',['X'], ['2007-04-25','6:24:00']]) +Traceback (most recent call last): +... +ValidationError: [u'Select a valid choice. X is not one of the available choices.'] + +# If insufficient data is provided, None is substituted +>>> f.clean(['some text',['JP']]) +Traceback (most recent call last): +... +ValidationError: [u'This field is required.'] + +>>> class ComplexFieldForm(Form): +... field1 = ComplexField(widget=w) +>>> f = ComplexFieldForm() +>>> print f + + + + +>>> f = ComplexFieldForm({'field1_0':'some text','field1_1':['J','P'], 'field1_2_0':'2007-04-25', 'field1_2_1':'06:24:00'}) +>>> print f + + + + +>>> f.clean_data +{'field1': u'some text,JP,2007-04-25 06:24:00'} + ################################# # Tests of underlying functions # ################################# diff --git a/tests/regressiontests/httpwrappers/tests.py b/tests/regressiontests/httpwrappers/tests.py index 385c3048d9..29cb8385e0 100644 --- a/tests/regressiontests/httpwrappers/tests.py +++ b/tests/regressiontests/httpwrappers/tests.py @@ -34,6 +34,9 @@ AttributeError: This QueryDict instance is immutable >>> q.has_key('foo') False +>>> 'foo' in q +False + >>> q.items() [] @@ -124,6 +127,9 @@ MultiValueDictKeyError: "Key 'foo' not found in " >>> q.has_key('foo') True +>>> 'foo' in q +True + >>> q.items() [('foo', 'another'), ('name', 'john')] @@ -218,9 +224,15 @@ AttributeError: This QueryDict instance is immutable >>> q.has_key('foo') True +>>> 'foo' in q +True + >>> q.has_key('bar') False +>>> 'bar' in q +False + >>> q.items() [('foo', 'bar')] @@ -303,9 +315,15 @@ AttributeError: This QueryDict instance is immutable >>> q.has_key('vote') True +>>> 'vote' in q +True + >>> q.has_key('foo') False +>>> 'foo' in q +False + >>> q.items() [('vote', 'no')] diff --git a/tests/regressiontests/templates/tests.py b/tests/regressiontests/templates/tests.py index f1590ff92a..db888f78d2 100644 --- a/tests/regressiontests/templates/tests.py +++ b/tests/regressiontests/templates/tests.py @@ -133,6 +133,18 @@ class Templates(unittest.TestCase): # Fail silently when accessing a non-simple method 'basic-syntax20': ("{{ var.method2 }}", {"var": SomeClass()}, ("","INVALID")), + # Don't get confused when parsing something that is almost, but not + # quite, a template tag. + 'basic-syntax21': ("a {{ moo %} b", {}, "a {{ moo %} b"), + 'basic-syntax22': ("{{ moo #}", {}, "{{ moo #}"), + + # Will try to treat "moo #} {{ cow" as the variable. Not ideal, but + # costly to work around, so this triggers an error. + 'basic-syntax23': ("{{ moo #} {{ cow }}", {"cow": "cow"}, template.TemplateSyntaxError), + + # Embedded newlines make it not-a-tag. + 'basic-syntax24': ("{{ moo\n }}", {}, "{{ moo\n }}"), + # List-index syntax allows a template to access a certain item of a subscriptable object. 'list-index01': ("{{ var.1 }}", {"var": ["first item", "second item"]}, "second item"), @@ -157,60 +169,61 @@ class Templates(unittest.TestCase): 'list-index07': ("{{ var.1 }}", {"var": {'1': "hello", 1: "world"}}, "hello"), # Basic filter usage - 'basic-syntax21': ("{{ var|upper }}", {"var": "Django is the greatest!"}, "DJANGO IS THE GREATEST!"), + 'filter-syntax01': ("{{ var|upper }}", {"var": "Django is the greatest!"}, "DJANGO IS THE GREATEST!"), # Chained filters - 'basic-syntax22': ("{{ var|upper|lower }}", {"var": "Django is the greatest!"}, "django is the greatest!"), + 'filter-syntax02': ("{{ var|upper|lower }}", {"var": "Django is the greatest!"}, "django is the greatest!"), # Raise TemplateSyntaxError for space between a variable and filter pipe - 'basic-syntax23': ("{{ var |upper }}", {}, template.TemplateSyntaxError), + 'filter-syntax03': ("{{ var |upper }}", {}, template.TemplateSyntaxError), # Raise TemplateSyntaxError for space after a filter pipe - 'basic-syntax24': ("{{ var| upper }}", {}, template.TemplateSyntaxError), + 'filter-syntax04': ("{{ var| upper }}", {}, template.TemplateSyntaxError), # Raise TemplateSyntaxError for a nonexistent filter - 'basic-syntax25': ("{{ var|does_not_exist }}", {}, template.TemplateSyntaxError), + 'filter-syntax05': ("{{ var|does_not_exist }}", {}, template.TemplateSyntaxError), # Raise TemplateSyntaxError when trying to access a filter containing an illegal character - 'basic-syntax26': ("{{ var|fil(ter) }}", {}, template.TemplateSyntaxError), + 'filter-syntax06': ("{{ var|fil(ter) }}", {}, template.TemplateSyntaxError), # Raise TemplateSyntaxError for invalid block tags - 'basic-syntax27': ("{% nothing_to_see_here %}", {}, template.TemplateSyntaxError), + 'filter-syntax07': ("{% nothing_to_see_here %}", {}, template.TemplateSyntaxError), # Raise TemplateSyntaxError for empty block tags - 'basic-syntax28': ("{% %}", {}, template.TemplateSyntaxError), + 'filter-syntax08': ("{% %}", {}, template.TemplateSyntaxError), # Chained filters, with an argument to the first one - 'basic-syntax29': ('{{ var|removetags:"b i"|upper|lower }}', {"var": "Yes"}, "yes"), + 'filter-syntax09': ('{{ var|removetags:"b i"|upper|lower }}', {"var": "Yes"}, "yes"), # Escaped string as argument - 'basic-syntax30': (r'{{ var|default_if_none:" endquote\" hah" }}', {"var": None}, ' endquote" hah'), + 'filter-syntax10': (r'{{ var|default_if_none:" endquote\" hah" }}', {"var": None}, ' endquote" hah'), # Variable as argument - 'basic-syntax31': (r'{{ var|default_if_none:var2 }}', {"var": None, "var2": "happy"}, 'happy'), + 'filter-syntax11': (r'{{ var|default_if_none:var2 }}', {"var": None, "var2": "happy"}, 'happy'), # Default argument testing - 'basic-syntax32': (r'{{ var|yesno:"yup,nup,mup" }} {{ var|yesno }}', {"var": True}, 'yup yes'), + 'filter-syntax12': (r'{{ var|yesno:"yup,nup,mup" }} {{ var|yesno }}', {"var": True}, 'yup yes'), - # Fail silently for methods that raise an exception with a "silent_variable_failure" attribute - 'basic-syntax33': (r'1{{ var.method3 }}2', {"var": SomeClass()}, ("12", "1INVALID2")), + # Fail silently for methods that raise an exception with a + # "silent_variable_failure" attribute + 'filter-syntax13': (r'1{{ var.method3 }}2', {"var": SomeClass()}, ("12", "1INVALID2")), - # In methods that raise an exception without a "silent_variable_attribute" set to True, - # the exception propagates - 'basic-syntax34': (r'1{{ var.method4 }}2', {"var": SomeClass()}, SomeOtherException), + # In methods that raise an exception without a + # "silent_variable_attribute" set to True, the exception propagates + 'filter-syntax14': (r'1{{ var.method4 }}2', {"var": SomeClass()}, SomeOtherException), # Escaped backslash in argument - 'basic-syntax35': (r'{{ var|default_if_none:"foo\bar" }}', {"var": None}, r'foo\bar'), + 'filter-syntax15': (r'{{ var|default_if_none:"foo\bar" }}', {"var": None}, r'foo\bar'), # Escaped backslash using known escape char - 'basic-syntax35': (r'{{ var|default_if_none:"foo\now" }}', {"var": None}, r'foo\now'), + 'filter-syntax16': (r'{{ var|default_if_none:"foo\now" }}', {"var": None}, r'foo\now'), # Empty strings can be passed as arguments to filters - 'basic-syntax36': (r'{{ var|join:"" }}', {'var': ['a', 'b', 'c']}, 'abc'), + 'filter-syntax17': (r'{{ var|join:"" }}', {'var': ['a', 'b', 'c']}, 'abc'), # Make sure that any unicode strings are converted to bytestrings # in the final output. - 'basic-syntax37': (r'{{ var }}', {'var': UnicodeInStrClass()}, '\xc5\xa0\xc4\x90\xc4\x86\xc5\xbd\xc4\x87\xc5\xbe\xc5\xa1\xc4\x91'), + 'filter-syntax18': (r'{{ var }}', {'var': UnicodeInStrClass()}, '\xc5\xa0\xc4\x90\xc4\x86\xc5\xbd\xc4\x87\xc5\xbe\xc5\xa1\xc4\x91'), ### COMMENT SYNTAX ######################################################## 'comment-syntax01': ("{# this is hidden #}hello", {}, "hello"),