From a937424faa1fd2a7ecf47321c2c5de9ec3194c64 Mon Sep 17 00:00:00 2001 From: Alexander Artemenko Date: Sat, 25 Dec 2010 17:26:24 +0300 Subject: [PATCH 1/5] Base routines were transformed into the class Pelican. This class could be overridden using PELICAN_CLASS option. --- pelican/__init__.py | 125 +++++++++++++++++++++++++------------------- pelican/settings.py | 1 + 2 files changed, 73 insertions(+), 53 deletions(-) diff --git a/pelican/__init__.py b/pelican/__init__.py index 915d92c7..f0684d65 100755 --- a/pelican/__init__.py +++ b/pelican/__init__.py @@ -10,71 +10,79 @@ from pelican.generators import (ArticlesGenerator, PagesGenerator, VERSION = "2.5.3" -def init_params(settings=None, path=None, theme=None, output_path=None, - markup=None, keep=False): - """Read the settings, and performs some checks on the environment - before doing anything else. - """ - if settings is None: - settings = {} - settings = read_settings(settings) - path = path or settings['PATH'] - if path.endswith('/'): - path = path[:-1] +class Pelican(object): + def __init__(self, settings=None, path=None, theme=None, output_path=None, + markup=None, keep=False): + """Read the settings, and performs some checks on the environment + before doing anything else. + """ + self.path = path or settings['PATH'] + if self.path.endswith('/'): + self.path = path[:-1] - # define the default settings - theme = theme or settings['THEME'] - output_path = output_path or settings['OUTPUT_PATH'] - output_path = os.path.realpath(output_path) - markup = markup or settings['MARKUP'] - keep = keep or settings['KEEP_OUTPUT_DIRECTORY'] + # define the default settings + self.settings = settings + self.theme = theme or settings['THEME'] + self.path = path + output_path = output_path or settings['OUTPUT_PATH'] + self.output_path = os.path.realpath(output_path) + self.markup = markup or settings['MARKUP'] + self.keep = keep or settings['KEEP_OUTPUT_DIRECTORY'] - # find the theme in pelican.theme if the given one does not exists - if not os.path.exists(theme): - theme_path = os.sep.join([os.path.dirname( - os.path.abspath(__file__)), "themes/%s" % theme]) - if os.path.exists(theme_path): - theme = theme_path - else: - raise Exception("Impossible to find the theme %s" % theme) + # find the theme in pelican.theme if the given one does not exists + if not os.path.exists(self.theme): + theme_path = os.sep.join([os.path.dirname( + os.path.abspath(__file__)), "themes/%s" % self.theme]) + if os.path.exists(theme_path): + self.theme = theme_path + else: + raise Exception("Impossible to find the theme %s" % theme) - # get the list of files to parse - if not path: - raise Exception('you need to specify a path to search the docs on !') - - return settings, path, theme, output_path, markup, keep + # get the list of files to parse + if not self.path: + raise Exception('you need to specify a path to search the docs on !') -def run_generators(generators, settings, path, theme, output_path, markup, keep): - """Run the generators and return""" + def run(self): + """Run the generators and return""" - context = settings.copy() - generators = [p(context, settings, path, theme, output_path, markup, keep) - for p in generators] + context = self.settings.copy() + generators = [ + cls( + context, + self.settings, + self.path, + self.theme, + self.output_path, + self.markup, + self.keep + ) for cls in self.get_generator_classes() + ] - for p in generators: - if hasattr(p, 'generate_context'): - p.generate_context() + for p in generators: + if hasattr(p, 'generate_context'): + p.generate_context() - # erase the directory if it is not the source - if output_path not in os.path.realpath(path) and not keep: - clean_output_dir(output_path) + # erase the directory if it is not the source + if os.path.realpath(self.path).startswith(self.output_path) and not keep: + clean_output_dir(self.output_path) - writer = Writer(output_path) + writer = self.get_writer() - for p in generators: - if hasattr(p, 'generate_output'): - p.generate_output(writer) + for p in generators: + if hasattr(p, 'generate_output'): + p.generate_output(writer) -def run_pelican(settings, path, theme, output_path, markup, delete): - """Run pelican with the given parameters""" + def get_generator_classes(self): + generators = [ArticlesGenerator, PagesGenerator, StaticGenerator] + if self.settings['PDF_GENERATOR']: + generators.append(PdfGenerator) + return generators + + def get_writer(self): + return Writer(self.output_path) - params = init_params(settings, path, theme, output_path, markup, delete) - generators = [ArticlesGenerator, PagesGenerator, StaticGenerator] - if params[0]['PDF_GENERATOR']: # param[0] is settings - generators.append(PdfGenerator) - run_generators(generators, *params) def main(): @@ -106,7 +114,18 @@ def main(): # the variable with None. markup = [a.strip().lower() for a in args.markup.split(',')] if args.markup else None - run_pelican(args.settings, args.path, args.theme, args.output, markup, args.keep) + if args.settings is None: + settings = {} + settings = read_settings(args.settings) + + cls = settings.get('PELICAN_CLASS') + if isinstance(cls, basestring): + module, cls_name = cls.rsplit('.', 1) + module = __import__(module) + cls = getattr(module, cls_name) + + pelican = cls(settings, args.path, args.theme, args.output, markup, args.keep) + pelican.run() if __name__ == '__main__': diff --git a/pelican/settings.py b/pelican/settings.py index 8f0dcdbd..0fef4fec 100644 --- a/pelican/settings.py +++ b/pelican/settings.py @@ -22,6 +22,7 @@ _DEFAULT_CONFIG = {'PATH': None, 'CLEAN_URLS': False, # use /blah/ instead /blah.html in urls 'RELATIVE_URLS': True, 'DEFAULT_LANG': 'en', + 'PELICAN_CLASS': 'pelican.Pelican', } def read_settings(filename): From 03104bfbc3b9221b9b559888b1c44ac803c1429d Mon Sep 17 00:00:00 2001 From: Alexander Artemenko Date: Sat, 25 Dec 2010 17:58:47 +0300 Subject: [PATCH 2/5] Feed writer was refactored to allow more granular overriding of functionality. --- pelican/writers.py | 39 ++++++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/pelican/writers.py b/pelican/writers.py index e71156c0..b6095d3b 100644 --- a/pelican/writers.py +++ b/pelican/writers.py @@ -11,6 +11,25 @@ class Writer(object): def __init__(self, output_path): self.output_path = output_path + def _create_new_feed(self, feed_type, context): + feed_class = Rss201rev2Feed if feed_type == 'rss' else Atom1Feed + feed = feed_class( + title=context['SITENAME'], + link=self.site_url, + feed_url=self.feed_url, + description=context.get('SITESUBTITLE', '')) + return feed + + + def _add_item_to_the_feed(self, feed, item): + feed.add_item( + title=item.title, + link='%s/%s' % (self.site_url, item.url), + description=item.content, + categories=item.tags if hasattr(item, 'tags') else None, + author_name=getattr(item, 'author', 'John Doe'), + pubdate=item.date) + def write_feed(self, elements, context, filename=None, feed_type='atom'): """Generate a feed with the list of articles provided @@ -23,23 +42,13 @@ class Writer(object): :param filename: the filename to output. :param feed_type: the feed type to use (atom or rss) """ - site_url = context.get('SITEURL', get_relative_path(filename)) + self.site_url = context.get('SITEURL', get_relative_path(filename)) + self.feed_url= '%s/%s' % (self.site_url, filename) - feed_class = Rss201rev2Feed if feed_type == 'rss' else Atom1Feed + feed = self._create_new_feed(feed_type, context) - feed = feed_class( - title=context['SITENAME'], - link=site_url, - feed_url= "%s/%s" % (site_url, filename), - description=context.get('SITESUBTITLE', '')) - for element in elements: - feed.add_item( - title=element.title, - link= "%s/%s" % (site_url, element.url), - description=element.content, - categories=element.tags if hasattr(element, "tags") else None, - author_name=getattr(element, 'author', 'John Doe'), - pubdate=element.date) + for item in elements: + self._add_item_to_the_feed(feed, item) if filename: complete_path = os.path.join(self.output_path, filename) From 01b4c069162bb332d2c3cef6e9d324abebe4317c Mon Sep 17 00:00:00 2001 From: Alexander Artemenko Date: Sun, 26 Dec 2010 23:59:30 +0300 Subject: [PATCH 3/5] Custom bicycle 'update_dict' was replaced with 'collections.defaultdict'. --- pelican/generators.py | 10 +++++----- pelican/utils.py | 11 ----------- 2 files changed, 5 insertions(+), 16 deletions(-) diff --git a/pelican/generators.py b/pelican/generators.py index 88ee6919..18dba81a 100755 --- a/pelican/generators.py +++ b/pelican/generators.py @@ -8,7 +8,7 @@ import os from jinja2 import Environment, FileSystemLoader from jinja2.exceptions import TemplateNotFound -from pelican.utils import update_dict, copytree, process_translations, open +from pelican.utils import copytree, process_translations, open from pelican.contents import Article, Page, is_valid_content from pelican.readers import read_file @@ -81,8 +81,8 @@ class ArticlesGenerator(Generator): self.articles = [] # only articles in default language self.translations = [] self.dates = {} - self.tags = {} - self.categories = {} + self.tags = defaultdict(list) + self.categories = defaultdict(list) super(ArticlesGenerator, self).__init__(*args, **kwargs) def generate_feeds(self, writer): @@ -178,14 +178,14 @@ class ArticlesGenerator(Generator): if hasattr(article, 'tags'): for tag in article.tags: - update_dict(self.tags, tag, article) + self.tags[tag].append(article) all_articles.append(article) self.articles, self.translations = process_translations(all_articles) for article in self.articles: # only main articles are listed in categories, not translations - update_dict(self.categories, article.category, article) + self.categories[article.category].append(article) # sort the articles by date diff --git a/pelican/utils.py b/pelican/utils.py index fe7ab009..9641b078 100644 --- a/pelican/utils.py +++ b/pelican/utils.py @@ -7,17 +7,6 @@ from codecs import open as _open from itertools import groupby from operator import attrgetter -def update_dict(mapping, key, value): - """Update a dict intenal list - - :param mapping: the mapping to update - :param key: the key of the mapping to update. - :param value: the value to append to the list. - """ - if key not in mapping: - mapping[key] = [] - mapping[key].append(value) - def get_date(string): """Return a datetime object from a string. From 6e4a826dc1b64bde468f987a387d3baa28c6dd66 Mon Sep 17 00:00:00 2001 From: Alexis Metaireau Date: Thu, 6 Jan 2011 02:33:14 +0100 Subject: [PATCH 4/5] Update the translation documentation. --- docs/getting_started.rst | 36 ++++++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/docs/getting_started.rst b/docs/getting_started.rst index f66a6f06..0b928afe 100644 --- a/docs/getting_started.rst +++ b/docs/getting_started.rst @@ -91,7 +91,39 @@ the menu. Translations ============ -It is possible to translate articles. To do so, you need to add a `Lang` meta +It is possible to translate articles. To do so, you need to add a `lang` meta in your articles/pages, and to set a `DEFAULT_LANG` setting (which is en by -default). Then, only articles with this default language will be listed, and +default). +Then, only articles with this default language will be listed, and each article will have a translation list. + +Pelican uses the "slug" of two articles to compare if they are translations of +each others. So it's possible to define (in restructured text) the slug +directly. + +Here is an exemple of two articles (one in english and the other one in +french). + +The english one:: + + Foobar is not dead + ################## + + :slug: foobar-is-not-dead + :lang: en + + That's true, foobar is still alive ! + +And the french one:: + + Foobar n'est pas mort ! + ####################### + + :slug: foobar-is-not-dead + :lang: fr + + Oui oui, foobar est toujours vivant ! + +Despite the text quality, you can see that only the slug is the same here. +You're not forced to define the slug that way, and it's completely possible to +have two translations with the same title (which defines the slug) From 30c2a0b681187180ca8228e0160962c6f25e794c Mon Sep 17 00:00:00 2001 From: Alexis Metaireau Date: Thu, 6 Jan 2011 02:37:37 +0100 Subject: [PATCH 5/5] Update doc version. --- docs/conf.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/conf.py b/docs/conf.py index 5b24d67c..507e30a3 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -15,6 +15,8 @@ project = u'Pelican' copyright = u'2010, Alexis Metaireau and contributors' exclude_patterns = ['_build'] pygments_style = 'sphinx' +version = "2" +release = version # -- Options for HTML output ---------------------------------------------------