Repository: getpelican/pelican

Issue:
improve URLWrappers comparision
current URLWrappers slugify a lot, resulting in a lot of processing time lost ( #1493 ).

we need to check if we can avoid the always occurring slugify call (which is wrong anyway) and speed up comparisions to other URLWrappers via:

source: @avaris 

```
try: 
  return other.slug
except AttributeError:
  return slugify(blabla)                                       
```

and maybe to strings as well as those comparisons are often done in themes  `{% if cat == "bla" %}`



Discussion:

Resolving patch:
diff --git a/pelican/contents.py b/pelican/contents.py
--- a/pelican/contents.py
+++ b/pelican/contents.py
@@ -25,6 +25,7 @@
 logger = logging.getLogger(__name__)
 
 
+@python_2_unicode_compatible
 class Content(object):
     """Represents a content.
 
@@ -148,12 +149,7 @@ def __init__(self, content, metadata=None, settings=None,
         signals.content_object_init.send(self)
 
     def __str__(self):
-        if self.source_path is None:
-            return repr(self)
-        elif six.PY3:
-            return self.source_path or repr(self)
-        else:
-            return str(self.source_path.encode('utf-8', 'replace'))
+        return self.source_path or repr(self)
 
     def check_properties(self):
         """Test mandatory properties are set."""
diff --git a/pelican/urlwrappers.py b/pelican/urlwrappers.py
--- a/pelican/urlwrappers.py
+++ b/pelican/urlwrappers.py
@@ -1,7 +1,9 @@
-import os
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
 import functools
 import logging
-
+import os
 import six
 
 from pelican.utils import (slugify, python_2_unicode_compatible)
@@ -52,27 +54,36 @@ def as_dict(self):
     def __hash__(self):
         return hash(self.slug)
 
-    def _key(self):
-        return self.slug
-
     def _normalize_key(self, key):
         subs = self.settings.get('SLUG_SUBSTITUTIONS', ())
         return six.text_type(slugify(key, subs))
 
     def __eq__(self, other):
-        return self._key() == self._normalize_key(other)
+        if isinstance(other, self.__class__):
+            return self.slug == other.slug
+        if isinstance(other, six.text_type):
+            return self.slug == self._normalize_key(other)
+        return False
 
     def __ne__(self, other):
-        return self._key() != self._normalize_key(other)
+        if isinstance(other, self.__class__):
+            return self.slug != other.slug
+        if isinstance(other, six.text_type):
+            return self.slug != self._normalize_key(other)
+        return True
 
     def __lt__(self, other):
-        return self._key() < self._normalize_key(other)
+        if isinstance(other, self.__class__):
+            return self.slug < other.slug
+        if isinstance(other, six.text_type):
+            return self.slug < self._normalize_key(other)
+        return False
 
     def __str__(self):
         return self.name
 
     def __repr__(self):
-        return '<{} {}>'.format(type(self).__name__, str(self))
+        return '<{} {}>'.format(type(self).__name__, repr(self._name))
 
     def _from_settings(self, key, get_page_name=False):
         """Returns URL information as defined in settings.


Test patch:
diff --git a/pelican/tests/test_contents.py b/pelican/tests/test_contents.py
--- a/pelican/tests/test_contents.py
+++ b/pelican/tests/test_contents.py
@@ -578,30 +578,3 @@ def test_category_link_syntax(self):
         content = page.get_content('')
 
         self.assertNotEqual(content, html)
-
-
-class TestURLWrapper(unittest.TestCase):
-    def test_comparisons(self):
-        # URLWrappers are sorted by name
-        wrapper_a = URLWrapper(name='first', settings={})
-        wrapper_b = URLWrapper(name='last', settings={})
-        self.assertFalse(wrapper_a > wrapper_b)
-        self.assertFalse(wrapper_a >= wrapper_b)
-        self.assertFalse(wrapper_a == wrapper_b)
-        self.assertTrue(wrapper_a != wrapper_b)
-        self.assertTrue(wrapper_a <= wrapper_b)
-        self.assertTrue(wrapper_a < wrapper_b)
-        wrapper_b.name = 'first'
-        self.assertFalse(wrapper_a > wrapper_b)
-        self.assertTrue(wrapper_a >= wrapper_b)
-        self.assertTrue(wrapper_a == wrapper_b)
-        self.assertFalse(wrapper_a != wrapper_b)
-        self.assertTrue(wrapper_a <= wrapper_b)
-        self.assertFalse(wrapper_a < wrapper_b)
-        wrapper_a.name = 'last'
-        self.assertTrue(wrapper_a > wrapper_b)
-        self.assertTrue(wrapper_a >= wrapper_b)
-        self.assertFalse(wrapper_a == wrapper_b)
-        self.assertTrue(wrapper_a != wrapper_b)
-        self.assertFalse(wrapper_a <= wrapper_b)
-        self.assertFalse(wrapper_a < wrapper_b)
diff --git a/pelican/tests/test_readers.py b/pelican/tests/test_readers.py
--- a/pelican/tests/test_readers.py
+++ b/pelican/tests/test_readers.py
@@ -29,12 +29,10 @@ def assertDictHasSubset(self, dictionary, subset):
                 self.assertEqual(
                     value,
                     real_value,
-                    str('Expected %r to have value %r, but was %r')
-                        % (key, value, real_value))
+                    'Expected %s to have value %s, but was %s' % (key, value, real_value))
             else:
                 self.fail(
-                    str('Expected %r to have value %r, but was not in Dict')
-                        % (key, value))
+                   'Expected %s to have value %s, but was not in Dict' % (key, value))
 
 class TestAssertDictHasSubset(ReaderTest):
     def setUp(self):
@@ -566,9 +564,12 @@ def test_article_with_null_attributes(self):
     def test_article_metadata_key_lowercase(self):
         # Keys of metadata should be lowercase.
         page = self.read_file(path='article_with_uppercase_metadata.html')
+
+        # Key should be lowercase
         self.assertIn('category', page.metadata, 'Key should be lowercase.')
-        self.assertEqual('Yeah', page.metadata.get('category'),
-                         'Value keeps cases.')
+
+        # Value should keep cases
+        self.assertEqual('Yeah', page.metadata.get('category'))
 
     def test_article_with_nonconformant_meta_tags(self):
         page = self.read_file(path='article_with_nonconformant_meta_tags.html')
diff --git a/pelican/tests/test_urlwrappers.py b/pelican/tests/test_urlwrappers.py
new file mode 100644
--- /dev/null
+++ b/pelican/tests/test_urlwrappers.py
@@ -0,0 +1,51 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from pelican.urlwrappers import URLWrapper, Tag, Category
+from pelican.tests.support import unittest
+
+class TestURLWrapper(unittest.TestCase):
+    def test_ordering(self):
+        # URLWrappers are sorted by name
+        wrapper_a = URLWrapper(name='first', settings={})
+        wrapper_b = URLWrapper(name='last', settings={})
+        self.assertFalse(wrapper_a > wrapper_b)
+        self.assertFalse(wrapper_a >= wrapper_b)
+        self.assertFalse(wrapper_a == wrapper_b)
+        self.assertTrue(wrapper_a != wrapper_b)
+        self.assertTrue(wrapper_a <= wrapper_b)
+        self.assertTrue(wrapper_a < wrapper_b)
+        wrapper_b.name = 'first'
+        self.assertFalse(wrapper_a > wrapper_b)
+        self.assertTrue(wrapper_a >= wrapper_b)
+        self.assertTrue(wrapper_a == wrapper_b)
+        self.assertFalse(wrapper_a != wrapper_b)
+        self.assertTrue(wrapper_a <= wrapper_b)
+        self.assertFalse(wrapper_a < wrapper_b)
+        wrapper_a.name = 'last'
+        self.assertTrue(wrapper_a > wrapper_b)
+        self.assertTrue(wrapper_a >= wrapper_b)
+        self.assertFalse(wrapper_a == wrapper_b)
+        self.assertTrue(wrapper_a != wrapper_b)
+        self.assertFalse(wrapper_a <= wrapper_b)
+        self.assertFalse(wrapper_a < wrapper_b)
+
+    def test_equality(self):
+        tag = Tag('test', settings={})
+        cat = Category('test', settings={})
+
+        # same name, but different class
+        self.assertNotEqual(tag, cat)
+
+        # should be equal vs text representing the same name
+        self.assertEqual(tag, u'test')
+
+        # should not be equal vs binary
+        self.assertNotEqual(tag, b'test')
+
+        # Tags describing the same should be equal
+        tag_equal = Tag('Test', settings={})
+        self.assertEqual(tag, tag_equal)
+
+        cat_ascii = Category('指導書', settings={})
+        self.assertEqual(cat_ascii, u'zhi-dao-shu')