Merge branch 'master' into fix-functional-tests

Conflicts:
	tests/test_generators.py
This commit is contained in:
Bruno Binet 2012-05-12 00:19:14 +02:00
commit ebfdabf2d7
25 changed files with 528 additions and 234 deletions

View file

@ -39,7 +39,7 @@ Usage
"""""
| pelican-import [-h] [--wpfile] [--dotclear] [--feed] [-o OUTPUT]
| [--dir-cat]
| [-m MARKUP][--dir-cat]
| input
Optional arguments
@ -51,6 +51,7 @@ Optional arguments
--feed Feed to parse
-o OUTPUT, --output OUTPUT
Output path
-m MARKUP Output markup
--dir-cat Put files in directories with categories name
Examples

View file

@ -23,6 +23,7 @@ Pelican currently supports:
* Publication of articles in multiple languages
* Atom/RSS feeds
* Code syntax highlighting
* Compilation of less css (optional)
* Import from WordPress, Dotclear, or RSS feeds
* Integration with external tools: Twitter, Google Analytics, etc. (optional)

View file

@ -21,9 +21,9 @@ Here is a list of settings for Pelican:
Basic settings
==============
================================================ =====================================================
===================================================================== =====================================================================
Setting name (default value) What does it do?
================================================ =====================================================
===================================================================== =====================================================================
`AUTHOR` Default author (put your name)
`DATE_FORMATS` (``{}``) If you do manage multiple languages, you can
set the date formatting here. See "Date format and locales"
@ -82,10 +82,20 @@ Setting name (default value) What does it do?
generated HTML, using the `Typogrify
<http://static.mintchaos.com/projects/typogrify/>`_
library
================================================ =====================================================
`LESS_GENERATOR` (``FALSE``) Set to True or complete path to `lessc` (if not
found in system PATH) to enable compiling less
css files. Requires installation of `less css`_.
`DIRECT_TEMPLATES` (``('index', 'tags', 'categories', 'archives')``) List of templates that are used directly to render
content. Typically direct templates are used to generate
index pages for collections of content e.g. tags and
category index pages.
`PAGINATED_DIRECT_TEMPLATES` (``('index',)``) Provides the direct templates that should be paginated.
===================================================================== =====================================================================
.. [#] Default is the system locale.
.. _less css: http://lesscss.org/
URL settings
------------
@ -96,9 +106,10 @@ your articles in a location such as '{slug}/index.html' and link to them as
'{slug}' for clean URLs. These settings give you the flexibility to place your
articles and pages anywhere you want.
Note: If you specify a datetime directive, it will be substituted using the
input files' date metadata attribute. If the date is not specified for a
particular file, Pelican will rely on the file's mtime timestamp.
.. note::
If you specify a datetime directive, it will be substituted using the
input files' date metadata attribute. If the date is not specified for a
particular file, Pelican will rely on the file's mtime timestamp.
Check the Python datetime documentation at http://bit.ly/cNcJUC for more
information.
@ -140,8 +151,15 @@ Setting name (default value) what does it do?
`CATEGORY_SAVE_AS` ('category/{name}.html') The location to save a category.
`TAG_URL` ('tag/{name}.html') The URL to use for a tag.
`TAG_SAVE_AS` ('tag/{name}.html') The location to save the tag page.
`<DIRECT_TEMPLATE_NAME>_SAVE_AS` The location to save content generated from direct
templates. Where <DIRECT_TEMPLATE_NAME> is the
upper case template name.
================================================ =====================================================
.. note::
When any of `*_SAVE_AS` is set to False, files will not be created.
Timezone
--------

View file

@ -6,7 +6,7 @@ import logging
import argparse
from pelican.generators import (ArticlesGenerator, PagesGenerator,
StaticGenerator, PdfGenerator)
StaticGenerator, PdfGenerator, LessCSSGenerator)
from pelican.log import init
from pelican.settings import read_settings, _DEFAULT_CONFIG
from pelican.utils import clean_output_dir, files_changed
@ -134,6 +134,8 @@ class Pelican(object):
generators = [ArticlesGenerator, PagesGenerator, StaticGenerator]
if self.settings['PDF_GENERATOR']:
generators.append(PdfGenerator)
if self.settings['LESS_GENERATOR']: # can be True or PATH to lessc
generators.append(LessCSSGenerator)
return generators
def get_writer(self):

View file

@ -183,7 +183,12 @@ class URLWrapper(object):
def _from_settings(self, key):
setting = "%s_%s" % (self.__class__.__name__.upper(), key)
return unicode(self.settings[setting]).format(**self.as_dict())
value = self.settings[setting]
if not isinstance(value, basestring):
logger.warning(u'%s is set to %s' % (setting, value))
return value
else:
return unicode(value).format(**self.as_dict())
url = property(functools.partial(_from_settings, key='URL'))
save_as = property(functools.partial(_from_settings, key='SAVE_AS'))

View file

@ -4,6 +4,7 @@ import math
import random
import logging
import datetime
import subprocess
from collections import defaultdict
from functools import partial
@ -162,31 +163,32 @@ class ArticlesGenerator(Generator):
writer.write_feed(items, self.context,
self.settings['TRANSLATION_FEED'] % lang)
def generate_pages(self, writer):
"""Generate the pages on the disk"""
write = partial(writer.write_file,
relative_urls=self.settings.get('RELATIVE_URLS'))
# to minimize the number of relative path stuff modification
# in writer, articles pass first
def generate_articles(self, write):
"""Generate the articles."""
article_template = self.get_template('article')
for article in chain(self.translations, self.articles):
write(article.save_as,
article_template, self.context, article=article,
category=article.category)
def generate_direct_templates(self, write):
"""Generate direct templates pages"""
PAGINATED_TEMPLATES = self.settings.get('PAGINATED_DIRECT_TEMPLATES')
for template in self.settings.get('DIRECT_TEMPLATES'):
paginated = {}
if template in PAGINATED_TEMPLATES:
paginated = {'articles': self.articles, 'dates': self.dates}
save_as = self.settings.get("%s_SAVE_AS" % template.upper(),
'%s.html' % template)
if not save_as:
continue
write('%s.html' % template, self.get_template(template),
write(save_as, self.get_template(template),
self.context, blog=True, paginated=paginated,
page_name=template)
# and subfolders after that
def generate_tags(self, write):
"""Generate Tags pages."""
tag_template = self.get_template('tag')
for tag, articles in self.tags.items():
articles.sort(key=attrgetter('date'), reverse=True)
@ -196,6 +198,8 @@ class ArticlesGenerator(Generator):
paginated={'articles': articles, 'dates': dates},
page_name=u'tag/%s' % tag)
def generate_categories(self, write):
"""Generate category pages."""
category_template = self.get_template('category')
for cat, articles in self.categories:
dates = [article for article in self.dates if article in articles]
@ -204,6 +208,8 @@ class ArticlesGenerator(Generator):
paginated={'articles': articles, 'dates': dates},
page_name=u'category/%s' % cat)
def generate_authors(self, write):
"""Generate Author pages."""
author_template = self.get_template('author')
for aut, articles in self.authors:
dates = [article for article in self.dates if article in articles]
@ -212,10 +218,30 @@ class ArticlesGenerator(Generator):
paginated={'articles': articles, 'dates': dates},
page_name=u'author/%s' % aut)
def generate_drafts(self, write):
"""Generate drafts pages."""
article_template = self.get_template('article')
for article in self.drafts:
write('drafts/%s.html' % article.slug, article_template,
self.context, article=article, category=article.category)
def generate_pages(self, writer):
"""Generate the pages on the disk"""
write = partial(writer.write_file,
relative_urls=self.settings.get('RELATIVE_URLS'))
# to minimize the number of relative path stuff modification
# in writer, articles pass first
self.generate_articles(write)
self.generate_direct_templates(write)
# and subfolders after that
self.generate_tags(write)
self.generate_categories(write)
self.generate_authors(write)
self.generate_drafts(write)
def generate_context(self):
"""change the context"""
@ -416,3 +442,50 @@ class PdfGenerator(Generator):
for page in self.context['pages']:
self._create_pdf(page, pdf_path)
class LessCSSGenerator(Generator):
"""Compile less css files."""
def _compile(self, less_file, source_dir, dest_dir):
base = os.path.relpath(less_file, source_dir)
target = os.path.splitext(
os.path.join(dest_dir, base))[0] + '.css'
target_dir = os.path.dirname(target)
if not os.path.exists(target_dir):
try:
os.makedirs(target_dir)
except OSError:
logger.error("Couldn't create the less css output folder in " +
target_dir)
subprocess.call([self._lessc, less_file, target])
logger.info(u' [ok] compiled %s' % base)
def generate_output(self, writer=None):
logger.info(u' Compiling less css')
# store out compiler here, so it won't be evaulted on each run of
# _compile
lg = self.settings['LESS_GENERATOR']
self._lessc = lg if isinstance(lg, basestring) else 'lessc'
# walk static paths
for static_path in self.settings['STATIC_PATHS']:
for f in self.get_files(
os.path.join(self.path, static_path),
extensions=['less']):
self._compile(f, self.path, self.output_path)
# walk theme static paths
theme_output_path = os.path.join(self.output_path, 'theme')
for static_path in self.settings['THEME_STATIC_PATHS']:
theme_static_path = os.path.join(self.theme, static_path)
for f in self.get_files(
theme_static_path,
extensions=['less']):
self._compile(f, theme_static_path, theme_output_path)

View file

@ -65,7 +65,7 @@ def render_node_to_html(document, node):
class RstReader(Reader):
enabled = bool(docutils)
extension = "rst"
file_extensions = ['rst']
def _parse_metadata(self, document):
"""Return the dict containing document metadata"""
@ -111,7 +111,7 @@ class RstReader(Reader):
class MarkdownReader(Reader):
enabled = bool(Markdown)
extension = "md"
file_extensions = ['md', 'markdown', 'mkd']
extensions = ['codehilite', 'extra']
def read(self, filename):
@ -128,7 +128,7 @@ class MarkdownReader(Reader):
class HtmlReader(Reader):
extension = "html"
file_extensions = ['html', 'htm']
_re = re.compile('\<\!\-\-\#\s?[A-z0-9_-]*\s?\:s?[A-z0-9\s_-]*\s?\-\-\>')
def read(self, filename):
@ -144,7 +144,11 @@ class HtmlReader(Reader):
return content, metadata
_EXTENSIONS = dict((cls.extension, cls) for cls in Reader.__subclasses__())
_EXTENSIONS = {}
for cls in Reader.__subclasses__():
for ext in cls.file_extensions:
_EXTENSIONS[ext] = cls
def read_file(filename, fmt=None, settings=None):
@ -170,5 +174,6 @@ def read_file(filename, fmt=None, settings=None):
if settings and settings['TYPOGRIFY']:
from typogrify import Typogrify
content = Typogrify.typogrify(content)
metadata['title'] = Typogrify.typogrify(metadata['title'])
return content, metadata

View file

@ -43,8 +43,8 @@ _DEFAULT_CONFIG = {'PATH': '.',
'PAGE_SAVE_AS': 'pages/{slug}.html',
'PAGE_LANG_URL': 'pages/{slug}-{lang}.html',
'PAGE_LANG_SAVE_AS': 'pages/{slug}-{lang}.html',
'CATEGORY_URL': 'category/{name}.html',
'CATEGORY_SAVE_AS': 'category/{name}.html',
'CATEGORY_URL': 'category/{slug}.html',
'CATEGORY_SAVE_AS': 'category/{slug}.html',
'TAG_URL': 'tag/{slug}.html',
'TAG_SAVE_AS': 'tag/{slug}.html',
'AUTHOR_URL': u'author/{slug}.html',
@ -67,6 +67,7 @@ _DEFAULT_CONFIG = {'PATH': '.',
'DEFAULT_STATUS': 'published',
'ARTICLE_PERMALINK_STRUCTURE': '',
'TYPOGRIFY': False,
'LESS_GENERATOR': False,
}

View file

@ -4,13 +4,17 @@ body {
font:1.3em/1.3 "Hoefler Text","Georgia",Georgia,serif,sans-serif;
}
.body, #banner nav, #banner nav ul, #about, #featured, #content{
width: inherit;
.post-info{
display: none;
}
#banner nav {
display: none;
-moz-border-radius: 0px;
margin-bottom: 0px;
margin-bottom: 20px;
overflow: hidden;
font-size: 1em;
background: #F5F4EF;
}
#banner nav ul{
@ -19,10 +23,11 @@ body {
#banner nav li{
float: right;
color: #000;
}
#banner nav li:first-child a {
-moz-border-radius: 0px;
#banner nav li a {
color: #000;
}
#banner h1 {

Binary file not shown.

After

Width:  |  Height:  |  Size: 300 B

View file

@ -6,7 +6,7 @@
<dl>
{% for article in dates %}
<dt>{{ article.locale_date }}</dt>
<dd><a href="{{ article.url }}">{{ article.title }}</a></dd>
<dd><a href="{{ SITEURL }}/{{ article.url }}">{{ article.title }}</a></dd>
{% endfor %}
</dl>
</section>

View file

@ -1,11 +1,15 @@
{% extends "base.html" %}
{% block title %}{{ article.title }}{% endblock %}
{% block title %}{{ article.title|striptags }}{% endblock %}
{% block content %}
<section id="content" class="body">
<article>
<header> <h1 class="entry-title"><a href="{{ pagename }}"
rel="bookmark" title="Permalink to {{ article.title }}">{{ article.title
}}</a></h1> {% include 'twitter.html' %} </header>
<article>
<header>
<h1 class="entry-title">
<a href="{{ article.url }}" rel="bookmark"
title="Permalink to {{ article.title|striptags }}">{{ article.title}}</a></h1>
{% include 'twitter.html' %}
</header>
<div class="entry-content">
{% include 'article_infos.html' %}
{{ article.content }}
@ -25,6 +29,6 @@
</div>
{% endif %}
</article>
</article>
</section>
{% endblock %}

View file

@ -2,7 +2,7 @@
{% block content %}
<ul>
{% for category, articles in categories %}
<li><a href="{{ category.url }}">{{ category }}</a></li>
<li><a href="{{ SITEURL }}/{{ category.url }}">{{ category }}</a></li>
{% endfor %}
</ul>
{% endblock %}

View file

@ -5,7 +5,7 @@
<dl>
{% for article in dates %}
<dt>{{ article.locale_date }}</dt>
<dd><a href="{{ article.url }}">{{ article.title }}</a></dd>
<dd><a href="{{ SITEURL }}/{{ article.url }}">{{ article.title }}</a></dd>
{% endfor %}
</dl>
{% endblock %}

View file

@ -1,7 +1,11 @@
{% extends "base.html" %}
{% block content %}
<section id="content" class="body">
<header> <h2 class="entry-title"><a href="{{ pagename }}" rel="bookmark" title="Permalink to {{ article.title}}">{{ article.title }}</a></h2> </header>
<header>
<h2 class="entry-title">
<a href="{{ article.url }}" rel="bookmark"
title="Permalink to {{ article.title|striptags }}">{{ article.title }}</a></h2>
</header>
<footer class="post-info">
<abbr class="published" title="{{ article.date.isoformat() }}">
{{ article.locale_date }}

View file

@ -7,94 +7,9 @@ import argparse
from pelican import __version__
TEMPLATES = {
'Makefile' : '''
PELICAN=$pelican
PELICANOPTS=$pelicanopts
_TEMPLATES_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), \
"templates")
BASEDIR=$$(PWD)
INPUTDIR=$$(BASEDIR)/src
OUTPUTDIR=$$(BASEDIR)/output
CONFFILE=$$(BASEDIR)/pelican.conf.py
FTP_HOST=$ftp_host
FTP_USER=$ftp_user
FTP_TARGET_DIR=$ftp_target_dir
SSH_HOST=$ssh_host
SSH_USER=$ssh_user
SSH_TARGET_DIR=$ssh_target_dir
DROPBOX_DIR=$dropbox_dir
help:
\t@echo 'Makefile for a pelican Web site '
\t@echo ' '
\t@echo 'Usage: '
\t@echo ' make html (re)generate the web site '
\t@echo ' make clean remove the generated files '
\t@echo ' ftp_upload upload the web site using FTP '
\t@echo ' ssh_upload upload the web site using SSH '
\t@echo ' dropbox_upload upload the web site using Dropbox '
\t@echo ' '
html: clean $$(OUTPUTDIR)/index.html
\t@echo 'Done'
$$(OUTPUTDIR)/%.html:
\t$$(PELICAN) $$(INPUTDIR) -o $$(OUTPUTDIR) -s $$(CONFFILE) $$(PELICANOPTS)
clean:
\trm -fr $$(OUTPUTDIR)
\tmkdir $$(OUTPUTDIR)
dropbox_upload: $$(OUTPUTDIR)/index.html
\tcp -r $$(OUTPUTDIR)/* $$(DROPBOX_DIR)
rsync_upload: $$(OUTPUTDIR)/index.html
\trsync --delete -rvz -e ssh $(OUTPUTDIR)/* $(SSH_USER)@$(SSH_HOST):$(SSH_TARGET_DIR)
ssh_upload: $$(OUTPUTDIR)/index.html
\tscp -r $$(OUTPUTDIR)/* $$(SSH_USER)@$$(SSH_HOST):$$(SSH_TARGET_DIR)
ftp_upload: $$(OUTPUTDIR)/index.html
\tlftp ftp://$$(FTP_USER)@$$(FTP_HOST) -e "mirror -R $$(OUTPUTDIR) $$(FTP_TARGET_DIR) ; quit"
github: $$(OUTPUTDIR)/index.html
\tghp-import $$(OUTPUTDIR)
\tgit push origin gh-pages
.PHONY: html help clean ftp_upload ssh_upload dropbox_upload github
''',
'pelican.conf.py': '''#!/usr/bin/env python
# -*- coding: utf-8 -*- #
AUTHOR = u"$author"
SITENAME = u"$sitename"
SITEURL = '/'
TIMEZONE = 'Europe/Paris'
DEFAULT_LANG='$lang'
# Blogroll
LINKS = (
('Pelican', 'http://docs.notmyidea.org/alexis/pelican/'),
('Python.org', 'http://python.org'),
('Jinja2', 'http://jinja.pocoo.org'),
('You can modify those links in your config file', '#')
)
# Social widget
SOCIAL = (
('You can add links in your config file', '#'),
)
DEFAULT_PAGINATION = $default_pagination
'''
}
CONF = {
'pelican' : 'pelican',
@ -112,6 +27,20 @@ CONF = {
}
def get_template(name):
template = os.path.join(_TEMPLATES_DIR, "{0}.in".format(name))
if not os.path.isfile(template):
raise RuntimeError("Cannot open {0}".format(template))
with open(template, 'r') as fd:
line = fd.readline()
while line:
yield line
line = fd.readline()
fd.close()
def ask(question, answer=str, default=None, l=None):
if answer == str:
r = ''
@ -246,20 +175,22 @@ Please answer the following questions so this script can generate the files need
except OSError, e:
print('Error: {0}'.format(e))
conf = string.Template(TEMPLATES['pelican.conf.py'])
try:
with open(os.path.join(CONF['basedir'], 'pelican.conf.py'), 'w') as fd:
fd.write(conf.safe_substitute(CONF))
for line in get_template('pelican.conf.py'):
template = string.Template(line)
fd.write(template.safe_substitute(CONF))
fd.close()
except OSError, e:
print('Error: {0}'.format(e))
if mkfile:
Makefile = string.Template(TEMPLATES['Makefile'])
try:
with open(os.path.join(CONF['basedir'], 'Makefile'), 'w') as fd:
fd.write(Makefile.safe_substitute(CONF))
for line in get_template('Makefile'):
template = string.Template(line)
fd.write(template.safe_substitute(CONF))
fd.close()
except OSError, e:
print('Error: {0}'.format(e))

View file

@ -0,0 +1,58 @@
PELICAN=$pelican
PELICANOPTS=$pelicanopts
BASEDIR=$$(PWD)
INPUTDIR=$$(BASEDIR)/src
OUTPUTDIR=$$(BASEDIR)/output
CONFFILE=$$(BASEDIR)/pelican.conf.py
FTP_HOST=$ftp_host
FTP_USER=$ftp_user
FTP_TARGET_DIR=$ftp_target_dir
SSH_HOST=$ssh_host
SSH_USER=$ssh_user
SSH_TARGET_DIR=$ssh_target_dir
DROPBOX_DIR=$dropbox_dir
help:
@echo 'Makefile for a pelican Web site '
@echo ' '
@echo 'Usage: '
@echo ' make html (re)generate the web site '
@echo ' make clean remove the generated files '
@echo ' ftp_upload upload the web site using FTP '
@echo ' ssh_upload upload the web site using SSH '
@echo ' dropbox_upload upload the web site using Dropbox '
@echo ' rsync_upload upload the web site using rsync/ssh'
@echo ' '
html: clean $$(OUTPUTDIR)/index.html
@echo 'Done'
$$(OUTPUTDIR)/%.html:
$$(PELICAN) $$(INPUTDIR) -o $$(OUTPUTDIR) -s $$(CONFFILE) $$(PELICANOPTS)
clean:
rm -fr $$(OUTPUTDIR)
mkdir $$(OUTPUTDIR)
dropbox_upload: $$(OUTPUTDIR)/index.html
cp -r $$(OUTPUTDIR)/* $$(DROPBOX_DIR)
ssh_upload: $$(OUTPUTDIR)/index.html
scp -r $$(OUTPUTDIR)/* $$(SSH_USER)@$$(SSH_HOST):$$(SSH_TARGET_DIR)
rsync_upload: $$(OUTPUTDIR)/index.html
rsync -e ssh -P -rvz --delete $(OUTPUTDIR)/* $(SSH_USER)@$(SSH_HOST):$(SSH_TARGET_DIR)
ftp_upload: $$(OUTPUTDIR)/index.html
lftp ftp://$$(FTP_USER)@$$(FTP_HOST) -e "mirror -R $$(OUTPUTDIR) $$(FTP_TARGET_DIR) ; quit"
github: $$(OUTPUTDIR)/index.html
ghp-import $$(OUTPUTDIR)
git push origin gh-pages
.PHONY: html help clean ftp_upload ssh_upload rsync_upload dropbox_upload github

View file

@ -0,0 +1,25 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*- #
AUTHOR = u"$author"
SITENAME = u"$sitename"
SITEURL = '/'
TIMEZONE = 'Europe/Paris'
DEFAULT_LANG='$lang'
# Blogroll
LINKS = (
('Pelican', 'http://docs.notmyidea.org/alexis/pelican/'),
('Python.org', 'http://python.org'),
('Jinja2', 'http://jinja.pocoo.org'),
('You can modify those links in your config file', '#')
)
# Social widget
SOCIAL = (
('You can add links in your config file', '#'),
)
DEFAULT_PAGINATION = $default_pagination

View file

@ -8,6 +8,7 @@ import logging
from codecs import open as _open
from datetime import datetime
from itertools import groupby
from jinja2 import Markup
from operator import attrgetter
logger = logging.getLogger(__name__)
@ -44,6 +45,7 @@ def slugify(value):
Took from django sources.
"""
value = Markup(value).striptags()
if type(value) == unicode:
import unicodedata
value = unicodedata.normalize('NFKD', value).encode('ascii', 'ignore')

View file

@ -8,8 +8,8 @@ import logging
from codecs import open
from functools import partial
from feedgenerator import Atom1Feed, Rss201rev2Feed
from jinja2 import Markup
from pelican.paginator import Paginator
from pelican.utils import get_relative_path, set_date_tzinfo
@ -25,8 +25,9 @@ class Writer(object):
def _create_new_feed(self, feed_type, context):
feed_class = Rss201rev2Feed if feed_type == 'rss' else Atom1Feed
sitename = Markup(context['SITENAME']).striptags()
feed = feed_class(
title=context['SITENAME'],
title=sitename,
link=(self.site_url + '/'),
feed_url=self.feed_url,
description=context.get('SITESUBTITLE', ''))
@ -34,8 +35,9 @@ class Writer(object):
def _add_item_to_the_feed(self, feed, item):
title = Markup(item.title).striptags()
feed.add_item(
title=item.title,
title=title,
link='%s/%s' % (self.site_url, item.url),
unique_id='tag:%s,%s:%s' % (self.site_url.replace('http://', ''),
item.date.date(), item.url),
@ -99,6 +101,12 @@ class Writer(object):
:param **kwargs: additional variables to pass to the templates
"""
if name is False:
return
elif not name:
# other stuff, just return for now
return
def _write_file(template, localcontext, output_path, name):
"""Render the template write the file."""
old_locale = locale.setlocale(locale.LC_ALL)

View file

@ -0,0 +1,10 @@
title: Test md File
category: test
Test Markdown File Header
=========================
Used for pelican test
---------------------
The quick brown fox jumped over the lazy dog's back.

View file

@ -0,0 +1,10 @@
title: Test mkd File
category: test
Test Markdown File Header
=========================
Used for pelican test
---------------------
This is another markdown test file. Uses the mkd extension.

View file

@ -4,6 +4,8 @@ __all__ = [
'unittest',
]
import os
import subprocess
from contextlib import contextmanager
from tempfile import mkdtemp
from shutil import rmtree
@ -35,3 +37,21 @@ def get_article(title, slug, content, lang, extra_metadata=None):
if extra_metadata is not None:
metadata.update(extra_metadata)
return Article(content, metadata=metadata)
def skipIfNoExecutable(executable, valid_exit_code=1):
"""Tries to run an executable to make sure it's in the path, Skips the tests
if not found.
"""
# calling with no params the command should exit with 1
with open(os.devnull, 'w') as fnull:
try:
res = subprocess.call(executable, stdout=fnull, stderr=fnull)
except OSError:
res = None
if res != valid_exit_code:
return unittest.skip('{0} compiler not found'.format(executable))
return lambda func: func

View file

@ -2,13 +2,15 @@
from mock import MagicMock
import os
import re
from pelican.generators import ArticlesGenerator
from pelican.generators import ArticlesGenerator, LessCSSGenerator
from pelican.settings import _DEFAULT_CONFIG
from .support import unittest
from .support import unittest, temporary_folder, skipIfNoExecutable
CUR_DIR = os.path.dirname(__file__)
class TestArticlesGenerator(unittest.TestCase):
def test_generate_feeds(self):
@ -49,4 +51,91 @@ class TestArticlesGenerator(unittest.TestCase):
categories = [cat.name for cat, _ in generator.categories]
# assert that the categories are ordered as expected
self.assertEquals(
categories, ['Default', 'TestCategory', 'Yeah', 'yeah'])
categories, ['Default', 'TestCategory', 'Yeah', 'test',
'yeah'])
def test_direct_templates_save_as_default(self):
settings = _DEFAULT_CONFIG.copy()
settings['DIRECT_TEMPLATES'] = ['archives']
generator = ArticlesGenerator(settings.copy(), settings, None,
_DEFAULT_CONFIG['THEME'], None,
_DEFAULT_CONFIG['MARKUP'])
write = MagicMock()
generator.generate_direct_templates(write)
write.assert_called_with("archives.html",
generator.get_template("archives"), settings,
blog=True, paginated={}, page_name='archives')
def test_direct_templates_save_as_modified(self):
settings = _DEFAULT_CONFIG.copy()
settings['DIRECT_TEMPLATES'] = ['archives']
settings['ARCHIVES_SAVE_AS'] = 'archives/index.html'
generator = ArticlesGenerator(settings, settings, None,
_DEFAULT_CONFIG['THEME'], None,
_DEFAULT_CONFIG['MARKUP'])
write = MagicMock()
generator.generate_direct_templates(write)
write.assert_called_with("archives/index.html",
generator.get_template("archives"), settings,
blog=True, paginated={}, page_name='archives')
def test_direct_templates_save_as_false(self):
settings = _DEFAULT_CONFIG.copy()
settings['DIRECT_TEMPLATES'] = ['archives']
settings['ARCHIVES_SAVE_AS'] = 'archives/index.html'
generator = ArticlesGenerator(settings, settings, None,
_DEFAULT_CONFIG['THEME'], None,
_DEFAULT_CONFIG['MARKUP'])
write = MagicMock()
generator.generate_direct_templates(write)
write.assert_called_count == 0
class TestLessCSSGenerator(unittest.TestCase):
LESS_CONTENT = """
@color: #4D926F;
#header {
color: @color;
}
h2 {
color: @color;
}
"""
@skipIfNoExecutable('lessc')
def test_less_compiler(self):
settings = _DEFAULT_CONFIG.copy()
settings['STATIC_PATHS'] = ['static']
settings['LESS_GENERATOR'] = True
# we'll nest here for py < 2.7 compat
with temporary_folder() as temp_content:
with temporary_folder() as temp_output:
generator = LessCSSGenerator(None, settings, temp_content,
_DEFAULT_CONFIG['THEME'], temp_output, None)
# create a dummy less file
less_dir = os.path.join(temp_content, 'static', 'css')
less_filename = os.path.join(less_dir, 'test.less')
less_output = os.path.join(temp_output, 'static', 'css',
'test.css')
os.makedirs(less_dir)
with open(less_filename, 'w') as less_file:
less_file.write(self.LESS_CONTENT)
generator.generate_output()
# we have the file ?
self.assertTrue(os.path.exists(less_output))
# was it compiled ?
self.assertIsNotNone(re.search(r'^\s+color:\s*#4D926F;$',
open(less_output).read(), re.MULTILINE | re.IGNORECASE))

View file

@ -61,3 +61,25 @@ class RstReaderTest(unittest.TestCase):
self.assertEqual(content, expected)
except ImportError:
return unittest.skip('need the typogrify distribution')
class MdReaderTest(unittest.TestCase):
def test_article_with_md_extention(self):
# test to ensure the md extension is being processed by the correct reader
reader = readers.MarkdownReader({})
content, metadata = reader.read(_filename('article_with_md_extension.md'))
expected = "<h1>Test Markdown File Header</h1>\n"\
"<h2>Used for pelican test</h2>\n"\
"<p>The quick brown fox jumped over the lazy dog's back.</p>"
self.assertEqual(content, expected)
def test_article_with_mkd_extension(self):
# test to ensure the mkd extension is being processed by the correct reader
reader = readers.MarkdownReader({})
content, metadata = reader.read(_filename('article_with_mkd_extension.mkd'))
expected = "<h1>Test Markdown File Header</h1>\n"\
"<h2>Used for pelican test</h2>\n"\
"<p>This is another markdown test file. Uses the mkd extension.</p>"
self.assertEqual(content, expected)