forked from github/pelican
Merge branch tests into main. (See #44)
Conflicts: pelican/contents.py pelican/settings.py samples/pelican.conf.py
This commit is contained in:
commit
371892ceaa
6 changed files with 128 additions and 22 deletions
|
|
@ -1,6 +1,7 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
from pelican.utils import slugify, truncate_html_words
|
from pelican.utils import slugify, truncate_html_words
|
||||||
from pelican.log import *
|
from pelican.log import *
|
||||||
|
from pelican.settings import _DEFAULT_CONFIG
|
||||||
|
|
||||||
class Page(object):
|
class Page(object):
|
||||||
"""Represents a page
|
"""Represents a page
|
||||||
|
|
@ -10,31 +11,45 @@ class Page(object):
|
||||||
"""
|
"""
|
||||||
mandatory_properties = ('title',)
|
mandatory_properties = ('title',)
|
||||||
|
|
||||||
def __init__(self, content, metadata={}, settings={}, filename=None):
|
def __init__(self, content, metadata=None, settings=None, filename=None):
|
||||||
|
# init parameters
|
||||||
|
if not metadata:
|
||||||
|
metadata = {}
|
||||||
|
if not settings:
|
||||||
|
settings = _DEFAULT_CONFIG
|
||||||
|
|
||||||
self._content = content
|
self._content = content
|
||||||
self.translations = []
|
self.translations = []
|
||||||
|
|
||||||
self.status = "published" # default value
|
self.status = "published" # default value
|
||||||
|
|
||||||
local_metadata = dict(settings['DEFAULT_METADATA'])
|
local_metadata = dict(settings.get('DEFAULT_METADATA', ()))
|
||||||
local_metadata.update(metadata)
|
local_metadata.update(metadata)
|
||||||
|
|
||||||
|
# set metadata as attributes
|
||||||
for key, value in local_metadata.items():
|
for key, value in local_metadata.items():
|
||||||
setattr(self, key.lower(), value)
|
setattr(self, key.lower(), value)
|
||||||
|
|
||||||
|
# default author to the one in settings if not defined
|
||||||
if not hasattr(self, 'author'):
|
if not hasattr(self, 'author'):
|
||||||
if 'AUTHOR' in settings:
|
if 'AUTHOR' in settings:
|
||||||
self.author = settings['AUTHOR']
|
self.author = settings['AUTHOR']
|
||||||
|
|
||||||
default_lang = settings.get('DEFAULT_LANG').lower()
|
# manage languages
|
||||||
if not hasattr(self, 'lang'):
|
self.in_default_lang = True
|
||||||
self.lang = default_lang
|
if 'DEFAULT_LANG' in settings:
|
||||||
|
default_lang = settings['DEFAULT_LANG'].lower()
|
||||||
|
if not hasattr(self, 'lang'):
|
||||||
|
self.lang = default_lang
|
||||||
|
|
||||||
self.in_default_lang = (self.lang == default_lang)
|
self.in_default_lang = (self.lang == default_lang)
|
||||||
|
|
||||||
if not hasattr(self, 'slug'):
|
# create the slug if not existing, fro mthe title
|
||||||
|
if not hasattr(self, 'slug') and hasattr(self, 'title'):
|
||||||
self.slug = slugify(self.title)
|
self.slug = slugify(self.title)
|
||||||
|
|
||||||
if not hasattr(self, 'save_as'):
|
# create save_as from the slug (+lang)
|
||||||
|
if not hasattr(self, 'save_as') and hasattr(self, 'slug'):
|
||||||
if self.in_default_lang:
|
if self.in_default_lang:
|
||||||
self.save_as = '%s.html' % self.slug
|
self.save_as = '%s.html' % self.slug
|
||||||
clean_url = '%s/' % self.slug
|
clean_url = '%s/' % self.slug
|
||||||
|
|
@ -42,16 +57,18 @@ class Page(object):
|
||||||
self.save_as = '%s-%s.html' % (self.slug, self.lang)
|
self.save_as = '%s-%s.html' % (self.slug, self.lang)
|
||||||
clean_url = '%s-%s/' % (self.slug, self.lang)
|
clean_url = '%s-%s/' % (self.slug, self.lang)
|
||||||
|
|
||||||
|
# change the save_as regarding the settings
|
||||||
if settings.get('CLEAN_URLS', False):
|
if settings.get('CLEAN_URLS', False):
|
||||||
self.url = clean_url
|
self.url = clean_url
|
||||||
else:
|
elif hasattr(self, 'save_as'):
|
||||||
self.url = self.save_as
|
self.url = self.save_as
|
||||||
|
|
||||||
if filename:
|
if filename:
|
||||||
self.filename = filename
|
self.filename = filename
|
||||||
|
|
||||||
|
# manage the date format
|
||||||
if not hasattr(self, 'date_format'):
|
if not hasattr(self, 'date_format'):
|
||||||
if self.lang in settings['DATE_FORMATS']:
|
if hasattr(self, 'lang') and self.lang in settings['DATE_FORMATS']:
|
||||||
self.date_format = settings['DATE_FORMATS'][self.lang]
|
self.date_format = settings['DATE_FORMATS'][self.lang]
|
||||||
else:
|
else:
|
||||||
self.date_format = settings['DEFAULT_DATE_FORMAT']
|
self.date_format = settings['DEFAULT_DATE_FORMAT']
|
||||||
|
|
@ -59,15 +76,14 @@ class Page(object):
|
||||||
if hasattr(self, 'date'):
|
if hasattr(self, 'date'):
|
||||||
self.locale_date = self.date.strftime(self.date_format.encode('ascii','xmlcharrefreplace')).decode('utf')
|
self.locale_date = self.date.strftime(self.date_format.encode('ascii','xmlcharrefreplace')).decode('utf')
|
||||||
|
|
||||||
|
# manage summary
|
||||||
if not hasattr(self, 'summary'):
|
if not hasattr(self, 'summary'):
|
||||||
self.summary = property(lambda self: truncate_html_words(self.content, 50)).__get__(self, Page)
|
self.summary = property(lambda self: truncate_html_words(self.content, 50)).__get__(self, Page)
|
||||||
|
|
||||||
|
# manage status
|
||||||
if not hasattr(self, 'status'):
|
if not hasattr(self, 'status'):
|
||||||
self.status = settings['DEFAULT_STATUS']
|
self.status = settings['DEFAULT_STATUS']
|
||||||
|
|
||||||
# store the settings ref.
|
|
||||||
self._settings = settings
|
|
||||||
|
|
||||||
def check_properties(self):
|
def check_properties(self):
|
||||||
"""test that each mandatory property is set."""
|
"""test that each mandatory property is set."""
|
||||||
for prop in self.mandatory_properties:
|
for prop in self.mandatory_properties:
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,10 @@
|
||||||
import os
|
import os
|
||||||
import locale
|
import locale
|
||||||
|
|
||||||
_DEFAULT_THEME = os.sep.join([os.path.dirname(os.path.abspath(__file__)),
|
DEFAULT_THEME = os.sep.join([os.path.dirname(os.path.abspath(__file__)),
|
||||||
"themes/notmyidea"])
|
"themes/notmyidea"])
|
||||||
_DEFAULT_CONFIG = {'PATH': None,
|
_DEFAULT_CONFIG = {'PATH': None,
|
||||||
'THEME': _DEFAULT_THEME,
|
'THEME': DEFAULT_THEME,
|
||||||
'OUTPUT_PATH': 'output/',
|
'OUTPUT_PATH': 'output/',
|
||||||
'MARKUP': ('rst', 'md'),
|
'MARKUP': ('rst', 'md'),
|
||||||
'STATIC_PATHS': ['images',],
|
'STATIC_PATHS': ['images',],
|
||||||
|
|
@ -40,7 +40,7 @@ _DEFAULT_CONFIG = {'PATH': None,
|
||||||
'DEFAULT_METADATA': (),
|
'DEFAULT_METADATA': (),
|
||||||
'FILES_TO_COPY': (),
|
'FILES_TO_COPY': (),
|
||||||
'DEFAULT_STATUS': 'published',
|
'DEFAULT_STATUS': 'published',
|
||||||
}
|
}
|
||||||
|
|
||||||
def read_settings(filename):
|
def read_settings(filename):
|
||||||
"""Load a Python file into a dictionary.
|
"""Load a Python file into a dictionary.
|
||||||
|
|
|
||||||
0
pelican/tests/__init__.py
Normal file
0
pelican/tests/__init__.py
Normal file
52
pelican/tests/test_contents.py
Normal file
52
pelican/tests/test_contents.py
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
from unittest2 import TestCase
|
||||||
|
|
||||||
|
from pelican.contents import Page
|
||||||
|
from pelican.settings import _DEFAULT_CONFIG
|
||||||
|
|
||||||
|
class TestPage(TestCase):
|
||||||
|
|
||||||
|
def test_use_args(self):
|
||||||
|
# creating a page with arguments passed to the connstructor should use
|
||||||
|
# them to initialise object's attributes
|
||||||
|
metadata = {'foo': 'bar', 'foobar': 'baz'}
|
||||||
|
page = Page('content', metadata=metadata)
|
||||||
|
for key, value in metadata.items():
|
||||||
|
self.assertTrue(hasattr(page, key))
|
||||||
|
self.assertEqual(value, getattr(page, key))
|
||||||
|
self.assertEqual(page.content, "content")
|
||||||
|
|
||||||
|
def test_mandatory_properties(self):
|
||||||
|
# if the title is not set, must throw an exception
|
||||||
|
page = Page('content')
|
||||||
|
with self.assertRaises(NameError) as cm:
|
||||||
|
page.check_properties()
|
||||||
|
|
||||||
|
page = Page('content', metadata={'title': 'foobar'})
|
||||||
|
page.check_properties()
|
||||||
|
|
||||||
|
def test_slug(self):
|
||||||
|
# if a title is given, it should be used to generate the slug
|
||||||
|
page = Page('content', {'title': 'foobar is foo'})
|
||||||
|
self.assertEqual(page.slug, 'foobar-is-foo')
|
||||||
|
|
||||||
|
def test_defaultlang(self):
|
||||||
|
# if no lang is given, default to the default one
|
||||||
|
page = Page('content')
|
||||||
|
self.assertEqual(page.lang, _DEFAULT_CONFIG['DEFAULT_LANG'])
|
||||||
|
|
||||||
|
# it is possible to specify the lang in the metadata infos
|
||||||
|
page = Page('content', {'lang': 'fr'})
|
||||||
|
self.assertEqual(page.lang, 'fr')
|
||||||
|
|
||||||
|
def test_save_as(self):
|
||||||
|
# if a lang is not the default lang, save_as should be set accordingly
|
||||||
|
page = Page('content', {'title': 'foobar', 'lang': 'fr'}) #default lang is en
|
||||||
|
self.assertEqual(page.save_as, "foobar-fr.html")
|
||||||
|
|
||||||
|
# otherwise, if a title is defined, save_as should be set
|
||||||
|
page = Page('content', {'title': 'foobar'})
|
||||||
|
page.save_as = 'foobar.html'
|
||||||
|
|
||||||
|
# if no title is given, there is no save_as
|
||||||
|
page = Page('content')
|
||||||
|
self.assertFalse(hasattr(page, 'save_as'))
|
||||||
34
pelican/tests/test_settings.py
Normal file
34
pelican/tests/test_settings.py
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
from unittest2 import TestCase
|
||||||
|
import os
|
||||||
|
|
||||||
|
from pelican.settings import read_settings, _DEFAULT_CONFIG
|
||||||
|
|
||||||
|
SETTINGS = os.sep.join([os.path.dirname(os.path.abspath(__file__)),
|
||||||
|
"../../samples/pelican.conf.py"])
|
||||||
|
|
||||||
|
class SettingsTest(TestCase):
|
||||||
|
|
||||||
|
|
||||||
|
def test_read_settings(self):
|
||||||
|
# providing a file, it should read it, replace the default values and append
|
||||||
|
# new values to the settings, if any
|
||||||
|
settings = read_settings(SETTINGS)
|
||||||
|
|
||||||
|
# overwrite existing settings
|
||||||
|
self.assertEqual(settings.get('SITENAME'), u"Alexis' log")
|
||||||
|
|
||||||
|
# add new settings
|
||||||
|
self.assertEqual(settings.get('SITEURL'), 'http://blog.notmyidea.org')
|
||||||
|
|
||||||
|
# keep default settings if not defined
|
||||||
|
self.assertEqual(settings.get('DEFAULT_CATEGORY'),
|
||||||
|
_DEFAULT_CONFIG['DEFAULT_CATEGORY'])
|
||||||
|
|
||||||
|
# do not copy keys not in caps
|
||||||
|
self.assertNotIn('foobar', settings)
|
||||||
|
|
||||||
|
|
||||||
|
def test_empty_read_settings(self):
|
||||||
|
# providing no file should return the default values
|
||||||
|
settings = read_settings(None)
|
||||||
|
self.assertDictEqual(settings, _DEFAULT_CONFIG)
|
||||||
|
|
@ -14,11 +14,11 @@ FEED_RSS = 'feeds/all.rss.xml'
|
||||||
CATEGORY_FEED_RSS = 'feeds/%s.rss.xml'
|
CATEGORY_FEED_RSS = 'feeds/%s.rss.xml'
|
||||||
|
|
||||||
LINKS = (('Biologeek', 'http://biologeek.org'),
|
LINKS = (('Biologeek', 'http://biologeek.org'),
|
||||||
('Filyb', "http://filyb.info/"),
|
('Filyb', "http://filyb.info/"),
|
||||||
('Libert-fr', "http://www.libert-fr.com"),
|
('Libert-fr', "http://www.libert-fr.com"),
|
||||||
('N1k0', "http://prendreuncafe.com/blog/"),
|
('N1k0', "http://prendreuncafe.com/blog/"),
|
||||||
(u'Tarek Ziadé', "http://ziade.org/blog"),
|
(u'Tarek Ziadé', "http://ziade.org/blog"),
|
||||||
('Zubin Mithra', "http://zubin71.wordpress.com/"),)
|
('Zubin Mithra', "http://zubin71.wordpress.com/"),)
|
||||||
|
|
||||||
SOCIAL = (('twitter', 'http://twitter.com/ametaireau'),
|
SOCIAL = (('twitter', 'http://twitter.com/ametaireau'),
|
||||||
('lastfm', 'http://lastfm.com/user/akounet'),
|
('lastfm', 'http://lastfm.com/user/akounet'),
|
||||||
|
|
@ -32,3 +32,7 @@ STATIC_PATHS = ["pictures",]
|
||||||
|
|
||||||
# A list of files to copy from the source to the destination
|
# A list of files to copy from the source to the destination
|
||||||
FILES_TO_COPY = (('extra/robots.txt', 'robots.txt'),)
|
FILES_TO_COPY = (('extra/robots.txt', 'robots.txt'),)
|
||||||
|
|
||||||
|
# foobar will not be used, because it's not in caps. All configuration keys
|
||||||
|
# have to be in caps
|
||||||
|
foobar = "barbaz"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue