From 67540997307caac11e4f61567a7edc2440adc9d5 Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Thu, 22 Dec 2011 15:13:12 +0000 Subject: [PATCH 01/11] Create a Category class which has a url property --- pelican/contents.py | 20 +++++++++++++++++++ pelican/generators.py | 4 ++-- pelican/readers.py | 2 ++ .../notmyidea/templates/article_infos.html | 2 +- .../notmyidea/templates/categories.html | 2 +- .../themes/simple/templates/categories.html | 2 +- 6 files changed, 27 insertions(+), 5 deletions(-) diff --git a/pelican/contents.py b/pelican/contents.py index 49f30316..aab6b330 100644 --- a/pelican/contents.py +++ b/pelican/contents.py @@ -143,6 +143,26 @@ class Quote(Page): base_properties = ('author', 'date') +class Category(object): + def __init__(self, category): + self.category = unicode(category) + + def __hash__(self): + return hash(self.category) + + def __eq__(self, other): + return self.category == unicode(other) + + def __str__(self): + return str(self.category) + + def __unicode__(self): + return self.category + + @property + def url(self): + return 'category/%s.html' % self + def is_valid_content(content, f): try: content.check_properties() diff --git a/pelican/generators.py b/pelican/generators.py index 6715126a..116c0b0b 100644 --- a/pelican/generators.py +++ b/pelican/generators.py @@ -187,7 +187,7 @@ class ArticlesGenerator(Generator): category_template = self.get_template('category') for cat, articles in self.categories: dates = [article for article in self.dates if article in articles] - write('category/%s.html' % cat, category_template, self.context, + write(cat.url, category_template, self.context, category=cat, articles=articles, dates=dates, paginated={'articles': articles, 'dates': dates}, page_name='category/%s' % cat) @@ -228,7 +228,7 @@ class ArticlesGenerator(Generator): category = os.path.basename(os.path.dirname(f)).decode('utf-8') if category != '': - metadata['category'] = unicode(category) + metadata['category'] = Category(category) if 'date' not in metadata.keys()\ and self.settings['FALLBACK_ON_FS_DATE']: diff --git a/pelican/readers.py b/pelican/readers.py index ee3ecd2c..1a62237a 100644 --- a/pelican/readers.py +++ b/pelican/readers.py @@ -15,6 +15,7 @@ except ImportError: Markdown = False import re +from pelican.contents import Category from pelican.utils import get_date, open @@ -22,6 +23,7 @@ _METADATA_PROCESSORS = { 'tags': lambda x: map(unicode.strip, unicode(x).split(',')), 'date': lambda x: get_date(x), 'status': unicode.strip, + 'category': Category, } def _process_metadata(name, value): diff --git a/pelican/themes/notmyidea/templates/article_infos.html b/pelican/themes/notmyidea/templates/article_infos.html index e1803be8..09ecd595 100644 --- a/pelican/themes/notmyidea/templates/article_infos.html +++ b/pelican/themes/notmyidea/templates/article_infos.html @@ -8,7 +8,7 @@ By {{ article.author }} {% endif %} -

In {{ article.category }}. {% if PDF_PROCESSOR %}get the pdf{% endif %}

+

In {{ article.category }}. {% if PDF_PROCESSOR %}get the pdf{% endif %}

{% include 'taglist.html' %} {% include 'translations.html' %} diff --git a/pelican/themes/notmyidea/templates/categories.html b/pelican/themes/notmyidea/templates/categories.html index 7e4bd2c9..e4d9d0a7 100644 --- a/pelican/themes/notmyidea/templates/categories.html +++ b/pelican/themes/notmyidea/templates/categories.html @@ -2,7 +2,7 @@ {% block content %} {% endblock %} diff --git a/pelican/themes/simple/templates/categories.html b/pelican/themes/simple/templates/categories.html index 7e4bd2c9..e29be0ca 100644 --- a/pelican/themes/simple/templates/categories.html +++ b/pelican/themes/simple/templates/categories.html @@ -2,7 +2,7 @@ {% block content %} {% endblock %} From f9ed01bb643ab6ad30d06517751f9002568bd0fd Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Thu, 22 Dec 2011 15:43:44 +0000 Subject: [PATCH 02/11] Create a Tag class which has a url property --- pelican/contents.py | 20 +++++++++++++++++++ pelican/generators.py | 2 +- pelican/readers.py | 4 ++-- .../themes/notmyidea/templates/taglist.html | 2 +- 4 files changed, 24 insertions(+), 4 deletions(-) diff --git a/pelican/contents.py b/pelican/contents.py index aab6b330..cca01911 100644 --- a/pelican/contents.py +++ b/pelican/contents.py @@ -163,6 +163,26 @@ class Category(object): def url(self): return 'category/%s.html' % self +class Tag(object): + def __init__(self, tag): + self.tag = unicode.strip(tag) + + def __hash__(self): + return hash(self.tag) + + def __eq__(self, other): + return self.tag == unicode(tag) + + def __str__(self): + return str(self.tag) + + def __unicode__(self): + return self.tag + + @property + def url(self): + return 'tag/%s.html' % self + def is_valid_content(content, f): try: content.check_properties() diff --git a/pelican/generators.py b/pelican/generators.py index 116c0b0b..816a6755 100644 --- a/pelican/generators.py +++ b/pelican/generators.py @@ -179,7 +179,7 @@ class ArticlesGenerator(Generator): for tag, articles in self.tags.items(): articles.sort(key=attrgetter('date'), reverse=True) dates = [article for article in self.dates if article in articles] - write('tag/%s.html' % tag, tag_template, self.context, tag=tag, + write(tag.url, tag_template, self.context, tag=tag, articles=articles, dates=dates, paginated={'articles': articles, 'dates': dates}, page_name='tag/%s' % tag) diff --git a/pelican/readers.py b/pelican/readers.py index 1a62237a..6011c272 100644 --- a/pelican/readers.py +++ b/pelican/readers.py @@ -15,12 +15,12 @@ except ImportError: Markdown = False import re -from pelican.contents import Category +from pelican.contents import Category, Tag from pelican.utils import get_date, open _METADATA_PROCESSORS = { - 'tags': lambda x: map(unicode.strip, unicode(x).split(',')), + 'tags': lambda x: map(Tag, unicode(x).split(',')), 'date': lambda x: get_date(x), 'status': unicode.strip, 'category': Category, diff --git a/pelican/themes/notmyidea/templates/taglist.html b/pelican/themes/notmyidea/templates/taglist.html index 0f4862d0..c792fd7d 100644 --- a/pelican/themes/notmyidea/templates/taglist.html +++ b/pelican/themes/notmyidea/templates/taglist.html @@ -1,2 +1,2 @@ -{% if article.tags %}

tags: {% for tag in article.tags %}{{ tag }}{% endfor %}

{% endif %} +{% if article.tags %}

tags: {% for tag in article.tags %}{{ tag }}{% endfor %}

{% endif %} {% if PDF_PROCESSOR %}

get the pdf

{% endif %} From ff9c7861497e9056df911bed95d26567b97749d3 Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Thu, 22 Dec 2011 16:22:34 +0000 Subject: [PATCH 03/11] Create a Author class which has a url property --- pelican/contents.py | 47 +++++++++---------- pelican/generators.py | 2 +- pelican/readers.py | 3 +- .../notmyidea/templates/article_infos.html | 2 +- pelican/themes/simple/templates/article.html | 2 +- pelican/themes/simple/templates/index.html | 2 +- 6 files changed, 28 insertions(+), 30 deletions(-) diff --git a/pelican/contents.py b/pelican/contents.py index cca01911..8cd36186 100644 --- a/pelican/contents.py +++ b/pelican/contents.py @@ -37,9 +37,9 @@ class Page(object): # default author to the one in settings if not defined if not hasattr(self, 'author'): if 'AUTHOR' in settings: - self.author = settings['AUTHOR'] + self.author = Author(settings['AUTHOR']) else: - self.author = getenv('USER', 'John Doe') + self.author = Author(getenv('USER', 'John Doe')) warning(u"Author of `{0}' unknow, assuming that his name is `{1}'".format(filename or self.title, self.author)) # manage languages @@ -142,47 +142,44 @@ class Article(Page): class Quote(Page): base_properties = ('author', 'date') - -class Category(object): - def __init__(self, category): - self.category = unicode(category) +class URLWrapper(object): + def __init__(self, name): + self.name = unicode(name) def __hash__(self): - return hash(self.category) + return hash(self.name) def __eq__(self, other): - return self.category == unicode(other) + return self.name == unicode(other) def __str__(self): - return str(self.category) + return str(self.name) def __unicode__(self): - return self.category + return self.name + @property + def url(self): + return '%s.html' % self.name + +class Category(URLWrapper): @property def url(self): return 'category/%s.html' % self -class Tag(object): - def __init__(self, tag): - self.tag = unicode.strip(tag) - - def __hash__(self): - return hash(self.tag) - - def __eq__(self, other): - return self.tag == unicode(tag) - - def __str__(self): - return str(self.tag) - - def __unicode__(self): - return self.tag +class Tag(URLWrapper): + def __init__(self, name): + self.name = unicode.strip(name) @property def url(self): return 'tag/%s.html' % self +class Author(URLWrapper): + @property + def url(self): + return 'author/%s.html' % self + def is_valid_content(content, f): try: content.check_properties() diff --git a/pelican/generators.py b/pelican/generators.py index 816a6755..d9d584a4 100644 --- a/pelican/generators.py +++ b/pelican/generators.py @@ -195,7 +195,7 @@ class ArticlesGenerator(Generator): author_template = self.get_template('author') for aut, articles in self.authors: dates = [article for article in self.dates if article in articles] - write('author/%s.html' % aut, author_template, self.context, + write(aut.url, author_template, self.context, author=aut, articles=articles, dates=dates, paginated={'articles': articles, 'dates': dates}, page_name='author/%s' % aut) diff --git a/pelican/readers.py b/pelican/readers.py index 6011c272..e760b662 100644 --- a/pelican/readers.py +++ b/pelican/readers.py @@ -15,7 +15,7 @@ except ImportError: Markdown = False import re -from pelican.contents import Category, Tag +from pelican.contents import Category, Tag, Author from pelican.utils import get_date, open @@ -24,6 +24,7 @@ _METADATA_PROCESSORS = { 'date': lambda x: get_date(x), 'status': unicode.strip, 'category': Category, + 'author': Author, } def _process_metadata(name, value): diff --git a/pelican/themes/notmyidea/templates/article_infos.html b/pelican/themes/notmyidea/templates/article_infos.html index 09ecd595..a1993a09 100644 --- a/pelican/themes/notmyidea/templates/article_infos.html +++ b/pelican/themes/notmyidea/templates/article_infos.html @@ -5,7 +5,7 @@ {% if article.author %}
- By {{ article.author }} + By {{ article.author }}
{% endif %}

In {{ article.category }}. {% if PDF_PROCESSOR %}get the pdf{% endif %}

diff --git a/pelican/themes/simple/templates/article.html b/pelican/themes/simple/templates/article.html index 30d31fb6..d6c96a13 100644 --- a/pelican/themes/simple/templates/article.html +++ b/pelican/themes/simple/templates/article.html @@ -8,7 +8,7 @@ {% if article.author %}
- By {{ article.author }} + By {{ article.author }}
{% endif %} diff --git a/pelican/themes/simple/templates/index.html b/pelican/themes/simple/templates/index.html index fd8545df..ad2a3b2e 100644 --- a/pelican/themes/simple/templates/index.html +++ b/pelican/themes/simple/templates/index.html @@ -11,7 +11,7 @@

{{ article.title }}

{{ article.summary }}
From a39787c1a2c32dc936dba9ace73a0fcef0b73098 Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Fri, 23 Dec 2011 22:01:32 +0000 Subject: [PATCH 04/11] Add settings to change the URL's and SAVE_AS paths Example usage: * ARTICLE_URL = 'posts/{date:%Y}/{date:%b}/{date:%d}/{slug}/' * ARTICLE_SAVE_AS = 'posts/{date:%Y}/{date:%b}/{date:%d}/{slug}/index.html' This removes CLEAN_URLS and ARTICLE_PERMALINK_STRUCTURE because these new settings can produce the same result. --- docs/settings.rst | 54 +++++++++++++++++++++++-------------- pelican/contents.py | 62 +++++++++++++++++++++++++++---------------- pelican/generators.py | 17 +----------- pelican/settings.py | 9 ++++++- 4 files changed, 82 insertions(+), 60 deletions(-) diff --git a/docs/settings.rst b/docs/settings.rst index 2d40d4ec..b93c8c11 100644 --- a/docs/settings.rst +++ b/docs/settings.rst @@ -24,12 +24,7 @@ Basic settings ================================================ ===================================================== Setting name (default value) What does it do? ================================================ ===================================================== -`ARTICLE_PERMALINK_STRUCTURE` (``''``) Empty by default. Enables some customization of URL - structure (see below for more detail). `AUTHOR` Default author (put your name) -`CLEAN_URLS` (``False``) If set to `True`, the URLs will not be suffixed by - `.html`, so you will have to setup URL rewriting on - your web server. `DATE_FORMATS` (``{}``) If you do manage multiple languages, you can set the date formatting here. See "Date format and locales" section below for details. @@ -79,16 +74,14 @@ Setting name (default value) What does it do? .. [#] Default is the system locale. -Article permalink structure ---------------------------- +URL Settings +------------ -This setting allows you to output your articles sorted by date, provided that -you specify a format as specified below. This format follows the Python -``datetime`` directives: - -* %Y: Year with century as a decimal number. -* %m: Month as a decimal number [01,12]. -* %d: Day of the month as a decimal number [01,31]. +You can customize the URL's and locations where files will be saved. The URL's and +SAVE_AS variables use python's format strings. These variables allow you to place +your articles in a location such as '{slug}/index.html' and link to then as +'{slug}' for clean urls. These settings give you the flexibility to place your +articles and pages anywhere you want. Note: If you specify a datetime directive, it will be substituted using the input files' date metadata attribute. If the date is not specified for a @@ -99,15 +92,36 @@ information. Also, you can use other file metadata attributes as well: -* category: '%(category)s' -* author: '%(author)s' -* tags: '%(tags)s' -* date: '%(date)s' +* slug +* date +* lang +* author +* category Example usage: -* '/%Y/%m/' will render something like '/2011/07/sample-post.html'. -* '/%Y/%(category)s/' will render something like '/2011/life/sample-post.html'. +* ARTICLE_URL = 'posts/{date:%Y}/{date:%b}/{date:%d}/{slug}/' +* ARTICLE_SAVE_AS = 'posts/{date:%Y}/{date:%b}/{date:%d}/{slug}/index.html' + +This would save your articles in something like '/posts/2011/Aug/07/sample-post/index.html', +and the URL to this would be '/posts/2011/Aug/07/sample-post/'. + +================================================ ===================================================== +Setting name (default value) what does it do? +================================================ ===================================================== +`ARTICLE_URL` ('{slug}.html') The URL to refer to an ARTICLE. +`ARTICLE_SAVE_AS` ('{slug}.html') The place where we will save an article. +`ARTICLE_LANG_URL` ('{slug}-{lang}.html') The URL to refer to an ARTICLE which doesn't use the + default language. +`ARTICLE_LANG_SAVE_AS` ('{slug}-{lang}.html' The place where we will save an article which + doesn't use the default language. +`PAGE_URL` ('pages/{slug}.html') The URL we will use to link to a page. +`PAGE_SAVE_AS` ('pages/{slug}.html') The location we will save the page. +`PAGE_LANG_URL` ('pages/{slug}-{lang}.html') The URL we will use to link to a page which doesn't + use the default language. +`PAGE_LANG_SAVE_AS` ('pages/{slug}-{lang}.html') The location we will save the page which doesn't + use the default language. +================================================ ===================================================== Timezone -------- diff --git a/pelican/contents.py b/pelican/contents.py index 8cd36186..bc42d41e 100644 --- a/pelican/contents.py +++ b/pelican/contents.py @@ -24,6 +24,7 @@ class Page(object): if not settings: settings = _DEFAULT_CONFIG + self.settings = settings self._content = content self.translations = [] @@ -55,29 +56,6 @@ class Page(object): if not hasattr(self, 'slug') and hasattr(self, 'title'): self.slug = slugify(self.title) - # create save_as from the slug (+lang) - if not hasattr(self, 'save_as') and hasattr(self, 'slug'): - if self.in_default_lang: - if settings.get('CLEAN_URLS', False): - self.save_as = '%s/index.html' % self.slug - else: - self.save_as = '%s.html' % self.slug - - clean_url = '%s/' % self.slug - else: - if settings.get('CLEAN_URLS', False): - self.save_as = '%s-%s/index.html' % (self.slug, self.lang) - else: - self.save_as = '%s-%s.html' % (self.slug, self.lang) - - clean_url = '%s-%s/' % (self.slug, self.lang) - - # change the save_as regarding the settings - if settings.get('CLEAN_URLS', False): - self.url = clean_url - elif hasattr(self, 'save_as'): - self.url = self.save_as - if filename: self.filename = filename @@ -115,6 +93,30 @@ class Page(object): if not hasattr(self, prop): raise NameError(prop) + @property + def url_format(self): + return { + 'slug': getattr(self, 'slug', ''), + 'lang': getattr(self, 'lang', 'en'), + 'date': getattr(self, 'date', datetime.now()), + 'author': self.author, + 'category': getattr(self, 'category', 'misc'), + } + + @property + def url(self): + if self.in_default_lang: + return self.settings.get('PAGE_URL', 'pages/{slug}.html').format(**self.url_format) + + return self.settings.get('PAGE_LANG_URL', 'pages/{slug}-{lang}.html').format(**self.url_format) + + @property + def save_as(self): + if self.in_default_lang: + return self.settings.get('PAGE_SAVE_AS', 'pages/{slug}.html').format(**self.url_format) + + return self.settings.get('PAGE_LANG_SAVE_AS', 'pages/{slug}-{lang}.html').format(**self.url_format) + @property def content(self): if hasattr(self, "_get_content"): @@ -138,6 +140,20 @@ class Page(object): class Article(Page): mandatory_properties = ('title', 'date', 'category') + @property + def url(self): + if self.in_default_lang: + return self.settings.get('ARTICLE_URL', '{slug}.html').format(**self.url_format) + + return self.settings.get('ARTICLE_LANG_URL', '{slug}-{lang}.html').format(**self.url_format) + + @property + def save_as(self): + if self.in_default_lang: + return self.settings.get('ARTICLE_SAVE_AS', '{slug}.html').format(**self.url_format) + + return self.settings.get('ARTICLE_LANG_SAVE_AS', '{slug}-{lang}.html').format(**self.url_format) + class Quote(Page): base_properties = ('author', 'date') diff --git a/pelican/generators.py b/pelican/generators.py index d9d584a4..7ad3d276 100644 --- a/pelican/generators.py +++ b/pelican/generators.py @@ -239,21 +239,6 @@ class ArticlesGenerator(Generator): if not is_valid_content(article, f): continue - add_to_url = u'' - if 'ARTICLE_PERMALINK_STRUCTURE' in self.settings: - article_permalink_structure = self.settings['ARTICLE_PERMALINK_STRUCTURE'] - article_permalink_structure = article_permalink_structure.lstrip('/').replace('%(', "%%(") - - # try to substitute any python datetime directive - add_to_url = article.date.strftime(article_permalink_structure) - # try to substitute any article metadata in rest file - add_to_url = add_to_url % article.__dict__ - add_to_url = [slugify(i) for i in add_to_url.split('/')] - add_to_url = os.path.join(*add_to_url) - - article.url = urlparse.urljoin(add_to_url, article.url) - article.save_as = urlparse.urljoin(add_to_url, article.save_as) - if article.status == "published": if hasattr(article, 'tags'): for tag in article.tags: @@ -348,7 +333,7 @@ class PagesGenerator(Generator): def generate_output(self, writer): for page in chain(self.translations, self.pages): - writer.write_file('pages/%s' % page.save_as, self.get_template('page'), + writer.write_file(page.save_as, self.get_template('page'), self.context, page=page, relative_urls = self.settings.get('RELATIVE_URLS')) diff --git a/pelican/settings.py b/pelican/settings.py index cf6b23e5..ec6ec483 100644 --- a/pelican/settings.py +++ b/pelican/settings.py @@ -26,7 +26,14 @@ _DEFAULT_CONFIG = {'PATH': None, 'REVERSE_ARCHIVE_ORDER': False, 'REVERSE_CATEGORY_ORDER': False, 'DELETE_OUTPUT_DIRECTORY': False, - 'CLEAN_URLS': False, # use /blah/ instead /blah.html in urls + 'ARTICLE_URL': '{slug}.html', + 'ARTICLE_SAVE_AS': '{slug}.html', + 'ARTICLE_LANG_URL': '{slug}-{lang}.html', + 'ARTICLE_LANG_SAVE_AS': '{slug}-{lang}.html', + 'PAGE_URL': 'pages/{slug}.html', + 'PAGE_SAVE_AS': 'pages/{slug}.html', + 'PAGE_LANG_URL': 'pages/{slug}-{lang}.html', + 'PAGE_LANG_SAVE_AS': 'pages/{slug}-{lang}.html', 'RELATIVE_URLS': True, 'DEFAULT_LANG': 'en', 'TAG_CLOUD_STEPS': 4, From 44cf2ad400629ea9d85dd598d837a35adcfaed85 Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Fri, 23 Dec 2011 23:43:32 +0000 Subject: [PATCH 05/11] Support configurable URL's & SAVE_AS path for Author, Category and Tag --- docs/settings.rst | 6 +++++ pelican/contents.py | 29 +++++++++++++++------ pelican/generators.py | 8 +++--- pelican/readers.py | 60 +++++++++++++++++++++---------------------- 4 files changed, 60 insertions(+), 43 deletions(-) diff --git a/docs/settings.rst b/docs/settings.rst index b93c8c11..69e2adc8 100644 --- a/docs/settings.rst +++ b/docs/settings.rst @@ -121,6 +121,12 @@ Setting name (default value) what does it do? use the default language. `PAGE_LANG_SAVE_AS` ('pages/{slug}-{lang}.html') The location we will save the page which doesn't use the default language. +`AUTHOR_URL` ('author/{name}.html') The URL to use for an author. +`AUTHOR_SAVE_AS` ('author/{name}.html') The location to save an author. +`CATEGORY_URL` ('category/{name}.html') The URL to use for a category. +`CATEGORY_SAVE_AS` ('category/{name}.html') The location to save a category. +`TAG_URL` ('tag/{name}.html') The URL to use for a tag. +`TAG_SAVE_AS` ('tag/{name}.html') The location to save the tag page. ================================================ ===================================================== Timezone diff --git a/pelican/contents.py b/pelican/contents.py index bc42d41e..316a0e56 100644 --- a/pelican/contents.py +++ b/pelican/contents.py @@ -38,9 +38,9 @@ class Page(object): # default author to the one in settings if not defined if not hasattr(self, 'author'): if 'AUTHOR' in settings: - self.author = Author(settings['AUTHOR']) + self.author = Author(settings['AUTHOR'], settings) else: - self.author = Author(getenv('USER', 'John Doe')) + self.author = Author(getenv('USER', 'John Doe'), settings) warning(u"Author of `{0}' unknow, assuming that his name is `{1}'".format(filename or self.title, self.author)) # manage languages @@ -159,8 +159,9 @@ class Quote(Page): base_properties = ('author', 'date') class URLWrapper(object): - def __init__(self, name): + def __init__(self, name, settings): self.name = unicode(name) + self.settings = settings def __hash__(self): return hash(self.name) @@ -181,20 +182,32 @@ class URLWrapper(object): class Category(URLWrapper): @property def url(self): - return 'category/%s.html' % self + return self.settings.get('CATEGORY_URL', 'category/{name}.html').format(name=self.name) + + @property + def save_as(self): + return self.settings.get('CATEGORY_SAVE_AS', 'category/{name}.html').format(name=self.name) class Tag(URLWrapper): - def __init__(self, name): - self.name = unicode.strip(name) + def __init__(self, name, *args, **kwargs): + super(Tag, self).__init__(unicode.strip(name), *args, **kwargs) @property def url(self): - return 'tag/%s.html' % self + return self.settings.get('TAG_URL', 'tag/{name}.html').format(name=self.name) + + @property + def save_as(self): + return self.settings.get('TAG_SAVE_AS', 'tag/{name}.html').format(name=self.name) class Author(URLWrapper): @property def url(self): - return 'author/%s.html' % self + return self.settings.get('AUTHOR_URL', 'author/{name}.html').format(name=self.name) + + @property + def save_as(self): + return self.settings.get('AUTHOR_SAVE_AS', 'author/{name}.html').format(name=self.name) def is_valid_content(content, f): try: diff --git a/pelican/generators.py b/pelican/generators.py index 7ad3d276..38bfb5b8 100644 --- a/pelican/generators.py +++ b/pelican/generators.py @@ -179,7 +179,7 @@ class ArticlesGenerator(Generator): for tag, articles in self.tags.items(): articles.sort(key=attrgetter('date'), reverse=True) dates = [article for article in self.dates if article in articles] - write(tag.url, tag_template, self.context, tag=tag, + write(tag.save_as, tag_template, self.context, tag=tag, articles=articles, dates=dates, paginated={'articles': articles, 'dates': dates}, page_name='tag/%s' % tag) @@ -187,7 +187,7 @@ class ArticlesGenerator(Generator): category_template = self.get_template('category') for cat, articles in self.categories: dates = [article for article in self.dates if article in articles] - write(cat.url, category_template, self.context, + write(cat.save_as, category_template, self.context, category=cat, articles=articles, dates=dates, paginated={'articles': articles, 'dates': dates}, page_name='category/%s' % cat) @@ -195,7 +195,7 @@ class ArticlesGenerator(Generator): author_template = self.get_template('author') for aut, articles in self.authors: dates = [article for article in self.dates if article in articles] - write(aut.url, author_template, self.context, + write(aut.save_as, author_template, self.context, author=aut, articles=articles, dates=dates, paginated={'articles': articles, 'dates': dates}, page_name='author/%s' % aut) @@ -228,7 +228,7 @@ class ArticlesGenerator(Generator): category = os.path.basename(os.path.dirname(f)).decode('utf-8') if category != '': - metadata['category'] = Category(category) + metadata['category'] = Category(category, self.settings) if 'date' not in metadata.keys()\ and self.settings['FALLBACK_ON_FS_DATE']: diff --git a/pelican/readers.py b/pelican/readers.py index e760b662..814f81d2 100644 --- a/pelican/readers.py +++ b/pelican/readers.py @@ -15,28 +15,30 @@ except ImportError: Markdown = False import re -from pelican.contents import Category, Tag, Author +from pelican.contents import Category, Tag, Author, URLWrapper from pelican.utils import get_date, open _METADATA_PROCESSORS = { - 'tags': lambda x: map(Tag, unicode(x).split(',')), - 'date': lambda x: get_date(x), - 'status': unicode.strip, + 'tags': lambda x, y: [Tag(tag, y) for tag in unicode(x).split(',')], + 'date': lambda x, y: get_date(x), + 'status': lambda x,y: unicode.strip(x), 'category': Category, 'author': Author, } -def _process_metadata(name, value): - if name.lower() in _METADATA_PROCESSORS: - return _METADATA_PROCESSORS[name.lower()](value) - return value - - class Reader(object): enabled = True extensions = None + def __init__(self, settings): + self.settings = settings + + def process_metadata(self, name, value): + if name.lower() in _METADATA_PROCESSORS: + return _METADATA_PROCESSORS[name.lower()](value, self.settings) + return value + class _FieldBodyTranslator(HTMLTranslator): def astext(self): @@ -54,29 +56,25 @@ def render_node_to_html(document, node): node.walkabout(visitor) return visitor.astext() -def get_metadata(document): - """Return the dict containing document metadata""" - output = {} - for docinfo in document.traverse(docutils.nodes.docinfo): - for element in docinfo.children: - if element.tagname == 'field': # custom fields (e.g. summary) - name_elem, body_elem = element.children - name = name_elem.astext() - value = render_node_to_html(document, body_elem) - else: # standard fields (e.g. address) - name = element.tagname - value = element.astext() - - output[name] = _process_metadata(name, value) - return output - - class RstReader(Reader): enabled = bool(docutils) extension = "rst" def _parse_metadata(self, document): - return get_metadata(document) + """Return the dict containing document metadata""" + output = {} + for docinfo in document.traverse(docutils.nodes.docinfo): + for element in docinfo.children: + if element.tagname == 'field': # custom fields (e.g. summary) + name_elem, body_elem = element.children + name = name_elem.astext() + value = render_node_to_html(document, body_elem) + else: # standard fields (e.g. address) + name = element.tagname + value = element.astext() + + output[name] = self.process_metadata(name, value) + return output def _get_publisher(self, filename): extra_params = {'initial_header_level': '2'} @@ -113,7 +111,7 @@ class MarkdownReader(Reader): metadata = {} for name, value in md.Meta.items(): name = name.lower() - metadata[name] = _process_metadata(name, value[0]) + metadata[name] = self.process_metadata(name, value[0]) return content, metadata @@ -129,7 +127,7 @@ class HtmlReader(Reader): key = i.split(':')[0][5:].strip() value = i.split(':')[-1][:-3].strip() name = key.lower() - metadata[name] = _process_metadata(name, value) + metadata[name] = self.process_metadata(name, value) return content, metadata @@ -143,7 +141,7 @@ def read_file(filename, fmt=None, settings=None): fmt = filename.split('.')[-1] if fmt not in _EXTENSIONS.keys(): raise TypeError('Pelican does not know how to parse %s' % filename) - reader = _EXTENSIONS[fmt]() + reader = _EXTENSIONS[fmt](settings) settings_key = '%s_EXTENSIONS' % fmt.upper() if settings and settings_key in settings: reader.extensions = settings[settings_key] From 9ba55c28b4cf22a74879f9a836af7e62fe3d9276 Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Sat, 24 Dec 2011 00:37:18 +0000 Subject: [PATCH 06/11] Support CLEAN_URLS and ARTICLE_PERMALINK_STRUCTURE for backwards compatibility --- pelican/__init__.py | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/pelican/__init__.py b/pelican/__init__.py index 710c9ff1..e7e90f56 100644 --- a/pelican/__init__.py +++ b/pelican/__init__.py @@ -1,5 +1,6 @@ import argparse import os, sys +import re import time from pelican.generators import (ArticlesGenerator, PagesGenerator, @@ -26,6 +27,42 @@ class Pelican(object): if self.path.endswith('/'): self.path = self.path[:-1] + if settings.get('CLEAN_URLS', False): + log.warning('Found deprecated `CLEAN_URLS` in settings. Modifing' + ' the following settings for the same behaviour.') + + settings['ARTICLE_URL'] = '{slug}/' + settings['ARTICLE_LANG_URL'] = '{slug}-{lang}/' + settings['PAGE_URL'] = 'pages/{slug}/' + settings['PAGE_LANG_URL'] = 'pages/{slug}-{lang}/' + + for setting in ('ARTICLE_URL', 'ARTICLE_LANG_URL', 'PAGE_URL', + 'PAGE_LANG_URL'): + log.warning("%s = '%s'" % (setting, settings[setting])) + + if settings.get('ARTICLE_PERMALINK_STRUCTURE', False): + log.warning('Found deprecated `ARTICLE_PERMALINK_STRUCTURE` in' + ' settings. Modifing the following settings for' + ' the same behaviour.') + + structure = settings['ARTICLE_PERMALINK_STRUCTURE'] + + # Convert %(variable) into {variable}. + structure = re.sub('%\((\w+)\)s', '{\g<1>}', structure) + + # Convert %x into {date:%x} for strftime + structure = re.sub('(%[A-z])', '{date:\g<1>}', structure) + + # Strip a / prefix + structure = re.sub('^/', '', structure) + + for setting in ('ARTICLE_URL', 'ARTICLE_LANG_URL', 'PAGE_URL', + 'PAGE_LANG_URL', 'ARTICLE_SAVE_AS', + 'ARTICLE_LANG_SAVE_AS', 'PAGE_SAVE_AS', + 'PAGE_LANG_SAVE_AS'): + settings[setting] = os.path.join(structure, settings[setting]) + log.warning("%s = '%s'" % (setting, settings[setting])) + # define the default settings self.settings = settings self.theme = theme or settings['THEME'] From c5816c9c5a242a3d5c3b26eb0b844fe2f79f52a2 Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Thu, 1 Mar 2012 14:19:46 +0000 Subject: [PATCH 07/11] Make these patches compatible with upstream master --- pelican/contents.py | 2 +- pelican/generators.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pelican/contents.py b/pelican/contents.py index 316a0e56..12da22ef 100644 --- a/pelican/contents.py +++ b/pelican/contents.py @@ -98,7 +98,7 @@ class Page(object): return { 'slug': getattr(self, 'slug', ''), 'lang': getattr(self, 'lang', 'en'), - 'date': getattr(self, 'date', datetime.now()), + 'date': getattr(self, 'date', datetime.datetime.now()), 'author': self.author, 'category': getattr(self, 'category', 'misc'), } diff --git a/pelican/generators.py b/pelican/generators.py index 38bfb5b8..12bd20af 100644 --- a/pelican/generators.py +++ b/pelican/generators.py @@ -13,7 +13,7 @@ from operator import attrgetter, itemgetter from jinja2 import Environment, FileSystemLoader, PrefixLoader, ChoiceLoader from jinja2.exceptions import TemplateNotFound -from pelican.contents import Article, Page, is_valid_content +from pelican.contents import Article, Page, Category, is_valid_content from pelican.log import * from pelican.readers import read_file from pelican.utils import copy, process_translations, open From 8bf0a22eb0a49cad133958cbd2145febb9e1228d Mon Sep 17 00:00:00 2001 From: Bruno Binet Date: Fri, 2 Mar 2012 16:32:05 +0100 Subject: [PATCH 08/11] fix encoding errors error was:codeEncodeError: 'ascii' codec can't encode character u'\xe9' [..] --- pelican/contents.py | 28 ++++++++++++++-------------- pelican/generators.py | 7 +++---- 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/pelican/contents.py b/pelican/contents.py index 12da22ef..90bc189d 100644 --- a/pelican/contents.py +++ b/pelican/contents.py @@ -106,16 +106,16 @@ class Page(object): @property def url(self): if self.in_default_lang: - return self.settings.get('PAGE_URL', 'pages/{slug}.html').format(**self.url_format) + return self.settings.get('PAGE_URL', u'pages/{slug}.html').format(**self.url_format) - return self.settings.get('PAGE_LANG_URL', 'pages/{slug}-{lang}.html').format(**self.url_format) + return self.settings.get('PAGE_LANG_URL', u'pages/{slug}-{lang}.html').format(**self.url_format) @property def save_as(self): if self.in_default_lang: - return self.settings.get('PAGE_SAVE_AS', 'pages/{slug}.html').format(**self.url_format) + return self.settings.get('PAGE_SAVE_AS', u'pages/{slug}.html').format(**self.url_format) - return self.settings.get('PAGE_LANG_SAVE_AS', 'pages/{slug}-{lang}.html').format(**self.url_format) + return self.settings.get('PAGE_LANG_SAVE_AS', u'pages/{slug}-{lang}.html').format(**self.url_format) @property def content(self): @@ -143,16 +143,16 @@ class Article(Page): @property def url(self): if self.in_default_lang: - return self.settings.get('ARTICLE_URL', '{slug}.html').format(**self.url_format) + return self.settings.get('ARTICLE_URL', u'{slug}.html').format(**self.url_format) - return self.settings.get('ARTICLE_LANG_URL', '{slug}-{lang}.html').format(**self.url_format) + return self.settings.get('ARTICLE_LANG_URL', u'{slug}-{lang}.html').format(**self.url_format) @property def save_as(self): if self.in_default_lang: - return self.settings.get('ARTICLE_SAVE_AS', '{slug}.html').format(**self.url_format) + return self.settings.get('ARTICLE_SAVE_AS', u'{slug}.html').format(**self.url_format) - return self.settings.get('ARTICLE_LANG_SAVE_AS', '{slug}-{lang}.html').format(**self.url_format) + return self.settings.get('ARTICLE_LANG_SAVE_AS', u'{slug}-{lang}.html').format(**self.url_format) class Quote(Page): @@ -182,11 +182,11 @@ class URLWrapper(object): class Category(URLWrapper): @property def url(self): - return self.settings.get('CATEGORY_URL', 'category/{name}.html').format(name=self.name) + return self.settings.get('CATEGORY_URL', u'category/{name}.html').format(name=self.name) @property def save_as(self): - return self.settings.get('CATEGORY_SAVE_AS', 'category/{name}.html').format(name=self.name) + return self.settings.get('CATEGORY_SAVE_AS', u'category/{name}.html').format(name=self.name) class Tag(URLWrapper): def __init__(self, name, *args, **kwargs): @@ -194,20 +194,20 @@ class Tag(URLWrapper): @property def url(self): - return self.settings.get('TAG_URL', 'tag/{name}.html').format(name=self.name) + return self.settings.get('TAG_URL', u'tag/{name}.html').format(name=self.name) @property def save_as(self): - return self.settings.get('TAG_SAVE_AS', 'tag/{name}.html').format(name=self.name) + return self.settings.get('TAG_SAVE_AS', u'tag/{name}.html').format(name=self.name) class Author(URLWrapper): @property def url(self): - return self.settings.get('AUTHOR_URL', 'author/{name}.html').format(name=self.name) + return self.settings.get('AUTHOR_URL', u'author/{name}.html').format(name=self.name) @property def save_as(self): - return self.settings.get('AUTHOR_SAVE_AS', 'author/{name}.html').format(name=self.name) + return self.settings.get('AUTHOR_SAVE_AS', u'author/{name}.html').format(name=self.name) def is_valid_content(content, f): try: diff --git a/pelican/generators.py b/pelican/generators.py index 12bd20af..47ebb941 100644 --- a/pelican/generators.py +++ b/pelican/generators.py @@ -182,7 +182,7 @@ class ArticlesGenerator(Generator): write(tag.save_as, tag_template, self.context, tag=tag, articles=articles, dates=dates, paginated={'articles': articles, 'dates': dates}, - page_name='tag/%s' % tag) + page_name=u'tag/%s' % tag) category_template = self.get_template('category') for cat, articles in self.categories: @@ -190,7 +190,7 @@ class ArticlesGenerator(Generator): write(cat.save_as, category_template, self.context, category=cat, articles=articles, dates=dates, paginated={'articles': articles, 'dates': dates}, - page_name='category/%s' % cat) + page_name=u'category/%s' % cat) author_template = self.get_template('author') for aut, articles in self.authors: @@ -198,7 +198,7 @@ class ArticlesGenerator(Generator): write(aut.save_as, author_template, self.context, author=aut, articles=articles, dates=dates, paginated={'articles': articles, 'dates': dates}, - page_name='author/%s' % aut) + page_name=u'author/%s' % aut) for article in self.drafts: write('drafts/%s.html' % article.slug, article_template, self.context, @@ -212,7 +212,6 @@ class ArticlesGenerator(Generator): files = self.get_files(self.path, exclude=['pages',]) all_articles = [] for f in files: - try: content, metadata = read_file(f, settings=self.settings) except Exception, e: From bfd0e63e3d4b7a6b006024611e0451f4e39fbd7a Mon Sep 17 00:00:00 2001 From: Bruno Binet Date: Fri, 2 Mar 2012 23:19:03 +0100 Subject: [PATCH 09/11] fix pages urls --- pelican/themes/notmyidea/templates/base.html | 2 +- pelican/themes/notmyidea/templates/index.html | 2 +- pelican/themes/simple/templates/base.html | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pelican/themes/notmyidea/templates/base.html b/pelican/themes/notmyidea/templates/base.html index 4a4c70c6..12086dc7 100644 --- a/pelican/themes/notmyidea/templates/base.html +++ b/pelican/themes/notmyidea/templates/base.html @@ -31,7 +31,7 @@ {% endfor %} {% if DISPLAY_PAGES_ON_MENU %} {% for page in PAGES %} -
  • {{ page.title }}
  • +
  • {{ page.title }}
  • {% endfor %} {% endif %} {% for cat, null in categories %} diff --git a/pelican/themes/notmyidea/templates/index.html b/pelican/themes/notmyidea/templates/index.html index 217bacf2..f81275ae 100644 --- a/pelican/themes/notmyidea/templates/index.html +++ b/pelican/themes/notmyidea/templates/index.html @@ -53,7 +53,7 @@

    Pages

    {% for page in PAGES %} -
  • {{ page.title }}
  • +
  • {{ page.title }}
  • {% endfor %}
    {% endif %} diff --git a/pelican/themes/simple/templates/base.html b/pelican/themes/simple/templates/base.html index a8fad2db..a1017219 100644 --- a/pelican/themes/simple/templates/base.html +++ b/pelican/themes/simple/templates/base.html @@ -17,7 +17,7 @@ {% endfor %} {% if DISPLAY_PAGES_ON_MENU %} {% for p in PAGES %} - {{ p.title }} + {{ p.title }} {% endfor %} {% else %} {% for cat, null in categories %} From c2b8caed3f75bb7f52065bf21226f8a41ac76519 Mon Sep 17 00:00:00 2001 From: Bruno Binet Date: Mon, 5 Mar 2012 23:33:25 +0100 Subject: [PATCH 10/11] fix test test_article_with_metadata error was: ERROR: test_article_with_metadata (tests.test_readers.RstReaderTest) ---------------------------------------------------------------------- Traceback (most recent call last): File "/home/bruno/dev/pelican/tests/test_readers.py", line 22, in test_article_with_metadata reader = readers.RstReader() TypeError: __init__() takes exactly 2 arguments (1 given) --- tests/test_readers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_readers.py b/tests/test_readers.py index 1e920e09..120b3125 100644 --- a/tests/test_readers.py +++ b/tests/test_readers.py @@ -19,7 +19,7 @@ def _filename(*args): class RstReaderTest(unittest2.TestCase): def test_article_with_metadata(self): - reader = readers.RstReader() + reader = readers.RstReader({}) content, metadata = reader.read(_filename('article_with_metadata.rst')) expected = { 'category': 'yeah', From 8f8933d991fd5e9da1a22cc6e3d2beced83f6c7d Mon Sep 17 00:00:00 2001 From: Bruno Binet Date: Mon, 5 Mar 2012 23:48:18 +0100 Subject: [PATCH 11/11] fix test test_save_as ERROR: test_save_as (tests.test_contents.TestPage) If a lang is not the default lang, save_as should be set ---------------------------------------------------------------------- Traceback (most recent call last): File "/home/bruno/dev/pelican/tests/test_contents.py", line 63, in test_save_as page.save_as = 'foo-bar.html' AttributeError: can't set attribute --- tests/test_contents.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_contents.py b/tests/test_contents.py index 9772fac5..1abb125d 100644 --- a/tests/test_contents.py +++ b/tests/test_contents.py @@ -60,12 +60,12 @@ class TestPage(TestCase): """ # if a title is defined, save_as should be set page = Page(**self.page_kwargs) - page.save_as = 'foo-bar.html' + self.assertEqual(page.save_as, "pages/foo-bar.html") # if a language is defined, save_as should include it accordingly self.page_kwargs['metadata'].update({'lang': 'fr', }) page = Page(**self.page_kwargs) - self.assertEqual(page.save_as, "foo-bar-fr.html") + self.assertEqual(page.save_as, "pages/foo-bar-fr.html") def test_datetime(self): """If DATETIME is set to a tuple, it should be used to override LOCALE