Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Ticket 21725 tests #2339

Closed
wants to merge 3 commits into from

1 participant

@bmispelon
Collaborator

Deprecate django.utils.text.javascript_quote and added some regression tests for the reported issue (which was fixed in a previous commit).

@bmispelon
Collaborator

Merged.

@bmispelon bmispelon closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.
View
6 django/utils/text.py
@@ -4,6 +4,7 @@
import unicodedata
from gzip import GzipFile
from io import BytesIO
+import warnings
from django.utils.encoding import force_text
from django.utils.functional import allow_lazy, SimpleLazyObject
@@ -327,6 +328,11 @@ def compress_sequence(sequence):
def javascript_quote(s, quote_double_quotes=False):
+ msg = (
+ "django.utils.text.javascript_quote() is deprecated. "
+ "Use django.utils.html.escapejs() instead."
+ )
+ warnings.warn(msg, PendingDeprecationWarning, stacklevel=2)
def fix(match):
return "\\u%04x" % ord(match.group(1))
View
2  docs/internals/deprecation.txt
@@ -119,6 +119,8 @@ details on these changes.
* ``ssi`` and ``url`` template tags will be removed from the ``future`` template
tag library (used during the 1.3/1.4 deprecation period).
+* ``django.utils.text.javascript_quote`` will be removed.
+
.. _deprecation-removed-in-1.8:
1.8
View
12 docs/releases/1.7.txt
@@ -1374,3 +1374,15 @@ Django 1.3 introduced ``{% load ssi from future %}`` and
:ttag:`ssi` and :ttag:`url` template tags. This syntax is now deprecated and
will be removed in Django 1.9. You can simply remove the
``{% load ... from future %}`` tags.
+
+``django.utils.text.javascript_quote``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+``javascript_quote()`` was an undocumented function present in ``django.utils.text``.
+It was used internally in the :ref:`javascript_catalog view <javascript_catalog-view>`
+whose implementation was changed to make use of ``json.dumps()`` instead.
+If you were relying on this function to provide safe output from untrusted
+strings, you should use ``django.utils.html.escapejs`` or the
+:tfilter:`escapejs` template filter.
+If all you need is to generate valid javascript strings, you can simply use
+``json.dumps()``.
View
26 tests/utils_tests/test_text.py
@@ -1,9 +1,14 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
+from unittest import skipUnless
+import warnings
+
from django.test import SimpleTestCase
from django.utils import six, text
+IS_WIDE_BUILD = (len('\U0001F4A9') == 1)
+
class TestUtilsText(SimpleTestCase):
@@ -148,15 +153,26 @@ def test_get_valid_filename(self):
def test_javascript_quote(self):
input = "<script>alert('Hello \\xff.\n Welcome\there\r');</script>"
output = r"<script>alert(\'Hello \\xff.\n Welcome\there\r\');<\/script>"
- self.assertEqual(text.javascript_quote(input), output)
+ with warnings.catch_warnings():
+ self.assertEqual(text.javascript_quote(input), output)
# Exercising quote_double_quotes keyword argument
input = '"Text"'
- self.assertEqual(text.javascript_quote(input), '"Text"')
- self.assertEqual(text.javascript_quote(input, quote_double_quotes=True),
- '&quot;Text&quot;')
+ with warnings.catch_warnings():
+ self.assertEqual(text.javascript_quote(input), '"Text"')
+ self.assertEqual(text.javascript_quote(input, quote_double_quotes=True),
+ '&quot;Text&quot;')
+ @skipUnless(IS_WIDE_BUILD, 'Not running in a wide build of Python')
def test_javascript_quote_unicode(self):
input = "<script>alert('Hello \\xff.\n Wel𝕃come\there\r');</script>"
output = r"<script>alert(\'Hello \\xff.\n Wel𝕃come\there\r\');<\/script>"
- self.assertEqual(text.javascript_quote(input), output)
+ with warnings.catch_warnings():
+ self.assertEqual(text.javascript_quote(input), output)
+
+ def test_deprecation(self):
+ with warnings.catch_warnings(record=True) as w:
+ warnings.simplefilter("always")
+ text.javascript_quote('thingy')
+ self.assertEqual(len(w), 1)
+ self.assertIn('escapejs()', repr(w[0].message))
View
0  tests/view_tests/app5/__init__.py
No changes.
View
BIN  tests/view_tests/app5/locale/fr/LC_MESSAGES/djangojs.mo
Binary file not shown
View
20 tests/view_tests/app5/locale/fr/LC_MESSAGES/djangojs.po
@@ -0,0 +1,20 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2007-09-15 19:15+0200\n"
+"PO-Revision-Date: 2010-05-12 12:41-0300\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+msgid "A nice emoji: 💩"
+msgstr "Un beau caractère emoji: 💩"
View
25 tests/view_tests/tests/test_i18n.py
@@ -1,5 +1,6 @@
# -*- coding:utf-8 -*-
import gettext
+import json
import os
from os import path
import unittest
@@ -11,7 +12,6 @@
from django.utils import six
from django.utils._os import upath
from django.utils.translation import override
-from django.utils.text import javascript_quote
try:
from selenium.webdriver.firefox import webdriver as firefox
@@ -63,8 +63,8 @@ def test_jsi18n(self):
response = self.client.get('/jsi18n/')
# response content must include a line like:
# "this is to be translated": <value of trans_txt Python variable>
- # javascript_quote is used to be able to check unicode strings
- self.assertContains(response, javascript_quote(trans_txt), 1)
+ # json.dumps() is used to be able to check unicode strings
+ self.assertContains(response, json.dumps(trans_txt), 1)
if lang_code == 'fr':
# Message with context (msgctxt)
self.assertContains(response, r'"month name\u0004May": "mai"', 1)
@@ -120,7 +120,7 @@ def test_nonenglish_default_english_userpref(self):
"""
with self.settings(LANGUAGE_CODE='fr'), override('en-us'):
response = self.client.get('/jsi18n_english_translation/')
- self.assertContains(response, javascript_quote('this app0 string is to be translated'))
+ self.assertContains(response, 'this app0 string is to be translated')
def testI18NLanguageNonEnglishFallback(self):
"""
@@ -136,6 +136,17 @@ def test_escaping(self):
response = self.client.get('/jsi18n_admin/?language=de')
self.assertContains(response, '\\x04')
+ @modify_settings(INSTALLED_APPS={'append': ['view_tests.app5']})
+ def test_non_BMP_char(self):
+ """
+ Non-BMP characters should not break the javascript_catalog (#21725).
+ """
+ with self.settings(LANGUAGE_CODE='en-us'), override('fr'):
+ response = self.client.get('/jsi18n/app5/')
+ self.assertEqual(response.status_code, 200)
+ self.assertContains(response, 'emoji')
+ self.assertContains(response, '\\ud83d\\udca9')
+
class JsI18NTestsMultiPackage(TestCase):
urls = 'view_tests.urls'
@@ -154,7 +165,7 @@ def testI18NLanguageEnglishDefault(self):
"""
with self.settings(LANGUAGE_CODE='en-us'), override('fr'):
response = self.client.get('/jsi18n_multi_packages1/')
- self.assertContains(response, javascript_quote('il faut traduire cette chaîne de caractères de app1'))
+ self.assertContains(response, 'il faut traduire cette cha\\u00eene de caract\\u00e8res de app1')
@modify_settings(INSTALLED_APPS={'append': ['view_tests.app3', 'view_tests.app4']})
def testI18NDifferentNonEnLangs(self):
@@ -164,7 +175,7 @@ def testI18NDifferentNonEnLangs(self):
"""
with self.settings(LANGUAGE_CODE='fr'), override('es-ar'):
response = self.client.get('/jsi18n_multi_packages2/')
- self.assertContains(response, javascript_quote('este texto de app3 debe ser traducido'))
+ self.assertContains(response, 'este texto de app3 debe ser traducido')
def testI18NWithLocalePaths(self):
extended_locale_paths = settings.LOCALE_PATHS + (
@@ -174,7 +185,7 @@ def testI18NWithLocalePaths(self):
with override('es-ar'):
response = self.client.get('/jsi18n/')
self.assertContains(response,
- javascript_quote('este texto de app3 debe ser traducido'))
+ 'este texto de app3 debe ser traducido')
skip_selenium = not os.environ.get('DJANGO_SELENIUM_TESTS', False)
View
6 tests/view_tests/urls.py
@@ -36,6 +36,11 @@
'packages': ('django.contrib.admin', 'view_tests'),
}
+js_info_dict_app5 = {
+ 'domain': 'djangojs',
+ 'packages': ('view_tests.app5',),
+}
+
urlpatterns = patterns('',
(r'^$', views.index_page),
@@ -54,6 +59,7 @@
# i18n views
(r'^i18n/', include('django.conf.urls.i18n')),
(r'^jsi18n/$', 'django.views.i18n.javascript_catalog', js_info_dict),
+ (r'^jsi18n/app5/$', 'django.views.i18n.javascript_catalog', js_info_dict_app5),
(r'^jsi18n_english_translation/$', 'django.views.i18n.javascript_catalog', js_info_dict_english_translation),
(r'^jsi18n_multi_packages1/$', 'django.views.i18n.javascript_catalog', js_info_dict_multi_packages1),
(r'^jsi18n_multi_packages2/$', 'django.views.i18n.javascript_catalog', js_info_dict_multi_packages2),
Something went wrong with that request. Please try again.