From 105b5c2863bfa4e578bcd92533e51595fcfd3495 Mon Sep 17 00:00:00 2001 From: Nicolas Duhamel Date: Thu, 21 Apr 2011 17:10:00 +0200 Subject: [PATCH 01/46] Add subtitle --- pelican/readers.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pelican/readers.py b/pelican/readers.py index 4e1d7b2e..6d0b6cea 100644 --- a/pelican/readers.py +++ b/pelican/readers.py @@ -49,9 +49,14 @@ class RstReader(Reader): rendered_content = core.publish_parts(text, writer_name='html', settings_overrides=extra_params) title = rendered_content.get('title') + subtitle = rendered_content.get('subtitle') or '' content = rendered_content.get('body') + if not metadatas.has_key('title'): metadatas['title'] = title + if not metadatas.has_key('subtitle'): + metadatas['subtitle'] = subtitle + return content, metadatas class MarkdownReader(Reader): From 98ed7338e6c360dd82f0220971851c39875d3cb3 Mon Sep 17 00:00:00 2001 From: Alexis Metaireau Date: Thu, 21 Apr 2011 19:26:12 +0200 Subject: [PATCH 02/46] add a test metadata for #98 --- samples/content/another_super_article.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/samples/content/another_super_article.rst b/samples/content/another_super_article.rst index abe8d26c..5ec1e2b8 100644 --- a/samples/content/another_super_article.rst +++ b/samples/content/another_super_article.rst @@ -6,6 +6,7 @@ Oh yeah ! :category: bar :author: Alexis Métaireau :slug: oh-yeah +:license: WTFPL Why not ? ========= From bb0d4bcc2f755e5ae27f41d402c158bba7496b6d Mon Sep 17 00:00:00 2001 From: Alexis Metaireau Date: Sun, 24 Apr 2011 13:05:40 +0200 Subject: [PATCH 03/46] =?UTF-8?q?Add=20documentation=20about=20the=20RELAT?= =?UTF-8?q?IVE=5FURLS=20setting.=20Thanks=20to=20G=C3=BCnter=20Kolousek.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- THANKS | 1 + docs/settings.rst | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/THANKS b/THANKS index 078a67d1..4a8a52a5 100644 --- a/THANKS +++ b/THANKS @@ -14,3 +14,4 @@ bugs or giving ideas. Thanks to them ! - Laureline Guérin - Samuel Martin - Marcus Fredriksson +- Günter Kolousek diff --git a/docs/settings.rst b/docs/settings.rst index 67039832..e3f4a94e 100644 --- a/docs/settings.rst +++ b/docs/settings.rst @@ -63,11 +63,16 @@ Setting name what it does ? `PATH` path to look at for input files. `PDF_PROCESSOR` Put True if you want to have PDF versions of your documents. You will need to install `rst2pdf`. +`RELATIVE_URL` Defines if pelican should use relative urls or not. + It is set to True per default. `REVERSE_ARCHIVE_ORDER` Reverse the archives order. (True makes it in descending order: the newer first) `REVERSE_CATEGORY_ORDER` Reverse the category order. (True makes it in descending order, default is alphabetically) -`SITEURL` base URL of your website. +`SITEURL` base URL of your website. Note that this is not + a way to tell pelican to use relative urls or + static ones. You should rather use the `RELATIVE_URL` + setting for such use. `SITENAME` Your site name, `SKRIBIT_TYPE` The type of skribit widget (TAB or WIDGET). `SKRIBIT_TAB_COLOR` Tab color (#XXXXXX, default #333333). From 8de525fa281a8052a57c7f9f2fde41b48e3b5e07 Mon Sep 17 00:00:00 2001 From: Skami18 Date: Mon, 25 Apr 2011 12:13:44 +0200 Subject: [PATCH 04/46] Removed a bug (debug messages was not showed) and improved readability --- pelican/log.py | 98 ++++++++++++++++++++++++++------------------------ 1 file changed, 52 insertions(+), 46 deletions(-) diff --git a/pelican/log.py b/pelican/log.py index b895ad66..72b7a017 100644 --- a/pelican/log.py +++ b/pelican/log.py @@ -1,46 +1,51 @@ -import logging +from logging import * import sys import os global ANSI ANSI = { - 'gray' : lambda(text) : '\033[1;30m' + unicode(text) + '\033[1;m', - 'red' : lambda(text) : '\033[1;31m' + unicode(text) + '\033[1;m', - 'green' : lambda(text) : '\033[1;32m' + unicode(text) + '\033[1;m', - 'yellow' : lambda(text) : '\033[1;33m' + unicode(text) + '\033[1;m', - 'blue' : lambda(text) : '\033[1;34m' + unicode(text) + '\033[1;m', - 'magenta' : lambda(text) : '\033[1;35m' + unicode(text) + '\033[1;m', - 'cyan' : lambda(text) : '\033[1;36m' + unicode(text) + '\033[1;m', - 'white' : lambda(text) : '\033[1;37m' + unicode(text) + '\033[1;m', - 'crimson' : lambda(text) : '\033[1;38m' + unicode(text) + '\033[1;m', - 'bgred' : lambda(text) : '\033[1;41m' + unicode(text) + '\033[1;m', - 'bggreen' : lambda(text) : '\033[1;42m' + unicode(text) + '\033[1;m', - 'bgbrown' : lambda(text) : '\033[1;43m' + unicode(text) + '\033[1;m', - 'bgblue' : lambda(text) : '\033[1;44m' + unicode(text) + '\033[1;m', - 'bgmagenta' : lambda(text) : '\033[1;45m' + unicode(text) + '\033[1;m', - 'bgcyan' : lambda(text) : '\033[1;46m' + unicode(text) + '\033[1;m', - 'bggray' : lambda(text) : '\033[1;47m' + unicode(text) + '\033[1;m', - 'bgcrimson' : lambda(text) : '\033[1;48m' + unicode(text) + '\033[1;m' + 'gray' : lambda(text) : u'\033[1;30m' + unicode(text) + u'\033[1;m', + 'red' : lambda(text) : u'\033[1;31m' + unicode(text) + u'\033[1;m', + 'green' : lambda(text) : u'\033[1;32m' + unicode(text) + u'\033[1;m', + 'yellow' : lambda(text) : u'\033[1;33m' + unicode(text) + u'\033[1;m', + 'blue' : lambda(text) : u'\033[1;34m' + unicode(text) + u'\033[1;m', + 'magenta' : lambda(text) : u'\033[1;35m' + unicode(text) + u'\033[1;m', + 'cyan' : lambda(text) : u'\033[1;36m' + unicode(text) + u'\033[1;m', + 'white' : lambda(text) : u'\033[1;37m' + unicode(text) + u'\033[1;m', + 'bgred' : lambda(text) : u'\033[1;41m' + unicode(text) + u'\033[1;m', + 'bggreen' : lambda(text) : u'\033[1;42m' + unicode(text) + u'\033[1;m', + 'bgbrown' : lambda(text) : u'\033[1;43m' + unicode(text) + u'\033[1;m', + 'bgblue' : lambda(text) : u'\033[1;44m' + unicode(text) + u'\033[1;m', + 'bgmagenta' : lambda(text) : u'\033[1;45m' + unicode(text) + u'\033[1;m', + 'bgcyan' : lambda(text) : u'\033[1;46m' + unicode(text) + u'\033[1;m', + 'bggray' : lambda(text) : u'\033[1;47m' + unicode(text) + u'\033[1;m', + 'bgyellow' : lambda(text) : u'\033[1;43m' + unicode(text) + u'\033[1;m', + 'bggrey' : lambda(text) : u'\033[1;100m' + unicode(text) + u'\033[1;m' } -class ANSIFormatter(logging.Formatter): + +class ANSIFormatter(Formatter): """ Convert a `logging.LogReport' object into colored text, using ANSI escape sequences. """ ## colors: def format(self, record): - if not record.levelname or record.levelname is 'INFO': - return ANSI['white'](record.msg) + if record.levelname is 'INFO': + return ANSI['cyan']('-> ') + unicode(record.msg) elif record.levelname is 'WARNING': - return ANSI['yellow'](record.levelname) + ': ' + record.msg + return ANSI['yellow'](record.levelname) + ': ' + unicode(record.msg) elif record.levelname is 'ERROR': - return ANSI['red'](record.levelname) + ': ' + record.msg + return ANSI['red'](record.levelname) + ': ' + unicode(record.msg) elif record.levelname is 'CRITICAL': - return ANSI['bgred'](record.levelname) + ': ' + record.msg + return ANSI['bgred'](record.levelname) + ': ' + unicode(record.msg) + elif record.levelname is 'DEBUG': + return ANSI['bggrey'](record.levelname) + ': ' + unicode(record.msg) + else: + return ANSI['white'](record.levelname) + ': ' + unicode(record.msg) -class TextFormatter(logging.Formatter): +class TextFormatter(Formatter): """ Convert a `logging.LogReport' object into text. """ @@ -52,7 +57,7 @@ class TextFormatter(logging.Formatter): return record.levelname + ': ' + record.msg -class Formatter(object): +class DummyFormatter(object): """ A dummy class. Return an instance of the appropriate formatter (ANSIFormatter if sys.stdout.isatty() is True, else TextFormatter) @@ -66,21 +71,10 @@ class Formatter(object): -# shortcuts -debug, info, warn, error, critical = (logging.debug, - logging.info, - logging.warn, - logging.error, - logging.critical) -DEBUG, INFO, WARN, ERROR, CRITICAL = (logging.DEBUG, - logging.INFO, - logging.WARN, - logging.ERROR, - logging.CRITICAL) -def init(level=None, logger=logging.getLogger(), handler=logging.StreamHandler()): - fmt = Formatter() +def init(level=None, logger=getLogger(), handler=StreamHandler()): + fmt = DummyFormatter() handler.setFormatter(fmt) logger.addHandler(handler) if level: @@ -88,11 +82,23 @@ def init(level=None, logger=logging.getLogger(), handler=logging.StreamHandler() if __name__ == '__main__': - init() - logging.basicConfig(filename='example.log',level=logging.DEBUG) - logging.debug('Logging test') - logging.info('info') - logging.warning('warning') - logging.error('error') - logging.critical('critical') + init(level=DEBUG) + debug('debug') + info('info') + warning('warning') + error('error') + critical('critical') + +__all__ = [ + "debug", + "info", + "warn", + "error", + "critical", + "DEBUG", + "INFO", + "WARN", + "ERROR", + "CRITICAL" +] From 764a135bb3a37d6be0fc08c3ddc67aaa7409314b Mon Sep 17 00:00:00 2001 From: Simon Liedtke Date: Sun, 24 Apr 2011 09:05:38 -0700 Subject: [PATCH 05/46] Pelican is an "it", not a "he" --- docs/getting_started.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/getting_started.rst b/docs/getting_started.rst index d90e1fe8..fc2e171e 100644 --- a/docs/getting_started.rst +++ b/docs/getting_started.rst @@ -38,7 +38,7 @@ Writing articles using pelican Files metadata -------------- -Pelican tries to be smart enough to get the informations he needs from the +Pelican tries to be smart enough to get the informations it needs from the file system (for instance, about the category of your articles), but you need to provide by hand some of those informations in your files. From b6b7238519f6049c932d5c1e542bdc5483fb7327 Mon Sep 17 00:00:00 2001 From: Simon Liedtke Date: Sun, 24 Apr 2011 09:24:05 -0700 Subject: [PATCH 06/46] removed unused import --- pelican/__init__.py | 1 - 1 file changed, 1 deletion(-) mode change 100755 => 100644 pelican/__init__.py diff --git a/pelican/__init__.py b/pelican/__init__.py old mode 100755 new mode 100644 index 497e5d0d..195ada34 --- a/pelican/__init__.py +++ b/pelican/__init__.py @@ -1,6 +1,5 @@ import argparse import os -from functools import partial from pelican.generators import (ArticlesGenerator, PagesGenerator, StaticGenerator, PdfGenerator) From ec9525a3e82a9c279b476c5bc6aeb0a0883f1804 Mon Sep 17 00:00:00 2001 From: derdon Date: Mon, 25 Apr 2011 00:33:55 +0200 Subject: [PATCH 07/46] include the default values of the settings in the 1st column in parens this way, it is much easier for the reader to see which variable has which default value. I also added some default values which could not be found in the documentation before. --- docs/settings.rst | 157 +++++++++++++++++++++++----------------------- 1 file changed, 79 insertions(+), 78 deletions(-) diff --git a/docs/settings.rst b/docs/settings.rst index e3f4a94e..498f60cd 100644 --- a/docs/settings.rst +++ b/docs/settings.rst @@ -20,84 +20,85 @@ Here are the available settings. Please note that all the settings you put in this file will be passed to the templates as well. -======================== ======================================================= -Setting name what it does ? -======================== ======================================================= -`AUTHOR` Default author (put your name) -`CATEGORY_FEED` Where to put the atom categories feeds. default is - `feeds/%s.atom.xml`, where %s is the name of the - category. -`CATEGORY_FEED_RSS` Where to put the categories rss feeds. default is None - (no rss) -`CSS_FILE` To specify the CSS file you want to load, if it's not - the default one ('main.css') -`DATE_FORMATS` If you do manage multiple languages, you can set - the date formatting here. -`DEFAULT_CATEGORY` The default category to fallback on. `misc` by default. -`DEFAULT_DATE_FORMAT` The default date format you want to use. -`DEFAULT_LANG` The default language to use. Default is 'en'. -`DEFAULT_ORPHANS` The minimum number of articles allowed on the last - page, defaults to zero. Use this when you don't want - to have a last page with very few articles. -`DEFAULT_PAGINATION` The maximum number of articles to include on a page, - not including orphans. Default is 5. -`DISPLAY_PAGES_ON_MENU` Display or not the pages on the menu of the template. - Templates can follow or not this settings. -`FALLBACK_ON_FS_DATE` If True, pelican will use the file system dates infos - (mtime) if it can't get informations from the - metadata? -`FEED` relative url to output the atom feed. Default is - `feeds/all.atom.xml` -`FEED_RSS` relative url to output the rss feed. Default is - None (no rss) -`JINJA_EXTENSIONS` A list of any Jinja2 extensions you want to use. - Default is no extensions (the empty list). -`KEEP_OUTPUT_DIRECTORY` Keep the output directory and just update all the - generated files. -`LOCALE` Change the locale. Default is the system locale. - Default is to delete the output directory. -`MARKUP` A list of available markup languages you want to use. - For the moment, only available values are `rst` and `md`. -`OUTPUT_PATH` Where to output the generated files. Default to - "output" -`PATH` path to look at for input files. -`PDF_PROCESSOR` Put True if you want to have PDF versions of your - documents. You will need to install `rst2pdf`. -`RELATIVE_URL` Defines if pelican should use relative urls or not. - It is set to True per default. -`REVERSE_ARCHIVE_ORDER` Reverse the archives order. (True makes it in - descending order: the newer first) -`REVERSE_CATEGORY_ORDER` Reverse the category order. (True makes it in - descending order, default is alphabetically) -`SITEURL` base URL of your website. Note that this is not - a way to tell pelican to use relative urls or - static ones. You should rather use the `RELATIVE_URL` - setting for such use. -`SITENAME` Your site name, -`SKRIBIT_TYPE` The type of skribit widget (TAB or WIDGET). -`SKRIBIT_TAB_COLOR` Tab color (#XXXXXX, default #333333). -`SKRIBIT_TAB_HORIZ` Tab Distance from Left (% or distance, default Null). -`SKRIBIT_TAB_VERT` Tab Distance from Top (% or distance, default 20%). -`SKRIBIT_TAB_PLACEMENT` Tab placement (Top, Bottom, Left or Right, default - LEFT). -`SKRIBIT_TAB_SITENAME` Tab identifier (See Skribit part below). -`SKRIBIT_WIDGET_ID` Widget identifier (See Skribit part below). -`STATIC_PATHS` The static paths you want to have accessible on the - output path "static". By default, pelican will copy - the 'images' folder to the output folder. -`STATIC_THEME_PATHS` Static theme paths you want to copy. Default values - is `static`, but if your theme have others static paths, - you can put them here. -`TAG_CLOUD_STEPS` Count of different font sizes in the tag cloud. -`TAG_CLOUD_MAX_ITEMS` Maximum tags count in the cloud. -`THEME` theme to use to product the output. can be the - complete static path to a theme folder, or chosen - between the list of default themes (see below) -`TRANSLATION_FEED` Where to put the RSS feed for translations. Default - is feeds/all-%s.atom.xml where %s is the name of the - lang. -`WITH_PAGINATION` Activate pagination. Default is False. -======================== ======================================================= +================================================ ===================================================== +Setting name (default value) what does it do? +================================================ ===================================================== +`AUTHOR` Default author (put your name) +`CATEGORY_FEED` ('feeds/%s.atom.xml'[1]_) Where to put the atom categories feeds. +`CATEGORY_FEED_RSS` (``None``, i.e. no RSS) Where to put the categories rss feeds. +`CSS_FILE` (``'main.css'``) specify the CSS file you want to load +`DATE_FORMATS` (``{}``) If you do manage multiple languages, you can + set the date formatting here. +`DEFAULT_CATEGORY` (``'misc'``) The default category to fallback on. +`DEFAULT_DATE_FORMAT` (``'%a %d %B %Y'``) The default date format you want to use. +`DEFAULT_LANG` (``'en'``) The default language to use. +`DEFAULT_ORPHANS` (0) The minimum number of articles allowed on the + last page. Use this when you don't want to + have a last page with very few articles. +`DEFAULT_PAGINATION` (5) The maximum number of articles to include on a + page, not including orphans. +`DISPLAY_PAGES_ON_MENU` (``True``) Display or not the pages on the menu of the + template. Templates can follow or not this + settings. +`FALLBACK_ON_FS_DATE` (``True``) If True, pelican will use the file system + dates infos (mtime) if it can't get + informations from the metadata? +`FEED` (``'feeds/all.atom.xml'``) relative url to output the atom feed. +`FEED_RSS` (``None``, i.e. no RSS) relative url to output the rss feed. +`JINJA_EXTENSIONS` (``[]``) A list of any Jinja2 extensions you want to use. +`KEEP_OUTPUT_DIRECTORY` (``False``) Keep the output directory and just update all + the generated files. +`LOCALE` (''[2]_) Change the locale. +`MARKUP` (``('rst', 'md')``) A list of available markup languages you want + to use. For the moment, only available values + are `rst` and `md`. +`OUTPUT_PATH` (``'output/'``) Where to output the generated files. +`PATH` (``None``) path to look at for input files. +`PDF_PROCESSOR` (``False``) Set to True if you want to have PDF versions + of your documents. You will need to install + `rst2pdf`. +`RELATIVE_URL` (``True``) Defines if pelican should use relative urls or + not. +`REVERSE_ARCHIVE_ORDER` (``False``) Reverse the archives order. (True makes it in + descending order: the newer first) +`REVERSE_CATEGORY_ORDER` (``False``) Reverse the category order. (True makes it in + descending order, default is alphabetically) +`SITEURL` base URL of your website. Note that this is + not a way to tell pelican to use relative urls + or static ones. You should rather use the + `RELATIVE_URL` setting for such use. +`SITENAME` (``'A Pelican Blog'``) Your site name, +`SKRIBIT_TYPE` The type of skribit widget (TAB or WIDGET). +`SKRIBIT_TAB_COLOR` Tab color (#XXXXXX, default #333333). +`SKRIBIT_TAB_HORIZ` Tab Distance from Left (% or distance, default Null). +`SKRIBIT_TAB_VERT` Tab Distance from Top (% or distance, default 20%). +`SKRIBIT_TAB_PLACEMENT` Tab placement (Top, Bottom, Left or Right, + default LEFT). +`SKRIBIT_TAB_SITENAME` Tab identifier (See Skribit part below). +`SKRIBIT_WIDGET_ID` Widget identifier (See Skribit part below). +`STATIC_PATHS` The static paths you want to have accessible +(``['images']``) on the output path "static". By default, + pelican will copy the 'images' folder to the + output folder. +`STATIC_THEME_PATHS` (``['static']``) Static theme paths you want to copy. Default + values is `static`, but if your theme have + others static paths, you can put them here. +`TAG_CLOUD_STEPS` (4) Count of different font sizes in the tag + cloud. +`TAG_CLOUD_MAX_ITEMS` (100) Maximum tags count in the cloud. +`THEME` theme to use to product the output. can be the + complete static path to a theme folder, or + chosen between the list of default themes (see + below) +`TRANSLATION_FEED` ('feeds/all-%s.atom.xml'[3]_) Where to put the RSS feed for translations. +`WITH_PAGINATION` (``False``) Activate pagination. +================================================ ===================================================== + +.. [1] %s is the name of the category. + +.. [2] Default is the system locale. Default is to delete the output directory. + +.. [3] %s is the language Skribit ======= From c8d20a70648debb1148a0e9bdd616652929a5a57 Mon Sep 17 00:00:00 2001 From: derdon Date: Mon, 25 Apr 2011 00:36:15 +0200 Subject: [PATCH 08/46] fixed the writings of two variable names in the settings table --- docs/settings.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/settings.rst b/docs/settings.rst index 498f60cd..66152a3e 100644 --- a/docs/settings.rst +++ b/docs/settings.rst @@ -54,7 +54,7 @@ Setting name (default value) what does it do? are `rst` and `md`. `OUTPUT_PATH` (``'output/'``) Where to output the generated files. `PATH` (``None``) path to look at for input files. -`PDF_PROCESSOR` (``False``) Set to True if you want to have PDF versions +`PDF_GENERATOR` (``False``) Set to True if you want to have PDF versions of your documents. You will need to install `rst2pdf`. `RELATIVE_URL` (``True``) Defines if pelican should use relative urls or @@ -80,7 +80,7 @@ Setting name (default value) what does it do? (``['images']``) on the output path "static". By default, pelican will copy the 'images' folder to the output folder. -`STATIC_THEME_PATHS` (``['static']``) Static theme paths you want to copy. Default +`THEME_STATIC_PATHS` (``['static']``) Static theme paths you want to copy. Default values is `static`, but if your theme have others static paths, you can put them here. `TAG_CLOUD_STEPS` (4) Count of different font sizes in the tag From 1ef913cb6434240640b2308cc1a2e220b056ce70 Mon Sep 17 00:00:00 2001 From: derdon Date: Mon, 25 Apr 2011 00:38:15 +0200 Subject: [PATCH 09/46] various grammar fixes --- docs/settings.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/settings.rst b/docs/settings.rst index 66152a3e..064bc64e 100644 --- a/docs/settings.rst +++ b/docs/settings.rst @@ -81,12 +81,12 @@ Setting name (default value) what does it do? pelican will copy the 'images' folder to the output folder. `THEME_STATIC_PATHS` (``['static']``) Static theme paths you want to copy. Default - values is `static`, but if your theme have - others static paths, you can put them here. + values is `static`, but if your theme has + other static paths, you can put them here. `TAG_CLOUD_STEPS` (4) Count of different font sizes in the tag cloud. `TAG_CLOUD_MAX_ITEMS` (100) Maximum tags count in the cloud. -`THEME` theme to use to product the output. can be the +`THEME` theme to use to produce the output. can be the complete static path to a theme folder, or chosen between the list of default themes (see below) From 6b62ed867379b6b6c4a513aaacaccc27113547a8 Mon Sep 17 00:00:00 2001 From: derdon Date: Mon, 25 Apr 2011 00:39:21 +0200 Subject: [PATCH 10/46] removed a useless comma --- docs/settings.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/settings.rst b/docs/settings.rst index 064bc64e..a40ebbb9 100644 --- a/docs/settings.rst +++ b/docs/settings.rst @@ -67,7 +67,7 @@ Setting name (default value) what does it do? not a way to tell pelican to use relative urls or static ones. You should rather use the `RELATIVE_URL` setting for such use. -`SITENAME` (``'A Pelican Blog'``) Your site name, +`SITENAME` (``'A Pelican Blog'``) Your site name `SKRIBIT_TYPE` The type of skribit widget (TAB or WIDGET). `SKRIBIT_TAB_COLOR` Tab color (#XXXXXX, default #333333). `SKRIBIT_TAB_HORIZ` Tab Distance from Left (% or distance, default Null). From 60807d1958eca0d46d77870e0353d0b3215436e1 Mon Sep 17 00:00:00 2001 From: derdon Date: Mon, 25 Apr 2011 00:40:42 +0200 Subject: [PATCH 11/46] removed a confusing question mark --- docs/settings.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/settings.rst b/docs/settings.rst index a40ebbb9..795f220c 100644 --- a/docs/settings.rst +++ b/docs/settings.rst @@ -42,7 +42,7 @@ Setting name (default value) what does it do? settings. `FALLBACK_ON_FS_DATE` (``True``) If True, pelican will use the file system dates infos (mtime) if it can't get - informations from the metadata? + informations from the metadata `FEED` (``'feeds/all.atom.xml'``) relative url to output the atom feed. `FEED_RSS` (``None``, i.e. no RSS) relative url to output the rss feed. `JINJA_EXTENSIONS` (``[]``) A list of any Jinja2 extensions you want to use. From 51f760edc2ab4a2ab18c1e5916eb30a7270849f1 Mon Sep 17 00:00:00 2001 From: derdon Date: Tue, 26 Apr 2011 00:39:31 +0200 Subject: [PATCH 12/46] move a default value to the table cell it belongs to --- docs/settings.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/settings.rst b/docs/settings.rst index 795f220c..d4340006 100644 --- a/docs/settings.rst +++ b/docs/settings.rst @@ -76,8 +76,8 @@ Setting name (default value) what does it do? default LEFT). `SKRIBIT_TAB_SITENAME` Tab identifier (See Skribit part below). `SKRIBIT_WIDGET_ID` Widget identifier (See Skribit part below). -`STATIC_PATHS` The static paths you want to have accessible -(``['images']``) on the output path "static". By default, +`STATIC_PATHS` (``['images']``) The static paths you want to have accessible + on the output path "static". By default, pelican will copy the 'images' folder to the output folder. `THEME_STATIC_PATHS` (``['static']``) Static theme paths you want to copy. Default From bb24c05b903d338b4f5ca9b79dcd0295bcb5c39f Mon Sep 17 00:00:00 2001 From: derdon Date: Tue, 26 Apr 2011 02:37:56 +0200 Subject: [PATCH 13/46] added missing whitespace in the CLI help --- pelican/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pelican/__init__.py b/pelican/__init__.py index 195ada34..08ddc716 100644 --- a/pelican/__init__.py +++ b/pelican/__init__.py @@ -91,8 +91,8 @@ def main(): parser.add_argument(dest='path', nargs='?', help='Path where to find the content files') 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.') + 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.') From f9819e0c712ad7cb2e06c1b5158d46314b9a70ee Mon Sep 17 00:00:00 2001 From: derdon Date: Tue, 26 Apr 2011 02:39:57 +0200 Subject: [PATCH 14/46] another whitespace mistake in the CLI help --- pelican/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pelican/__init__.py b/pelican/__init__.py index 08ddc716..12d12210 100644 --- a/pelican/__init__.py +++ b/pelican/__init__.py @@ -97,8 +97,8 @@ def main(): 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', default=None, dest='markup', - help='the list of markup language to use (rst or md). Please indicate them' - 'separated by commas') + 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. Default to None.') parser.add_argument('-k', '--keep-output-directory', dest='keep', From deb5b8a98f56bf73ced4a1e14227767aa008cd29 Mon Sep 17 00:00:00 2001 From: derdon Date: Tue, 26 Apr 2011 02:49:00 +0200 Subject: [PATCH 15/46] typos, grammar mistakes, minor whitespace issues --- docs/themes.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/themes.rst b/docs/themes.rst index 9f8b8765..301e090e 100644 --- a/docs/themes.rst +++ b/docs/themes.rst @@ -32,17 +32,17 @@ To make your own theme, you must follow the following structure:: just examples. Put what you need here. * `templates` contains all the templates that will be used to generate the content. - I've just put the mandatory templates here, you can define your own if it helps + I've just put the mandatory templates here, you can define your own if it helps you to organize yourself while doing the theme. Templates and variables ======================= It's using a simple syntax, that you can embbed into your html pages. -This document describes which templates should exists on a theme, and which +This document describes which templates should exist on a theme, and which variables will be passed to each template, while generating it. -All templates will receive the variables defined in your settings file, if they +All templates will receive the variables defined in your settings file, if they are in caps. You can access them directly. Common variables @@ -114,7 +114,7 @@ page_name 'category/`category_name`'. Useful for pagination article.html ------------- -This template will be processed for each article. .html files will be outputed +This template will be processed for each article. .html files will be output in output/`article_name`.html. Here are the specific variables it gets. ============= =================================================== @@ -152,8 +152,8 @@ page_name 'tag/`tag_name`'. Useful for pagination links. Include skribit script ====================== -In order to support skribit scripts in your themes, you must following these -actions : +In order to support skribit scripts in your themes, you must perform these +actions: * Copy `skribit_tab_script.html` and `skribit_widget_script.html` in your templates directory. From d2bb85ab6ce534b92457f08ad0333c2a4e90358b Mon Sep 17 00:00:00 2001 From: Alexis Metaireau Date: Mon, 25 Apr 2011 23:29:45 +0100 Subject: [PATCH 16/46] Thanks Simon Liedtke --- THANKS | 1 + 1 file changed, 1 insertion(+) diff --git a/THANKS b/THANKS index 4a8a52a5..39f54e61 100644 --- a/THANKS +++ b/THANKS @@ -15,3 +15,4 @@ bugs or giving ideas. Thanks to them ! - Samuel Martin - Marcus Fredriksson - Günter Kolousek +- Simon Liedtke From 15de7d45c9c0402f3669169ab0605b999d89726e Mon Sep 17 00:00:00 2001 From: Alexis Metaireau Date: Mon, 25 Apr 2011 23:33:13 +0100 Subject: [PATCH 17/46] Little doc fix --- docs/settings.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/settings.rst b/docs/settings.rst index d4340006..363ffc87 100644 --- a/docs/settings.rst +++ b/docs/settings.rst @@ -167,7 +167,7 @@ The `notmyidea` theme can make good use of the following settings. I recommend to use them too in your themes. ======================= ======================================================= -Setting name what it does ? +Setting name what does it do ? ======================= ======================================================= `DISQUS_SITENAME` Pelican can handle disqus comments, specify the sitename you've filled in on disqus From ca2030f62c652b8c62ef8c45800634379ab6717a Mon Sep 17 00:00:00 2001 From: Alexis Metaireau Date: Tue, 26 Apr 2011 00:34:03 +0100 Subject: [PATCH 18/46] theme switch --- docs/_themes/LICENSE | 37 -- docs/_themes/README | 31 -- docs/_themes/flask/layout.html | 16 - docs/_themes/flask/relations.html | 19 - docs/_themes/flask/static/flasky.css_t | 387 ------------------ docs/_themes/flask/static/small_flask.css | 70 ---- docs/_themes/flask/theme.conf | 7 - docs/_themes/flask_small/static/flasky.css_t | 287 ------------- docs/_themes/flask_theme_support.py | 86 ---- .../{flask_small => pelican}/layout.html | 0 docs/_themes/pelican/static/pelican.css_t | 247 +++++++++++ .../{flask_small => pelican}/theme.conf | 4 +- docs/conf.py | 4 +- 13 files changed, 251 insertions(+), 944 deletions(-) delete mode 100644 docs/_themes/LICENSE delete mode 100644 docs/_themes/README delete mode 100644 docs/_themes/flask/layout.html delete mode 100644 docs/_themes/flask/relations.html delete mode 100644 docs/_themes/flask/static/flasky.css_t delete mode 100644 docs/_themes/flask/static/small_flask.css delete mode 100644 docs/_themes/flask/theme.conf delete mode 100644 docs/_themes/flask_small/static/flasky.css_t delete mode 100644 docs/_themes/flask_theme_support.py rename docs/_themes/{flask_small => pelican}/layout.html (100%) create mode 100644 docs/_themes/pelican/static/pelican.css_t rename docs/_themes/{flask_small => pelican}/theme.conf (58%) diff --git a/docs/_themes/LICENSE b/docs/_themes/LICENSE deleted file mode 100644 index 8daab7ee..00000000 --- a/docs/_themes/LICENSE +++ /dev/null @@ -1,37 +0,0 @@ -Copyright (c) 2010 by Armin Ronacher. - -Some rights reserved. - -Redistribution and use in source and binary forms of the theme, with or -without modification, are permitted provided that the following conditions -are met: - -* Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - -* The names of the contributors may not be used to endorse or - promote products derived from this software without specific - prior written permission. - -We kindly ask you to only use these themes in an unmodified manner just -for Flask and Flask-related products, not for unrelated projects. If you -like the visual style and want to use it for your own projects, please -consider making some larger changes to the themes (such as changing -font faces, sizes, colors or margins). - -THIS THEME IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS THEME, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. diff --git a/docs/_themes/README b/docs/_themes/README deleted file mode 100644 index b3292bdf..00000000 --- a/docs/_themes/README +++ /dev/null @@ -1,31 +0,0 @@ -Flask Sphinx Styles -=================== - -This repository contains sphinx styles for Flask and Flask related -projects. To use this style in your Sphinx documentation, follow -this guide: - -1. put this folder as _themes into your docs folder. Alternatively - you can also use git submodules to check out the contents there. -2. add this to your conf.py: - - sys.path.append(os.path.abspath('_themes')) - html_theme_path = ['_themes'] - html_theme = 'flask' - -The following themes exist: - -- 'flask' - the standard flask documentation theme for large - projects -- 'flask_small' - small one-page theme. Intended to be used by - very small addon libraries for flask. - -The following options exist for the flask_small theme: - - [options] - index_logo = '' filename of a picture in _static - to be used as replacement for the - h1 in the index.rst file. - index_logo_height = 120px height of the index logo - github_fork = '' repository name on github for the - "fork me" badge diff --git a/docs/_themes/flask/layout.html b/docs/_themes/flask/layout.html deleted file mode 100644 index d7c87927..00000000 --- a/docs/_themes/flask/layout.html +++ /dev/null @@ -1,16 +0,0 @@ -{%- extends "basic/layout.html" %} -{%- block extrahead %} - {{ super() }} - {% if theme_touch_icon %} - - {% endif %} - -{% endblock %} -{%- block relbar2 %}{% endblock %} -{%- block footer %} - -{%- endblock %} diff --git a/docs/_themes/flask/relations.html b/docs/_themes/flask/relations.html deleted file mode 100644 index 3bbcde85..00000000 --- a/docs/_themes/flask/relations.html +++ /dev/null @@ -1,19 +0,0 @@ -

Related Topics

- diff --git a/docs/_themes/flask/static/flasky.css_t b/docs/_themes/flask/static/flasky.css_t deleted file mode 100644 index 0de60eee..00000000 --- a/docs/_themes/flask/static/flasky.css_t +++ /dev/null @@ -1,387 +0,0 @@ -/* - * flasky.css_t - * ~~~~~~~~~~~~ - * - * :copyright: Copyright 2010 by Armin Ronacher. - * :license: Flask Design License, see LICENSE for details. - */ - -{% set page_width = '940px' %} -{% set sidebar_width = '220px' %} - -@import url("basic.css"); - -/* -- page layout ----------------------------------------------------------- */ - -body { - font-family: 'Georgia', serif; - font-size: 17px; - background-color: white; - color: #000; - margin: 0; - padding: 0; -} - -div.document { - width: {{ page_width }}; - margin: 30px auto 0 auto; -} - -div.documentwrapper { - float: left; - width: 100%; -} - -div.bodywrapper { - margin: 0 0 0 {{ sidebar_width }}; -} - -div.sphinxsidebar { - width: {{ sidebar_width }}; -} - -hr { - border: 1px solid #B1B4B6; -} - -div.body { - background-color: #ffffff; - color: #3E4349; - padding: 0 30px 0 30px; -} - -img.floatingflask { - padding: 0 0 10px 10px; - float: right; -} - -div.footer { - width: {{ page_width }}; - margin: 20px auto 30px auto; - font-size: 14px; - color: #888; - text-align: right; -} - -div.footer a { - color: #888; -} - -div.related { - display: none; -} - -div.sphinxsidebar a { - color: #444; - text-decoration: none; - border-bottom: 1px dotted #999; -} - -div.sphinxsidebar a:hover { - border-bottom: 1px solid #999; -} - -div.sphinxsidebar { - font-size: 14px; - line-height: 1.5; -} - -div.sphinxsidebarwrapper { - padding: 18px 10px; -} - -div.sphinxsidebarwrapper p.logo { - padding: 0 0 20px 0; - margin: 0; - text-align: center; -} - -div.sphinxsidebar h3, -div.sphinxsidebar h4 { - font-family: 'Garamond', 'Georgia', serif; - color: #444; - font-size: 24px; - font-weight: normal; - margin: 0 0 5px 0; - padding: 0; -} - -div.sphinxsidebar h4 { - font-size: 20px; -} - -div.sphinxsidebar h3 a { - color: #444; -} - -div.sphinxsidebar p.logo a, -div.sphinxsidebar h3 a, -div.sphinxsidebar p.logo a:hover, -div.sphinxsidebar h3 a:hover { - border: none; -} - -div.sphinxsidebar p { - color: #555; - margin: 10px 0; -} - -div.sphinxsidebar ul { - margin: 10px 0; - padding: 0; - color: #000; -} - -div.sphinxsidebar input { - border: 1px solid #ccc; - font-family: 'Georgia', serif; - font-size: 1em; -} - -/* -- body styles ----------------------------------------------------------- */ - -a { - color: #004B6B; - text-decoration: underline; -} - -a:hover { - color: #6D4100; - text-decoration: underline; -} - -div.body h1, -div.body h2, -div.body h3, -div.body h4, -div.body h5, -div.body h6 { - font-family: 'Garamond', 'Georgia', serif; - font-weight: normal; - margin: 30px 0px 10px 0px; - padding: 0; -} - -div.body h1 { margin-top: 0; padding-top: 0; font-size: 240%; } -div.body h2 { font-size: 180%; } -div.body h3 { font-size: 150%; } -div.body h4 { font-size: 130%; } -div.body h5 { font-size: 100%; } -div.body h6 { font-size: 100%; } - -a.headerlink { - color: #ddd; - padding: 0 4px; - text-decoration: none; -} - -a.headerlink:hover { - color: #444; - background: #eaeaea; -} - -div.body p, div.body dd, div.body li { - line-height: 1.4em; -} - -div.admonition { - background: #fafafa; - margin: 20px -30px; - padding: 10px 30px; - border-top: 1px solid #ccc; - border-bottom: 1px solid #ccc; -} - -div.admonition tt.xref, div.admonition a tt { - border-bottom: 1px solid #fafafa; -} - -dd div.admonition { - margin-left: -60px; - padding-left: 60px; -} - -div.admonition p.admonition-title { - font-family: 'Garamond', 'Georgia', serif; - font-weight: normal; - font-size: 24px; - margin: 0 0 10px 0; - padding: 0; - line-height: 1; -} - -div.admonition p.last { - margin-bottom: 0; -} - -div.highlight { - background-color: white; -} - -dt:target, .highlight { - background: #FAF3E8; -} - -div.note { - background-color: #eee; - border: 1px solid #ccc; -} - -div.seealso { - background-color: #ffc; - border: 1px solid #ff6; -} - -div.topic { - background-color: #eee; -} - -p.admonition-title { - display: inline; -} - -p.admonition-title:after { - content: ":"; -} - -pre, tt { - font-family: 'Consolas', 'Menlo', 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; - font-size: 0.9em; -} - -img.screenshot { -} - -tt.descname, tt.descclassname { - font-size: 0.95em; -} - -tt.descname { - padding-right: 0.08em; -} - -img.screenshot { - -moz-box-shadow: 2px 2px 4px #eee; - -webkit-box-shadow: 2px 2px 4px #eee; - box-shadow: 2px 2px 4px #eee; -} - -table.docutils { - border: 1px solid #888; - -moz-box-shadow: 2px 2px 4px #eee; - -webkit-box-shadow: 2px 2px 4px #eee; - box-shadow: 2px 2px 4px #eee; -} - -table.docutils td, table.docutils th { - border: 1px solid #888; - padding: 0.25em 0.7em; -} - -table.field-list, table.footnote { - border: none; - -moz-box-shadow: none; - -webkit-box-shadow: none; - box-shadow: none; -} - -table.footnote { - margin: 15px 0; - width: 100%; - border: 1px solid #eee; - background: #fdfdfd; - font-size: 0.9em; -} - -table.footnote + table.footnote { - margin-top: -15px; - border-top: none; -} - -table.field-list th { - padding: 0 0.8em 0 0; -} - -table.field-list td { - padding: 0; -} - -table.footnote td.label { - width: 0px; - padding: 0.3em 0 0.3em 0.5em; -} - -table.footnote td { - padding: 0.3em 0.5em; -} - -dl { - margin: 0; - padding: 0; -} - -dl dd { - margin-left: 30px; -} - -blockquote { - margin: 0 0 0 30px; - padding: 0; -} - -ul, ol { - margin: 10px 0 10px 30px; - padding: 0; -} - -pre { - background: #eee; - padding: 7px 30px; - margin: 15px -30px; - line-height: 1.3em; -} - -dl pre, blockquote pre, li pre { - margin-left: -60px; - padding-left: 60px; -} - -dl dl pre { - margin-left: -90px; - padding-left: 90px; -} - -tt { - background-color: #ecf0f3; - color: #222; - /* padding: 1px 2px; */ -} - -tt.xref, a tt { - background-color: #FBFBFB; - border-bottom: 1px solid white; -} - -a.reference { - text-decoration: none; - border-bottom: 1px dotted #004B6B; -} - -a.reference:hover { - border-bottom: 1px solid #6D4100; -} - -a.footnote-reference { - text-decoration: none; - font-size: 0.7em; - vertical-align: top; - border-bottom: 1px dotted #004B6B; -} - -a.footnote-reference:hover { - border-bottom: 1px solid #6D4100; -} - -a:hover tt { - background: #EEE; -} diff --git a/docs/_themes/flask/static/small_flask.css b/docs/_themes/flask/static/small_flask.css deleted file mode 100644 index 1c6df309..00000000 --- a/docs/_themes/flask/static/small_flask.css +++ /dev/null @@ -1,70 +0,0 @@ -/* - * small_flask.css_t - * ~~~~~~~~~~~~~~~~~ - * - * :copyright: Copyright 2010 by Armin Ronacher. - * :license: Flask Design License, see LICENSE for details. - */ - -body { - margin: 0; - padding: 20px 30px; -} - -div.documentwrapper { - float: none; - background: white; -} - -div.sphinxsidebar { - display: block; - float: none; - width: 102.5%; - margin: 50px -30px -20px -30px; - padding: 10px 20px; - background: #333; - color: white; -} - -div.sphinxsidebar h3, div.sphinxsidebar h4, div.sphinxsidebar p, -div.sphinxsidebar h3 a { - color: white; -} - -div.sphinxsidebar a { - color: #aaa; -} - -div.sphinxsidebar p.logo { - display: none; -} - -div.document { - width: 100%; - margin: 0; -} - -div.related { - display: block; - margin: 0; - padding: 10px 0 20px 0; -} - -div.related ul, -div.related ul li { - margin: 0; - padding: 0; -} - -div.footer { - display: none; -} - -div.bodywrapper { - margin: 0; -} - -div.body { - min-height: 0; - padding: 0; -} diff --git a/docs/_themes/flask/theme.conf b/docs/_themes/flask/theme.conf deleted file mode 100644 index 307a1f0d..00000000 --- a/docs/_themes/flask/theme.conf +++ /dev/null @@ -1,7 +0,0 @@ -[theme] -inherit = basic -stylesheet = flasky.css -pygments_style = flask_theme_support.FlaskyStyle - -[options] -touch_icon = diff --git a/docs/_themes/flask_small/static/flasky.css_t b/docs/_themes/flask_small/static/flasky.css_t deleted file mode 100644 index fe2141c5..00000000 --- a/docs/_themes/flask_small/static/flasky.css_t +++ /dev/null @@ -1,287 +0,0 @@ -/* - * flasky.css_t - * ~~~~~~~~~~~~ - * - * Sphinx stylesheet -- flasky theme based on nature theme. - * - * :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS. - * :license: BSD, see LICENSE for details. - * - */ - -@import url("basic.css"); - -/* -- page layout ----------------------------------------------------------- */ - -body { - font-family: 'Georgia', serif; - font-size: 17px; - color: #000; - background: white; - margin: 0; - padding: 0; -} - -div.documentwrapper { - float: left; - width: 100%; -} - -div.bodywrapper { - margin: 40px auto 0 auto; - width: 700px; -} - -hr { - border: 1px solid #B1B4B6; -} - -div.body { - background-color: #ffffff; - color: #3E4349; - padding: 0 30px 30px 30px; -} - -img.floatingflask { - padding: 0 0 10px 10px; - float: right; -} - -div.footer { - text-align: right; - color: #888; - padding: 10px; - font-size: 14px; - width: 650px; - margin: 0 auto 40px auto; -} - -div.footer a { - color: #888; - text-decoration: underline; -} - -div.related { - line-height: 32px; - color: #888; -} - -div.related ul { - padding: 0 0 0 10px; -} - -div.related a { - color: #444; -} - -/* -- body styles ----------------------------------------------------------- */ - -a { - color: #004B6B; - text-decoration: underline; -} - -a:hover { - color: #6D4100; - text-decoration: underline; -} - -div.body { - padding-bottom: 40px; /* saved for footer */ -} - -div.body h1, -div.body h2, -div.body h3, -div.body h4, -div.body h5, -div.body h6 { - font-family: 'Garamond', 'Georgia', serif; - font-weight: normal; - margin: 30px 0px 10px 0px; - padding: 0; -} - -{% if theme_index_logo %} -div.indexwrapper h1 { - text-indent: -999999px; - background: url({{ theme_index_logo }}) no-repeat center center; - height: {{ theme_index_logo_height }}; -} -{% endif %} - -div.body h2 { font-size: 180%; } -div.body h3 { font-size: 150%; } -div.body h4 { font-size: 130%; } -div.body h5 { font-size: 100%; } -div.body h6 { font-size: 100%; } - -a.headerlink { - color: white; - padding: 0 4px; - text-decoration: none; -} - -a.headerlink:hover { - color: #444; - background: #eaeaea; -} - -div.body p, div.body dd, div.body li { - line-height: 1.4em; -} - -div.admonition { - background: #fafafa; - margin: 20px -30px; - padding: 10px 30px; - border-top: 1px solid #ccc; - border-bottom: 1px solid #ccc; -} - -div.admonition p.admonition-title { - font-family: 'Garamond', 'Georgia', serif; - font-weight: normal; - font-size: 24px; - margin: 0 0 10px 0; - padding: 0; - line-height: 1; -} - -div.admonition p.last { - margin-bottom: 0; -} - -div.highlight{ - background-color: white; -} - -dt:target, .highlight { - background: #FAF3E8; -} - -div.note { - background-color: #eee; - border: 1px solid #ccc; -} - -div.seealso { - background-color: #ffc; - border: 1px solid #ff6; -} - -div.topic { - background-color: #eee; -} - -div.warning { - background-color: #ffe4e4; - border: 1px solid #f66; -} - -p.admonition-title { - display: inline; -} - -p.admonition-title:after { - content: ":"; -} - -pre, tt { - font-family: 'Consolas', 'Menlo', 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; - font-size: 0.85em; -} - -img.screenshot { -} - -tt.descname, tt.descclassname { - font-size: 0.95em; -} - -tt.descname { - padding-right: 0.08em; -} - -img.screenshot { - -moz-box-shadow: 2px 2px 4px #eee; - -webkit-box-shadow: 2px 2px 4px #eee; - box-shadow: 2px 2px 4px #eee; -} - -table.docutils { - border: 1px solid #888; - -moz-box-shadow: 2px 2px 4px #eee; - -webkit-box-shadow: 2px 2px 4px #eee; - box-shadow: 2px 2px 4px #eee; -} - -table.docutils td, table.docutils th { - border: 1px solid #888; - padding: 0.25em 0.7em; -} - -table.field-list, table.footnote { - border: none; - -moz-box-shadow: none; - -webkit-box-shadow: none; - box-shadow: none; -} - -table.footnote { - margin: 15px 0; - width: 100%; - border: 1px solid #eee; -} - -table.field-list th { - padding: 0 0.8em 0 0; -} - -table.field-list td { - padding: 0; -} - -table.footnote td { - padding: 0.5em; -} - -dl { - margin: 0; - padding: 0; -} - -dl dd { - margin-left: 30px; -} - -pre { - padding: 0; - margin: 15px -30px; - padding: 8px; - line-height: 1.3em; - padding: 7px 30px; - background: #eee; - border-radius: 2px; - -moz-border-radius: 2px; - -webkit-border-radius: 2px; -} - -dl pre { - margin-left: -60px; - padding-left: 60px; -} - -tt { - background-color: #ecf0f3; - color: #222; - /* padding: 1px 2px; */ -} - -tt.xref, a tt { - background-color: #FBFBFB; -} - -a:hover tt { - background: #EEE; -} diff --git a/docs/_themes/flask_theme_support.py b/docs/_themes/flask_theme_support.py deleted file mode 100644 index 33f47449..00000000 --- a/docs/_themes/flask_theme_support.py +++ /dev/null @@ -1,86 +0,0 @@ -# flasky extensions. flasky pygments style based on tango style -from pygments.style import Style -from pygments.token import Keyword, Name, Comment, String, Error, \ - Number, Operator, Generic, Whitespace, Punctuation, Other, Literal - - -class FlaskyStyle(Style): - background_color = "#f8f8f8" - default_style = "" - - styles = { - # No corresponding class for the following: - #Text: "", # class: '' - Whitespace: "underline #f8f8f8", # class: 'w' - Error: "#a40000 border:#ef2929", # class: 'err' - Other: "#000000", # class 'x' - - Comment: "italic #8f5902", # class: 'c' - Comment.Preproc: "noitalic", # class: 'cp' - - Keyword: "bold #004461", # class: 'k' - Keyword.Constant: "bold #004461", # class: 'kc' - Keyword.Declaration: "bold #004461", # class: 'kd' - Keyword.Namespace: "bold #004461", # class: 'kn' - Keyword.Pseudo: "bold #004461", # class: 'kp' - Keyword.Reserved: "bold #004461", # class: 'kr' - Keyword.Type: "bold #004461", # class: 'kt' - - Operator: "#582800", # class: 'o' - Operator.Word: "bold #004461", # class: 'ow' - like keywords - - Punctuation: "bold #000000", # class: 'p' - - # because special names such as Name.Class, Name.Function, etc. - # are not recognized as such later in the parsing, we choose them - # to look the same as ordinary variables. - Name: "#000000", # class: 'n' - Name.Attribute: "#c4a000", # class: 'na' - to be revised - Name.Builtin: "#004461", # class: 'nb' - Name.Builtin.Pseudo: "#3465a4", # class: 'bp' - Name.Class: "#000000", # class: 'nc' - to be revised - Name.Constant: "#000000", # class: 'no' - to be revised - Name.Decorator: "#888", # class: 'nd' - to be revised - Name.Entity: "#ce5c00", # class: 'ni' - Name.Exception: "bold #cc0000", # class: 'ne' - Name.Function: "#000000", # class: 'nf' - Name.Property: "#000000", # class: 'py' - Name.Label: "#f57900", # class: 'nl' - Name.Namespace: "#000000", # class: 'nn' - to be revised - Name.Other: "#000000", # class: 'nx' - Name.Tag: "bold #004461", # class: 'nt' - like a keyword - Name.Variable: "#000000", # class: 'nv' - to be revised - Name.Variable.Class: "#000000", # class: 'vc' - to be revised - Name.Variable.Global: "#000000", # class: 'vg' - to be revised - Name.Variable.Instance: "#000000", # class: 'vi' - to be revised - - Number: "#990000", # class: 'm' - - Literal: "#000000", # class: 'l' - Literal.Date: "#000000", # class: 'ld' - - String: "#4e9a06", # class: 's' - String.Backtick: "#4e9a06", # class: 'sb' - String.Char: "#4e9a06", # class: 'sc' - String.Doc: "italic #8f5902", # class: 'sd' - like a comment - String.Double: "#4e9a06", # class: 's2' - String.Escape: "#4e9a06", # class: 'se' - String.Heredoc: "#4e9a06", # class: 'sh' - String.Interpol: "#4e9a06", # class: 'si' - String.Other: "#4e9a06", # class: 'sx' - String.Regex: "#4e9a06", # class: 'sr' - String.Single: "#4e9a06", # class: 's1' - String.Symbol: "#4e9a06", # class: 'ss' - - Generic: "#000000", # class: 'g' - Generic.Deleted: "#a40000", # class: 'gd' - Generic.Emph: "italic #000000", # class: 'ge' - Generic.Error: "#ef2929", # class: 'gr' - Generic.Heading: "bold #000080", # class: 'gh' - Generic.Inserted: "#00A000", # class: 'gi' - Generic.Output: "#888", # class: 'go' - Generic.Prompt: "#745334", # class: 'gp' - Generic.Strong: "bold #000000", # class: 'gs' - Generic.Subheading: "bold #800080", # class: 'gu' - Generic.Traceback: "bold #a40000", # class: 'gt' - } diff --git a/docs/_themes/flask_small/layout.html b/docs/_themes/pelican/layout.html similarity index 100% rename from docs/_themes/flask_small/layout.html rename to docs/_themes/pelican/layout.html diff --git a/docs/_themes/pelican/static/pelican.css_t b/docs/_themes/pelican/static/pelican.css_t new file mode 100644 index 00000000..164073e1 --- /dev/null +++ b/docs/_themes/pelican/static/pelican.css_t @@ -0,0 +1,247 @@ +/* + * pelican.css_t + * ~~~~~~~~~~~~ + * + * Sphinx stylesheet -- pelican theme, based on the nature theme + * + * :copyright: Copyright 2011 by Alexis Metaireau. + */ + +@import url("basic.css"); + +/* -- page layout ----------------------------------------------------------- */ + +body { + font-family: Arial, sans-serif; + font-size: 100%; + background-color: white; + color: #555; + margin: 0; + padding: 0; +} + +div.documentwrapper { + width: 70%; + margin: auto; +} + +div.bodywrapper { + margin: 0 0 0 230px; +} + +hr { + border: 1px solid #B1B4B6; +} + +div.document { + background-color: #eee; +} + +div.body { + background-color: #ffffff; + color: #3E4349; + padding: 0 30px 30px 30px; + font-size: 0.9em; +} + +div.footer { + color: #555; + width: 100%; + padding: 13px 0; + text-align: center; + font-size: 75%; +} + +div.footer a { + color: #444; + text-decoration: underline; +} + +div.related { + background-color: #6BA81E; + line-height: 32px; + color: #fff; + text-shadow: 0px 1px 0 #444; + font-size: 0.9em; +} + +div.related a { + color: #E2F3CC; +} + +div.sphinxsidebar { + font-size: 0.75em; + line-height: 1.5em; +} + +div.sphinxsidebarwrapper{ + padding: 20px 0; +} + +div.sphinxsidebar h3, +div.sphinxsidebar h4 { + font-family: Arial, sans-serif; + color: #222; + font-size: 1.2em; + font-weight: normal; + margin: 0; + padding: 5px 10px; + background-color: #ddd; + text-shadow: 1px 1px 0 white +} + +div.sphinxsidebar h4{ + font-size: 1.1em; +} + +div.sphinxsidebar h3 a { + color: #444; +} + + +div.sphinxsidebar p { + color: #888; + padding: 5px 20px; +} + +div.sphinxsidebar p.topless { +} + +div.sphinxsidebar ul { + margin: 10px 20px; + padding: 0; + color: #000; +} + +div.sphinxsidebar a { + color: #444; +} + +div.sphinxsidebar input { + border: 1px solid #ccc; + font-family: sans-serif; + font-size: 1em; +} + +div.sphinxsidebar input[type=text]{ + margin-left: 20px; +} + +/* -- body styles ----------------------------------------------------------- */ + +a { + color: #005B81; + text-decoration: none; +} + +a:hover { + color: #E32E00; + text-decoration: underline; +} + +div.body h1, +div.body h2, +div.body h3, +div.body h4, +div.body h5, +div.body h6 { + font-family: Arial, sans-serif; + font-weight: normal; + color: #212224; + margin: 30px 0px 10px 0px; + padding: 5px 0 5px 10px; + text-shadow: 0px 1px 0 white +} + +div.body h1 { + border-top: 20px solid white; + margin-top: 0; + font-size: 250%; + text-align: center; +} +div.body h2 { font-size: 150%; background-color: #C8D5E3; } +div.body h3 { font-size: 120%; background-color: #D8DEE3; } +div.body h4 { font-size: 110%; background-color: #D8DEE3; } +div.body h5 { font-size: 100%; background-color: #D8DEE3; } +div.body h6 { font-size: 100%; background-color: #D8DEE3; } + +a.headerlink { + color: #c60f0f; + font-size: 0.8em; + padding: 0 4px 0 4px; + text-decoration: none; +} + +a.headerlink:hover { + background-color: #c60f0f; + color: white; +} + +div.body p, div.body dd, div.body li { + line-height: 1.5em; +} + +div.admonition p.admonition-title + p { + display: inline; +} + +div.highlight{ + background-color: #111; +} + +div.note { + background-color: #eee; + border: 1px solid #ccc; +} + +div.seealso { + background-color: #ffc; + border: 1px solid #ff6; +} + +div.topic { + background-color: #eee; +} + +div.warning { + background-color: #ffe4e4; + border: 1px solid #f66; +} + +p.admonition-title { + display: inline; +} + +p.admonition-title:after { + content: ":"; +} + +pre { + padding: 10px; + background-color: #111; + color: #fff; + line-height: 1.2em; + border: 1px solid #C6C9CB; + font-size: 1.1em; + margin: 1.5em 0 1.5em 0; + -webkit-box-shadow: 1px 1px 1px #d8d8d8; + -moz-box-shadow: 1px 1px 1px #d8d8d8; +} + +tt { + background-color: #ecf0f3; + color: #222; + /* padding: 1px 2px; */ + font-size: 1.1em; + font-family: monospace; +} + +.viewcode-back { + font-family: Arial, sans-serif; +} + +div.viewcode-block:target { + background-color: #f4debf; + border-top: 1px solid #ac9; + border-bottom: 1px solid #ac9; +} diff --git a/docs/_themes/flask_small/theme.conf b/docs/_themes/pelican/theme.conf similarity index 58% rename from docs/_themes/flask_small/theme.conf rename to docs/_themes/pelican/theme.conf index 07036d14..ffbb7945 100644 --- a/docs/_themes/flask_small/theme.conf +++ b/docs/_themes/pelican/theme.conf @@ -1,8 +1,8 @@ [theme] inherit = basic -stylesheet = flasky.css +stylesheet = pelican.css nosidebar = true -pygments_style = flask_theme_support.FlaskyStyle +pygments_style = fruity [options] index_logo_height = 120px diff --git a/docs/conf.py b/docs/conf.py index 507e30a3..76167eaf 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -14,7 +14,6 @@ master_doc = 'index' project = u'Pelican' copyright = u'2010, Alexis Metaireau and contributors' exclude_patterns = ['_build'] -pygments_style = 'sphinx' version = "2" release = version @@ -24,12 +23,13 @@ release = version # a list of builtin themes. sys.path.append(os.path.abspath('_themes')) html_theme_path = ['_themes'] -html_theme = 'flask_small' +html_theme = 'pelican' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. html_theme_options = { + 'nosidebar': True, 'index_logo': 'pelican.png', 'github_fork': 'ametaireau/pelican', } From 3d2ae33799fc334aaa24f6be7cf9557c1d3e2811 Mon Sep 17 00:00:00 2001 From: Alexis Metaireau Date: Tue, 26 Apr 2011 00:40:16 +0100 Subject: [PATCH 19/46] update the theme (logo) --- docs/_themes/pelican/static/pelican.css_t | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/docs/_themes/pelican/static/pelican.css_t b/docs/_themes/pelican/static/pelican.css_t index 164073e1..3cb2a3c1 100644 --- a/docs/_themes/pelican/static/pelican.css_t +++ b/docs/_themes/pelican/static/pelican.css_t @@ -34,7 +34,6 @@ hr { } div.document { - background-color: #eee; } div.body { @@ -153,12 +152,20 @@ div.body h6 { text-shadow: 0px 1px 0 white } +{% if theme_index_logo %} +div.indexwrapper h1 { + text-indent: -999999px; + background: url({{ theme_index_logo }}) no-repeat center center; + height: {{ theme_index_logo_height }}; +} +{% endif %} div.body h1 { border-top: 20px solid white; margin-top: 0; font-size: 250%; text-align: center; } + div.body h2 { font-size: 150%; background-color: #C8D5E3; } div.body h3 { font-size: 120%; background-color: #D8DEE3; } div.body h4 { font-size: 110%; background-color: #D8DEE3; } From 91cb42d7d887d1899617dd5bcf76685ba8f67865 Mon Sep 17 00:00:00 2001 From: Nicolas Duhamel Date: Tue, 26 Apr 2011 12:23:45 +0200 Subject: [PATCH 20/46] add a KISS plugin system --- pelican/__init__.py | 25 +++++++++++++++++++++++-- pelican/settings.py | 1 + 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/pelican/__init__.py b/pelican/__init__.py index 12d12210..cf99295e 100644 --- a/pelican/__init__.py +++ b/pelican/__init__.py @@ -1,5 +1,8 @@ import argparse import os +import pkgutil + +from blinker import signal from pelican.generators import (ArticlesGenerator, PagesGenerator, StaticGenerator, PdfGenerator) @@ -13,7 +16,7 @@ VERSION = "2.6.0" class Pelican(object): def __init__(self, settings=None, path=None, theme=None, output_path=None, - markup=None, keep=False): + markup=None, keep=False, plugins_path=None): """Read the settings, and performs some checks on the environment before doing anything else. """ @@ -41,6 +44,15 @@ class Pelican(object): self.theme = theme_path else: raise Exception("Impossible to find the theme %s" % theme) + + plugins_path = plugins_path or settings['PLUGINS_PATH'] + if plugins_path: + plugins_path = os.path.abspath(plugins_path) + self.load_plugins(plugins_path) + else: + self.plugins = None + + signal('pelican_initialized').send(self) def run(self): """Run the generators and return""" @@ -81,6 +93,13 @@ class Pelican(object): def get_writer(self): return Writer(self.output_path, settings=self.settings) + + def load_plugins(self,path): + loaded = [] + for module_loader, name, ispkg in pkgutil.walk_packages(path=[path,]): + loaded.append( module_loader.find_module(name).load_module(name) ) + self.plugins = loaded + @@ -116,6 +135,8 @@ def main(): parser.add_argument('-r', '--autoreload', dest='autoreload', action='store_true', help="Relaunch pelican each time a modification occurs on the content" "files") + parser.add_argument('-p', '--plugins', default=None, dest='plugins_path', + help='the path of plugins to use') args = parser.parse_args() log.init(args.verbosity) @@ -134,7 +155,7 @@ def main(): cls = getattr(module, cls_name) try: - pelican = cls(settings, args.path, args.theme, args.output, markup, args.keep) + pelican = cls(settings, args.path, args.theme, args.output, markup, args.keep, args.plugins_path) if args.autoreload: while True: try: diff --git a/pelican/settings.py b/pelican/settings.py index 6c0918a0..3786b7f5 100644 --- a/pelican/settings.py +++ b/pelican/settings.py @@ -37,6 +37,7 @@ _DEFAULT_CONFIG = {'PATH': None, 'WITH_PAGINATION': False, 'DEFAULT_PAGINATION': 5, 'DEFAULT_ORPHANS': 0, + 'PLUGINS_PATH': None, } def read_settings(filename): From 4fb5d2b31e755d346e1ff5b7f6d188e0f3ef8b09 Mon Sep 17 00:00:00 2001 From: Nicolas Duhamel Date: Tue, 26 Apr 2011 12:26:56 +0200 Subject: [PATCH 21/46] add plugin sample --- plugins_samples/initialized.py | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 plugins_samples/initialized.py diff --git a/plugins_samples/initialized.py b/plugins_samples/initialized.py new file mode 100644 index 00000000..f104c275 --- /dev/null +++ b/plugins_samples/initialized.py @@ -0,0 +1,7 @@ +from blinker import signal + + +def test(sender): + print "%s initialized !!" % sender + +signal('pelican_initialized').connect(test) From dfe4d4e1320d3652fcf11bfd4983df4bf7fdc8e1 Mon Sep 17 00:00:00 2001 From: Nicolas Duhamel Date: Tue, 26 Apr 2011 13:16:09 +0200 Subject: [PATCH 22/46] add gravatar plugin and pelican_generate_context signal --- pelican/generators.py | 5 +++++ plugins_samples/gravatar.py | 20 ++++++++++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 plugins_samples/gravatar.py diff --git a/pelican/generators.py b/pelican/generators.py index 569d5f50..02131532 100755 --- a/pelican/generators.py +++ b/pelican/generators.py @@ -8,6 +8,8 @@ import os import math import random +from blinker import signal + from jinja2 import Environment, FileSystemLoader from jinja2.exceptions import TemplateNotFound @@ -92,6 +94,7 @@ class ArticlesGenerator(Generator): self.dates = {} self.tags = defaultdict(list) self.categories = defaultdict(list) + self.signal = {'pelican_generate_context' : signal('pelican_generate_context')} super(ArticlesGenerator, self).__init__(*args, **kwargs) def generate_feeds(self, writer): @@ -200,6 +203,8 @@ class ArticlesGenerator(Generator): and self.settings['FALLBACK_ON_FS_DATE']: metadatas['date'] = datetime.fromtimestamp(os.stat(f).st_ctime) + self.signal['pelican_generate_context'].send(self, metadatas=metadatas) + article = Article(content, metadatas, settings=self.settings, filename=f) if not is_valid_content(article, f): diff --git a/plugins_samples/gravatar.py b/plugins_samples/gravatar.py new file mode 100644 index 00000000..ca08984c --- /dev/null +++ b/plugins_samples/gravatar.py @@ -0,0 +1,20 @@ +import hashlib + +from blinker import signal + + +def add_gravatar(generator, metadatas): + + #first check email + if 'email' not in metadatas.keys()\ + and 'AUTHOR_EMAIL' in generator.settings.keys(): + metadatas['email'] = generator.settings['AUTHOR_EMAIL'] + + #then add gravatar url + if 'email' in metadatas.keys(): + gravatar_url = "http://www.gravatar.com/avatar/" + \ + hashlib.md5(metadatas['email'].lower()).hexdigest() + metadatas["author_gravatar"] = gravatar_url + + +signal('pelican_generate_context').connect(add_gravatar) From eef5fc8f9969da8a32a5371dea4c1be897141ca0 Mon Sep 17 00:00:00 2001 From: Nicolas Duhamel Date: Tue, 26 Apr 2011 19:44:40 +0200 Subject: [PATCH 23/46] rename signal --- pelican/generators.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pelican/generators.py b/pelican/generators.py index 02131532..38826a49 100755 --- a/pelican/generators.py +++ b/pelican/generators.py @@ -94,7 +94,7 @@ class ArticlesGenerator(Generator): self.dates = {} self.tags = defaultdict(list) self.categories = defaultdict(list) - self.signal = {'pelican_generate_context' : signal('pelican_generate_context')} + self.signal = {'pelican_article_generate_context' : signal('pelican_article_generate_context')} super(ArticlesGenerator, self).__init__(*args, **kwargs) def generate_feeds(self, writer): @@ -203,7 +203,7 @@ class ArticlesGenerator(Generator): and self.settings['FALLBACK_ON_FS_DATE']: metadatas['date'] = datetime.fromtimestamp(os.stat(f).st_ctime) - self.signal['pelican_generate_context'].send(self, metadatas=metadatas) + self.signal['pelican_article_generate_context'].send(self, metadatas=metadatas) article = Article(content, metadatas, settings=self.settings, filename=f) From 91831eb5259757c3b1da586cb95080f6b719b99a Mon Sep 17 00:00:00 2001 From: Nicolas Duhamel Date: Tue, 26 Apr 2011 19:44:55 +0200 Subject: [PATCH 24/46] add doc --- plugins_samples/gravatar.py | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/plugins_samples/gravatar.py b/plugins_samples/gravatar.py index ca08984c..9887e97e 100644 --- a/plugins_samples/gravatar.py +++ b/plugins_samples/gravatar.py @@ -1,7 +1,26 @@ import hashlib from blinker import signal +""" +Gravata plugin for Pelican +========================== +Simply add author_gravatar variable in article's context, which contain +the gravatar url. + +Settings: +--------- + +Add AUTHOR_EMAIL to your settings file to define default author email + +Article metadatas: +------------------ + +:email: article's author email + +If one of them are defined the author_gravatar variable is added to +article's context. +""" def add_gravatar(generator, metadatas): @@ -17,4 +36,4 @@ def add_gravatar(generator, metadatas): metadatas["author_gravatar"] = gravatar_url -signal('pelican_generate_context').connect(add_gravatar) +signal('pelican_article_generate_context').connect(add_gravatar) From 09567fa99ea0cb27ab4f1ca146c909cdacda814c Mon Sep 17 00:00:00 2001 From: Nicolas Duhamel Date: Tue, 26 Apr 2011 20:02:05 +0200 Subject: [PATCH 25/46] add global license capabability as a plugin --- plugins_samples/global_license.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 plugins_samples/global_license.py diff --git a/plugins_samples/global_license.py b/plugins_samples/global_license.py new file mode 100644 index 00000000..feae64e2 --- /dev/null +++ b/plugins_samples/global_license.py @@ -0,0 +1,23 @@ +from blinker import signal + +""" +License plugin for Pelican +========================== + +Simply add license variable in article's context, which contain +the license text. + +Settings: +--------- + +Add LICENSE to your settings file to define default license. + +""" + +def add_license(generator, metadatas): + if 'license' not in metadatas.keys()\ + and 'LICENSE' in self.settings.keys(): + metadatas['license'] = self.settings['LICENSE'] + + +signal('pelican_article_generate_context').connect(add_license) From f4b2b628744efbda99f9b0c43035f1d49c8cecb0 Mon Sep 17 00:00:00 2001 From: Nicolas Duhamel Date: Tue, 26 Apr 2011 20:04:44 +0200 Subject: [PATCH 26/46] fix mistake --- plugins_samples/global_license.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins_samples/global_license.py b/plugins_samples/global_license.py index feae64e2..eeb20965 100644 --- a/plugins_samples/global_license.py +++ b/plugins_samples/global_license.py @@ -16,8 +16,8 @@ Add LICENSE to your settings file to define default license. def add_license(generator, metadatas): if 'license' not in metadatas.keys()\ - and 'LICENSE' in self.settings.keys(): - metadatas['license'] = self.settings['LICENSE'] + and 'LICENSE' in generator.settings.keys(): + metadatas['license'] = generator.settings['LICENSE'] signal('pelican_article_generate_context').connect(add_license) From 07edd96088f0ac7e4d39f86853eacc64fc8623e5 Mon Sep 17 00:00:00 2001 From: Nicolas Duhamel Date: Tue, 26 Apr 2011 23:13:28 +0200 Subject: [PATCH 27/46] add blinker to requires --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 936a3171..4744d0fb 100644 --- a/setup.py +++ b/setup.py @@ -3,7 +3,7 @@ import sys VERSION = "2.6.0" # find a better way to do so. -requires = ['feedgenerator', 'jinja2', 'pygments', 'docutils', 'Markdown'] +requires = ['feedgenerator', 'jinja2', 'pygments', 'docutils', 'Markdown', 'blinker'] if sys.version_info < (2,7): requires.append('argparse') From 20b0d1d4ae3aff83b49d542652dd44c7ab9872bb Mon Sep 17 00:00:00 2001 From: Nicolas Duhamel Date: Wed, 27 Apr 2011 18:09:55 +0200 Subject: [PATCH 28/46] Fix little bug when declaring plugins path in config file --- pelican/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pelican/__init__.py b/pelican/__init__.py index cf99295e..1a618b45 100644 --- a/pelican/__init__.py +++ b/pelican/__init__.py @@ -47,7 +47,7 @@ class Pelican(object): plugins_path = plugins_path or settings['PLUGINS_PATH'] if plugins_path: - plugins_path = os.path.abspath(plugins_path) + plugins_path = os.path.abspath(os.path.expanduser(plugins_path)) self.load_plugins(plugins_path) else: self.plugins = None From c5a63c953a0f9e068a2563a9c5ab11045eaf4c1e Mon Sep 17 00:00:00 2001 From: Alexis Metaireau Date: Fri, 17 Jun 2011 23:37:08 +0200 Subject: [PATCH 29/46] Remove the dependency to pkgutil for the plugins --- pelican/__init__.py | 29 +++++++------------ pelican/generators.py | 4 +-- pelican/plugins/__init__.py | 0 .../plugins}/global_license.py | 6 ++-- .../plugins}/gravatar.py | 19 ++++++------ .../plugins}/initialized.py | 3 +- 6 files changed, 28 insertions(+), 33 deletions(-) create mode 100644 pelican/plugins/__init__.py rename {plugins_samples => pelican/plugins}/global_license.py (72%) rename {plugins_samples => pelican/plugins}/gravatar.py (60%) rename {plugins_samples => pelican/plugins}/initialized.py (57%) diff --git a/pelican/__init__.py b/pelican/__init__.py index 846e2554..515434cc 100644 --- a/pelican/__init__.py +++ b/pelican/__init__.py @@ -1,7 +1,6 @@ import argparse import os import time -import pkgutil from blinker import signal @@ -46,15 +45,18 @@ class Pelican(object): else: raise Exception("Impossible to find the theme %s" % theme) - plugins_path = plugins_path or settings['PLUGINS_PATH'] - if plugins_path: - plugins_path = os.path.abspath(os.path.expanduser(plugins_path)) - self.load_plugins(plugins_path) - else: - self.plugins = None - + self.init_plugins() signal('pelican_initialized').send(self) + def init_plugins(self): + self.plugins = self.settings['PLUGINS'] + for plugin in self.plugins: + # if it's a string, then import it + if isinstance(plugin, str): + plugin = __import__(plugin, globals(), locals(), 'module') + + plugin.register() + def run(self): """Run the generators and return""" @@ -97,13 +99,6 @@ class Pelican(object): def get_writer(self): return Writer(self.output_path, settings=self.settings) - def load_plugins(self, path): - loaded = [] - for module_loader, name, ispkg in pkgutil.walk_packages(path=[path,]): - loaded.append(module_loader.find_module(name).load_module(name)) - self.plugins = loaded - - def main(): @@ -136,8 +131,6 @@ def main(): parser.add_argument('-r', '--autoreload', dest='autoreload', action='store_true', help="Relaunch pelican each time a modification occurs on the content" "files") - parser.add_argument('-p', '--plugins', default=None, dest='plugins_path', - help='the path of plugins to use') args = parser.parse_args() log.init(args.verbosity) @@ -155,7 +148,7 @@ def main(): try: pelican = cls(settings, args.path, args.theme, args.output, markup, - args.delete_outputdir, args.plugins_path) + args.delete_outputdir) if args.autoreload: while True: try: diff --git a/pelican/generators.py b/pelican/generators.py index b6619d0e..eb74aff9 100755 --- a/pelican/generators.py +++ b/pelican/generators.py @@ -13,7 +13,7 @@ from blinker import signal from jinja2 import Environment, FileSystemLoader from jinja2.exceptions import TemplateNotFound -from pelican.utils import copytree, get_relative_path, process_translations, open +from pelican.utils import copy, get_relative_path, process_translations, open from pelican.contents import Article, Page, is_valid_content from pelican.readers import read_file from pelican.log import * @@ -214,7 +214,7 @@ class ArticlesGenerator(Generator): and self.settings['FALLBACK_ON_FS_DATE']: metadata['date'] = datetime.fromtimestamp(os.stat(f).st_ctime) - self.signal['pelican_article_generate_context'].send(self, metadatas=metadatas) + self.signal['pelican_article_generate_context'].send(self, metadata=metadata) article = Article(content, metadata, settings=self.settings, filename=f) if not is_valid_content(article, f): diff --git a/pelican/plugins/__init__.py b/pelican/plugins/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/plugins_samples/global_license.py b/pelican/plugins/global_license.py similarity index 72% rename from plugins_samples/global_license.py rename to pelican/plugins/global_license.py index eeb20965..b6913831 100644 --- a/plugins_samples/global_license.py +++ b/pelican/plugins/global_license.py @@ -14,10 +14,10 @@ Add LICENSE to your settings file to define default license. """ -def add_license(generator, metadatas): - if 'license' not in metadatas.keys()\ +def add_license(generator, metadata): + if 'license' not in metadata.keys()\ and 'LICENSE' in generator.settings.keys(): - metadatas['license'] = generator.settings['LICENSE'] + metadata['license'] = generator.settings['LICENSE'] signal('pelican_article_generate_context').connect(add_license) diff --git a/plugins_samples/gravatar.py b/pelican/plugins/gravatar.py similarity index 60% rename from plugins_samples/gravatar.py rename to pelican/plugins/gravatar.py index 9887e97e..2601ada0 100644 --- a/plugins_samples/gravatar.py +++ b/pelican/plugins/gravatar.py @@ -13,7 +13,7 @@ Settings: Add AUTHOR_EMAIL to your settings file to define default author email -Article metadatas: +Article metadata: ------------------ :email: article's author email @@ -22,18 +22,19 @@ If one of them are defined the author_gravatar variable is added to article's context. """ -def add_gravatar(generator, metadatas): +def add_gravatar(generator, metadata): #first check email - if 'email' not in metadatas.keys()\ + if 'email' not in metadata.keys()\ and 'AUTHOR_EMAIL' in generator.settings.keys(): - metadatas['email'] = generator.settings['AUTHOR_EMAIL'] + metadata['email'] = generator.settings['AUTHOR_EMAIL'] #then add gravatar url - if 'email' in metadatas.keys(): + if 'email' in metadata.keys(): gravatar_url = "http://www.gravatar.com/avatar/" + \ - hashlib.md5(metadatas['email'].lower()).hexdigest() - metadatas["author_gravatar"] = gravatar_url + hashlib.md5(metadata['email'].lower()).hexdigest() + metadata["author_gravatar"] = gravatar_url - -signal('pelican_article_generate_context').connect(add_gravatar) + +def register(): + signal('pelican_article_generate_context').connect(add_gravatar) diff --git a/plugins_samples/initialized.py b/pelican/plugins/initialized.py similarity index 57% rename from plugins_samples/initialized.py rename to pelican/plugins/initialized.py index f104c275..076ba06d 100644 --- a/plugins_samples/initialized.py +++ b/pelican/plugins/initialized.py @@ -4,4 +4,5 @@ from blinker import signal def test(sender): print "%s initialized !!" % sender -signal('pelican_initialized').connect(test) +def register(): + signal('pelican_initialized').connect(test) From 28c0644eb60200e333a9f21f9e8ada5e16307df7 Mon Sep 17 00:00:00 2001 From: Alexis Metaireau Date: Sat, 18 Jun 2011 01:03:53 +0200 Subject: [PATCH 30/46] Plugins doc + minor design changes. --- docs/index.rst | 2 + docs/plugins.rst | 75 +++++++++++++++++++++++++++++++ docs/settings.rst | 5 ++- pelican/__init__.py | 4 +- pelican/generators.py | 8 ++-- pelican/plugins/global_license.py | 6 +-- pelican/plugins/gravatar.py | 4 +- pelican/plugins/initialized.py | 5 +-- pelican/settings.py | 2 +- pelican/signals.py | 4 ++ 10 files changed, 97 insertions(+), 18 deletions(-) create mode 100644 docs/plugins.rst create mode 100644 pelican/signals.py diff --git a/docs/index.rst b/docs/index.rst index 2897bc63..0e6ba583 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -55,6 +55,8 @@ A french version of the documentation is available at :doc:`fr/index`. getting_started settings themes + pelican-themes + plugins internals faq contribute diff --git a/docs/plugins.rst b/docs/plugins.rst new file mode 100644 index 00000000..6763f5ef --- /dev/null +++ b/docs/plugins.rst @@ -0,0 +1,75 @@ +.. _plugins: + +Plugins +####### + +Since version 2.8, pelican manages plugins. Plugins are a way to add feature to +pelican without having to directly hack pelican code. + +Pelican is shipped with a set of core plugins, but you can easily implement +your own (and this page describes how) + +How to use plugins? +==================== + +To load plugins, you have to specify a them in your settings file. You have two +ways to do so: by specifying strings with the path to the callables: :: + + PLUGINS = ['pelican.plugins.gravatar',] + +Or by importing them and adding them to the list:: + + from pelican.plugins import gravatar + PLUGINS = [gravatar, ] + +If your plugins are not in an importable path, you can specify a `PLUGIN_PATH` +in the settings:: + + PLUGIN_PATH = "plugins" + PLUGINS = ["list", "of", "plugins"] + +How to create plugins? +====================== + +Plugins are based on the concept of signals. Pelican sends signals and plugins +subscribe to those signals. The list of signals are defined in a following +section. + +The only rule to follow for plugins is to define a `register` callable, in +which you map the signals to your plugin logic. Let's take a simple exemple:: + + from pelican import signals + + def test(sender): + print "%s initialized !!" % sender + + def register(): + signals.initialized.connect(test) + + +List of signals +=============== + +Here is the list of currently implemented signals: + +========================= ============================ ===================== +Signal Arguments Description +========================= ============================ ===================== +initialized pelican object +article_generate_context article_generator, metadata +========================= ============================ ===================== + +The list is currently small, don't hesitate to add signals and make a pull +request if you need them! + +List of plugins +=============== + +Not all the list are described here, but a few of them have been extracted from +pelican core and provided in pelican.plugins. They are described here: + +Tag cloud +--------- + +Translation +----------- diff --git a/docs/settings.rst b/docs/settings.rst index 9c596da3..9287facd 100644 --- a/docs/settings.rst +++ b/docs/settings.rst @@ -51,6 +51,7 @@ Setting name (default value) what does it do? `PDF_GENERATOR` (``False``) Set to True if you want to have PDF versions of your documents. You will need to install `rst2pdf`. +`PLUGINS` (``[]``) The list of plugins to load. See :ref:`plugins`. `RELATIVE_URL` (``True``) Defines if pelican should use relative urls or not. `SITEURL` base URL of your website. Note that this is @@ -208,14 +209,14 @@ Setting name what does it do ? `GITHUB_URL` Your github URL (if you have one), it will then use it to create a github ribbon. `GOOGLE_ANALYTICS` 'UA-XXXX-YYYY' to activate google analytics. +`LINKS` A list of tuples (Title, Url) for links to appear on + the header. `PIWIK_URL` URL to your Piwik server - without 'http://' at the beginning. `PIWIK_SSL_URL` If the SSL-URL differs from the normal Piwik-URL you have to include this setting too. (optional) `PIWIK_SITE_ID` ID for the monitored website. You can find the ID in the Piwik admin interface > settings > websites. -`LINKS` A list of tuples (Title, Url) for links to appear on - the header. `SOCIAL` A list of tuples (Title, Url) to appear in the "social" section. `TWITTER_USERNAME` Allows to add a button on the articles to tweet about diff --git a/pelican/__init__.py b/pelican/__init__.py index 515434cc..7121318e 100644 --- a/pelican/__init__.py +++ b/pelican/__init__.py @@ -2,7 +2,7 @@ import argparse import os import time -from blinker import signal +from pelican import signals from pelican.generators import (ArticlesGenerator, PagesGenerator, StaticGenerator, PdfGenerator) @@ -46,7 +46,7 @@ class Pelican(object): raise Exception("Impossible to find the theme %s" % theme) self.init_plugins() - signal('pelican_initialized').send(self) + signals.initialized.send(self) def init_plugins(self): self.plugins = self.settings['PLUGINS'] diff --git a/pelican/generators.py b/pelican/generators.py index eb74aff9..38fa9da7 100755 --- a/pelican/generators.py +++ b/pelican/generators.py @@ -8,8 +8,6 @@ import os import math import random -from blinker import signal - from jinja2 import Environment, FileSystemLoader from jinja2.exceptions import TemplateNotFound @@ -17,6 +15,7 @@ from pelican.utils import copy, get_relative_path, process_translations, open from pelican.contents import Article, Page, is_valid_content from pelican.readers import read_file from pelican.log import * +from pelican import signals class Generator(object): @@ -100,7 +99,6 @@ class ArticlesGenerator(Generator): self.dates = {} self.tags = defaultdict(list) self.categories = defaultdict(list) - self.signal = {'pelican_article_generate_context' : signal('pelican_article_generate_context')} super(ArticlesGenerator, self).__init__(*args, **kwargs) self.drafts = [] @@ -214,7 +212,7 @@ class ArticlesGenerator(Generator): and self.settings['FALLBACK_ON_FS_DATE']: metadata['date'] = datetime.fromtimestamp(os.stat(f).st_ctime) - self.signal['pelican_article_generate_context'].send(self, metadata=metadata) + signals.article_generate_context.send(self, metadata=metadata) article = Article(content, metadata, settings=self.settings, filename=f) if not is_valid_content(article, f): @@ -318,7 +316,7 @@ class StaticGenerator(Generator): final_path=None): """Copy all the paths from source to destination""" for path in paths: - copy(path, source, os.path.join(output_path, destination), final_path, + copy(path, source, os.path.join(output_path, destination), final_path, overwrite=True) def generate_output(self, writer): diff --git a/pelican/plugins/global_license.py b/pelican/plugins/global_license.py index b6913831..463a93b3 100644 --- a/pelican/plugins/global_license.py +++ b/pelican/plugins/global_license.py @@ -1,4 +1,4 @@ -from blinker import signal +from pelican import signals """ License plugin for Pelican @@ -19,5 +19,5 @@ def add_license(generator, metadata): and 'LICENSE' in generator.settings.keys(): metadata['license'] = generator.settings['LICENSE'] - -signal('pelican_article_generate_context').connect(add_license) +def register(): + signals.article_generate_context.connect(add_license) diff --git a/pelican/plugins/gravatar.py b/pelican/plugins/gravatar.py index 2601ada0..200bb5a5 100644 --- a/pelican/plugins/gravatar.py +++ b/pelican/plugins/gravatar.py @@ -1,6 +1,6 @@ import hashlib -from blinker import signal +from pelican import signals """ Gravata plugin for Pelican ========================== @@ -37,4 +37,4 @@ def add_gravatar(generator, metadata): def register(): - signal('pelican_article_generate_context').connect(add_gravatar) + signals.article_generate_context.connect(add_gravatar) diff --git a/pelican/plugins/initialized.py b/pelican/plugins/initialized.py index 076ba06d..5e4cf174 100644 --- a/pelican/plugins/initialized.py +++ b/pelican/plugins/initialized.py @@ -1,8 +1,7 @@ -from blinker import signal - +from pelican import signals def test(sender): print "%s initialized !!" % sender def register(): - signal('pelican_initialized').connect(test) + signals.initialized.connect(test) diff --git a/pelican/settings.py b/pelican/settings.py index 3cc4157a..c1f15b2d 100644 --- a/pelican/settings.py +++ b/pelican/settings.py @@ -42,7 +42,7 @@ _DEFAULT_CONFIG = {'PATH': None, 'DEFAULT_METADATA': (), 'FILES_TO_COPY': (), 'DEFAULT_STATUS': 'published', - 'PLUGINS_PATH': None, + 'PLUGINS': [], } def read_settings(filename): diff --git a/pelican/signals.py b/pelican/signals.py new file mode 100644 index 00000000..f2bf4547 --- /dev/null +++ b/pelican/signals.py @@ -0,0 +1,4 @@ +from blinker import signal + +initialized = signal('pelican_initialized') +article_generate_context = signal('article_generate_context') From c6c0ee76c2d47017a56ef8442d8616e2dd2fb9d7 Mon Sep 17 00:00:00 2001 From: Marco Milanesi Date: Tue, 6 Sep 2011 18:54:41 +0200 Subject: [PATCH 31/46] implemented github activity plugin --- pelican/plugins/github_activity.py | 27 +++++++++++++++++++++++++++ pelican/signals.py | 1 + pelican/utils.py | 12 ++++++++++++ 3 files changed, 40 insertions(+) create mode 100644 pelican/plugins/github_activity.py diff --git a/pelican/plugins/github_activity.py b/pelican/plugins/github_activity.py new file mode 100644 index 00000000..d279e616 --- /dev/null +++ b/pelican/plugins/github_activity.py @@ -0,0 +1,27 @@ +from pelican import signals +from pelican.utils import singleton + +@singleton +class GitHubActivity(): + def __init__(self, generator): + try: + import feedparser + self.ga = feedparser.parse( + generator.settings['GITHUB_ACTIVITY_FEED']) + except ImportError: + raise Exception("unable to find feedparser") + + def fetch(self): + return [activity['content'][0]['value'].strip() + for activity in self.ga['entries']] + +def add_github_activity(generator, metadata): + if 'GITHUB_ACTIVITY_FEED' in generator.settings.keys(): + + ga = GitHubActivity(generator) + + ga_html_snippets = ga.fetch() + generator.context['github_activity'] = ga_html_snippets + +def register(): + signals.article_generate_context.connect(add_github_activity) diff --git a/pelican/signals.py b/pelican/signals.py index f2bf4547..fb50252f 100644 --- a/pelican/signals.py +++ b/pelican/signals.py @@ -2,3 +2,4 @@ from blinker import signal initialized = signal('pelican_initialized') article_generate_context = signal('article_generate_context') +github_activity = signal('github_activity') diff --git a/pelican/utils.py b/pelican/utils.py index 8e48c2e9..a67836ca 100644 --- a/pelican/utils.py +++ b/pelican/utils.py @@ -222,3 +222,15 @@ def files_changed(path, extensions): LAST_MTIME = mtime return True return False + +def singleton(cls): + """ + Singleton decorator for multiple calls inside plugins + for an example see pelican/plugins/github_activity.py + """ + instances = {} + def getinstance(*args, **kwargs): + if cls not in instances: + instances[cls] = cls(*args, **kwargs) + return instances[cls] + return getinstance From 3743617d27f5ec5216432636433dc566a7f802c1 Mon Sep 17 00:00:00 2001 From: Marco Milanesi Date: Tue, 6 Sep 2011 18:56:44 +0200 Subject: [PATCH 32/46] removed spurious signal --- pelican/signals.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pelican/signals.py b/pelican/signals.py index fb50252f..f2bf4547 100644 --- a/pelican/signals.py +++ b/pelican/signals.py @@ -2,4 +2,3 @@ from blinker import signal initialized = signal('pelican_initialized') article_generate_context = signal('article_generate_context') -github_activity = signal('github_activity') From 575905ac53f1af696045f68e0ac469ecd2a2ba9a Mon Sep 17 00:00:00 2001 From: Marco Milanesi Date: Tue, 6 Sep 2011 19:14:21 +0200 Subject: [PATCH 33/46] some commentary copyright infos some instructions on how to use the plugin --- pelican/plugins/github_activity.py | 35 ++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/pelican/plugins/github_activity.py b/pelican/plugins/github_activity.py index d279e616..bbce2759 100644 --- a/pelican/plugins/github_activity.py +++ b/pelican/plugins/github_activity.py @@ -1,8 +1,32 @@ +# -*- coding: utf-8 -*- +""" + Copyright (c) Marco Milanesi + + A plugin to list your Github Activity + To enable it set in your pelican config file the GITHUB_ACTIVITY_FEED + parameter pointing to your github activity feed. + + for example my personal activity feed is: + + https://github.com/kpanic.atom + + in your template just write a for in jinja2 syntax against the + github_activity variable. + + github_activity is a list containing raw html from github so you can + include it directly in your template + +""" + from pelican import signals from pelican.utils import singleton + @singleton class GitHubActivity(): + """ + A class created to fetch github activity with feedparser + """ def __init__(self, generator): try: import feedparser @@ -12,10 +36,17 @@ class GitHubActivity(): raise Exception("unable to find feedparser") def fetch(self): + """ + returns a list of html snippets fetched from github actitivy feed + """ return [activity['content'][0]['value'].strip() for activity in self.ga['entries']] + def add_github_activity(generator, metadata): + """ + registered handler for the github activity plugin + """ if 'GITHUB_ACTIVITY_FEED' in generator.settings.keys(): ga = GitHubActivity(generator) @@ -23,5 +54,9 @@ def add_github_activity(generator, metadata): ga_html_snippets = ga.fetch() generator.context['github_activity'] = ga_html_snippets + def register(): + """ + Plugin registration + """ signals.article_generate_context.connect(add_github_activity) From 48d7df72f1a0d9c405cac85b662a70c6c14dc238 Mon Sep 17 00:00:00 2001 From: Marco Milanesi Date: Wed, 7 Sep 2011 17:08:28 +0200 Subject: [PATCH 34/46] refactored code and introduced a new signal in ArticlesGenerator __init__ --- pelican/generators.py | 1 + pelican/plugins/github_activity.py | 26 ++++++++++++++++---------- pelican/signals.py | 1 + pelican/utils.py | 12 ------------ 4 files changed, 18 insertions(+), 22 deletions(-) diff --git a/pelican/generators.py b/pelican/generators.py index 38fa9da7..9baf240e 100755 --- a/pelican/generators.py +++ b/pelican/generators.py @@ -101,6 +101,7 @@ class ArticlesGenerator(Generator): self.categories = defaultdict(list) super(ArticlesGenerator, self).__init__(*args, **kwargs) self.drafts = [] + signals.article_generator_init.send(self) def generate_feeds(self, writer): """Generate the feeds from the current context, and output files.""" diff --git a/pelican/plugins/github_activity.py b/pelican/plugins/github_activity.py index bbce2759..ba6cd70f 100644 --- a/pelican/plugins/github_activity.py +++ b/pelican/plugins/github_activity.py @@ -19,10 +19,8 @@ """ from pelican import signals -from pelican.utils import singleton -@singleton class GitHubActivity(): """ A class created to fetch github activity with feedparser @@ -30,7 +28,7 @@ class GitHubActivity(): def __init__(self, generator): try: import feedparser - self.ga = feedparser.parse( + self.activities = feedparser.parse( generator.settings['GITHUB_ACTIVITY_FEED']) except ImportError: raise Exception("unable to find feedparser") @@ -40,23 +38,31 @@ class GitHubActivity(): returns a list of html snippets fetched from github actitivy feed """ return [activity['content'][0]['value'].strip() - for activity in self.ga['entries']] + for activity in self.activities['entries']] -def add_github_activity(generator, metadata): +def fetch_github_activity(gen, metadata): """ registered handler for the github activity plugin + it puts in generator.context the html needed to be displayed on a + template """ - if 'GITHUB_ACTIVITY_FEED' in generator.settings.keys(): - ga = GitHubActivity(generator) + if 'GITHUB_ACTIVITY_FEED' in gen.settings.keys(): + gen.context['github_activity'] = gen.plugin_instance.fetch() - ga_html_snippets = ga.fetch() - generator.context['github_activity'] = ga_html_snippets + +def feed_parser_initialization(generator): + """ + Initialization of feed parser + """ + + generator.plugin_instance = GitHubActivity(generator) def register(): """ Plugin registration """ - signals.article_generate_context.connect(add_github_activity) + signals.article_generator_init.connect(feed_parser_initialization) + signals.article_generate_context.connect(fetch_github_activity) diff --git a/pelican/signals.py b/pelican/signals.py index f2bf4547..b1c35794 100644 --- a/pelican/signals.py +++ b/pelican/signals.py @@ -2,3 +2,4 @@ from blinker import signal initialized = signal('pelican_initialized') article_generate_context = signal('article_generate_context') +article_generator_init = signal('article_generator_init') diff --git a/pelican/utils.py b/pelican/utils.py index a67836ca..8e48c2e9 100644 --- a/pelican/utils.py +++ b/pelican/utils.py @@ -222,15 +222,3 @@ def files_changed(path, extensions): LAST_MTIME = mtime return True return False - -def singleton(cls): - """ - Singleton decorator for multiple calls inside plugins - for an example see pelican/plugins/github_activity.py - """ - instances = {} - def getinstance(*args, **kwargs): - if cls not in instances: - instances[cls] = cls(*args, **kwargs) - return instances[cls] - return getinstance From 948ef452ca7d6a02175674b1169fa9c700f72c28 Mon Sep 17 00:00:00 2001 From: Marco Milanesi Date: Wed, 7 Sep 2011 18:55:37 +0200 Subject: [PATCH 35/46] documentation for the github activity plugin --- docs/plugins.rst | 45 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 42 insertions(+), 3 deletions(-) diff --git a/docs/plugins.rst b/docs/plugins.rst index 6763f5ef..42ecd656 100644 --- a/docs/plugins.rst +++ b/docs/plugins.rst @@ -52,12 +52,13 @@ List of signals Here is the list of currently implemented signals: -========================= ============================ ===================== +========================= ============================ ========================================= Signal Arguments Description -========================= ============================ ===================== +========================= ============================ ========================================= initialized pelican object article_generate_context article_generator, metadata -========================= ============================ ===================== +article_generator_init article_generator invoked in the ArticlesGenerator.__init__ +========================= ============================ ========================================= The list is currently small, don't hesitate to add signals and make a pull request if you need them! @@ -73,3 +74,41 @@ Tag cloud Translation ----------- + +Github Activity +_______________ + +This plugins introduces a new depencency, you have to install feedparser +if you want to use it, these are some ways to do it:: + + apt-get install python-feedparser # on debian based distributions like ubuntu + sudo easy_install feedparser + sudo pip install feedparser + +To enable it set in your pelican config file the GITHUB_ACTIVITY_FEED +parameter pointing to your github activity feed. + +for example my personal activity feed is:: + + https://github.com/kpanic.atom + +and the config line could be:: + + GITHUB_ACTIVITY_FEED = 'https://github.com/kpanic.atom' + +in your template just write a for in jinja2 syntax against the +github_activity variable, like for example:: + + {% if GITHUB_ACTIVITY_FEED %} + + {% endif %} + + +github_activity is a list containing raw html from github so you can include it +directly in your (for example base.html) template and style it in a way that +your prefer using your css skills From 83d59d6b93a9300572c5f1adddca524baba5cb43 Mon Sep 17 00:00:00 2001 From: Marco Milanesi Date: Tue, 18 Oct 2011 22:21:43 +0200 Subject: [PATCH 36/46] revised github activity to adapt it to new github atom feed changes --- pelican/plugins/github_activity.py | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/pelican/plugins/github_activity.py b/pelican/plugins/github_activity.py index ba6cd70f..f2ba1da7 100644 --- a/pelican/plugins/github_activity.py +++ b/pelican/plugins/github_activity.py @@ -13,9 +13,20 @@ in your template just write a for in jinja2 syntax against the github_activity variable. - github_activity is a list containing raw html from github so you can - include it directly in your template + i.e. + + + github_activity is a list containing a list. The first element is the title + and the second element is the raw html from github """ from pelican import signals @@ -31,14 +42,20 @@ class GitHubActivity(): self.activities = feedparser.parse( generator.settings['GITHUB_ACTIVITY_FEED']) except ImportError: - raise Exception("unable to find feedparser") + raise Exception("Unable to find feedparser") def fetch(self): """ returns a list of html snippets fetched from github actitivy feed """ - return [activity['content'][0]['value'].strip() - for activity in self.activities['entries']] + + entries = [] + for activity in self.activities['entries']: + entries.append( + [element for element in [activity['title'], + activity['content'][0]['value']]]) + + return entries def fetch_github_activity(gen, metadata): From 462e637e69e46318411b53eac6d237c8ef498542 Mon Sep 17 00:00:00 2001 From: Marco Milanesi Date: Wed, 19 Oct 2011 11:57:37 +0200 Subject: [PATCH 37/46] updated doc --- docs/plugins.rst | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/docs/plugins.rst b/docs/plugins.rst index 42ecd656..3bf7c532 100644 --- a/docs/plugins.rst +++ b/docs/plugins.rst @@ -100,15 +100,20 @@ in your template just write a for in jinja2 syntax against the github_activity variable, like for example:: {% if GITHUB_ACTIVITY_FEED %} - + {% endif %} -github_activity is a list containing raw html from github so you can include it -directly in your (for example base.html) template and style it in a way that -your prefer using your css skills + +github_activity is a list containing a list. The first element is the title and +the second element is the raw html from github so you can include it directly +in your (for example base.html) template and style it in a way that your prefer +using your css skills From f248a811076bdf5facfbf75de49e52fef0d6315a Mon Sep 17 00:00:00 2001 From: Skami18 Date: Sat, 29 Oct 2011 18:04:59 +0200 Subject: [PATCH 38/46] Plugins are now installed by setuptools --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 18db914f..071d3523 100755 --- a/setup.py +++ b/setup.py @@ -16,7 +16,7 @@ setup( author_email = 'alexis@notmyidea.org', description = "A tool to generate a static blog, with restructured text (or markdown) input files.", long_description=open('README.rst').read(), - packages = ['pelican'], + packages = ['pelican', 'pelican.plugins'], include_package_data = True, install_requires = requires, scripts = ['bin/pelican', 'tools/pelican-themes'], From b735f5fa49643bbf87aa58dca53b2e2830bbc0d7 Mon Sep 17 00:00:00 2001 From: Skami18 Date: Sun, 30 Oct 2011 14:10:50 +0100 Subject: [PATCH 39/46] Plugin loading is logged in debug mode (-D) --- pelican/__init__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pelican/__init__.py b/pelican/__init__.py index 7121318e..5b84685d 100644 --- a/pelican/__init__.py +++ b/pelican/__init__.py @@ -53,8 +53,10 @@ class Pelican(object): for plugin in self.plugins: # if it's a string, then import it if isinstance(plugin, str): + log.debug("Loading plugin `{0}' ...".format(plugin)) plugin = __import__(plugin, globals(), locals(), 'module') + log.debug("Registering plugin `{0}' ...".format(plugin.__name__)) plugin.register() def run(self): From c522ce7fbcb37a8ca141c6b2604ba85bfef00125 Mon Sep 17 00:00:00 2001 From: Skami18 Date: Sun, 30 Oct 2011 14:14:10 +0100 Subject: [PATCH 40/46] New plugin that provides an ..html:: directive for reStructuredText --- pelican/plugins/html_rst_directive.py | 63 +++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 pelican/plugins/html_rst_directive.py diff --git a/pelican/plugins/html_rst_directive.py b/pelican/plugins/html_rst_directive.py new file mode 100644 index 00000000..d14000a0 --- /dev/null +++ b/pelican/plugins/html_rst_directive.py @@ -0,0 +1,63 @@ +from docutils import nodes +from docutils.parsers.rst import directives, Directive +from pelican import log + +""" +HTML tags for reStructuredText +============================== + +Directives +---------- + +.. html:: + + (HTML code) + + +Example +------- + +A search engine: + +.. html:: +
+ + + +
+ + +A contact form: + +.. html:: + +
+

+ +
+ +
+ +

+
+ +""" + + +class RawHtml(Directive): + required_arguments = 0 + optional_arguments = 0 + final_argument_whitespace = True + has_content = True + + def run(self): + html = u' '.join(self.content) + node = nodes.raw('', html, format='html') + return [node] + + + +def register(): + directives.register_directive('html', RawHtml) + From 229ebbbcbf5f6ccb1b3c193fb992ab0539c4ac1f Mon Sep 17 00:00:00 2001 From: Bruno Binet Date: Tue, 20 Mar 2012 01:26:26 +0100 Subject: [PATCH 41/46] plugins branch is planned to be merged for 3.0 --- docs/plugins.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/plugins.rst b/docs/plugins.rst index 3bf7c532..f788b32a 100644 --- a/docs/plugins.rst +++ b/docs/plugins.rst @@ -3,7 +3,7 @@ Plugins ####### -Since version 2.8, pelican manages plugins. Plugins are a way to add feature to +Since version 3.0, pelican manages plugins. Plugins are a way to add feature to pelican without having to directly hack pelican code. Pelican is shipped with a set of core plugins, but you can easily implement From 67f7fcba264eaa122d86286636531247935eca71 Mon Sep 17 00:00:00 2001 From: Bruno Binet Date: Tue, 20 Mar 2012 01:39:52 +0100 Subject: [PATCH 42/46] remove duplicated pelican-themes entry from the toctree --- docs/index.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/index.rst b/docs/index.rst index 202bdbd9..7dbac168 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -60,7 +60,6 @@ A French version of the documentation is available at :doc:`fr/index`. getting_started settings themes - pelican-themes plugins internals pelican-themes From 7cd4d28bb2e57e0154a3cb8b1546b669abdf715f Mon Sep 17 00:00:00 2001 From: Bruno Binet Date: Tue, 20 Mar 2012 23:31:04 +0100 Subject: [PATCH 43/46] better plugins doc --- docs/plugins.rst | 41 +++++++++++++++-------------------------- 1 file changed, 15 insertions(+), 26 deletions(-) diff --git a/docs/plugins.rst b/docs/plugins.rst index f788b32a..db5a4bfc 100644 --- a/docs/plugins.rst +++ b/docs/plugins.rst @@ -3,17 +3,18 @@ Plugins ####### -Since version 3.0, pelican manages plugins. Plugins are a way to add feature to -pelican without having to directly hack pelican code. +Since version 3.0, pelican manages plugins. Plugins are a way to add features +to pelican without having to directly hack pelican code. Pelican is shipped with a set of core plugins, but you can easily implement -your own (and this page describes how) +your own (and this page describes how). How to use plugins? ==================== -To load plugins, you have to specify a them in your settings file. You have two -ways to do so: by specifying strings with the path to the callables: :: +To load plugins, you have to specify them in your settings file. You have two +ways to do so. +Either by specifying strings with the path to the callables:: PLUGINS = ['pelican.plugins.gravatar',] @@ -76,28 +77,18 @@ Translation ----------- Github Activity -_______________ +--------------- -This plugins introduces a new depencency, you have to install feedparser -if you want to use it, these are some ways to do it:: +This plugin makes use of the ``feedparser`` library that you'll need to +install. - apt-get install python-feedparser # on debian based distributions like ubuntu - sudo easy_install feedparser - sudo pip install feedparser - -To enable it set in your pelican config file the GITHUB_ACTIVITY_FEED -parameter pointing to your github activity feed. - -for example my personal activity feed is:: - - https://github.com/kpanic.atom - -and the config line could be:: +Set the GITHUB_ACTIVITY_FEED parameter to your github activity feed. +For example, my setting would look like:: GITHUB_ACTIVITY_FEED = 'https://github.com/kpanic.atom' -in your template just write a for in jinja2 syntax against the -github_activity variable, like for example:: +On the templates side, you just have to iterate over the ``github_activity`` +variable, as in the example:: {% if GITHUB_ACTIVITY_FEED %}