prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Category/Tag/Author slugs are not settable
  URLWrapper objects have a setter for their 'slug' property, but all of the concrete URLWrapper subclasses override the _getter_ for 'slug', which, because of the way Python's property accessors work, makes the setter inaccessible.  This breaks the 'category_meta' plugin and probably other things as well.
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `pelican/urlwrappers.py`
  Content:
  ```
  1 # -*- coding: utf-8 -*-
  2 from __future__ import unicode_literals
  3 
  4 import functools
  5 import logging
  6 import os
  7 
  8 import six
  9 
  10 from pelican.utils import python_2_unicode_compatible, slugify
  11 
  12 logger = logging.getLogger(__name__)
  13 
  14 
  15 @python_2_unicode_compatible
  16 @functools.total_ordering
  17 class URLWrapper(object):
  18     def __init__(self, name, settings):
  19         self.settings = settings
  20         self._name = name
  21         self._slug = None
  22         self._slug_from_name = True
  23 
  24     @property
  25     def name(self):
  26         return self._name
  27 
  28     @name.setter
  29     def name(self, name):
  30         self._name = name
  31         # if slug wasn't explicitly set, it needs to be regenerated from name
  32         # so, changing name should reset slug for slugification
  33         if self._slug_from_name:
  34             self._slug = None
  35 
  36     @property
  37     def slug(self):
  38         if self._slug is None:
  39             self._slug = slugify(
  40                 self.name,
  41                 regex_subs=self.settings.get('SLUG_REGEX_SUBSTITUTIONS', []))
  42         return self._slug
  43 
  44     @slug.setter
  45     def slug(self, slug):
  46         # if slug is expliticly set, changing name won't alter slug
  47         self._slug_from_name = False
  48         self._slug = slug
  49 
  50     def as_dict(self):
  51         d = self.__dict__
  52         d['name'] = self.name
  53         d['slug'] = self.slug
  54         return d
  55 
  56     def __hash__(self):
  57         return hash(self.slug)
  58 
  59     def _normalize_key(self, key):
  60         subs = self.settings.get('SLUG_REGEX_SUBSTITUTIONS', [])
  61         return six.text_type(slugify(key, regex_subs=subs))
  62 
  63     def __eq__(self, other):
  64         if isinstance(other, self.__class__):
  65             return self.slug == other.slug
  66         if isinstance(other, six.text_type):
  67             return self.slug == self._normalize_key(other)
  68         return False
  69 
  70     def __ne__(self, other):
  71         if isinstance(other, self.__class__):
  72             return self.slug != other.slug
  73         if isinstance(other, six.text_type):
  74             return self.slug != self._normalize_key(other)
  75         return True
  76 
  77     def __lt__(self, other):
  78         if isinstance(other, self.__class__):
  79             return self.slug < other.slug
  80         if isinstance(other, six.text_type):
  81             return self.slug < self._normalize_key(other)
  82         return False
  83 
  84     def __str__(self):
  85         return self.name
  86 
  87     def __repr__(self):
  88         return '<{} {}>'.format(type(self).__name__, repr(self._name))
  89 
  90     def _from_settings(self, key, get_page_name=False):
  91         """Returns URL information as defined in settings.
  92 
  93         When get_page_name=True returns URL without anything after {slug} e.g.
  94         if in settings: CATEGORY_URL="cat/{slug}.html" this returns
  95         "cat/{slug}" Useful for pagination.
  96 
  97         """
  98         setting = "%s_%s" % (self.__class__.__name__.upper(), key)
  99         value = self.settings[setting]
  100         if not isinstance(value, six.string_types):
  101             logger.warning('%s is set to %s', setting, value)
  102             return value
  103         else:
  104             if get_page_name:
  105                 return os.path.splitext(value)[0].format(**self.as_dict())
  106             else:
  107                 return value.format(**self.as_dict())
  108 
  109     page_name = property(functools.partial(_from_settings, key='URL',
  110                          get_page_name=True))
  111     url = property(functools.partial(_from_settings, key='URL'))
  112     save_as = property(functools.partial(_from_settings, key='SAVE_AS'))
  113 
  114 
  115 class Category(URLWrapper):
  116     @property
  117     def slug(self):
  118         if self._slug is None:
  119             if 'CATEGORY_REGEX_SUBSTITUTIONS' in self.settings:
  120                 subs = self.settings['CATEGORY_REGEX_SUBSTITUTIONS']
  121             else:
  122                 subs = self.settings.get('SLUG_REGEX_SUBSTITUTIONS', [])
  123             self._slug = slugify(self.name, regex_subs=subs)
  124         return self._slug
  125 
  126 
  127 class Tag(URLWrapper):
  128     def __init__(self, name, *args, **kwargs):
  129         super(Tag, self).__init__(name.strip(), *args, **kwargs)
  130 
  131     @property
  132     def slug(self):
  133         if self._slug is None:
  134             if 'TAG_REGEX_SUBSTITUTIONS' in self.settings:
  135                 subs = self.settings['TAG_REGEX_SUBSTITUTIONS']
  136             else:
  137                 subs = self.settings.get('SLUG_REGEX_SUBSTITUTIONS', [])
  138             self._slug = slugify(self.name, regex_subs=subs)
  139         return self._slug
  140 
  141 
  142 class Author(URLWrapper):
  143     @property
  144     def slug(self):
  145         if self._slug is None:
  146             if 'AUTHOR_REGEX_SUBSTITUTIONS' in self.settings:
  147                 subs = self.settings['AUTHOR_REGEX_SUBSTITUTIONS']
  148             else:
  149                 subs = self.settings.get('SLUG_REGEX_SUBSTITUTIONS', [])
  150             self._slug = slugify(self.name, regex_subs=subs)
  151         return self._slug
  152
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/pelican/urlwrappers.py b/pelican/urlwrappers.py
  --- a/pelican/urlwrappers.py
  +++ b/pelican/urlwrappers.py
  @@ -36,9 +36,17 @@
       @property
       def slug(self):
           if self._slug is None:
  -            self._slug = slugify(
  -                self.name,
  -                regex_subs=self.settings.get('SLUG_REGEX_SUBSTITUTIONS', []))
  +            class_key = '{}_REGEX_SUBSTITUTIONS'.format(
  +                self.__class__.__name__.upper())
  +            if class_key in self.settings:
  +                self._slug = slugify(
  +                    self.name,
  +                    regex_subs=self.settings[class_key])
  +            else:
  +                self._slug = slugify(
  +                    self.name,
  +                    regex_subs=self.settings.get(
  +                        'SLUG_REGEX_SUBSTITUTIONS', []))
           return self._slug
   
       @slug.setter
  @@ -113,39 +121,13 @@
   
   
   class Category(URLWrapper):
  -    @property
  -    def slug(self):
  -        if self._slug is None:
  -            if 'CATEGORY_REGEX_SUBSTITUTIONS' in self.settings:
  -                subs = self.settings['CATEGORY_REGEX_SUBSTITUTIONS']
  -            else:
  -                subs = self.settings.get('SLUG_REGEX_SUBSTITUTIONS', [])
  -            self._slug = slugify(self.name, regex_subs=subs)
  -        return self._slug
  +    pass
   
   
   class Tag(URLWrapper):
       def __init__(self, name, *args, **kwargs):
           super(Tag, self).__init__(name.strip(), *args, **kwargs)
   
  -    @property
  -    def slug(self):
  -        if self._slug is None:
  -            if 'TAG_REGEX_SUBSTITUTIONS' in self.settings:
  -                subs = self.settings['TAG_REGEX_SUBSTITUTIONS']
  -            else:
  -                subs = self.settings.get('SLUG_REGEX_SUBSTITUTIONS', [])
  -            self._slug = slugify(self.name, regex_subs=subs)
  -        return self._slug
  -
   
   class Author(URLWrapper):
  -    @property
  -    def slug(self):
  -        if self._slug is None:
  -            if 'AUTHOR_REGEX_SUBSTITUTIONS' in self.settings:
  -                subs = self.settings['AUTHOR_REGEX_SUBSTITUTIONS']
  -            else:
  -                subs = self.settings.get('SLUG_REGEX_SUBSTITUTIONS', [])
  -            self._slug = slugify(self.name, regex_subs=subs)
  -        return self._slug
  +    pass
  
verification_info: {"golden_diff": "diff --git a/pelican/urlwrappers.py b/pelican/urlwrappers.py\n--- a/pelican/urlwrappers.py\n+++ b/pelican/urlwrappers.py\n@@ -36,9 +36,17 @@\n     @property\n     def slug(self):\n         if self._slug is None:\n-            self._slug = slugify(\n-                self.name,\n-                regex_subs=self.settings.get('SLUG_REGEX_SUBSTITUTIONS', []))\n+            class_key = '{}_REGEX_SUBSTITUTIONS'.format(\n+                self.__class__.__name__.upper())\n+            if class_key in self.settings:\n+                self._slug = slugify(\n+                    self.name,\n+                    regex_subs=self.settings[class_key])\n+            else:\n+                self._slug = slugify(\n+                    self.name,\n+                    regex_subs=self.settings.get(\n+                        'SLUG_REGEX_SUBSTITUTIONS', []))\n         return self._slug\n \n     @slug.setter\n@@ -113,39 +121,13 @@\n \n \n class Category(URLWrapper):\n-    @property\n-    def slug(self):\n-        if self._slug is None:\n-            if 'CATEGORY_REGEX_SUBSTITUTIONS' in self.settings:\n-                subs = self.settings['CATEGORY_REGEX_SUBSTITUTIONS']\n-            else:\n-                subs = self.settings.get('SLUG_REGEX_SUBSTITUTIONS', [])\n-            self._slug = slugify(self.name, regex_subs=subs)\n-        return self._slug\n+    pass\n \n \n class Tag(URLWrapper):\n     def __init__(self, name, *args, **kwargs):\n         super(Tag, self).__init__(name.strip(), *args, **kwargs)\n \n-    @property\n-    def slug(self):\n-        if self._slug is None:\n-            if 'TAG_REGEX_SUBSTITUTIONS' in self.settings:\n-                subs = self.settings['TAG_REGEX_SUBSTITUTIONS']\n-            else:\n-                subs = self.settings.get('SLUG_REGEX_SUBSTITUTIONS', [])\n-            self._slug = slugify(self.name, regex_subs=subs)\n-        return self._slug\n-\n \n class Author(URLWrapper):\n-    @property\n-    def slug(self):\n-        if self._slug is None:\n-            if 'AUTHOR_REGEX_SUBSTITUTIONS' in self.settings:\n-                subs = self.settings['AUTHOR_REGEX_SUBSTITUTIONS']\n-            else:\n-                subs = self.settings.get('SLUG_REGEX_SUBSTITUTIONS', [])\n-            self._slug = slugify(self.name, regex_subs=subs)\n-        return self._slug\n+    pass\n", "issue": "Category/Tag/Author slugs are not settable\nURLWrapper objects have a setter for their 'slug' property, but all of the concrete URLWrapper subclasses override the _getter_ for 'slug', which, because of the way Python's property accessors work, makes the setter inaccessible.  This breaks the 'category_meta' plugin and probably other things as well.\n", "before_files": [{"content": "# -*- coding: utf-8 -*-\nfrom __future__ import unicode_literals\n\nimport functools\nimport logging\nimport os\n\nimport six\n\nfrom pelican.utils import python_2_unicode_compatible, slugify\n\nlogger = logging.getLogger(__name__)\n\n\n@python_2_unicode_compatible\n@functools.total_ordering\nclass URLWrapper(object):\n    def __init__(self, name, settings):\n        self.settings = settings\n        self._name = name\n        self._slug = None\n        self._slug_from_name = True\n\n    @property\n    def name(self):\n        return self._name\n\n    @name.setter\n    def name(self, name):\n        self._name = name\n        # if slug wasn't explicitly set, it needs to be regenerated from name\n        # so, changing name should reset slug for slugification\n        if self._slug_from_name:\n            self._slug = None\n\n    @property\n    def slug(self):\n        if self._slug is None:\n            self._slug = slugify(\n                self.name,\n                regex_subs=self.settings.get('SLUG_REGEX_SUBSTITUTIONS', []))\n        return self._slug\n\n    @slug.setter\n    def slug(self, slug):\n        # if slug is expliticly set, changing name won't alter slug\n        self._slug_from_name = False\n        self._slug = slug\n\n    def as_dict(self):\n        d = self.__dict__\n        d['name'] = self.name\n        d['slug'] = self.slug\n        return d\n\n    def __hash__(self):\n        return hash(self.slug)\n\n    def _normalize_key(self, key):\n        subs = self.settings.get('SLUG_REGEX_SUBSTITUTIONS', [])\n        return six.text_type(slugify(key, regex_subs=subs))\n\n    def __eq__(self, other):\n        if isinstance(other, self.__class__):\n            return self.slug == other.slug\n        if isinstance(other, six.text_type):\n            return self.slug == self._normalize_key(other)\n        return False\n\n    def __ne__(self, other):\n        if isinstance(other, self.__class__):\n            return self.slug != other.slug\n        if isinstance(other, six.text_type):\n            return self.slug != self._normalize_key(other)\n        return True\n\n    def __lt__(self, other):\n        if isinstance(other, self.__class__):\n            return self.slug < other.slug\n        if isinstance(other, six.text_type):\n            return self.slug < self._normalize_key(other)\n        return False\n\n    def __str__(self):\n        return self.name\n\n    def __repr__(self):\n        return '<{} {}>'.format(type(self).__name__, repr(self._name))\n\n    def _from_settings(self, key, get_page_name=False):\n        \"\"\"Returns URL information as defined in settings.\n\n        When get_page_name=True returns URL without anything after {slug} e.g.\n        if in settings: CATEGORY_URL=\"cat/{slug}.html\" this returns\n        \"cat/{slug}\" Useful for pagination.\n\n        \"\"\"\n        setting = \"%s_%s\" % (self.__class__.__name__.upper(), key)\n        value = self.settings[setting]\n        if not isinstance(value, six.string_types):\n            logger.warning('%s is set to %s', setting, value)\n            return value\n        else:\n            if get_page_name:\n                return os.path.splitext(value)[0].format(**self.as_dict())\n            else:\n                return value.format(**self.as_dict())\n\n    page_name = property(functools.partial(_from_settings, key='URL',\n                         get_page_name=True))\n    url = property(functools.partial(_from_settings, key='URL'))\n    save_as = property(functools.partial(_from_settings, key='SAVE_AS'))\n\n\nclass Category(URLWrapper):\n    @property\n    def slug(self):\n        if self._slug is None:\n            if 'CATEGORY_REGEX_SUBSTITUTIONS' in self.settings:\n                subs = self.settings['CATEGORY_REGEX_SUBSTITUTIONS']\n            else:\n                subs = self.settings.get('SLUG_REGEX_SUBSTITUTIONS', [])\n            self._slug = slugify(self.name, regex_subs=subs)\n        return self._slug\n\n\nclass Tag(URLWrapper):\n    def __init__(self, name, *args, **kwargs):\n        super(Tag, self).__init__(name.strip(), *args, **kwargs)\n\n    @property\n    def slug(self):\n        if self._slug is None:\n            if 'TAG_REGEX_SUBSTITUTIONS' in self.settings:\n                subs = self.settings['TAG_REGEX_SUBSTITUTIONS']\n            else:\n                subs = self.settings.get('SLUG_REGEX_SUBSTITUTIONS', [])\n            self._slug = slugify(self.name, regex_subs=subs)\n        return self._slug\n\n\nclass Author(URLWrapper):\n    @property\n    def slug(self):\n        if self._slug is None:\n            if 'AUTHOR_REGEX_SUBSTITUTIONS' in self.settings:\n                subs = self.settings['AUTHOR_REGEX_SUBSTITUTIONS']\n            else:\n                subs = self.settings.get('SLUG_REGEX_SUBSTITUTIONS', [])\n            self._slug = slugify(self.name, regex_subs=subs)\n        return self._slug\n", "path": "pelican/urlwrappers.py"}], "after_files": [{"content": "# -*- coding: utf-8 -*-\nfrom __future__ import unicode_literals\n\nimport functools\nimport logging\nimport os\n\nimport six\n\nfrom pelican.utils import python_2_unicode_compatible, slugify\n\nlogger = logging.getLogger(__name__)\n\n\n@python_2_unicode_compatible\n@functools.total_ordering\nclass URLWrapper(object):\n    def __init__(self, name, settings):\n        self.settings = settings\n        self._name = name\n        self._slug = None\n        self._slug_from_name = True\n\n    @property\n    def name(self):\n        return self._name\n\n    @name.setter\n    def name(self, name):\n        self._name = name\n        # if slug wasn't explicitly set, it needs to be regenerated from name\n        # so, changing name should reset slug for slugification\n        if self._slug_from_name:\n            self._slug = None\n\n    @property\n    def slug(self):\n        if self._slug is None:\n            class_key = '{}_REGEX_SUBSTITUTIONS'.format(\n                self.__class__.__name__.upper())\n            if class_key in self.settings:\n                self._slug = slugify(\n                    self.name,\n                    regex_subs=self.settings[class_key])\n            else:\n                self._slug = slugify(\n                    self.name,\n                    regex_subs=self.settings.get(\n                        'SLUG_REGEX_SUBSTITUTIONS', []))\n        return self._slug\n\n    @slug.setter\n    def slug(self, slug):\n        # if slug is expliticly set, changing name won't alter slug\n        self._slug_from_name = False\n        self._slug = slug\n\n    def as_dict(self):\n        d = self.__dict__\n        d['name'] = self.name\n        d['slug'] = self.slug\n        return d\n\n    def __hash__(self):\n        return hash(self.slug)\n\n    def _normalize_key(self, key):\n        subs = self.settings.get('SLUG_REGEX_SUBSTITUTIONS', [])\n        return six.text_type(slugify(key, regex_subs=subs))\n\n    def __eq__(self, other):\n        if isinstance(other, self.__class__):\n            return self.slug == other.slug\n        if isinstance(other, six.text_type):\n            return self.slug == self._normalize_key(other)\n        return False\n\n    def __ne__(self, other):\n        if isinstance(other, self.__class__):\n            return self.slug != other.slug\n        if isinstance(other, six.text_type):\n            return self.slug != self._normalize_key(other)\n        return True\n\n    def __lt__(self, other):\n        if isinstance(other, self.__class__):\n            return self.slug < other.slug\n        if isinstance(other, six.text_type):\n            return self.slug < self._normalize_key(other)\n        return False\n\n    def __str__(self):\n        return self.name\n\n    def __repr__(self):\n        return '<{} {}>'.format(type(self).__name__, repr(self._name))\n\n    def _from_settings(self, key, get_page_name=False):\n        \"\"\"Returns URL information as defined in settings.\n\n        When get_page_name=True returns URL without anything after {slug} e.g.\n        if in settings: CATEGORY_URL=\"cat/{slug}.html\" this returns\n        \"cat/{slug}\" Useful for pagination.\n\n        \"\"\"\n        setting = \"%s_%s\" % (self.__class__.__name__.upper(), key)\n        value = self.settings[setting]\n        if not isinstance(value, six.string_types):\n            logger.warning('%s is set to %s', setting, value)\n            return value\n        else:\n            if get_page_name:\n                return os.path.splitext(value)[0].format(**self.as_dict())\n            else:\n                return value.format(**self.as_dict())\n\n    page_name = property(functools.partial(_from_settings, key='URL',\n                         get_page_name=True))\n    url = property(functools.partial(_from_settings, key='URL'))\n    save_as = property(functools.partial(_from_settings, key='SAVE_AS'))\n\n\nclass Category(URLWrapper):\n    pass\n\n\nclass Tag(URLWrapper):\n    def __init__(self, name, *args, **kwargs):\n        super(Tag, self).__init__(name.strip(), *args, **kwargs)\n\n\nclass Author(URLWrapper):\n    pass\n", "path": "pelican/urlwrappers.py"}]}