Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge branch 'master' into schema-alteration

  • Loading branch information...
commit b546e7eb633022ee1962570387f22fb2bcea46ed 2 parents cd583d6 + cff911f
Andrew Godwin andrewgodwin authored
Showing with 4,373 additions and 1,950 deletions.
  1. +2 −0  AUTHORS
  2. +1 −1  MANIFEST.in
  3. +10 −0 django/bin/django-2to3.py
  4. +11 −3 django/conf/__init__.py
  5. +5 −4 django/conf/project_template/project_name/settings.py
  6. +3 −1 django/contrib/admin/models.py
  7. +1 −1  django/contrib/admin/templates/admin/change_form.html
  8. +1 −1  django/contrib/admin/templatetags/log.py
  9. +2 −2 django/contrib/admin/util.py
  10. +3 −3 django/contrib/admin/views/main.py
  11. +2 −2 django/contrib/admindocs/utils.py
  12. +4 −1 django/contrib/auth/decorators.py
  13. +5 −5 django/contrib/auth/forms.py
  14. +5 −5 django/contrib/auth/hashers.py
  15. +14 −4 django/contrib/auth/management/__init__.py
  16. +9 −7 django/contrib/auth/models.py
  17. +38 −6 django/contrib/auth/tests/basic.py
  18. +6 −2 django/contrib/auth/tests/management.py
  19. +3 −0  django/contrib/auth/tests/tokens.py
  20. +5 −4 django/contrib/auth/views.py
  21. +5 −2 django/contrib/comments/models.py
  22. +3 −1 django/contrib/contenttypes/models.py
  23. +3 −1 django/contrib/contenttypes/tests.py
  24. +9 −10 django/contrib/databrowse/datastructures.py
  25. +7 −3 django/contrib/databrowse/tests.py
  26. +3 −1 django/contrib/flatpages/models.py
  27. +43 −18 django/contrib/formtools/tests/__init__.py
  28. +1 −0  django/contrib/formtools/tests/forms.py
  29. +12 −5 django/contrib/formtools/tests/wizard/namedwizardtests/tests.py
  30. +11 −4 django/contrib/formtools/tests/wizard/wizardtests/tests.py
  31. +2 −0  django/contrib/formtools/utils.py
  32. +1 −3 django/contrib/formtools/wizard/storage/base.py
  33. +3 −1 django/contrib/gis/db/backends/base.py
  34. +3 −1 django/contrib/gis/db/backends/oracle/models.py
  35. +3 −1 django/contrib/gis/db/backends/postgis/models.py
  36. +1 −0  django/contrib/gis/db/backends/spatialite/creation.py
  37. +3 −1 django/contrib/gis/db/backends/spatialite/models.py
  38. +6 −5 django/contrib/gis/db/backends/spatialite/operations.py
  39. +1 −2  django/contrib/gis/db/models/query.py
  40. +2 −1  django/contrib/gis/gdal/tests/__init__.py
  41. +5 −2 django/contrib/gis/maps/google/overlays.py
  42. +1 −2  django/contrib/gis/sitemaps/views.py
  43. +15 −7 django/contrib/gis/tests/distapp/models.py
  44. +17 −9 django/contrib/gis/tests/geo3d/models.py
  45. +3 −1 django/contrib/gis/tests/geoadmin/models.py
  46. +11 −5 django/contrib/gis/tests/geoapp/models.py
  47. +9 −0 django/contrib/gis/tests/geoapp/tests.py
  48. +7 −3 django/contrib/gis/tests/geogapp/models.py
  49. +9 −5 django/contrib/gis/tests/relatedapp/models.py
  50. +1 −1  django/contrib/gis/utils/ogrinspect.py
  51. +3 −3 django/contrib/markup/templatetags/markup.py
  52. +4 −3 django/contrib/messages/storage/base.py
  53. +4 −2 django/contrib/redirects/models.py
  54. +7 −4 django/contrib/sessions/backends/base.py
  55. +1 −2  django/contrib/sessions/backends/db.py
  56. +1 −1  django/contrib/sessions/backends/file.py
  57. +5 −2 django/contrib/sitemaps/tests/generic.py
  58. +22 −14 django/contrib/sitemaps/tests/http.py
  59. +14 −8 django/contrib/sitemaps/tests/https.py
  60. +5 −2 django/contrib/sites/models.py
  61. +1 −1  django/contrib/staticfiles/management/commands/collectstatic.py
  62. +13 −7 django/contrib/staticfiles/storage.py
  63. +1 −1  django/contrib/syndication/views.py
  64. +3 −3 django/core/cache/backends/base.py
  65. +4 −3 django/core/cache/backends/db.py
  66. +2 −1  django/core/cache/backends/filebased.py
  67. +5 −0 django/core/cache/backends/memcached.py
  68. +7 −4 django/core/context_processors.py
  69. +11 −7 django/core/files/base.py
  70. +1 −1  django/core/files/move.py
  71. +9 −2 django/core/files/storage.py
  72. +2 −2 django/core/files/uploadedfile.py
  73. +3 −1 django/core/files/uploadhandler.py
  74. +11 −14 django/core/handlers/base.py
  75. +2 −2 django/core/handlers/wsgi.py
  76. +6 −1 django/core/mail/message.py
  77. +6 −1 django/core/management/__init__.py
  78. +2 −2 django/core/management/base.py
  79. +77 −39 django/core/management/commands/inspectdb.py
  80. +9 −3 django/core/management/commands/loaddata.py
  81. +19 −41 django/core/management/commands/makemessages.py
  82. +9 −9 django/core/management/commands/shell.py
  83. +1 −1  django/core/management/commands/syncdb.py
  84. +3 −2 django/core/management/sql.py
  85. +4 −2 django/core/management/templates.py
  86. +2 −2 django/core/management/validation.py
  87. +2 −4 django/core/serializers/base.py
  88. +3 −5 django/core/serializers/json.py
  89. +0 −1  django/core/serializers/pyyaml.py
  90. +6 −4 django/core/servers/basehttp.py
  91. +28 −19 django/core/signing.py
  92. +26 −14 django/core/urlresolvers.py
  93. +8 −7 django/core/validators.py
  94. +16 −12 django/db/backends/__init__.py
  95. +4 −4 django/db/backends/mysql/base.py
  96. +8 −2 django/db/backends/mysql/compiler.py
  97. +17 −5 django/db/backends/mysql/introspection.py
  98. +15 −8 django/db/backends/oracle/base.py
  99. +7 −2 django/db/backends/oracle/compiler.py
  100. +3 −3 django/db/backends/postgresql_psycopg2/base.py
  101. +2 −2 django/db/backends/postgresql_psycopg2/introspection.py
  102. +17 −9 django/db/backends/sqlite3/base.py
  103. +13 −5 django/db/backends/sqlite3/introspection.py
  104. +2 −1  django/db/backends/util.py
  105. +24 −6 django/db/models/base.py
  106. +4 −2 django/db/models/expressions.py
  107. +3 −2 django/db/models/fields/__init__.py
  108. +2 −2 django/db/models/fields/files.py
  109. +3 −2 django/db/models/fields/subclassing.py
  110. +7 −3 django/db/models/options.py
  111. +3 −5 django/db/models/query.py
  112. +5 −9 django/db/models/sql/compiler.py
  113. +1 −1  django/db/models/sql/constants.py
  114. +55 −51 django/db/models/sql/query.py
  115. +4 −2 django/dispatch/saferef.py
  116. +7 −5 django/forms/forms.py
  117. +14 −15 django/forms/formsets.py
  118. +7 −9 django/forms/models.py
  119. +7 −5 django/forms/util.py
  120. +13 −11 django/forms/widgets.py
  121. +119 −80 django/http/__init__.py
  122. +8 −4 django/http/multipartparser.py
  123. +4 −3 django/middleware/csrf.py
  124. +5 −6 django/template/base.py
  125. +7 −12 django/template/defaultfilters.py
  126. +2 −2 django/template/defaulttags.py
  127. +9 −4 django/template/loaders/eggs.py
  128. +7 −7 django/template/response.py
  129. +4 −2 django/templatetags/cache.py
  130. +26 −24 django/test/client.py
  131. +5 −2 django/test/html.py
  132. +8 −1 django/test/signals.py
  133. +27 −26 django/test/testcases.py
  134. +1 −1  django/test/utils.py
  135. 0  django/utils/2to3_fixes/__init__.py
  136. +36 −0 django/utils/2to3_fixes/fix_unicode.py
  137. +17 −1 django/utils/archive.py
  138. +3 −2 django/utils/autoreload.py
  139. +6 −5 django/utils/cache.py
  140. +11 −6 django/utils/crypto.py
  141. +7 −11 django/utils/dateparse.py
  142. +44 −5 django/utils/encoding.py
  143. +5 −5 django/utils/formats.py
  144. +0 −1  django/utils/functional.py
  145. +15 −4 django/utils/html.py
  146. +100 −88 django/utils/html_parser.py
  147. +10 −8 django/utils/http.py
  148. +1 −1  django/utils/ipv6.py
  149. +44 −30 django/utils/safestring.py
  150. +33 −19 django/utils/six.py
  151. +19 −2 django/utils/text.py
  152. +3 −3 django/utils/translation/__init__.py
  153. +13 −6 django/utils/translation/trans_real.py
  154. +3 −3 django/utils/tzinfo.py
  155. +2 −2 django/views/debug.py
  156. +5 −3 django/views/generic/base.py
  157. +13 −4 django/views/generic/dates.py
  158. +1 −1  django/views/static.py
  159. +4 −8 docs/conf.py
  160. +1 −1  docs/faq/general.txt
  161. +3 −3 docs/howto/custom-template-tags.txt
  162. +1 −1  docs/howto/deployment/wsgi/gunicorn.txt
  163. +6 −3 docs/index.txt
  164. +1 −3 docs/internals/committers.txt
  165. +0 −2  docs/internals/contributing/bugs-and-features.txt
  166. +11 −0 docs/intro/tutorial03.txt
  167. +22 −13 docs/ref/class-based-views/base.txt
  168. +556 −0 docs/ref/class-based-views/flattened-index.txt
  169. +26 −1 docs/ref/class-based-views/generic-date-based.txt
  170. +8 −2 docs/ref/class-based-views/generic-display.txt
  171. +19 −8 docs/ref/class-based-views/generic-editing.txt
  172. +2 −1  docs/ref/class-based-views/index.txt
  173. +18 −0 docs/ref/class-based-views/mixins-date-based.txt
  174. +12 −2 docs/ref/class-based-views/mixins-editing.txt
  175. +6 −0 docs/ref/class-based-views/mixins-multiple-object.txt
  176. +20 −2 docs/ref/class-based-views/mixins-simple.txt
  177. +6 −0 docs/ref/class-based-views/mixins-single-object.txt
  178. +5 −3 docs/ref/contrib/admin/index.txt
  179. +3 −1 docs/ref/contrib/comments/index.txt
  180. +104 −43 docs/ref/contrib/csrf.txt
  181. +41 −2 docs/ref/contrib/flatpages.txt
  182. +3 −3 docs/ref/contrib/formtools/form-wizard.txt
  183. +20 −22 docs/ref/contrib/gis/install.txt
  184. +3 −2 docs/ref/contrib/gis/testing.txt
  185. +11 −0 docs/ref/contrib/gis/tutorial.txt
  186. +4 −4 docs/ref/databases.txt
  187. +8 −4 docs/ref/files/file.txt
  188. +46 −46 docs/ref/models/fields.txt
  189. +9 −3 docs/ref/models/instances.txt
  190. +16 −0 docs/ref/models/querysets.txt
  191. +11 −8 docs/ref/request-response.txt
  192. +28 −13 docs/ref/settings.txt
  193. +10 −0 docs/ref/templates/api.txt
  194. +87 −5 docs/ref/utils.txt
  195. +14 −0 docs/releases/1.3.2.txt
  196. +14 −0 docs/releases/1.4.1.txt
  197. +14 −0 docs/releases/1.4.2.txt
  198. +89 −4 docs/releases/1.5.txt
  199. +3 −0  docs/releases/index.txt
  200. +11 −10 docs/topics/auth.txt
  201. +1 −1  docs/topics/cache.txt
  202. +35 −118 docs/topics/class-based-views/index.txt
  203. +115 −35 docs/topics/class-based-views/mixins.txt
  204. +13 −15 docs/topics/db/models.txt
  205. +1 −1  docs/topics/db/multi-db.txt
  206. +2 −2 docs/topics/db/queries.txt
  207. +30 −30 docs/topics/forms/media.txt
  208. +3 −1 docs/topics/forms/modelforms.txt
  209. +46 −0 docs/topics/http/file-uploads.txt
  210. +8 −4 docs/topics/http/urls.txt
  211. +4 −0 docs/topics/http/views.txt
  212. +16 −6 docs/topics/i18n/translation.txt
  213. +34 −4 docs/topics/logging.txt
  214. +281 −27 docs/topics/python3.txt
  215. +5 −1 docs/topics/templates.txt
  216. +1 −1  docs/topics/testing.txt
  217. +1 −1  setup.cfg
  218. +9 −4 tests/modeltests/aggregation/models.py
  219. +3 −1 tests/modeltests/basic/models.py
  220. +3 −1 tests/modeltests/choices/models.py
  221. +5 −2 tests/modeltests/custom_columns/models.py
  222. +7 −3 tests/modeltests/custom_managers/models.py
  223. +3 −1 tests/modeltests/custom_methods/models.py
  224. +5 −4 tests/modeltests/custom_pk/fields.py
  225. +7 −3 tests/modeltests/custom_pk/models.py
  226. +3 −1 tests/modeltests/defer/models.py
  227. +4 −0 tests/modeltests/delete/models.py
  228. +9 −4 tests/modeltests/distinct_on_fields/models.py
  229. +5 −2 tests/modeltests/expressions/models.py
  230. +3 −1 tests/modeltests/field_defaults/models.py
  231. +5 −8 tests/modeltests/field_subclassing/fields.py
  232. +3 −1 tests/modeltests/field_subclassing/models.py
  233. +7 −7 tests/modeltests/files/tests.py
  234. +15 −7 tests/modeltests/fixtures/models.py
  235. +3 −1 tests/modeltests/fixtures_model_package/models/__init__.py
  236. +11 −5 tests/modeltests/generic_relations/models.py
  237. +5 −2 tests/modeltests/get_latest/models.py
  238. +5 −2 tests/modeltests/get_object_or_404/models.py
  239. +3 −1 tests/modeltests/get_or_create/models.py
  240. +2 −2 tests/modeltests/invalid_models/tests.py
  241. +9 −4 tests/modeltests/lookup/models.py
  242. +3 −1 tests/modeltests/m2m_and_m2o/models.py
  243. +7 −3 tests/modeltests/m2m_intermediary/models.py
  244. +5 −2 tests/modeltests/m2m_multiple/models.py
  245. +3 −1 tests/modeltests/m2m_recursive/models.py
  246. +7 −3 tests/modeltests/m2m_signals/models.py
  247. +11 −5 tests/modeltests/m2m_through/models.py
  248. +5 −2 tests/modeltests/m2o_recursive/models.py
  249. +5 −2 tests/modeltests/many_to_many/models.py
  250. +5 −2 tests/modeltests/many_to_one/models.py
  251. +5 −2 tests/modeltests/many_to_one_null/models.py
  252. +37 −15 tests/modeltests/model_forms/models.py
  253. +35 −34 tests/modeltests/model_forms/tests.py
  254. +37 −18 tests/modeltests/model_formsets/models.py
  255. +19 −9 tests/modeltests/model_inheritance/models.py
  256. +3 −1 tests/modeltests/model_inheritance_same_model_name/models.py
  257. +9 −4 tests/modeltests/one_to_one/models.py
  258. +3 −1 tests/modeltests/or_lookups/models.py
  259. +5 −2 tests/modeltests/order_with_respect_to/models.py
  260. +5 −2 tests/modeltests/ordering/models.py
  261. +3 −1 tests/modeltests/pagination/models.py
  262. +6 −6 tests/modeltests/pagination/tests.py
  263. +15 −7 tests/modeltests/prefetch_related/models.py
  264. +1 −1  tests/modeltests/prefetch_related/tests.py
  265. +2 −1  tests/modeltests/proxy_model_inheritance/tests.py
  266. +9 −4 tests/modeltests/proxy_models/models.py
  267. +4 −2 tests/modeltests/reserved_names/models.py
  268. +7 −3 tests/modeltests/reverse_lookup/models.py
  269. +3 −1 tests/modeltests/save_delete_hooks/models.py
  270. +18 −9 tests/modeltests/select_related/models.py
  271. +17 −12 tests/modeltests/serializers/models.py
  272. +9 −9 tests/modeltests/serializers/tests.py
  273. +5 −2 tests/modeltests/signals/models.py
  274. +4 −2 tests/modeltests/str/models.py
  275. +13 −4 tests/modeltests/str/tests.py
  276. +1 −1  tests/modeltests/test_client/models.py
  277. +1 −0  tests/modeltests/timezones/tests.py
  278. +3 −1 tests/modeltests/transactions/models.py
  279. +13 −6 tests/modeltests/unmanaged_models/models.py
  280. +5 −2 tests/modeltests/update/models.py
  281. +6 −2 tests/modeltests/update_only_fields/models.py
  282. +101 −0 tests/modeltests/update_only_fields/tests.py
  283. +5 −1 tests/modeltests/validation/models.py
  284. +3 −3 tests/modeltests/validation/tests.py
  285. +5 −2 tests/regressiontests/admin_changelist/models.py
  286. +2 −2 tests/regressiontests/admin_changelist/tests.py
  287. +8 −1 tests/regressiontests/admin_custom_urls/fixtures/actions.json
  288. +4 −2 tests/regressiontests/admin_custom_urls/models.py
  289. +30 −13 tests/regressiontests/admin_custom_urls/tests.py
  290. +7 −3 tests/regressiontests/admin_filters/models.py
  291. +7 −3 tests/regressiontests/admin_inlines/models.py
  292. +2 −0  tests/regressiontests/admin_scripts/custom_templates/project_template/ticket-18091-non-ascii-template.txt
  293. +3 −1 tests/regressiontests/admin_scripts/models.py
  294. +24 −6 tests/regressiontests/admin_scripts/tests.py
  295. +3 −1 tests/regressiontests/admin_util/models.py
  296. +1 −1  tests/regressiontests/admin_util/tests.py
  297. +3 −1 tests/regressiontests/admin_validation/models.py
  298. +61 −30 tests/regressiontests/admin_views/models.py
  299. +160 −189 tests/regressiontests/admin_views/tests.py
  300. +16 −8 tests/regressiontests/admin_widgets/models.py
Sorry, we could not display the entire diff because too many files (410) changed.
2  AUTHORS
View
@@ -373,6 +373,7 @@ answer newbie questions, and generally made Django that much better:
michael.mcewan@gmail.com
Paul McLanahan <paul@mclanahan.net>
Tobias McNulty <http://www.caktusgroup.com/blog>
+ Andrews Medina <andrewsmedina@gmail.com>
Zain Memon
Christian Metts
michal@plovarna.cz
@@ -467,6 +468,7 @@ answer newbie questions, and generally made Django that much better:
Vinay Sajip <vinay_sajip@yahoo.co.uk>
Bartolome Sanchez Salado <i42sasab@uco.es>
Kadesarin Sanjek
+ Tim Saylor <tim.saylor@gmail.com>
Massimo Scamarcia <massimo.scamarcia@gmail.com>
Paulo Scardine <paulo@scardine.com.br>
David Schein
2  MANIFEST.in
View
@@ -1,4 +1,4 @@
-include README
+include README.rst
include AUTHORS
include INSTALL
include LICENSE
10 django/bin/django-2to3.py
View
@@ -0,0 +1,10 @@
+#!/usr/bin/env python
+
+# This works exactly like 2to3, except that it uses Django's fixers rather
+# than 2to3's built-in fixers.
+
+import sys
+from lib2to3.main import main
+
+sys.exit(main("django.utils.2to3_fixes"))
+
14 django/conf/__init__.py
View
@@ -152,17 +152,25 @@ def __init__(self, default_settings):
Requests for configuration variables not in this class are satisfied
from the module specified in default_settings (if possible).
"""
+ self.__dict__['_deleted'] = set()
self.default_settings = default_settings
def __getattr__(self, name):
+ if name in self._deleted:
+ raise AttributeError
return getattr(self.default_settings, name)
+ def __setattr__(self, name, value):
+ self._deleted.discard(name)
+ return super(UserSettingsHolder, self).__setattr__(name, value)
+
+ def __delattr__(self, name):
+ self._deleted.add(name)
+ return super(UserSettingsHolder, self).__delattr__(name)
+
def __dir__(self):
return list(self.__dict__) + dir(self.default_settings)
- # For Python < 2.6:
- __members__ = property(lambda self: self.__dir__())
-
settings = LazySettings()
9 django/conf/project_template/project_name/settings.py
View
@@ -13,10 +13,11 @@
'default': {
'ENGINE': 'django.db.backends.', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.
'NAME': '', # Or path to database file if using sqlite3.
- 'USER': '', # Not used with sqlite3.
- 'PASSWORD': '', # Not used with sqlite3.
- 'HOST': '', # Set to empty string for localhost. Not used with sqlite3.
- 'PORT': '', # Set to empty string for default. Not used with sqlite3.
+ # The following settings are not used with sqlite3:
+ 'USER': '',
+ 'PASSWORD': '',
+ 'HOST': '', # Empty for localhost through domain sockets or '127.0.0.1' for localhost through TCP.
+ 'PORT': '', # Set to empty string for default.
}
}
4 django/contrib/admin/models.py
View
@@ -6,6 +6,7 @@
from django.contrib.admin.util import quote
from django.utils.translation import ugettext_lazy as _
from django.utils.encoding import smart_text
+from django.utils.encoding import python_2_unicode_compatible
ADDITION = 1
CHANGE = 2
@@ -16,6 +17,7 @@ def log_action(self, user_id, content_type_id, object_id, object_repr, action_fl
e = self.model(None, None, user_id, content_type_id, smart_text(object_id), object_repr[:200], action_flag, change_message)
e.save()
+@python_2_unicode_compatible
class LogEntry(models.Model):
action_time = models.DateTimeField(_('action time'), auto_now=True)
user = models.ForeignKey(User)
@@ -36,7 +38,7 @@ class Meta:
def __repr__(self):
return smart_text(self.action_time)
- def __unicode__(self):
+ def __str__(self):
if self.action_flag == ADDITION:
return _('Added "%(object)s".') % {'object': self.object_repr}
elif self.action_flag == CHANGE:
2  django/contrib/admin/templates/admin/change_form.html
View
@@ -29,7 +29,7 @@
{% if change %}{% if not is_popup %}
<ul class="object-tools">
{% block object-tools-items %}
- <li><a href="history/" class="historylink">{% trans "History" %}</a></li>
+ <li><a href="{% url opts|admin_urlname:'history' original.pk %}" class="historylink">{% trans "History" %}</a></li>
{% if has_absolute_url %}<li><a href="{% url 'admin:view_on_site' content_type_id original.pk %}" class="viewsitelink">{% trans "View on site" %}</a></li>{% endif%}
{% endblock %}
</ul>
2  django/contrib/admin/templatetags/log.py
View
@@ -17,7 +17,7 @@ def render(self, context):
user_id = self.user
if not user_id.isdigit():
user_id = context[self.user].id
- context[self.varname] = LogEntry.objects.filter(user__id__exact=user_id).select_related('content_type', 'user')[:self.limit]
+ context[self.varname] = LogEntry.objects.filter(user__id__exact=user_id).select_related('content_type', 'user')[:int(self.limit)]
return ''
@register.tag
4 django/contrib/admin/util.py
View
@@ -12,7 +12,7 @@
from django.utils.html import format_html
from django.utils.text import capfirst
from django.utils import timezone
-from django.utils.encoding import force_text, smart_text, smart_bytes
+from django.utils.encoding import force_str, force_text, smart_text
from django.utils import six
from django.utils.translation import ungettext
from django.core.urlresolvers import reverse
@@ -277,7 +277,7 @@ def label_for_field(name, model, model_admin=None, return_attr=False):
label = force_text(model._meta.verbose_name)
attr = six.text_type
elif name == "__str__":
- label = smart_bytes(model._meta.verbose_name)
+ label = force_str(model._meta.verbose_name)
attr = bytes
else:
if callable(name):
6 django/contrib/admin/views/main.py
View
@@ -6,7 +6,7 @@
from django.db import models
from django.db.models.fields import FieldDoesNotExist
from django.utils.datastructures import SortedDict
-from django.utils.encoding import force_text, smart_bytes
+from django.utils.encoding import force_str, force_text
from django.utils.translation import ugettext, ugettext_lazy
from django.utils.http import urlencode
@@ -94,7 +94,7 @@ def get_filters(self, request):
# 'key' will be used as a keyword argument later, so Python
# requires it to be a string.
del lookup_params[key]
- lookup_params[smart_bytes(key)] = value
+ lookup_params[force_str(key)] = value
if not self.model_admin.lookup_allowed(key, value):
raise SuspiciousOperation("Filtering by %s not allowed" % key)
@@ -148,7 +148,7 @@ def get_query_string(self, new_params=None, remove=None):
if remove is None: remove = []
p = self.params.copy()
for r in remove:
- for k in p.keys():
+ for k in list(p):
if k.startswith(r):
del p[k]
for k, v in new_params.items():
4 django/contrib/admindocs/utils.py
View
@@ -6,7 +6,7 @@
from django.utils.safestring import mark_safe
from django.core.urlresolvers import reverse
-from django.utils.encoding import smart_bytes
+from django.utils.encoding import force_bytes
try:
import docutils.core
import docutils.nodes
@@ -66,7 +66,7 @@ def parse_rst(text, default_reference_context, thing_being_parsed=None):
"link_base" : reverse('django-admindocs-docroot').rstrip('/')
}
if thing_being_parsed:
- thing_being_parsed = smart_bytes("<%s>" % thing_being_parsed)
+ thing_being_parsed = force_bytes("<%s>" % thing_being_parsed)
parts = docutils.core.publish_parts(text, source_path=thing_being_parsed,
destination_path=None, writer_name='html',
settings_overrides=overrides)
5 django/contrib/auth/decorators.py
View
@@ -7,6 +7,7 @@
from django.contrib.auth import REDIRECT_FIELD_NAME
from django.core.exceptions import PermissionDenied
from django.utils.decorators import available_attrs
+from django.utils.encoding import force_str
def user_passes_test(test_func, login_url=None, redirect_field_name=REDIRECT_FIELD_NAME):
@@ -22,9 +23,11 @@ def _wrapped_view(request, *args, **kwargs):
if test_func(request.user):
return view_func(request, *args, **kwargs)
path = request.build_absolute_uri()
+ # urlparse chokes on lazy objects in Python 3
+ login_url_as_str = force_str(login_url or settings.LOGIN_URL)
# If the login url is the same scheme and net location then just
# use the path as the "next" url.
- login_scheme, login_netloc = urlparse(login_url or settings.LOGIN_URL)[:2]
+ login_scheme, login_netloc = urlparse(login_url_as_str)[:2]
current_scheme, current_netloc = urlparse(path)[:2]
if ((not login_scheme or login_scheme == current_scheme) and
(not login_netloc or login_netloc == current_netloc)):
10 django/contrib/auth/forms.py
View
@@ -63,16 +63,16 @@ class UserCreationForm(forms.ModelForm):
}
username = forms.RegexField(label=_("Username"), max_length=30,
regex=r'^[\w.@+-]+$',
- help_text = _("Required. 30 characters or fewer. Letters, digits and "
+ help_text=_("Required. 30 characters or fewer. Letters, digits and "
"@/./+/-/_ only."),
- error_messages = {
+ error_messages={
'invalid': _("This value may contain only letters, numbers and "
"@/./+/-/_ characters.")})
password1 = forms.CharField(label=_("Password"),
widget=forms.PasswordInput)
password2 = forms.CharField(label=_("Password confirmation"),
widget=forms.PasswordInput,
- help_text = _("Enter the same password as above, for verification."))
+ help_text=_("Enter the same password as above, for verification."))
class Meta:
model = User
@@ -107,9 +107,9 @@ def save(self, commit=True):
class UserChangeForm(forms.ModelForm):
username = forms.RegexField(
label=_("Username"), max_length=30, regex=r"^[\w.@+-]+$",
- help_text = _("Required. 30 characters or fewer. Letters, digits and "
+ help_text=_("Required. 30 characters or fewer. Letters, digits and "
"@/./+/-/_ only."),
- error_messages = {
+ error_messages={
'invalid': _("This value may contain only letters, numbers and "
"@/./+/-/_ characters.")})
password = ReadOnlyPasswordHashField(label=_("Password"),
10 django/contrib/auth/hashers.py
View
@@ -8,7 +8,7 @@
from django.test.signals import setting_changed
from django.utils import importlib
from django.utils.datastructures import SortedDict
-from django.utils.encoding import smart_bytes
+from django.utils.encoding import force_bytes
from django.core.exceptions import ImproperlyConfigured
from django.utils.crypto import (
pbkdf2, constant_time_compare, get_random_string)
@@ -219,7 +219,7 @@ def encode(self, password, salt, iterations=None):
if not iterations:
iterations = self.iterations
hash = pbkdf2(password, salt, iterations, digest=self.digest)
- hash = base64.b64encode(hash).strip()
+ hash = base64.b64encode(hash).decode('ascii').strip()
return "%s$%d$%s$%s" % (self.algorithm, iterations, salt, hash)
def verify(self, password, encoded):
@@ -299,7 +299,7 @@ class SHA1PasswordHasher(BasePasswordHasher):
def encode(self, password, salt):
assert password
assert salt and '$' not in salt
- hash = hashlib.sha1(smart_bytes(salt + password)).hexdigest()
+ hash = hashlib.sha1(force_bytes(salt + password)).hexdigest()
return "%s$%s$%s" % (self.algorithm, salt, hash)
def verify(self, password, encoded):
@@ -327,7 +327,7 @@ class MD5PasswordHasher(BasePasswordHasher):
def encode(self, password, salt):
assert password
assert salt and '$' not in salt
- hash = hashlib.md5(smart_bytes(salt + password)).hexdigest()
+ hash = hashlib.md5(force_bytes(salt + password)).hexdigest()
return "%s$%s$%s" % (self.algorithm, salt, hash)
def verify(self, password, encoded):
@@ -361,7 +361,7 @@ def salt(self):
return ''
def encode(self, password, salt):
- return hashlib.md5(smart_bytes(password)).hexdigest()
+ return hashlib.md5(force_bytes(password)).hexdigest()
def verify(self, password, encoded):
encoded_2 = self.encode(password, '')
18 django/contrib/auth/management/__init__.py
View
@@ -9,6 +9,7 @@
from django.contrib.auth import models as auth_app
from django.db.models import get_models, signals
from django.contrib.auth.models import User
+from django.utils import six
from django.utils.six.moves import input
@@ -85,13 +86,22 @@ def get_system_username():
username could not be determined.
"""
try:
- return getpass.getuser().decode(locale.getdefaultlocale()[1])
- except (ImportError, KeyError, UnicodeDecodeError):
+ result = getpass.getuser()
+ except (ImportError, KeyError):
# KeyError will be raised by os.getpwuid() (called by getuser())
# if there is no corresponding entry in the /etc/passwd file
# (a very restricted chroot environment, for example).
- # UnicodeDecodeError - preventive treatment for non-latin Windows.
return ''
+ if not six.PY3:
+ default_locale = locale.getdefaultlocale()[1]
+ if not default_locale:
+ return ''
+ try:
+ result = result.decode(default_locale)
+ except UnicodeDecodeError:
+ # UnicodeDecodeError - preventive treatment for non-latin Windows.
+ return ''
+ return result
def get_default_username(check_db=True):
@@ -108,7 +118,7 @@ def get_default_username(check_db=True):
default_username = get_system_username()
try:
default_username = unicodedata.normalize('NFKD', default_username)\
- .encode('ascii', 'ignore').replace(' ', '').lower()
+ .encode('ascii', 'ignore').decode('ascii').replace(' ', '').lower()
except UnicodeDecodeError:
return ''
if not RE_VALID_USERNAME.match(default_username):
16 django/contrib/auth/models.py
View
@@ -16,6 +16,7 @@
check_password, make_password, is_password_usable, UNUSABLE_PASSWORD)
from django.contrib.auth.signals import user_logged_in
from django.contrib.contenttypes.models import ContentType
+from django.utils.encoding import python_2_unicode_compatible
def update_last_login(sender, user, **kwargs):
@@ -41,6 +42,7 @@ def get_by_natural_key(self, codename, app_label, model):
)
+@python_2_unicode_compatible
class Permission(models.Model):
"""
The permissions system provides a way to assign permissions to specific
@@ -76,7 +78,7 @@ class Meta:
ordering = ('content_type__app_label', 'content_type__model',
'codename')
- def __unicode__(self):
+ def __str__(self):
return "%s | %s | %s" % (
six.text_type(self.content_type.app_label),
six.text_type(self.content_type),
@@ -94,6 +96,7 @@ class GroupManager(models.Manager):
def get_by_natural_key(self, name):
return self.get(name=name)
+@python_2_unicode_compatible
class Group(models.Model):
"""
Groups are a generic way of categorizing users to apply permissions, or
@@ -121,7 +124,7 @@ class Meta:
verbose_name = _('group')
verbose_name_plural = _('groups')
- def __unicode__(self):
+ def __str__(self):
return self.name
def natural_key(self):
@@ -221,6 +224,7 @@ def _user_has_module_perms(user, app_label):
return False
+@python_2_unicode_compatible
class User(models.Model):
"""
Users within the Django authentication system are represented by this
@@ -259,7 +263,7 @@ class Meta:
verbose_name = _('user')
verbose_name_plural = _('users')
- def __unicode__(self):
+ def __str__(self):
return self.username
def natural_key(self):
@@ -403,6 +407,7 @@ def get_profile(self):
return self._profile_cache
+@python_2_unicode_compatible
class AnonymousUser(object):
id = None
pk = None
@@ -416,11 +421,8 @@ class AnonymousUser(object):
def __init__(self):
pass
- def __unicode__(self):
- return 'AnonymousUser'
-
def __str__(self):
- return six.text_type(self).encode('utf-8')
+ return 'AnonymousUser'
def __eq__(self, other):
return isinstance(other, self.__class__)
44 django/contrib/auth/tests/basic.py
View
@@ -1,13 +1,11 @@
+import locale
+import traceback
+
+from django.contrib.auth.management.commands import createsuperuser
from django.contrib.auth.models import User, AnonymousUser
from django.core.management import call_command
from django.test import TestCase
from django.utils.six import StringIO
-from django.utils.unittest import skipUnless
-
-try:
- import crypt as crypt_module
-except ImportError:
- crypt_module = None
class BasicTestCase(TestCase):
@@ -111,3 +109,37 @@ def test_createsuperuser_management_command(self):
u = User.objects.get(username="joe+admin@somewhere.org")
self.assertEqual(u.email, 'joe@somewhere.org')
self.assertFalse(u.has_usable_password())
+
+ def test_createsuperuser_nolocale(self):
+ """
+ Check that createsuperuser does not break when no locale is set. See
+ ticket #16017.
+ """
+
+ old_getdefaultlocale = locale.getdefaultlocale
+ old_getpass = createsuperuser.getpass
+ try:
+ # Temporarily remove locale information
+ locale.getdefaultlocale = lambda: (None, None)
+
+ # Temporarily replace getpass to allow interactive code to be used
+ # non-interactively
+ class mock_getpass: pass
+ mock_getpass.getpass = staticmethod(lambda p=None: "nopasswd")
+ createsuperuser.getpass = mock_getpass
+
+ # Call the command in this new environment
+ new_io = StringIO()
+ call_command("createsuperuser", interactive=True, username="nolocale@somewhere.org", email="nolocale@somewhere.org", stdout=new_io)
+
+ except TypeError as e:
+ self.fail("createsuperuser fails if the OS provides no information about the current locale")
+
+ finally:
+ # Re-apply locale and getpass information
+ createsuperuser.getpass = old_getpass
+ locale.getdefaultlocale = old_getdefaultlocale
+
+ # If we were successful, a user should have been created
+ u = User.objects.get(username="nolocale@somewhere.org")
+ self.assertEqual(u.email, 'nolocale@somewhere.org')
8 django/contrib/auth/tests/management.py
View
@@ -4,16 +4,20 @@
from django.contrib.auth.management.commands import changepassword
from django.core.management.base import CommandError
from django.test import TestCase
+from django.utils import six
from django.utils.six import StringIO
class GetDefaultUsernameTestCase(TestCase):
def setUp(self):
- self._getpass_getuser = management.get_system_username
+ self.old_get_system_username = management.get_system_username
def tearDown(self):
- management.get_system_username = self._getpass_getuser
+ management.get_system_username = self.old_get_system_username
+
+ def test_actual_implementation(self):
+ self.assertIsInstance(management.get_system_username(), six.text_type)
def test_simple(self):
management.get_system_username = lambda: 'joe'
3  django/contrib/auth/tests/tokens.py
View
@@ -1,9 +1,11 @@
+import sys
from datetime import date, timedelta
from django.conf import settings
from django.contrib.auth.models import User
from django.contrib.auth.tokens import PasswordResetTokenGenerator
from django.test import TestCase
+from django.utils import unittest
class TokenGeneratorTest(TestCase):
@@ -51,6 +53,7 @@ def _today(self):
p2 = Mocked(date.today() + timedelta(settings.PASSWORD_RESET_TIMEOUT_DAYS + 1))
self.assertFalse(p2.check_token(user, tk1))
+ @unittest.skipIf(sys.version_info[:2] >= (3, 0), "Unnecessary test with Python 3")
def test_date_length(self):
"""
Make sure we don't allow overly long dates, causing a potential DoS.
9 django/contrib/auth/views.py
View
@@ -7,6 +7,7 @@
from django.core.urlresolvers import reverse
from django.http import HttpResponseRedirect, QueryDict
from django.template.response import TemplateResponse
+from django.utils.encoding import force_str
from django.utils.http import base36_to_int
from django.utils.translation import ugettext as _
from django.views.decorators.debug import sensitive_post_parameters
@@ -116,10 +117,10 @@ def redirect_to_login(next, login_url=None,
"""
Redirects the user to the login page, passing the given 'next' page
"""
- if not login_url:
- login_url = settings.LOGIN_URL
+ # urlparse chokes on lazy objects in Python 3
+ login_url_as_str = force_str(login_url or settings.LOGIN_URL)
- login_url_parts = list(urlparse(login_url))
+ login_url_parts = list(urlparse(login_url_as_str))
if redirect_field_name:
querystring = QueryDict(login_url_parts[4], mutable=True)
querystring[redirect_field_name] = next
@@ -200,7 +201,7 @@ def password_reset_confirm(request, uidb36=None, token=None,
try:
uid_int = base36_to_int(uidb36)
user = User.objects.get(id=uid_int)
- except (ValueError, User.DoesNotExist):
+ except (ValueError, OverflowError, User.DoesNotExist):
user = None
if user is not None and token_generator.check_token(user, token):
7 django/contrib/comments/models.py
View
@@ -8,6 +8,7 @@
from django.utils.translation import ugettext_lazy as _
from django.utils import timezone
from django.conf import settings
+from django.utils.encoding import python_2_unicode_compatible
COMMENT_MAX_LENGTH = getattr(settings,'COMMENT_MAX_LENGTH',3000)
@@ -39,6 +40,7 @@ def get_content_object_url(self):
args=(self.content_type_id, self.object_pk)
)
+@python_2_unicode_compatible
class Comment(BaseCommentAbstractModel):
"""
A user comment about some object.
@@ -76,7 +78,7 @@ class Meta:
verbose_name = _('comment')
verbose_name_plural = _('comments')
- def __unicode__(self):
+ def __str__(self):
return "%s: %s..." % (self.name, self.comment[:50])
def save(self, *args, **kwargs):
@@ -153,6 +155,7 @@ def get_as_text(self):
}
return _('Posted by %(user)s at %(date)s\n\n%(comment)s\n\nhttp://%(domain)s%(url)s') % d
+@python_2_unicode_compatible
class CommentFlag(models.Model):
"""
Records a flag on a comment. This is intentionally flexible; right now, a
@@ -182,7 +185,7 @@ class Meta:
verbose_name = _('comment flag')
verbose_name_plural = _('comment flags')
- def __unicode__(self):
+ def __str__(self):
return "%s flag of comment ID %s by %s" % \
(self.flag, self.comment_id, self.user.username)
4 django/contrib/contenttypes/models.py
View
@@ -1,6 +1,7 @@
from django.db import models
from django.utils.translation import ugettext_lazy as _
from django.utils.encoding import smart_text, force_text
+from django.utils.encoding import python_2_unicode_compatible
class ContentTypeManager(models.Manager):
@@ -122,6 +123,7 @@ def _add_to_cache(self, using, ct):
self.__class__._cache.setdefault(using, {})[key] = ct
self.__class__._cache.setdefault(using, {})[ct.id] = ct
+@python_2_unicode_compatible
class ContentType(models.Model):
name = models.CharField(max_length=100)
app_label = models.CharField(max_length=100)
@@ -135,7 +137,7 @@ class Meta:
ordering = ('name',)
unique_together = (('app_label', 'model'),)
- def __unicode__(self):
+ def __str__(self):
# self.name is deprecated in favor of using model's verbose_name, which
# can be translated. Formal deprecation is delayed until we have DB
# migration to be able to remove the field from the database along with
4 django/contrib/contenttypes/tests.py
View
@@ -8,6 +8,7 @@
from django.test import TestCase
from django.utils.http import urlquote
from django.utils import six
+from django.utils.encoding import python_2_unicode_compatible
class ConcreteModel(models.Model):
@@ -17,13 +18,14 @@ class ProxyModel(ConcreteModel):
class Meta:
proxy = True
+@python_2_unicode_compatible
class FooWithoutUrl(models.Model):
"""
Fake model not defining ``get_absolute_url`` for
:meth:`ContentTypesTests.test_shortcut_view_without_get_absolute_url`"""
name = models.CharField(max_length=30, unique=True)
- def __unicode__(self):
+ def __str__(self):
return self.name
19 django/contrib/databrowse/datastructures.py
View
@@ -7,8 +7,9 @@
from django.db import models
from django.utils import formats
from django.utils.text import capfirst
-from django.utils.encoding import smart_text, smart_bytes, iri_to_uri
+from django.utils.encoding import smart_text, force_str, iri_to_uri
from django.db.models.query import QuerySet
+from django.utils.encoding import python_2_unicode_compatible
EMPTY_VALUE = '(None)'
DISPLAY_SIZE = 100
@@ -22,7 +23,7 @@ def __init__(self, site, model):
self.verbose_name_plural = model._meta.verbose_name_plural
def __repr__(self):
- return '<EasyModel for %s>' % smart_bytes(self.model._meta.object_name)
+ return force_str('<EasyModel for %s>' % self.model._meta.object_name)
def model_databrowse(self):
"Returns the ModelDatabrowse class for this model."
@@ -61,7 +62,7 @@ def __init__(self, easy_model, field):
self.model, self.field = easy_model, field
def __repr__(self):
- return smart_bytes('<EasyField for %s.%s>' % (self.model.model._meta.object_name, self.field.name))
+ return force_str('<EasyField for %s.%s>' % (self.model.model._meta.object_name, self.field.name))
def choices(self):
for value, label in self.field.choices:
@@ -79,27 +80,25 @@ def __init__(self, easy_model, field, value, label):
self.value, self.label = value, label
def __repr__(self):
- return smart_bytes('<EasyChoice for %s.%s>' % (self.model.model._meta.object_name, self.field.name))
+ return force_str('<EasyChoice for %s.%s>' % (self.model.model._meta.object_name, self.field.name))
def url(self):
return '%s%s/%s/%s/%s/' % (self.model.site.root_url, self.model.model._meta.app_label, self.model.model._meta.module_name, self.field.field.name, iri_to_uri(self.value))
+@python_2_unicode_compatible
class EasyInstance(object):
def __init__(self, easy_model, instance):
self.model, self.instance = easy_model, instance
def __repr__(self):
- return smart_bytes('<EasyInstance for %s (%s)>' % (self.model.model._meta.object_name, self.instance._get_pk_val()))
+ return force_str('<EasyInstance for %s (%s)>' % (self.model.model._meta.object_name, self.instance._get_pk_val()))
- def __unicode__(self):
+ def __str__(self):
val = smart_text(self.instance)
if len(val) > DISPLAY_SIZE:
return val[:DISPLAY_SIZE] + '...'
return val
- def __str__(self):
- return self.__unicode__().encode('utf-8')
-
def pk(self):
return self.instance._get_pk_val()
@@ -136,7 +135,7 @@ def __init__(self, easy_model, instance, field):
self.raw_value = getattr(instance.instance, field.name)
def __repr__(self):
- return smart_bytes('<EasyInstanceField for %s.%s>' % (self.model.model._meta.object_name, self.field.name))
+ return force_str('<EasyInstanceField for %s.%s>' % (self.model.model._meta.object_name, self.field.name))
def values(self):
"""
10 django/contrib/databrowse/tests.py
View
@@ -1,26 +1,30 @@
from django.contrib import databrowse
from django.db import models
from django.test import TestCase
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class SomeModel(models.Model):
some_field = models.CharField(max_length=50)
- def __unicode__(self):
+ def __str__(self):
return self.some_field
+@python_2_unicode_compatible
class SomeOtherModel(models.Model):
some_other_field = models.CharField(max_length=50)
- def __unicode__(self):
+ def __str__(self):
return self.some_other_field
+@python_2_unicode_compatible
class YetAnotherModel(models.Model):
yet_another_field = models.CharField(max_length=50)
- def __unicode__(self):
+ def __str__(self):
return self.yet_another_field
4 django/contrib/flatpages/models.py
View
@@ -3,8 +3,10 @@
from django.db import models
from django.contrib.sites.models import Site
from django.utils.translation import ugettext_lazy as _
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class FlatPage(models.Model):
url = models.CharField(_('URL'), max_length=100, db_index=True)
title = models.CharField(_('title'), max_length=200)
@@ -21,7 +23,7 @@ class Meta:
verbose_name_plural = _('flat pages')
ordering = ('url',)
- def __unicode__(self):
+ def __str__(self):
return "%s -- %s" % (self.url, self.title)
def get_absolute_url(self):
61 django/contrib/formtools/tests/__init__.py
View
@@ -1,6 +1,9 @@
+# -*- coding: utf-8 -*-
from __future__ import unicode_literals
+import datetime
import os
+import pickle
import re
import warnings
@@ -16,6 +19,7 @@
from django.contrib.formtools.tests.forms import *
success_string = "Done was called!"
+success_string_encoded = success_string.encode()
class TestFormPreview(preview.FormPreview):
def get_context(self, request, form):
@@ -78,7 +82,7 @@ def test_form_preview(self):
"""
# Pass strings for form submittal and add stage variable to
# show we previously saw first stage of the form.
- self.test_data.update({'stage': 1})
+ self.test_data.update({'stage': 1, 'date1': datetime.date(2006, 10, 25)})
response = self.client.post('/preview/', self.test_data)
# Check to confirm stage is set to 2 in output form.
stage = self.input % 2
@@ -96,13 +100,13 @@ def test_form_submit(self):
"""
# Pass strings for form submittal and add stage variable to
# show we previously saw first stage of the form.
- self.test_data.update({'stage':2})
+ self.test_data.update({'stage': 2, 'date1': datetime.date(2006, 10, 25)})
response = self.client.post('/preview/', self.test_data)
- self.assertNotEqual(response.content, success_string)
+ self.assertNotEqual(response.content, success_string_encoded)
hash = self.preview.security_hash(None, TestForm(self.test_data))
self.test_data.update({'hash': hash})
response = self.client.post('/preview/', self.test_data)
- self.assertEqual(response.content, success_string)
+ self.assertEqual(response.content, success_string_encoded)
def test_bool_submit(self):
"""
@@ -122,7 +126,7 @@ def test_bool_submit(self):
self.test_data.update({'hash': hash, 'bool1': 'False'})
with warnings.catch_warnings(record=True):
response = self.client.post('/preview/', self.test_data)
- self.assertEqual(response.content, success_string)
+ self.assertEqual(response.content, success_string_encoded)
def test_form_submit_good_hash(self):
"""
@@ -133,11 +137,11 @@ def test_form_submit_good_hash(self):
# show we previously saw first stage of the form.
self.test_data.update({'stage':2})
response = self.client.post('/preview/', self.test_data)
- self.assertNotEqual(response.content, success_string)
+ self.assertNotEqual(response.content, success_string_encoded)
hash = utils.form_hmac(TestForm(self.test_data))
self.test_data.update({'hash': hash})
response = self.client.post('/preview/', self.test_data)
- self.assertEqual(response.content, success_string)
+ self.assertEqual(response.content, success_string_encoded)
def test_form_submit_bad_hash(self):
@@ -150,11 +154,11 @@ def test_form_submit_bad_hash(self):
self.test_data.update({'stage':2})
response = self.client.post('/preview/', self.test_data)
self.assertEqual(response.status_code, 200)
- self.assertNotEqual(response.content, success_string)
+ self.assertNotEqual(response.content, success_string_encoded)
hash = utils.form_hmac(TestForm(self.test_data)) + "bad"
self.test_data.update({'hash': hash})
response = self.client.post('/previewpreview/', self.test_data)
- self.assertNotEqual(response.content, success_string)
+ self.assertNotEqual(response.content, success_string_encoded)
class FormHmacTests(unittest.TestCase):
@@ -165,8 +169,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': 'joe', 'bio': 'Speaking español.'})
+ f2 = HashTestForm({'name': ' joe', 'bio': 'Speaking español. '})
hash1 = utils.form_hmac(f1)
hash2 = utils.form_hmac(f2)
self.assertEqual(hash1, hash2)
@@ -270,7 +274,10 @@ def test_good_hash(self):
"""
data = {"0-field": "test",
"1-field": "test2",
- "hash_0": "cd13b1db3e8f55174bc5745a1b1a53408d4fd1ca",
+ "hash_0": {
+ 2: "cd13b1db3e8f55174bc5745a1b1a53408d4fd1ca",
+ 3: "9355d5dff22d49dbad58e46189982cec649f9f5b",
+ }[pickle.HIGHEST_PROTOCOL],
"wizard_step": "1"}
response = self.client.post('/wizard1/', data)
self.assertEqual(2, response.context['step0'])
@@ -295,15 +302,24 @@ def process_step(self, request, form, step):
wizard = WizardWithProcessStep([WizardPageOneForm])
data = {"0-field": "test",
"1-field": "test2",
- "hash_0": "cd13b1db3e8f55174bc5745a1b1a53408d4fd1ca",
+ "hash_0": {
+ 2: "cd13b1db3e8f55174bc5745a1b1a53408d4fd1ca",
+ 3: "9355d5dff22d49dbad58e46189982cec649f9f5b",
+ }[pickle.HIGHEST_PROTOCOL],
"wizard_step": "1"}
wizard(DummyRequest(POST=data))
self.assertTrue(reached[0])
data = {"0-field": "test",
"1-field": "test2",
- "hash_0": "cd13b1db3e8f55174bc5745a1b1a53408d4fd1ca",
- "hash_1": "1e6f6315da42e62f33a30640ec7e007ad3fbf1a1",
+ "hash_0": {
+ 2: "cd13b1db3e8f55174bc5745a1b1a53408d4fd1ca",
+ 3: "9355d5dff22d49dbad58e46189982cec649f9f5b",
+ }[pickle.HIGHEST_PROTOCOL],
+ "hash_1": {
+ 2: "1e6f6315da42e62f33a30640ec7e007ad3fbf1a1",
+ 3: "c33142ef9d01b1beae238adf22c3c6c57328f51a",
+ }[pickle.HIGHEST_PROTOCOL],
"wizard_step": "2"}
self.assertRaises(http.Http404, wizard, DummyRequest(POST=data))
@@ -325,7 +341,10 @@ def process_step(self, request, form, step):
WizardPageThreeForm])
data = {"0-field": "test",
"1-field": "test2",
- "hash_0": "cd13b1db3e8f55174bc5745a1b1a53408d4fd1ca",
+ "hash_0": {
+ 2: "cd13b1db3e8f55174bc5745a1b1a53408d4fd1ca",
+ 3: "9355d5dff22d49dbad58e46189982cec649f9f5b",
+ }[pickle.HIGHEST_PROTOCOL],
"wizard_step": "1"}
wizard(DummyRequest(POST=data))
self.assertTrue(reached[0])
@@ -349,7 +368,10 @@ def done(self, request, form_list):
data = {"0-field": "test",
"1-field": "test2",
- "hash_0": "cd13b1db3e8f55174bc5745a1b1a53408d4fd1ca",
+ "hash_0": {
+ 2: "cd13b1db3e8f55174bc5745a1b1a53408d4fd1ca",
+ 3: "9355d5dff22d49dbad58e46189982cec649f9f5b",
+ }[pickle.HIGHEST_PROTOCOL],
"wizard_step": "1"}
wizard(DummyRequest(POST=data))
self.assertTrue(reached[0])
@@ -375,7 +397,10 @@ def process_step(self, request, form, step):
WizardPageThreeForm])
data = {"0-field": "test",
"1-field": "test2",
- "hash_0": "cd13b1db3e8f55174bc5745a1b1a53408d4fd1ca",
+ "hash_0": {
+ 2: "cd13b1db3e8f55174bc5745a1b1a53408d4fd1ca",
+ 3: "9355d5dff22d49dbad58e46189982cec649f9f5b",
+ }[pickle.HIGHEST_PROTOCOL],
"wizard_step": "1"}
wizard(DummyRequest(POST=data))
self.assertTrue(reached[0])
1  django/contrib/formtools/tests/forms.py
View
@@ -21,6 +21,7 @@ class TestForm(forms.Form):
field1 = forms.CharField()
field1_ = forms.CharField()
bool1 = forms.BooleanField(required=False)
+ date1 = forms.DateField(required=False)
class HashTestForm(forms.Form):
name = forms.CharField()
17 django/contrib/formtools/tests/wizard/namedwizardtests/tests.py
View
@@ -122,6 +122,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'].close()
post_data['form2-file1'] = open(__file__, 'rb')
response = self.client.post(
reverse(self.wizard_urlname,
@@ -149,7 +150,9 @@ 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__, 'rb').read())
+ with open(__file__, 'rb') as f:
+ self.assertEqual(all_data[1]['file1'].read(), f.read())
+ all_data[1]['file1'].close()
del all_data[1]['file1']
self.assertEqual(all_data, [
{'name': 'Pony', 'thirsty': True, 'user': self.testuser},
@@ -182,9 +185,10 @@ 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__, 'rb').read())
+ with open(__file__, 'rb') as f:
+ self.assertEqual(
+ response.context['wizard']['form'].files['form2-file1'].read(),
+ f.read())
response = self.client.post(
reverse(self.wizard_urlname,
@@ -201,7 +205,9 @@ 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__, 'rb').read())
+ with open(__file__, 'rb') as f:
+ self.assertEqual(all_data['file1'].read(), f.read())
+ all_data['file1'].close()
del all_data['file1']
self.assertEqual(
all_data,
@@ -225,6 +231,7 @@ def test_manipulated_data(self):
self.assertEqual(response.status_code, 200)
post_data = self.wizard_step_data[1]
+ post_data['form2-file1'].close()
post_data['form2-file1'] = open(__file__, 'rb')
response = self.client.post(
reverse(self.wizard_urlname,
15 django/contrib/formtools/tests/wizard/wizardtests/tests.py
View
@@ -95,7 +95,9 @@ 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__, 'rb').read())
+ with open(__file__, 'rb') as f:
+ self.assertEqual(all_data[1]['file1'].read(), f.read())
+ all_data[1]['file1'].close()
del all_data[1]['file1']
self.assertEqual(all_data, [
{'name': 'Pony', 'thirsty': True, 'user': self.testuser},
@@ -112,8 +114,9 @@ def test_cleaned_data(self):
self.assertEqual(response.status_code, 200)
post_data = self.wizard_step_data[1]
- post_data['form2-file1'] = open(__file__, 'rb')
- response = self.client.post(self.wizard_url, post_data)
+ with open(__file__, 'rb') as post_file:
+ post_data['form2-file1'] = post_file
+ response = self.client.post(self.wizard_url, post_data)
self.assertEqual(response.status_code, 200)
response = self.client.post(self.wizard_url, self.wizard_step_data[2])
@@ -123,7 +126,9 @@ 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__, 'rb').read())
+ with open(__file__, 'rb') as f:
+ self.assertEqual(all_data['file1'].read(), f.read())
+ all_data['file1'].close()
del all_data['file1']
self.assertEqual(all_data, {
'name': 'Pony', 'thirsty': True, 'user': self.testuser,
@@ -140,6 +145,7 @@ def test_manipulated_data(self):
self.assertEqual(response.status_code, 200)
post_data = self.wizard_step_data[1]
+ post_data['form2-file1'].close()
post_data['form2-file1'] = open(__file__, 'rb')
response = self.client.post(self.wizard_url, post_data)
self.assertEqual(response.status_code, 200)
@@ -167,6 +173,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'].close()
post_data['form2-file1'] = open(__file__, 'rb')
response = self.client.post(self.wizard_url, post_data)
self.assertEqual(response.status_code, 200)
2  django/contrib/formtools/utils.py
View
@@ -1,3 +1,5 @@
+from __future__ import unicode_literals
+
# Do not try cPickle here (see #18340)
import pickle
4 django/contrib/formtools/wizard/storage/base.py
View
@@ -1,6 +1,5 @@
from django.core.files.uploadedfile import UploadedFile
from django.utils.datastructures import MultiValueDict
-from django.utils.encoding import smart_bytes
from django.utils.functional import lazy_property
from django.utils import six
@@ -74,8 +73,7 @@ def get_step_files(self, step):
files = {}
for field, field_dict in six.iteritems(wizard_files):
- field_dict = dict((smart_bytes(k), v)
- for k, v in six.iteritems(field_dict))
+ field_dict = field_dict.copy()
tmp_name = field_dict.pop('tmp_name')
files[field] = UploadedFile(
file=self.file_storage.open(tmp_name), **field_dict)
4 django/contrib/gis/db/backends/base.py
View
@@ -5,6 +5,7 @@
import re
from django.contrib.gis import gdal
from django.utils import six
+from django.utils.encoding import python_2_unicode_compatible
class BaseSpatialOperations(object):
"""
@@ -131,6 +132,7 @@ def geometry_columns(self):
def spatial_ref_sys(self):
raise NotImplementedError
+@python_2_unicode_compatible
class SpatialRefSysMixin(object):
"""
The SpatialRefSysMixin is a class used by the database-dependent
@@ -325,7 +327,7 @@ def get_spheroid(cls, wkt, string=True):
radius, flattening = sphere_params
return 'SPHEROID["%s",%s,%s]' % (sphere_name, radius, flattening)
- def __unicode__(self):
+ def __str__(self):
"""
Returns the string representation. If GDAL is installed,
it will be 'pretty' OGC WKT.
4 django/contrib/gis/db/backends/oracle/models.py
View
@@ -9,7 +9,9 @@
"""
from django.contrib.gis.db import models
from django.contrib.gis.db.backends.base import SpatialRefSysMixin
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class GeometryColumns(models.Model):
"Maps to the Oracle USER_SDO_GEOM_METADATA table."
table_name = models.CharField(max_length=32)
@@ -36,7 +38,7 @@ def geom_col_name(cls):
"""
return 'column_name'
- def __unicode__(self):
+ def __str__(self):
return '%s - %s (SRID: %s)' % (self.table_name, self.column_name, self.srid)
class SpatialRefSys(models.Model, SpatialRefSysMixin):
4 django/contrib/gis/db/backends/postgis/models.py
View
@@ -3,7 +3,9 @@
"""
from django.db import models
from django.contrib.gis.db.backends.base import SpatialRefSysMixin
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class GeometryColumns(models.Model):
"""
The 'geometry_columns' table from the PostGIS. See the PostGIS
@@ -37,7 +39,7 @@ def geom_col_name(cls):
"""
return 'f_geometry_column'
- def __unicode__(self):
+ def __str__(self):
return "%s.%s - %dD %s field (SRID: %d)" % \
(self.f_table_name, self.f_geometry_column,
self.coord_dimension, self.type, self.srid)
1  django/contrib/gis/db/backends/spatialite/creation.py
View
@@ -30,6 +30,7 @@ def create_test_db(self, verbosity=1, autoclobber=False):
self.connection.close()
self.connection.settings_dict["NAME"] = test_database_name
+ self.connection.ops.confirm_spatial_components_versions()
# Need to load the SpatiaLite initialization SQL before running `syncdb`.
self.load_spatialite_sql()
4 django/contrib/gis/db/backends/spatialite/models.py
View
@@ -3,7 +3,9 @@
"""
from django.db import models
from django.contrib.gis.db.backends.base import SpatialRefSysMixin
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class GeometryColumns(models.Model):
"""
The 'geometry_columns' table from SpatiaLite.
@@ -35,7 +37,7 @@ def geom_col_name(cls):
"""
return 'f_geometry_column'
- def __unicode__(self):
+ def __str__(self):
return "%s.%s - %dD %s field (SRID: %d)" % \
(self.f_table_name, self.f_geometry_column,
self.coord_dimension, self.type, self.srid)
11 django/contrib/gis/db/backends/spatialite/operations.py
View
@@ -113,6 +113,12 @@ class SpatiaLiteOperations(DatabaseOperations, BaseSpatialOperations):
def __init__(self, connection):
super(DatabaseOperations, self).__init__(connection)
+ # Creating the GIS terms dictionary.
+ gis_terms = ['isnull']
+ gis_terms += self.geometry_functions.keys()
+ self.gis_terms = dict([(term, None) for term in gis_terms])
+
+ def confirm_spatial_components_versions(self):
# Determine the version of the SpatiaLite library.
try:
vtup = self.spatialite_version_tuple()
@@ -129,11 +135,6 @@ def __init__(self, connection):
'SQL loaded on this database?' %
(self.connection.settings_dict['NAME'], msg))
- # Creating the GIS terms dictionary.
- gis_terms = ['isnull']
- gis_terms += list(self.geometry_functions)
- self.gis_terms = dict([(term, None) for term in gis_terms])
-
if version >= (2, 4, 0):
# Spatialite 2.4.0-RC4 added AsGML and AsKML, however both
# RC2 (shipped in popular Debian/Ubuntu packages) and RC4
3  django/contrib/gis/db/models/query.py
View
@@ -1,16 +1,15 @@
from django.db import connections
from django.db.models.query import QuerySet, ValuesQuerySet, ValuesListQuerySet
-from django.utils import six
from django.contrib.gis.db.models import aggregates
from django.contrib.gis.db.models.fields import get_srid_info, PointField, LineStringField
from django.contrib.gis.db.models.sql import AreaField, DistanceField, GeomField, GeoQuery
from django.contrib.gis.geometry.backend import Geometry
from django.contrib.gis.measure import Area, Distance
-from django.utils import six
from django.utils import six
+
class GeoQuerySet(QuerySet):
"The Geographic QuerySet."
3  django/contrib/gis/gdal/tests/__init__.py
View
@@ -19,7 +19,8 @@
def suite():
"Builds a test suite for the GDAL tests."
s = TestSuite()
- map(s.addTest, test_suites)
+ for test_suite in test_suites:
+ s.addTest(test_suite)
return s
def run(verbosity=1):
7 django/contrib/gis/maps/google/overlays.py
View
@@ -2,8 +2,10 @@
from django.utils.functional import total_ordering
from django.utils.safestring import mark_safe
from django.utils import six
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class GEvent(object):
"""
A Python wrapper for the Google GEvent object.
@@ -48,10 +50,11 @@ def __init__(self, event, action):
self.event = event
self.action = action
- def __unicode__(self):
+ def __str__(self):
"Returns the parameter part of a GEvent."
return mark_safe('"%s", %s' %(self.event, self.action))
+@python_2_unicode_compatible
class GOverlayBase(object):
def __init__(self):
self.events = []
@@ -64,7 +67,7 @@ def add_event(self, event):
"Attaches a GEvent to the overlay object."
self.events.append(event)
- def __unicode__(self):
+ def __str__(self):
"The string representation is the JavaScript API call."
return mark_safe('%s(%s)' % (self.__class__.__name__, self.js_params))
3  django/contrib/gis/sitemaps/views.py
View
@@ -8,7 +8,6 @@
from django.contrib.gis.db.models.fields import GeometryField
from django.db import connections, DEFAULT_DB_ALIAS
from django.db.models import get_model
-from django.utils.encoding import smart_bytes
from django.utils import six
from django.utils.translation import ugettext as _
@@ -61,7 +60,7 @@ def sitemap(request, sitemaps, section=None):
raise Http404(_("Page %s empty") % page)
except PageNotAnInteger:
raise Http404(_("No page '%s'") % page)
- xml = smart_bytes(loader.render_to_string('gis/sitemaps/geo_sitemap.xml', {'urlset': urls}))
+ xml = loader.render_to_string('gis/sitemaps/geo_sitemap.xml', {'urlset': urls})
return HttpResponse(xml, content_type='application/xml')
def kml(request, label, model, field_name=None, compress=False, using=DEFAULT_DB_ALIAS):
22 django/contrib/gis/tests/distapp/models.py
View
@@ -1,50 +1,58 @@
from django.contrib.gis.db import models
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class SouthTexasCity(models.Model):
"City model on projected coordinate system for South Texas."
name = models.CharField(max_length=30)
point = models.PointField(srid=32140)
objects = models.GeoManager()
- def __unicode__(self): return self.name
+ def __str__(self): return self.name
+@python_2_unicode_compatible
class SouthTexasCityFt(models.Model):
"Same City model as above, but U.S. survey feet are the units."
name = models.CharField(max_length=30)
point = models.PointField(srid=2278)
objects = models.GeoManager()
- def __unicode__(self): return self.name
+ def __str__(self): return self.name
+@python_2_unicode_compatible
class AustraliaCity(models.Model):
"City model for Australia, using WGS84."
name = models.CharField(max_length=30)
point = models.PointField()
objects = models.GeoManager()
- def __unicode__(self): return self.name
+ def __str__(self): return self.name
+@python_2_unicode_compatible
class CensusZipcode(models.Model):
"Model for a few South Texas ZIP codes (in original Census NAD83)."
name = models.CharField(max_length=5)
poly = models.PolygonField(srid=4269)
objects = models.GeoManager()
- def __unicode__(self): return self.name
+ def __str__(self): return self.name
+@python_2_unicode_compatible
class SouthTexasZipcode(models.Model):
"Model for a few South Texas ZIP codes."
name = models.CharField(max_length=5)
poly = models.PolygonField(srid=32140, null=True)
objects = models.GeoManager()
- def __unicode__(self): return self.name
+ def __str__(self): return self.name
+@python_2_unicode_compatible
class Interstate(models.Model):
"Geodetic model for U.S. Interstates."
name = models.CharField(max_length=10)
path = models.LineStringField()
objects = models.GeoManager()
- def __unicode__(self): return self.name
+ def __str__(self): return self.name
+@python_2_unicode_compatible
class SouthTexasInterstate(models.Model):
"Projected model for South Texas Interstates."
name = models.CharField(max_length=10)
path = models.LineStringField(srid=32140)
objects = models.GeoManager()
- def __unicode__(self): return self.name
+ def __str__(self): return self.name
26 django/contrib/gis/tests/geo3d/models.py
View
@@ -1,59 +1,67 @@
from django.contrib.gis.db import models
+from django.utils.encoding import python_2_unicode_compatible
+@python_2_unicode_compatible
class City3D(models.Model):
name = models.CharField(max_length=30)
point = models.PointField(dim=3)
objects = models.GeoManager()
- def __unicode__(self):
+ def __str__(self):
return self.name
+@python_2_unicode_compatible
class Interstate2D(models.Model):
name = models.CharField(max_length=30)
line = models.LineStringField(srid=4269)
objects = models.GeoManager()
- def __unicode__(self):
+ def __str__(self):
return self.name
+@python_2_unicode_compatible
class Interstate3D(models.Model):
name = models.CharField(max_length=30)
line = models.LineStringField(dim=3, srid=4269)
objects = models.GeoManager()
- def __unicode__(self):
+ def __str__(self):
return self.name
+@python_2_unicode_compatible
class InterstateProj2D(models.Model):
name = models.CharField(max_length=30)
line = models.LineStringField(srid=32140)
objects = models.GeoManager()
- def __unicode__(self):
+ def __str__(self):
return self.name
+@python_2_unicode_compatible
class InterstateProj3D(models.Model):
name = models.CharField(max_length=30)
line = models.LineStringField(dim=3, srid=32140)
objects = models.GeoManager()
- def __unicode__(self):
+ def __str__(self):
return self.name
+@python_2_unicode_compatible
class Polygon2D(models.Model):
name = models.CharField(max_length=30)
poly = models.PolygonField(srid=32140)
objects = models.GeoManager()
-
- def __unicode__(self):
+
+ def __str__(self):
return self.name
+@python_2_unicode_compatible
class Polygon3D(models.Model):
name = models.CharField(max_length=30)
poly = models.PolygonField(dim=3, srid=32140)
objects = models.GeoManager()
-
- def __unicode__(self):
+
+ def __str__(self):
return self.name
class Point2D(models.Model):
4 django/contrib/gis/tests/geoadmin/models.py
View
@@ -1,10 +1,12 @@
from django.contrib.gis.db import models
from django.contrib.gis import admin
+from django.utils.encoding import python_2_unicode_compatible