Merge pull request #2381 from oulenz/static_links

Automatically copy linked static files
This commit is contained in:
Justin Mayer 2018-11-02 22:41:30 +01:00 committed by GitHub
commit 0da7ac677a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
32 changed files with 424 additions and 224 deletions

View file

@ -150,8 +150,11 @@ class Pelican(object):
start_time = time.time()
context = self.settings.copy()
# Share these among all the generators and content objects:
context['filenames'] = {} # maps source path to Content object or None
# Share these among all the generators and content objects
# They map source paths to Content objects or None
context['generated_content'] = {}
context['static_links'] = set()
context['static_content'] = {}
context['localsiteurl'] = self.settings['SITEURL']
generators = [

View file

@ -142,7 +142,8 @@ class Content(object):
if not hasattr(self, 'status'):
self.status = getattr(self, 'default_status', None)
if len(self._context.get('filenames', [])) > 0:
if (len(self._context.get('generated_content', [])) > 0 or
len(self._context.get('static_content', [])) > 0):
self.refresh_metadata_intersite_links()
signals.content_object_init.send(self)
@ -255,7 +256,7 @@ class Content(object):
siteurl += '/'
# XXX Put this in a different location.
if what in {'filename', 'attach'}:
if what in {'filename', 'static', 'attach'}:
if path.startswith('/'):
path = path[1:]
else:
@ -264,22 +265,33 @@ class Content(object):
os.path.join(self.relative_dir, path)
)
if path not in self._context['filenames']:
unquoted_path = path.replace('%20', ' ')
key = 'static_content' if what in ('static', 'attach')\
else 'generated_content'
if unquoted_path in self._context['filenames']:
path = unquoted_path
def _get_linked_content(key, path):
try:
return self._context[key][path]
except KeyError:
try:
# Markdown escapes spaces, try unescaping
return self._context[key][path.replace('%20', ' ')]
except KeyError:
if what == 'filename' and key == 'generated_content':
key = 'static_content'
linked_content = _get_linked_content(key, path)
if linked_content:
logger.warning(
'{filename} used for linking to static'
'content %s in %s. Use {static} instead',
path,
self.get_relative_source_path())
return linked_content
return None
linked_content = self._context['filenames'].get(path)
linked_content = _get_linked_content(key, path)
if linked_content:
if what == 'attach':
if isinstance(linked_content, Static):
linked_content.attach_to(self)
else:
logger.warning(
"%s used {attach} link syntax on a "
"non-static file. Use {filename} instead.",
self.get_relative_source_path())
linked_content.attach_to(self)
origin = joiner(siteurl, linked_content.url)
origin = origin.replace('\\', '/') # for Windows paths.
else:
@ -310,6 +322,17 @@ class Content(object):
return ''.join((m.group('markup'), m.group('quote'), origin,
m.group('quote')))
def _get_intrasite_link_regex(self):
intrasite_link_regex = self.settings['INTRASITE_LINK_REGEX']
regex = r"""
(?P<markup><[^\>]+ # match tag with all url-value attributes
(?:href|src|poster|data|cite|formaction|action)\s*=\s*)
(?P<quote>["\']) # require value to be quoted
(?P<path>{0}(?P<value>.*?)) # the url value
\2""".format(intrasite_link_regex)
return re.compile(regex, re.X)
def _update_content(self, content, siteurl):
"""Update the content attribute.
@ -323,18 +346,29 @@ class Content(object):
if not content:
return content
instrasite_link_regex = self.settings['INTRASITE_LINK_REGEX']
regex = r"""
(?P<markup><[^\>]+ # match tag with all url-value attributes
(?:href|src|poster|data|cite|formaction|action)\s*=\s*)
(?P<quote>["\']) # require value to be quoted
(?P<path>{0}(?P<value>.*?)) # the url value
\2""".format(instrasite_link_regex)
hrefs = re.compile(regex, re.X)
hrefs = self._get_intrasite_link_regex()
return hrefs.sub(lambda m: self._link_replacer(siteurl, m), content)
def get_static_links(self):
static_links = set()
hrefs = self._get_intrasite_link_regex()
for m in hrefs.finditer(self._content):
what = m.group('what')
value = urlparse(m.group('value'))
path = value.path
if what not in {'static', 'attach'}:
continue
if path.startswith('/'):
path = path[1:]
else:
# relative to the source path of this content
path = self.get_relative_source_path(
os.path.join(self.relative_dir, path)
)
path = path.replace('%20', ' ')
static_links.add(path)
return static_links
def get_siteurl(self):
return self._context.get('localsiteurl', '')

View file

@ -147,7 +147,7 @@ class Generator(object):
parent_path, subdir = os.path.split(os.path.join(self.path, e))
exclusions_by_dirpath.setdefault(parent_path, set()).add(subdir)
files = []
files = set()
ignores = self.settings['IGNORE_FILES']
for path in paths:
# careful: os.path.join() will add a slash when path == ''.
@ -170,33 +170,41 @@ class Generator(object):
for f in temp_files:
fp = os.path.join(reldir, f)
if self._include_path(fp, extensions):
files.append(fp)
files.add(fp)
elif os.path.exists(root) and self._include_path(path, extensions):
files.append(path) # can't walk non-directories
files.add(path) # can't walk non-directories
return files
def add_source_path(self, content):
def add_source_path(self, content, static=False):
"""Record a source file path that a Generator found and processed.
Store a reference to its Content object, for url lookups later.
"""
location = content.get_relative_source_path()
self.context['filenames'][location] = content
key = 'static_content' if static else 'generated_content'
self.context[key][location] = content
def _add_failed_source_path(self, path):
def _add_failed_source_path(self, path, static=False):
"""Record a source file path that a Generator failed to process.
(For example, one that was missing mandatory metadata.)
The path argument is expected to be relative to self.path.
"""
self.context['filenames'][posixize_path(os.path.normpath(path))] = None
key = 'static_content' if static else 'generated_content'
self.context[key][posixize_path(os.path.normpath(path))] = None
def _is_potential_source_path(self, path):
def _is_potential_source_path(self, path, static=False):
"""Return True if path was supposed to be used as a source file.
(This includes all source files that have been found by generators
before this method is called, even if they failed to process.)
The path argument is expected to be relative to self.path.
"""
return (posixize_path(os.path.normpath(path))
in self.context['filenames'])
key = 'static_content' if static else 'generated_content'
return (posixize_path(os.path.normpath(path)) in self.context[key])
def add_static_links(self, content):
"""Add file links in content to context to be processed as Static
content.
"""
self.context['static_links'] |= content.get_static_links()
def _update_context(self, items):
"""Update the context with the given items from the currrent
@ -596,6 +604,7 @@ class ArticlesGenerator(CachingGenerator):
elif article.status == "draft":
all_drafts.append(article)
self.add_source_path(article)
self.add_static_links(article)
def _process(arts):
origs, translations = process_translations(
@ -702,6 +711,7 @@ class PagesGenerator(CachingGenerator):
elif page.status == "draft":
draft_pages.append(page)
self.add_source_path(page)
self.add_static_links(page)
def _process(pages):
origs, translations = process_translations(
@ -753,9 +763,12 @@ class StaticGenerator(Generator):
def generate_context(self):
self.staticfiles = []
for f in self.get_files(self.settings['STATIC_PATHS'],
exclude=self.settings['STATIC_EXCLUDES'],
extensions=False):
linked_files = {os.path.join(self.path, path)
for path in self.context['static_links']}
found_files = self.get_files(self.settings['STATIC_PATHS'],
exclude=self.settings['STATIC_EXCLUDES'],
extensions=False)
for f in linked_files | found_files:
# skip content source files unless the user explicitly wants them
if self.settings['STATIC_EXCLUDE_SOURCES']:
@ -770,7 +783,7 @@ class StaticGenerator(Generator):
context_signal=signals.static_generator_context,
context_sender=self)
self.staticfiles.append(static)
self.add_source_path(static)
self.add_source_path(static, static=True)
self._update_context(('staticfiles',))
signals.static_generator_finalized.send(self)

View file

@ -0,0 +1,7 @@
Title: Page with static links
My links:
[Link 0]({static}image0.jpg)
[Link 1]({attach}image1.jpg)

View file

@ -42,8 +42,8 @@
<div class="section" id="this-is-a-simple-title">
<h2>This is a simple title</h2>
<p>And here comes the cool <a class="reference external" href="http://books.couchdb.org/relax/design-documents/views">stuff</a>.</p>
<img alt="alternate text" src="|filename|/pictures/Sushi.jpg" style="width: 600px; height: 450px;" />
<img alt="alternate text" src="|filename|/pictures/Sushi_Macro.jpg" style="width: 600px; height: 450px;" />
<img alt="alternate text" src="/pictures/Sushi.jpg" style="width: 600px; height: 450px;" />
<img alt="alternate text" src="/pictures/Sushi_Macro.jpg" style="width: 600px; height: 450px;" />
<pre class="literal-block">
&gt;&gt;&gt; from ipdb import set_trace
&gt;&gt;&gt; set_trace()
@ -78,7 +78,7 @@
<h2>Why not ?</h2>
<p>After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst !
YEAH !</p>
<img alt="alternate text" src="|filename|/pictures/Sushi.jpg" style="width: 600px; height: 450px;" />
<img alt="alternate text" src="/pictures/Sushi.jpg" style="width: 600px; height: 450px;" />
</div>
<a class="readmore" href="/oh-yeah.html">read more</a>

View file

@ -38,7 +38,7 @@
<h2>Why not ?</h2>
<p>After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst !
YEAH !</p>
<img alt="alternate text" src="|filename|/pictures/Sushi.jpg" style="width: 600px; height: 450px;" />
<img alt="alternate text" src="/pictures/Sushi.jpg" style="width: 600px; height: 450px;" />
</div>
</article>
</aside><!-- /#featured -->

View file

@ -42,8 +42,8 @@
<div class="section" id="this-is-a-simple-title">
<h2>This is a simple title</h2>
<p>And here comes the cool <a class="reference external" href="http://books.couchdb.org/relax/design-documents/views">stuff</a>.</p>
<img alt="alternate text" src="|filename|/pictures/Sushi.jpg" style="width: 600px; height: 450px;" />
<img alt="alternate text" src="|filename|/pictures/Sushi_Macro.jpg" style="width: 600px; height: 450px;" />
<img alt="alternate text" src="/pictures/Sushi.jpg" style="width: 600px; height: 450px;" />
<img alt="alternate text" src="/pictures/Sushi_Macro.jpg" style="width: 600px; height: 450px;" />
<pre class="literal-block">
&gt;&gt;&gt; from ipdb import set_trace
&gt;&gt;&gt; set_trace()

View file

@ -5,8 +5,8 @@ as well as &lt;strong&gt;inline markup&lt;/strong&gt;.&lt;/p&gt;
&lt;div class="section" id="this-is-a-simple-title"&gt;
&lt;h2&gt;This is a simple title&lt;/h2&gt;
&lt;p&gt;And here comes the cool &lt;a class="reference external" href="http://books.couchdb.org/relax/design-documents/views"&gt;stuff&lt;/a&gt;.&lt;/p&gt;
&lt;img alt="alternate text" src="|filename|/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /&gt;
&lt;img alt="alternate text" src="|filename|/pictures/Sushi_Macro.jpg" style="width: 600px; height: 450px;" /&gt;
&lt;img alt="alternate text" src="/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /&gt;
&lt;img alt="alternate text" src="/pictures/Sushi_Macro.jpg" style="width: 600px; height: 450px;" /&gt;
&lt;pre class="literal-block"&gt;
&amp;gt;&amp;gt;&amp;gt; from ipdb import set_trace
&amp;gt;&amp;gt;&amp;gt; set_trace()
@ -17,12 +17,12 @@ as well as &lt;strong&gt;inline markup&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;Why not ?&lt;/h2&gt;
&lt;p&gt;After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst !
YEAH !&lt;/p&gt;
&lt;img alt="alternate text" src="|filename|/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /&gt;
&lt;img alt="alternate text" src="/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /&gt;
&lt;/div&gt;
</summary><content type="html">&lt;div class="section" id="why-not"&gt;
&lt;h2&gt;Why not ?&lt;/h2&gt;
&lt;p&gt;After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst !
YEAH !&lt;/p&gt;
&lt;img alt="alternate text" src="|filename|/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /&gt;
&lt;img alt="alternate text" src="/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /&gt;
&lt;/div&gt;
</content><category term="oh"></category><category term="bar"></category><category term="yeah"></category></entry></feed>

View file

@ -5,6 +5,6 @@ as well as &lt;strong&gt;inline markup&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;Why not ?&lt;/h2&gt;
&lt;p&gt;After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst !
YEAH !&lt;/p&gt;
&lt;img alt="alternate text" src="|filename|/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /&gt;
&lt;img alt="alternate text" src="/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /&gt;
&lt;/div&gt;
</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Alexis Métaireau</dc:creator><pubDate>Wed, 20 Oct 2010 10:14:00 +0000</pubDate><guid isPermaLink="false">tag:None,2010-10-20:/oh-yeah.html</guid><category>oh</category><category>bar</category><category>yeah</category></item></channel></rss>

View file

@ -19,8 +19,8 @@ as well as &lt;strong&gt;inline markup&lt;/strong&gt;.&lt;/p&gt;
&lt;div class="section" id="this-is-a-simple-title"&gt;
&lt;h2&gt;This is a simple title&lt;/h2&gt;
&lt;p&gt;And here comes the cool &lt;a class="reference external" href="http://books.couchdb.org/relax/design-documents/views"&gt;stuff&lt;/a&gt;.&lt;/p&gt;
&lt;img alt="alternate text" src="|filename|/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /&gt;
&lt;img alt="alternate text" src="|filename|/pictures/Sushi_Macro.jpg" style="width: 600px; height: 450px;" /&gt;
&lt;img alt="alternate text" src="/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /&gt;
&lt;img alt="alternate text" src="/pictures/Sushi_Macro.jpg" style="width: 600px; height: 450px;" /&gt;
&lt;pre class="literal-block"&gt;
&amp;gt;&amp;gt;&amp;gt; from ipdb import set_trace
&amp;gt;&amp;gt;&amp;gt; set_trace()
@ -31,13 +31,13 @@ as well as &lt;strong&gt;inline markup&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;Why not ?&lt;/h2&gt;
&lt;p&gt;After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst !
YEAH !&lt;/p&gt;
&lt;img alt="alternate text" src="|filename|/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /&gt;
&lt;img alt="alternate text" src="/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /&gt;
&lt;/div&gt;
</summary><content type="html">&lt;div class="section" id="why-not"&gt;
&lt;h2&gt;Why not ?&lt;/h2&gt;
&lt;p&gt;After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst !
YEAH !&lt;/p&gt;
&lt;img alt="alternate text" src="|filename|/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /&gt;
&lt;img alt="alternate text" src="/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /&gt;
&lt;/div&gt;
</content><category term="oh"></category><category term="bar"></category><category term="yeah"></category></entry><entry><title>Unbelievable !</title><link href="/unbelievable.html" rel="alternate"></link><published>2010-10-15T20:30:00+00:00</published><updated>2010-10-15T20:30:00+00:00</updated><author><name></name></author><id>tag:None,2010-10-15:/unbelievable.html</id><summary type="html">&lt;p&gt;Or completely awesome. Depends the needs.&lt;/p&gt;
&lt;p&gt;&lt;a class="reference external" href="/a-markdown-powered-article.html"&gt;a root-relative link to markdown-article&lt;/a&gt;

View file

@ -21,8 +21,8 @@ as well as &lt;strong&gt;inline markup&lt;/strong&gt;.&lt;/p&gt;
&lt;div class="section" id="this-is-a-simple-title"&gt;
&lt;h2&gt;This is a simple title&lt;/h2&gt;
&lt;p&gt;And here comes the cool &lt;a class="reference external" href="http://books.couchdb.org/relax/design-documents/views"&gt;stuff&lt;/a&gt;.&lt;/p&gt;
&lt;img alt="alternate text" src="|filename|/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /&gt;
&lt;img alt="alternate text" src="|filename|/pictures/Sushi_Macro.jpg" style="width: 600px; height: 450px;" /&gt;
&lt;img alt="alternate text" src="/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /&gt;
&lt;img alt="alternate text" src="/pictures/Sushi_Macro.jpg" style="width: 600px; height: 450px;" /&gt;
&lt;pre class="literal-block"&gt;
&amp;gt;&amp;gt;&amp;gt; from ipdb import set_trace
&amp;gt;&amp;gt;&amp;gt; set_trace()
@ -33,13 +33,13 @@ as well as &lt;strong&gt;inline markup&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;Why not ?&lt;/h2&gt;
&lt;p&gt;After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst !
YEAH !&lt;/p&gt;
&lt;img alt="alternate text" src="|filename|/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /&gt;
&lt;img alt="alternate text" src="/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /&gt;
&lt;/div&gt;
</summary><content type="html">&lt;div class="section" id="why-not"&gt;
&lt;h2&gt;Why not ?&lt;/h2&gt;
&lt;p&gt;After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst !
YEAH !&lt;/p&gt;
&lt;img alt="alternate text" src="|filename|/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /&gt;
&lt;img alt="alternate text" src="/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /&gt;
&lt;/div&gt;
</content><category term="oh"></category><category term="bar"></category><category term="yeah"></category></entry><entry><title>Unbelievable !</title><link href="/unbelievable.html" rel="alternate"></link><published>2010-10-15T20:30:00+00:00</published><updated>2010-10-15T20:30:00+00:00</updated><author><name></name></author><id>tag:None,2010-10-15:/unbelievable.html</id><summary type="html">&lt;p&gt;Or completely awesome. Depends the needs.&lt;/p&gt;
&lt;p&gt;&lt;a class="reference external" href="/a-markdown-powered-article.html"&gt;a root-relative link to markdown-article&lt;/a&gt;

View file

@ -3,12 +3,12 @@
&lt;h2&gt;Why not ?&lt;/h2&gt;
&lt;p&gt;After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst !
YEAH !&lt;/p&gt;
&lt;img alt="alternate text" src="|filename|/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /&gt;
&lt;img alt="alternate text" src="/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /&gt;
&lt;/div&gt;
</summary><content type="html">&lt;div class="section" id="why-not"&gt;
&lt;h2&gt;Why not ?&lt;/h2&gt;
&lt;p&gt;After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst !
YEAH !&lt;/p&gt;
&lt;img alt="alternate text" src="|filename|/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /&gt;
&lt;img alt="alternate text" src="/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /&gt;
&lt;/div&gt;
</content><category term="oh"></category><category term="bar"></category><category term="yeah"></category></entry></feed>

View file

@ -5,8 +5,8 @@ as well as &lt;strong&gt;inline markup&lt;/strong&gt;.&lt;/p&gt;
&lt;div class="section" id="this-is-a-simple-title"&gt;
&lt;h2&gt;This is a simple title&lt;/h2&gt;
&lt;p&gt;And here comes the cool &lt;a class="reference external" href="http://books.couchdb.org/relax/design-documents/views"&gt;stuff&lt;/a&gt;.&lt;/p&gt;
&lt;img alt="alternate text" src="|filename|/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /&gt;
&lt;img alt="alternate text" src="|filename|/pictures/Sushi_Macro.jpg" style="width: 600px; height: 450px;" /&gt;
&lt;img alt="alternate text" src="/pictures/Sushi.jpg" style="width: 600px; height: 450px;" /&gt;
&lt;img alt="alternate text" src="/pictures/Sushi_Macro.jpg" style="width: 600px; height: 450px;" /&gt;
&lt;pre class="literal-block"&gt;
&amp;gt;&amp;gt;&amp;gt; from ipdb import set_trace
&amp;gt;&amp;gt;&amp;gt; set_trace()

View file

@ -191,7 +191,7 @@ as well as <strong>inline markup</strong>.</p>
<h2>Why not ?</h2>
<p>After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst !
YEAH !</p>
<img alt="alternate text" src="|filename|/pictures/Sushi.jpg" style="width: 600px; height: 450px;" />
<img alt="alternate text" src="/pictures/Sushi.jpg" style="width: 600px; height: 450px;" />
</div>
<a class="readmore" href="/oh-yeah.html">read more</a>

View file

@ -43,7 +43,7 @@
<h2>Why not ?</h2>
<p>After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst !
YEAH !</p>
<img alt="alternate text" src="|filename|/pictures/Sushi.jpg" style="width: 600px; height: 450px;" />
<img alt="alternate text" src="/pictures/Sushi.jpg" style="width: 600px; height: 450px;" />
</div>
</div><!-- /.entry-content -->

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

View file

@ -90,7 +90,7 @@ as well as <strong>inline markup</strong>.</p>
<h2>Why not ?</h2>
<p>After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst !
YEAH !</p>
<img alt="alternate text" src="|filename|/pictures/Sushi.jpg" style="width: 600px; height: 450px;" />
<img alt="alternate text" src="/pictures/Sushi.jpg" style="width: 600px; height: 450px;" />
</div>
<a class="readmore" href="/oh-yeah.html">read more</a>

View file

@ -42,8 +42,8 @@
<div class="section" id="this-is-a-simple-title">
<h2>This is a simple title</h2>
<p>And here comes the cool <a class="reference external" href="http://books.couchdb.org/relax/design-documents/views">stuff</a>.</p>
<img alt="alternate text" src="|filename|/pictures/Sushi.jpg" style="width: 600px; height: 450px;" />
<img alt="alternate text" src="|filename|/pictures/Sushi_Macro.jpg" style="width: 600px; height: 450px;" />
<img alt="alternate text" src="/pictures/Sushi.jpg" style="width: 600px; height: 450px;" />
<img alt="alternate text" src="/pictures/Sushi_Macro.jpg" style="width: 600px; height: 450px;" />
<pre class="literal-block">
&gt;&gt;&gt; from ipdb import set_trace
&gt;&gt;&gt; set_trace()

View file

@ -38,7 +38,7 @@
<h2>Why not ?</h2>
<p>After all, why not ? It's pretty simple to do it, and it will allow me to write my blogposts in rst !
YEAH !</p>
<img alt="alternate text" src="|filename|/pictures/Sushi.jpg" style="width: 600px; height: 450px;" />
<img alt="alternate text" src="/pictures/Sushi.jpg" style="width: 600px; height: 450px;" />
</div>
</article>
</aside><!-- /#featured -->

View file

@ -47,8 +47,8 @@
<div class="section" id="this-is-a-simple-title">
<h2>This is a simple title</h2>
<p>And here comes the cool <a class="reference external" href="http://books.couchdb.org/relax/design-documents/views">stuff</a>.</p>
<img alt="alternate text" src="|filename|/pictures/Sushi.jpg" style="width: 600px; height: 450px;" />
<img alt="alternate text" src="|filename|/pictures/Sushi_Macro.jpg" style="width: 600px; height: 450px;" />
<img alt="alternate text" src="/pictures/Sushi.jpg" style="width: 600px; height: 450px;" />
<img alt="alternate text" src="/pictures/Sushi_Macro.jpg" style="width: 600px; height: 450px;" />
<pre class="literal-block">
&gt;&gt;&gt; from ipdb import set_trace
&gt;&gt;&gt; set_trace()

View file

@ -175,6 +175,15 @@ def get_settings(**kwargs):
return settings
def get_context(settings=None, **kwargs):
context = settings.copy() if settings else {}
context['generated_content'] = {}
context['static_links'] = set()
context['static_content'] = {}
context.update(kwargs)
return context
class LogCountHandler(BufferingHandler):
"""Capturing and counting logged messages."""

View file

@ -6,7 +6,7 @@ from shutil import rmtree
from tempfile import mkdtemp
from pelican.generators import ArticlesGenerator, PagesGenerator
from pelican.tests.support import get_settings, unittest
from pelican.tests.support import get_context, get_settings, unittest
try:
from unittest.mock import MagicMock
@ -29,7 +29,7 @@ class TestCache(unittest.TestCase):
rmtree(self.temp_cache)
def _get_cache_enabled_settings(self):
settings = get_settings(filenames={})
settings = get_settings()
settings['CACHE_CONTENT'] = True
settings['LOAD_CONTENT_CACHE'] = True
settings['CACHE_PATH'] = self.temp_cache
@ -42,20 +42,21 @@ class TestCache(unittest.TestCase):
settings['PAGE_PATHS'] = ['TestPages']
settings['DEFAULT_DATE'] = (1970, 1, 1)
settings['READERS'] = {'asc': None}
context = get_context(settings)
def sorted_titles(items):
return sorted(item.title for item in items)
# Articles
generator = ArticlesGenerator(
context=settings.copy(), settings=settings,
context=context.copy(), settings=settings,
path=CONTENT_DIR, theme=settings['THEME'], output_path=None)
generator.generate_context()
uncached_articles = sorted_titles(generator.articles)
uncached_drafts = sorted_titles(generator.drafts)
generator = ArticlesGenerator(
context=settings.copy(), settings=settings,
context=context.copy(), settings=settings,
path=CONTENT_DIR, theme=settings['THEME'], output_path=None)
generator.generate_context()
cached_articles = sorted_titles(generator.articles)
@ -66,7 +67,7 @@ class TestCache(unittest.TestCase):
# Pages
generator = PagesGenerator(
context=settings.copy(), settings=settings,
context=context.copy(), settings=settings,
path=CUR_DIR, theme=settings['THEME'], output_path=None)
generator.generate_context()
uncached_pages = sorted_titles(generator.pages)
@ -74,7 +75,7 @@ class TestCache(unittest.TestCase):
uncached_draft_pages = sorted_titles(generator.draft_pages)
generator = PagesGenerator(
context=settings.copy(), settings=settings,
context=context.copy(), settings=settings,
path=CUR_DIR, theme=settings['THEME'], output_path=None)
generator.generate_context()
cached_pages = sorted_titles(generator.pages)
@ -92,20 +93,21 @@ class TestCache(unittest.TestCase):
settings['PAGE_PATHS'] = ['TestPages']
settings['DEFAULT_DATE'] = (1970, 1, 1)
settings['READERS'] = {'asc': None}
context = get_context(settings)
def sorted_titles(items):
return sorted(item.title for item in items)
# Articles
generator = ArticlesGenerator(
context=settings.copy(), settings=settings,
context=context.copy(), settings=settings,
path=CONTENT_DIR, theme=settings['THEME'], output_path=None)
generator.generate_context()
uncached_articles = sorted_titles(generator.articles)
uncached_drafts = sorted_titles(generator.drafts)
generator = ArticlesGenerator(
context=settings.copy(), settings=settings,
context=context.copy(), settings=settings,
path=CONTENT_DIR, theme=settings['THEME'], output_path=None)
generator.generate_context()
cached_articles = sorted_titles(generator.articles)
@ -116,14 +118,14 @@ class TestCache(unittest.TestCase):
# Pages
generator = PagesGenerator(
context=settings.copy(), settings=settings,
context=context.copy(), settings=settings,
path=CUR_DIR, theme=settings['THEME'], output_path=None)
generator.generate_context()
uncached_pages = sorted_titles(generator.pages)
uncached_hidden_pages = sorted_titles(generator.hidden_pages)
generator = PagesGenerator(
context=settings.copy(), settings=settings,
context=context.copy(), settings=settings,
path=CUR_DIR, theme=settings['THEME'], output_path=None)
generator.generate_context()
cached_pages = sorted_titles(generator.pages)
@ -139,15 +141,16 @@ class TestCache(unittest.TestCase):
settings['CONTENT_CACHING_LAYER'] = 'generator'
settings['DEFAULT_DATE'] = (1970, 1, 1)
settings['READERS'] = {'asc': None}
context = get_context(settings)
generator = ArticlesGenerator(
context=settings.copy(), settings=settings,
context=context.copy(), settings=settings,
path=CONTENT_DIR, theme=settings['THEME'], output_path=None)
generator.generate_context()
self.assertTrue(hasattr(generator, '_cache'))
generator = ArticlesGenerator(
context=settings.copy(), settings=settings,
context=context.copy(), settings=settings,
path=CONTENT_DIR, theme=settings['THEME'], output_path=None)
generator.readers.read_file = MagicMock()
generator.generate_context()
@ -167,15 +170,16 @@ class TestCache(unittest.TestCase):
"""Test raw article content caching at the reader level"""
settings = self._get_cache_enabled_settings()
settings['READERS'] = {'asc': None}
context = get_context(settings)
generator = ArticlesGenerator(
context=settings.copy(), settings=settings,
context=context.copy(), settings=settings,
path=CONTENT_DIR, theme=settings['THEME'], output_path=None)
generator.generate_context()
self.assertTrue(hasattr(generator.readers, '_cache'))
generator = ArticlesGenerator(
context=settings.copy(), settings=settings,
context=context.copy(), settings=settings,
path=CONTENT_DIR, theme=settings['THEME'], output_path=None)
readers = generator.readers.readers
for reader in readers.values():
@ -191,9 +195,10 @@ class TestCache(unittest.TestCase):
used in --ignore-cache or autoreload mode"""
settings = self._get_cache_enabled_settings()
settings['READERS'] = {'asc': None}
context = get_context(settings)
generator = ArticlesGenerator(
context=settings.copy(), settings=settings,
context=context.copy(), settings=settings,
path=CONTENT_DIR, theme=settings['THEME'], output_path=None)
generator.readers.read_file = MagicMock()
generator.generate_context()
@ -202,7 +207,7 @@ class TestCache(unittest.TestCase):
settings['LOAD_CONTENT_CACHE'] = False
generator = ArticlesGenerator(
context=settings.copy(), settings=settings,
context=context.copy(), settings=settings,
path=CONTENT_DIR, theme=settings['THEME'], output_path=None)
generator.readers.read_file = MagicMock()
generator.generate_context()
@ -217,15 +222,16 @@ class TestCache(unittest.TestCase):
settings['CONTENT_CACHING_LAYER'] = 'generator'
settings['PAGE_PATHS'] = ['TestPages']
settings['READERS'] = {'asc': None}
context = get_context(settings)
generator = PagesGenerator(
context=settings.copy(), settings=settings,
context=context.copy(), settings=settings,
path=CUR_DIR, theme=settings['THEME'], output_path=None)
generator.generate_context()
self.assertTrue(hasattr(generator, '_cache'))
generator = PagesGenerator(
context=settings.copy(), settings=settings,
context=context.copy(), settings=settings,
path=CUR_DIR, theme=settings['THEME'], output_path=None)
generator.readers.read_file = MagicMock()
generator.generate_context()
@ -241,15 +247,16 @@ class TestCache(unittest.TestCase):
settings = self._get_cache_enabled_settings()
settings['PAGE_PATHS'] = ['TestPages']
settings['READERS'] = {'asc': None}
context = get_context(settings)
generator = PagesGenerator(
context=settings.copy(), settings=settings,
context=context.copy(), settings=settings,
path=CUR_DIR, theme=settings['THEME'], output_path=None)
generator.generate_context()
self.assertTrue(hasattr(generator.readers, '_cache'))
generator = PagesGenerator(
context=settings.copy(), settings=settings,
context=context.copy(), settings=settings,
path=CUR_DIR, theme=settings['THEME'], output_path=None)
readers = generator.readers.readers
for reader in readers.values():
@ -266,9 +273,10 @@ class TestCache(unittest.TestCase):
settings = self._get_cache_enabled_settings()
settings['PAGE_PATHS'] = ['TestPages']
settings['READERS'] = {'asc': None}
context = get_context(settings)
generator = PagesGenerator(
context=settings.copy(), settings=settings,
context=context.copy(), settings=settings,
path=CUR_DIR, theme=settings['THEME'], output_path=None)
generator.readers.read_file = MagicMock()
generator.generate_context()
@ -277,7 +285,7 @@ class TestCache(unittest.TestCase):
settings['LOAD_CONTENT_CACHE'] = False
generator = PagesGenerator(
context=settings.copy(), settings=settings,
context=context.copy(), settings=settings,
path=CUR_DIR, theme=settings['THEME'], output_path=None)
generator.readers.read_file = MagicMock()
generator.generate_context()

View file

@ -14,7 +14,8 @@ import six
from pelican.contents import Article, Author, Category, Page, Static, Tag
from pelican.settings import DEFAULT_CONFIG
from pelican.signals import content_object_init
from pelican.tests.support import LoggedTestCase, get_settings, unittest
from pelican.tests.support import LoggedTestCase, get_context, get_settings,\
unittest
from pelican.utils import SafeDatetime, path_to_url, truncate_html_words
@ -264,7 +265,7 @@ class TestPage(LoggedTestCase):
args = self.page_kwargs.copy()
args['settings'] = get_settings()
args['source_path'] = 'content'
args['context']['filenames'] = {'article.rst': article}
args['context']['generated_content'] = {'article.rst': article}
# Classic intrasite link via filename
args['content'] = (
@ -343,22 +344,24 @@ class TestPage(LoggedTestCase):
args = self.page_kwargs.copy()
args['settings'] = get_settings()
args['source_path'] = 'content'
args['context']['filenames'] = {
'images/poster.jpg': type(
cls_name, (object,), {'url': 'images/poster.jpg'}),
'assets/video.mp4': type(
cls_name, (object,), {'url': 'assets/video.mp4'}),
'images/graph.svg': type(
cls_name, (object,), {'url': 'images/graph.svg'}),
'reference.rst': type(
cls_name, (object,), {'url': 'reference.html'}),
args['context']['static_content'] = {
'images/poster.jpg':
type(cls_name, (object,), {'url': 'images/poster.jpg'}),
'assets/video.mp4':
type(cls_name, (object,), {'url': 'assets/video.mp4'}),
'images/graph.svg':
type(cls_name, (object,), {'url': 'images/graph.svg'}),
}
args['context']['generated_content'] = {
'reference.rst':
type(cls_name, (object,), {'url': 'reference.html'}),
}
# video.poster
args['content'] = (
'There is a video with poster '
'<video controls poster="{filename}/images/poster.jpg">'
'<source src="|filename|/assets/video.mp4" type="video/mp4">'
'<video controls poster="{static}/images/poster.jpg">'
'<source src="|static|/assets/video.mp4" type="video/mp4">'
'</video>'
)
content = Page(**args).get_content('http://notmyidea.org')
@ -374,7 +377,7 @@ class TestPage(LoggedTestCase):
# object.data
args['content'] = (
'There is a svg object '
'<object data="{filename}/images/graph.svg"'
'<object data="{static}/images/graph.svg"'
' type="image/svg+xml">'
'</object>'
)
@ -409,14 +412,15 @@ class TestPage(LoggedTestCase):
STATIC_URL='http://static.cool.site/{path}',
ARTICLE_URL='http://blog.cool.site/{slug}.html')
args['source_path'] = 'content'
args['context']['filenames'] = {
'images/poster.jpg': Static('',
settings=args['settings'],
source_path='images/poster.jpg'),
'article.rst': Article('',
settings=args['settings'],
metadata={'slug': 'article',
'title': 'Article'})
args['context']['static_content'] = {
'images/poster.jpg':
Static('', settings=args['settings'],
source_path='images/poster.jpg'),
}
args['context']['generated_content'] = {
'article.rst':
Article('', settings=args['settings'], metadata={
'slug': 'article', 'title': 'Article'})
}
# Article link will go to blog
@ -441,7 +445,7 @@ class TestPage(LoggedTestCase):
# Image link will go to static
args['content'] = (
'<img src="{filename}/images/poster.jpg"/>'
'<img src="{static}/images/poster.jpg"/>'
)
content = Page(**args).get_content('http://cool.site')
self.assertEqual(
@ -458,7 +462,7 @@ class TestPage(LoggedTestCase):
args = self.page_kwargs.copy()
args['settings'] = get_settings()
args['source_path'] = 'content'
args['context']['filenames'] = {'article spaces.rst': article}
args['context']['generated_content'] = {'article spaces.rst': article}
# An intrasite link via filename with %20 as a space
args['content'] = (
@ -472,6 +476,55 @@ class TestPage(LoggedTestCase):
'<a href="http://notmyidea.org/article-spaces.html">link</a>'
)
def test_intrasite_link_source_and_generated(self):
"""Test linking both to the source and the generated article
"""
cls_name = '_DummyAsset' if six.PY3 else b'_DummyAsset'
args = self.page_kwargs.copy()
args['settings'] = get_settings()
args['source_path'] = 'content'
args['context']['generated_content'] = {
'article.rst': type(cls_name, (object,), {'url': 'article.html'})}
args['context']['static_content'] = {
'article.rst': type(cls_name, (object,), {'url': 'article.rst'})}
args['content'] = (
'A simple test, with a link to an'
'<a href="{filename}article.rst">article</a> and its'
'<a href="{static}article.rst">source</a>'
)
content = Page(**args).get_content('http://notmyidea.org')
self.assertEqual(
content,
'A simple test, with a link to an'
'<a href="http://notmyidea.org/article.html">article</a> and its'
'<a href="http://notmyidea.org/article.rst">source</a>'
)
def test_intrasite_link_to_static_content_with_filename(self):
"""Test linking to a static resource with deprecated {filename}
"""
cls_name = '_DummyAsset' if six.PY3 else b'_DummyAsset'
args = self.page_kwargs.copy()
args['settings'] = get_settings()
args['source_path'] = 'content'
args['context']['static_content'] = {
'poster.jpg':
type(cls_name, (object,), {'url': 'images/poster.jpg'})}
args['content'] = (
'A simple test, with a link to a'
'<a href="{filename}poster.jpg">poster</a>'
)
content = Page(**args).get_content('http://notmyidea.org')
self.assertEqual(
content,
'A simple test, with a link to a'
'<a href="http://notmyidea.org/images/poster.jpg">poster</a>'
)
def test_multiple_authors(self):
"""Test article with multiple authors."""
args = self.page_kwargs.copy()
@ -599,13 +652,13 @@ class TestStatic(LoggedTestCase):
STATIC_URL='{path}',
PAGE_SAVE_AS=os.path.join('outpages', '{slug}.html'),
PAGE_URL='outpages/{slug}.html')
self.context = self.settings.copy()
self.context = get_context(self.settings)
self.static = Static(content=None, metadata={}, settings=self.settings,
source_path=posix_join('dir', 'foo.jpg'),
context=self.context)
self.context['filenames'] = {self.static.source_path: self.static}
self.context['static_content'][self.static.source_path] = self.static
def tearDown(self):
pass
@ -674,7 +727,7 @@ class TestStatic(LoggedTestCase):
def test_attach_to_does_nothing_after_save_as_referenced(self):
"""attach_to() does nothing if the save_as was already referenced.
(For example, by a {filename} link an a document processed earlier.)
(For example, by a {static} link an a document processed earlier.)
"""
original_save_as = self.static.save_as
@ -690,7 +743,7 @@ class TestStatic(LoggedTestCase):
def test_attach_to_does_nothing_after_url_referenced(self):
"""attach_to() does nothing if the url was already referenced.
(For example, by a {filename} link an a document processed earlier.)
(For example, by a {static} link an a document processed earlier.)
"""
original_url = self.static.url

View file

@ -10,7 +10,7 @@ from tempfile import mkdtemp
from pelican.generators import (ArticlesGenerator, Generator, PagesGenerator,
PelicanTemplateNotFound, StaticGenerator,
TemplatePagesGenerator)
from pelican.tests.support import get_settings, unittest
from pelican.tests.support import get_context, get_settings, unittest
from pelican.writers import Writer
try:
@ -178,14 +178,15 @@ class TestArticlesGenerator(unittest.TestCase):
@classmethod
def setUpClass(cls):
settings = get_settings(filenames={})
settings = get_settings()
settings['DEFAULT_CATEGORY'] = 'Default'
settings['DEFAULT_DATE'] = (1970, 1, 1)
settings['READERS'] = {'asc': None}
settings['CACHE_CONTENT'] = False
context = get_context(settings)
cls.generator = ArticlesGenerator(
context=settings.copy(), settings=settings,
context=context, settings=settings,
path=CONTENT_DIR, theme=settings['THEME'], output_path=None)
cls.generator.generate_context()
cls.articles = cls.distill_articles(cls.generator.articles)
@ -299,15 +300,15 @@ class TestArticlesGenerator(unittest.TestCase):
self.assertEqual(sorted(categories), sorted(categories_expected))
def test_do_not_use_folder_as_category(self):
settings = get_settings(filenames={})
settings = get_settings()
settings['DEFAULT_CATEGORY'] = 'Default'
settings['DEFAULT_DATE'] = (1970, 1, 1)
settings['USE_FOLDER_AS_CATEGORY'] = False
settings['CACHE_PATH'] = self.temp_cache
settings['READERS'] = {'asc': None}
settings['filenames'] = {}
context = get_context(settings)
generator = ArticlesGenerator(
context=settings.copy(), settings=settings,
context=context, settings=settings,
path=CONTENT_DIR, theme=settings['THEME'], output_path=None)
generator.generate_context()
# test for name
@ -328,15 +329,16 @@ class TestArticlesGenerator(unittest.TestCase):
@unittest.skipUnless(MagicMock, 'Needs Mock module')
def test_direct_templates_save_as_url_default(self):
settings = get_settings(filenames={})
settings = get_settings()
settings['CACHE_PATH'] = self.temp_cache
context = get_context(settings)
generator = ArticlesGenerator(
context=settings, settings=settings,
context=context, settings=settings,
path=None, theme=settings['THEME'], output_path=None)
write = MagicMock()
generator.generate_direct_templates(write)
write.assert_called_with("archives.html",
generator.get_template("archives"), settings,
generator.get_template("archives"), context,
articles=generator.articles,
dates=generator.dates, blog=True,
template_name='archives',
@ -396,13 +398,14 @@ class TestArticlesGenerator(unittest.TestCase):
"""
old_locale = locale.setlocale(locale.LC_ALL)
locale.setlocale(locale.LC_ALL, str('C'))
settings = get_settings(filenames={})
settings = get_settings()
settings['YEAR_ARCHIVE_SAVE_AS'] = 'posts/{date:%Y}/index.html'
settings['YEAR_ARCHIVE_URL'] = 'posts/{date:%Y}/'
settings['CACHE_PATH'] = self.temp_cache
context = get_context(settings)
generator = ArticlesGenerator(
context=settings, settings=settings,
context=context, settings=settings,
path=CONTENT_DIR, theme=settings['THEME'], output_path=None)
generator.generate_context()
write = MagicMock()
@ -411,20 +414,20 @@ class TestArticlesGenerator(unittest.TestCase):
articles = [d for d in generator.articles if d.date.year == 1970]
self.assertEqual(len(dates), 1)
# among other things it must have at least been called with this
settings["period"] = (1970,)
context["period"] = (1970,)
write.assert_called_with("posts/1970/index.html",
generator.get_template("period_archives"),
settings, blog=True, articles=articles,
context, blog=True, articles=articles,
dates=dates, template_name='period_archives',
url="posts/1970/")
del settings["period"]
settings['MONTH_ARCHIVE_SAVE_AS'] = \
'posts/{date:%Y}/{date:%b}/index.html'
settings['MONTH_ARCHIVE_URL'] = \
'posts/{date:%Y}/{date:%b}/'
context = get_context(settings)
generator = ArticlesGenerator(
context=settings, settings=settings,
context=context, settings=settings,
path=CONTENT_DIR, theme=settings['THEME'], output_path=None)
generator.generate_context()
write = MagicMock()
@ -434,21 +437,21 @@ class TestArticlesGenerator(unittest.TestCase):
articles = [d for d in generator.articles
if d.date.year == 1970 and d.date.month == 1]
self.assertEqual(len(dates), 1)
settings["period"] = (1970, "January")
context["period"] = (1970, "January")
# among other things it must have at least been called with this
write.assert_called_with("posts/1970/Jan/index.html",
generator.get_template("period_archives"),
settings, blog=True, articles=articles,
context, blog=True, articles=articles,
dates=dates, template_name='period_archives',
url="posts/1970/Jan/")
del settings["period"]
settings['DAY_ARCHIVE_SAVE_AS'] = \
'posts/{date:%Y}/{date:%b}/{date:%d}/index.html'
settings['DAY_ARCHIVE_URL'] = \
'posts/{date:%Y}/{date:%b}/{date:%d}/'
context = get_context(settings)
generator = ArticlesGenerator(
context=settings, settings=settings,
context=context, settings=settings,
path=CONTENT_DIR, theme=settings['THEME'], output_path=None)
generator.generate_context()
write = MagicMock()
@ -466,20 +469,21 @@ class TestArticlesGenerator(unittest.TestCase):
d.date.day == 1
]
self.assertEqual(len(dates), 1)
settings["period"] = (1970, "January", 1)
context["period"] = (1970, "January", 1)
# among other things it must have at least been called with this
write.assert_called_with("posts/1970/Jan/01/index.html",
generator.get_template("period_archives"),
settings, blog=True, articles=articles,
context, blog=True, articles=articles,
dates=dates, template_name='period_archives',
url="posts/1970/Jan/01/")
locale.setlocale(locale.LC_ALL, old_locale)
def test_nonexistent_template(self):
"""Attempt to load a non-existent template"""
settings = get_settings(filenames={})
settings = get_settings()
context = get_context(settings)
generator = ArticlesGenerator(
context=settings, settings=settings,
context=context, settings=settings,
path=None, theme=settings['THEME'], output_path=None)
self.assertRaises(Exception, generator.get_template, "not_a_template")
@ -497,7 +501,7 @@ class TestArticlesGenerator(unittest.TestCase):
self.assertEqual(sorted(authors), sorted(authors_expected))
def test_standard_metadata_in_default_metadata(self):
settings = get_settings(filenames={})
settings = get_settings()
settings['CACHE_CONTENT'] = False
settings['DEFAULT_CATEGORY'] = 'Default'
settings['DEFAULT_DATE'] = (1970, 1, 1)
@ -506,8 +510,9 @@ class TestArticlesGenerator(unittest.TestCase):
# DEFAULT_CATEGORY
('category', 'Random'),
('tags', 'general, untagged'))
context = get_context(settings)
generator = ArticlesGenerator(
context=settings.copy(), settings=settings,
context=context, settings=settings,
path=CONTENT_DIR, theme=settings['THEME'], output_path=None)
generator.generate_context()
@ -530,13 +535,14 @@ class TestArticlesGenerator(unittest.TestCase):
self.assertEqual(tags, tags_expected)
def test_article_order_by(self):
settings = get_settings(filenames={})
settings = get_settings()
settings['DEFAULT_CATEGORY'] = 'Default'
settings['DEFAULT_DATE'] = (1970, 1, 1)
settings['ARTICLE_ORDER_BY'] = 'title'
context = get_context(settings)
generator = ArticlesGenerator(
context=settings.copy(), settings=settings,
context=context, settings=settings,
path=CONTENT_DIR, theme=settings['THEME'], output_path=None)
generator.generate_context()
@ -575,13 +581,14 @@ class TestArticlesGenerator(unittest.TestCase):
self.assertEqual(articles, expected)
# reversed title
settings = get_settings(filenames={})
settings = get_settings()
settings['DEFAULT_CATEGORY'] = 'Default'
settings['DEFAULT_DATE'] = (1970, 1, 1)
settings['ARTICLE_ORDER_BY'] = 'reversed-title'
context = get_context(settings)
generator = ArticlesGenerator(
context=settings.copy(), settings=settings,
context=context, settings=settings,
path=CONTENT_DIR, theme=settings['THEME'], output_path=None)
generator.generate_context()
@ -605,13 +612,14 @@ class TestPageGenerator(unittest.TestCase):
return [[page.title, page.status, page.template] for page in pages]
def test_generate_context(self):
settings = get_settings(filenames={})
settings = get_settings()
settings['CACHE_PATH'] = self.temp_cache
settings['PAGE_PATHS'] = ['TestPages'] # relative to CUR_DIR
settings['DEFAULT_DATE'] = (1970, 1, 1)
context = get_context(settings)
generator = PagesGenerator(
context=settings.copy(), settings=settings,
context=context, settings=settings,
path=CUR_DIR, theme=settings['THEME'], output_path=None)
generator.generate_context()
pages = self.distill_pages(generator.pages)
@ -624,6 +632,7 @@ class TestPageGenerator(unittest.TestCase):
['This is a test page with a preset template', 'published',
'custom'],
['Page with a bunch of links', 'published', 'page'],
['Page with static links', 'published', 'page'],
['A Page (Test) for sorting', 'published', 'page'],
]
hidden_pages_expected = [
@ -653,10 +662,11 @@ class TestPageGenerator(unittest.TestCase):
sorted(self.distill_pages(generator.context['draft_pages'])))
def test_generate_sorted(self):
settings = get_settings(filenames={})
settings = get_settings()
settings['PAGE_PATHS'] = ['TestPages'] # relative to CUR_DIR
settings['CACHE_PATH'] = self.temp_cache
settings['DEFAULT_DATE'] = (1970, 1, 1)
context = get_context(settings)
# default sort (filename)
pages_expected_sorted_by_filename = [
@ -664,11 +674,12 @@ class TestPageGenerator(unittest.TestCase):
['This is a markdown test page', 'published', 'page'],
['A Page (Test) for sorting', 'published', 'page'],
['Page with a bunch of links', 'published', 'page'],
['Page with static links', 'published', 'page'],
['This is a test page with a preset template', 'published',
'custom'],
]
generator = PagesGenerator(
context=settings.copy(), settings=settings,
context=context, settings=settings,
path=CUR_DIR, theme=settings['THEME'], output_path=None)
generator.generate_context()
pages = self.distill_pages(generator.pages)
@ -678,14 +689,16 @@ class TestPageGenerator(unittest.TestCase):
pages_expected_sorted_by_title = [
['A Page (Test) for sorting', 'published', 'page'],
['Page with a bunch of links', 'published', 'page'],
['Page with static links', 'published', 'page'],
['This is a markdown test page', 'published', 'page'],
['This is a test page', 'published', 'page'],
['This is a test page with a preset template', 'published',
'custom'],
]
settings['PAGE_ORDER_BY'] = 'title'
context = get_context(settings)
generator = PagesGenerator(
context=settings.copy(), settings=settings,
context=context.copy(), settings=settings,
path=CUR_DIR, theme=settings['THEME'], output_path=None)
generator.generate_context()
pages = self.distill_pages(generator.pages)
@ -697,12 +710,14 @@ class TestPageGenerator(unittest.TestCase):
'custom'],
['This is a test page', 'published', 'page'],
['This is a markdown test page', 'published', 'page'],
['Page with static links', 'published', 'page'],
['Page with a bunch of links', 'published', 'page'],
['A Page (Test) for sorting', 'published', 'page'],
]
settings['PAGE_ORDER_BY'] = 'reversed-title'
context = get_context(settings)
generator = PagesGenerator(
context=settings.copy(), settings=settings,
context=context, settings=settings,
path=CUR_DIR, theme=settings['THEME'], output_path=None)
generator.generate_context()
pages = self.distill_pages(generator.pages)
@ -713,21 +728,43 @@ class TestPageGenerator(unittest.TestCase):
Test to ensure links of the form {tag}tagname and {category}catname
are generated correctly on pages
"""
settings = get_settings(filenames={})
settings = get_settings()
settings['PAGE_PATHS'] = ['TestPages'] # relative to CUR_DIR
settings['CACHE_PATH'] = self.temp_cache
settings['DEFAULT_DATE'] = (1970, 1, 1)
context = get_context(settings)
generator = PagesGenerator(
context=settings.copy(), settings=settings,
context=context, settings=settings,
path=CUR_DIR, theme=settings['THEME'], output_path=None)
generator.generate_context()
pages_by_title = {p.title: p.content for p in generator.pages}
pages_by_title = {p.title: p for p in generator.pages}
test_content = pages_by_title['Page with a bunch of links']
test_content = pages_by_title['Page with a bunch of links'].content
self.assertIn('<a href="/category/yeah.html">', test_content)
self.assertIn('<a href="/tag/matsuku.html">', test_content)
def test_static_and_attach_links_on_generated_pages(self):
"""
Test to ensure links of the form {static}filename and {attach}filename
are included in context['static_links']
"""
settings = get_settings()
settings['PAGE_PATHS'] = ['TestPages/page_with_static_links.md']
settings['CACHE_PATH'] = self.temp_cache
settings['DEFAULT_DATE'] = (1970, 1, 1)
context = get_context(settings)
generator = PagesGenerator(
context=context, settings=settings,
path=CUR_DIR, theme=settings['THEME'], output_path=None)
generator.generate_context()
self.assertIn('pelican/tests/TestPages/image0.jpg',
context['static_links'])
self.assertIn('pelican/tests/TestPages/image1.jpg',
context['static_links'])
class TestTemplatePagesGenerator(unittest.TestCase):
@ -791,7 +828,7 @@ class TestStaticGenerator(unittest.TestCase):
"static", "staticfile")
self.endfile = os.path.join(self.temp_output, "static", "staticfile")
self.generator = StaticGenerator(
context={'filenames': {}},
context=get_context(),
settings=self.settings,
path=self.temp_content,
theme="",
@ -808,11 +845,8 @@ class TestStaticGenerator(unittest.TestCase):
def test_theme_static_paths_dirs(self):
"""Test that StaticGenerator properly copies also files mentioned in
TEMPLATE_STATIC_PATHS, not just directories."""
settings = get_settings(
PATH=self.content_path,
filenames={})
context = settings.copy()
context['staticfiles'] = []
settings = get_settings(PATH=self.content_path)
context = get_context(settings, staticfiles=[])
StaticGenerator(
context=context, settings=settings,
@ -831,10 +865,8 @@ class TestStaticGenerator(unittest.TestCase):
TEMPLATE_STATIC_PATHS, not just directories."""
settings = get_settings(
PATH=self.content_path,
THEME_STATIC_PATHS=['static/css/fonts.css', 'static/fonts/'],
filenames={})
context = settings.copy()
context['staticfiles'] = []
THEME_STATIC_PATHS=['static/css/fonts.css', 'static/fonts/'],)
context = get_context(settings, staticfiles=[])
StaticGenerator(
context=context, settings=settings,
@ -869,9 +901,8 @@ class TestStaticGenerator(unittest.TestCase):
settings = get_settings(
STATIC_EXCLUDES=['subdir'],
PATH=self.content_path,
STATIC_PATHS=[''],
filenames={})
context = settings.copy()
STATIC_PATHS=[''],)
context = get_context(settings)
StaticGenerator(
context=context, settings=settings,
@ -897,9 +928,8 @@ class TestStaticGenerator(unittest.TestCase):
PATH=self.content_path,
PAGE_PATHS=[''],
STATIC_PATHS=[''],
CACHE_CONTENT=False,
filenames={})
context = settings.copy()
CACHE_CONTENT=False,)
context = get_context(settings)
for generator_class in (PagesGenerator, StaticGenerator):
generator_class(
@ -915,8 +945,7 @@ class TestStaticGenerator(unittest.TestCase):
"STATIC_EXCLUDE_SOURCES=True failed to exclude a markdown file")
settings.update(STATIC_EXCLUDE_SOURCES=False)
context = settings.copy()
context['filenames'] = {}
context = get_context(settings)
for generator_class in (PagesGenerator, StaticGenerator):
generator_class(
@ -931,6 +960,40 @@ class TestStaticGenerator(unittest.TestCase):
any(name.endswith(".md") for name in staticnames),
"STATIC_EXCLUDE_SOURCES=False failed to include a markdown file")
def test_static_links(self):
"""Test that StaticGenerator uses files in static_links
"""
settings = get_settings(
STATIC_EXCLUDES=['subdir'],
PATH=self.content_path,
STATIC_PATHS=[],)
context = get_context(settings)
context['static_links'] |= {'short_page.md', 'subdir_fake_image.jpg'}
StaticGenerator(
context=context, settings=settings,
path=settings['PATH'], output_path=self.temp_output,
theme=settings['THEME']).generate_context()
staticfiles_names = [
os.path.basename(c.source_path) for c in context['staticfiles']]
static_content_names = [
os.path.basename(c) for c in context['static_content']]
self.assertIn(
'short_page.md', staticfiles_names,
"StaticGenerator skipped a file that it should have included")
self.assertIn(
'short_page.md', static_content_names,
"StaticGenerator skipped a file that it should have included")
self.assertIn(
'subdir_fake_image.jpg', staticfiles_names,
"StaticGenerator skipped a file that it should have included")
self.assertIn(
'subdir_fake_image.jpg', static_content_names,
"StaticGenerator skipped a file that it should have included")
def test_copy_one_file(self):
with open(self.startfile, "w") as f:
f.write("staticcontent")

View file

@ -112,7 +112,7 @@ class TestPelican(LoggedTestCase):
self.assertDirsEqual(
self.temp_path, os.path.join(OUTPUT_PATH, 'basic'))
self.assertLogCountEqual(
count=3,
count=1,
msg="Unable to find.*skipping url replacement",
level=logging.WARNING)

View file

@ -761,7 +761,7 @@ def update_links_to_attached_files(content, attachments):
http_url = old_url.replace('https://', 'http://')
https_url = old_url.replace('http://', 'https://')
for url in [http_url, https_url]:
content = content.replace(url, '{filename}' + new_path)
content = content.replace(url, '{static}' + new_path)
return content

View file

@ -435,7 +435,7 @@ def path_to_url(path):
def posixize_path(rel_path):
"""Use '/' as path separator, so that source references,
like '{filename}/foo/bar.jpg' or 'extras/favicon.ico',
like '{static}/foo/bar.jpg' or 'extras/favicon.ico',
will work on Windows as well as on Mac and Linux."""
return rel_path.replace(os.sep, '/')