site_opytex/plugins/hierarchy/article_hierarchy.py

89 lines
3.4 KiB
Python

from pelican import signals, contents
import os.path
from copy import copy
from itertools import chain
'''
This plugin creates a URL hierarchy for articles that matches the
directory hierarchy of their sources.
'''
class UnexpectedException(Exception): pass
def get_path(article, settings):
''' Return the dirname relative to ARTICLE_PATHS prefix. '''
path = os.path.split(article.get_relative_source_path())[0] + '/'
path = path.replace( os.path.sep, '/' )
# Try to lstrip the longest prefix first
for prefix in sorted(settings['ARTICLE_PATHS'], key=len, reverse=True):
if not prefix.endswith('/'): prefix += '/'
if path.startswith(prefix):
return path[len(prefix):-1]
raise UnexpectedException('Article outside of ARTICLE_PATHS ?!?')
def in_default_lang(article):
# article.in_default_lang property is undocumented (=unstable) interface
return article.lang == article.settings['DEFAULT_LANG']
def override_metadata(content_object):
if type(content_object) is not contents.Article:
return
article = content_object
path = get_path(article, article.settings)
def _override_value(article, key):
metadata = copy(article.metadata)
# We override the slug to include the path up to the filename
#metadata['slug'] = os.path.join(path, article.slug)
metadata['slug'] = path
# We have to account for non-default language and format either,
# e.g., ARTICLE_SAVE_AS or ARTICLE_LANG_SAVE_AS
#infix = '' if in_default_lang(article) else 'LANG_'
infix = ''
return article.settings['ARTICLE_' + infix + key.upper()].format(**metadata)
for key in ('save_as', 'url'):
if not hasattr(article, 'override_' + key):
setattr(article, 'override_' + key, _override_value(article, key))
def set_relationships(generator):
def _all_articles():
return chain(generator.articles, generator.translations)
# initialize parents and children lists
for article in _all_articles():
article.parent = None
article.parents = []
article.children = []
# set immediate parents and children
for article in _all_articles():
# Parent of /a/b/ is /a/, parent of /a/b.html is /a/
parent_url = os.path.dirname(article.url[:-1])
if parent_url: parent_url += '/'
for article2 in _all_articles():
if article2.url == parent_url and article2 != article:
article.parent = article2
article2.children.append(article)
# If no parent found, try the parent of the default language article
#if not article.parent and not in_default_lang(article):
if not article.parent:
for article2 in generator.articles:
if (article.slug == article2.slug and
os.path.dirname(article.source_path) ==
os.path.dirname(article2.source_path)):
# Only set the parent but not the children, obviously
article.parent = article2.parent
# set all parents (ancestors)
for article in _all_articles():
p = article
while p.parent:
article.parents.insert(0, p.parent)
p = p.parent
def register():
signals.content_object_init.connect(override_metadata)
signals.article_generator_finalized.connect(set_relationships)