We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Internal content link doesn't work on video.poster
I'm using pelican 3.3.0, with python 2.7.5.

The [internal content link](http://docs.getpelican.com/en/3.3.0/getting_started.html#linking-to-internal-content) feature is very useful that I don't need to determine where attachment files will be placed after site generation. But recently I find that this feature has no effect on poster property of a video tag.

For example, I wrote this in my post.md:

``` html
<video controls poster="{filename}/images/2011/07/poster.jpg">
  <source src="{filename}/assets/2011/07/video.mp4" type="video/mp4">
</video>
```

After generation, I got this html code in my page:

``` html
<video controls poster="{filename}/images/2011/07/poster.jpg">
  <source src="/assets/2011/07/video.mp4" type="video/mp4">
</video>
```

As you can see, the `{filename}` still there, it should be replace to an empty string in this case.


--- 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/contents.py`
Content:
```
1 # -*- coding: utf-8 -*-
2 from __future__ import unicode_literals, print_function
3 import six
4 
5 import copy
6 import locale
7 import logging
8 import functools
9 import os
10 import re
11 import sys
12 
13 try:
14     from urlparse import urlparse, urlunparse
15 except ImportError:
16     from urllib.parse import urlparse, urlunparse
17 
18 from datetime import datetime
19 
20 
21 from pelican import signals
22 from pelican.settings import DEFAULT_CONFIG
23 from pelican.utils import (slugify, truncate_html_words, memoized, strftime,
24                            python_2_unicode_compatible, deprecated_attribute,
25                            path_to_url)
26 
27 # Import these so that they're avalaible when you import from pelican.contents.
28 from pelican.urlwrappers import (URLWrapper, Author, Category, Tag)  # NOQA
29 
30 logger = logging.getLogger(__name__)
31 
32 
33 class Content(object):
34     """Represents a content.
35 
36     :param content: the string to parse, containing the original content.
37     :param metadata: the metadata associated to this page (optional).
38     :param settings: the settings dictionary (optional).
39     :param source_path: The location of the source of this content (if any).
40     :param context: The shared context between generators.
41 
42     """
43     @deprecated_attribute(old='filename', new='source_path', since=(3, 2, 0))
44     def filename():
45         return None
46 
47     def __init__(self, content, metadata=None, settings=None,
48                  source_path=None, context=None):
49         if metadata is None:
50             metadata = {}
51         if settings is None:
52             settings = copy.deepcopy(DEFAULT_CONFIG)
53 
54         self.settings = settings
55         self._content = content
56         if context is None:
57             context = {}
58         self._context = context
59         self.translations = []
60 
61         local_metadata = dict(settings['DEFAULT_METADATA'])
62         local_metadata.update(metadata)
63 
64         # set metadata as attributes
65         for key, value in local_metadata.items():
66             if key in ('save_as', 'url'):
67                 key = 'override_' + key
68             setattr(self, key.lower(), value)
69 
70         # also keep track of the metadata attributes available
71         self.metadata = local_metadata
72 
73         #default template if it's not defined in page
74         self.template = self._get_template()
75 
76         # default author to the one in settings if not defined
77         if not hasattr(self, 'author'):
78             if 'AUTHOR' in settings:
79                 self.author = Author(settings['AUTHOR'], settings)
80 
81         # XXX Split all the following code into pieces, there is too much here.
82 
83         # manage languages
84         self.in_default_lang = True
85         if 'DEFAULT_LANG' in settings:
86             default_lang = settings['DEFAULT_LANG'].lower()
87             if not hasattr(self, 'lang'):
88                 self.lang = default_lang
89 
90             self.in_default_lang = (self.lang == default_lang)
91 
92         # create the slug if not existing, from the title
93         if not hasattr(self, 'slug') and hasattr(self, 'title'):
94             self.slug = slugify(self.title,
95                                 settings.get('SLUG_SUBSTITUTIONS', ()))
96 
97         self.source_path = source_path
98 
99         # manage the date format
100         if not hasattr(self, 'date_format'):
101             if hasattr(self, 'lang') and self.lang in settings['DATE_FORMATS']:
102                 self.date_format = settings['DATE_FORMATS'][self.lang]
103             else:
104                 self.date_format = settings['DEFAULT_DATE_FORMAT']
105 
106         if isinstance(self.date_format, tuple):
107             locale_string = self.date_format[0]
108             if sys.version_info < (3, ) and isinstance(locale_string,
109                                                        six.text_type):
110                 locale_string = locale_string.encode('ascii')
111             locale.setlocale(locale.LC_ALL, locale_string)
112             self.date_format = self.date_format[1]
113 
114         if hasattr(self, 'date'):
115             self.locale_date = strftime(self.date, self.date_format)
116 
117         # manage status
118         if not hasattr(self, 'status'):
119             self.status = settings['DEFAULT_STATUS']
120             if not settings['WITH_FUTURE_DATES']:
121                 if hasattr(self, 'date') and self.date > datetime.now():
122                     self.status = 'draft'
123 
124         # store the summary metadata if it is set
125         if 'summary' in metadata:
126             self._summary = metadata['summary']
127 
128         signals.content_object_init.send(self)
129 
130     def __str__(self):
131         if self.source_path is None:
132             return repr(self)
133         elif six.PY3:
134             return self.source_path or repr(self)
135         else:
136             return str(self.source_path.encode('utf-8', 'replace'))
137 
138     def check_properties(self):
139         """Test mandatory properties are set."""
140         for prop in self.mandatory_properties:
141             if not hasattr(self, prop):
142                 raise NameError(prop)
143 
144     @property
145     def url_format(self):
146         """Returns the URL, formatted with the proper values"""
147         metadata = copy.copy(self.metadata)
148         path = self.metadata.get('path', self.get_relative_source_path())
149         default_category = self.settings['DEFAULT_CATEGORY']
150         slug_substitutions = self.settings.get('SLUG_SUBSTITUTIONS', ())
151         metadata.update({
152             'path': path_to_url(path),
153             'slug': getattr(self, 'slug', ''),
154             'lang': getattr(self, 'lang', 'en'),
155             'date': getattr(self, 'date', datetime.now()),
156             'author': slugify(
157                 getattr(self, 'author', ''),
158                 slug_substitutions
159             ),
160             'category': slugify(
161                 getattr(self, 'category', default_category),
162                 slug_substitutions
163             )
164         })
165         return metadata
166 
167     def _expand_settings(self, key):
168         fq_key = ('%s_%s' % (self.__class__.__name__, key)).upper()
169         return self.settings[fq_key].format(**self.url_format)
170 
171     def get_url_setting(self, key):
172         if hasattr(self, 'override_' + key):
173             return getattr(self, 'override_' + key)
174         key = key if self.in_default_lang else 'lang_%s' % key
175         return self._expand_settings(key)
176 
177     def _update_content(self, content, siteurl):
178         """Update the content attribute.
179 
180         Change all the relative paths of the content to relative paths
181         suitable for the ouput content.
182 
183         :param content: content resource that will be passed to the templates.
184         :param siteurl: siteurl which is locally generated by the writer in
185                         case of RELATIVE_URLS.
186         """
187         if not content:
188             return content
189 
190         instrasite_link_regex = self.settings['INTRASITE_LINK_REGEX']
191         regex = r"""
192             (?P<markup><\s*[^\>]*  # match tag with src and href attr
193                 (?:href|src)\s*=)
194 
195             (?P<quote>["\'])      # require value to be quoted
196             (?P<path>{0}(?P<value>.*?))  # the url value
197             \2""".format(instrasite_link_regex)
198         hrefs = re.compile(regex, re.X)
199 
200         def replacer(m):
201             what = m.group('what')
202             value = urlparse(m.group('value'))
203             path = value.path
204             origin = m.group('path')
205 
206             # XXX Put this in a different location.
207             if what == 'filename':
208                 if path.startswith('/'):
209                     path = path[1:]
210                 else:
211                     # relative to the source path of this content
212                     path = self.get_relative_source_path(
213                         os.path.join(self.relative_dir, path)
214                     )
215 
216                 if path in self._context['filenames']:
217                     origin = '/'.join((siteurl,
218                              self._context['filenames'][path].url))
219                     origin = origin.replace('\\', '/')  # for Windows paths.
220                 else:
221                     logger.warning("Unable to find {fn}, skipping url"
222                                    " replacement".format(fn=path))
223             elif what == 'category':
224                 origin = Category(path, self.settings).url
225             elif what == 'tag':
226                 origin = Tag(path, self.settings).url
227 
228             # keep all other parts, such as query, fragment, etc.
229             parts = list(value)
230             parts[2] = origin
231             origin = urlunparse(parts)
232 
233             return ''.join((m.group('markup'), m.group('quote'), origin,
234                             m.group('quote')))
235 
236         return hrefs.sub(replacer, content)
237 
238     @memoized
239     def get_content(self, siteurl):
240 
241         if hasattr(self, '_get_content'):
242             content = self._get_content()
243         else:
244             content = self._content
245         return self._update_content(content, siteurl)
246 
247     @property
248     def content(self):
249         return self.get_content(self._context.get('localsiteurl', ''))
250 
251     def _get_summary(self):
252         """Returns the summary of an article.
253 
254         This is based on the summary metadata if set, otherwise truncate the
255         content.
256         """
257         if hasattr(self, '_summary'):
258             return self._summary
259 
260         if self.settings['SUMMARY_MAX_LENGTH'] is None:
261             return self.content
262 
263         return truncate_html_words(self.content,
264                                    self.settings['SUMMARY_MAX_LENGTH'])
265 
266     def _set_summary(self, summary):
267         """Dummy function"""
268         pass
269 
270     summary = property(_get_summary, _set_summary, "Summary of the article."
271                        "Based on the content. Can't be set")
272     url = property(functools.partial(get_url_setting, key='url'))
273     save_as = property(functools.partial(get_url_setting, key='save_as'))
274 
275     def _get_template(self):
276         if hasattr(self, 'template') and self.template is not None:
277             return self.template
278         else:
279             return self.default_template
280 
281     def get_relative_source_path(self, source_path=None):
282         """Return the relative path (from the content path) to the given
283         source_path.
284 
285         If no source path is specified, use the source path of this
286         content object.
287         """
288         if not source_path:
289             source_path = self.source_path
290         if source_path is None:
291             return None
292 
293         return os.path.relpath(
294             os.path.abspath(os.path.join(self.settings['PATH'], source_path)),
295             os.path.abspath(self.settings['PATH'])
296         )
297 
298     @property
299     def relative_dir(self):
300         return os.path.dirname(os.path.relpath(
301             os.path.abspath(self.source_path),
302             os.path.abspath(self.settings['PATH']))
303         )
304 
305 
306 class Page(Content):
307     mandatory_properties = ('title',)
308     default_template = 'page'
309 
310 
311 class Article(Page):
312     mandatory_properties = ('title', 'date', 'category')
313     default_template = 'article'
314 
315 
316 class Quote(Page):
317     base_properties = ('author', 'date')
318 
319 
320 @python_2_unicode_compatible
321 class Static(Page):
322     @deprecated_attribute(old='filepath', new='source_path', since=(3, 2, 0))
323     def filepath():
324         return None
325 
326     @deprecated_attribute(old='src', new='source_path', since=(3, 2, 0))
327     def src():
328         return None
329 
330     @deprecated_attribute(old='dst', new='save_as', since=(3, 2, 0))
331     def dst():
332         return None
333 
334 
335 def is_valid_content(content, f):
336     try:
337         content.check_properties()
338         return True
339     except NameError as e:
340         logger.error("Skipping %s: could not find information about "
341                      "'%s'" % (f, e))
342         return False
343
```
--- 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()

```

diff --git a/pelican/contents.py b/pelican/contents.py
--- a/pelican/contents.py
+++ b/pelican/contents.py
@@ -189,8 +189,8 @@
 
         instrasite_link_regex = self.settings['INTRASITE_LINK_REGEX']
         regex = r"""
-            (?P<markup><\s*[^\>]*  # match tag with src and href attr
-                (?:href|src)\s*=)
+            (?P<markup><\s*[^\>]*  # match tag with all url-value attributes
+                (?:href|src|poster|data|cite|formaction|action)\s*=)
 
             (?P<quote>["\'])      # require value to be quoted
             (?P<path>{0}(?P<value>.*?))  # the url value

{"golden_diff": "diff --git a/pelican/contents.py b/pelican/contents.py\n--- a/pelican/contents.py\n+++ b/pelican/contents.py\n@@ -189,8 +189,8 @@\n \n         instrasite_link_regex = self.settings['INTRASITE_LINK_REGEX']\n         regex = r\"\"\"\n-            (?P<markup><\\s*[^\\>]*  # match tag with src and href attr\n-                (?:href|src)\\s*=)\n+            (?P<markup><\\s*[^\\>]*  # match tag with all url-value attributes\n+                (?:href|src|poster|data|cite|formaction|action)\\s*=)\n \n             (?P<quote>[\"\\'])      # require value to be quoted\n             (?P<path>{0}(?P<value>.*?))  # the url value\n", "issue": "Internal content link doesn't work on video.poster\nI'm using pelican 3.3.0, with python 2.7.5.\n\nThe [internal content link](http://docs.getpelican.com/en/3.3.0/getting_started.html#linking-to-internal-content) feature is very useful that I don't need to determine where attachment files will be placed after site generation. But recently I find that this feature has no effect on poster property of a video tag.\n\nFor example, I wrote this in my post.md:\n\n``` html\n<video controls poster=\"{filename}/images/2011/07/poster.jpg\">\n  <source src=\"{filename}/assets/2011/07/video.mp4\" type=\"video/mp4\">\n</video>\n```\n\nAfter generation, I got this html code in my page:\n\n``` html\n<video controls poster=\"{filename}/images/2011/07/poster.jpg\">\n  <source src=\"/assets/2011/07/video.mp4\" type=\"video/mp4\">\n</video>\n```\n\nAs you can see, the `{filename}` still there, it should be replace to an empty string in this case.\n\n", "before_files": [{"content": "# -*- coding: utf-8 -*-\nfrom __future__ import unicode_literals, print_function\nimport six\n\nimport copy\nimport locale\nimport logging\nimport functools\nimport os\nimport re\nimport sys\n\ntry:\n    from urlparse import urlparse, urlunparse\nexcept ImportError:\n    from urllib.parse import urlparse, urlunparse\n\nfrom datetime import datetime\n\n\nfrom pelican import signals\nfrom pelican.settings import DEFAULT_CONFIG\nfrom pelican.utils import (slugify, truncate_html_words, memoized, strftime,\n                           python_2_unicode_compatible, deprecated_attribute,\n                           path_to_url)\n\n# Import these so that they're avalaible when you import from pelican.contents.\nfrom pelican.urlwrappers import (URLWrapper, Author, Category, Tag)  # NOQA\n\nlogger = logging.getLogger(__name__)\n\n\nclass Content(object):\n    \"\"\"Represents a content.\n\n    :param content: the string to parse, containing the original content.\n    :param metadata: the metadata associated to this page (optional).\n    :param settings: the settings dictionary (optional).\n    :param source_path: The location of the source of this content (if any).\n    :param context: The shared context between generators.\n\n    \"\"\"\n    @deprecated_attribute(old='filename', new='source_path', since=(3, 2, 0))\n    def filename():\n        return None\n\n    def __init__(self, content, metadata=None, settings=None,\n                 source_path=None, context=None):\n        if metadata is None:\n            metadata = {}\n        if settings is None:\n            settings = copy.deepcopy(DEFAULT_CONFIG)\n\n        self.settings = settings\n        self._content = content\n        if context is None:\n            context = {}\n        self._context = context\n        self.translations = []\n\n        local_metadata = dict(settings['DEFAULT_METADATA'])\n        local_metadata.update(metadata)\n\n        # set metadata as attributes\n        for key, value in local_metadata.items():\n            if key in ('save_as', 'url'):\n                key = 'override_' + key\n            setattr(self, key.lower(), value)\n\n        # also keep track of the metadata attributes available\n        self.metadata = local_metadata\n\n        #default template if it's not defined in page\n        self.template = self._get_template()\n\n        # default author to the one in settings if not defined\n        if not hasattr(self, 'author'):\n            if 'AUTHOR' in settings:\n                self.author = Author(settings['AUTHOR'], settings)\n\n        # XXX Split all the following code into pieces, there is too much here.\n\n        # manage languages\n        self.in_default_lang = True\n        if 'DEFAULT_LANG' in settings:\n            default_lang = settings['DEFAULT_LANG'].lower()\n            if not hasattr(self, 'lang'):\n                self.lang = default_lang\n\n            self.in_default_lang = (self.lang == default_lang)\n\n        # create the slug if not existing, from the title\n        if not hasattr(self, 'slug') and hasattr(self, 'title'):\n            self.slug = slugify(self.title,\n                                settings.get('SLUG_SUBSTITUTIONS', ()))\n\n        self.source_path = source_path\n\n        # manage the date format\n        if not hasattr(self, 'date_format'):\n            if hasattr(self, 'lang') and self.lang in settings['DATE_FORMATS']:\n                self.date_format = settings['DATE_FORMATS'][self.lang]\n            else:\n                self.date_format = settings['DEFAULT_DATE_FORMAT']\n\n        if isinstance(self.date_format, tuple):\n            locale_string = self.date_format[0]\n            if sys.version_info < (3, ) and isinstance(locale_string,\n                                                       six.text_type):\n                locale_string = locale_string.encode('ascii')\n            locale.setlocale(locale.LC_ALL, locale_string)\n            self.date_format = self.date_format[1]\n\n        if hasattr(self, 'date'):\n            self.locale_date = strftime(self.date, self.date_format)\n\n        # manage status\n        if not hasattr(self, 'status'):\n            self.status = settings['DEFAULT_STATUS']\n            if not settings['WITH_FUTURE_DATES']:\n                if hasattr(self, 'date') and self.date > datetime.now():\n                    self.status = 'draft'\n\n        # store the summary metadata if it is set\n        if 'summary' in metadata:\n            self._summary = metadata['summary']\n\n        signals.content_object_init.send(self)\n\n    def __str__(self):\n        if self.source_path is None:\n            return repr(self)\n        elif six.PY3:\n            return self.source_path or repr(self)\n        else:\n            return str(self.source_path.encode('utf-8', 'replace'))\n\n    def check_properties(self):\n        \"\"\"Test mandatory properties are set.\"\"\"\n        for prop in self.mandatory_properties:\n            if not hasattr(self, prop):\n                raise NameError(prop)\n\n    @property\n    def url_format(self):\n        \"\"\"Returns the URL, formatted with the proper values\"\"\"\n        metadata = copy.copy(self.metadata)\n        path = self.metadata.get('path', self.get_relative_source_path())\n        default_category = self.settings['DEFAULT_CATEGORY']\n        slug_substitutions = self.settings.get('SLUG_SUBSTITUTIONS', ())\n        metadata.update({\n            'path': path_to_url(path),\n            'slug': getattr(self, 'slug', ''),\n            'lang': getattr(self, 'lang', 'en'),\n            'date': getattr(self, 'date', datetime.now()),\n            'author': slugify(\n                getattr(self, 'author', ''),\n                slug_substitutions\n            ),\n            'category': slugify(\n                getattr(self, 'category', default_category),\n                slug_substitutions\n            )\n        })\n        return metadata\n\n    def _expand_settings(self, key):\n        fq_key = ('%s_%s' % (self.__class__.__name__, key)).upper()\n        return self.settings[fq_key].format(**self.url_format)\n\n    def get_url_setting(self, key):\n        if hasattr(self, 'override_' + key):\n            return getattr(self, 'override_' + key)\n        key = key if self.in_default_lang else 'lang_%s' % key\n        return self._expand_settings(key)\n\n    def _update_content(self, content, siteurl):\n        \"\"\"Update the content attribute.\n\n        Change all the relative paths of the content to relative paths\n        suitable for the ouput content.\n\n        :param content: content resource that will be passed to the templates.\n        :param siteurl: siteurl which is locally generated by the writer in\n                        case of RELATIVE_URLS.\n        \"\"\"\n        if not content:\n            return content\n\n        instrasite_link_regex = self.settings['INTRASITE_LINK_REGEX']\n        regex = r\"\"\"\n            (?P<markup><\\s*[^\\>]*  # match tag with src and href attr\n                (?:href|src)\\s*=)\n\n            (?P<quote>[\"\\'])      # require value to be quoted\n            (?P<path>{0}(?P<value>.*?))  # the url value\n            \\2\"\"\".format(instrasite_link_regex)\n        hrefs = re.compile(regex, re.X)\n\n        def replacer(m):\n            what = m.group('what')\n            value = urlparse(m.group('value'))\n            path = value.path\n            origin = m.group('path')\n\n            # XXX Put this in a different location.\n            if what == 'filename':\n                if path.startswith('/'):\n                    path = path[1:]\n                else:\n                    # relative to the source path of this content\n                    path = self.get_relative_source_path(\n                        os.path.join(self.relative_dir, path)\n                    )\n\n                if path in self._context['filenames']:\n                    origin = '/'.join((siteurl,\n                             self._context['filenames'][path].url))\n                    origin = origin.replace('\\\\', '/')  # for Windows paths.\n                else:\n                    logger.warning(\"Unable to find {fn}, skipping url\"\n                                   \" replacement\".format(fn=path))\n            elif what == 'category':\n                origin = Category(path, self.settings).url\n            elif what == 'tag':\n                origin = Tag(path, self.settings).url\n\n            # keep all other parts, such as query, fragment, etc.\n            parts = list(value)\n            parts[2] = origin\n            origin = urlunparse(parts)\n\n            return ''.join((m.group('markup'), m.group('quote'), origin,\n                            m.group('quote')))\n\n        return hrefs.sub(replacer, content)\n\n    @memoized\n    def get_content(self, siteurl):\n\n        if hasattr(self, '_get_content'):\n            content = self._get_content()\n        else:\n            content = self._content\n        return self._update_content(content, siteurl)\n\n    @property\n    def content(self):\n        return self.get_content(self._context.get('localsiteurl', ''))\n\n    def _get_summary(self):\n        \"\"\"Returns the summary of an article.\n\n        This is based on the summary metadata if set, otherwise truncate the\n        content.\n        \"\"\"\n        if hasattr(self, '_summary'):\n            return self._summary\n\n        if self.settings['SUMMARY_MAX_LENGTH'] is None:\n            return self.content\n\n        return truncate_html_words(self.content,\n                                   self.settings['SUMMARY_MAX_LENGTH'])\n\n    def _set_summary(self, summary):\n        \"\"\"Dummy function\"\"\"\n        pass\n\n    summary = property(_get_summary, _set_summary, \"Summary of the article.\"\n                       \"Based on the content. Can't be set\")\n    url = property(functools.partial(get_url_setting, key='url'))\n    save_as = property(functools.partial(get_url_setting, key='save_as'))\n\n    def _get_template(self):\n        if hasattr(self, 'template') and self.template is not None:\n            return self.template\n        else:\n            return self.default_template\n\n    def get_relative_source_path(self, source_path=None):\n        \"\"\"Return the relative path (from the content path) to the given\n        source_path.\n\n        If no source path is specified, use the source path of this\n        content object.\n        \"\"\"\n        if not source_path:\n            source_path = self.source_path\n        if source_path is None:\n            return None\n\n        return os.path.relpath(\n            os.path.abspath(os.path.join(self.settings['PATH'], source_path)),\n            os.path.abspath(self.settings['PATH'])\n        )\n\n    @property\n    def relative_dir(self):\n        return os.path.dirname(os.path.relpath(\n            os.path.abspath(self.source_path),\n            os.path.abspath(self.settings['PATH']))\n        )\n\n\nclass Page(Content):\n    mandatory_properties = ('title',)\n    default_template = 'page'\n\n\nclass Article(Page):\n    mandatory_properties = ('title', 'date', 'category')\n    default_template = 'article'\n\n\nclass Quote(Page):\n    base_properties = ('author', 'date')\n\n\n@python_2_unicode_compatible\nclass Static(Page):\n    @deprecated_attribute(old='filepath', new='source_path', since=(3, 2, 0))\n    def filepath():\n        return None\n\n    @deprecated_attribute(old='src', new='source_path', since=(3, 2, 0))\n    def src():\n        return None\n\n    @deprecated_attribute(old='dst', new='save_as', since=(3, 2, 0))\n    def dst():\n        return None\n\n\ndef is_valid_content(content, f):\n    try:\n        content.check_properties()\n        return True\n    except NameError as e:\n        logger.error(\"Skipping %s: could not find information about \"\n                     \"'%s'\" % (f, e))\n        return False\n", "path": "pelican/contents.py"}], "after_files": [{"content": "# -*- coding: utf-8 -*-\nfrom __future__ import unicode_literals, print_function\nimport six\n\nimport copy\nimport locale\nimport logging\nimport functools\nimport os\nimport re\nimport sys\n\ntry:\n    from urlparse import urlparse, urlunparse\nexcept ImportError:\n    from urllib.parse import urlparse, urlunparse\n\nfrom datetime import datetime\n\n\nfrom pelican import signals\nfrom pelican.settings import DEFAULT_CONFIG\nfrom pelican.utils import (slugify, truncate_html_words, memoized, strftime,\n                           python_2_unicode_compatible, deprecated_attribute,\n                           path_to_url)\n\n# Import these so that they're avalaible when you import from pelican.contents.\nfrom pelican.urlwrappers import (URLWrapper, Author, Category, Tag)  # NOQA\n\nlogger = logging.getLogger(__name__)\n\n\nclass Content(object):\n    \"\"\"Represents a content.\n\n    :param content: the string to parse, containing the original content.\n    :param metadata: the metadata associated to this page (optional).\n    :param settings: the settings dictionary (optional).\n    :param source_path: The location of the source of this content (if any).\n    :param context: The shared context between generators.\n\n    \"\"\"\n    @deprecated_attribute(old='filename', new='source_path', since=(3, 2, 0))\n    def filename():\n        return None\n\n    def __init__(self, content, metadata=None, settings=None,\n                 source_path=None, context=None):\n        if metadata is None:\n            metadata = {}\n        if settings is None:\n            settings = copy.deepcopy(DEFAULT_CONFIG)\n\n        self.settings = settings\n        self._content = content\n        if context is None:\n            context = {}\n        self._context = context\n        self.translations = []\n\n        local_metadata = dict(settings['DEFAULT_METADATA'])\n        local_metadata.update(metadata)\n\n        # set metadata as attributes\n        for key, value in local_metadata.items():\n            if key in ('save_as', 'url'):\n                key = 'override_' + key\n            setattr(self, key.lower(), value)\n\n        # also keep track of the metadata attributes available\n        self.metadata = local_metadata\n\n        #default template if it's not defined in page\n        self.template = self._get_template()\n\n        # default author to the one in settings if not defined\n        if not hasattr(self, 'author'):\n            if 'AUTHOR' in settings:\n                self.author = Author(settings['AUTHOR'], settings)\n\n        # XXX Split all the following code into pieces, there is too much here.\n\n        # manage languages\n        self.in_default_lang = True\n        if 'DEFAULT_LANG' in settings:\n            default_lang = settings['DEFAULT_LANG'].lower()\n            if not hasattr(self, 'lang'):\n                self.lang = default_lang\n\n            self.in_default_lang = (self.lang == default_lang)\n\n        # create the slug if not existing, from the title\n        if not hasattr(self, 'slug') and hasattr(self, 'title'):\n            self.slug = slugify(self.title,\n                                settings.get('SLUG_SUBSTITUTIONS', ()))\n\n        self.source_path = source_path\n\n        # manage the date format\n        if not hasattr(self, 'date_format'):\n            if hasattr(self, 'lang') and self.lang in settings['DATE_FORMATS']:\n                self.date_format = settings['DATE_FORMATS'][self.lang]\n            else:\n                self.date_format = settings['DEFAULT_DATE_FORMAT']\n\n        if isinstance(self.date_format, tuple):\n            locale_string = self.date_format[0]\n            if sys.version_info < (3, ) and isinstance(locale_string,\n                                                       six.text_type):\n                locale_string = locale_string.encode('ascii')\n            locale.setlocale(locale.LC_ALL, locale_string)\n            self.date_format = self.date_format[1]\n\n        if hasattr(self, 'date'):\n            self.locale_date = strftime(self.date, self.date_format)\n\n        # manage status\n        if not hasattr(self, 'status'):\n            self.status = settings['DEFAULT_STATUS']\n            if not settings['WITH_FUTURE_DATES']:\n                if hasattr(self, 'date') and self.date > datetime.now():\n                    self.status = 'draft'\n\n        # store the summary metadata if it is set\n        if 'summary' in metadata:\n            self._summary = metadata['summary']\n\n        signals.content_object_init.send(self)\n\n    def __str__(self):\n        if self.source_path is None:\n            return repr(self)\n        elif six.PY3:\n            return self.source_path or repr(self)\n        else:\n            return str(self.source_path.encode('utf-8', 'replace'))\n\n    def check_properties(self):\n        \"\"\"Test mandatory properties are set.\"\"\"\n        for prop in self.mandatory_properties:\n            if not hasattr(self, prop):\n                raise NameError(prop)\n\n    @property\n    def url_format(self):\n        \"\"\"Returns the URL, formatted with the proper values\"\"\"\n        metadata = copy.copy(self.metadata)\n        path = self.metadata.get('path', self.get_relative_source_path())\n        default_category = self.settings['DEFAULT_CATEGORY']\n        slug_substitutions = self.settings.get('SLUG_SUBSTITUTIONS', ())\n        metadata.update({\n            'path': path_to_url(path),\n            'slug': getattr(self, 'slug', ''),\n            'lang': getattr(self, 'lang', 'en'),\n            'date': getattr(self, 'date', datetime.now()),\n            'author': slugify(\n                getattr(self, 'author', ''),\n                slug_substitutions\n            ),\n            'category': slugify(\n                getattr(self, 'category', default_category),\n                slug_substitutions\n            )\n        })\n        return metadata\n\n    def _expand_settings(self, key):\n        fq_key = ('%s_%s' % (self.__class__.__name__, key)).upper()\n        return self.settings[fq_key].format(**self.url_format)\n\n    def get_url_setting(self, key):\n        if hasattr(self, 'override_' + key):\n            return getattr(self, 'override_' + key)\n        key = key if self.in_default_lang else 'lang_%s' % key\n        return self._expand_settings(key)\n\n    def _update_content(self, content, siteurl):\n        \"\"\"Update the content attribute.\n\n        Change all the relative paths of the content to relative paths\n        suitable for the ouput content.\n\n        :param content: content resource that will be passed to the templates.\n        :param siteurl: siteurl which is locally generated by the writer in\n                        case of RELATIVE_URLS.\n        \"\"\"\n        if not content:\n            return content\n\n        instrasite_link_regex = self.settings['INTRASITE_LINK_REGEX']\n        regex = r\"\"\"\n            (?P<markup><\\s*[^\\>]*  # match tag with all url-value attributes\n                (?:href|src|poster|data|cite|formaction|action)\\s*=)\n\n            (?P<quote>[\"\\'])      # require value to be quoted\n            (?P<path>{0}(?P<value>.*?))  # the url value\n            \\2\"\"\".format(instrasite_link_regex)\n        hrefs = re.compile(regex, re.X)\n\n        def replacer(m):\n            what = m.group('what')\n            value = urlparse(m.group('value'))\n            path = value.path\n            origin = m.group('path')\n\n            # XXX Put this in a different location.\n            if what == 'filename':\n                if path.startswith('/'):\n                    path = path[1:]\n                else:\n                    # relative to the source path of this content\n                    path = self.get_relative_source_path(\n                        os.path.join(self.relative_dir, path)\n                    )\n\n                if path in self._context['filenames']:\n                    origin = '/'.join((siteurl,\n                             self._context['filenames'][path].url))\n                    origin = origin.replace('\\\\', '/')  # for Windows paths.\n                else:\n                    logger.warning(\"Unable to find {fn}, skipping url\"\n                                   \" replacement\".format(fn=path))\n            elif what == 'category':\n                origin = Category(path, self.settings).url\n            elif what == 'tag':\n                origin = Tag(path, self.settings).url\n\n            # keep all other parts, such as query, fragment, etc.\n            parts = list(value)\n            parts[2] = origin\n            origin = urlunparse(parts)\n\n            return ''.join((m.group('markup'), m.group('quote'), origin,\n                            m.group('quote')))\n\n        return hrefs.sub(replacer, content)\n\n    @memoized\n    def get_content(self, siteurl):\n\n        if hasattr(self, '_get_content'):\n            content = self._get_content()\n        else:\n            content = self._content\n        return self._update_content(content, siteurl)\n\n    @property\n    def content(self):\n        return self.get_content(self._context.get('localsiteurl', ''))\n\n    def _get_summary(self):\n        \"\"\"Returns the summary of an article.\n\n        This is based on the summary metadata if set, otherwise truncate the\n        content.\n        \"\"\"\n        if hasattr(self, '_summary'):\n            return self._summary\n\n        if self.settings['SUMMARY_MAX_LENGTH'] is None:\n            return self.content\n\n        return truncate_html_words(self.content,\n                                   self.settings['SUMMARY_MAX_LENGTH'])\n\n    def _set_summary(self, summary):\n        \"\"\"Dummy function\"\"\"\n        pass\n\n    summary = property(_get_summary, _set_summary, \"Summary of the article.\"\n                       \"Based on the content. Can't be set\")\n    url = property(functools.partial(get_url_setting, key='url'))\n    save_as = property(functools.partial(get_url_setting, key='save_as'))\n\n    def _get_template(self):\n        if hasattr(self, 'template') and self.template is not None:\n            return self.template\n        else:\n            return self.default_template\n\n    def get_relative_source_path(self, source_path=None):\n        \"\"\"Return the relative path (from the content path) to the given\n        source_path.\n\n        If no source path is specified, use the source path of this\n        content object.\n        \"\"\"\n        if not source_path:\n            source_path = self.source_path\n        if source_path is None:\n            return None\n\n        return os.path.relpath(\n            os.path.abspath(os.path.join(self.settings['PATH'], source_path)),\n            os.path.abspath(self.settings['PATH'])\n        )\n\n    @property\n    def relative_dir(self):\n        return os.path.dirname(os.path.relpath(\n            os.path.abspath(self.source_path),\n            os.path.abspath(self.settings['PATH']))\n        )\n\n\nclass Page(Content):\n    mandatory_properties = ('title',)\n    default_template = 'page'\n\n\nclass Article(Page):\n    mandatory_properties = ('title', 'date', 'category')\n    default_template = 'article'\n\n\nclass Quote(Page):\n    base_properties = ('author', 'date')\n\n\n@python_2_unicode_compatible\nclass Static(Page):\n    @deprecated_attribute(old='filepath', new='source_path', since=(3, 2, 0))\n    def filepath():\n        return None\n\n    @deprecated_attribute(old='src', new='source_path', since=(3, 2, 0))\n    def src():\n        return None\n\n    @deprecated_attribute(old='dst', new='save_as', since=(3, 2, 0))\n    def dst():\n        return None\n\n\ndef is_valid_content(content, f):\n    try:\n        content.check_properties()\n        return True\n    except NameError as e:\n        logger.error(\"Skipping %s: could not find information about \"\n                     \"'%s'\" % (f, e))\n        return False\n", "path": "pelican/contents.py"}]}