Skip to content

Commit 514bfc3

Browse files
committed
Use unicode-slugify to generate Version.slug
1 parent 05cc76b commit 514bfc3

File tree

3 files changed

+50
-8
lines changed

3 files changed

+50
-8
lines changed

readthedocs/builds/version_slug.py

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626

2727
from django.db import models
2828
from django.utils.encoding import force_text
29+
from slugify import slugify
2930

3031

3132
def get_fields_with_model(cls):
@@ -53,13 +54,15 @@ def get_fields_with_model(cls):
5354

5455
class VersionSlugField(models.CharField):
5556

56-
"""Inspired by ``django_extensions.db.fields.AutoSlugField``."""
57+
"""
58+
Inspired by ``django_extensions.db.fields.AutoSlugField``.
5759
58-
invalid_chars_re = re.compile('[^-._a-z0-9]')
59-
leading_punctuation_re = re.compile('^[-._]+')
60-
placeholder = '-'
61-
fallback_slug = 'unknown'
60+
Uses ``unicode-slugify`` to generate the slug.
61+
"""
62+
63+
ok_chars = '-._' # dash, dot, underscore
6264
test_pattern = re.compile('^{pattern}$'.format(pattern=VERSION_SLUG_REGEX))
65+
fallback_slug = 'unknown'
6366

6467
def __init__(self, *args, **kwargs):
6568
kwargs.setdefault('db_index', True)
@@ -78,13 +81,37 @@ def get_queryset(self, model_cls, slug_field):
7881
return model._default_manager.all()
7982
return model_cls._default_manager.all()
8083

84+
def _normalize(self, content):
85+
"""
86+
Normalize some invalid characters to become a dash (``-``).
87+
88+
For example, ``release/1.0`` will become ``release-1.0``.
89+
"""
90+
return re.sub('[/%!?]', '-', content)
91+
8192
def slugify(self, content):
93+
"""
94+
Make ``content`` a valid slug.
95+
96+
It uses ``unicode-slugify`` behind the scenes which works properly with
97+
Unicode characters.
98+
"""
8299
if not content:
83100
return ''
84101

85-
slugified = content.lower()
86-
slugified = self.invalid_chars_re.sub(self.placeholder, slugified)
87-
slugified = self.leading_punctuation_re.sub('', slugified)
102+
normalized = self._normalize(content)
103+
slugified = slugify(
104+
normalized,
105+
only_ascii=True,
106+
spaces=False,
107+
lower=True,
108+
ok=self.ok_chars,
109+
space_replacement='-',
110+
)
111+
112+
# Remove first character wile it's an invalid character for the
113+
# beginning of the slug
114+
slugified = slugified.lstrip(self.ok_chars)
88115

89116
if not slugified:
90117
return self.fallback_slug

readthedocs/rtd_tests/tests/test_version_slug.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,3 +105,15 @@ def test_uniquifying_suffix(self):
105105
self.assertEqual(field.uniquifying_suffix(25), '_z')
106106
self.assertEqual(field.uniquifying_suffix(26), '_ba')
107107
self.assertEqual(field.uniquifying_suffix(52), '_ca')
108+
109+
def test_unicode(self):
110+
version = Version.objects.create(
111+
verbose_name='camión',
112+
project=self.pip,
113+
)
114+
self.assertEqual(version.slug, 'camion')
115+
version = Version.objects.create(
116+
verbose_name='ŭñíč°də-branch',
117+
project=self.pip,
118+
)
119+
self.assertEqual(version.slug, 'unicd-branch')

requirements/pip.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,9 @@ django-kombu==0.9.4
7070
mock==2.0.0
7171
stripe==2.18.0
7272

73+
# unicode-slugify==0.1.5 is not released on PyPI yet
74+
git+https://github.com/mozilla/unicode-slugify@b696c37#egg=unicode-slugify
75+
7376
django-formtools==2.1
7477

7578
# docker is pinned to 3.1.3 because we found some strange behavior

0 commit comments

Comments
 (0)