diff --git a/docs/faq.rst b/docs/faq.rst index e76bea6a..4225ab5f 100644 --- a/docs/faq.rst +++ b/docs/faq.rst @@ -21,7 +21,7 @@ How can I help? ================ There are several ways to help out. First, you can use Pelican and report any -suggestions or problems you might have via IRC or the issue tracker. +suggestions or problems you might have via IRC or the `issue tracker `_. If you want to contribute, please fork `the git repository `_, create a new feature branch, make diff --git a/docs/getting_started.rst b/docs/getting_started.rst index f73f802e..add77c17 100644 --- a/docs/getting_started.rst +++ b/docs/getting_started.rst @@ -187,7 +187,9 @@ Note that, aside from the title, none of this metadata is mandatory: if the date is not specified, Pelican will rely on the file's "mtime" timestamp, and the category can be determined by the directory in which the file resides. For example, a file located at ``python/foobar/myfoobar.rst`` will have a category of -``foobar``. +``foobar``. If you would like to organize your files in other ways where the +name of the subfolder would not be a good category name, you can set the +setting ``USE_FOLDER_AS_CATEGORY`` to ``False``. Generate your blog ------------------ diff --git a/docs/settings.rst b/docs/settings.rst index 063011bc..72c507a7 100644 --- a/docs/settings.rst +++ b/docs/settings.rst @@ -34,6 +34,10 @@ Setting name (default value) What doe `DATE_FORMATS` (``{}``) If you do manage multiple languages, you can set the date formatting here. See "Date format and locales" section below for details. +`USE_FOLDER_AS_CATEGORY` (``True``) When you don't specify a category in your post metadata and set this + setting to ``True`` and organize your articles in subfolders, the + subfolder will become the category of your post. If set to ``False`` + ``DEFAULT_CATEGORY`` will be used as a fallback. `DEFAULT_CATEGORY` (``'misc'``) The default category to fall back on. `DEFAULT_DATE_FORMAT` (``'%a %d %B %Y'``) The default date format you want to use. `DISPLAY_PAGES_ON_MENU` (``True``) Whether to display pages on the menu of the diff --git a/pelican/contents.py b/pelican/contents.py index 0dee19f3..74a66934 100644 --- a/pelican/contents.py +++ b/pelican/contents.py @@ -121,7 +121,8 @@ class Page(object): 'lang': getattr(self, 'lang', 'en'), 'date': getattr(self, 'date', datetime.now()), 'author': self.author, - 'category': getattr(self, 'category', 'misc'), + 'category': getattr(self, 'category', + self.settings['DEFAULT_CATEGORY']), } def _expand_settings(self, key): diff --git a/pelican/generators.py b/pelican/generators.py index fdec93fa..c38409a1 100644 --- a/pelican/generators.py +++ b/pelican/generators.py @@ -280,11 +280,14 @@ class ArticlesGenerator(Generator): # if no category is set, use the name of the path as a category if 'category' not in metadata: - if os.path.dirname(f) == article_path: # if the article is not in a subdirectory - category = self.settings['DEFAULT_CATEGORY'] - else: + if (self.settings['USE_FOLDER_AS_CATEGORY'] + and os.path.dirname(f) != article_path): + # if the article is in a subdirectory category = os.path.basename(os.path.dirname(f))\ - .decode('utf-8') + .decode('utf-8') + else: + # if the article is not in a subdirectory + category = self.settings['DEFAULT_CATEGORY'] if category != '': metadata['category'] = Category(category, self.settings) diff --git a/pelican/settings.py b/pelican/settings.py index ccc010d7..4d297332 100644 --- a/pelican/settings.py +++ b/pelican/settings.py @@ -34,6 +34,7 @@ _DEFAULT_CONFIG = {'PATH': '.', 'PDF_GENERATOR': False, 'OUTPUT_SOURCES': False, 'OUTPUT_SOURCES_EXTENSION': '.text', + 'USE_FOLDER_AS_CATEGORY': True, 'DEFAULT_CATEGORY': 'misc', 'DEFAULT_DATE': 'fs', 'WITH_FUTURE_DATES': True, diff --git a/tests/support.py b/tests/support.py index e5bfcca1..13bbfb15 100644 --- a/tests/support.py +++ b/tests/support.py @@ -114,7 +114,6 @@ def mute(returns_output=False): return decorator - def get_article(title, slug, content, lang, extra_metadata=None): metadata = {'slug': slug, 'title': title, 'lang': lang} if extra_metadata is not None: @@ -122,19 +121,20 @@ def get_article(title, slug, content, lang, extra_metadata=None): return Article(content, metadata=metadata) -def skipIfNoExecutable(executable, valid_exit_code=1): - """Tries to run an executable to make sure it's in the path, Skips the tests - if not found. +def skipIfNoExecutable(executable): + """Skip test if `executable` is not found + + Tries to run `executable` with subprocess to make sure it's in the path, + and skips the tests if not found (if subprocess raises a `OSError`). """ - # calling with no params the command should exit with 1 with open(os.devnull, 'w') as fnull: try: res = subprocess.call(executable, stdout=fnull, stderr=fnull) except OSError: res = None - if res != valid_exit_code: - return unittest.skip('{0} compiler not found'.format(executable)) + if res is None: + return unittest.skip('{0} executable not found'.format(executable)) return lambda func: func diff --git a/tests/test_generators.py b/tests/test_generators.py index ac2cd560..0907cc37 100644 --- a/tests/test_generators.py +++ b/tests/test_generators.py @@ -86,6 +86,20 @@ class TestArticlesGenerator(unittest.TestCase): categories_expected = ['Default', 'TestCategory', 'Yeah', 'test', 'yeah'] self.assertEquals(categories, categories_expected) + def test_do_not_use_folder_as_category(self): + + settings = _DEFAULT_CONFIG.copy() + settings['ARTICLE_DIR'] = 'content' + settings['DEFAULT_CATEGORY'] = 'Default' + settings['USE_FOLDER_AS_CATEGORY'] = False + generator = ArticlesGenerator(settings.copy(), settings, + CUR_DIR, _DEFAULT_CONFIG['THEME'], None, + _DEFAULT_CONFIG['MARKUP']) + generator.generate_context() + + categories = [cat.name for cat, _ in generator.categories] + self.assertEquals(categories, ['Default', 'Yeah', 'test', 'yeah']) + def test_direct_templates_save_as_default(self): settings = _DEFAULT_CONFIG.copy() diff --git a/tests/test_importer.py b/tests/test_importer.py index 5504b12e..d4ff8205 100644 --- a/tests/test_importer.py +++ b/tests/test_importer.py @@ -3,25 +3,24 @@ import os from pelican.tools.pelican_import import wp2fields, fields2pelican -from .support import unittest, temporary_folder, mute +from .support import unittest, temporary_folder, mute, skipIfNoExecutable CUR_DIR = os.path.dirname(__file__) WORDPRESS_XML_SAMPLE = os.path.join(CUR_DIR, 'content', 'wordpressexport.xml') -PANDOC = os.system('pandoc --version') == 0 try: import BeautifulSoup except ImportError: BeautifulSoup = False # NOQA +@skipIfNoExecutable(['pandoc', '--version']) +@unittest.skipUnless(BeautifulSoup, 'Needs BeautifulSoup module') class TestWordpressXmlImporter(unittest.TestCase): def setUp(self): self.posts = wp2fields(WORDPRESS_XML_SAMPLE) - @unittest.skipUnless(PANDOC and BeautifulSoup, - 'Needs Pandoc and BeautifulSoup') def test_ignore_empty_posts(self): posts = list(self.posts) @@ -29,8 +28,6 @@ class TestWordpressXmlImporter(unittest.TestCase): for title, content, fname, date, author, categ, tags, format in posts: self.assertTrue(title.strip()) - @unittest.skipUnless(PANDOC and BeautifulSoup, - 'Needs Pandoc and BeautifulSoup') def test_can_toggle_raw_html_code_parsing(self): posts = list(self.posts)