subcategory.py 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. # -*- coding: utf-8 -*-
  2. """
  3. @Author: Alistair Magee
  4. Adds support for subcategories on pelican articles
  5. """
  6. import os
  7. from collections import defaultdict
  8. from operator import attrgetter
  9. from functools import partial
  10. from pelican import signals
  11. from pelican.urlwrappers import URLWrapper, Category
  12. from pelican.utils import (slugify, python_2_unicode_compatible)
  13. from six import text_type
  14. class SubCategory(URLWrapper):
  15. def __init__(self, name, parent, settings):
  16. super(SubCategory, self).__init__(name, settings)
  17. self.parent = parent
  18. self.shortname = name.split('/')
  19. self.shortname = self.shortname.pop()
  20. self.slug = slugify(self.shortname, settings.get('SLUG_SUBSTITUIONS', ()))
  21. if isinstance(self.parent, SubCategory):
  22. self.savepath = os.path.join(self.parent.savepath, self.slug)
  23. self.fullurl = '{}/{}'.format(self.parent.fullurl, self.slug)
  24. else: #parent is a category
  25. self.savepath = os.path.join(self.parent.slug, self.slug)
  26. self.fullurl = '{}/{}'.format(self.parent.slug, self.slug)
  27. def as_dict(self):
  28. d = self.__dict__
  29. d['shortname'] = self.shortname
  30. d['savepath'] = self.savepath
  31. d['fullurl'] = self.fullurl
  32. d['parent'] = self.parent
  33. return d
  34. def __hash__(self):
  35. return hash(self.fullurl)
  36. def _key(self):
  37. return self.fullurl
  38. def get_subcategories(generator, metadata):
  39. if 'SUBCATEGORY_SAVE_AS' not in generator.settings:
  40. generator.settings['SUBCATEGORY_SAVE_AS'] = os.path.join(
  41. 'subcategory', '{savepath}.html')
  42. if 'SUBCATEGORY_URL' not in generator.settings:
  43. generator.settings['SUBCATEGORY_URL'] = 'subcategory/{fullurl}.html'
  44. category_list = text_type(metadata.get('category')).split('/')
  45. category = (category_list.pop(0)).strip()
  46. category = Category(category, generator.settings)
  47. metadata['category'] = category
  48. #generate a list of subcategories with their parents
  49. sub_list = []
  50. parent = category.name
  51. for subcategory in category_list:
  52. subcategory.strip()
  53. subcategory = parent + '/' + subcategory
  54. sub_list.append(subcategory)
  55. parent = subcategory
  56. metadata['subcategories'] = sub_list
  57. def create_subcategories(generator):
  58. generator.subcategories = []
  59. for article in generator.articles:
  60. parent = article.category
  61. actual_subcategories = []
  62. for subcategory in article.subcategories:
  63. #following line returns a list of items, tuples in this case
  64. sub_cat = [item for item in generator.subcategories
  65. if item[0].name == subcategory]
  66. if sub_cat:
  67. sub_cat[0][1].append(article)
  68. parent = sub_cat[0][0]
  69. actual_subcategories.append(parent)
  70. else:
  71. new_sub = SubCategory(subcategory, parent, generator.settings)
  72. generator.subcategories.append((new_sub, [article,]))
  73. parent = new_sub
  74. actual_subcategories.append(parent)
  75. article.subcategories = actual_subcategories
  76. def generate_subcategories(generator, writer):
  77. write = partial(writer.write_file,
  78. relative_urls=generator.settings['RELATIVE_URLS'])
  79. subcategory_template = generator.get_template('subcategory')
  80. for subcat, articles in generator.subcategories:
  81. articles.sort(key=attrgetter('date'), reverse=True)
  82. dates = [article for article in generator.dates if article in articles]
  83. write(subcat.save_as, subcategory_template, generator.context,
  84. subcategory=subcat, articles=articles, dates=dates,
  85. paginated={'articles': articles, 'dates': dates},
  86. page_name=subcat.page_name, all_articles=generator.articles)
  87. def generate_subcategory_feeds(generator, writer):
  88. for subcat, articles in generator.subcategories:
  89. articles.sort(key=attrgetter('date'), reverse=True)
  90. if generator.settings.get('SUBCATEGORY_FEED_ATOM'):
  91. writer.write_feed(articles, generator.context,
  92. generator.settings['SUBCATEGORY_FEED_ATOM']
  93. % subcat.fullurl)
  94. if generator.settings.get('SUBCATEGORY_FEED_RSS'):
  95. writer.write_feed(articles, generator.context,
  96. generator.settings['SUBCATEGORY_FEED_RSS']
  97. % subcat.fullurl, feed_type='rss')
  98. def generate(generator, writer):
  99. generate_subcategory_feeds(generator, writer)
  100. generate_subcategories(generator, writer)
  101. def register():
  102. signals.article_generator_context.connect(get_subcategories)
  103. signals.article_generator_finalized.connect(create_subcategories)
  104. signals.article_writer_finalized.connect(generate)