Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Merge branch 'master' of https://github.com/django/django

  • Loading branch information...
commit eee791e9b216333ad0b4c6c441a88828bf9aee62 2 parents fbb7389 + 840ffd8
@bohyn bohyn authored
Showing with 3,275 additions and 2,324 deletions.
  1. +3 −2 AUTHORS
  2. +11 −11 django/contrib/admin/static/admin/js/actions.js
  3. +6 −7 django/contrib/admin/static/admin/js/actions.min.js
  4. +13 −13 django/contrib/admin/static/admin/js/inlines.js
  5. +5 −5 django/contrib/admin/static/admin/js/inlines.min.js
  6. +6 −2 django/contrib/admin/templates/admin/index.html
  7. +1 −0  django/contrib/admin/views/main.py
  8. +7 −7 django/contrib/auth/management/commands/createsuperuser.py
  9. +4 −9 django/contrib/auth/tests/management.py
  10. +11 −0 django/contrib/flatpages/fixtures/example_site.json
  11. +2 −1  django/contrib/flatpages/tests/csrf.py
  12. +4 −1 django/contrib/flatpages/tests/forms.py
  13. +7 −5 django/contrib/flatpages/tests/middleware.py
  14. +1 −0  django/contrib/flatpages/tests/templatetags.py
  15. +5 −3 django/contrib/flatpages/tests/views.py
  16. +27 −30 django/contrib/formtools/tests/__init__.py
  17. +8 −6 django/contrib/formtools/tests/wizard/namedwizardtests/tests.py
  18. +6 −6 django/contrib/formtools/tests/wizard/wizardtests/tests.py
  19. +2 −4 django/contrib/formtools/utils.py
  20. +8 −0 django/contrib/gis/admin/options.py
  21. +2 −2 django/contrib/gis/gdal/base.py
  22. +3 −1 django/contrib/gis/gdal/tests/__init__.py
  23. +3 −1 django/contrib/gis/geoip/__init__.py
  24. +2 −2 django/contrib/gis/geos/base.py
  25. +20 −9 django/contrib/gis/geos/mutable_list.py
  26. +3 −1 django/contrib/gis/geos/tests/__init__.py
  27. +65 −60 django/contrib/gis/geos/tests/test_geos.py
  28. +9 −3 django/contrib/gis/maps/google/overlays.py
  29. +20 −4 django/contrib/gis/measure.py
  30. +1 −1  django/contrib/gis/templates/gis/admin/openlayers.js
  31. +19 −0 django/contrib/gis/tests/geoadmin/tests.py
  32. +1 −0  django/contrib/gis/tests/layermap/models.py
  33. +34 −31 django/contrib/gis/tests/layermap/tests.py
  34. +1 −1  django/contrib/gis/utils/layermapping.py
  35. +1 −1  django/contrib/humanize/tests.py
  36. +1 −1  django/contrib/localflavor/es/es_provinces.py
  37. +2 −1  django/contrib/messages/tests/base.py
  38. +0 −10 django/contrib/sitemaps/tests/base.py
  39. +11 −2 django/contrib/sitemaps/tests/http.py
  40. +2 −5 django/contrib/staticfiles/management/commands/collectstatic.py
  41. +2 −4 django/contrib/staticfiles/management/commands/findstatic.py
  42. +16 −7 django/contrib/staticfiles/storage.py
  43. +1 −1  django/core/context_processors.py
  44. +1 −0  django/core/exceptions.py
  45. +3 −2 django/core/files/base.py
  46. +2 −2 django/core/files/uploadedfile.py
  47. +5 −5 django/core/handlers/wsgi.py
  48. +46 −32 django/core/management/base.py
  49. +1 −1  django/core/management/commands/compilemessages.py
  50. +7 −8 django/core/management/commands/createcachetable.py
  51. +16 −12 django/core/management/commands/dumpdata.py
  52. +5 −0 django/core/management/commands/inspectdb.py
  53. +18 −18 django/core/management/commands/loaddata.py
  54. +2 −2 django/core/management/commands/runserver.py
  55. +2 −4 django/core/management/templates.py
  56. +3 −0  django/core/serializers/base.py
  57. +27 −2 django/core/serializers/json.py
  58. +8 −5 django/core/serializers/python.py
  59. +12 −14 django/core/servers/basehttp.py
  60. +2 −4 django/core/urlresolvers.py
  61. +10 −5 django/db/backends/__init__.py
  62. +11 −2 django/db/backends/mysql/base.py
  63. +1 −0  django/db/backends/oracle/base.py
  64. +9 −9 django/db/backends/sqlite3/base.py
  65. +3 −9 django/db/models/base.py
  66. +10 −15 django/db/models/fields/__init__.py
  67. +21 −0 django/db/models/fields/files.py
  68. +40 −23 django/db/models/fields/related.py
  69. +13 −8 django/db/models/query.py
  70. +32 −17 django/db/models/query_utils.py
  71. +12 −2 django/db/models/sql/compiler.py
  72. +2 −1  django/db/models/sql/where.py
  73. +5 −5 django/dispatch/saferef.py
  74. +5 −1 django/forms/fields.py
  75. +2 −2 django/forms/models.py
  76. +3 −3 django/http/__init__.py
  77. +19 −19 django/http/multipartparser.py
  78. +1 −1  django/template/loaders/app_directories.py
  79. +1 −1  django/template/loaders/filesystem.py
  80. +1 −1  django/templatetags/i18n.py
  81. +32 −38 django/test/client.py
  82. +2 −2 django/utils/cache.py
  83. +5 −4 django/utils/crypto.py
  84. +4 −5 django/utils/encoding.py
  85. +15 −8 django/utils/functional.py
  86. +1 −1  django/utils/html.py
  87. +15 −4 django/views/debug.py
  88. +6 −6 django/views/decorators/debug.py
  89. +10 −2 django/views/generic/base.py
  90. +168 −77 django/views/generic/dates.py
  91. +2 −3 django/views/generic/detail.py
  92. +16 −7 django/views/generic/list.py
  93. +8 −4 docs/howto/custom-management-commands.txt
  94. BIN  docs/intro/_images/admin10.png
  95. BIN  docs/intro/_images/admin11.png
  96. BIN  docs/intro/_images/admin11t.png
  97. BIN  docs/intro/_images/admin12.png
  98. +28 −17 docs/intro/tutorial01.txt
  99. +6 −6 docs/intro/tutorial02.txt
  100. +2 −2 docs/intro/tutorial03.txt
  101. +2 −2 docs/intro/tutorial04.txt
  102. +17 −1 docs/ref/class-based-views.txt
  103. +1 −0  docs/ref/contrib/formtools/form-wizard.txt
  104. +1 −1  docs/ref/contrib/gis/geoquerysets.txt
  105. +9 −0 docs/ref/contrib/staticfiles.txt
  106. +1 −1  docs/ref/files/file.txt
  107. +3 −2 docs/ref/settings.txt
  108. +4 −3 docs/ref/templates/api.txt
  109. +2 −2 docs/ref/unicode.txt
  110. +60 −1 docs/releases/1.5.txt
  111. +0 −3  docs/topics/class-based-views.txt
  112. +2 −0  docs/topics/forms/formsets.txt
  113. +1 −1  docs/topics/forms/index.txt
  114. +1 −1  docs/topics/i18n/timezones.txt
  115. +86 −52 docs/topics/install.txt
  116. +10 −13 docs/topics/security.txt
  117. +11 −2 docs/topics/settings.txt
  118. +34 −23 docs/topics/testing.txt
  119. +36 −0 setup.py
  120. +15 −0 tests/modeltests/defer/tests.py
  121. +4 −0 tests/modeltests/field_subclassing/tests.py
  122. +12 −1 tests/modeltests/files/tests.py
  123. +15 −15 tests/modeltests/fixtures/tests.py
  124. 0  tests/modeltests/known_related_objects/__init__.py
  125. +65 −0 tests/modeltests/known_related_objects/fixtures/tournament.json
  126. +19 −0 tests/modeltests/known_related_objects/models.py
  127. +88 −0 tests/modeltests/known_related_objects/tests.py
  128. +7 −7 tests/modeltests/model_forms/tests.py
  129. +18 −0 tests/modeltests/model_inheritance/tests.py
  130. +9 −9 tests/modeltests/serializers/tests.py
  131. +4 −4 tests/modeltests/str/tests.py
  132. +1 −4 tests/modeltests/update_only_fields/tests.py
  133. +5 −3 tests/modeltests/user_commands/management/commands/dance.py
  134. +19 −2 tests/modeltests/user_commands/tests.py
  135. +52 −104 tests/modeltests/validation/test_error_messages.py
  136. +7 −4 tests/regressiontests/admin_scripts/tests.py
  137. +1 −1  tests/regressiontests/admin_util/tests.py
  138. +1 −1  tests/regressiontests/admin_widgets/tests.py
  139. +12 −0 tests/regressiontests/backends/tests.py
  140. +8 −4 tests/regressiontests/cache/tests.py
  141. +2 −2 tests/regressiontests/conditional_processing/models.py
  142. +1 −1  tests/regressiontests/csrf_tests/tests.py
  143. +27 −27 tests/regressiontests/file_storage/tests.py
  144. +16 −16 tests/regressiontests/file_uploads/tests.py
  145. +0 −19 tests/regressiontests/fixtures_regress/tests.py
  146. +29 −30 tests/regressiontests/forms/tests/fields.py
  147. 0  tests/regressiontests/forms/tests/filepath_test_files/.dot-file
  148. 0  tests/regressiontests/forms/tests/filepath_test_files/directory/.keep
  149. 0  tests/regressiontests/forms/tests/filepath_test_files/fake-image.jpg
  150. 0  tests/regressiontests/forms/tests/filepath_test_files/real-text-file.txt
  151. +3 −3 tests/regressiontests/forms/tests/forms.py
  152. +3 −3 tests/regressiontests/forms/tests/models.py
  153. +3 −2 tests/regressiontests/forms/tests/regressions.py
  154. +1 −1  tests/regressiontests/forms/tests/widgets.py
  155. +52 −0 tests/regressiontests/generic_views/base.py
  156. +28 −3 tests/regressiontests/generic_views/dates.py
  157. +10 −0 tests/regressiontests/generic_views/list.py
  158. +1 −1  tests/regressiontests/generic_views/templates/generic_views/book_archive.html
  159. +1 −1  tests/regressiontests/generic_views/templates/generic_views/book_archive_year.html
  160. +9 −0 tests/regressiontests/generic_views/urls.py
  161. +1 −1  tests/regressiontests/handlers/tests.py
  162. +5 −5 tests/regressiontests/httpwrappers/tests.py
  163. +6 −17 tests/regressiontests/i18n/commands/compilation.py
  164. BIN  tests/regressiontests/i18n/other/locale/fr/LC_MESSAGES/django.mo
  165. +6 −0 tests/regressiontests/i18n/other/locale/fr/LC_MESSAGES/django.po
  166. +16 −2 tests/regressiontests/i18n/tests.py
  167. +24 −2 tests/regressiontests/inspectdb/tests.py
  168. +1 −1  tests/regressiontests/localflavor/es/tests.py
  169. +1 −1  tests/regressiontests/localflavor/mk/tests.py
  170. +25 −25 tests/regressiontests/mail/tests.py
  171. +13 −1 tests/regressiontests/model_fields/tests.py
  172. +3 −3 tests/regressiontests/model_forms_regress/tests.py
  173. +1 −1  tests/regressiontests/queries/models.py
  174. +57 −2 tests/regressiontests/queries/tests.py
  175. +44 −44 tests/regressiontests/requests/tests.py
  176. +3 −3 tests/regressiontests/servers/tests.py
  177. +3 −3 tests/regressiontests/signing/tests.py
  178. +7 −0 tests/regressiontests/staticfiles_tests/storage.py
  179. +76 −46 tests/regressiontests/staticfiles_tests/tests.py
  180. +1 −1  tests/regressiontests/string_lookup/tests.py
  181. +7 −7 tests/regressiontests/templates/tests.py
  182. +6 −6 tests/regressiontests/templates/unicode.py
  183. +0 −1,034 tests/regressiontests/test_client_regress/models.py
  184. +1,006 −0 tests/regressiontests/test_client_regress/tests.py
  185. +2 −3 tests/regressiontests/test_client_regress/views.py
  186. +3 −8 tests/regressiontests/test_runner/tests.py
  187. +3 −3 tests/regressiontests/views/__init__.py
  188. +63 −41 tests/regressiontests/views/tests/debug.py
  189. +5 −5 tests/regressiontests/views/tests/static.py
  190. +21 −2 tests/regressiontests/views/views.py
View
5 AUTHORS
@@ -93,7 +93,7 @@ answer newbie questions, and generally made Django that much better:
Simon Blanchard
David Blewett <david@dawninglight.net>
Matt Boersma <matt@sprout.org>
- boobsd@gmail.com
+ Artem Gnilov <boobsd@gmail.com>
Matías Bordese
Nate Bragg <jonathan.bragg@alum.rpi.edu>
Sean Brant
@@ -211,7 +211,6 @@ answer newbie questions, and generally made Django that much better:
Dimitris Glezos <dimitris@glezos.com>
glin@seznam.cz
martin.glueck@gmail.com
- Artyom Gnilov <boobsd@gmail.com>
Ben Godfrey <http://aftnn.org>
GomoX <gomo@datafull.com>
Guilherme Mesquita Gondim <semente@taurinus.org>
@@ -347,6 +346,7 @@ answer newbie questions, and generally made Django that much better:
Frantisek Malina <vizualbod@vizualbod.com>
Mike Malone <mjmalone@gmail.com>
Martin Maney <http://www.chipy.org/Martin_Maney>
+ Michael Manfre <mmanfre@gmail.com>
masonsimon+django@gmail.com
Manuzhai
Petr Marhoun <petr.marhoun@gmail.com>
@@ -401,6 +401,7 @@ answer newbie questions, and generally made Django that much better:
Christian Oudard <christian.oudard@gmail.com>
oggie rob <oz.robharvey@gmail.com>
oggy <ognjen.maric@gmail.com>
+ Jens Page
Jay Parlar <parlar@gmail.com>
Carlos Eduardo de Paula <carlosedp@gmail.com>
John Paulett <john@paulett.org>
View
22 django/contrib/admin/static/admin/js/actions.js
@@ -3,7 +3,7 @@
var options = $.extend({}, $.fn.actions.defaults, opts);
var actionCheckboxes = $(this);
var list_editable_changed = false;
- checker = function(checked) {
+ var checker = function(checked) {
if (checked) {
showQuestion();
} else {
@@ -11,7 +11,7 @@
}
$(actionCheckboxes).attr("checked", checked)
.parent().parent().toggleClass(options.selectedClass, checked);
- }
+ },
updateCounter = function() {
var sel = $(actionCheckboxes).filter(":checked").length;
$(options.counterContainer).html(interpolate(
@@ -29,30 +29,30 @@
}
return value;
});
- }
+ },
showQuestion = function() {
$(options.acrossClears).hide();
$(options.acrossQuestions).show();
$(options.allContainer).hide();
- }
+ },
showClear = function() {
$(options.acrossClears).show();
$(options.acrossQuestions).hide();
$(options.actionContainer).toggleClass(options.selectedClass);
$(options.allContainer).show();
$(options.counterContainer).hide();
- }
+ },
reset = function() {
$(options.acrossClears).hide();
$(options.acrossQuestions).hide();
$(options.allContainer).hide();
$(options.counterContainer).show();
- }
+ },
clearAcross = function() {
reset();
$(options.acrossInput).val(0);
$(options.actionContainer).removeClass(options.selectedClass);
- }
+ };
// Show counter by default
$(options.counterContainer).show();
// Check state of checkboxes and reinit state if needed
@@ -81,9 +81,9 @@
});
lastChecked = null;
$(actionCheckboxes).click(function(event) {
- if (!event) { var event = window.event; }
+ if (!event) { event = window.event; }
var target = event.target ? event.target : event.srcElement;
- if (lastChecked && $.data(lastChecked) != $.data(target) && event.shiftKey == true) {
+ if (lastChecked && $.data(lastChecked) != $.data(target) && event.shiftKey === true) {
var inrange = false;
$(lastChecked).attr("checked", target.checked)
.parent().parent().toggleClass(options.selectedClass, target.checked);
@@ -124,7 +124,7 @@
}
}
});
- }
+ };
/* Setup plugin defaults */
$.fn.actions.defaults = {
actionContainer: "div.actions",
@@ -135,5 +135,5 @@
acrossClears: "div.actions span.clear",
allToggle: "#action-toggle",
selectedClass: "selected"
- }
+ };
})(django.jQuery);
View
13 django/contrib/admin/static/admin/js/actions.min.js
@@ -1,7 +1,6 @@
-(function(a){a.fn.actions=function(g){var b=a.extend({},a.fn.actions.defaults,g),f=a(this),e=!1;checker=function(c){c?showQuestion():reset();a(f).attr("checked",c).parent().parent().toggleClass(b.selectedClass,c)};updateCounter=function(){var c=a(f).filter(":checked").length;a(b.counterContainer).html(interpolate(ngettext("%(sel)s of %(cnt)s selected","%(sel)s of %(cnt)s selected",c),{sel:c,cnt:_actions_icnt},!0));a(b.allToggle).attr("checked",function(){c==f.length?(value=!0,showQuestion()):(value=
-!1,clearAcross());return value})};showQuestion=function(){a(b.acrossClears).hide();a(b.acrossQuestions).show();a(b.allContainer).hide()};showClear=function(){a(b.acrossClears).show();a(b.acrossQuestions).hide();a(b.actionContainer).toggleClass(b.selectedClass);a(b.allContainer).show();a(b.counterContainer).hide()};reset=function(){a(b.acrossClears).hide();a(b.acrossQuestions).hide();a(b.allContainer).hide();a(b.counterContainer).show()};clearAcross=function(){reset();a(b.acrossInput).val(0);a(b.actionContainer).removeClass(b.selectedClass)};
-a(b.counterContainer).show();a(this).filter(":checked").each(function(){a(this).parent().parent().toggleClass(b.selectedClass);updateCounter();1==a(b.acrossInput).val()&&showClear()});a(b.allToggle).show().click(function(){checker(a(this).attr("checked"));updateCounter()});a("div.actions span.question a").click(function(c){c.preventDefault();a(b.acrossInput).val(1);showClear()});a("div.actions span.clear a").click(function(c){c.preventDefault();a(b.allToggle).attr("checked",!1);clearAcross();checker(0);
-updateCounter()});lastChecked=null;a(f).click(function(c){if(!c)c=window.event;var d=c.target?c.target:c.srcElement;if(lastChecked&&a.data(lastChecked)!=a.data(d)&&!0==c.shiftKey){var e=!1;a(lastChecked).attr("checked",d.checked).parent().parent().toggleClass(b.selectedClass,d.checked);a(f).each(function(){if(a.data(this)==a.data(lastChecked)||a.data(this)==a.data(d))e=e?!1:!0;e&&a(this).attr("checked",d.checked).parent().parent().toggleClass(b.selectedClass,d.checked)})}a(d).parent().parent().toggleClass(b.selectedClass,
-d.checked);lastChecked=d;updateCounter()});a("form#changelist-form table#result_list tr").find("td:gt(0) :input").change(function(){e=!0});a('form#changelist-form button[name="index"]').click(function(){if(e)return confirm(gettext("You have unsaved changes on individual editable fields. If you run an action, your unsaved changes will be lost."))});a('form#changelist-form input[name="_save"]').click(function(){var b=!1;a("div.actions select option:selected").each(function(){a(this).val()&&(b=!0)});
-if(b)return e?confirm(gettext("You have selected an action, but you haven't saved your changes to individual fields yet. Please click OK to save. You'll need to re-run the action.")):confirm(gettext("You have selected an action, and you haven't made any changes on individual fields. You're probably looking for the Go button rather than the Save button."))})};a.fn.actions.defaults={actionContainer:"div.actions",counterContainer:"span.action-counter",allContainer:"div.actions span.all",acrossInput:"div.actions input.select-across",
-acrossQuestions:"div.actions span.question",acrossClears:"div.actions span.clear",allToggle:"#action-toggle",selectedClass:"selected"}})(django.jQuery);
+(function(a){a.fn.actions=function(m){var b=a.extend({},a.fn.actions.defaults,m),f=a(this),e=!1,j=function(c){c?h():i();a(f).attr("checked",c).parent().parent().toggleClass(b.selectedClass,c)},g=function(){var c=a(f).filter(":checked").length;a(b.counterContainer).html(interpolate(ngettext("%(sel)s of %(cnt)s selected","%(sel)s of %(cnt)s selected",c),{sel:c,cnt:_actions_icnt},!0));a(b.allToggle).attr("checked",function(){c==f.length?(value=!0,h()):(value=!1,k());return value})},h=function(){a(b.acrossClears).hide();
+a(b.acrossQuestions).show();a(b.allContainer).hide()},l=function(){a(b.acrossClears).show();a(b.acrossQuestions).hide();a(b.actionContainer).toggleClass(b.selectedClass);a(b.allContainer).show();a(b.counterContainer).hide()},i=function(){a(b.acrossClears).hide();a(b.acrossQuestions).hide();a(b.allContainer).hide();a(b.counterContainer).show()},k=function(){i();a(b.acrossInput).val(0);a(b.actionContainer).removeClass(b.selectedClass)};a(b.counterContainer).show();a(this).filter(":checked").each(function(){a(this).parent().parent().toggleClass(b.selectedClass);
+g();1==a(b.acrossInput).val()&&l()});a(b.allToggle).show().click(function(){j(a(this).attr("checked"));g()});a("div.actions span.question a").click(function(c){c.preventDefault();a(b.acrossInput).val(1);l()});a("div.actions span.clear a").click(function(c){c.preventDefault();a(b.allToggle).attr("checked",!1);k();j(0);g()});lastChecked=null;a(f).click(function(c){c||(c=window.event);var d=c.target?c.target:c.srcElement;if(lastChecked&&a.data(lastChecked)!=a.data(d)&&!0===c.shiftKey){var e=!1;a(lastChecked).attr("checked",
+d.checked).parent().parent().toggleClass(b.selectedClass,d.checked);a(f).each(function(){if(a.data(this)==a.data(lastChecked)||a.data(this)==a.data(d))e=e?false:true;e&&a(this).attr("checked",d.checked).parent().parent().toggleClass(b.selectedClass,d.checked)})}a(d).parent().parent().toggleClass(b.selectedClass,d.checked);lastChecked=d;g()});a("form#changelist-form table#result_list tr").find("td:gt(0) :input").change(function(){e=!0});a('form#changelist-form button[name="index"]').click(function(){if(e)return confirm(gettext("You have unsaved changes on individual editable fields. If you run an action, your unsaved changes will be lost."))});
+a('form#changelist-form input[name="_save"]').click(function(){var b=!1;a("div.actions select option:selected").each(function(){a(this).val()&&(b=!0)});if(b)return e?confirm(gettext("You have selected an action, but you haven't saved your changes to individual fields yet. Please click OK to save. You'll need to re-run the action.")):confirm(gettext("You have selected an action, and you haven't made any changes on individual fields. You're probably looking for the Go button rather than the Save button."))})};
+a.fn.actions.defaults={actionContainer:"div.actions",counterContainer:"span.action-counter",allContainer:"div.actions span.all",acrossInput:"div.actions input.select-across",acrossQuestions:"div.actions span.question",acrossClears:"div.actions span.clear",allToggle:"#action-toggle",selectedClass:"selected"}})(django.jQuery);
View
26 django/contrib/admin/static/admin/js/inlines.js
@@ -31,11 +31,11 @@
}
};
var totalForms = $("#id_" + options.prefix + "-TOTAL_FORMS").attr("autocomplete", "off");
- var nextIndex = parseInt(totalForms.val());
+ var nextIndex = parseInt(totalForms.val(), 10);
var maxForms = $("#id_" + options.prefix + "-MAX_NUM_FORMS").attr("autocomplete", "off");
// only show the add button if we are allowed to add more items,
// note that max_num = None translates to a blank string.
- var showAddButton = maxForms.val() == '' || (maxForms.val()-totalForms.val()) > 0;
+ var showAddButton = maxForms.val() === '' || (maxForms.val()-totalForms.val()) > 0;
$(this).each(function(i) {
$(this).not("." + options.emptyCssClass).addClass(options.formCssClass);
});
@@ -52,13 +52,14 @@
$(this).filter(":last").after('<div class="' + options.addCssClass + '"><a href="javascript:void(0)">' + options.addText + "</a></div>");
addButton = $(this).filter(":last").next().find("a");
}
- addButton.click(function() {
+ addButton.click(function(e) {
+ e.preventDefault();
var totalForms = $("#id_" + options.prefix + "-TOTAL_FORMS");
var template = $("#" + options.prefix + "-empty");
var row = template.clone(true);
row.removeClass(options.emptyCssClass)
- .addClass(options.formCssClass)
- .attr("id", options.prefix + "-" + nextIndex);
+ .addClass(options.formCssClass)
+ .attr("id", options.prefix + "-" + nextIndex);
if (row.is("tr")) {
// If the forms are laid out in table rows, insert
// the remove button into the last table cell:
@@ -78,14 +79,15 @@
// Insert the new form when it has been fully edited
row.insertBefore($(template));
// Update number of total forms
- $(totalForms).val(parseInt(totalForms.val()) + 1);
+ $(totalForms).val(parseInt(totalForms.val(), 10) + 1);
nextIndex += 1;
// Hide add button in case we've hit the max, except we want to add infinitely
- if ((maxForms.val() != '') && (maxForms.val()-totalForms.val()) <= 0) {
+ if ((maxForms.val() !== '') && (maxForms.val()-totalForms.val()) <= 0) {
addButton.parent().hide();
}
// The delete button of each row triggers a bunch of other things
- row.find("a." + options.deleteCssClass).click(function() {
+ row.find("a." + options.deleteCssClass).click(function(e) {
+ e.preventDefault();
// Remove the parent form containing this button:
var row = $(this).parents("." + options.formCssClass);
row.remove();
@@ -98,7 +100,7 @@
var forms = $("." + options.formCssClass);
$("#id_" + options.prefix + "-TOTAL_FORMS").val(forms.length);
// Show add button again once we drop below max
- if ((maxForms.val() == '') || (maxForms.val()-forms.length) > 0) {
+ if ((maxForms.val() === '') || (maxForms.val()-forms.length) > 0) {
addButton.parent().show();
}
// Also, update names and ids for all remaining form controls
@@ -110,17 +112,15 @@
updateElementIndex(this, options.prefix, i);
});
}
- return false;
});
// If a post-add callback was supplied, call it with the added form:
if (options.added) {
options.added(row);
}
- return false;
});
}
return this;
- }
+ };
/* Setup plugin defaults */
$.fn.formset.defaults = {
prefix: "form", // The form prefix for your django formset
@@ -132,5 +132,5 @@
formCssClass: "dynamic-form", // CSS class applied to each form in a formset
added: null, // Function called each time a new form is added
removed: null // Function called each time a form is deleted
- }
+ };
})(django.jQuery);
View
10 django/contrib/admin/static/admin/js/inlines.min.js
@@ -1,5 +1,5 @@
-(function(b){b.fn.formset=function(c){var a=b.extend({},b.fn.formset.defaults,c),j=function(a,e,d){var i=RegExp("("+e+"-(\\d+|__prefix__))"),e=e+"-"+d;b(a).attr("for")&&b(a).attr("for",b(a).attr("for").replace(i,e));if(a.id)a.id=a.id.replace(i,e);if(a.name)a.name=a.name.replace(i,e)},c=b("#id_"+a.prefix+"-TOTAL_FORMS").attr("autocomplete","off"),g=parseInt(c.val()),f=b("#id_"+a.prefix+"-MAX_NUM_FORMS").attr("autocomplete","off"),c=""==f.val()||0<f.val()-c.val();b(this).each(function(){b(this).not("."+
-a.emptyCssClass).addClass(a.formCssClass)});if(b(this).length&&c){var h;"TR"==b(this).attr("tagName")?(c=this.eq(0).children().length,b(this).parent().append('<tr class="'+a.addCssClass+'"><td colspan="'+c+'"><a href="javascript:void(0)">'+a.addText+"</a></tr>"),h=b(this).parent().find("tr:last a")):(b(this).filter(":last").after('<div class="'+a.addCssClass+'"><a href="javascript:void(0)">'+a.addText+"</a></div>"),h=b(this).filter(":last").next().find("a"));h.click(function(){var c=b("#id_"+a.prefix+
-"-TOTAL_FORMS"),e=b("#"+a.prefix+"-empty"),d=e.clone(!0);d.removeClass(a.emptyCssClass).addClass(a.formCssClass).attr("id",a.prefix+"-"+g);d.is("tr")?d.children(":last").append('<div><a class="'+a.deleteCssClass+'" href="javascript:void(0)">'+a.deleteText+"</a></div>"):d.is("ul")||d.is("ol")?d.append('<li><a class="'+a.deleteCssClass+'" href="javascript:void(0)">'+a.deleteText+"</a></li>"):d.children(":first").append('<span><a class="'+a.deleteCssClass+'" href="javascript:void(0)">'+a.deleteText+
-"</a></span>");d.find("*").each(function(){j(this,a.prefix,c.val())});d.insertBefore(b(e));b(c).val(parseInt(c.val())+1);g+=1;""!=f.val()&&0>=f.val()-c.val()&&h.parent().hide();d.find("a."+a.deleteCssClass).click(function(){var c=b(this).parents("."+a.formCssClass);c.remove();g-=1;a.removed&&a.removed(c);c=b("."+a.formCssClass);b("#id_"+a.prefix+"-TOTAL_FORMS").val(c.length);(""==f.val()||0<f.val()-c.length)&&h.parent().show();for(var d=0,e=c.length;d<e;d++)j(b(c).get(d),a.prefix,d),b(c.get(d)).find("*").each(function(){j(this,
-a.prefix,d)});return!1});a.added&&a.added(d);return!1})}return this};b.fn.formset.defaults={prefix:"form",addText:"add another",deleteText:"remove",addCssClass:"add-row",deleteCssClass:"delete-row",emptyCssClass:"empty-row",formCssClass:"dynamic-form",added:null,removed:null}})(django.jQuery);
+(function(b){b.fn.formset=function(c){var a=b.extend({},b.fn.formset.defaults,c),j=function(a,f,d){var e=RegExp("("+f+"-(\\d+|__prefix__))"),f=f+"-"+d;b(a).attr("for")&&b(a).attr("for",b(a).attr("for").replace(e,f));a.id&&(a.id=a.id.replace(e,f));a.name&&(a.name=a.name.replace(e,f))},c=b("#id_"+a.prefix+"-TOTAL_FORMS").attr("autocomplete","off"),h=parseInt(c.val(),10),g=b("#id_"+a.prefix+"-MAX_NUM_FORMS").attr("autocomplete","off"),c=""===g.val()||0<g.val()-c.val();b(this).each(function(){b(this).not("."+
+a.emptyCssClass).addClass(a.formCssClass)});if(b(this).length&&c){var i;"TR"==b(this).attr("tagName")?(c=this.eq(0).children().length,b(this).parent().append('<tr class="'+a.addCssClass+'"><td colspan="'+c+'"><a href="javascript:void(0)">'+a.addText+"</a></tr>"),i=b(this).parent().find("tr:last a")):(b(this).filter(":last").after('<div class="'+a.addCssClass+'"><a href="javascript:void(0)">'+a.addText+"</a></div>"),i=b(this).filter(":last").next().find("a"));i.click(function(c){c.preventDefault();
+var f=b("#id_"+a.prefix+"-TOTAL_FORMS"),c=b("#"+a.prefix+"-empty"),d=c.clone(true);d.removeClass(a.emptyCssClass).addClass(a.formCssClass).attr("id",a.prefix+"-"+h);d.is("tr")?d.children(":last").append('<div><a class="'+a.deleteCssClass+'" href="javascript:void(0)">'+a.deleteText+"</a></div>"):d.is("ul")||d.is("ol")?d.append('<li><a class="'+a.deleteCssClass+'" href="javascript:void(0)">'+a.deleteText+"</a></li>"):d.children(":first").append('<span><a class="'+a.deleteCssClass+'" href="javascript:void(0)">'+
+a.deleteText+"</a></span>");d.find("*").each(function(){j(this,a.prefix,f.val())});d.insertBefore(b(c));b(f).val(parseInt(f.val(),10)+1);h=h+1;g.val()!==""&&g.val()-f.val()<=0&&i.parent().hide();d.find("a."+a.deleteCssClass).click(function(e){e.preventDefault();e=b(this).parents("."+a.formCssClass);e.remove();h=h-1;a.removed&&a.removed(e);e=b("."+a.formCssClass);b("#id_"+a.prefix+"-TOTAL_FORMS").val(e.length);(g.val()===""||g.val()-e.length>0)&&i.parent().show();for(var c=0,d=e.length;c<d;c++){j(b(e).get(c),
+a.prefix,c);b(e.get(c)).find("*").each(function(){j(this,a.prefix,c)})}});a.added&&a.added(d)})}return this};b.fn.formset.defaults={prefix:"form",addText:"add another",deleteText:"remove",addCssClass:"add-row",deleteCssClass:"delete-row",emptyCssClass:"empty-row",formCssClass:"dynamic-form",added:null,removed:null}})(django.jQuery);
View
8 django/contrib/admin/templates/admin/index.html
@@ -15,8 +15,12 @@
{% if app_list %}
{% for app in app_list %}
<div class="module">
- <table summary="{% blocktrans with name=app.name %}Models available in the {{ name }} application.{% endblocktrans %}">
- <caption><a href="{{ app.app_url }}" class="section">{% blocktrans with name=app.name %}{{ name }}{% endblocktrans %}</a></caption>
+ <table>
+ <caption>
+ <a href="{{ app.app_url }}" class="section" title="{% blocktrans with name=app.name %}Models in the {{ name }} application{% endblocktrans %}">
+ {% blocktrans with name=app.name %}{{ name }}{% endblocktrans %}
+ </a>
+ </caption>
{% for model in app.models %}
<tr>
{% if model.admin_url %}
View
1  django/contrib/admin/views/main.py
@@ -1,4 +1,5 @@
import operator
+from functools import reduce
from django.core.exceptions import SuspiciousOperation, ImproperlyConfigured
from django.core.paginator import InvalidPage
View
14 django/contrib/auth/management/commands/createsuperuser.py
@@ -80,7 +80,7 @@ def handle(self, *args, **options):
if default_username and username == '':
username = default_username
if not RE_VALID_USERNAME.match(username):
- sys.stderr.write("Error: That username is invalid. Use only letters, digits and underscores.\n")
+ self.stderr.write("Error: That username is invalid. Use only letters, digits and underscores.")
username = None
continue
try:
@@ -88,7 +88,7 @@ def handle(self, *args, **options):
except User.DoesNotExist:
break
else:
- sys.stderr.write("Error: That username is already taken.\n")
+ self.stderr.write("Error: That username is already taken.")
username = None
# Get an email
@@ -98,7 +98,7 @@ def handle(self, *args, **options):
try:
is_valid_email(email)
except exceptions.ValidationError:
- sys.stderr.write("Error: That e-mail address is invalid.\n")
+ self.stderr.write("Error: That e-mail address is invalid.")
email = None
else:
break
@@ -109,19 +109,19 @@ def handle(self, *args, **options):
password = getpass.getpass()
password2 = getpass.getpass('Password (again): ')
if password != password2:
- sys.stderr.write("Error: Your passwords didn't match.\n")
+ self.stderr.write("Error: Your passwords didn't match.")
password = None
continue
if password.strip() == '':
- sys.stderr.write("Error: Blank passwords aren't allowed.\n")
+ self.stderr.write("Error: Blank passwords aren't allowed.")
password = None
continue
break
except KeyboardInterrupt:
- sys.stderr.write("\nOperation cancelled.\n")
+ self.stderr.write("\nOperation cancelled.")
sys.exit(1)
User.objects.db_manager(database).create_superuser(username, email, password)
if verbosity >= 1:
- self.stdout.write("Superuser created successfully.\n")
+ self.stdout.write("Superuser created successfully.")
View
13 django/contrib/auth/tests/management.py
@@ -2,6 +2,7 @@
from django.contrib.auth import models, management
from django.contrib.auth.management.commands import changepassword
+from django.core.management.base import CommandError
from django.test import TestCase
@@ -56,16 +57,10 @@ def test_that_changepassword_command_changes_joes_password(self):
def test_that_max_tries_exits_1(self):
"""
A CommandError should be thrown by handle() if the user enters in
- mismatched passwords three times. This should be caught by execute() and
- converted to a SystemExit
+ mismatched passwords three times.
"""
command = changepassword.Command()
command._get_pass = lambda *args: args or 'foo'
- self.assertRaises(
- SystemExit,
- command.execute,
- "joe",
- stdout=self.stdout,
- stderr=self.stderr
- )
+ with self.assertRaises(CommandError):
+ command.execute("joe", stdout=self.stdout, stderr=self.stderr)
View
11 django/contrib/flatpages/fixtures/example_site.json
@@ -0,0 +1,11 @@
+[
+ {
+ "pk": 1,
+ "model": "sites.site",
+ "fields": {
+ "domain": "example.com",
+ "name": "example.com"
+ }
+ }
+]
+
View
3  django/contrib/flatpages/tests/csrf.py
@@ -18,9 +18,10 @@
TEMPLATE_DIRS=(
os.path.join(os.path.dirname(__file__), 'templates'),
),
+ SITE_ID=1,
)
class FlatpageCSRFTests(TestCase):
- fixtures = ['sample_flatpages']
+ fixtures = ['sample_flatpages', 'example_site']
urls = 'django.contrib.flatpages.tests.urls'
def setUp(self):
View
5 django/contrib/flatpages/tests/forms.py
@@ -5,7 +5,10 @@
from django.test.utils import override_settings
from django.utils import translation
+@override_settings(SITE_ID=1)
class FlatpageAdminFormTests(TestCase):
+ fixtures = ['example_site']
+
def setUp(self):
self.form_data = {
'title': "A test page",
@@ -89,5 +92,5 @@ def test_flatpage_nosites(self):
self.assertEqual(
f.errors,
- {'sites': [u'This field is required.']})
+ {'sites': [translation.ugettext(u'This field is required.')]})
View
12 django/contrib/flatpages/tests/middleware.py
@@ -19,9 +19,10 @@
TEMPLATE_DIRS=(
os.path.join(os.path.dirname(__file__), 'templates'),
),
+ SITE_ID=1,
)
class FlatpageMiddlewareTests(TestCase):
- fixtures = ['sample_flatpages']
+ fixtures = ['sample_flatpages', 'example_site']
urls = 'django.contrib.flatpages.tests.urls'
def test_view_flatpage(self):
@@ -75,7 +76,7 @@ def test_fallback_flatpage_special_chars(self):
enable_comments=False,
registration_required=False,
)
- fp.sites.add(1)
+ fp.sites.add(settings.SITE_ID)
response = self.client.get('/some.very_special~chars-here/')
self.assertEqual(response.status_code, 200)
@@ -96,9 +97,10 @@ def test_fallback_flatpage_special_chars(self):
TEMPLATE_DIRS=(
os.path.join(os.path.dirname(__file__), 'templates'),
),
+ SITE_ID=1,
)
class FlatpageMiddlewareAppendSlashTests(TestCase):
- fixtures = ['sample_flatpages']
+ fixtures = ['sample_flatpages', 'example_site']
urls = 'django.contrib.flatpages.tests.urls'
def test_redirect_view_flatpage(self):
@@ -130,7 +132,7 @@ def test_redirect_fallback_flatpage_special_chars(self):
enable_comments=False,
registration_required=False,
)
- fp.sites.add(1)
+ fp.sites.add(settings.SITE_ID)
response = self.client.get('/some.very_special~chars-here')
self.assertRedirects(response, '/some.very_special~chars-here/', status_code=301)
@@ -144,7 +146,7 @@ def test_redirect_fallback_flatpage_root(self):
enable_comments=False,
registration_required=False,
)
- fp.sites.add(1)
+ fp.sites.add(settings.SITE_ID)
response = self.client.get('/')
self.assertEqual(response.status_code, 200)
View
1  django/contrib/flatpages/tests/templatetags.py
@@ -18,6 +18,7 @@
TEMPLATE_DIRS=(
os.path.join(os.path.dirname(__file__), 'templates'),
),
+ SITE_ID=1,
)
class FlatpageTemplateTagTests(TestCase):
fixtures = ['sample_flatpages']
View
8 django/contrib/flatpages/tests/views.py
@@ -19,9 +19,10 @@
TEMPLATE_DIRS=(
os.path.join(os.path.dirname(__file__), 'templates'),
),
+ SITE_ID=1,
)
class FlatpageViewTests(TestCase):
- fixtures = ['sample_flatpages']
+ fixtures = ['sample_flatpages', 'example_site']
urls = 'django.contrib.flatpages.tests.urls'
def test_view_flatpage(self):
@@ -85,9 +86,10 @@ def test_view_flatpage_special_chars(self):
TEMPLATE_DIRS=(
os.path.join(os.path.dirname(__file__), 'templates'),
),
+ SITE_ID=1,
)
class FlatpageViewAppendSlashTests(TestCase):
- fixtures = ['sample_flatpages']
+ fixtures = ['sample_flatpages', 'example_site']
urls = 'django.contrib.flatpages.tests.urls'
def test_redirect_view_flatpage(self):
@@ -119,7 +121,7 @@ def test_redirect_view_flatpage_special_chars(self):
enable_comments=False,
registration_required=False,
)
- fp.sites.add(1)
+ fp.sites.add(settings.SITE_ID)
response = self.client.get('/flatpage_root/some.very_special~chars-here')
self.assertRedirects(response, '/flatpage_root/some.very_special~chars-here/', status_code=301)
View
57 django/contrib/formtools/tests/__init__.py
@@ -156,9 +156,6 @@ def test_form_submit_bad_hash(self):
class FormHmacTests(unittest.TestCase):
- """
- Same as SecurityHashTests, but with form_hmac
- """
def test_textfield_hash(self):
"""
@@ -166,8 +163,8 @@ def test_textfield_hash(self):
leading/trailing whitespace so as to be friendly to broken browsers that
submit it (usually in textareas).
"""
- f1 = HashTestForm({'name': 'joe', 'bio': 'Nothing notable.'})
- f2 = HashTestForm({'name': ' joe', 'bio': 'Nothing notable. '})
+ f1 = HashTestForm({'name': u'joe', 'bio': u'Nothing notable.'})
+ f2 = HashTestForm({'name': u' joe', 'bio': u'Nothing notable. '})
hash1 = utils.form_hmac(f1)
hash2 = utils.form_hmac(f2)
self.assertEqual(hash1, hash2)
@@ -269,10 +266,10 @@ def test_good_hash(self):
Form should advance if the hash is present and good, as calculated using
current method.
"""
- data = {"0-field": "test",
- "1-field": "test2",
- "hash_0": "7e9cea465f6a10a6fb47fcea65cb9a76350c9a5c",
- "wizard_step": "1"}
+ data = {"0-field": u"test",
+ "1-field": u"test2",
+ "hash_0": u"cd13b1db3e8f55174bc5745a1b1a53408d4fd1ca",
+ "wizard_step": u"1"}
response = self.client.post('/wizard1/', data)
self.assertEqual(2, response.context['step0'])
@@ -294,18 +291,18 @@ def process_step(self, request, form, step):
reached[0] = True
wizard = WizardWithProcessStep([WizardPageOneForm])
- data = {"0-field": "test",
- "1-field": "test2",
- "hash_0": "7e9cea465f6a10a6fb47fcea65cb9a76350c9a5c",
- "wizard_step": "1"}
+ data = {"0-field": u"test",
+ "1-field": u"test2",
+ "hash_0": u"cd13b1db3e8f55174bc5745a1b1a53408d4fd1ca",
+ "wizard_step": u"1"}
wizard(DummyRequest(POST=data))
self.assertTrue(reached[0])
- data = {"0-field": "test",
- "1-field": "test2",
- "hash_0": "7e9cea465f6a10a6fb47fcea65cb9a76350c9a5c",
- "hash_1": "d5b434e3934cc92fee4bd2964c4ebc06f81d362d",
- "wizard_step": "2"}
+ data = {"0-field": u"test",
+ "1-field": u"test2",
+ "hash_0": "cd13b1db3e8f55174bc5745a1b1a53408d4fd1ca",
+ "hash_1": u"1e6f6315da42e62f33a30640ec7e007ad3fbf1a1",
+ "wizard_step": u"2"}
self.assertRaises(http.Http404, wizard, DummyRequest(POST=data))
def test_14498(self):
@@ -324,10 +321,10 @@ def process_step(self, request, form, step):
wizard = WizardWithProcessStep([WizardPageOneForm,
WizardPageTwoForm,
WizardPageThreeForm])
- data = {"0-field": "test",
- "1-field": "test2",
- "hash_0": "7e9cea465f6a10a6fb47fcea65cb9a76350c9a5c",
- "wizard_step": "1"}
+ data = {"0-field": u"test",
+ "1-field": u"test2",
+ "hash_0": u"cd13b1db3e8f55174bc5745a1b1a53408d4fd1ca",
+ "wizard_step": u"1"}
wizard(DummyRequest(POST=data))
self.assertTrue(reached[0])
@@ -348,10 +345,10 @@ def done(self, request, form_list):
wizard = Wizard([WizardPageOneForm,
WizardPageTwoForm])
- data = {"0-field": "test",
- "1-field": "test2",
- "hash_0": "7e9cea465f6a10a6fb47fcea65cb9a76350c9a5c",
- "wizard_step": "1"}
+ data = {"0-field": u"test",
+ "1-field": u"test2",
+ "hash_0": u"cd13b1db3e8f55174bc5745a1b1a53408d4fd1ca",
+ "wizard_step": u"1"}
wizard(DummyRequest(POST=data))
self.assertTrue(reached[0])
@@ -374,10 +371,10 @@ def process_step(self, request, form, step):
wizard = WizardWithProcessStep([WizardPageOneForm,
WizardPageTwoForm,
WizardPageThreeForm])
- data = {"0-field": "test",
- "1-field": "test2",
- "hash_0": "7e9cea465f6a10a6fb47fcea65cb9a76350c9a5c",
- "wizard_step": "1"}
+ data = {"0-field": u"test",
+ "1-field": u"test2",
+ "hash_0": u"cd13b1db3e8f55174bc5745a1b1a53408d4fd1ca",
+ "wizard_step": u"1"}
wizard(DummyRequest(POST=data))
self.assertTrue(reached[0])
View
14 django/contrib/formtools/tests/wizard/namedwizardtests/tests.py
@@ -120,7 +120,7 @@ def test_form_finish(self):
self.assertEqual(response.context['wizard']['steps'].current, 'form2')
post_data = self.wizard_step_data[1]
- post_data['form2-file1'] = open(__file__)
+ post_data['form2-file1'] = open(__file__, 'rb')
response = self.client.post(
reverse(self.wizard_urlname,
kwargs={'step': response.context['wizard']['steps'].current}),
@@ -147,7 +147,7 @@ def test_form_finish(self):
self.assertEqual(response.status_code, 200)
all_data = response.context['form_list']
- self.assertEqual(all_data[1]['file1'].read(), open(__file__).read())
+ self.assertEqual(all_data[1]['file1'].read(), open(__file__, 'rb').read())
del all_data[1]['file1']
self.assertEqual(all_data, [
{'name': u'Pony', 'thirsty': True, 'user': self.testuser},
@@ -168,7 +168,7 @@ def test_cleaned_data(self):
self.assertEqual(response.status_code, 200)
post_data = self.wizard_step_data[1]
- post_data['form2-file1'] = open(__file__)
+ post_data['form2-file1'] = open(__file__, 'rb')
response = self.client.post(
reverse(self.wizard_urlname,
kwargs={'step': response.context['wizard']['steps'].current}),
@@ -180,7 +180,9 @@ def test_cleaned_data(self):
response = self.client.get(step2_url)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.context['wizard']['steps'].current, 'form2')
- self.assertEqual(response.context['wizard']['form'].files['form2-file1'].read(), open(__file__).read())
+ self.assertEqual(
+ response.context['wizard']['form'].files['form2-file1'].read(),
+ open(__file__, 'rb').read())
response = self.client.post(
reverse(self.wizard_urlname,
@@ -197,7 +199,7 @@ def test_cleaned_data(self):
self.assertEqual(response.status_code, 200)
all_data = response.context['all_cleaned_data']
- self.assertEqual(all_data['file1'].read(), open(__file__).read())
+ self.assertEqual(all_data['file1'].read(), open(__file__, 'rb').read())
del all_data['file1']
self.assertEqual(
all_data,
@@ -221,7 +223,7 @@ def test_manipulated_data(self):
self.assertEqual(response.status_code, 200)
post_data = self.wizard_step_data[1]
- post_data['form2-file1'] = open(__file__)
+ post_data['form2-file1'] = open(__file__, 'rb')
response = self.client.post(
reverse(self.wizard_urlname,
kwargs={'step': response.context['wizard']['steps'].current}),
View
12 django/contrib/formtools/tests/wizard/wizardtests/tests.py
@@ -80,7 +80,7 @@ def test_form_finish(self):
self.assertEqual(response.context['wizard']['steps'].current, 'form2')
post_data = self.wizard_step_data[1]
- post_data['form2-file1'] = open(__file__)
+ post_data['form2-file1'] = open(__file__, 'rb')
response = self.client.post(self.wizard_url, post_data)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.context['wizard']['steps'].current, 'form3')
@@ -93,7 +93,7 @@ def test_form_finish(self):
self.assertEqual(response.status_code, 200)
all_data = response.context['form_list']
- self.assertEqual(all_data[1]['file1'].read(), open(__file__).read())
+ self.assertEqual(all_data[1]['file1'].read(), open(__file__, 'rb').read())
del all_data[1]['file1']
self.assertEqual(all_data, [
{'name': u'Pony', 'thirsty': True, 'user': self.testuser},
@@ -110,7 +110,7 @@ def test_cleaned_data(self):
self.assertEqual(response.status_code, 200)
post_data = self.wizard_step_data[1]
- post_data['form2-file1'] = open(__file__)
+ post_data['form2-file1'] = open(__file__, 'rb')
response = self.client.post(self.wizard_url, post_data)
self.assertEqual(response.status_code, 200)
@@ -121,7 +121,7 @@ def test_cleaned_data(self):
self.assertEqual(response.status_code, 200)
all_data = response.context['all_cleaned_data']
- self.assertEqual(all_data['file1'].read(), open(__file__).read())
+ self.assertEqual(all_data['file1'].read(), open(__file__, 'rb').read())
del all_data['file1']
self.assertEqual(all_data, {
'name': u'Pony', 'thirsty': True, 'user': self.testuser,
@@ -138,7 +138,7 @@ def test_manipulated_data(self):
self.assertEqual(response.status_code, 200)
post_data = self.wizard_step_data[1]
- post_data['form2-file1'] = open(__file__)
+ post_data['form2-file1'] = open(__file__, 'rb')
response = self.client.post(self.wizard_url, post_data)
self.assertEqual(response.status_code, 200)
@@ -165,7 +165,7 @@ def test_form_refresh(self):
self.assertEqual(response.context['wizard']['steps'].current, 'form2')
post_data = self.wizard_step_data[1]
- post_data['form2-file1'] = open(__file__)
+ post_data['form2-file1'] = open(__file__, 'rb')
response = self.client.post(self.wizard_url, post_data)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.context['wizard']['steps'].current, 'form3')
View
6 django/contrib/formtools/utils.py
@@ -1,7 +1,5 @@
-try:
- import cPickle as pickle
-except ImportError:
- import pickle
+# Do not try cPickle here (see #18340)
+import pickle
from django.utils.crypto import salted_hmac
View
8 django/contrib/gis/admin/options.py
@@ -36,6 +36,7 @@ class GeoModelAdmin(ModelAdmin):
wms_url = 'http://vmap0.tiles.osgeo.org/wms/vmap0'
wms_layer = 'basic'
wms_name = 'OpenLayers WMS'
+ wms_options = {'format': 'image/jpeg'}
debug = False
widget = OpenLayersWidget
@@ -76,6 +77,12 @@ def get_map_widget(self, db_field):
class OLMap(self.widget):
template = self.map_template
geom_type = db_field.geom_type
+
+ wms_options = ''
+ if self.wms_options:
+ wms_options = ["%s: '%s'" % pair for pair in self.wms_options.items()]
+ wms_options = ', %s' % ', '.join(wms_options)
+
params = {'default_lon' : self.default_lon,
'default_lat' : self.default_lat,
'default_zoom' : self.default_zoom,
@@ -106,6 +113,7 @@ class OLMap(self.widget):
'wms_url' : self.wms_url,
'wms_layer' : self.wms_layer,
'wms_name' : self.wms_name,
+ 'wms_options' : wms_options,
'debug' : self.debug,
}
return OLMap
View
4 django/contrib/gis/gdal/base.py
@@ -1,5 +1,5 @@
from ctypes import c_void_p
-from types import NoneType
+
from django.contrib.gis.gdal.error import GDALException
class GDALBase(object):
@@ -26,7 +26,7 @@ def _set_ptr(self, ptr):
# compatible type or None (NULL).
if isinstance(ptr, (int, long)):
self._ptr = self.ptr_type(ptr)
- elif isinstance(ptr, (self.ptr_type, NoneType)):
+ elif ptr is None or isinstance(ptr, self.ptr_type):
self._ptr = ptr
else:
raise TypeError('Incompatible pointer type')
View
4 django/contrib/gis/gdal/tests/__init__.py
@@ -2,10 +2,12 @@
Module for executing all of the GDAL tests. None
of these tests require the use of the database.
"""
+from __future__ import absolute_import
+
from django.utils.unittest import TestSuite, TextTestRunner
# Importing the GDAL test modules.
-import test_driver, test_ds, test_envelope, test_geom, test_srs
+from . import test_driver, test_ds, test_envelope, test_geom, test_srs
test_suites = [test_driver.suite(),
test_ds.suite(),
View
4 django/contrib/gis/geoip/__init__.py
@@ -11,8 +11,10 @@
Grab GeoIP.dat.gz and GeoLiteCity.dat.gz, and unzip them in the directory
corresponding to settings.GEOIP_PATH.
"""
+from __future__ import absolute_import
+
try:
- from django.contrib.gis.geoip.base import GeoIP, GeoIPException
+ from .base import GeoIP, GeoIPException
HAS_GEOIP = True
except:
HAS_GEOIP = False
View
4 django/contrib/gis/geos/base.py
@@ -1,5 +1,5 @@
from ctypes import c_void_p
-from types import NoneType
+
from django.contrib.gis.geos.error import GEOSException
# Trying to import GDAL libraries, if available. Have to place in
@@ -41,7 +41,7 @@ def _get_ptr(self):
def _set_ptr(self, ptr):
# Only allow the pointer to be set with pointers of the
# compatible type or None (NULL).
- if isinstance(ptr, (self.ptr_type, NoneType)):
+ if ptr is None or isinstance(ptr, self.ptr_type):
self._ptr = ptr
else:
raise TypeError('Incompatible pointer type')
View
29 django/contrib/gis/geos/mutable_list.py
@@ -8,6 +8,9 @@
Author: Aryeh Leib Taurog.
"""
+from django.utils.functional import total_ordering
+
+@total_ordering
class ListMixin(object):
"""
A base class which provides complete list interface.
@@ -143,20 +146,28 @@ def __imul__(self, n):
self.extend(cache)
return self
- def __cmp__(self, other):
- 'cmp'
+ def __eq__(self, other):
+ for i in range(len(self)):
+ try:
+ c = self[i] == other[i]
+ except IndexError:
+ # must be other is shorter
+ return False
+ if not c:
+ return False
+ return True
+
+ def __lt__(self, other):
slen = len(self)
for i in range(slen):
try:
- c = cmp(self[i], other[i])
+ c = self[i] < other[i]
except IndexError:
# must be other is shorter
- return 1
- else:
- # elements not equal
- if c: return c
-
- return cmp(slen, len(other))
+ return False
+ if c:
+ return c
+ return slen < len(other)
### Public list interface Methods ###
## Non-mutating ##
View
4 django/contrib/gis/geos/tests/__init__.py
@@ -1,8 +1,10 @@
"""
GEOS Testing module.
"""
+from __future__ import absolute_import
+
from django.utils.unittest import TestSuite, TextTestRunner
-import test_geos, test_io, test_geos_mutation, test_mutable_list
+from . import test_geos, test_io, test_geos_mutation, test_mutable_list
test_suites = [
test_geos.suite(),
View
125 django/contrib/gis/geos/tests/test_geos.py
@@ -1,18 +1,23 @@
import ctypes
import random
-import unittest
-from django.contrib.gis.geos import *
+
+from django.contrib.gis.geos import (GEOSException, GEOSIndexError, GEOSGeometry,
+ GeometryCollection, Point, MultiPoint, Polygon, MultiPolygon, LinearRing,
+ LineString, MultiLineString, fromfile, fromstr, geos_version_info)
from django.contrib.gis.geos.base import gdal, numpy, GEOSBase
from django.contrib.gis.geos.libgeos import GEOS_PREPARE
from django.contrib.gis.geometry.test_data import TestDataMixin
+from django.utils import unittest
+
+
class GEOSTest(unittest.TestCase, TestDataMixin):
@property
def null_srid(self):
"""
Returns the proper null SRID depending on the GEOS version.
- See the comments in `test15_srid` for more details.
+ See the comments in `test_srid` for more details.
"""
info = geos_version_info()
if info['version'] == '3.0.0' and info['release_candidate']:
@@ -20,7 +25,7 @@ def null_srid(self):
else:
return None
- def test00_base(self):
+ def test_base(self):
"Tests out the GEOSBase class."
# Testing out GEOSBase class, which provides a `ptr` property
# that abstracts out access to underlying C pointers.
@@ -62,19 +67,19 @@ class FakeGeom2(GEOSBase):
self.assertRaises(TypeError, fg1._set_ptr, bad_ptr)
self.assertRaises(TypeError, fg2._set_ptr, bad_ptr)
- def test01a_wkt(self):
+ def test_wkt(self):
"Testing WKT output."
for g in self.geometries.wkt_out:
geom = fromstr(g.wkt)
self.assertEqual(g.ewkt, geom.wkt)
- def test01b_hex(self):
+ def test_hex(self):
"Testing HEX output."
for g in self.geometries.hex_wkt:
geom = fromstr(g.wkt)
self.assertEqual(g.hex, geom.hex)
- def test01b_hexewkb(self):
+ def test_hexewkb(self):
"Testing (HEX)EWKB output."
from binascii import a2b_hex
@@ -124,14 +129,14 @@ def test01b_hexewkb(self):
# Redundant sanity check.
self.assertEqual(4326, GEOSGeometry(hexewkb_2d).srid)
- def test01c_kml(self):
+ def test_kml(self):
"Testing KML output."
for tg in self.geometries.wkt_out:
geom = fromstr(tg.wkt)
kml = getattr(tg, 'kml', False)
if kml: self.assertEqual(kml, geom.kml)
- def test01d_errors(self):
+ def test_errors(self):
"Testing the Error handlers."
# string-based
print("\nBEGIN - expecting GEOS_ERROR; safe to ignore.\n")
@@ -154,7 +159,7 @@ class NotAGeometry(object):
# None
self.assertRaises(TypeError, GEOSGeometry, None)
- def test01e_wkb(self):
+ def test_wkb(self):
"Testing WKB output."
from binascii import b2a_hex
for g in self.geometries.hex_wkt:
@@ -162,7 +167,7 @@ def test01e_wkb(self):
wkb = geom.wkb
self.assertEqual(b2a_hex(wkb).upper(), g.hex)
- def test01f_create_hex(self):
+ def test_create_hex(self):
"Testing creation from HEX."
for g in self.geometries.hex_wkt:
geom_h = GEOSGeometry(g.hex)
@@ -170,7 +175,7 @@ def test01f_create_hex(self):
geom_t = fromstr(g.wkt)
self.assertEqual(geom_t.wkt, geom_h.wkt)
- def test01g_create_wkb(self):
+ def test_create_wkb(self):
"Testing creation from WKB."
from binascii import a2b_hex
for g in self.geometries.hex_wkt:
@@ -180,7 +185,7 @@ def test01g_create_wkb(self):
geom_t = fromstr(g.wkt)
self.assertEqual(geom_t.wkt, geom_h.wkt)
- def test01h_ewkt(self):
+ def test_ewkt(self):
"Testing EWKT."
srids = (-1, 32140)
for srid in srids:
@@ -191,9 +196,9 @@ def test01h_ewkt(self):
self.assertEqual(srid, poly.shell.srid)
self.assertEqual(srid, fromstr(poly.ewkt).srid) # Checking export
- def test01i_json(self):
+ @unittest.skipUnless(gdal.HAS_GDAL and gdal.GEOJSON, "gdal >= 1.5 is required")
+ def test_json(self):
"Testing GeoJSON input/output (via GDAL)."
- if not gdal or not gdal.GEOJSON: return
for g in self.geometries.json_geoms:
geom = GEOSGeometry(g.wkt)
if not hasattr(g, 'not_equal'):
@@ -201,7 +206,7 @@ def test01i_json(self):
self.assertEqual(g.json, geom.geojson)
self.assertEqual(GEOSGeometry(g.wkt), GEOSGeometry(geom.json))
- def test01k_fromfile(self):
+ def test_fromfile(self):
"Testing the fromfile() factory."
from io import BytesIO
ref_pnt = GEOSGeometry('POINT(5 23)')
@@ -218,7 +223,7 @@ def test01k_fromfile(self):
pnt = fromfile(fh)
self.assertEqual(ref_pnt, pnt)
- def test01k_eq(self):
+ def test_eq(self):
"Testing equivalence."
p = fromstr('POINT(5 23)')
self.assertEqual(p, p.wkt)
@@ -233,7 +238,7 @@ def test01k_eq(self):
self.assertNotEqual(g, {'foo' : 'bar'})
self.assertNotEqual(g, False)
- def test02a_points(self):
+ def test_points(self):
"Testing Point objects."
prev = fromstr('POINT(0 0)')
for p in self.geometries.points:
@@ -288,7 +293,7 @@ def test02a_points(self):
prev = pnt # setting the previous geometry
- def test02b_multipoints(self):
+ def test_multipoints(self):
"Testing MultiPoint objects."
for mp in self.geometries.multipoints:
mpnt = fromstr(mp.wkt)
@@ -307,7 +312,7 @@ def test02b_multipoints(self):
self.assertEqual(p.empty, False)
self.assertEqual(p.valid, True)
- def test03a_linestring(self):
+ def test_linestring(self):
"Testing LineString objects."
prev = fromstr('POINT(0 0)')
for l in self.geometries.linestrings:
@@ -333,7 +338,7 @@ def test03a_linestring(self):
self.assertEqual(ls.wkt, LineString(*tuple(Point(tup) for tup in ls.tuple)).wkt) # Point individual arguments
if numpy: self.assertEqual(ls, LineString(numpy.array(ls.tuple))) # as numpy array
- def test03b_multilinestring(self):
+ def test_multilinestring(self):
"Testing MultiLineString objects."
prev = fromstr('POINT(0 0)')
for l in self.geometries.multilinestrings:
@@ -357,7 +362,7 @@ def test03b_multilinestring(self):
self.assertEqual(ml.wkt, MultiLineString(*tuple(s.clone() for s in ml)).wkt)
self.assertEqual(ml, MultiLineString(*tuple(LineString(s.tuple) for s in ml)))
- def test04_linearring(self):
+ def test_linearring(self):
"Testing LinearRing objects."
for rr in self.geometries.linearrings:
lr = fromstr(rr.wkt)
@@ -373,14 +378,15 @@ def test04_linearring(self):
self.assertEqual(lr, LinearRing([list(tup) for tup in lr.tuple]))
if numpy: self.assertEqual(lr, LinearRing(numpy.array(lr.tuple)))
- def test05a_polygons(self):
- "Testing Polygon objects."
-
- # Testing `from_bbox` class method
+ def test_polygons_from_bbox(self):
+ "Testing `from_bbox` class method."
bbox = (-180, -90, 180, 90)
- p = Polygon.from_bbox( bbox )
+ p = Polygon.from_bbox(bbox)
self.assertEqual(bbox, p.extent)
+ def test_polygons(self):
+ "Testing Polygon objects."
+
prev = fromstr('POINT(0 0)')
for p in self.geometries.polygons:
# Creating the Polygon, testing its properties.
@@ -437,7 +443,7 @@ def test05a_polygons(self):
self.assertEqual(poly.wkt, Polygon(*tuple(r for r in poly)).wkt)
self.assertEqual(poly.wkt, Polygon(*tuple(LinearRing(r.tuple) for r in poly)).wkt)
- def test05b_multipolygons(self):
+ def test_multipolygons(self):
"Testing MultiPolygon objects."
print("\nBEGIN - expecting GEOS_NOTICE; safe to ignore.\n")
prev = fromstr('POINT (0 0)')
@@ -460,7 +466,7 @@ def test05b_multipolygons(self):
print("\nEND - expecting GEOS_NOTICE; safe to ignore.\n")
- def test06a_memory_hijinks(self):
+ def test_memory_hijinks(self):
"Testing Geometry __del__() on rings and polygons."
#### Memory issues with rings and polygons
@@ -483,7 +489,7 @@ def test06a_memory_hijinks(self):
# Access to these rings is OK since they are clones.
s1, s2 = str(ring1), str(ring2)
- def test08_coord_seq(self):
+ def test_coord_seq(self):
"Testing Coordinate Sequence objects."
for p in self.geometries.polygons:
if p.ext_ring_cs:
@@ -510,7 +516,7 @@ def test08_coord_seq(self):
cs[i] = tset
self.assertEqual(tset[j], cs[i][j])
- def test09_relate_pattern(self):
+ def test_relate_pattern(self):
"Testing relate() and relate_pattern()."
g = fromstr('POINT (0 0)')
self.assertRaises(GEOSException, g.relate_pattern, 0, 'invalid pattern, yo')
@@ -520,7 +526,7 @@ def test09_relate_pattern(self):
self.assertEqual(rg.result, a.relate_pattern(b, rg.pattern))
self.assertEqual(rg.pattern, a.relate(b))
- def test10_intersection(self):
+ def test_intersection(self):
"Testing intersects() and intersection()."
for i in xrange(len(self.geometries.topology_geoms)):
a = fromstr(self.geometries.topology_geoms[i].wkt_a)
@@ -533,7 +539,7 @@ def test10_intersection(self):
a &= b # testing __iand__
self.assertEqual(i1, a)
- def test11_union(self):
+ def test_union(self):
"Testing union()."
for i in xrange(len(self.geometries.topology_geoms)):
a = fromstr(self.geometries.topology_geoms[i].wkt_a)
@@ -545,7 +551,7 @@ def test11_union(self):
a |= b # testing __ior__
self.assertEqual(u1, a)
- def test12_difference(self):
+ def test_difference(self):
"Testing difference()."
for i in xrange(len(self.geometries.topology_geoms)):
a = fromstr(self.geometries.topology_geoms[i].wkt_a)
@@ -557,7 +563,7 @@ def test12_difference(self):
a -= b # testing __isub__
self.assertEqual(d1, a)
- def test13_symdifference(self):
+ def test_symdifference(self):
"Testing sym_difference()."
for i in xrange(len(self.geometries.topology_geoms)):
a = fromstr(self.geometries.topology_geoms[i].wkt_a)
@@ -569,7 +575,7 @@ def test13_symdifference(self):
a ^= b # testing __ixor__
self.assertEqual(d1, a)
- def test14_buffer(self):
+ def test_buffer(self):
"Testing buffer()."
for bg in self.geometries.buffer_geoms:
g = fromstr(bg.wkt)
@@ -597,7 +603,7 @@ def test14_buffer(self):
self.assertAlmostEqual(exp_ring[k][0], buf_ring[k][0], 9)
self.assertAlmostEqual(exp_ring[k][1], buf_ring[k][1], 9)
- def test15_srid(self):
+ def test_srid(self):
"Testing the SRID property and keyword."
# Testing SRID keyword on Point
pnt = Point(5, 23, srid=4326)
@@ -635,7 +641,7 @@ def test15_srid(self):
p3 = fromstr(p1.hex, srid=-1) # -1 is intended.
self.assertEqual(-1, p3.srid)
- def test16_mutable_geometries(self):
+ def test_mutable_geometries(self):
"Testing the mutability of Polygons and Geometry Collections."
### Testing the mutability of Polygons ###
for p in self.geometries.polygons:
@@ -699,7 +705,7 @@ def test16_mutable_geometries(self):
#self.assertEqual((3.14, 2.71), mpoly[0].shell[0])
#del mpoly
- def test17_threed(self):
+ def test_threed(self):
"Testing three-dimensional geometries."
# Testing a 3D Point
pnt = Point(2, 3, 8)
@@ -715,7 +721,7 @@ def test17_threed(self):
ls[0] = (1.,2.,3.)
self.assertEqual((1.,2.,3.), ls[0])
- def test18_distance(self):
+ def test_distance(self):
"Testing the distance() function."
# Distance to self should be 0.
pnt = Point(0, 0)
@@ -733,7 +739,7 @@ def test18_distance(self):
ls2 = LineString((5, 2), (6, 1), (7, 0))
self.assertEqual(3, ls1.distance(ls2))
- def test19_length(self):
+ def test_length(self):
"Testing the length property."
# Points have 0 length.
pnt = Point(0, 0)
@@ -751,7 +757,7 @@ def test19_length(self):
mpoly = MultiPolygon(poly.clone(), poly)
self.assertEqual(8.0, mpoly.length)
- def test20a_emptyCollections(self):
+ def test_emptyCollections(self):
"Testing empty geometries and collections."
gc1 = GeometryCollection([])
gc2 = fromstr('GEOMETRYCOLLECTION EMPTY')
@@ -789,7 +795,7 @@ def test20a_emptyCollections(self):
else:
self.assertRaises(GEOSIndexError, g.__getitem__, 0)
- def test20b_collections_of_collections(self):
+ def test_collections_of_collections(self):
"Testing GeometryCollection handling of other collections."
# Creating a GeometryCollection WKT string composed of other
# collections and polygons.
@@ -808,9 +814,9 @@ def test20b_collections_of_collections(self):
# And, they should be equal.
self.assertEqual(gc1, gc2)
- def test21_test_gdal(self):
+ @unittest.skipUnless(gdal.HAS_GDAL, "gdal is required")
+ def test_gdal(self):
"Testing `ogr` and `srs` properties."
- if not gdal.HAS_GDAL: return
g1 = fromstr('POINT(5 23)')
self.assertEqual(True, isinstance(g1.ogr, gdal.OGRGeometry))
self.assertEqual(g1.srs, None)
@@ -821,7 +827,7 @@ def test21_test_gdal(self):
self.assertEqual(g2.hex, g2.ogr.hex)
self.assertEqual('WGS 84', g2.srs.name)
- def test22_copy(self):
+ def test_copy(self):
"Testing use with the Python `copy` module."
import copy
poly = GEOSGeometry('POLYGON((0 0, 0 23, 23 23, 23 0, 0 0), (5 5, 5 10, 10 10, 10 5, 5 5))')
@@ -830,9 +836,9 @@ def test22_copy(self):
self.assertNotEqual(poly._ptr, cpy1._ptr)
self.assertNotEqual(poly._ptr, cpy2._ptr)
- def test23_transform(self):
+ @unittest.skipUnless(gdal.HAS_GDAL, "gdal is required")
+ def test_transform(self):
"Testing `transform` method."
- if not gdal.HAS_GDAL: return
orig = GEOSGeometry('POINT (-104.609 38.255)', 4326)
trans = GEOSGeometry('POINT (992385.4472045 481455.4944650)', 2774)
@@ -855,7 +861,7 @@ def test23_transform(self):
self.assertAlmostEqual(trans.x, p.x, prec)
self.assertAlmostEqual(trans.y, p.y, prec)
- def test23_transform_noop(self):
+ def test_transform_noop(self):
""" Testing `transform` method (SRID match) """
# transform() should no-op if source & dest SRIDs match,
# regardless of whether GDAL is available.
@@ -890,7 +896,7 @@ def test23_transform_noop(self):
finally:
gdal.HAS_GDAL = old_has_gdal
- def test23_transform_nosrid(self):
+ def test_transform_nosrid(self):
""" Testing `transform` method (no SRID or negative SRID) """
g = GEOSGeometry('POINT (-104.609 38.255)', srid=None)
@@ -905,7 +911,7 @@ def test23_transform_nosrid(self):
g = GEOSGeometry('POINT (-104.609 38.255)', srid=-1)
self.assertRaises(GEOSException, g.transform, 2774, clone=True)
- def test23_transform_nogdal(self):
+ def test_transform_nogdal(self):
""" Testing `transform` method (GDAL not available) """
old_has_gdal = gdal.HAS_GDAL
try:
@@ -919,7 +925,7 @@ def test23_transform_nogdal(self):
finally:
gdal.HAS_GDAL = old_has_gdal
- def test24_extent(self):
+ def test_extent(self):
"Testing `extent` method."
# The xmin, ymin, xmax, ymax of the MultiPoint should be returned.
mp = MultiPoint(Point(5, 23), Point(0, 0), Point(10, 50))
@@ -935,7 +941,7 @@ def test24_extent(self):
xmax, ymax = max(x), max(y)
self.assertEqual((xmin, ymin, xmax, ymax), poly.extent)
- def test25_pickle(self):
+ def test_pickle(self):
"Testing pickling and unpickling support."
# Using both pickle and cPickle -- just 'cause.
import pickle, cPickle
@@ -958,9 +964,9 @@ def get_geoms(lst, srid=None):
self.assertEqual(geom, tmpg)
if not no_srid: self.assertEqual(geom.srid, tmpg.srid)
- def test26_prepared(self):
+ @unittest.skipUnless(GEOS_PREPARE, "geos >= 3.1.0 is required")
+ def test_prepared(self):
"Testing PreparedGeometry support."
- if not GEOS_PREPARE: return
# Creating a simple multipolygon and getting a prepared version.
mpoly = GEOSGeometry('MULTIPOLYGON(((0 0,0 5,5 5,5 0,0 0)),((5 5,5 10,10 10,10 5,5 5)))')
prep = mpoly.prepared
@@ -974,7 +980,7 @@ def test26_prepared(self):
self.assertEqual(mpoly.intersects(pnt), prep.intersects(pnt))
self.assertEqual(c, prep.covers(pnt))
- def test26_line_merge(self):
+ def test_line_merge(self):
"Testing line merge support"
ref_geoms = (fromstr('LINESTRING(1 1, 1 1, 3 3)'),
fromstr('MULTILINESTRING((1 1, 3 3), (3 3, 4 2))'),
@@ -985,10 +991,9 @@ def test26_line_merge(self):
for geom, merged in zip(ref_geoms, ref_merged):
self.assertEqual(merged, geom.merged)
- def test27_valid_reason(self):
+ @unittest.skipUnless(GEOS_PREPARE, "geos >= 3.1.0 is required")
+ def test_valid_reason(self):
"Testing IsValidReason support"
- # Skipping tests if GEOS < v3.1.
- if not GEOS_PREPARE: return
g = GEOSGeometry("POINT(0 0)")
self.assertTrue(g.valid)
@@ -1005,7 +1010,7 @@ def test27_valid_reason(self):
print("\nEND - expecting GEOS_NOTICE; safe to ignore.\n")
- def test28_geos_version(self):
+ def test_geos_version(self):
"Testing the GEOS version regular expression."
from django.contrib.gis.geos.libgeos import version_regex
versions = [ ('3.0.0rc4-CAPI-1.3.3', '3.0.0'),
View
12 django/contrib/gis/maps/google/overlays.py
@@ -1,5 +1,7 @@
-from django.utils.safestring import mark_safe
from django.contrib.gis.geos import fromstr, Point, LineString, LinearRing, Polygon
+from django.utils.functional import total_ordering
+from django.utils.safestring import mark_safe
+
class GEvent(object):
"""
@@ -166,6 +168,7 @@ def js_params(self):
return '%s, "%s", %s, %s' % (self.latlngs, self.color, self.weight, self.opacity)
+@total_ordering
class GIcon(object):
"""
Creates a GIcon object to pass into a Gmarker object.
@@ -231,8 +234,11 @@ def __init__(self, varname, image=None, iconsize=None,
self.iconanchor = iconanchor
self.infowindowanchor = infowindowanchor
- def __cmp__(self, other):
- return cmp(self.varname, other.varname)
+ def __eq__(self, other):
+ return self.varname == other.varname
+
+ def __lt__(self, other):
+ return self.varname < other.varname
def __hash__(self):
# XOR with hash of GIcon type so that hash('varname') won't
View
24 django/contrib/gis/measure.py
@@ -38,6 +38,8 @@
__all__ = ['A', 'Area', 'D', 'Distance']
from decimal import Decimal
+from django.utils.functional import total_ordering
+
class MeasureBase(object):
def default_units(self, kwargs):
"""
@@ -84,6 +86,7 @@ def unit_attname(cls, unit_str):
else:
raise Exception('Could not find a unit keyword associated with "%s"' % unit_str)
+@total_ordering
class Distance(MeasureBase):
UNITS = {
'chain' : 20.1168,
@@ -178,9 +181,15 @@ def __repr__(self):
def __str__(self):
return '%s %s' % (getattr(self, self._default_unit), self._default_unit)
- def __cmp__(self, other):
+ def __eq__(self, other):
+ if isinstance(other, Distance):
+ return self.m == other.m
+ else:
+ return NotImplemented
+
+ def __lt__(self, other):
if isinstance(other, Distance):
- return cmp(self.m, other.m)
+ return self.m < other.m
else:
return NotImplemented
@@ -244,6 +253,7 @@ def __idiv__(self, other):
def __nonzero__(self):
return bool(self.m)
+@total_ordering
class Area(MeasureBase):
# Getting the square units values and the alias dictionary.
UNITS = dict([('sq_%s' % k, v ** 2) for k, v in Distance.UNITS.items()])
@@ -267,9 +277,15 @@ def __repr__(self):
def __str__(self):
return '%s %s' % (getattr(self, self._default_unit), self._default_unit)
- def __cmp__(self, other):
+ def __eq__(self, other):
+ if isinstance(other, Area):
+ return self.sq_m == other.sq_m
+ else:
+ return NotImplemented
+
+ def __lt__(self, other):
if isinstance(other, Area):
- return cmp(self.sq_m, other.sq_m)
+ return self.sq_m < other.sq_m
else:
return NotImplemented
View
2  django/contrib/gis/templates/gis/admin/openlayers.js
@@ -111,7 +111,7 @@ OpenLayers.Projection.addTransform("EPSG:4326", "EPSG:3857", OpenLayers.Layer.Sp
// The admin map for this geometry field.
{{ module }}.map = new OpenLayers.Map('{{ id }}_map', options);
// Base Layer
- {{ module }}.layers.base = {% block base_layer %}new OpenLayers.Layer.WMS( "{{ wms_name }}", "{{ wms_url }}", {layers: '{{ wms_layer }}'} );{% endblock %}
+ {{ module }}.layers.base = {% block base_layer %}new OpenLayers.Layer.WMS("{{ wms_name }}", "{{ wms_url }}", {layers: '{{ wms_layer }}'{{ wms_options|safe }}});{% endblock %}
{{ module }}.map.addLayer({{ module }}.layers.base);
{% block extra_layers %}{% endblock %}
{% if is_linestring %}OpenLayers.Feature.Vector.style["default"]["strokeWidth"] = 3; // Default too thin for linestrings. {% endif %}
View
19 django/contrib/gis/tests/geoadmin/tests.py
@@ -2,6 +2,7 @@
from django.test import TestCase
from django.contrib.gis import admin
+from django.contrib.gis.geos import Point
from .models import City
@@ -14,3 +15,21 @@ def test01_ensure_geographic_media(self):
admin_js = geoadmin.media.render_js()
self.assertTrue(any([geoadmin.openlayers_url in js for js in admin_js]))
+ def test_olmap_OSM_rendering(self):
+ geoadmin = admin.site._registry[City]
+ result = geoadmin.get_map_widget(City._meta.get_field('point'))(
+ ).render('point', Point(-79.460734, 40.18476))
+ self.assertIn(
+ """geodjango_point.layers.base = new OpenLayers.Layer.OSM("OpenStreetMap (Mapnik)");""",
+ result)
+
+ def test_olmap_WMS_rendering(self):
+ admin.site.unregister(City)
+ admin.site.register(City, admin.GeoModelAdmin)
+
+ geoadmin = admin.site._registry[City]
+ result = geoadmin.get_map_widget(City._meta.get_field('point'))(
+ ).render('point', Point(-79.460734, 40.18476))
+ self.assertIn(
+ """geodjango_point.layers.base = new OpenLayers.Layer.WMS("OpenLayers WMS", "http://vmap0.tiles.osgeo.org/wms/vmap0", {layers: \'basic\', format: 'image/jpeg'});""",
+ result)
View
1  django/contrib/gis/tests/layermap/models.py
@@ -17,6 +17,7 @@ class CountyFeat(models.Model):
class City(models.Model):
name = models.CharField(max_length=25)
+ name_txt = models.TextField(default='')
population = models.IntegerField()
density = models.DecimalField(max_digits=7, decimal_places=1)
dt = models.DateField()
View
65 django/contrib/gis/tests/layermap/tests.py
@@ -4,11 +4,11 @@
from copy import copy
from decimal import Decimal
-from django.utils.unittest import TestCase
-
from django.contrib.gis.gdal import DataSource
from django.contrib.gis.tests.utils import mysql
-from django.contrib.gis.utils.layermapping import LayerMapping, LayerMapError, InvalidDecimal, MissingForeignKey
+from django.contrib.gis.utils.layermapping import (LayerMapping, LayerMapError,
+ InvalidDecimal, MissingForeignKey)
+from django.test import TestCase