Skip to content

Commit

Permalink
Merge c816b63 into 85b22e8
Browse files Browse the repository at this point in the history
  • Loading branch information
felixfontein committed Nov 27, 2016
2 parents 85b22e8 + c816b63 commit 822e483
Show file tree
Hide file tree
Showing 18 changed files with 1,423 additions and 929 deletions.
5 changes: 4 additions & 1 deletion nikola/nikola.py
Expand Up @@ -73,6 +73,7 @@
SignalHandler,
ConfigPlugin,
PostScanner,
Taxonomy,
)

if DEBUG:
Expand Down Expand Up @@ -949,6 +950,7 @@ def init_plugins(self, commands_only=False, load_all=False):
"SignalHandler": SignalHandler,
"ConfigPlugin": ConfigPlugin,
"PostScanner": PostScanner,
"Taxonomy": Taxonomy,
})
self.plugin_manager.getPluginLocator().setPluginInfoExtension('plugin')
extra_plugins_dirs = self.config['EXTRA_PLUGINS_DIRS']
Expand Down Expand Up @@ -1020,6 +1022,7 @@ def plugin_position_in_places(plugin):

self.plugin_manager.loadPlugins()

self._activate_plugins_of_category("Taxonomy")
self._activate_plugins_of_category("SignalHandler")

# Emit signal for SignalHandlers which need to start running immediately.
Expand Down Expand Up @@ -2344,7 +2347,7 @@ def generic_index_renderer(self, lang, posts, indexes_title, template_name, cont
kw['indexes_prety_page_url'] = self.config["INDEXES_PRETTY_PAGE_URL"]
kw['demote_headers'] = self.config['DEMOTE_HEADERS']
kw['generate_atom'] = self.config["GENERATE_ATOM"]
kw['feed_link_append_query'] = self.config["FEED_LINKS_APPEND_QUERY"]
kw['feed_links_append_query'] = self.config["FEED_LINKS_APPEND_QUERY"]
kw['currentfeed'] = None

# Split in smaller lists
Expand Down
266 changes: 266 additions & 0 deletions nikola/plugin_categories.py
Expand Up @@ -49,6 +49,7 @@
'SignalHandler',
'ConfigPlugin',
'PostScanner',
'Taxonomy',
)


Expand Down Expand Up @@ -471,3 +472,268 @@ def import_file(self):
def save_post(self):
"""Save a post to disk."""
raise NotImplementedError()


class Taxonomy(BasePlugin):
"""Taxonomy for posts.
A taxonomy plugin allows to classify posts (see #2107) by
classification strings. Classification plugins must adjust
a set of options to determine certain aspects.
The following options are class attributes with their default
values. These variables should be set in the class definition,
in the constructor or latest in the `set_site` function.
classification_name = "taxonomy":
The classification name to be used for path handlers.
metadata_name = "taxonomy":
The classification name to be used when storing the classification
in the metadata. If set to None, the classification won't be stored
in the metadata.
overview_page_variable_name = "taxonomy":
When rendering the overview page, its template will have a list
of classifications available in a variable by this name.
more_than_one_classifications_per_post = False:
If True, there can be more than one classification per post; in that case,
the classification data in the metadata is stored as a list. If False,
the classification data in the metadata is stored as a string, or None
when no classification is given.
has_hierarchy = False:
Whether the classification has a hierarchy.
include_posts_from_subhierarchies = False:
If True, the list for a classification includes all posts with a
sub-classification (in case has_hierarchy is True).
include_posts_into_hierarchy_root = False:
If True, include_posts_from_subhierarchies == True will also insert
posts into the list for the empty hierarchy [].
show_list_as_subcategories_list = False:
If not False, for every classification which has at least one
subclassification, create a list of subcategories instead of a list/index
of posts. This is only used when has_hierarchy = True. If not False, this
must be the template name for the list; usually "list.tmpl".
If this is set to a string, it is recommended to set
include_posts_from_subhierarchies to True to get correct post counts.
show_list_as_index = False:
Whether to show the posts for one classification as an index or
as a post list.
generate_atom_feeds_for_post_lists = False:
Whether to generate Atom feeds for post lists in case GENERATE_ATOM is set.
template_for_single_list = "tagindex.tmpl":
The template to use for the post list for one classification.
template_for_classification_overview = "list.tmpl":
The template to use for the classification overview page.
Set to None to avoid generating overviews.
always_disable_rss = False:
Whether to always disable RSS feed generation
apply_to_posts = True:
Whether this classification applies to posts.
apply_to_pages = False:
Whether this classification applies to pages.
minimum_post_count_per_classification_in_overview = 1:
The minimum number of posts a classification must have to be listed in
the overview.
omit_empty_classifications = False:
Whether post lists resp. indexes should be created for empty
classifications.
also_create_classifications_from_other_languages = True:
Whether to include all classifications for all languages in every
language, or only the classifications for one language in its language's
pages.
"""

name = "dummy_taxonomy"

# Adjust the following values in your plugin!
classification_name = "taxonomy"
metadata_name = "taxonomy"
overview_page_variable_name = "taxonomy"
more_than_one_classifications_per_post = False
has_hierarchy = False
include_posts_from_subhierarchies = False
include_posts_into_hierarchy_root = False
show_list_as_subcategories_list = False
show_list_as_index = False
generate_atom_feeds_for_post_lists = False
template_for_single_list = "tagindex.tmpl"
template_for_classification_overview = "list.tmpl"
always_disable_rss = False
apply_to_posts = True
apply_to_pages = False
minimum_post_count_per_classification_in_overview = 1
omit_empty_classifications = False
also_create_classifications_from_other_languages = True

def is_enabled(self, lang=None):
"""Return True if this taxonomy is enabled, or False otherwise.
If lang is None, this determins whether the classification is
made at all. If lang is not None, this determines whether the
overview page and the classification lists are created for this
language.
"""
return True

def get_implicit_classifications(self, lang):
"""Return a list of classification strings which should always appear in posts_per_classification."""
return []

def classify(self, post, lang):
"""Classify the given post for the given language.
Must return a list or tuple of strings.
"""
raise NotImplementedError()

def sort_posts(self, posts, classification, lang):
"""Sort the given list of posts.
Allows the plugin to order the posts per classification as it wants.
The posts will be ordered by date (latest first) before calling
this function. This function must sort in-place.
"""
pass

def sort_classifications(self, classifications, lang, level=None):
"""Sort the given list of classification strings.
Allows the plugin to order the classifications as it wants. The
classifications will be ordered by `natsort` before calling this
function. This function must sort in-place.
For hierarchical taxonomies, the elements of the list are a single
path element of the path returned by `extract_hierarchy()`. The index
of the path element in the path will be provided in `level`.
"""
pass

def get_classification_friendly_name(self, classification, lang, only_last_component=False):
"""Extract a friendly name from the classification.
The result of this function is usually displayed to the user, instead
of using the classification string.
For hierarchical taxonomies, the result of extract_hierarchy is provided
as `classification`. For non-hierarchical taxonomies, the classification
string itself is provided as `classification`.
The argument `only_last_component` is only relevant to hierarchical
taxonomies. If it is set, the printable name should only describe the
last component of `classification` if possible.
"""
raise NotImplementedError()

def get_list_path(self, lang, type='page'):
"""A path handler for the list of all classifications.
Must return one or two values (in this order):
* a list or tuple of strings: the path relative to OUTPUT_DIRECTORY;
* a string with values 'auto', 'always' or 'never', indicating whether
INDEX_FILE should be added or not.
Note that this function must always return a list or tuple of strings;
the other return value is optional with default value `'auto'`.
In case INDEX_FILE should potentially be added, the last element in the
returned path must have no extension, and the PRETTY_URLS config must
be ignored by this handler. The return value will be modified based on
the PRETTY_URLS and INDEX_FILE settings.
Type can be either 'page', 'feed' (for Atom feed) or 'rss'.
"""
raise NotImplementedError()

def get_path(self, classification, lang, type='page'):
"""A path handler for the given classification.
Must return one to three values (in this order):
* a list or tuple of strings: the path relative to OUTPUT_DIRECTORY;
* a string with values 'auto', 'always' or 'never', indicating whether
INDEX_FILE should be added or not;
* an integer if a specific page of the index is to be targeted (will be
ignored for post lists), or `None` if the most current page is targeted.
Note that this function must always return a list or tuple of strings;
the other two return values are optional with default values `'auto'` and
`None`.
In case INDEX_FILE should potentially be added, the last element in the
returned path must have no extension, and the PRETTY_URLS config must
be ignored by this handler. The return value will be modified based on
the PRETTY_URLS and INDEX_FILE settings.
Type can be either 'page', 'feed' (for Atom feed) or 'rss'.
For hierarchical taxonomies, the result of extract_hierarchy is provided
as `classification`. For non-hierarchical taxonomies, the classification
string itself is provided as `classification`.
"""
raise NotImplementedError()

def extract_hierarchy(self, classification):
"""Given a classification, return a list of parts in the hierarchy.
For non-hierarchical taxonomies, it usually suffices to return
`[classification]`.
"""
return [classification]

def recombine_classification_from_hierarchy(self, hierarchy):
"""Given a list of parts in the hierarchy, return the classification string.
For non-hierarchical taxonomies, it usually suffices to return hierarchy[0].
"""
return hierarchy[0]

def provide_list_context_and_uptodate(self, lang):
"""Provide data for the context and the uptodate list for the list of all classifiations.
Must return a tuple of two dicts. The first is merged into the page's context,
the second will be put into the uptodate list of all generated tasks.
Context must contain `title`.
"""
raise NotImplementedError()

def provide_context_and_uptodate(self, classification, lang):
"""Provide data for the context and the uptodate list for the list of the given classifiation.
Must return a tuple of two dicts. The first is merged into the page's context,
the second will be put into the uptodate list of all generated tasks.
Context must contain `title`, which should be something like 'Posts about <classification>'.
"""
raise NotImplementedError()

def should_generate_classification_list(self, classification, post_list, lang):
"""Only generates list of posts for classification if this function returns True."""
return True

def postprocess_posts_per_classification(self, posts_per_classification_per_language, flat_hierarchy_per_lang=None, hierarchy_lookup_per_lang=None):
"""Rearrange, modify or otherwise use the list of posts per classification and per language.
For compatibility reasons, the list could be stored somewhere else as well.
In case `has_hierarchy` is `True`, `flat_hierarchy_per_lang` is the flat
hierarchy consisting of `utils.TreeNode` elements, and `hierarchy_lookup_per_lang`
is the corresponding hierarchy lookup mapping classification strings to
`utils.TreeNode` objects.
"""
pass
12 changes: 12 additions & 0 deletions nikola/plugins/misc/taxonomies_classifier.plugin
@@ -0,0 +1,12 @@
[Core]
name = classify_taxonomies
module = taxonomies_classifier

[Documentation]
author = Roberto Alsina
version = 1.0
website = https://getnikola.com/
description = Classifies the timeline into taxonomies.

[Nikola]
plugincategory = SignalHandler

0 comments on commit 822e483

Please sign in to comment.