summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlessio Ababilov <aababilov@griddynamics.com>2013-06-10 10:49:59 +0300
committerAlessio Ababilov <ilovegnulinux@gmail.com>2013-06-11 20:05:49 +0300
commit472d8ed162ffc0b1083b761627a8ed86e7d71ae7 (patch)
treee7c23277b4d5d44dcb4d799c6af815a9214d0345
parentfaddbbe318cf62791624469c4304ae4fdcc2e639 (diff)
downloadoslo-472d8ed162ffc0b1083b761627a8ed86e7d71ae7.tar.gz
oslo-472d8ed162ffc0b1083b761627a8ed86e7d71ae7.tar.xz
oslo-472d8ed162ffc0b1083b761627a8ed86e7d71ae7.zip
Add slugify to strutils
This function will be used in apiclient library. Change-Id: I19f976eda896e7bede07510aafebe4931e512351
-rw-r--r--openstack/common/strutils.py30
-rw-r--r--tests/unit/test_strutils.py15
2 files changed, 45 insertions, 0 deletions
diff --git a/openstack/common/strutils.py b/openstack/common/strutils.py
index 8a5367b..87a9f24 100644
--- a/openstack/common/strutils.py
+++ b/openstack/common/strutils.py
@@ -19,7 +19,9 @@
System-level utilities and helper functions.
"""
+import re
import sys
+import unicodedata
from openstack.common.gettextutils import _
@@ -38,6 +40,9 @@ BYTE_MULTIPLIERS = {
TRUE_STRINGS = ('1', 't', 'true', 'on', 'y', 'yes')
FALSE_STRINGS = ('0', 'f', 'false', 'off', 'n', 'no')
+SLUGIFY_STRIP_RE = re.compile(r"[^\w\s-]")
+SLUGIFY_HYPHENATE_RE = re.compile(r"[-\s]+")
+
def int_from_bool_as_string(subject):
"""
@@ -187,3 +192,28 @@ def to_bytes(text, default=0):
raise TypeError(msg)
except ValueError:
return default
+
+
+def to_slug(value, incoming=None, errors="strict"):
+ """Normalize string.
+
+ Convert to lowercase, remove non-word characters, and convert spaces
+ to hyphens.
+
+ Inspired by Django's `slugify` filter.
+
+ :param value: Text to slugify
+ :param incoming: Text's current encoding
+ :param errors: Errors handling policy. See here for valid
+ values http://docs.python.org/2/library/codecs.html
+ :returns: slugified unicode representation of `value`
+ :raises TypeError: If text is not an instance of basestring
+ """
+ value = safe_decode(value, incoming, errors)
+ # NOTE(aababilov): no need to use safe_(encode|decode) here:
+ # encodings are always "ascii", error handling is always "ignore"
+ # and types are always known (first: unicode; second: str)
+ value = unicodedata.normalize("NFKD", value).encode(
+ "ascii", "ignore").decode("ascii")
+ value = SLUGIFY_STRIP_RE.sub("", value).strip().lower()
+ return SLUGIFY_HYPHENATE_RE.sub("-", value)
diff --git a/tests/unit/test_strutils.py b/tests/unit/test_strutils.py
index 42160a6..a8d8462 100644
--- a/tests/unit/test_strutils.py
+++ b/tests/unit/test_strutils.py
@@ -198,3 +198,18 @@ class StrUtilsTest(utils.BaseTestCase):
]
for v in breaking_examples:
self.assertRaises(TypeError, strutils.to_bytes, v)
+
+ def test_slugify(self):
+ to_slug = strutils.to_slug
+ self.assertRaises(TypeError, to_slug, True)
+ self.assertEqual(six.u("hello"), to_slug("hello"))
+ self.assertEqual(six.u("two-words"), to_slug("Two Words"))
+ self.assertEqual(six.u("ma-any-spa-ce-es"),
+ to_slug("Ma-any\t spa--ce- es"))
+ self.assertEqual(six.u("excamation"), to_slug("exc!amation!"))
+ self.assertEqual(six.u("ampserand"), to_slug("&ampser$and"))
+ self.assertEqual(six.u("ju5tnum8er"), to_slug("ju5tnum8er"))
+ self.assertEqual(six.u("strip-"), to_slug(" strip - "))
+ self.assertEqual(six.u("perche"), to_slug("perch\xc3\xa9"))
+ self.assertEqual(six.u("strange"),
+ to_slug("\x80strange", errors="ignore"))