From a9f5fdc47b5c42dee41e8ffebd773bcc9c2276ab Mon Sep 17 00:00:00 2001 From: Martin Brochhaus Date: Sun, 18 Mar 2012 14:57:53 +0800 Subject: [PATCH 1/5] Always using normal capitalization in headlines. --- docs/settings.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/settings.rst b/docs/settings.rst index b98b649e..b1c35122 100644 --- a/docs/settings.rst +++ b/docs/settings.rst @@ -83,7 +83,7 @@ Setting name (default value) What does it do? .. [#] Default is the system locale. -URL Settings +URL settings ------------ You can customize the URL's and locations where files will be saved. The URL's and From 9c4b40fd35833a6f68b04316ca5ce8f77f19c325 Mon Sep 17 00:00:00 2001 From: Alexis Metaireau Date: Sun, 18 Mar 2012 15:12:06 +0100 Subject: [PATCH 2/5] Keep raw metadata text (but for summary) --- pelican/readers.py | 5 ++++- tests/content/article_with_metadata.rst | 1 + tests/test_readers.py | 1 + 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/pelican/readers.py b/pelican/readers.py index d4e13b4d..2e269647 100644 --- a/pelican/readers.py +++ b/pelican/readers.py @@ -71,7 +71,10 @@ class RstReader(Reader): if element.tagname == 'field': # custom fields (e.g. summary) name_elem, body_elem = element.children name = name_elem.astext() - value = render_node_to_html(document, body_elem) + if name == 'summary': + value = render_node_to_html(document, body_elem) + else: + value = body_elem.astext() else: # standard fields (e.g. address) name = element.tagname value = element.astext() diff --git a/tests/content/article_with_metadata.rst b/tests/content/article_with_metadata.rst index 3410885e..d4bac1c0 100644 --- a/tests/content/article_with_metadata.rst +++ b/tests/content/article_with_metadata.rst @@ -9,3 +9,4 @@ This is a super article ! :summary: Multi-line metadata should be supported as well as **inline markup**. +:custom_field: http://notmyidea.org diff --git a/tests/test_readers.py b/tests/test_readers.py index 058469d4..4c04a212 100644 --- a/tests/test_readers.py +++ b/tests/test_readers.py @@ -30,6 +30,7 @@ class RstReaderTest(unittest.TestCase): ' inline markup.', 'date': datetime.datetime(2010, 12, 2, 10, 14), 'tags': ['foo', 'bar', 'foobar'], + 'custom_field': 'http://notmyidea.org', } for key, value in expected.items(): From ff5921a4697b83050ace01e564def6968c9440d1 Mon Sep 17 00:00:00 2001 From: Andrea Crotti Date: Sun, 18 Mar 2012 21:08:43 +0000 Subject: [PATCH 3/5] - move the try/except dance in support.py - use relative . imports in test files - remove the "future with import", since python < 2.6 is not supported --- tests/support.py | 11 +++++++++++ tests/test_contents.py | 13 +++++-------- tests/test_generators.py | 9 +++------ tests/test_pelican.py | 2 +- tests/test_readers.py | 5 +---- tests/test_settings.py | 8 ++------ tests/test_utils.py | 7 +------ 7 files changed, 24 insertions(+), 31 deletions(-) diff --git a/tests/support.py b/tests/support.py index 5829fe78..4eb07ec4 100644 --- a/tests/support.py +++ b/tests/support.py @@ -1,9 +1,20 @@ +__all__ = [ + 'temporary_folder', + 'get_article', + 'unittest', +] + from contextlib import contextmanager from tempfile import mkdtemp from shutil import rmtree from pelican.contents import Article +try: + import unittest2 as unittest +except ImportError: + import unittest + @contextmanager def temporary_folder(): diff --git a/tests/test_contents.py b/tests/test_contents.py index 8e1407dc..c6ef29a8 100644 --- a/tests/test_contents.py +++ b/tests/test_contents.py @@ -1,9 +1,6 @@ # -*- coding: utf-8 -*- -from __future__ import with_statement -try: - from unittest2 import TestCase, skip -except ImportError, e: - from unittest import TestCase, skip # NOQA + +from .support import unittest from pelican.contents import Page from pelican.settings import _DEFAULT_CONFIG @@ -14,7 +11,8 @@ from jinja2.utils import generate_lorem_ipsum TEST_CONTENT = str(generate_lorem_ipsum(n=1)) TEST_SUMMARY = generate_lorem_ipsum(n=1, html=False) -class TestPage(TestCase): + +class TestPage(unittest.TestCase): def setUp(self): super(TestPage, self).setUp() @@ -117,7 +115,6 @@ class TestPage(TestCase): try: page = Page(**page_kwargs) self.assertEqual(page.locale_date, u'2015-09-13(\u65e5)') - # above is unicode in Japanese: 2015-09-13(“ú) except locale_module.Error: # The constructor of ``Page`` will try to set the locale to # ``ja_JP.utf8``. But this attempt will failed when there is no @@ -126,4 +123,4 @@ class TestPage(TestCase): # # Until we find some other method to test this functionality, we # will simply skip this test. - skip("There is no locale %s in this system." % locale) + unittest.skip("There is no locale %s in this system." % locale) diff --git a/tests/test_generators.py b/tests/test_generators.py index 20929622..e30b0c98 100644 --- a/tests/test_generators.py +++ b/tests/test_generators.py @@ -1,13 +1,10 @@ # -*- coding: utf-8 -*- -try: - import unittest2 as unittest -except ImportError, e: - import unittest # NOQA + +from mock import MagicMock from pelican.generators import ArticlesGenerator from pelican.settings import _DEFAULT_CONFIG - -from mock import MagicMock +from .support import unittest class TestArticlesGenerator(unittest.TestCase): diff --git a/tests/test_pelican.py b/tests/test_pelican.py index dce4fadc..ce270955 100644 --- a/tests/test_pelican.py +++ b/tests/test_pelican.py @@ -1,7 +1,7 @@ import unittest import os -from support import temporary_folder +from .support import temporary_folder from pelican import Pelican from pelican.settings import read_settings diff --git a/tests/test_readers.py b/tests/test_readers.py index 4c04a212..3e830e17 100644 --- a/tests/test_readers.py +++ b/tests/test_readers.py @@ -1,13 +1,10 @@ # coding: utf-8 -try: - import unittest2 as unittest -except ImportError, e: - import unittest import datetime import os from pelican import readers +from .support import unittest CUR_DIR = os.path.dirname(__file__) CONTENT_PATH = os.path.join(CUR_DIR, 'content') diff --git a/tests/test_settings.py b/tests/test_settings.py index 571f66a1..ae331053 100644 --- a/tests/test_settings.py +++ b/tests/test_settings.py @@ -1,14 +1,10 @@ -try: - import unittest2 -except ImportError, e: - import unittest as unittest2 - from os.path import dirname, abspath, join from pelican.settings import read_settings, _DEFAULT_CONFIG +from .support import unittest -class TestSettingsFromFile(unittest2.TestCase): +class TestSettingsFromFile(unittest.TestCase): """Providing a file, it should read it, replace the default values and append new values to the settings, if any """ diff --git a/tests/test_utils.py b/tests/test_utils.py index 40f710d9..06843872 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -1,15 +1,10 @@ # -*- coding: utf-8 -*- -try: - import unittest2 as unittest -except ImportError: - import unittest # NOQA - import os import datetime import time from pelican import utils -from support import get_article +from .support import get_article, unittest class TestUtils(unittest.TestCase): From 0922efa371c76cb82120dcbe05f36945bacf5ec0 Mon Sep 17 00:00:00 2001 From: Andrea Crotti Date: Tue, 20 Mar 2012 13:01:21 +0000 Subject: [PATCH 4/5] change the way logging is done, using the standard log tree instead of calling the module-level functions on an unitialised logging object. This allows to - simplify log.py - use one logger object for each file --- pelican/__init__.py | 30 +++++++++++++++++------------- pelican/contents.py | 14 +++++++++----- pelican/generators.py | 19 +++++++++++-------- pelican/log.py | 37 +++++++++++++++---------------------- pelican/settings.py | 12 ++++++++---- pelican/utils.py | 18 ++++++++++-------- pelican/writers.py | 14 +++++++++----- 7 files changed, 79 insertions(+), 65 deletions(-) diff --git a/pelican/__init__.py b/pelican/__init__.py index 780938a7..2065feaa 100644 --- a/pelican/__init__.py +++ b/pelican/__init__.py @@ -1,21 +1,25 @@ -import argparse import os -import sys import re +import sys import time +import logging +import argparse from pelican.generators import (ArticlesGenerator, PagesGenerator, StaticGenerator, PdfGenerator) +from pelican.log import init from pelican.settings import read_settings, _DEFAULT_CONFIG from pelican.utils import clean_output_dir, files_changed from pelican.writers import Writer -from pelican import log __major__ = 3 __minor__ = 0 __version__ = "{0}.{1}".format(__major__, __minor__) +logger = logging.getLogger(__name__) + + class Pelican(object): def __init__(self, settings=None, path=None, theme=None, output_path=None, markup=None, delete_outputdir=False): @@ -57,7 +61,7 @@ class Pelican(object): def _handle_deprecation(self): if self.settings.get('CLEAN_URLS', False): - log.warning('Found deprecated `CLEAN_URLS` in settings. Modifing' + logger.warning('Found deprecated `CLEAN_URLS` in settings. Modifing' ' the following settings for the same behaviour.') self.settings['ARTICLE_URL'] = '{slug}/' @@ -67,10 +71,10 @@ class Pelican(object): for setting in ('ARTICLE_URL', 'ARTICLE_LANG_URL', 'PAGE_URL', 'PAGE_LANG_URL'): - log.warning("%s = '%s'" % (setting, self.settings[setting])) + logger.warning("%s = '%s'" % (setting, self.settings[setting])) if self.settings.get('ARTICLE_PERMALINK_STRUCTURE', False): - log.warning('Found deprecated `ARTICLE_PERMALINK_STRUCTURE` in' + logger.warning('Found deprecated `ARTICLE_PERMALINK_STRUCTURE` in' ' settings. Modifing the following settings for' ' the same behaviour.') @@ -91,7 +95,7 @@ class Pelican(object): 'PAGE_LANG_SAVE_AS'): self.settings[setting] = os.path.join(structure, self.settings[setting]) - log.warning("%s = '%s'" % (setting, self.settings[setting])) + logger.warning("%s = '%s'" % (setting, self.settings[setting])) def run(self): """Run the generators and return""" @@ -157,13 +161,13 @@ def main(): dest='delete_outputdir', action='store_true', help='Delete the output directory.') parser.add_argument('-v', '--verbose', action='store_const', - const=log.INFO, dest='verbosity', + const=logging.INFO, dest='verbosity', help='Show all messages.') parser.add_argument('-q', '--quiet', action='store_const', - const=log.CRITICAL, dest='verbosity', + const=logging.CRITICAL, dest='verbosity', help='Show only critical errors.') parser.add_argument('-D', '--debug', action='store_const', - const=log.DEBUG, dest='verbosity', + const=logging.DEBUG, dest='verbosity', help='Show all message, including debug messages.') parser.add_argument('--version', action='version', version=__version__, help='Print the pelican version and exit.') @@ -173,7 +177,7 @@ def main(): " on the content files.") args = parser.parse_args() - log.init(args.verbosity) + init(args.verbosity) # Split the markup languages only if some have been given. Otherwise, # populate the variable with None. markup = [a.strip().lower() for a in args.markup.split(',')]\ @@ -207,9 +211,9 @@ def main(): else: pelican.run() except Exception, e: - log.critical(unicode(e)) + logger.critical(unicode(e)) - if (args.verbosity == log.DEBUG): + if (args.verbosity == logging.DEBUG): raise else: sys.exit(getattr(e, 'exitcode', 1)) diff --git a/pelican/contents.py b/pelican/contents.py index 3386dba9..ee6b9637 100644 --- a/pelican/contents.py +++ b/pelican/contents.py @@ -1,15 +1,19 @@ # -*- coding: utf-8 -*- +import locale +import logging +import functools + from datetime import datetime from os import getenv from sys import platform, stdin -import functools -import locale -from pelican.log import warning, error + from pelican.settings import _DEFAULT_CONFIG from pelican.utils import slugify, truncate_html_words +logger = logging.getLogger(__name__) + class Page(object): """Represents a page Given a content, and metadata, create an adequate object. @@ -44,7 +48,7 @@ class Page(object): else: title = filename.decode('utf-8') if filename else self.title self.author = Author(getenv('USER', 'John Doe'), settings) - warning(u"Author of `{0}' unknown, assuming that his name is " + logger.warning(u"Author of `{0}' unknown, assuming that his name is " "`{1}'".format(title, self.author)) # manage languages @@ -200,6 +204,6 @@ def is_valid_content(content, f): content.check_properties() return True except NameError, e: - error(u"Skipping %s: impossible to find informations about '%s'"\ + logger.error(u"Skipping %s: impossible to find informations about '%s'"\ % (f, e)) return False diff --git a/pelican/generators.py b/pelican/generators.py index 71208430..4e756213 100644 --- a/pelican/generators.py +++ b/pelican/generators.py @@ -1,8 +1,9 @@ # -*- coding: utf-8 -*- import os -import datetime import math import random +import logging +import datetime from collections import defaultdict from functools import partial @@ -13,11 +14,13 @@ from jinja2 import Environment, FileSystemLoader, PrefixLoader, ChoiceLoader from jinja2.exceptions import TemplateNotFound from pelican.contents import Article, Page, Category, is_valid_content -from pelican.log import warning, error, debug, info from pelican.readers import read_file from pelican.utils import copy, process_translations, open +logger = logging.getLogger(__name__) + + class Generator(object): """Baseclass generator""" @@ -47,7 +50,7 @@ class Generator(object): extensions=self.settings.get('JINJA_EXTENSIONS', []), ) - debug('template list: {0}'.format(self._env.list_templates())) + logger.debug('template list: {0}'.format(self._env.list_templates())) # get custom Jinja filters from user settings custom_filters = self.settings.get('JINJA_FILTERS', {}) @@ -223,7 +226,7 @@ class ArticlesGenerator(Generator): try: content, metadata = read_file(f, settings=self.settings) except Exception, e: - warning(u'Could not process %s\n%s' % (f, str(e))) + logger.warning(u'Could not process %s\n%s' % (f, str(e))) continue # if no category is set, use the name of the path as a category @@ -326,7 +329,7 @@ class PagesGenerator(Generator): try: content, metadata = read_file(f) except Exception, e: - error(u'Could not process %s\n%s' % (f, str(e))) + logger.error(u'Could not process %s\n%s' % (f, str(e))) continue page = Page(content, metadata, settings=self.settings, filename=f) @@ -388,7 +391,7 @@ class PdfGenerator(Generator): # print "Generating pdf for", obj.filename, " in ", output_pdf with open(obj.filename) as f: self.pdfcreator.createPdf(text=f, output=output_pdf) - info(u' [ok] writing %s' % output_pdf) + logger.info(u' [ok] writing %s' % output_pdf) def generate_context(self): pass @@ -396,13 +399,13 @@ class PdfGenerator(Generator): def generate_output(self, writer=None): # we don't use the writer passed as argument here # since we write our own files - info(u' Generating PDF files...') + logger.info(u' Generating PDF files...') pdf_path = os.path.join(self.output_path, 'pdf') if not os.path.exists(pdf_path): try: os.mkdir(pdf_path) except OSError: - error("Couldn't create the pdf output folder in " + pdf_path) + logger.error("Couldn't create the pdf output folder in " + pdf_path) pass for article in self.context['articles']: diff --git a/pelican/log.py b/pelican/log.py index 8811b372..64fa87bd 100644 --- a/pelican/log.py +++ b/pelican/log.py @@ -1,8 +1,12 @@ +__all__ = [ + 'init' +] + import os import sys -from logging import CRITICAL, ERROR, WARN, INFO, DEBUG -from logging import critical, error, info, warning, warn, debug -from logging import Formatter, getLogger, StreamHandler +import logging + +from logging import Formatter, getLogger, StreamHandler, DEBUG RESET_TERM = u'\033[0;m' @@ -78,32 +82,21 @@ class DummyFormatter(object): def init(level=None, logger=getLogger(), handler=StreamHandler()): + logger = logging.getLogger() fmt = DummyFormatter() handler.setFormatter(fmt) logger.addHandler(handler) + if level: logger.setLevel(level) if __name__ == '__main__': init(level=DEBUG) - debug('debug') - info('info') - warning('warning') - error('error') - critical('critical') - -__all__ = [ - "debug", - "info", - "warn", - "warning", - "error", - "critical", - "DEBUG", - "INFO", - "WARN", - "ERROR", - "CRITICAL" -] + root_logger = logging.getLogger() + root_logger.debug('debug') + root_logger.info('info') + root_logger.warning('warning') + root_logger.error('error') + root_logger.critical('critical') diff --git a/pelican/settings.py b/pelican/settings.py index b38a99fd..97a2e83d 100644 --- a/pelican/settings.py +++ b/pelican/settings.py @@ -1,9 +1,13 @@ # -*- coding: utf-8 -*- import os -from os.path import isabs import locale +import logging + +from os.path import isabs + + +logger = logging.getLogger(__name__) -from pelican import log DEFAULT_THEME = os.sep.join([os.path.dirname(os.path.abspath(__file__)), "themes/notmyidea"]) @@ -102,10 +106,10 @@ def read_settings(filename=None): except locale.Error: pass else: - log.warn("LOCALE option doesn't contain a correct value") + logger.warn("LOCALE option doesn't contain a correct value") if not 'TIMEZONE' in context: - log.warn("No timezone information specified in the settings. Assuming" + 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") diff --git a/pelican/utils.py b/pelican/utils.py index 7ffd9eb9..c74b36bd 100644 --- a/pelican/utils.py +++ b/pelican/utils.py @@ -1,14 +1,16 @@ # -*- coding: utf-8 -*- import os -import pytz import re +import pytz import shutil +import logging from codecs import open as _open from datetime import datetime from itertools import groupby from operator import attrgetter -from pelican.log import warning, info + +logger = logging.getLogger(__name__) def get_date(string): @@ -71,16 +73,16 @@ def copy(path, source, destination, destination_path=None, overwrite=False): if os.path.isdir(source_): try: shutil.copytree(source_, destination_) - info('copying %s to %s' % (source_, destination_)) + logger.info('copying %s to %s' % (source_, destination_)) except OSError: if overwrite: shutil.rmtree(destination_) shutil.copytree(source_, destination_) - info('replacement of %s with %s' % (source_, destination_)) + logger.info('replacement of %s with %s' % (source_, destination_)) elif os.path.isfile(source_): shutil.copy(source_, destination_) - info('copying %s to %s' % (source_, destination_)) + logger.info('copying %s to %s' % (source_, destination_)) def clean_output_dir(path): @@ -186,14 +188,14 @@ def process_translations(content_list): default_lang_items = filter(attrgetter('in_default_lang'), items) len_ = len(default_lang_items) if len_ > 1: - warning(u'there are %s variants of "%s"' % (len_, slug)) + logger.warning(u'there are %s variants of "%s"' % (len_, slug)) for x in default_lang_items: - warning(' %s' % x.filename) + logger.warning(' %s' % x.filename) elif len_ == 0: default_lang_items = items[:1] if not slug: - warning('empty slug for %r' % (default_lang_items[0].filename,)) + logger.warning('empty slug for %r' % (default_lang_items[0].filename,)) index.extend(default_lang_items) translations.extend(filter( lambda x: x not in default_lang_items, diff --git a/pelican/writers.py b/pelican/writers.py index b27443be..7bb7ab44 100644 --- a/pelican/writers.py +++ b/pelican/writers.py @@ -1,16 +1,20 @@ # -*- coding: utf-8 -*- from __future__ import with_statement + import os +import re +import locale +import logging + from codecs import open from functools import partial -import locale -import re from feedgenerator import Atom1Feed, Rss201rev2Feed from pelican.paginator import Paginator -from pelican.log import info from pelican.utils import get_relative_path, set_date_tzinfo +logger = logging.getLogger(__name__) + class Writer(object): @@ -73,7 +77,7 @@ class Writer(object): pass fp = open(complete_path, 'w') feed.write(fp, 'utf-8') - info('writing %s' % complete_path) + logger.info('writing %s' % complete_path) fp.close() return feed @@ -108,7 +112,7 @@ class Writer(object): pass with open(filename, 'w', encoding='utf-8') as f: f.write(output) - info(u'writing %s' % filename) + logger.info(u'writing %s' % filename) localcontext = context.copy() if relative_urls: From bc7c8c14f42c28d66df78eb403de318b0b01d02c Mon Sep 17 00:00:00 2001 From: Andrea Crotti Date: Thu, 22 Mar 2012 07:02:06 +0000 Subject: [PATCH 5/5] - split main and parse arguments in two function - add '.' as default value for the path --- pelican/__init__.py | 56 ++++++++++++++++++++++++++++----------------- 1 file changed, 35 insertions(+), 21 deletions(-) diff --git a/pelican/__init__.py b/pelican/__init__.py index 2065feaa..bbcd96bf 100644 --- a/pelican/__init__.py +++ b/pelican/__init__.py @@ -139,44 +139,58 @@ class Pelican(object): return Writer(self.output_path, settings=self.settings) -def main(): +def parse_arguments(): parser = argparse.ArgumentParser(description="""A tool to generate a static blog, with restructured text input files.""", formatter_class=argparse.ArgumentDefaultsHelpFormatter) parser.add_argument(dest='path', nargs='?', - help='Path where to find the content files.') + help='Path where to find the content files.', + default='.') + parser.add_argument('-t', '--theme-path', dest='theme', help='Path where to find the theme templates. If not specified, it' 'will use the default one included with pelican.') + parser.add_argument('-o', '--output', dest='output', help='Where to output the generated files. If not specified, a ' 'directory will be created, named "output" in the current path.') + parser.add_argument('-m', '--markup', dest='markup', help='The list of markup language to use (rst or md). Please indicate ' 'them separated by commas.') + parser.add_argument('-s', '--settings', dest='settings', help='The settings of the application.') - parser.add_argument('-d', '--delete-output-directory', - dest='delete_outputdir', - action='store_true', help='Delete the output directory.') - parser.add_argument('-v', '--verbose', action='store_const', - const=logging.INFO, dest='verbosity', - help='Show all messages.') - parser.add_argument('-q', '--quiet', action='store_const', - const=logging.CRITICAL, dest='verbosity', - help='Show only critical errors.') - parser.add_argument('-D', '--debug', action='store_const', - const=logging.DEBUG, dest='verbosity', - help='Show all message, including debug messages.') - parser.add_argument('--version', action='version', version=__version__, - help='Print the pelican version and exit.') - parser.add_argument('-r', '--autoreload', dest='autoreload', - action='store_true', - help="Relaunch pelican each time a modification occurs" - " on the content files.") - args = parser.parse_args() + parser.add_argument('-d', '--delete-output-directory', + dest='delete_outputdir', + action='store_true', help='Delete the output directory.') + + parser.add_argument('-v', '--verbose', action='store_const', + const=logging.INFO, dest='verbosity', + help='Show all messages.') + + parser.add_argument('-q', '--quiet', action='store_const', + const=logging.CRITICAL, dest='verbosity', + help='Show only critical errors.') + + parser.add_argument('-D', '--debug', action='store_const', + const=logging.DEBUG, dest='verbosity', + help='Show all message, including debug messages.') + + parser.add_argument('--version', action='version', version=__version__, + help='Print the pelican version and exit.') + + parser.add_argument('-r', '--autoreload', dest='autoreload', + action='store_true', + help="Relaunch pelican each time a modification occurs" + " on the content files.") + return parser.parse_args() + + +def main(): + args = parse_arguments() init(args.verbosity) # Split the markup languages only if some have been given. Otherwise, # populate the variable with None.