Repository: getpelican/pelican

Issue:
preserve_case option for category names slugification (fix #2248)



Discussion:
I have amended the commit message just to restart a completly failing Travis run. Lose time because of this shit (false error messages) 2 times on 3 PR, it's a shame.
I haven't looked further, but what happens when a set of case sensitive categories hits a case insensitive file system?
Although I haven't done tests, I think it changes nothing from a case insensitive file system point of view.
Thoughts on this PR from @getpelican/reviewers? (especially @avaris)
It'd be nice to add a test or two.
@fgallaire: Would you mind adding some corresponding tests? 😊
@justinmayer The tests are run with preserve_case enabled as it will be the default option. Do you want more ?
@fgallaire I meant just a couple basic tests for `slugify` to directly test that option. Something like:
```python
slugify('Foo') == 'foo'
slugify('Foo', preserve_case=False) == 'foo'
slugify('Foo', preserve_case=True) == 'Foo'
```
in [here](https://github.com/getpelican/pelican/blob/master/pelican/tests/test_utils.py#L123)
@fgallaire: Would you mind adding a few tests as @avaris suggested so we can merge your contribution?
Hi @fgallaire. Any chance you could add the tests @avaris mentioned so we can merge your pull request?

Resolving patch:
diff --git a/pelican/tools/pelican_import.py b/pelican/tools/pelican_import.py
--- a/pelican/tools/pelican_import.py
+++ b/pelican/tools/pelican_import.py
@@ -634,7 +634,8 @@ def get_out_filename(output_path, filename, ext, kind,
             typename = ''
             kind = 'article'
         if dircat and (len(categories) > 0):
-            catname = slugify(categories[0], regex_subs=slug_subs)
+            catname = slugify(
+                categories[0], regex_subs=slug_subs, preserve_case=True)
         else:
             catname = ''
         out_filename = os.path.join(output_path, typename,
@@ -643,7 +644,8 @@ def get_out_filename(output_path, filename, ext, kind,
             os.makedirs(os.path.join(output_path, typename, catname))
     # option to put files in directories with categories names
     elif dircat and (len(categories) > 0):
-        catname = slugify(categories[0], regex_subs=slug_subs)
+        catname = slugify(
+            categories[0], regex_subs=slug_subs, preserve_case=True)
         out_filename = os.path.join(output_path, catname, filename + ext)
         if not os.path.isdir(os.path.join(output_path, catname)):
             os.mkdir(os.path.join(output_path, catname))
diff --git a/pelican/utils.py b/pelican/utils.py
--- a/pelican/utils.py
+++ b/pelican/utils.py
@@ -222,7 +222,7 @@ def pelican_open(filename, mode='r', strip_crs=(sys.platform == 'win32')):
     yield content
 
 
-def slugify(value, regex_subs=()):
+def slugify(value, regex_subs=(), preserve_case=False):
     """
     Normalizes string, converts to lowercase, removes non-alpha characters,
     and converts spaces to hyphens.
@@ -245,7 +245,8 @@ def slugify(value, regex_subs=()):
         value = re.sub(src, dst, value, flags=re.IGNORECASE)
 
     # convert to lowercase
-    value = value.lower()
+    if not preserve_case:
+        value = value.lower()
 
     # we want only ASCII chars
     value = value.encode('ascii', 'ignore').strip()


Test patch:
diff --git a/pelican/tests/test_importer.py b/pelican/tests/test_importer.py
--- a/pelican/tests/test_importer.py
+++ b/pelican/tests/test_importer.py
@@ -1,4 +1,4 @@
-﻿# -*- coding: utf-8 -*-
+# -*- coding: utf-8 -*-
 
 import locale
 import os
@@ -138,7 +138,7 @@ def test_dircat(self):
         index = 0
         for post in test_posts:
             name = post[2]
-            category = slugify(post[5][0], regex_subs=subs)
+            category = slugify(post[5][0], regex_subs=subs, preserve_case=True)
             name += '.md'
             filename = os.path.join(category, name)
             out_name = fnames[index]
@@ -215,7 +215,7 @@ def test_custom_posts_put_in_own_dir_and_catagory_sub_dir(self):
         for post in test_posts:
             name = post[2]
             kind = post[8]
-            category = slugify(post[5][0], regex_subs=subs)
+            category = slugify(post[5][0], regex_subs=subs, preserve_case=True)
             name += '.md'
             filename = os.path.join(kind, category, name)
             out_name = fnames[index]
diff --git a/pelican/tests/test_utils.py b/pelican/tests/test_utils.py
--- a/pelican/tests/test_utils.py
+++ b/pelican/tests/test_utils.py
@@ -122,6 +122,12 @@ def test_slugify(self):
         for value, expected in samples:
             self.assertEqual(utils.slugify(value, regex_subs=subs), expected)
 
+        self.assertEqual(utils.slugify('Cat', regex_subs=subs), 'cat')
+        self.assertEqual(
+            utils.slugify('Cat', regex_subs=subs, preserve_case=False), 'cat')
+        self.assertEqual(
+            utils.slugify('Cat', regex_subs=subs, preserve_case=True), 'Cat')
+
     def test_slugify_substitute(self):
 
         samples = (('C++ is based on C', 'cpp-is-based-on-c'),