diff --git a/gluon/contrib/markmin/markmin2html.py b/gluon/contrib/markmin/markmin2html.py
index 45f78dd1..51622ce7 100755
--- a/gluon/contrib/markmin/markmin2html.py
+++ b/gluon/contrib/markmin/markmin2html.py
@@ -7,7 +7,7 @@ from __future__ import print_function
import re
import urllib
from pydal._compat import maketrans, urllib_quote, unicodeT, to_bytes, to_native, xrange
-from gluon.local_html_escape import local_html_escape as escape
+from pydal.utils import local_html_escape as escape
from ast import parse as ast_parse
import ast
diff --git a/gluon/highlight.py b/gluon/highlight.py
index 91b4fa78..97b77990 100644
--- a/gluon/highlight.py
+++ b/gluon/highlight.py
@@ -8,7 +8,7 @@
"""
from __future__ import print_function
from pydal._compat import xrange
-from gluon.local_html_escape import local_html_escape
+from pydal.utils import local_html_escape
import re
__all__ = ['highlight']
diff --git a/gluon/html.py b/gluon/html.py
index db3a7c15..bd693406 100644
--- a/gluon/html.py
+++ b/gluon/html.py
@@ -21,7 +21,7 @@ import base64
from gluon import sanitizer, decoder
import itertools
from pydal._compat import reduce, pickle, copyreg, HTMLParser, name2codepoint, iteritems, unichr, unicodeT, urllib_quote, to_bytes, to_native, to_unicode, basestring, urlencode, implements_bool
-from gluon.local_html_escape import local_html_escape
+from pydal.utils import local_html_escape
import marshal
from gluon.storage import Storage
diff --git a/gluon/languages.py b/gluon/languages.py
index 0daf475d..88e659a6 100644
--- a/gluon/languages.py
+++ b/gluon/languages.py
@@ -19,7 +19,7 @@ import logging
from cgi import escape
from threading import RLock
from gluon.utf8 import Utf8
-from gluon.local_html_escape import local_html_escape
+from pydal.utils import local_html_escape
from pydal._compat import copyreg, PY2, maketrans, iterkeys, unicodeT, to_unicode, to_bytes, iteritems, to_native, pjoin
from pydal.contrib.portalocker import read_locked, LockedFile
diff --git a/gluon/local_html_escape.py b/gluon/local_html_escape.py
deleted file mode 100644
index a4345eef..00000000
--- a/gluon/local_html_escape.py
+++ /dev/null
@@ -1,27 +0,0 @@
-import sys
-
-PY2 = sys.version_info[0] == 2
-
-def local_html_escape(data, quote=False):
- """
- Works with bytes.
- Replace special characters "&", "<" and ">" to HTML-safe sequences.
- If the optional flag quote is true (the default), the quotation mark
- characters, both double quote (") and single quote (') characters are also
- translated.
- """
- if PY2:
- import cgi
- s = cgi.escape(data, quote)
- return s.replace("'", "'") if quote else s
- else:
- import html
- if isinstance(s, str):
- return html.escape(s, quote=quote)
- s = s.replace(b"&", b"&") # Must be done first!
- s = s.replace(b"<", b"<")
- s = s.replace(b">", b">")
- if quote:
- s = s.replace(b'"', b""")
- s = s.replace(b'\'', b"'")
- return s
diff --git a/gluon/utils.py b/gluon/utils.py
index 5e611b9c..22e3cef4 100644
--- a/gluon/utils.py
+++ b/gluon/utils.py
@@ -359,3 +359,28 @@ def getipaddrinfo(host):
and isinstance(addrinfo[4][0], basestring)]
except socket.error:
return []
+
+
+def local_html_escape(data, quote=False):
+ """
+ Works with bytes.
+ Replace special characters "&", "<" and ">" to HTML-safe sequences.
+ If the optional flag quote is true (the default), the quotation mark
+ characters, both double quote (") and single quote (') characters are also
+ translated.
+ """
+ if PY2:
+ import cgi
+ s = cgi.escape(data, quote)
+ return s.replace("'", "'") if quote else s
+ else:
+ import html
+ if isinstance(s, str):
+ return html.escape(s, quote=quote)
+ s = s.replace(b"&", b"&") # Must be done first!
+ s = s.replace(b"<", b"<")
+ s = s.replace(b">", b">")
+ if quote:
+ s = s.replace(b'"', b""")
+ s = s.replace(b'\'', b"'")
+ return s