Manual pass on sources for better standards.

This commit is contained in:
Alexis Métaireau 2013-03-03 20:12:31 -08:00
commit 519dcdbcb3
9 changed files with 136 additions and 105 deletions

View file

@ -293,8 +293,15 @@ def main():
# restriction; all files are recursively checked if they
# have changed, no matter what extension the filenames
# have.
if files_changed(pelican.path, pelican.markup, pelican.ignore_files) or \
files_changed(pelican.theme, [''], pelican.ignore_files):
if (files_changed(
pelican.path,
pelican.markup,
pelican.ignore_files)
or files_changed(
pelican.theme,
[''],
pelican.ignore_files
)):
if not files_found_error:
files_found_error = True
pelican.run()
@ -318,8 +325,7 @@ def main():
time.sleep(1) # sleep to avoid cpu load
except Exception as e:
logger.warning(
"Caught exception \"{}\". Reloading.".format(e)
)
'Caught exception "{0}". Reloading.'.format(e))
continue
else:
pelican.run()

View file

@ -11,7 +11,6 @@ import re
import sys
from datetime import datetime
from sys import platform, stdin
from pelican.settings import _DEFAULT_CONFIG
@ -92,7 +91,8 @@ class Page(object):
if isinstance(self.date_format, tuple):
locale_string = self.date_format[0]
if sys.version_info < (3, ) and isinstance(locale_string, six.text_type):
if sys.version_info < (3, ) and isinstance(locale_string,
six.text_type):
locale_string = locale_string.encode('ascii')
locale.setlocale(locale.LC_ALL, locale_string)
self.date_format = self.date_format[1]
@ -289,9 +289,12 @@ class URLWrapper(object):
def _from_settings(self, key, get_page_name=False):
"""Returns URL information as defined in settings.
When get_page_name=True returns URL without anything after {slug}
e.g. if in settings: CATEGORY_URL="cat/{slug}.html" this returns "cat/{slug}"
Useful for pagination."""
When get_page_name=True returns URL without anything after {slug} e.g.
if in settings: CATEGORY_URL="cat/{slug}.html" this returns
"cat/{slug}" Useful for pagination.
"""
setting = "%s_%s" % (self.__class__.__name__.upper(), key)
value = self.settings[setting]
if not isinstance(value, six.string_types):
@ -303,7 +306,8 @@ class URLWrapper(object):
else:
return value.format(**self.as_dict())
page_name = property(functools.partial(_from_settings, key='URL', get_page_name=True))
page_name = property(functools.partial(_from_settings, key='URL',
get_page_name=True))
url = property(functools.partial(_from_settings, key='URL'))
save_as = property(functools.partial(_from_settings, key='SAVE_AS'))

View file

@ -14,11 +14,14 @@ from functools import partial
from itertools import chain
from operator import attrgetter, itemgetter
from jinja2 import (Environment, FileSystemLoader, PrefixLoader, ChoiceLoader,
BaseLoader, TemplateNotFound)
from jinja2 import (
Environment, FileSystemLoader, PrefixLoader, ChoiceLoader, BaseLoader,
TemplateNotFound
)
from pelican.contents import Article, Page, Category, StaticContent, \
is_valid_content
from pelican.contents import (
Article, Page, Category, StaticContent, is_valid_content
)
from pelican.readers import read_file
from pelican.utils import copy, process_translations, mkdir_p
from pelican import signals
@ -76,8 +79,9 @@ class Generator(object):
try:
self._templates[name] = self.env.get_template(name + '.html')
except TemplateNotFound:
raise Exception('[templates] unable to load %s.html from %s' \
% (name, self._templates_path))
raise Exception(
('[templates] unable to load %s.html from %s'
% (name, self._templates_path)))
return self._templates[name]
def get_files(self, path, exclude=[], extensions=None):
@ -165,8 +169,8 @@ class ArticlesGenerator(Generator):
self.categories = defaultdict(list)
self.related_posts = []
self.authors = defaultdict(list)
super(ArticlesGenerator, self).__init__(*args, **kwargs)
self.drafts = []
super(ArticlesGenerator, self).__init__(*args, **kwargs)
signals.article_generator_init.send(self)
def generate_feeds(self, writer):
@ -180,8 +184,8 @@ class ArticlesGenerator(Generator):
writer.write_feed(self.articles, self.context,
self.settings['FEED_RSS'], feed_type='rss')
if self.settings.get('FEED_ALL_ATOM') or \
self.settings.get('FEED_ALL_RSS'):
if (self.settings.get('FEED_ALL_ATOM')
or self.settings.get('FEED_ALL_RSS')):
all_articles = list(self.articles)
for article in self.articles:
all_articles.extend(article.translations)
@ -193,7 +197,8 @@ class ArticlesGenerator(Generator):
if self.settings.get('FEED_ALL_RSS'):
writer.write_feed(all_articles, self.context,
self.settings['FEED_ALL_RSS'], feed_type='rss')
self.settings['FEED_ALL_RSS'],
feed_type='rss')
for cat, arts in self.categories:
arts.sort(key=attrgetter('date'), reverse=True)
@ -206,8 +211,8 @@ class ArticlesGenerator(Generator):
self.settings['CATEGORY_FEED_RSS'] % cat,
feed_type='rss')
if self.settings.get('TAG_FEED_ATOM') \
or self.settings.get('TAG_FEED_RSS'):
if (self.settings.get('TAG_FEED_ATOM')
or self.settings.get('TAG_FEED_RSS')):
for tag, arts in self.tags.items():
arts.sort(key=attrgetter('date'), reverse=True)
if self.settings.get('TAG_FEED_ATOM'):
@ -219,8 +224,8 @@ class ArticlesGenerator(Generator):
self.settings['TAG_FEED_RSS'] % tag,
feed_type='rss')
if self.settings.get('TRANSLATION_FEED_ATOM') or \
self.settings.get('TRANSLATION_FEED_RSS'):
if (self.settings.get('TRANSLATION_FEED_ATOM')
or self.settings.get('TRANSLATION_FEED_RSS')):
translations_feeds = defaultdict(list)
for article in chain(self.articles, self.translations):
translations_feeds[article.lang].append(article)
@ -376,7 +381,7 @@ class ArticlesGenerator(Generator):
# only main articles are listed in categories, not translations
self.categories[article.category].append(article)
# ignore blank authors as well as undefined
if hasattr(article,'author') and article.author.name != '':
if hasattr(article, 'author') and article.author.name != '':
self.authors[article.author].append(article)
# sort the articles by date
@ -470,7 +475,8 @@ class PagesGenerator(Generator):
repr(f)))
self.pages, self.translations = process_translations(all_pages)
self.hidden_pages, self.hidden_translations = process_translations(hidden_pages)
self.hidden_pages, self.hidden_translations = (
process_translations(hidden_pages))
self._update_context(('pages', ))
self.context['PAGES'] = self.pages
@ -574,6 +580,7 @@ class PdfGenerator(Generator):
for page in self.context['pages']:
self._create_pdf(page, pdf_path)
class SourceFileGenerator(Generator):
def generate_context(self):
self.output_extension = self.settings['OUTPUT_SOURCES_EXTENSION']

View file

@ -31,11 +31,10 @@ def ansi(color, text):
class ANSIFormatter(Formatter):
"""
Convert a `logging.LogRecord' object into colored text, using ANSI escape sequences.
"""
## colors:
"""Convert a `logging.LogRecord' object into colored text, using ANSI
escape sequences.
"""
def format(self, record):
msg = str(record.msg)
if record.levelname == 'INFO':
@ -67,8 +66,8 @@ class TextFormatter(Formatter):
def init(level=None, logger=getLogger(), handler=StreamHandler()):
logger = logging.getLogger()
if os.isatty(sys.stdout.fileno()) \
and not sys.platform.startswith('win'):
if (os.isatty(sys.stdout.fileno())
and not sys.platform.startswith('win')):
fmt = ANSIFormatter()
else:
fmt = TextFormatter()

View file

@ -1,6 +1,5 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals, print_function
import six
import os
import re
@ -23,7 +22,6 @@ try:
asciidoc = True
except ImportError:
asciidoc = False
import re
import cgi
try:
@ -168,6 +166,7 @@ class MarkdownReader(Reader):
metadata = self._parse_metadata(md.Meta)
return content, metadata
class HTMLReader(Reader):
"""Parses HTML files as input, looking for meta, title, and body tags"""
file_extensions = ['htm', 'html']
@ -240,7 +239,7 @@ class HTMLReader(Reader):
def build_tag(self, tag, attrs, close_tag):
result = '<{}'.format(cgi.escape(tag))
for k,v in attrs:
for k, v in attrs:
result += ' ' + cgi.escape(k)
if v is not None:
result += '="{}"'.format(cgi.escape(v))
@ -272,6 +271,7 @@ class HTMLReader(Reader):
metadata[k] = self.process_metadata(k, parser.metadata[k])
return parser.body, metadata
class AsciiDocReader(Reader):
enabled = bool(asciidoc)
file_extensions = ['asc']

View file

@ -2,12 +2,12 @@ from __future__ import print_function
try:
import SimpleHTTPServer as srvmod
except ImportError:
import http.server as srvmod
import http.server as srvmod # NOQA
try:
import SocketServer as socketserver
except ImportError:
import socketserver
import socketserver # NOQA
PORT = 8000
@ -17,4 +17,3 @@ httpd = socketserver.TCPServer(("", PORT), Handler)
print("serving at port", PORT)
httpd.serve_forever()

View file

@ -62,7 +62,8 @@ _DEFAULT_CONFIG = {'PATH': '.',
'DEFAULT_LANG': 'en',
'TAG_CLOUD_STEPS': 4,
'TAG_CLOUD_MAX_ITEMS': 100,
'DIRECT_TEMPLATES': ('index', 'tags', 'categories', 'archives'),
'DIRECT_TEMPLATES': ('index', 'tags', 'categories',
'archives'),
'EXTRA_TEMPLATES_PATHS': [],
'PAGINATED_DIRECT_TEMPLATES': ('index', ),
'PELICAN_CLASS': 'pelican.Pelican',
@ -171,7 +172,8 @@ def configure_settings(settings):
if (siteurl.endswith('/')):
settings['SITEURL'] = siteurl[:-1]
logger.warn("Removed extraneous trailing slash from SITEURL.")
# If SITEURL is defined but FEED_DOMAIN isn't, set FEED_DOMAIN = SITEURL
# If SITEURL is defined but FEED_DOMAIN isn't,
# set FEED_DOMAIN to SITEURL
if not 'FEED_DOMAIN' in settings:
settings['FEED_DOMAIN'] = settings['SITEURL']
@ -185,36 +187,45 @@ def configure_settings(settings):
if any(settings.get(k) for k in feed_keys):
if not settings.get('FEED_DOMAIN'):
logger.warn("Since feed URLs should always be absolute, you should specify "
"FEED_DOMAIN in your settings. (e.g., 'FEED_DOMAIN = "
"http://www.example.com')")
logger.warn(
"Since feed URLs should always be absolute, you should specify"
" FEED_DOMAIN in your settings. (e.g., 'FEED_DOMAIN = "
"http://www.example.com')")
if not settings.get('SITEURL'):
logger.warn("Feeds generated without SITEURL set properly may not be valid")
logger.warn('Feeds generated without SITEURL set properly may not'
' be valid')
if not 'TIMEZONE' in settings:
logger.warn("No timezone information specified in the settings. Assuming"
" your timezone is UTC for feed generation. Check "
"http://docs.notmyidea.org/alexis/pelican/settings.html#timezone "
"for more information")
logger.warn(
'No timezone information specified in the settings. Assuming'
' your timezone is UTC for feed generation. Check '
'http://docs.notmyidea.org/alexis/pelican/settings.html#timezone '
'for more information')
if 'LESS_GENERATOR' in settings:
logger.warn("The LESS_GENERATOR setting has been removed in favor "
"of the Webassets plugin")
logger.warn(
'The LESS_GENERATOR setting has been removed in favor '
'of the Webassets plugin')
if 'OUTPUT_SOURCES_EXTENSION' in settings:
if not isinstance(settings['OUTPUT_SOURCES_EXTENSION'], six.string_types):
settings['OUTPUT_SOURCES_EXTENSION'] = _DEFAULT_CONFIG['OUTPUT_SOURCES_EXTENSION']
logger.warn("Detected misconfiguration with OUTPUT_SOURCES_EXTENSION."
" falling back to the default extension " +
_DEFAULT_CONFIG['OUTPUT_SOURCES_EXTENSION'])
if not isinstance(settings['OUTPUT_SOURCES_EXTENSION'],
six.string_types):
settings['OUTPUT_SOURCES_EXTENSION'] = (
_DEFAULT_CONFIG['OUTPUT_SOURCES_EXTENSION'])
logger.warn(
'Detected misconfiguration with OUTPUT_SOURCES_EXTENSION, '
'falling back to the default extension ' +
_DEFAULT_CONFIG['OUTPUT_SOURCES_EXTENSION'])
filename_metadata = settings.get('FILENAME_METADATA')
if filename_metadata and not isinstance(filename_metadata, six.string_types):
logger.error("Detected misconfiguration with FILENAME_METADATA"
" setting (must be string or compiled pattern), falling"
"back to the default")
settings['FILENAME_METADATA'] = \
_DEFAULT_CONFIG['FILENAME_METADATA']
if filename_metadata and not isinstance(filename_metadata,
six.string_types):
logger.error(
'Detected misconfiguration with FILENAME_METADATA '
'setting (must be string or compiled pattern), falling '
'back to the default')
settings['FILENAME_METADATA'] = (
_DEFAULT_CONFIG['FILENAME_METADATA'])
return settings

View file

@ -34,7 +34,8 @@ def strftime(date, date_format):
chars in the format string. So if e.g. your format string contains 'ø' or
'ä', the result will be 'o' and 'a'.
See here for an `extensive testcase <https://github.com/dmdm/test_strftime>`_.
See here for an `extensive testcase
<https://github.com/dmdm/test_strftime>`_.
:param date: Any object that sports a :meth:`strftime()` method.
:param date_format: Format string, can always be unicode.
@ -67,18 +68,12 @@ def strftime(date, date_format):
result = unicode(result)
# Convert XML character references back to unicode characters.
if "&#" in result:
result = re.sub(r'&#(?P<num>\d+);'
, lambda m: unichr(int(m.group('num')))
, result
)
result = re.sub(r'&#(?P<num>\d+);',
lambda m: unichr(int(m.group('num'))),
result)
return result
#----------------------------------------------------------------------------
# Stolen from Django: django.utils.encoding
#
def python_2_unicode_compatible(klass):
"""
A decorator that defines __unicode__ and __str__ methods under Python 2.
@ -86,43 +81,48 @@ def python_2_unicode_compatible(klass):
To support Python 2 and 3 with a single code base, define a __str__ method
returning text and apply this decorator to the class.
From django.utils.encoding.
"""
if not six.PY3:
klass.__unicode__ = klass.__str__
klass.__str__ = lambda self: self.__unicode__().encode('utf-8')
return klass
#----------------------------------------------------------------------------
class NoFilesError(Exception):
pass
class memoized(object):
'''Decorator. Caches a function's return value each time it is called.
If called later with the same arguments, the cached value is returned
(not reevaluated).
'''
def __init__(self, func):
self.func = func
self.cache = {}
def __call__(self, *args):
if not isinstance(args, Hashable):
# uncacheable. a list, for instance.
# better to not cache than blow up.
return self.func(*args)
if args in self.cache:
return self.cache[args]
else:
value = self.func(*args)
self.cache[args] = value
return value
def __repr__(self):
'''Return the function's docstring.'''
return self.func.__doc__
def __get__(self, obj, objtype):
'''Support instance methods.'''
return partial(self.__call__, obj)
"""Function decorator to cache return values.
If called later with the same arguments, the cached value is returned
(not reevaluated).
"""
def __init__(self, func):
self.func = func
self.cache = {}
def __call__(self, *args):
if not isinstance(args, Hashable):
# uncacheable. a list, for instance.
# better to not cache than blow up.
return self.func(*args)
if args in self.cache:
return self.cache[args]
else:
value = self.func(*args)
self.cache[args] = value
return value
def __repr__(self):
return self.func.__doc__
def __get__(self, obj, objtype):
'''Support instance methods.'''
return partial(self.__call__, obj)
def deprecated_attribute(old, new, since=None, remove=None, doc=None):
@ -166,6 +166,7 @@ def deprecated_attribute(old, new, since=None, remove=None, doc=None):
return decorator
def get_date(string):
"""Return a datetime object from a string.
@ -196,6 +197,7 @@ class pelican_open(object):
def __exit__(self, exc_type, exc_value, traceback):
pass
def slugify(value):
"""
Normalizes string, converts to lowercase, removes non-alpha characters,
@ -262,6 +264,7 @@ def copy(path, source, destination, destination_path=None, overwrite=False):
else:
logger.warning('skipped copy %s to %s' % (source_, destination_))
def clean_output_dir(path):
"""Remove all the files from the output directory"""
@ -414,6 +417,7 @@ def process_translations(content_list):
LAST_MTIME = 0
def files_changed(path, extensions, ignores=[]):
"""Return True if the files have changed since the last check"""
@ -423,7 +427,8 @@ def files_changed(path, extensions, ignores=[]):
dirs[:] = [x for x in dirs if x[0] != '.']
for f in files:
if any(f.endswith(ext) for ext in extensions) \
and not any(fnmatch.fnmatch(f, ignore) for ignore in ignores):
and not any(fnmatch.fnmatch(f, ignore)
for ignore in ignores):
yield os.stat(os.path.join(root, f)).st_mtime
global LAST_MTIME

View file

@ -78,11 +78,11 @@ class Writer(object):
os.makedirs(os.path.dirname(complete_path))
except Exception:
pass
fp = open(complete_path, 'w', encoding='utf-8' if six.PY3 else None)
feed.write(fp, 'utf-8')
logger.info('writing %s' % complete_path)
fp.close()
encoding = 'utf-8' if six.PY3 else None
with open(complete_path, 'w', encoding=encoding) as fp:
feed.write(fp, 'utf-8')
logger.info('writing %s' % complete_path)
return feed
finally:
locale.setlocale(locale.LC_ALL, old_locale)